aGrUM  0.16.0
clusteredLayerGenerator_tpl.h
Go to the documentation of this file.
1 
30 namespace gum {
31  namespace prm {
32 
33  template < typename GUM_SCALAR >
35  if (__layers.size() == 0) {
37  "cannot generate a layered PRM<GUM_SCALAR> without layers");
38  }
39 
40  std::vector< MyData > l;
42  std::string type = __generateType(factory);
43  __generateInterfaces(factory, type, l);
44  __generateClasses(factory, type, l);
45  __generateSystem(factory, l);
46  return factory.prm();
47  }
48 
49  template < typename GUM_SCALAR >
51  PRMFactory< GUM_SCALAR >& factory) {
52  std::string name = this->_name_gen.nextName(PRMObject::prm_type::TYPE);
53  factory.startDiscreteType(name);
54 
55  for (Size i = 0; i < __domain_size; ++i) {
56  std::stringstream sBuff;
57  sBuff << i;
58  factory.addLabel(sBuff.str());
59  }
60 
61  factory.endDiscreteType();
62  return name;
63  }
64 
65  template < typename GUM_SCALAR >
68  const std::string& type,
69  std::vector< typename ClusteredLayerGenerator< GUM_SCALAR >::MyData >& l) {
70  for (Size lvl = 0; lvl < __layers.size(); ++lvl) {
72  l[lvl].i = this->_name_gen.nextName(PRMObject::prm_type::PRM_INTERFACE);
73  f.startInterface(l[lvl].i);
74 
75  for (Size a = 0; a < __layers[lvl].a; ++a) {
76  l[lvl].a.push_back(
77  this->_name_gen.nextName(PRMObject::prm_type::CLASS_ELT));
78  f.addAttribute(type, l[lvl].a.back());
79  }
80 
81  if (lvl) {
82  for (Size g = 0; g < __layers[lvl].g; ++g) {
83  l[lvl].g.push_back(
84  this->_name_gen.nextName(PRMObject::prm_type::CLASS_ELT));
85  f.addAttribute("boolean", l[lvl].g.back());
86  }
87 
88  l[lvl].r = this->_name_gen.nextName(PRMObject::prm_type::CLASS_ELT);
89  f.addReferenceSlot(l[lvl - 1].i, l[lvl].r, true);
90  }
91 
92  f.endInterface();
93  }
94  }
95 
96  template < typename GUM_SCALAR >
99  const std::string& type,
100  std::vector< typename ClusteredLayerGenerator< GUM_SCALAR >::MyData >& l) {
101  // double ratio = getClusterRatio() + RAND_MAX;
103 
104  for (Size lvl = 0; lvl < __layers.size(); ++lvl) {
105  i.insert(l[lvl].i);
106 
107  for (Size c = 0; c < __layers[lvl].c; ++c) {
108  // if (std::rand() < ratio)
109  __generateCluster(f, type, l, lvl, i);
110  // else
111  // __generateClass(f, type, l, lvl, i);
112  }
113 
114  i.erase(l[lvl].i);
115  }
116  }
117 
118  template < typename GUM_SCALAR >
121  const std::string& type,
122  std::vector< typename ClusteredLayerGenerator< GUM_SCALAR >::MyData >& l,
123  Size lvl,
124  Set< std::string >& i) {
125  Size size = 0;
126  GUM_SCALAR sum = 0.0;
127  std::string first, second, third;
128  std::vector< std::string >* v = 0;
129 
130  switch (std::rand() % 2) {
131  // Shape A->B
132  // v == [first, second, second.ref -> first]
133  case 0: {
134  v = new std::vector< std::string >();
135  __generateClass(f, type, l, lvl, i);
136  first = l[lvl].c.back();
137  v->push_back(first);
138  v->push_back(this->_name_gen.nextName(PRMObject::prm_type::CLASS));
139  f.startClass(v->back());
140  v->push_back(this->_name_gen.nextName(PRMObject::prm_type::CLASS_ELT));
141  f.addReferenceSlot(first, v->back(), true);
142  DAG dag;
144  __generateClassDag(lvl, dag, names, l);
145 
146  // Adding aggregates
147  for (std::vector< std::string >::iterator g = l[lvl].g.begin();
148  g != l[lvl].g.end();
149  ++g) {
150  std::stringstream s;
151  s << v->back() << "." << l[lvl].a[std::rand() % l[lvl].a.size()];
152  std::vector< std::string > chain(1, s.str()), param(1, "1");
153  f.addAggregator(*g, "exists", chain, param);
154  }
155 
156  // Adding attributes
157  for (std::vector< std::string >::iterator a = l[lvl].a.begin();
158  a != l[lvl].a.end();
159  ++a) {
160  f.startAttribute(type, *a, true);
161  size = getDomainSize();
162 
163  for (const auto par : dag.parents(names.second(*a))) {
164  f.addParent(names.first(par));
165  size *= f.retrieveClass(l[lvl].c.back())
166  .get(names.first(par))
167  .type()
168  ->domainSize();
169  }
170 
171  std::vector< GUM_SCALAR > cpf(size), val(getDomainSize());
172 
173  for (size_t norms = 0; norms < size; norms += getDomainSize()) {
174  sum = 0.0;
175 
176  for (size_t idx = 0; idx < getDomainSize(); ++idx) {
177  val[idx] = 1 + std::rand();
178  sum += val[idx];
179  }
180 
181  for (size_t idx = 0; idx < getDomainSize(); ++idx)
182  cpf[norms + idx] = val[idx] / sum;
183  }
184 
185  f.setRawCPFByLines(cpf);
186  f.endAttribute();
187  }
188 
189  f.endClass();
190  break;
191  }
192 
193  // Shape A -> B -> C
194  // v == [first, second, second.ref -> first, third, third.ref -> second]
195  case 1: {
196  v = new std::vector< std::string >();
197  __generateClass(f, type, l, lvl, i);
198  {
199  first = l[lvl].c.back();
200  v->push_back(first);
201  v->push_back(this->_name_gen.nextName(PRMObject::prm_type::CLASS));
202  second = v->back();
203  f.startClass(second);
204  v->push_back(this->_name_gen.nextName(PRMObject::prm_type::CLASS_ELT));
205  f.addReferenceSlot(first, v->back(), true);
206  DAG dag;
208  __generateClassDag(lvl, dag, names, l);
209 
210  // Adding aggregates
211  for (std::vector< std::string >::iterator g = l[lvl].g.begin();
212  g != l[lvl].g.end();
213  ++g) {
214  std::stringstream s;
215  s << v->back() << "." << l[lvl].a[std::rand() % l[lvl].a.size()];
216  std::vector< std::string > chain(1, s.str()), param(1, "1");
217  f.addAggregator(*g, "exists", chain, param);
218  }
219 
220  // Adding attributes
221  for (std::vector< std::string >::iterator a = l[lvl].a.begin();
222  a != l[lvl].a.end();
223  ++a) {
224  f.startAttribute(type, *a, true);
225  size = getDomainSize();
226 
227  for (const auto par : dag.parents(names.second(*a))) {
228  f.addParent(names.first(par));
229  size *= f.retrieveClass(l[lvl].c.back())
230  .get(names.first(par))
231  .type()
232  ->domainSize();
233  }
234 
235  std::vector< GUM_SCALAR > cpf(size), val(getDomainSize());
236 
237  for (size_t norms = 0; norms < size; norms += getDomainSize()) {
238  sum = 0.0;
239 
240  for (size_t idx = 0; idx < getDomainSize(); ++idx) {
241  val[idx] = 1 + std::rand();
242  sum += val[idx];
243  }
244 
245  for (size_t idx = 0; idx < getDomainSize(); ++idx)
246  cpf[norms + idx] = val[idx] / sum;
247  }
248 
249  f.setRawCPFByLines(cpf);
250  f.endAttribute();
251  }
252 
253  f.endClass();
254  }
255  {
256  v->push_back(this->_name_gen.nextName(PRMObject::prm_type::CLASS));
257  third = v->back();
258  f.startClass(third);
259  v->push_back(this->_name_gen.nextName(PRMObject::prm_type::CLASS_ELT));
260  f.addReferenceSlot(second, v->back(), true);
261  DAG dag;
263  __generateClassDag(lvl, dag, names, l);
264 
265  // Adding aggregates
266  for (std::vector< std::string >::iterator g = l[lvl].g.begin();
267  g != l[lvl].g.end();
268  ++g) {
269  std::stringstream s;
270  s << v->back() << "." << l[lvl].a[std::rand() % l[lvl].a.size()];
271  std::vector< std::string > chain(1, s.str()), param(1, "1");
272  f.addAggregator(*g, "exists", chain, param);
273  }
274 
275  // Adding attributes
276  for (std::vector< std::string >::iterator a = l[lvl].a.begin();
277  a != l[lvl].a.end();
278  ++a) {
279  f.startAttribute(type, *a, true);
280  size = getDomainSize();
281 
282  for (const auto par : dag.parents(names.second(*a))) {
283  f.addParent(names.first(par));
284  size *= f.retrieveClass(l[lvl].c.back())
285  .get(names.first(par))
286  .type()
287  ->domainSize();
288  }
289 
290  std::vector< GUM_SCALAR > cpf(size), val(getDomainSize());
291 
292  for (size_t norms = 0; norms < size; norms += getDomainSize()) {
293  sum = 0.0;
294 
295  for (size_t idx = 0; idx < getDomainSize(); ++idx) {
296  val[idx] = 1 + std::rand();
297  sum += val[idx];
298  }
299 
300  for (size_t idx = 0; idx < getDomainSize(); ++idx)
301  cpf[norms + idx] = val[idx] / sum;
302  }
303 
304  f.setRawCPFByLines(cpf);
305  f.endAttribute();
306  }
307 
308  f.endClass();
309  }
310  break;
311  }
312 
313  default: {
314  GUM_ERROR(OperationNotAllowed, "unexpected value");
315  }
316  }
317 
318  __cluster_map.insert(first, v);
319  }
320 
321  template < typename GUM_SCALAR >
324  const std::string& type,
325  std::vector< typename ClusteredLayerGenerator< GUM_SCALAR >::MyData >& l,
326  Size lvl,
327  Set< std::string >& i) {
328  Size size = 0;
329  GUM_SCALAR sum = 0.0;
330  l[lvl].c.push_back(this->_name_gen.nextName(PRMObject::prm_type::CLASS));
331  f.startClass(l[lvl].c.back(), "", &i);
332 
333  if (lvl) f.addReferenceSlot(l[lvl - 1].i, l[lvl].r, true);
334 
335  DAG dag;
337  __generateClassDag(lvl, dag, names, l);
338 
339  // Adding aggregates
340  if (lvl) {
341  for (const auto agg : l[lvl].g) {
342  std::stringstream s;
343  s << l[lvl].r << "." << l[lvl - 1].a[std::rand() % l[lvl - 1].a.size()];
344  std::vector< std::string > chain(1, s.str()), param(1, "1");
345  f.addAggregator(agg, "exists", chain, param);
346  }
347  }
348 
349  // Adding attributes
350  for (const auto attr : l[lvl].a) {
351  f.startAttribute(type, attr, true);
352  size = getDomainSize();
353 
354  for (const auto par : dag.parents(names.second(attr))) {
355  f.addParent(names.first(par));
356  size *= f.retrieveClass(l[lvl].c.back())
357  .get(names.first(par))
358  .type()
359  ->domainSize();
360  }
361 
362  std::vector< GUM_SCALAR > cpf(size), val(getDomainSize());
363 
364  for (size_t norms = 0; norms < size; norms += getDomainSize()) {
365  sum = 0.0;
366 
367  for (size_t idx = 0; idx < getDomainSize(); ++idx) {
368  val[idx] = 1 + std::rand();
369  sum += val[idx];
370  }
371 
372  for (size_t idx = 0; idx < getDomainSize(); ++idx)
373  cpf[norms + idx] = val[idx] / sum;
374  }
375 
376  f.setRawCPFByLines(cpf);
377  f.endAttribute();
378  }
379 
380  f.endClass();
381  }
382 
383  template < typename GUM_SCALAR >
385  Size lvl,
386  DAG& dag,
388  std::vector< typename ClusteredLayerGenerator< GUM_SCALAR >::MyData >& l) {
389  float density = __layers[lvl].inner_density * RAND_MAX;
390  std::vector< NodeId > nodes;
391  NodeId id = 0;
392 
393  if (lvl) {
394  for (std::vector< std::string >::iterator g = l[lvl].g.begin();
395  g != l[lvl].g.end();
396  ++g) {
397  id = dag.addNode();
398  names.insert(*g, id);
399  nodes.push_back(id);
400  }
401  }
402 
403  for (std::vector< std::string >::iterator a = l[lvl].a.begin();
404  a != l[lvl].a.end();
405  ++a) {
406  id = dag.addNode();
407  names.insert(*a, id);
408 
409  for (std::vector< NodeId >::iterator prnt = nodes.begin();
410  prnt != nodes.end();
411  ++prnt)
412  if (std::rand() < density) dag.addArc(*prnt, names.second(*a));
413 
414  nodes.push_back(id);
415  }
416 
417  // For each nodes with #parents > __max_parents we randomly remove parents
418  // until
419  // #parents <= __max_parents
420  for (const auto node : dag.nodes()) {
421  if (dag.parents(node).size() > getMaxParents()) {
422  std::vector< NodeId > v;
423 
424  for (const auto par : dag.parents(node))
425  v.push_back(par);
426 
427  while (dag.parents(node).size() > getMaxParents()) {
428  size_t idx = std::rand() % v.size();
429  Arc arc(v[idx], node);
430  GUM_ASSERT(dag.existsArc(arc));
431  dag.eraseArc(arc);
432  v[idx] = v.back();
433  v.pop_back();
434  }
435  }
436  }
437  }
438 
439  template < typename GUM_SCALAR >
441  PRMFactory< GUM_SCALAR >& factory,
442  std::vector< typename ClusteredLayerGenerator< GUM_SCALAR >::MyData >& l) {
443  factory.startSystem(this->_name_gen.nextName(PRMObject::prm_type::SYSTEM));
444  std::vector< std::vector< std::string > > o(__layers.size());
445  std::string name, c, first, second, third;
446  std::vector< std::string >* v = 0;
447  size_t idx = 0;
448 
449  for (size_t lvl = 0; lvl < __layers.size(); ++lvl) {
450  float density = __layers[lvl].outter_density * RAND_MAX;
451 
452  for (size_t count = 0; count < __layers[lvl].o; ++count) {
453  c = l[lvl].c[std::rand() % l[lvl].c.size()];
454 
455  if (__cluster_map.exists(c)) {
456  v = __cluster_map[c];
457 
458  switch (v->size()) {
459  case 3: {
460  first = this->_name_gen.nextName(PRMObject::prm_type::INSTANCE);
461  factory.addInstance(c, first);
462  second = this->_name_gen.nextName(PRMObject::prm_type::INSTANCE);
463  factory.addInstance(v->at(1), second);
464  std::stringstream chain;
465  chain << second << "." << v->at(2);
466  factory.setReferenceSlot(chain.str(), first);
467  break;
468  }
469 
470  case 5: {
471  first = this->_name_gen.nextName(PRMObject::prm_type::INSTANCE);
472  factory.addInstance(c, first);
473  second = this->_name_gen.nextName(PRMObject::prm_type::INSTANCE);
474  factory.addInstance(v->at(1), second);
475  std::stringstream chain_1, chain_2;
476  chain_1 << second << "." << v->at(2);
477  factory.setReferenceSlot(chain_1.str(), first);
478  third = this->_name_gen.nextName(PRMObject::prm_type::INSTANCE);
479  factory.addInstance(v->at(3), third);
480  chain_2 << third << "." << v->at(4);
481  factory.setReferenceSlot(chain_2.str(), second);
482  break;
483  }
484 
485  default: {
486  GUM_ERROR(OperationNotAllowed, "unexpected vector size");
487  }
488  }
489 
490  // __cluster_map.erase(c);
491  // delete v;
492  name = first;
493  } else {
494  name = this->_name_gen.nextName(PRMObject::prm_type::INSTANCE);
495  factory.addInstance(c, name);
496  }
497 
498  o[lvl].push_back(name);
499 
500  if (lvl) {
501  std::stringstream chain;
502  chain << name << "." << l[lvl].r;
503  std::vector< std::string > ref2add;
504 
505  for (std::vector< std::string >::iterator iter = o[lvl - 1].begin();
506  iter != o[lvl - 1].end();
507  ++iter)
508  if (std::rand() <= density) ref2add.push_back(*iter);
509 
510  if (ref2add.empty())
511  factory.setReferenceSlot(
512  chain.str(), o[lvl - 1][std::rand() % o[lvl - 1].size()]);
513 
514  while (ref2add.size() > getMaxParents()) {
515  idx = std::rand() % ref2add.size();
516  ref2add[idx] = ref2add.back();
517  ref2add.pop_back();
518  }
519 
520  for (std::vector< std::string >::iterator iter = ref2add.begin();
521  iter != ref2add.end();
522  ++iter)
523  factory.setReferenceSlot(chain.str(), *iter);
524  }
525  }
526  }
527 
528  factory.endSystem();
529  }
530 
531  template < typename GUM_SCALAR >
533  __layers(), __domain_size(2), __max_parents(INT_MAX),
534  __cluster_ratio(0.0) {
535  GUM_CONSTRUCTOR(ClusteredLayerGenerator);
536  }
537 
538  template < typename GUM_SCALAR >
541  __layers(source.__layers),
543  GUM_CONS_CPY(ClusteredLayerGenerator);
544  }
545 
546  template < typename GUM_SCALAR >
548  GUM_DESTRUCTOR(ClusteredLayerGenerator);
549  // typedef HashTable<std::string, std::vector<std::string>*>::iterator
550  // Iter;
551  // for (Iter iter = __cluster_map.begin(); iter != __cluster_map.end();
552  // ++iter)
553  // {
554  // delete *iter;
555  // }
556  }
557 
558  template < typename GUM_SCALAR >
562  __layers = source.__layers;
563  __domain_size = source.__domain_size;
564  __max_parents = source.__max_parents;
565  return *this;
566  }
567 
568  template < typename GUM_SCALAR >
570  return __domain_size;
571  }
572 
573  template < typename GUM_SCALAR >
575  __domain_size = s;
576  }
577 
578  template < typename GUM_SCALAR >
580  return __max_parents;
581  }
582 
583  template < typename GUM_SCALAR >
585  __max_parents = s;
586  }
587 
588  template < typename GUM_SCALAR >
590  const std::vector< typename LayerGenerator< GUM_SCALAR >::LayerData >& v) {
591  __layers = v;
592  }
593 
594  template < typename GUM_SCALAR >
595  INLINE std::vector< typename LayerGenerator< GUM_SCALAR >::LayerData >&
597  return __layers;
598  }
599 
600  template < typename GUM_SCALAR >
601  INLINE const std::vector< typename LayerGenerator< GUM_SCALAR >::LayerData >&
603  return __layers;
604  }
605 
606  template < typename GUM_SCALAR >
608  return __cluster_ratio;
609  }
610 
611  template < typename GUM_SCALAR >
612  INLINE void
614  __cluster_ratio = ratio;
615  }
616 
617  } /* namespace prm */
618 } /* namespace gum */
void insert(const T1 &first, const T2 &second)
Inserts a new association in the gum::Bijection.
Size getMaxParents() const
Returns the max number of parents allowed for any attribute or aggregator.
const T2 & second(const T1 &first) const
Returns the second value of a pair given its first value.
<agrum/PRM/generator/clusteredLayerGenerator.h>
virtual void endInterface() override
Tells the factory that we finished an interface declaration.
virtual void addAggregator(const std::string &name, const std::string &agg_type, const std::vector< std::string > &chains, const std::vector< std::string > &params, std::string type="") override
Add an aggregator in the current declared class.
std::string __generateType(PRMFactory< GUM_SCALAR > &f)
virtual void setReferenceSlot(const std::string &left_instance, const std::string &left_reference, const std::string &right_instance) override
Instantiate a reference in the current model.
const T1 & first(const T2 &second) const
Returns the first value of a pair given its second value.
void __generateSystem(PRMFactory< GUM_SCALAR > &factory, std::vector< typename ClusteredLayerGenerator::MyData > &l)
void setLayers(const std::vector< typename LayerGenerator< GUM_SCALAR >::LayerData > &v)
Defines the structure of each layers.
virtual void addInstance(const std::string &type, const std::string &name) override
Add an instance to the model.
virtual void eraseArc(const Arc &arc)
removes an arc from the ArcGraphPart
std::vector< typename LayerGenerator< GUM_SCALAR >::LayerData > & getLayer()
Getters and setters.
PRMClass< GUM_SCALAR > & retrieveClass(const std::string &name)
Returns a reference over a Class<GUM_SCALAR> given its name.
virtual void endAttribute() override
Tells the factory that we finished declaring an attribute.
virtual void startInterface(const std::string &i, const std::string &ext="", bool delayInheritance=false) override
Tells the factory that we start an interface declaration.
virtual void addReferenceSlot(const std::string &type, const std::string &name, bool isArray) override
Tells the factory that we started declaring a slot.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
virtual void addAttribute(const std::string &type, const std::string &name) override
Add an attribute to an interface.
double getClusterRatio() const
Returns the odds of a given class to be replaced by a cluster.
virtual NodeId addNode()
insert a new node and return its id
virtual void startClass(const std::string &c, const std::string &ext="", const Set< std::string > *implements=nullptr, bool delayInheritance=false) override
Tells the factory that we start a class declaration.
ClusteredLayerGenerator & operator=(const ClusteredLayerGenerator &source)
Copy operator.
virtual void startSystem(const std::string &name) override
Tells the factory that we started declaring a model.
void __generateInterfaces(PRMFactory< GUM_SCALAR > &f, const std::string &type, std::vector< MyData > &l)
virtual void startAttribute(const std::string &type, const std::string &name, bool scalar_atttr=false) override
Tells the factory that we start an attribute declaration.
std::vector< typename LayerGenerator< GUM_SCALAR >::LayerData > __layers
Factory which builds a PRM<GUM_SCALAR>.
Definition: PRMType.h:50
void __generateClassDag(Size lvl, DAG &dag, Bijection< std::string, NodeId > &names, std::vector< typename ClusteredLayerGenerator::MyData > &l)
The base class for all directed edgesThis class is used as a basis for manipulating all directed edge...
const NodeSet & parents(const NodeId id) const
returns the set of nodes with arc ingoing to a given node
const NodeGraphPart & nodes() const
return *this as a NodeGraphPart
virtual void addArc(const NodeId tail, const NodeId head)
insert a new arc into the directed graph
Definition: DAG_inl.h:43
void __generateClasses(PRMFactory< GUM_SCALAR > &f, const std::string &type, std::vector< typename ClusteredLayerGenerator::MyData > &l)
virtual void endClass(bool checkImplementations=true) override
Tells the factory that we finished a class declaration.
void setRawCPFByLines(const std::vector< GUM_SCALAR > &array)
Gives the factory the CPF in its raw form.
virtual PRM< GUM_SCALAR > * generate()
Proceeds with the generation of the PRM<GUM_SCALAR>.
This class represents a Probabilistic Relational PRMSystem<GUM_SCALAR>.
Definition: PRM.h:66
virtual void startDiscreteType(const std::string &name, std::string super="") override
Start a discrete subtype declaration.
void __generateClass(PRMFactory< GUM_SCALAR > &f, const std::string &type, std::vector< typename ClusteredLayerGenerator::MyData > &l, Size lvl, Set< std::string > &i)
virtual void endDiscreteType() override
End the current discrete type declaration.
void setClusterRatio(double ratio)
Define the odds of a given class to be replaced by a cluster.
void setDomainSize(Size s)
Set the domain size of generated types.
void setMaxParents(Size s)
Returns the max number of parents allowed for any attribute or aggregator.
virtual void addLabel(const std::string &l, std::string ext="") override
Add a label to the current discrete type.
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:48
void __generateCluster(PRMFactory< GUM_SCALAR > &f, const std::string &type, std::vector< typename ClusteredLayerGenerator::MyData > &l, Size lvl, Set< std::string > &i)
Size size() const noexcept
Returns the number of elements in the set.
Definition: set_tpl.h:701
virtual void endSystem() override
Tells the factory that we finished declaring a model.
Base class for dag.
Definition: DAG.h:102
bool existsArc(const Arc &arc) const
indicates whether a given arc exists
Size getDomainSize() const
Getters and setters.
Size NodeId
Type for node ids.
Definition: graphElements.h:98
PRM< GUM_SCALAR > * prm() const
Returns a pointer on the PRM<GUM_SCALAR> created by this factory.
void insert(const Key &k)
Inserts a new element into the set.
Definition: set_tpl.h:613
virtual void addParent(const std::string &name) override
Tells the factory that we add a parent to the current declared attribute.
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55