aGrUM  0.14.2
PRMClass_tpl.h
Go to the documentation of this file.
1 /**************************************************************************
2  * Copyright (C) 2005 by Christophe GONZALES and Pierre-Henri WUILLEMIN *
3  * {prenom.nom}_at_lip6.fr *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
27 // to ease parsing
28 #include <queue>
29 
31 
33 
34 namespace gum {
35  namespace prm {
36  template < typename GUM_SCALAR >
37  PRMClass< GUM_SCALAR >::PRMClass(const std::string& name) :
38  PRMClassElementContainer< GUM_SCALAR >(name), __superClass(nullptr),
39  __implements(nullptr), __bijection(nullptr) {
40  GUM_CONSTRUCTOR(PRMClass);
41  }
42 
43  template < typename GUM_SCALAR >
44  PRMClass< GUM_SCALAR >::PRMClass(const std::string& name,
46  bool delayInheritance) :
47  PRMClassElementContainer< GUM_SCALAR >(name),
48  __superClass(&super), __implements(nullptr),
49  __bijection(
50  new Bijection< const DiscreteVariable*, const DiscreteVariable* >()) {
51  GUM_CONSTRUCTOR(PRMClass);
52  if (!delayInheritance) {
53  __dag = super.containerDag();
54  __inheritClass(super);
55  }
56  }
57 
58  template < typename GUM_SCALAR >
59  PRMClass< GUM_SCALAR >::PRMClass(const std::string& name,
60  const Set< PRMInterface< GUM_SCALAR >* >& set,
61  bool delayInheritance) :
62  PRMClassElementContainer< GUM_SCALAR >(name),
63  __superClass(nullptr),
64  __implements(new Set< PRMInterface< GUM_SCALAR >* >(set)),
65  __bijection(nullptr) {
66  GUM_CONSTRUCTOR(PRMClass);
67 
68  if (!delayInheritance) { __implementInterfaces(false); }
69  }
70 
71  template < typename GUM_SCALAR >
72  PRMClass< GUM_SCALAR >::PRMClass(const std::string& name,
74  const Set< PRMInterface< GUM_SCALAR >* >& set,
75  bool delayInheritance) :
76  PRMClassElementContainer< GUM_SCALAR >(name),
77  __superClass(&super), __implements(nullptr),
78  __bijection(
79  new Bijection< const DiscreteVariable*, const DiscreteVariable* >()) {
80  GUM_CONSTRUCTOR(PRMClass);
81  if (!delayInheritance) {
82  __dag = super.containerDag();
83  __inheritClass(super);
84  }
85 
86  // Adding other implementation
87  if (__implements == nullptr) { // super has not created __implements
88  __implements = new Set< PRMInterface< GUM_SCALAR >* >(set);
89  } else { // we just add the new implementations
90  for (const auto elt : set) {
91  __implements->insert(elt);
92  }
93  }
94 
95  if (!delayInheritance) { __implementInterfaces(false); }
96  }
97 
98  template < typename GUM_SCALAR >
99  void PRMClass< GUM_SCALAR >::__implementInterfaces(bool delayedInheritance) {
100  for (const auto impl : *__implements) {
101  impl->__addImplementation(this);
102  if ((!__superClass) || (!super().isSubTypeOf(*impl))
103  || delayedInheritance) {
104  // Reserve reference id in DAG
105  for (auto ref : impl->referenceSlots()) {
106  __dag.addNodeWithId(ref->id());
107  }
108  // Reserve attribute id in DAG
109  for (auto attr : impl->attributes()) {
110  __dag.addNodeWithId(attr->id());
111  }
112  }
113  }
114  }
115 
116  template < typename GUM_SCALAR >
118  GUM_DESTRUCTOR(PRMClass);
119 
120  for (const auto& elt : __nodeIdMap) {
121  delete elt.second;
122  }
123 
124  if (__implements) { delete __implements; }
125 
126  if (__bijection) { delete __bijection; }
127  }
128 
129  template < typename GUM_SCALAR >
131  if (__superClass) {
132  __superClass->__addExtension(this);
133  // Adding implemented interfaces, if any
134  if (__superClass->__implements) {
135  if (!__implements) {
136  __implements = new Set< PRMInterface< GUM_SCALAR >* >(
137  *(__superClass->__implements));
138  } else {
139  for (auto i : *(__superClass->__implements)) {
140  __implements->insert(i);
141  }
142  }
143  }
144  }
145  if (__implements) { __implementInterfaces(true); }
146  }
147 
148  template < typename GUM_SCALAR >
150  if (__superClass) {
151  // Copying reference slots
152  for (const auto c_refslot : __superClass->__referenceSlots) {
153  auto ref = new PRMReferenceSlot< GUM_SCALAR >(
154  c_refslot->name(),
156  c_refslot->slotType()),
157  c_refslot->isArray());
158 
159  ref->setId(c_refslot->id());
160  // Not reserved by an interface
161  if (!__dag.existsNode(ref->id())) { __dag.addNodeWithId(ref->id()); }
162  __nodeIdMap.insert(ref->id(), ref);
163  __referenceSlots.insert(ref);
164 
165  if (__superClass->__nameMap[c_refslot->name()]
166  == __superClass->__nameMap[c_refslot->safeName()]) {
167  __nameMap.insert(ref->name(), ref);
168  }
169 
170  __nameMap.insert(ref->safeName(), ref);
171  }
172  }
173  }
174 
175  template < typename GUM_SCALAR >
177  if (__superClass) {
178  // Copying parameters
179  for (const auto c_param : __superClass->__parameters) {
180  auto param = new PRMParameter< GUM_SCALAR >(
181  c_param->name(), c_param->valueType(), c_param->value());
182 
183  __parameters.insert(param);
184 
185  param->setId(c_param->id());
186  __dag.addNodeWithId(param->id());
187  __nodeIdMap.insert(param->id(), param);
188  __nameMap.insert(param->name(), param);
189  }
190  }
191  }
192 
193  template < typename GUM_SCALAR >
195  if (__superClass) {
196  for (const auto c_attr : __superClass->__attributes) {
197  // using multiDimSparse to prevent unecessary memory allocation for
198  // large arrays (the potentials are copied latter)
199  auto attr = c_attr->newFactory(*this);
200 
201  __bijection->insert(&(c_attr->type().variable()),
202  &(attr->type().variable()));
203  attr->setId(c_attr->id());
204  try {
205  __dag.addNodeWithId(attr->id());
206  } catch (gum::Exception&) {
207  // Node reserved by an interface
208  }
209  __nodeIdMap.insert(attr->id(), attr);
210  __attributes.insert(attr);
211 
212  if (__superClass->__nameMap[c_attr->name()]
213  == __superClass->__nameMap[c_attr->safeName()]) {
214  __nameMap.insert(attr->name(), attr);
215  }
216 
217  __nameMap.insert(attr->safeName(), attr);
218  }
219  }
220  }
221 
222  template < typename GUM_SCALAR >
224  if (__superClass) {
225  for (const auto c_agg : __superClass->__aggregates) {
226  PRMAggregate< GUM_SCALAR >* agg = nullptr;
227 
228  try {
229  agg = new PRMAggregate< GUM_SCALAR >(
230  c_agg->name(), c_agg->agg_type(), c_agg->type(), c_agg->label());
231  } catch (OperationNotAllowed&) {
232  agg = new PRMAggregate< GUM_SCALAR >(
233  c_agg->name(), c_agg->agg_type(), c_agg->type());
234  agg->sharedLabel(c_agg->sharedLabel());
235  agg->setLabel(c_agg->labelValue());
236  }
237 
238  __bijection->insert(&(c_agg->type().variable()),
239  &(agg->type().variable()));
240  agg->setId(c_agg->id());
241  __dag.addNodeWithId(agg->id());
242  __nodeIdMap.insert(agg->id(), agg);
243  __aggregates.insert(agg);
244 
245  if (__superClass->__nameMap[c_agg->name()]
246  == __superClass->__nameMap[c_agg->safeName()])
247  __nameMap.insert(agg->name(), agg);
248 
249  __nameMap.insert(agg->safeName(), agg);
250  }
251  }
252  }
253 
254  template < typename GUM_SCALAR >
256  if (__superClass) {
257  // Copying slot chains
258  for (const auto c_sc : __superClass->__slotChains) {
259  // Because of aggregators, some slotchains may exists already
260  if (!(__nameMap.exists(c_sc->name())
261  && __nameMap.exists(c_sc->safeName()))) {
262  // We just need to change the first PRMReferenceSlot<GUM_SCALAR> in
263  // the
264  // chain
265  auto chain = c_sc->chain();
266 
267  chain.setAtPos(0, __nameMap[c_sc->chain().front()->name()]);
268 
269  auto sc = new PRMSlotChain< GUM_SCALAR >(c_sc->name(), chain);
270  __bijection->insert(&(c_sc->type().variable()),
271  &(sc->type().variable()));
272  sc->setId(c_sc->id());
273  __dag.addNodeWithId(sc->id());
274  __nodeIdMap.insert(sc->id(), sc);
275  __slotChains.insert(sc);
276 
277  if (!__nameMap.exists(sc->name())) {
278  __nameMap.insert(sc->name(), sc);
279  }
280  if (!__nameMap.exists(sc->safeName())) {
281  __nameMap.insert(sc->safeName(), sc);
282  }
283  }
284  }
285  }
286  }
287 
288  template < typename GUM_SCALAR >
289  void PRMClass< GUM_SCALAR >::completeInheritance(const std::string& name) {
290  if (__superClass) {
291  auto& elt = this->get(name);
295  "you can only complete inheritance for attributes");
296  }
297 
298  for (const auto& prnt : super().containerDag().parents(elt.id())) {
299  this->addArc(super().get(prnt).safeName(), elt.safeName());
300  }
301 
303  auto& attr = static_cast< PRMAttribute< GUM_SCALAR >& >(elt);
304  auto& super_attr =
305  static_cast< const PRMAttribute< GUM_SCALAR >& >(super().get(name));
306  attr.copyCpf(*__bijection, super_attr);
307  }
308  }
309  }
310 
311  template < typename GUM_SCALAR >
313  if (__superClass) {
314  __superClass->__addExtension(this);
315  // Adding implemented interfaces of c, if any
316  if (c.__implements) {
317  if (!__implements) {
318  __implements =
320  } else {
321  for (auto i : *(c.__implements)) {
322  __implements->insert(i);
323  }
324  }
325  }
326 
327  // Copying attributes, the bijection's firsts are attributes in this and
328  // its
329  // seconds are attributes
330  // in c.
332 
333  // Copying parameters
334  for (const auto c_param : c.__parameters) {
335  auto param = new PRMParameter< GUM_SCALAR >(
336  c_param->name(), c_param->valueType(), c_param->value());
337 
338  __parameters.insert(param);
339 
340  param->setId(c_param->id());
341  __nodeIdMap.insert(param->id(), param);
342  __nameMap.insert(param->name(), param);
343  }
344 
345  // Copying attributes
346  for (const auto c_attr : c.__attributes) {
347  // using multiDimSparse to prevent unecessary memory allocation for
348  // large arrays (the potentials are copied latter)
349  auto attr = c_attr->newFactory(*this);
350 
351  bij.insert(&(c_attr->type().variable()), &(attr->type().variable()));
352  attr->setId(c_attr->id());
353  __nodeIdMap.insert(attr->id(), attr);
354  __attributes.insert(attr);
355 
356  if (c.__nameMap[c_attr->name()] == c.__nameMap[c_attr->safeName()]) {
357  __nameMap.insert(attr->name(), attr);
358  }
359 
360  __nameMap.insert(attr->safeName(), attr);
361  }
362 
363  // Copying aggregates
364  for (const auto c_agg : c.__aggregates) {
365  PRMAggregate< GUM_SCALAR >* agg = nullptr;
366 
367  try {
368  agg = new PRMAggregate< GUM_SCALAR >(
369  c_agg->name(), c_agg->agg_type(), c_agg->type(), c_agg->label());
370  } catch (OperationNotAllowed&) {
371  agg = new PRMAggregate< GUM_SCALAR >(
372  c_agg->name(), c_agg->agg_type(), c_agg->type());
373  }
374 
375  bij.insert(&(c_agg->type().variable()), &(agg->type().variable()));
376  agg->setId(c_agg->id());
377  __nodeIdMap.insert(agg->id(), agg);
378  __aggregates.insert(agg);
379 
380  if (c.__nameMap[c_agg->name()] == c.__nameMap[c_agg->safeName()])
381  __nameMap.insert(agg->name(), agg);
382 
383  __nameMap.insert(agg->safeName(), agg);
384  }
385 
386  // Copying reference slots
387  for (const auto c_refslot : c.__referenceSlots) {
389  c_refslot->name(),
391  c_refslot->slotType()),
392  c_refslot->isArray());
393 
394  ref->setId(c_refslot->id());
395  __nodeIdMap.insert(ref->id(), ref);
396  __referenceSlots.insert(ref);
397 
398  if (c.__nameMap[c_refslot->name()] == c.__nameMap[c_refslot->safeName()])
399  __nameMap.insert(ref->name(), ref);
400 
401  __nameMap.insert(ref->safeName(), ref);
402  }
403 
404  // Copying slot chains
405  for (const auto c_slotchain : c.__slotChains) {
406  // We just need to change the first PRMReferenceSlot<GUM_SCALAR> in
407  // the
408  // chain
409  Sequence< PRMClassElement< GUM_SCALAR >* > chain(c_slotchain->chain());
410 
411  chain.setAtPos(0, __nameMap[c_slotchain->chain().front()->name()]);
412 
414  new PRMSlotChain< GUM_SCALAR >(c_slotchain->name(), chain);
415  bij.insert(&(c_slotchain->type().variable()), &(sc->type().variable()));
416  sc->setId(c_slotchain->id());
417  __nodeIdMap.insert(sc->id(), sc);
418  __slotChains.insert(sc);
419 
420  __nameMap.insert(sc->name(), sc);
421  __nameMap.insert(sc->safeName(), sc);
422  }
423 
424  // Copying dependencies yield by arcs
425  for (const auto& arc : c.containerDag().arcs()) {
426  __nodeIdMap[arc.tail()]->addChild(*(__nodeIdMap[arc.head()]));
427  __nodeIdMap[arc.head()]->addParent(*(__nodeIdMap[arc.tail()]));
428  }
429 
430  // Copying the IO flag
431  this->_copyIOFlags(c);
432  // Copying content of CPF
433  for (const auto attr : c.__attributes) {
434  auto a = static_cast< PRMAttribute< GUM_SCALAR >* >(
435  __nameMap[attr->safeName()]);
436  a->copyCpf(bij, *attr);
437  }
438  }
439  }
440 
441  template < typename GUM_SCALAR >
443  const PRMClassElementContainer< GUM_SCALAR >& cec) const {
444  switch (cec.obj_type()) {
445  case PRMObject::prm_type::CLASS: {
446  const PRMClass< GUM_SCALAR >* current = this;
447 
448  while (current != 0) {
449  if (current == &(cec)) return true;
450 
451  current = current->__superClass;
452  }
453 
454  return false;
455  }
456 
457  case PRMObject::prm_type::PRM_INTERFACE: {
458  if (__implements != nullptr) {
459  const PRMInterface< GUM_SCALAR >& i =
460  static_cast< const PRMInterface< GUM_SCALAR >& >(cec);
461 
462  if (__implements->exists(
463  const_cast< PRMInterface< GUM_SCALAR >* >(&i)))
464  return true;
465 
466  for (const auto impl : *__implements)
467  if (impl->isSubTypeOf(i)) return true;
468  }
469 
470  return false;
471  }
472 
473  default: {
474  GUM_ERROR(FatalError, "unknown ClassElementContainer<GUM_SCALAR>");
475  }
476  }
477  }
478 
479  template < typename GUM_SCALAR >
480  void PRMClass< GUM_SCALAR >::addArc(const std::string& tail_name,
481  const std::string& head_name) {
484 
485  try {
486  tail = __nameMap[tail_name];
487  head = __nameMap[head_name];
488  } catch (NotFound&) {
490  "tail and/or head of arc does not exists in this Class");
491  }
492 
496  "a PRMReferenceSlot<GUM_SCALAR> can "
497  "not on neither side of an arc");
498  }
499 
503  "illegal insertion of an arc between two SlotChain<GUM_SCALAR>");
504  }
505 
506  if (!__dag.existsArc(Arc(tail->id(), head->id()))) {
507  __dag.addArc(tail->id(), head->id());
508  } else {
510  "duplicate arc " << tail_name << "->" << head_name);
511  }
512 
513  get(tail->id()).addChild(get(head->id()));
514  get(head->id()).addParent(get(tail->id()));
515 
516  // Defining input / output nodes
519  static_cast< PRMSlotChain< GUM_SCALAR >* >(tail);
520  this->setInputNode(*head, true);
521  sc->end().setOutputNode(sc->end().get(sc->lastElt().safeName()), true);
522  }
523  }
524 
525  template < typename GUM_SCALAR >
528  try {
529  for (auto i : implements()) {
530  if (i->exists(elt->name())) { __checkInterface(elt, i); }
531  }
532  } catch (NotFound&) {
533  // No interface
534  }
535  }
536 
537  template < typename GUM_SCALAR >
538  void
541  const auto& i_elt = i->get(elt->name());
542  bool is_attr = PRMClassElement< GUM_SCALAR >::isAttribute(i_elt);
543  bool is_agg = PRMClassElement< GUM_SCALAR >::isAggregate(i_elt);
544 
545  if (!(is_attr || is_agg)) {
546  GUM_ERROR(OperationNotAllowed, "Class does not respect it's interface");
547  }
548 
549  if (!elt->type().isSubTypeOf(i_elt.type())) {
551  "Attribute type does not respect class interface");
552  }
553 
554  if (elt->type() != i_elt.type()) {
555  if (!this->exists(i_elt.safeName())) {
557  "Attribute type does not respect class interface");
558  }
559  elt = &(this->get(i_elt.safeName()));
560  }
561 
562  // Node must be reserved by constructor
563  if (!__dag.existsNode(i_elt.id())) {
564  GUM_ERROR(FatalError, "Class does not reserved implemented nodes");
565  }
566 
567  // Removing unused node and changing to proper node
568  if (elt->id() != i_elt.id()) {
569  // Update cast descendants
570  for (auto child : __dag.children(elt->id())) {
571  __dag.addArc(i_elt.id(), child);
572  }
573  __dag.eraseNode(elt->id());
574  }
575  __nodeIdMap.erase(elt->id());
576  elt->setId(i_elt.id());
577  __nodeIdMap.insert(elt->id(), elt);
578  }
579 
580  template < typename GUM_SCALAR >
583  try {
584  for (auto i : implements()) {
585  if (i->exists(ref->name())) { __checkRefInterface(ref, i); }
586  }
587  } catch (NotFound&) {
588  // No interface to check
589  }
590  }
591 
592  template < typename GUM_SCALAR >
595  auto& i_elt = i->get(ref->name());
596  if (i_elt.elt_type() != ref->elt_type()) {
597  GUM_ERROR(OperationNotAllowed, "Class does not respect it's interface");
598  }
599  auto& i_ref = static_cast< PRMReferenceSlot< GUM_SCALAR >& >(i_elt);
600  if (!ref->slotType().isSubTypeOf(i_ref.slotType())) {
602  "ReferenceSlot type does not respect class interface");
603  }
604  // Node must be reserved by constructor
605  if (!__dag.exists(i_ref.id())) {
607  "class " << this->name() << " does not respect interface "
608  << i->name() << " implementation");
609  }
610  // Removing unused node and changin to propoer node
611  if (ref->id() != i_ref.id()) { __dag.eraseNode(ref->id()); }
612  __nodeIdMap.erase(ref->id());
613  ref->setId(i_ref.id());
614  __nodeIdMap.insert(ref->id(), ref);
615  }
616 
617  template < typename GUM_SCALAR >
619  if (__nameMap.exists(elt->name())) {
621  "name " << elt->name()
622  << " already used by another ClassElement");
623  }
624 
625  elt->setId(nextNodeId());
626  __dag.addNodeWithId(elt->id());
627  __nodeIdMap.insert(elt->id(), elt);
628  __nameMap.insert(elt->name(), elt);
629 
630  try {
631  __nameMap.insert(elt->safeName(), elt);
632  } catch (DuplicateElement& e) {
635  throw DuplicateElement(e);
636  }
637  }
638 
639  switch (elt->elt_type()) {
641  __attributes.insert(static_cast< PRMAttribute< GUM_SCALAR >* >(elt));
642  __addCastDescendants(static_cast< PRMAttribute< GUM_SCALAR >* >(elt));
643 
644  // Update attribute or cast descendant id to respect implemented
645  // interface
646  __checkInterfaces(elt);
647 
648  __addIOInterfaceFlags(elt);
649  break;
650  }
651 
653  __aggregates.insert(static_cast< PRMAggregate< GUM_SCALAR >* >(elt));
654  __addCastDescendants(static_cast< PRMAttribute< GUM_SCALAR >* >(elt));
655 
656  // Update attribute or cast descendant id to respect implemented
657  // interface
658  __checkInterfaces(elt);
659 
660  __addIOInterfaceFlags(elt);
661  break;
662  }
663 
665  auto ref = static_cast< PRMReferenceSlot< GUM_SCALAR >* >(elt);
666  __referenceSlots.insert(ref);
667 
668  // Updating ref's id if ref implements an interface
669  __checkRefInterfaces(ref);
670  break;
671  }
672 
674  __slotChains.insert(static_cast< PRMSlotChain< GUM_SCALAR >* >(elt));
675  break;
676  }
677 
679  __parameters.insert(static_cast< PRMParameter< GUM_SCALAR >* >(elt));
680  break;
681  }
682 
683  default: {
684  GUM_ERROR(FatalError, "unknown ClassElement<GUM_SCALAR> type");
685  }
686  }
687 
688  return elt->id();
689  }
690 
691  template < typename GUM_SCALAR >
694  auto parent = attr;
695  PRMAttribute< GUM_SCALAR >* child = 0;
696 
697  while (parent->type().isSubType()) {
698  child = parent->getCastDescendant();
699 
700  // Check if id was reserved by one of the class interfaces
701  bool found = false;
702  try {
703  for (auto i : implements()) {
704  if (i->exists(child->safeName())) {
705  child->setId(i->get(child->safeName()).id());
706  found = true;
707  break;
708  }
709  }
710  } catch (NotFound&) {
711  // No interface
712  }
713  if (!found) {
714  child->setId(nextNodeId());
715  __dag.addNodeWithId(child->id());
716  }
717  __nodeIdMap.insert(child->id(), child);
718  // Only use child's safe name when adding to the name map!
719  __nameMap.insert(child->safeName(), child);
720  __attributes.insert(child);
721  // Do not use Class<GUM_SCALAR>::insertArc(), child's CPF is already
722  // initialized properly
723  __dag.addArc(parent->id(), child->id());
724 
725  parent = child;
726  }
727  }
728 
729  template < typename GUM_SCALAR >
731  PRMClassElement< GUM_SCALAR >* overloader) {
732  try {
733  if (!super().exists(overloader->name())) {
735  "found no ClassElement<GUM_SCALAR> to overload");
736  }
737  } catch (NotFound&) {
739  "overload is possible only with subclasses");
740  }
741 
742  PRMClassElement< GUM_SCALAR >* overloaded = __nameMap[overloader->name()];
743  if (overloaded == overloader) {
745  "dupplicate ClassElement " << overloader->name());
746  }
747  // Checking overload legality
748  if (!__checkOverloadLegality(overloaded, overloader)) {
749  GUM_ERROR(OperationNotAllowed, "illegal overload");
750  }
751 
752  switch (overloader->elt_type()) {
754  auto overloader_attr =
755  static_cast< PRMAttribute< GUM_SCALAR >* >(overloader);
756  auto overloaded_attr =
757  static_cast< PRMAttribute< GUM_SCALAR >* >(overloaded);
758  __overloadAttribute(overloader_attr, overloaded_attr);
759  __addIOInterfaceFlags(overloader);
760  break;
761  }
762 
764  __overloadAggregate(
765  static_cast< PRMAggregate< GUM_SCALAR >* >(overloader), overloaded);
766  __addIOInterfaceFlags(overloader);
767  break;
768  }
769 
771  // __checkOverloadLegality guaranties that overloaded is a
772  // PRMReferenceSlot<GUM_SCALAR>
773  auto overloader_ref =
774  static_cast< PRMReferenceSlot< GUM_SCALAR >* >(overloader);
775  auto overloaded_ref =
776  static_cast< PRMReferenceSlot< GUM_SCALAR >* >(overloaded);
777  __overloadReference(overloader_ref, overloaded_ref);
778  break;
779  }
780 
783  "SlotChain<GUM_SCALAR> can not be overloaded");
784  break;
785  }
786 
788  auto overloaded_param =
789  static_cast< PRMParameter< GUM_SCALAR >* >(overloaded);
790  auto overloader_param =
791  static_cast< PRMParameter< GUM_SCALAR >* >(overloader);
792  __overloadParameter(overloader_param, overloaded_param);
793  break;
794  }
795  default: {
796  GUM_ERROR(OperationNotAllowed, "unknown ClassElement<GUM_SCALAR> type");
797  }
798  }
799 
800  return overloader->id();
801  }
802 
803  template < typename GUM_SCALAR >
805  PRMAttribute< GUM_SCALAR >* overloader,
806  PRMAttribute< GUM_SCALAR >* overloaded) {
807  __dag.eraseParents(overloaded->id());
808 
809  // Checking if we have to add cast descendant
810  if (overloader->type() != overloaded->type()) {
811  overloader->setId(nextNodeId());
812  __dag.addNodeWithId(overloader->id());
813  __nodeIdMap.insert(overloader->id(), overloader);
814  __nameMap[overloader->name()] = overloader;
815  __nameMap.insert(overloader->safeName(), overloader);
816  __attributes.insert(overloader);
817  __addCastDescendants(overloader, overloaded);
818  } else {
819  overloader->setId(overloaded->id());
820  __nodeIdMap[overloader->id()] = overloader;
821  __nameMap[overloader->name()] = overloader;
822  __nameMap[overloader->safeName()] = overloader;
823  __attributes.erase(overloaded);
824  __attributes.insert(overloader);
825  overloader->overload(overloaded);
826  delete overloaded;
827  }
828  }
829 
830  template < typename GUM_SCALAR >
832  PRMReferenceSlot< GUM_SCALAR >* overloader,
833  PRMReferenceSlot< GUM_SCALAR >* overloaded) {
834  // Adding overloading reference
835  overloader->setId(overloaded->id());
836  __nodeIdMap[overloader->id()] = overloader;
837  __nameMap[overloader->name()] = overloader;
838  __nameMap.insert(overloader->safeName(), overloader);
839  __referenceSlots.insert(overloader);
843  std::vector< PRMSlotChain< GUM_SCALAR >* > toRemove, toAdd;
844 
845  // Updating PRMSlotChain<GUM_SCALAR> which started with overloaded
846  for (const auto slotchain : __slotChains) {
847  // If the attribute pointed by this slotchain is overloaded, we need to
848  // change the slotchain
849  // names to it's safename version: ref.attr is replaced by
850  // ref.(type)attr.
851  if ((slotchain->chain().atPos(0) == overloaded)) {
853  seq.insert(overloader);
854 
855  auto elt = ++(slotchain->chain().begin());
856 
857  while (elt != slotchain->chain().end()) {
858  ref = static_cast< PRMReferenceSlot< GUM_SCALAR >* >(seq.back());
859  next = &(ref->slotType().get((*elt)->name()));
860  seq.insert(next);
861  ++elt;
862  }
863 
864  // If the slotchain last element type changes, we change the slotchain
865  // to
866  // point towards the cast decendant
867  // with the correct type
868  if (seq.back()->type() != slotchain->lastElt().type()) {
869  seq.erase(seq.back());
870  seq.insert(&(static_cast< PRMReferenceSlot< GUM_SCALAR >* >(seq.back())
871  ->slotType()
872  .get(slotchain->lastElt().safeName())));
873  std::string sc_name;
874  std::string dot = ".";
875 
876  for (Size i = 0; i < seq.size() - 1; ++i) {
877  sc_name += seq.atPos(i)->name() + dot;
878  }
879 
880  sc_name += seq.back()->safeName();
881  sc = new PRMSlotChain< GUM_SCALAR >(sc_name, seq);
882  sc->setId(slotchain->id());
883 
884  for (const auto child : this->containerDag().children(sc->id())) {
885  auto& elt = get(child);
887  auto& attr = static_cast< PRMAttribute< GUM_SCALAR >& >(elt);
888  auto& old_type = slotchain->lastElt().type();
889  auto& new_type = sc->lastElt().type();
890  attr.swap(old_type, new_type);
891  } else {
892  GUM_ERROR(OperationNotAllowed, "unexpected ClassElement");
893  // get( child ).cpf().replace(
894  // slotchain->lastElt().type().variable(),
895  // sc->lastElt().type().variable() );
896  }
897  }
898 
899  toAdd.push_back(sc);
900  toRemove.push_back(slotchain);
901  } else {
902  // Types are identical, we just need to change the first reference
903  slotchain->chain().setAtPos(0, overloader);
904  }
905  }
906  }
907 
908  for (const auto torem : toRemove) {
909  __nameMap.erase(torem->name());
910  __slotChains.erase(torem);
911  delete torem;
912  }
913 
914  for (const auto toadd : toAdd) {
915  __nameMap.insert(toadd->name(), toadd);
916  __nodeIdMap[toadd->id()] = toadd;
917  __slotChains.insert(sc);
918  }
919 
920  // Removing overloaded PRMReferenceSlot<GUM_SCALAR>
921  __referenceSlots.erase(overloaded);
922  __nameMap.erase(overloaded->safeName());
923  delete overloaded;
924  }
925 
926  template < typename GUM_SCALAR >
928  PRMParameter< GUM_SCALAR >* overloader,
929  PRMParameter< GUM_SCALAR >* overloaded) {
930  overloader->setId(overloaded->id());
931  __nodeIdMap[overloader->id()] = overloader;
932  __nameMap[overloader->name()] = overloader;
933  __nameMap[overloader->safeName()] = overloader;
934  __parameters.erase(overloaded);
935  __parameters.insert(overloader);
936  delete overloaded;
937  }
938 
939  template < typename GUM_SCALAR >
942  PRMAttribute< GUM_SCALAR >* parent = start;
943  PRMAttribute< GUM_SCALAR >* child = 0;
944 
945  while (parent->type().superType() != end->type()) {
946  child = parent->getCastDescendant();
947  child->setId(nextNodeId());
948  __nodeIdMap.insert(child->id(), child);
949  __dag.addNodeWithId(child->id());
950  // Only use child's safe name when adding to the name map!
951  __nameMap.insert(child->safeName(), child);
952  __attributes.insert(child);
953  __addIOInterfaceFlags(child);
954  // Do not use Class<GUM_SCALAR>::insertArc(), child's CPF is already
955  // initialized properly
956  __dag.addArc(parent->id(), child->id());
957  parent = child;
958  }
959 
960  parent->setAsCastDescendant(end);
961  __dag.addArc(parent->id(), end->id());
962  }
963 
964  template < typename GUM_SCALAR >
967  for (auto ext : __extensions) {
968  set.insert(ext);
969  ext->_findAllSubtypes(set);
970  }
971  }
972 
973  template < typename GUM_SCALAR >
976  // We only add IO Flags if elt matches is required by and interface
977  if (__implements != nullptr) {
978  for (const auto impl : *__implements) {
979  PRMInterface< GUM_SCALAR >* super = impl;
980  while (super) {
981  // If the attribute is defined in an interface, we set it as an
982  // OutputNode
983  if (impl->exists(elt->name())) {
984  try {
985  this->_getIOFlag(*elt).second = true;
986  } catch (NotFound&) {
987  this->_setIOFlag(*elt, std::make_pair(false, true));
988  }
989  }
990  try {
991  super = &(super->super());
992  } catch (NotFound&) { super = nullptr; }
993  }
994  }
995  }
996  }
997 
998  template < typename GUM_SCALAR >
1000  const PRMClassElement< GUM_SCALAR >& elt) {
1001  // for ( const auto ext : __extensions ) {
1002  // // We test to prevent unnecessary recursive call from iter
1003  // if ( !ext->isOutputNode( elt ) ) {
1004  // ext->setOutputNode( elt, true );
1005  // }
1006  //}
1007  }
1008 
1009  template < typename GUM_SCALAR >
1011  return PRMObject::prm_type::CLASS;
1012  }
1013 
1014  template < typename GUM_SCALAR >
1015  INLINE const DAG& PRMClass< GUM_SCALAR >::_dag() const {
1016  return __dag;
1017  }
1018 
1019  template < typename GUM_SCALAR >
1021  return __dag;
1022  }
1023 
1024  template < typename GUM_SCALAR >
1026  try {
1027  return *(__nodeIdMap[id]);
1028  } catch (NotFound&) {
1029  GUM_ERROR(NotFound, "no ClassElement<GUM_SCALAR> with the given NodeId");
1030  }
1031  }
1032 
1033  template < typename GUM_SCALAR >
1034  INLINE const PRMClassElement< GUM_SCALAR >&
1036  try {
1037  return *(__nodeIdMap[id]);
1038  } catch (NotFound&) {
1040  "no ClassElement<GUM_SCALAR> with the given NodeId (" << id
1041  << ")");
1042  }
1043  }
1044 
1045  template < typename GUM_SCALAR >
1047  PRMClass< GUM_SCALAR >::get(const std::string& name) {
1048  try {
1049  return *(__nameMap[name]);
1050  } catch (NotFound&) {
1052  "no ClassElement<GUM_SCALAR> with the given name (" << name
1053  << ")");
1054  }
1055  }
1056 
1057  template < typename GUM_SCALAR >
1058  INLINE const PRMClassElement< GUM_SCALAR >&
1059  PRMClass< GUM_SCALAR >::get(const std::string& name) const {
1060  try {
1061  return *(__nameMap[name]);
1062  } catch (NotFound&) {
1064  "no ClassElement<GUM_SCALAR> with the given name (" << name
1065  << ")");
1066  }
1067  }
1068 
1069  template < typename GUM_SCALAR >
1070  INLINE const Set< PRMAttribute< GUM_SCALAR >* >&
1072  return __attributes;
1073  }
1074 
1075  template < typename GUM_SCALAR >
1076  INLINE const Set< PRMParameter< GUM_SCALAR >* >&
1078  return __parameters;
1079  }
1080 
1081  // Private struct for retrieving all params in scope
1082  template < typename GUM_SCALAR >
1084  std::string prefix;
1087 
1088  ParamScopeData(const std::string& s,
1089  const PRMReferenceSlot< GUM_SCALAR >& ref,
1090  Idx d) :
1091  prefix(s + ref.name() + "."),
1092  c(static_cast< const PRMClass< GUM_SCALAR >* >(&(ref.slotType()))),
1093  depth(d) {}
1094  };
1095 
1096  template < typename GUM_SCALAR >
1100 
1101  for (const auto p : parameters()) {
1102  params.insert(p->name(), p);
1103  }
1104 
1105  std::queue< ParamScopeData< GUM_SCALAR > > queue;
1106 
1107  for (const auto ref : referenceSlots()) {
1108  if (PRMObject::isClass(ref->slotType())) {
1109  queue.push(ParamScopeData< GUM_SCALAR >("", *ref, 1));
1110  }
1111  }
1112 
1113  while (!queue.empty()) {
1114  auto data = queue.front();
1115  queue.pop();
1116 
1117  if (data.depth < 5) {
1118  for (const auto p : data.c->parameters()) {
1119  params.insert(data.prefix + p->name(), p);
1120  }
1121 
1122  for (const auto ref : data.c->referenceSlots()) {
1123  if (PRMObject::isClass(ref->slotType())) {
1124  queue.push(
1125  ParamScopeData< GUM_SCALAR >(data.prefix, *ref, data.depth + 1));
1126  }
1127  }
1128  } else {
1129  // @todo depth>5 is a workaround. Cycle detection is needed here !
1130  GUM_TRACE("Depth limit reached when looking up parameters");
1131  }
1132  }
1133 
1134  return params;
1135  }
1136 
1137  template < typename GUM_SCALAR >
1138  INLINE const Set< PRMAggregate< GUM_SCALAR >* >&
1140  return __aggregates;
1141  }
1142 
1143  template < typename GUM_SCALAR >
1144  INLINE const Set< PRMReferenceSlot< GUM_SCALAR >* >&
1146  return __referenceSlots;
1147  }
1148 
1149  template < typename GUM_SCALAR >
1150  INLINE const Set< PRMSlotChain< GUM_SCALAR >* >&
1152  return __slotChains;
1153  }
1154 
1155  template < typename GUM_SCALAR >
1157  if (__superClass) {
1158  return *__superClass;
1159  } else {
1160  GUM_ERROR(NotFound, "this Class is not a subclass");
1161  }
1162  }
1163 
1164  template < typename GUM_SCALAR >
1165  INLINE const Set< PRMInterface< GUM_SCALAR >* >&
1167  if (__implements) {
1168  return *__implements;
1169  } else {
1171  "this Class does not implement any Interface<GUM_SCALAR>");
1172  }
1173  }
1174 
1175  template < typename GUM_SCALAR >
1178  return get(id);
1179  }
1180 
1181  template < typename GUM_SCALAR >
1183  operator[](NodeId id) const {
1184  return get(id);
1185  }
1186 
1187  template < typename GUM_SCALAR >
1189  operator[](const std::string& name) {
1190  return get(name);
1191  }
1192 
1193  template < typename GUM_SCALAR >
1195  operator[](const std::string& name) const {
1196  return get(name);
1197  }
1198 
1199  template < typename GUM_SCALAR >
1201  PRMAggregate< GUM_SCALAR >* overloader,
1202  PRMClassElement< GUM_SCALAR >* overloaded) {
1203  __nameMap.insert(overloader->safeName(), overloader);
1204  __aggregates.insert(overloader);
1205  }
1206 
1207  template < typename GUM_SCALAR >
1209  const PRMClassElement< GUM_SCALAR >* overloaded,
1210  const PRMClassElement< GUM_SCALAR >* overloader) {
1211  if (overloaded->elt_type() != overloader->elt_type()) { return false; }
1212 
1213  switch (overloaded->elt_type()) {
1215  if (!overloader->type().isSubTypeOf(overloaded->type())) {
1216  return false;
1217  }
1218  break;
1219  }
1220 
1222  const auto& new_slot_type =
1223  static_cast< const PRMReferenceSlot< GUM_SCALAR >* >(overloader)
1224  ->slotType();
1225  const auto& old_slot_type =
1226  static_cast< const PRMReferenceSlot< GUM_SCALAR >* >(overloaded)
1227  ->slotType();
1228 
1229  if (!new_slot_type.isSubTypeOf(old_slot_type)) { return false; }
1230 
1231  break;
1232  }
1233 
1235  auto overloaded_param =
1236  static_cast< const PRMParameter< GUM_SCALAR >* >(overloaded);
1237  auto overloader_param =
1238  static_cast< const PRMParameter< GUM_SCALAR >* >(overloader);
1239 
1240  return overloaded_param->valueType() == overloader_param->valueType();
1241  break;
1242  }
1243 
1244  default: { return false; }
1245  }
1246  return true;
1247  }
1248 
1249  template < typename GUM_SCALAR >
1250  INLINE const Set< PRMClass< GUM_SCALAR >* >&
1252  return __extensions;
1253  }
1254 
1255  template < typename GUM_SCALAR >
1257  __extensions.insert(c);
1258  }
1259 
1260  template < typename GUM_SCALAR >
1262  const std::string& safe_name) const {
1263  const PRMClassElement< GUM_SCALAR >& elt = get(safe_name);
1264 
1265  try {
1266  return elt.type().name() == get(elt.name()).type().name();
1267  } catch (OperationNotAllowed&) {
1268  GUM_ERROR(NotFound, "no attribute with the given name");
1269  }
1270  }
1271 
1272  template < typename GUM_SCALAR >
1274  const PRMClassElement< GUM_SCALAR >& elt) const {
1275  try {
1276  if (!this->_getIOFlag(elt).second) {
1277  if (__implements) {
1278  for (auto i : *__implements) {
1279  if (i->isOutputNode(elt)) { return true; }
1280  }
1281  }
1282 
1283  if (__superClass && (__superClass->isOutputNode(elt))) { return true; }
1284 
1285  } else {
1286  return true;
1287  }
1288  } catch (NotFound&) {}
1289  return false;
1290  }
1291 
1292 
1293  } /* namespace prm */
1294 } /* namespace gum */
void insert(const T1 &first, const T2 &second)
Inserts a new association in the gum::Bijection.
PRMParameter is a member of a Class in a PRM.
Definition: PRMParameter.h:49
PRMClass< GUM_SCALAR > * __superClass
The alternate PRMClassElementContainer<GUM_SCALAR> searched for elements defined in this...
Definition: PRMClass.h:388
virtual PRMAttribute< GUM_SCALAR > * getCastDescendant() const =0
Returns a proper cast descendant of this PRMAttribute.
const std::string & name() const
Returns the name of this object.
Definition: PRMObject_inl.h:32
const PRMClass< GUM_SCALAR > * c
Size size() const noexcept
Returns the size of the sequence.
Definition: sequence_tpl.h:35
virtual PRMType & type()=0
See gum::PRMClassElement::type().
Headers of gum::prm::Class<GUM_SCALAR>.
The generic class for storing (ordered) sequences of objects.
Definition: sequence.h:1019
virtual prm_type obj_type() const =0
Returns the type of this object.
Abstract class representing an element of PRM class.
Set< PRMReferenceSlot< GUM_SCALAR > *> __referenceSlots
The sequence of PRMReferenceSlot<GUM_SCALAR>.
Definition: PRMClass.h:359
Base class for discrete random variable.
Set< PRMAggregate< GUM_SCALAR > *> __aggregates
The sequence of aggregate.
Definition: PRMClass.h:362
virtual PRMType & type()
This is similar to the following call: this->lastElt().type()
gum is the global namespace for all aGrUM entities
Definition: agrum.h:25
Headers of gum::prm::PRMInterface.
void setLabel(Idx idx)
Set the aggregator&#39;s label.
A PRMReferenceSlot represent a relation between two PRMClassElementContainer.
Definition: PRMObject.h:220
PRMClassElementContainer< GUM_SCALAR > & slotType()
Returns the type of this slot, which is a PRMClassElementContainer (it is not the type of PRMObject)...
The class for generic Hash Tables.
Definition: hashTable.h:676
void _findAllSubtypes(Set< PRMClassElementContainer< GUM_SCALAR > * > &set)
Fills set with all the subtypes of this Class<GUM_SCALAR>.
Definition: PRMClass_tpl.h:965
Set< PRMSlotChain< GUM_SCALAR > *> __slotChains
The set of gum::PRMSlotChain<GUM_SCALAR>s.
Definition: PRMClass.h:365
virtual PRMClassElement< GUM_SCALAR >::ClassElementType elt_type() const
Implementation of the pure virtual method of PRMObject.
Set< PRMInterface< GUM_SCALAR > *> * __implements
The Set of implemented interface of this.
Definition: PRMClass.h:391
Representation of a setA Set is a structure that contains arbitrary elements.
Definition: set.h:162
const std::string & safeName() const
Returns the safe name of this PRMClassElement, if any.
std::shared_ptr< Idx > sharedLabel() const
Returns the shared_ptr holding this Aggregate label.
prm_type
Enumeration of the different types of objects handled by a PRM.
Definition: PRMObject.h:66
virtual void overload(PRMAttribute< GUM_SCALAR > *source)
Set this as overload of source (necessayr to preserver internal pointers for MultiDims).
The base class for all directed edgesThis class is used as a basis for manipulating all directed edge...
PRMClass(const std::string &name)
Default constructor.
Definition: PRMClass_tpl.h:37
ParamScopeData(const std::string &s, const PRMReferenceSlot< GUM_SCALAR > &ref, Idx d)
PRMClassElementContainer< GUM_SCALAR > & end()
Returns the PRMClassElement<GUM_SCALAR>Container over which this slot chain ends. ...
Base class for all aGrUM&#39;s exceptions.
Definition: exceptions.h:103
Set of pairs of elements with fast search for both elements.
Definition: bijection.h:1803
An PRMInterface is implemented by a Class<GUM_SCALAR> and defines a set of PRMReferenceSlot<GUM_SCALA...
Definition: PRMClass.h:51
virtual ClassElementType elt_type() const =0
Return the type of class element this object is.
virtual PRMType & type()=0
Return a reference over the gum::PRMType of this class element.
A PRMSlotChain represents a sequence of gum::prm::PRMClassElement<GUM_SCALAR> where the n-1 first gum...
Definition: PRMObject.h:218
PRMInterface< GUM_SCALAR > & super()
Returns the superInterface of this PRMInterface.
NodeId nextNodeId()
Returns the next value of an unique counter for PRM&#39;s node id.
Definition: utils_prm.cpp:63
virtual PRMType & type()
See gum::PRMClassElement::type().
void erase(const Key &k)
Remove an element from the sequence.
Definition: sequence_tpl.h:450
virtual PRMClassElement< GUM_SCALAR > & get(NodeId id)
See gum::prm::PRMClassElementContainer<GUM_SCALAR>::get(NodeId).
<agrum/PRM/classElementContainer.h>
NodeId id() const
Returns the NodeId of this element in it&#39;s class DAG.
virtual void setId(NodeId id)
Used to assign the id of this element.
A PRMClass is an object of a PRM representing a fragment of a Bayesian Network which can be instantia...
Definition: PRMClass.h:63
virtual void setAsCastDescendant(PRMAttribute< GUM_SCALAR > *attr)=0
Define attr as a cast descendant of this PRMAttribute.
void __addExtension(PRMClass< GUM_SCALAR > *c)
This method is called when a sub-Class<GUM_SCALAR> of this Class<GUM_SCALAR> is created.
Size Idx
Type for indexes.
Definition: types.h:50
ParameterType valueType() const
See gum::PRMClassElement::elt_type().
virtual void copyCpf(const Bijection< const DiscreteVariable *, const DiscreteVariable * > &bif, const PRMAttribute< GUM_SCALAR > &source)=0
See gum::PRMClassElement::elt_type().
Set< PRMAttribute< GUM_SCALAR > *> __attributes
The sequence of PRMAttribute<GUM_SCALAR>s.
Definition: PRMClass.h:356
PRMAttribute is a member of a Class in a PRM.
Definition: PRMAttribute.h:58
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:45
PRMClassElement< GUM_SCALAR > & lastElt()
Returns the last element of the slot chain, typically this is an gum::PRMAttribute or a gum::PRMAggre...
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
HashTable< std::string, PRMClassElement< GUM_SCALAR > *> __nameMap
Mapping between a member&#39;s name and itself. Used for fast access to a member given it&#39;s name...
Definition: PRMClass.h:353
virtual const DAG & containerDag() const
Returns the gum::DAG of this PRMClassElementContainer.
Base class for dag.
Definition: DAG.h:99
void setAtPos(Idx i, const Key &newKey)
Change the value.
Definition: sequence_tpl.h:522
Size NodeId
Type for node ids.
Definition: graphElements.h:97
void insert(const Key &k)
Inserts a new element into the set.
Definition: set_tpl.h:610
const Key & back() const
Returns the last element of the sequence.
Definition: sequence_tpl.h:565
#define GUM_ERROR(type, msg)
Definition: exceptions.h:52
const Key & atPos(Idx i) const
Returns the object at the pos i.
Definition: sequence_tpl.h:497
Set< PRMParameter< GUM_SCALAR > *> __parameters
The Set of parameters in this Class<GUM_SCALAR>.
Definition: PRMClass.h:368
void insert(const Key &k)
Insert an element at the end of the sequence.
Definition: sequence_tpl.h:405