aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
PRMFactory_tpl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /** @file
23  * @brief Inline implementation of PRMFactory.
24  *
25  * @author Lionel TORTI and Pierre-Henri WUILLEMIN(@LIP6)
26  */
27 
28 #include <agrum/PRM/PRMFactory.h>
29 
30 #include <iostream>
31 #include <sstream>
32 
33 #include <agrum/tools/core/math/formula.h>
34 
35 #include <agrum/tools/variables/discretizedVariable.h>
36 #include <agrum/tools/variables/rangeVariable.h>
37 
38 #include <agrum/PRM/elements/PRMFormAttribute.h>
39 #include <agrum/PRM/elements/PRMFuncAttribute.h>
40 
41 namespace gum {
42 
43  namespace prm {
44 
45  template < typename GUM_SCALAR >
46  INLINE void PRMFactory< GUM_SCALAR >::startClass(const std::string& name,
47  const std::string& extends,
48  const Set< std::string >* implements,
49  bool delayInheritance) {
50  std::string real_name = _addPrefix_(name);
51  if (_prm_->_classMap_.exists(real_name) || _prm_->_interfaceMap_.exists(real_name)) {
52  GUM_ERROR(DuplicateElement, "'" << real_name << "' is already used.")
53  }
54  PRMClass< GUM_SCALAR >* c = nullptr;
55  PRMClass< GUM_SCALAR >* mother = nullptr;
56  Set< PRMInterface< GUM_SCALAR >* > impl;
57 
58  if (implements != 0) {
59  for (const auto& imp: *implements) {
60  impl.insert(_retrieveInterface_(imp));
61  }
62  }
63 
64  if (extends != "") { mother = _retrieveClass_(extends); }
65 
66  if ((extends == "") && impl.empty()) {
67  c = new PRMClass< GUM_SCALAR >(real_name);
68  } else if ((extends != "") && impl.empty()) {
69  c = new PRMClass< GUM_SCALAR >(real_name, *mother, delayInheritance);
70  } else if ((extends == "") && (!impl.empty())) {
71  c = new PRMClass< GUM_SCALAR >(real_name, impl, delayInheritance);
72  } else if ((extends != "") && (!impl.empty())) {
73  c = new PRMClass< GUM_SCALAR >(real_name, *mother, impl, delayInheritance);
74  }
75 
76  _prm_->_classMap_.insert(c->name(), c);
77  _prm_->_classes_.insert(c);
78  _stack_.push_back(c);
79  }
80 
81  template < typename GUM_SCALAR >
82  INLINE void PRMFactory< GUM_SCALAR >::continueClass(const std::string& name) {
83  std::string real_name = _addPrefix_(name);
84  if (!(_prm_->_classMap_.exists(real_name))) {
85  std::stringstream msg;
86  msg << "'" << real_name << "' not found";
87  GUM_ERROR(NotFound, msg.str())
88  }
89  _stack_.push_back(&(_prm_->getClass(real_name)));
90  }
91 
92  template < typename GUM_SCALAR >
93  INLINE void PRMFactory< GUM_SCALAR >::endClass(bool checkImplementations) {
94  PRMClass< GUM_SCALAR >* c
95  = static_cast< PRMClass< GUM_SCALAR >* >(_checkStack_(1, PRMObject::prm_type::CLASS));
96 
97  if (checkImplementations) { _checkInterfaceImplementation_(c); }
98 
99  _stack_.pop_back();
100  }
101 
102  template < typename GUM_SCALAR >
103  INLINE void
104  PRMFactory< GUM_SCALAR >::_checkInterfaceImplementation_(PRMClass< GUM_SCALAR >* c) {
105  try {
106  for (const auto& i: c->implements()) {
107  try {
108  for (const auto& node: i->containerDag().nodes()) {
109  std::string name = i->get(node).name();
110 
111  switch (i->get(node).elt_type()) {
112  case PRMClassElement< GUM_SCALAR >::prm_aggregate:
113  case PRMClassElement< GUM_SCALAR >::prm_attribute: {
114  if ((c->get(name).elt_type() == PRMClassElement< GUM_SCALAR >::prm_attribute)
115  || (c->get(name).elt_type()
116  == PRMClassElement< GUM_SCALAR >::prm_aggregate)) {
117  if (!c->get(name).type().isSubTypeOf(i->get(name).type())) {
118  std::stringstream msg;
119  msg << "class " << c->name() << " does not respect interface ";
120  GUM_ERROR(PRMTypeError, msg.str() + i->name())
121  }
122  } else {
123  std::stringstream msg;
124  msg << "class " << c->name() << " does not respect interface ";
125  GUM_ERROR(PRMTypeError, msg.str() + i->name())
126  }
127 
128  break;
129  }
130 
131  case PRMClassElement< GUM_SCALAR >::prm_refslot: {
132  if (c->get(name).elt_type() == PRMClassElement< GUM_SCALAR >::prm_refslot) {
133  const PRMReferenceSlot< GUM_SCALAR >& ref_i
134  = static_cast< const PRMReferenceSlot< GUM_SCALAR >& >(i->get(name));
135  const PRMReferenceSlot< GUM_SCALAR >& ref_this
136  = static_cast< const PRMReferenceSlot< GUM_SCALAR >& >(c->get(name));
137 
138  if (!ref_this.slotType().isSubTypeOf(ref_i.slotType())) {
139  std::stringstream msg;
140  msg << "class " << c->name() << " does not respect interface ";
141  GUM_ERROR(PRMTypeError, msg.str() + i->name())
142  }
143  } else {
144  std::stringstream msg;
145  msg << "class " << c->name() << " does not respect interface ";
146  GUM_ERROR(PRMTypeError, msg.str() + i->name())
147  }
148 
149  break;
150  }
151 
152  case PRMClassElement< GUM_SCALAR >::prm_slotchain: {
153  // Nothing to check: they are automatically inherited
154  break;
155  }
156 
157  default: {
158  std::string msg = "unexpected ClassElement<GUM_SCALAR> in interface ";
159  GUM_ERROR(FatalError, msg + i->name())
160  }
161  }
162  }
163  } catch (NotFound&) {
164  std::stringstream msg;
165  msg << "class " << c->name() << " does not respect interface ";
166  GUM_ERROR(PRMTypeError, msg.str() + i->name())
167  }
168  }
169  } catch (NotFound&) {
170  // this Class<GUM_SCALAR> does not implement any
171  // PRMInterface<GUM_SCALAR>
172  }
173  }
174 
175  template < typename GUM_SCALAR >
176  INLINE void PRMFactory< GUM_SCALAR >::startInterface(const std::string& name,
177  const std::string& extends,
178  bool delayInheritance) {
179  std::string real_name = _addPrefix_(name);
180  if (_prm_->_classMap_.exists(real_name) || _prm_->_interfaceMap_.exists(real_name)) {
181  GUM_ERROR(DuplicateElement, "'" << real_name << "' is already used.")
182  }
183  PRMInterface< GUM_SCALAR >* i = nullptr;
184  PRMInterface< GUM_SCALAR >* super = nullptr;
185 
186  if (extends != "") { super = _retrieveInterface_(extends); }
187 
188  if (super != nullptr) {
189  i = new PRMInterface< GUM_SCALAR >(real_name, *super, delayInheritance);
190  } else {
191  i = new PRMInterface< GUM_SCALAR >(real_name);
192  }
193 
194  _prm_->_interfaceMap_.insert(i->name(), i);
195  _prm_->_interfaces_.insert(i);
196  _stack_.push_back(i);
197  }
198 
199  template < typename GUM_SCALAR >
200  INLINE void PRMFactory< GUM_SCALAR >::continueInterface(const std::string& name) {
201  std::string real_name = _addPrefix_(name);
202  if (!_prm_->_interfaceMap_.exists(real_name)) {
203  GUM_ERROR(DuplicateElement, "'" << real_name << "' not found.")
204  }
205 
206  PRMInterface< GUM_SCALAR >* i = _retrieveInterface_(real_name);
207  _stack_.push_back(i);
208  }
209 
210  template < typename GUM_SCALAR >
211  INLINE void PRMFactory< GUM_SCALAR >::addAttribute(PRMAttribute< GUM_SCALAR >* attr) {
212  PRMClass< GUM_SCALAR >* c
213  = static_cast< PRMClass< GUM_SCALAR >* >(_checkStack_(1, PRMObject::prm_type::CLASS));
214  c->add(attr);
215  Size count = 0;
216  const Sequence< const DiscreteVariable* >& vars = attr->cpf().variablesSequence();
217 
218  for (const auto& node: c->containerDag().nodes()) {
219  try {
220  if (vars.exists(&(c->get(node).type().variable()))) {
221  ++count;
222 
223  if (&(attr->type().variable()) != &(c->get(node).type().variable())) {
224  c->addArc(c->get(node).safeName(), attr->safeName());
225  }
226  }
227  } catch (OperationNotAllowed&) {}
228  }
229 
230  if (count != attr->cpf().variablesSequence().size()) {
231  GUM_ERROR(NotFound, "unable to found all parents of this attribute")
232  }
233  }
234 
235  template < typename GUM_SCALAR >
236  INLINE void PRMFactory< GUM_SCALAR >::_addParent_(PRMClassElementContainer< GUM_SCALAR >* c,
237  PRMAttribute< GUM_SCALAR >* a,
238  const std::string& name) {
239  try {
240  PRMClassElement< GUM_SCALAR >& elt = c->get(name);
241 
242  switch (elt.elt_type()) {
243  case PRMClassElement< GUM_SCALAR >::prm_refslot: {
244  GUM_ERROR(OperationNotAllowed,
245  "can not add a reference slot as a parent of an attribute")
246  break;
247  }
248 
249  case PRMClassElement< GUM_SCALAR >::prm_slotchain: {
250  if (static_cast< PRMSlotChain< GUM_SCALAR >& >(elt).isMultiple()) {
251  GUM_ERROR(OperationNotAllowed, "can not add a multiple slot chain to an attribute")
252  }
253 
254  c->addArc(name, a->name());
255 
256  break;
257  }
258 
259  case PRMClassElement< GUM_SCALAR >::prm_attribute:
260  case PRMClassElement< GUM_SCALAR >::prm_aggregate: {
261  c->addArc(name, a->name());
262  break;
263  }
264 
265  default: {
266  GUM_ERROR(FatalError, "unknown ClassElement<GUM_SCALAR>")
267  }
268  }
269  } catch (NotFound&) {
270  // Check if name is a slot chain
271  PRMSlotChain< GUM_SCALAR >* sc = _buildSlotChain_(c, name);
272 
273  if (sc == nullptr) {
274  std::string msg = "found no ClassElement<GUM_SCALAR> with the given name ";
275  GUM_ERROR(NotFound, msg + name)
276  } else if (!sc->isMultiple()) {
277  c->add(sc);
278  c->addArc(sc->name(), a->name());
279  } else {
280  delete sc;
281  GUM_ERROR(OperationNotAllowed,
282  "Impossible to add a multiple reference slot as"
283  " direct parent of an PRMAttribute<GUM_SCALAR>.");
284  }
285  }
286  }
287 
288 
289  template < typename GUM_SCALAR >
290  INLINE void PRMFactory< GUM_SCALAR >::addParent(const std::string& name) {
291  PRMClassElementContainer< GUM_SCALAR >* c = _checkStackContainter_(2);
292  try {
293  // Retrieving pointers
294  PRMAttribute< GUM_SCALAR >* a = static_cast< PRMAttribute< GUM_SCALAR >* >(
295  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_attribute));
296  _addParent_(c, a, name);
297  } catch (FactoryInvalidState&) {
298  auto agg = static_cast< PRMAggregate< GUM_SCALAR >* >(
299  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_aggregate));
300  _addParent_(static_cast< PRMClass< GUM_SCALAR >* >(c), agg, name);
301  }
302  }
303 
304  template < typename GUM_SCALAR >
305  INLINE void PRMFactory< GUM_SCALAR >::setRawCPFByFloatLines(const std::vector< float >& array) {
306  PRMAttribute< GUM_SCALAR >* a = static_cast< PRMAttribute< GUM_SCALAR >* >(
307  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_attribute));
308  _checkStack_(2, PRMObject::prm_type::CLASS);
309 
310  if (a->cpf().domainSize() != array.size()) GUM_ERROR(OperationNotAllowed, "illegal CPF size")
311 
312  std::vector< GUM_SCALAR > array2(array.begin(), array.end());
313  a->cpf().fillWith(array2);
314  }
315 
316  template < typename GUM_SCALAR >
317  INLINE void PRMFactory< GUM_SCALAR >::setRawCPFByLines(const std::vector< GUM_SCALAR >& array) {
318  auto elt = _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_attribute);
319  auto a = static_cast< PRMAttribute< GUM_SCALAR >* >(elt);
320  _checkStack_(2, PRMObject::prm_type::CLASS);
321 
322  if (a->cpf().domainSize() != array.size()) {
323  GUM_ERROR(OperationNotAllowed, "illegal CPF size")
324  }
325 
326  a->cpf().fillWith(array);
327  }
328 
329  template < typename GUM_SCALAR >
330  INLINE void
331  PRMFactory< GUM_SCALAR >::setRawCPFByFloatColumns(const std::vector< float >& array) {
332  PRMAttribute< GUM_SCALAR >* a = static_cast< PRMAttribute< GUM_SCALAR >* >(
333  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_attribute));
334 
335  if (a->cpf().domainSize() != array.size()) {
336  GUM_ERROR(OperationNotAllowed, "illegal CPF size")
337  }
338 
339  std::vector< GUM_SCALAR > array2(array.begin(), array.end());
340  setRawCPFByColumns(array2);
341  }
342 
343  template < typename GUM_SCALAR >
344  INLINE void
345  PRMFactory< GUM_SCALAR >::setRawCPFByColumns(const std::vector< GUM_SCALAR >& array) {
346  PRMAttribute< GUM_SCALAR >* a = static_cast< PRMAttribute< GUM_SCALAR >* >(
347  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_attribute));
348 
349  if (a->cpf().domainSize() != array.size()) {
350  GUM_ERROR(OperationNotAllowed, "illegal CPF size")
351  }
352 
353  if (a->cpf().nbrDim() == 1) {
354  setRawCPFByLines(array);
355 
356  } else {
357  Instantiation inst(a->cpf());
358  Instantiation jnst;
359  for (auto idx = inst.variablesSequence().rbegin(); idx != inst.variablesSequence().rend();
360  --idx) {
361  jnst.add(**idx);
362  }
363 
364  jnst.setFirst();
365  auto idx = (std::size_t)0;
366  while ((!jnst.end()) && idx < array.size()) {
367  inst.setVals(jnst);
368  a->cpf().set(inst, array[idx]);
369  jnst.inc();
370  ++idx;
371  }
372  }
373  }
374 
375  template < typename GUM_SCALAR >
376  INLINE void
377  PRMFactory< GUM_SCALAR >::setCPFByFloatRule(const std::vector< std::string >& parents,
378  const std::vector< float >& values) {
379  auto a = static_cast< PRMAttribute< GUM_SCALAR >* >(
380  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_attribute));
381 
382  if ((parents.size() + 1) != a->cpf().variablesSequence().size()) {
383  GUM_ERROR(OperationNotAllowed, "wrong number of parents")
384  }
385 
386  if (values.size() != a->type().variable().domainSize()) {
387  GUM_ERROR(OperationNotAllowed, "wrong number of values")
388  }
389 
390  std::vector< GUM_SCALAR > values2(values.begin(), values.end());
391  setCPFByRule(parents, values2);
392  }
393 
394  template < typename GUM_SCALAR >
395  INLINE void PRMFactory< GUM_SCALAR >::setCPFByRule(const std::vector< std::string >& parents,
396  const std::vector< GUM_SCALAR >& values) {
397  auto a = static_cast< PRMAttribute< GUM_SCALAR >* >(
398  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_attribute));
399 
400  if ((parents.size() + 1) != a->cpf().variablesSequence().size()) {
401  GUM_ERROR(OperationNotAllowed, "wrong number of parents")
402  }
403 
404  if (values.size() != a->type().variable().domainSize()) {
405  GUM_ERROR(OperationNotAllowed, "wrong number of values")
406  }
407 
408  if (dynamic_cast< PRMFormAttribute< GUM_SCALAR >* >(a)) {
409  auto form = static_cast< PRMFormAttribute< GUM_SCALAR >* >(a);
410  // jnst holds parents with a specific value (not "*")
411  // knst holds parents without a specific value ("*")
412  Instantiation jnst, knst;
413  const DiscreteVariable* var = 0;
414  // not_used Size pos = 0;
415  bool found = false;
416 
417  for (Idx i = 0; i < parents.size(); ++i) {
418  var = form->formulas().variablesSequence().atPos(1 + i);
419 
420  if (parents[i] == "*") {
421  knst.add(*var);
422  } else {
423  jnst.add(*var);
424  // not_used pos = 0;
425  found = false;
426 
427  for (Size j = 0; j < var->domainSize(); ++j) {
428  if (var->label(j) == parents[i]) {
429  jnst.chgVal(*var, j);
430  found = true;
431  break;
432  }
433  }
434 
435  if (!found) {
436  std::string msg = "could not find label ";
437  GUM_ERROR(NotFound, msg + parents[i])
438  }
439  }
440  }
441 
442  Instantiation inst(form->formulas());
443  inst.setVals(jnst);
444 
445  for (Size i = 0; i < form->type()->domainSize(); ++i) {
446  inst.chgVal(form->type().variable(), i);
447 
448  for (inst.setFirstIn(knst); !inst.end(); inst.incIn(knst)) {
449  form->formulas().set(inst, std::to_string(values[i]));
450  }
451  }
452 
453  } else {
454  GUM_ERROR(OperationNotAllowed, "invalide attribute type")
455  }
456  }
457 
458  template < typename GUM_SCALAR >
459  INLINE void PRMFactory< GUM_SCALAR >::setCPFByRule(const std::vector< std::string >& parents,
460  const std::vector< std::string >& values) {
461  auto a = static_cast< PRMAttribute< GUM_SCALAR >* >(
462  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_attribute));
463 
464  if ((parents.size() + 1) != a->cpf().variablesSequence().size()) {
465  GUM_ERROR(OperationNotAllowed, "wrong number of parents")
466  }
467 
468  if (values.size() != a->type().variable().domainSize()) {
469  GUM_ERROR(OperationNotAllowed, "wrong number of values")
470  }
471 
472  if (dynamic_cast< PRMFormAttribute< GUM_SCALAR >* >(a)) {
473  auto form = static_cast< PRMFormAttribute< GUM_SCALAR >* >(a);
474  // jnst holds parents with a specific value (not "*")
475  // knst holds parents without a specific value ("*")
476  Instantiation jnst, knst;
477  const DiscreteVariable* var = 0;
478  // not_used Size pos = 0;
479  bool found = false;
480 
481  for (Idx i = 0; i < parents.size(); ++i) {
482  var = form->formulas().variablesSequence().atPos(1 + i);
483 
484  if (parents[i] == "*") {
485  knst.add(*var);
486  } else {
487  jnst.add(*var);
488  // not_used pos = 0;
489  found = false;
490 
491  for (Size j = 0; j < var->domainSize(); ++j) {
492  if (var->label(j) == parents[i]) {
493  jnst.chgVal(*var, j);
494  found = true;
495  break;
496  }
497  }
498 
499  if (!found) {
500  std::string msg = "could not find label ";
501  GUM_ERROR(NotFound, msg + parents[i])
502  }
503  }
504  }
505 
506  Instantiation inst(form->formulas());
507  inst.setVals(jnst);
508 
509  for (Size i = 0; i < form->type()->domainSize(); ++i) {
510  inst.chgVal(form->type().variable(), i);
511 
512  for (inst.setFirstIn(knst); !inst.end(); inst.incIn(knst)) {
513  form->formulas().set(inst, values[i]);
514  }
515  }
516 
517  } else {
518  GUM_ERROR(OperationNotAllowed, "invalide attribute type")
519  }
520  }
521 
522  template < typename GUM_SCALAR >
523  INLINE void PRMFactory< GUM_SCALAR >::addParameter(const std::string& type,
524  const std::string& name,
525  double value) {
526  auto c = static_cast< PRMClass< GUM_SCALAR >* >(_checkStack_(1, PRMObject::prm_type::CLASS));
527 
528  PRMParameter< GUM_SCALAR >* p = nullptr;
529  if (type == "int") {
530  p = new PRMParameter< GUM_SCALAR >(name,
531  PRMParameter< GUM_SCALAR >::ParameterType::INT,
532  (GUM_SCALAR)value);
533  } else if (type == "real") {
534  p = new PRMParameter< GUM_SCALAR >(name,
535  PRMParameter< GUM_SCALAR >::ParameterType::REAL,
536  (GUM_SCALAR)value);
537  }
538 
539  try {
540  c->add(p);
541  } catch (DuplicateElement&) { c->overload(p); }
542  }
543 
544  template < typename GUM_SCALAR >
545  INLINE void
546  PRMFactory< GUM_SCALAR >::startAggregator(const std::string& name,
547  const std::string& agg_type,
548  const std::string& rv_type,
549  const std::vector< std::string >& params) {
550  PRMClass< GUM_SCALAR >* c
551  = static_cast< PRMClass< GUM_SCALAR >* >(_checkStack_(1, PRMObject::prm_type::CLASS));
552 
553  auto agg = new PRMAggregate< GUM_SCALAR >(name,
554  PRMAggregate< GUM_SCALAR >::str2enum(agg_type),
555  *_retrieveType_(rv_type));
556 
557  try {
558  c->add(agg);
559  } catch (DuplicateElement&) { c->overload(agg); }
560 
561  switch (agg->agg_type()) {
562  case PRMAggregate< GUM_SCALAR >::AggregateType::COUNT:
563  case PRMAggregate< GUM_SCALAR >::AggregateType::EXISTS:
564  case PRMAggregate< GUM_SCALAR >::AggregateType::FORALL: {
565  if (params.size() != 1) {
566  GUM_ERROR(OperationNotAllowed, "aggregate requires a parameter")
567  }
568  agg->setLabel(params.front());
569  break;
570  }
571  default: {
572  // Nothing to do
573  }
574  }
575  _stack_.push_back(agg);
576  }
577 
578  template < typename GUM_SCALAR >
579  INLINE void PRMFactory< GUM_SCALAR >::continueAggregator(const std::string& name) {
580  PRMClassElementContainer< GUM_SCALAR >* c = _checkStackContainter_(1);
581 
582  if (!c->exists(name)) GUM_ERROR(NotFound, "Element " << name << "not found")
583 
584  auto& agg = c->get(name);
585  if (!PRMClassElement< GUM_SCALAR >::isAggregate(agg))
586  GUM_ERROR(OperationNotAllowed, "Element " << name << " not an aggregate")
587 
588  _stack_.push_back(&agg);
589  }
590 
591  template < typename GUM_SCALAR >
592  INLINE void PRMFactory< GUM_SCALAR >::_addParent_(PRMClass< GUM_SCALAR >* c,
593  PRMAggregate< GUM_SCALAR >* agg,
594  const std::string& name) {
595  auto chains = std::vector< std::string >{name};
596  auto inputs = std::vector< PRMClassElement< GUM_SCALAR >* >();
597  _retrieveInputs_(c, chains, inputs);
598 
599  switch (agg->agg_type()) {
600  case PRMAggregate< GUM_SCALAR >::AggregateType::OR:
601  case PRMAggregate< GUM_SCALAR >::AggregateType::AND: {
602  if (inputs.front()->type() != *(_retrieveType_("boolean"))) {
603  GUM_ERROR(TypeError, "expected booleans")
604  }
605 
606  break;
607  }
608 
609  case PRMAggregate< GUM_SCALAR >::AggregateType::COUNT:
610  case PRMAggregate< GUM_SCALAR >::AggregateType::EXISTS:
611  case PRMAggregate< GUM_SCALAR >::AggregateType::FORALL: {
612  if (!agg->hasLabel()) {
613  auto param = agg->labelValue();
614  Idx label_idx = 0;
615 
616  while (label_idx < inputs.front()->type()->domainSize()) {
617  if (inputs.front()->type()->label(label_idx) == param) { break; }
618 
619  ++label_idx;
620  }
621 
622  if (label_idx == inputs.front()->type()->domainSize()) {
623  GUM_ERROR(NotFound, "could not find label")
624  }
625 
626  agg->setLabel(label_idx);
627  }
628 
629  break;
630  }
631 
632  case PRMAggregate< GUM_SCALAR >::AggregateType::SUM:
633  case PRMAggregate< GUM_SCALAR >::AggregateType::MEDIAN:
634  case PRMAggregate< GUM_SCALAR >::AggregateType::AMPLITUDE:
635  case PRMAggregate< GUM_SCALAR >::AggregateType::MIN:
636  case PRMAggregate< GUM_SCALAR >::AggregateType::MAX: {
637  break;
638  }
639 
640  default: {
641  GUM_ERROR(FatalError, "Unknown aggregator.")
642  }
643  }
644 
645  c->addArc(inputs.front()->safeName(), agg->safeName());
646  }
647 
648  template < typename GUM_SCALAR >
649  INLINE void PRMFactory< GUM_SCALAR >::endAggregator() {
650  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_aggregate);
651  _stack_.pop_back();
652  }
653 
654  template < typename GUM_SCALAR >
655  INLINE void PRMFactory< GUM_SCALAR >::addAggregator(const std::string& name,
656  const std::string& agg_type,
657  const std::vector< std::string >& chains,
658  const std::vector< std::string >& params,
659  std::string type) {
660  PRMClass< GUM_SCALAR >* c
661  = static_cast< PRMClass< GUM_SCALAR >* >(_checkStack_(1, PRMObject::prm_type::CLASS));
662  // Checking call legality
663 
664  if (chains.size() == 0) {
665  GUM_ERROR(OperationNotAllowed, "a PRMAggregate<GUM_SCALAR> requires at least one parent")
666  }
667 
668  // Retrieving the parents of the aggregate
669  std::vector< PRMClassElement< GUM_SCALAR >* > inputs;
670 
671  // This helps knowing if the aggregate has parents outside the current
672  // class
673  // (see below)
674  bool hasSC = _retrieveInputs_(c, chains, inputs);
675 
676  // Checking that all inputs shares the same PRMType (trivial
677  // if
678  // inputs.size() == 1)
679  if (inputs.size() > 1) {
680  for (auto iter = inputs.begin() + 1; iter != inputs.end(); ++iter) {
681  if ((**(iter - 1)).type() != (**iter).type()) {
682  GUM_ERROR(TypeError, "found different types")
683  }
684  }
685  }
686 
687  // Different treatments for different types of aggregate.
688  PRMAggregate< GUM_SCALAR >* agg = nullptr;
689 
690  switch (PRMAggregate< GUM_SCALAR >::str2enum(agg_type)) {
691  case PRMAggregate< GUM_SCALAR >::AggregateType::OR:
692  case PRMAggregate< GUM_SCALAR >::AggregateType::AND: {
693  if (inputs.front()->type() != *(_retrieveType_("boolean"))) {
694  GUM_ERROR(TypeError, "expected booleans")
695  }
696  if (params.size() != 0) { GUM_ERROR(OperationNotAllowed, "invalid number of paramaters") }
697 
698  agg = new PRMAggregate< GUM_SCALAR >(name,
699  PRMAggregate< GUM_SCALAR >::str2enum(agg_type),
700  inputs.front()->type());
701 
702  break;
703  }
704 
705  case PRMAggregate< GUM_SCALAR >::AggregateType::EXISTS:
706  case PRMAggregate< GUM_SCALAR >::AggregateType::FORALL: {
707  if (params.size() != 1) { GUM_ERROR(OperationNotAllowed, "invalid number of parameters") }
708 
709  Idx label_idx = 0;
710 
711  while (label_idx < inputs.front()->type()->domainSize()) {
712  if (inputs.front()->type()->label(label_idx) == params.front()) { break; }
713 
714  ++label_idx;
715  }
716 
717  if (label_idx == inputs.front()->type()->domainSize()) {
718  GUM_ERROR(NotFound, "could not find label")
719  }
720 
721  // Creating and adding the PRMAggregate<GUM_SCALAR>
722  agg = new PRMAggregate< GUM_SCALAR >(name,
723  PRMAggregate< GUM_SCALAR >::str2enum(agg_type),
724  *(_retrieveType_("boolean")),
725  label_idx);
726  agg->label();
727 
728  break;
729  }
730 
731  case PRMAggregate< GUM_SCALAR >::AggregateType::SUM:
732  case PRMAggregate< GUM_SCALAR >::AggregateType::MEDIAN:
733  case PRMAggregate< GUM_SCALAR >::AggregateType::AMPLITUDE:
734  case PRMAggregate< GUM_SCALAR >::AggregateType::MIN:
735  case PRMAggregate< GUM_SCALAR >::AggregateType::MAX: {
736  if (params.size() != 0) { GUM_ERROR(OperationNotAllowed, "invalid number of parameters") }
737 
738  auto output_type = _retrieveType_(type);
739 
740  // Creating and adding the PRMAggregate<GUM_SCALAR>
741  agg = new PRMAggregate< GUM_SCALAR >(name,
742  PRMAggregate< GUM_SCALAR >::str2enum(agg_type),
743  *output_type);
744 
745  break;
746  }
747 
748  case PRMAggregate< GUM_SCALAR >::AggregateType::COUNT: {
749  if (params.size() != 1) { GUM_ERROR(OperationNotAllowed, "invalid number of parameters") }
750 
751  Idx label_idx = 0;
752 
753  while (label_idx < inputs.front()->type()->domainSize()) {
754  if (inputs.front()->type()->label(label_idx) == params.front()) { break; }
755 
756  ++label_idx;
757  }
758 
759  if (label_idx == inputs.front()->type()->domainSize()) {
760  GUM_ERROR(NotFound, "could not find label")
761  }
762 
763  auto output_type = _retrieveType_(type);
764 
765  // Creating and adding the PRMAggregate<GUM_SCALAR>
766  agg = new PRMAggregate< GUM_SCALAR >(name,
767  PRMAggregate< GUM_SCALAR >::str2enum(agg_type),
768  *output_type,
769  label_idx);
770 
771  break;
772  }
773 
774  default: {
775  GUM_ERROR(FatalError, "Unknown aggregator.")
776  }
777  }
778 
779  std::string safe_name = agg->safeName();
780 
781  try {
782  if (hasSC) {
783  try {
784  c->add(agg);
785  } catch (DuplicateElement&) { c->overload(agg); }
786  } else {
787  // Inner aggregators can be directly used as attributes
788  auto attr
789  = new PRMScalarAttribute< GUM_SCALAR >(agg->name(), agg->type(), agg->buildImpl());
790 
791  try {
792  c->add(attr);
793  } catch (DuplicateElement&) { c->overload(attr); }
794 
795  delete agg;
796  }
797  } catch (DuplicateElement&) {
798  delete agg;
799  throw;
800  }
801 
802  for (const auto& elt: inputs) {
803  c->addArc(elt->safeName(), safe_name);
804  }
805  }
806 
807  template < typename GUM_SCALAR >
808  INLINE void PRMFactory< GUM_SCALAR >::addReferenceSlot(const std::string& type,
809  const std::string& name,
810  bool isArray) {
811  PRMClassElementContainer< GUM_SCALAR >* owner = _checkStackContainter_(1);
812  PRMClassElementContainer< GUM_SCALAR >* slotType = 0;
813 
814  try {
815  slotType = _retrieveClass_(type);
816  } catch (NotFound&) {
817  try {
818  slotType = _retrieveInterface_(type);
819  } catch (NotFound&) { GUM_ERROR(NotFound, "unknown ReferenceSlot<GUM_SCALAR> slot type") }
820  }
821 
822  PRMReferenceSlot< GUM_SCALAR >* ref
823  = new PRMReferenceSlot< GUM_SCALAR >(name, *slotType, isArray);
824 
825  try {
826  owner->add(ref);
827  } catch (DuplicateElement&) { owner->overload(ref); }
828  }
829 
830  template < typename GUM_SCALAR >
831  INLINE void PRMFactory< GUM_SCALAR >::addArray(const std::string& type,
832  const std::string& name,
833  Size size) {
834  PRMSystem< GUM_SCALAR >* model
835  = static_cast< PRMSystem< GUM_SCALAR >* >(_checkStack_(1, PRMObject::prm_type::SYSTEM));
836  PRMClass< GUM_SCALAR >* c = _retrieveClass_(type);
837  PRMInstance< GUM_SCALAR >* inst = 0;
838 
839  try {
840  model->addArray(name, *c);
841 
842  for (Size i = 0; i < size; ++i) {
843  std::stringstream elt_name;
844  elt_name << name << "[" << i << "]";
845  inst = new PRMInstance< GUM_SCALAR >(elt_name.str(), *c);
846  model->add(name, inst);
847  }
848  } catch (PRMTypeError&) {
849  delete inst;
850  throw;
851  } catch (NotFound&) {
852  delete inst;
853  throw;
854  }
855  }
856 
857  template < typename GUM_SCALAR >
858  INLINE void PRMFactory< GUM_SCALAR >::incArray(const std::string& l_i, const std::string& r_i) {
859  PRMSystem< GUM_SCALAR >* model
860  = static_cast< PRMSystem< GUM_SCALAR >* >(_checkStack_(1, PRMObject::prm_type::SYSTEM));
861 
862  if (model->isArray(l_i)) {
863  if (model->isInstance(r_i)) {
864  model->add(l_i, model->get(r_i));
865  } else {
866  GUM_ERROR(NotFound, "right value is not an instance")
867  }
868  } else {
869  GUM_ERROR(NotFound, "left value is no an array")
870  }
871  }
872 
873  template < typename GUM_SCALAR >
874  INLINE void PRMFactory< GUM_SCALAR >::setReferenceSlot(const std::string& l_i,
875  const std::string& l_ref,
876  const std::string& r_i) {
877  auto model
878  = static_cast< PRMSystem< GUM_SCALAR >* >(_checkStack_(1, PRMObject::prm_type::SYSTEM));
879  std::vector< PRMInstance< GUM_SCALAR >* > lefts;
880  std::vector< PRMInstance< GUM_SCALAR >* > rights;
881 
882  if (model->isInstance(l_i)) {
883  lefts.push_back(&(model->get(l_i)));
884  } else if (model->isArray(l_i)) {
885  for (const auto& elt: model->getArray(l_i))
886  lefts.push_back(elt);
887  } else {
888  GUM_ERROR(NotFound, "left value does not name an instance or an array")
889  }
890 
891  if (model->isInstance(r_i)) {
892  rights.push_back(&(model->get(r_i)));
893  } else if (model->isArray(r_i)) {
894  for (const auto& elt: model->getArray(r_i))
895  rights.push_back(elt);
896  } else {
897  GUM_ERROR(NotFound, "left value does not name an instance or an array")
898  }
899 
900  for (const auto l: lefts) {
901  for (const auto r: rights) {
902  auto& elt = l->type().get(l_ref);
903  if (PRMClassElement< GUM_SCALAR >::isReferenceSlot(elt)) {
904  l->add(elt.id(), *r);
905 
906  } else {
907  GUM_ERROR(NotFound, "unfound reference slot")
908  }
909  }
910  }
911  }
912 
913  template < typename GUM_SCALAR >
914  INLINE PRMSlotChain< GUM_SCALAR >*
915  PRMFactory< GUM_SCALAR >::_buildSlotChain_(PRMClassElementContainer< GUM_SCALAR >* start,
916  const std::string& name) {
917  std::vector< std::string > v;
918  decomposePath(name, v);
919  PRMClassElementContainer< GUM_SCALAR >* current = start;
920  PRMReferenceSlot< GUM_SCALAR >* ref = nullptr;
921  Sequence< PRMClassElement< GUM_SCALAR >* > elts;
922 
923  for (size_t i = 0; i < v.size(); ++i) {
924  try {
925  switch (current->get(v[i]).elt_type()) {
926  case PRMClassElement< GUM_SCALAR >::prm_refslot:
927  ref = &(static_cast< PRMReferenceSlot< GUM_SCALAR >& >(current->get(v[i])));
928  elts.insert(ref);
929  current = &(/*const_cast<PRMClassElementContainer<GUM_SCALAR>&>*/ (ref->slotType()));
930  break;
931 
932  case PRMClassElement< GUM_SCALAR >::prm_aggregate:
933  case PRMClassElement< GUM_SCALAR >::prm_attribute:
934 
935  if (i == v.size() - 1) {
936  elts.insert(&(current->get(v[i])));
937  break;
938  } else {
939  return nullptr;
940  }
941 
942  default: {
943  return nullptr;
944  }
945  }
946  } catch (NotFound&) { return nullptr; }
947  }
948 
949  GUM_ASSERT(v.size() == elts.size());
950 
951  current->setOutputNode(*(elts.back()), true);
952 
953  return new PRMSlotChain< GUM_SCALAR >(name, elts);
954  }
955 
956  template < typename GUM_SCALAR >
957  INLINE bool PRMFactory< GUM_SCALAR >::_retrieveInputs_(
958  PRMClass< GUM_SCALAR >* c,
959  const std::vector< std::string >& chains,
960  std::vector< PRMClassElement< GUM_SCALAR >* >& inputs) {
961  bool retVal = false;
962 
963  for (size_t i = 0; i < chains.size(); ++i) {
964  try {
965  inputs.push_back(&(c->get(chains[i])));
966  retVal = retVal || PRMClassElement< GUM_SCALAR >::isSlotChain(*(inputs.back()));
967  } catch (NotFound&) {
968  inputs.push_back(_buildSlotChain_(c, chains[i]));
969  retVal = true;
970 
971  if (inputs.back()) {
972  c->add(inputs.back());
973  } else {
974  GUM_ERROR(NotFound, "unknown slot chain")
975  }
976  }
977  }
978 
979  PRMType* t = _retrieveCommonType_(inputs);
980 
981  std::vector< std::pair< PRMClassElement< GUM_SCALAR >*, PRMClassElement< GUM_SCALAR >* > >
982  toAdd;
983 
984  for (const auto& elt: inputs) {
985  if ((*elt).type() != (*t)) {
986  if (PRMClassElement< GUM_SCALAR >::isSlotChain(*elt)) {
987  PRMSlotChain< GUM_SCALAR >* sc = static_cast< PRMSlotChain< GUM_SCALAR >* >(elt);
988  std::stringstream name;
989 
990  for (Size idx = 0; idx < sc->chain().size() - 1; ++idx) {
991  name << sc->chain().atPos(idx)->name() << ".";
992  }
993 
994  name << ".(" << t->name() << ")" << sc->lastElt().name();
995 
996  try {
997  toAdd.push_back(std::make_pair(elt, &(c->get(name.str()))));
998  } catch (NotFound&) {
999  toAdd.push_back(std::make_pair(elt, _buildSlotChain_(c, name.str())));
1000  }
1001  } else {
1002  std::stringstream name;
1003  name << "(" << t->name() << ")" << elt->name();
1004  toAdd.push_back(std::make_pair(elt, &(c->get(name.str()))));
1005  }
1006  }
1007  }
1008 
1009  return retVal;
1010  }
1011 
1012  template < typename GUM_SCALAR >
1013  INLINE PRMType* PRMFactory< GUM_SCALAR >::_retrieveCommonType_(
1014  const std::vector< PRMClassElement< GUM_SCALAR >* >& elts) {
1015  const PRMType* current = nullptr;
1016  HashTable< std::string, Size > counters;
1017  // Finding all types and super types
1018 
1019  for (const auto& elt: elts) {
1020  try {
1021  current = &((*elt).type());
1022 
1023  while (current != 0) {
1024  // Filling counters
1025  if (counters.exists(current->name())) {
1026  ++(counters[current->name()]);
1027  } else {
1028  counters.insert(current->name(), 1);
1029  }
1030 
1031  // Loop guard
1032  if (current->isSubType()) {
1033  current = &(current->superType());
1034  } else {
1035  current = nullptr;
1036  }
1037  }
1038  } catch (OperationNotAllowed&) {
1039  GUM_ERROR(WrongClassElement, "found a ClassElement<GUM_SCALAR> without a type")
1040  }
1041  }
1042 
1043  // We need to find the most specialized (i.e. max depth) common type
1044  current = nullptr;
1045 
1046  int max_depth = -1;
1047 
1048  int current_depth = 0;
1049 
1050  for (const auto& elt: counters) {
1051  if ((elt.second) == elts.size()) {
1052  current_depth = _typeDepth_(_retrieveType_(elt.first));
1053 
1054  if (current_depth > max_depth) {
1055  max_depth = current_depth;
1056  current = _retrieveType_(elt.first);
1057  }
1058  }
1059  }
1060 
1061  if (current) { return const_cast< PRMType* >(current); }
1062 
1063  GUM_ERROR(NotFound, "could not find a common type")
1064  }
1065 
1066  template < typename GUM_SCALAR >
1067  INLINE void
1068  PRMFactory< GUM_SCALAR >::addNoisyOrCompound(const std::string& name,
1069  const std::vector< std::string >& chains,
1070  const std::vector< float >& numbers,
1071  float leak,
1072  const std::vector< std::string >& labels) {
1073  if (currentType() != PRMObject::prm_type::CLASS) {
1074  GUM_ERROR(gum::FactoryInvalidState, "invalid state to add a noisy-or")
1075  }
1076 
1077  PRMClass< GUM_SCALAR >* c = dynamic_cast< gum::prm::PRMClass< GUM_SCALAR >* >(getCurrent());
1078 
1079  std::vector< PRMClassElement< GUM_SCALAR >* > parents;
1080 
1081  for (const auto& elt: chains)
1082  parents.push_back(&(c->get(elt)));
1083 
1084  PRMType* common_type = _retrieveCommonType_(parents);
1085 
1086  for (size_t idx = 0; idx < parents.size(); ++idx) {
1087  if (parents[idx]->type() != (*common_type)) {
1088  PRMClassElement< GUM_SCALAR >* parent = parents[idx];
1089  // Either safe_name is an non existing slot chain or an existing cast
1090  // descendant
1091  std::string safe_name = parent->cast(*common_type);
1092 
1093  if (!c->exists(safe_name)) {
1094  if (PRMClassElement< GUM_SCALAR >::isSlotChain(*parent)) {
1095  parents[idx] = _buildSlotChain_(c, safe_name);
1096  c->add(parents[idx]);
1097  } else {
1098  GUM_ERROR(NotFound, "unable to find parent")
1099  }
1100  } else {
1101  parents[idx] = &(c->get(safe_name));
1102  }
1103  }
1104  }
1105 
1106  if (numbers.size() == 1) {
1107  auto impl = new gum::MultiDimNoisyORCompound< GUM_SCALAR >(leak, numbers.front());
1108  auto attr = new PRMScalarAttribute< GUM_SCALAR >(name, retrieveType("boolean"), impl);
1109  addAttribute(attr);
1110  } else if (numbers.size() == parents.size()) {
1111  gum::MultiDimNoisyORCompound< GUM_SCALAR >* noisy
1112  = new gum::MultiDimNoisyORCompound< GUM_SCALAR >(leak);
1113  gum::prm::PRMFuncAttribute< GUM_SCALAR >* attr
1114  = new gum::prm::PRMFuncAttribute< GUM_SCALAR >(name, retrieveType("boolean"), noisy);
1115 
1116  for (size_t idx = 0; idx < numbers.size(); ++idx) {
1117  noisy->causalWeight(parents[idx]->type().variable(), numbers[idx]);
1118  }
1119 
1120  addAttribute(attr);
1121  } else {
1122  GUM_ERROR(OperationNotAllowed, "invalid parameters for a noisy or")
1123  }
1124 
1125  if (!labels.empty()) {
1126  GUM_ERROR(OperationNotAllowed, "labels definitions not handle for noisy-or")
1127  }
1128  }
1129 
1130  template < typename GUM_SCALAR >
1131  INLINE PRMType* PRMFactory< GUM_SCALAR >::_retrieveType_(const std::string& name) const {
1132  PRMType* type = nullptr;
1133  std::string full_name;
1134 
1135  // Looking for the type using its name
1136  if (_prm_->_typeMap_.exists(name)) {
1137  type = _prm_->_typeMap_[name];
1138  full_name = name;
1139  }
1140 
1141  // Looking for the type in current package
1142  std::string prefixed = _addPrefix_(name);
1143  if (_prm_->_typeMap_.exists(prefixed)) {
1144  if (type == 0) {
1145  type = _prm_->_typeMap_[prefixed];
1146  full_name = prefixed;
1147  } else if (full_name != prefixed) {
1148  GUM_ERROR(DuplicateElement, "Type name '" << name << "' is ambiguous: specify full name.")
1149  }
1150  }
1151 
1152  // Looking for the type relatively to current package
1153  std::string relatif_ns = currentPackage();
1154  size_t last_dot = relatif_ns.find_last_of('.');
1155  if (last_dot != std::string::npos) {
1156  relatif_ns = relatif_ns.substr(0, last_dot) + '.' + name;
1157  if (_prm_->_typeMap_.exists(relatif_ns)) {
1158  if (type == 0) {
1159  type = _prm_->_typeMap_[relatif_ns];
1160  full_name = relatif_ns;
1161  } else if (full_name != relatif_ns) {
1162  GUM_ERROR(DuplicateElement,
1163  "Type name '" << name << "' is ambiguous: specify full name.");
1164  }
1165  }
1166  }
1167 
1168 
1169  // Looking for the type using all declared namespaces
1170  if (!_namespaces_.empty()) {
1171  auto ns_list = _namespaces_.back();
1172  for (gum::Size i = 0; i < ns_list->size(); ++i) {
1173  std::string ns = (*ns_list)[i];
1174  std::string ns_name = ns + "." + name;
1175  if (_prm_->_typeMap_.exists(ns_name)) {
1176  if (type == 0) {
1177  type = _prm_->_typeMap_[ns_name];
1178  full_name = ns_name;
1179  } else if (full_name != ns_name) {
1180  GUM_ERROR(DuplicateElement,
1181  "Type name '" << name << "' is ambiguous: specify full name.");
1182  }
1183  }
1184  }
1185  }
1186 
1187  if (type == 0) { GUM_ERROR(NotFound, "Type '" << name << "' not found, check imports.") }
1188 
1189  return type;
1190  }
1191 
1192  template < typename GUM_SCALAR >
1193  PRMClass< GUM_SCALAR >*
1194  PRMFactory< GUM_SCALAR >::_retrieveClass_(const std::string& name) const {
1195  PRMClass< GUM_SCALAR >* a_class = nullptr;
1196  std::string full_name;
1197 
1198  // Looking for the type using its name
1199  if (_prm_->_classMap_.exists(name)) {
1200  a_class = _prm_->_classMap_[name];
1201  full_name = name;
1202  }
1203 
1204  // Looking for the type using current package
1205  std::string prefixed = _addPrefix_(name);
1206  if (_prm_->_classMap_.exists(prefixed)) {
1207  if (a_class == nullptr) {
1208  a_class = _prm_->_classMap_[prefixed];
1209  full_name = prefixed;
1210  } else if (full_name != prefixed) {
1211  GUM_ERROR(DuplicateElement,
1212  "Class name '" << name << "' is ambiguous: specify full name.");
1213  }
1214  }
1215 
1216  // Looking for the class using all declared namespaces
1217  if (!_namespaces_.empty()) {
1218  auto ns_list = _namespaces_.back();
1219  for (gum::Size i = 0; i < ns_list->size(); ++i) {
1220  std::string ns = (*ns_list)[i];
1221  std::string ns_name = ns + "." + name;
1222  if (_prm_->_classMap_.exists(ns_name)) {
1223  if (a_class == 0) {
1224  a_class = _prm_->_classMap_[ns_name];
1225  full_name = ns_name;
1226  } else if (full_name != ns_name) {
1227  GUM_ERROR(DuplicateElement,
1228  "Class name '" << name << "' is ambiguous: specify full name.");
1229  }
1230  }
1231  }
1232  }
1233 
1234  if (a_class == 0) { GUM_ERROR(NotFound, "Class '" << name << "' not found, check imports.") }
1235 
1236  return a_class;
1237  }
1238 
1239  template < typename GUM_SCALAR >
1240  PRMInterface< GUM_SCALAR >*
1241  PRMFactory< GUM_SCALAR >::_retrieveInterface_(const std::string& name) const {
1242  PRMInterface< GUM_SCALAR >* interface = nullptr;
1243  std::string full_name;
1244 
1245  // Looking for the type using its name
1246  if (_prm_->_interfaceMap_.exists(name)) {
1247  interface = _prm_->_interfaceMap_[name];
1248  full_name = name;
1249  }
1250 
1251  // Looking for the type using current package
1252  std::string prefixed = _addPrefix_(name);
1253  if (_prm_->_interfaceMap_.exists(prefixed)) {
1254  if (interface == nullptr) {
1255  interface = _prm_->_interfaceMap_[prefixed];
1256  full_name = prefixed;
1257  } else if (full_name != prefixed) {
1258  GUM_ERROR(DuplicateElement,
1259  "Interface name '" << name << "' is ambiguous: specify full name.");
1260  }
1261  }
1262 
1263  // Looking for the interf using all declared namespaces
1264  if (!_namespaces_.empty()) {
1265  auto ns_list = _namespaces_.back();
1266  // for( const auto & ns : *( _namespaces_.top()) ) {
1267  for (gum::Size i = 0; i < ns_list->size(); ++i) {
1268  std::string ns = (*ns_list)[i];
1269  std::string ns_name = ns + "." + name;
1270 
1271  if (_prm_->_interfaceMap_.exists(ns_name)) {
1272  if (interface == nullptr) {
1273  interface = _prm_->_interfaceMap_[ns_name];
1274  full_name = ns_name;
1275  } else if (full_name != ns_name) {
1276  GUM_ERROR(DuplicateElement,
1277  "Interface name '" << name << "' is ambiguous: specify full name.");
1278  }
1279  }
1280  }
1281  }
1282 
1283  if (interface == nullptr) {
1284  GUM_ERROR(NotFound, "Interface '" << name << "' not found, check imports.")
1285  }
1286 
1287  return interface;
1288  }
1289 
1290  template < typename GUM_SCALAR >
1291  INLINE PRMFactory< GUM_SCALAR >::PRMFactory() {
1292  GUM_CONSTRUCTOR(PRMFactory);
1293  _prm_ = new PRM< GUM_SCALAR >();
1294  }
1295 
1296  template < typename GUM_SCALAR >
1297  INLINE PRMFactory< GUM_SCALAR >::PRMFactory(PRM< GUM_SCALAR >* prm) :
1298  IPRMFactory(), _prm_(prm) {
1299  GUM_CONSTRUCTOR(PRMFactory);
1300  }
1301 
1302  template < typename GUM_SCALAR >
1303  INLINE PRMFactory< GUM_SCALAR >::~PRMFactory() {
1304  GUM_DESTRUCTOR(PRMFactory);
1305  while (!_namespaces_.empty()) {
1306  auto ns = _namespaces_.back();
1307  _namespaces_.pop_back();
1308  delete ns;
1309  }
1310  }
1311 
1312  template < typename GUM_SCALAR >
1313  INLINE PRM< GUM_SCALAR >* PRMFactory< GUM_SCALAR >::prm() const {
1314  return _prm_;
1315  }
1316 
1317  template < typename GUM_SCALAR >
1318  INLINE PRMObject::prm_type PRMFactory< GUM_SCALAR >::currentType() const {
1319  if (_stack_.size() == 0) { GUM_ERROR(NotFound, "no object being built") }
1320 
1321  return _stack_.back()->obj_type();
1322  }
1323 
1324  template < typename GUM_SCALAR >
1325  INLINE PRMObject* PRMFactory< GUM_SCALAR >::getCurrent() {
1326  if (_stack_.size() == 0) { GUM_ERROR(NotFound, "no object being built") }
1327 
1328  return _stack_.back();
1329  }
1330 
1331  template < typename GUM_SCALAR >
1332  INLINE const PRMObject* PRMFactory< GUM_SCALAR >::getCurrent() const {
1333  if (_stack_.size() == 0) { GUM_ERROR(NotFound, "no object being built") }
1334 
1335  return _stack_.back();
1336  }
1337 
1338  template < typename GUM_SCALAR >
1339  INLINE PRMObject* PRMFactory< GUM_SCALAR >::closeCurrent() {
1340  if (_stack_.size() > 0) {
1341  PRMObject* obj = _stack_.back();
1342  _stack_.pop_back();
1343  return obj;
1344  } else {
1345  return 0;
1346  }
1347  }
1348 
1349  template < typename GUM_SCALAR >
1350  INLINE std::string PRMFactory< GUM_SCALAR >::currentPackage() const {
1351  return (_packages_.empty()) ? "" : _packages_.back();
1352  }
1353 
1354  template < typename GUM_SCALAR >
1355  INLINE void PRMFactory< GUM_SCALAR >::startDiscreteType(const std::string& name,
1356  std::string super) {
1357  std::string real_name = _addPrefix_(name);
1358  if (_prm_->_typeMap_.exists(real_name)) {
1359  GUM_ERROR(DuplicateElement, "'" << real_name << "' is already used.")
1360  }
1361  if (super == "") {
1362  auto t = new PRMType(LabelizedVariable(real_name, "", 0));
1363  _stack_.push_back(t);
1364  } else {
1365  auto t = new PRMType(LabelizedVariable(real_name, "", 0));
1366  t->_superType_ = _retrieveType_(super);
1367  t->_label_map_ = new std::vector< Idx >();
1368  _stack_.push_back(t);
1369  }
1370  }
1371 
1372  template < typename GUM_SCALAR >
1373  INLINE void PRMFactory< GUM_SCALAR >::addLabel(const std::string& l, std::string extends) {
1374  if (extends == "") {
1375  PRMType* t = static_cast< PRMType* >(_checkStack_(1, PRMObject::prm_type::TYPE));
1376  LabelizedVariable* var = dynamic_cast< LabelizedVariable* >(t->_var_);
1377 
1378  if (!var) {
1379  GUM_ERROR(FatalError, "the current type's variable is not a LabelizedVariable.")
1380  } else if (t->_superType_) {
1381  GUM_ERROR(OperationNotAllowed, "current type is a subtype.")
1382  }
1383 
1384  try {
1385  var->addLabel(l);
1386  } catch (DuplicateElement&) {
1387  GUM_ERROR(DuplicateElement, "a label '" << l << "' already exists")
1388  }
1389  } else {
1390  PRMType* t = static_cast< PRMType* >(_checkStack_(1, PRMObject::prm_type::TYPE));
1391  LabelizedVariable* var = dynamic_cast< LabelizedVariable* >(t->_var_);
1392 
1393  if (!var) {
1394  GUM_ERROR(FatalError, "the current type's variable is not a LabelizedVariable.")
1395  } else if (!t->_superType_) {
1396  GUM_ERROR(OperationNotAllowed, "current type is not a subtype.")
1397  }
1398 
1399  bool found = false;
1400 
1401  for (Idx i = 0; i < t->_superType_->_var_->domainSize(); ++i) {
1402  if (t->_superType_->_var_->label(i) == extends) {
1403  try {
1404  var->addLabel(l);
1405  } catch (DuplicateElement&) {
1406  GUM_ERROR(DuplicateElement, "a label '" << l << "' already exists")
1407  }
1408 
1409  t->_label_map_->push_back(i);
1410 
1411  found = true;
1412  break;
1413  }
1414  }
1415 
1416  if (!found) { GUM_ERROR(NotFound, "inexistent label in super type.") }
1417  }
1418  }
1419 
1420  template < typename GUM_SCALAR >
1421  INLINE void PRMFactory< GUM_SCALAR >::endDiscreteType() {
1422  PRMType* t = static_cast< PRMType* >(_checkStack_(1, PRMObject::prm_type::TYPE));
1423 
1424  if (!t->_isValid_()) {
1425  GUM_ERROR(OperationNotAllowed, "current type is not a valid subtype")
1426  } else if (t->variable().domainSize() < 2) {
1427  GUM_ERROR(OperationNotAllowed, "current type is not a valid discrete type")
1428  }
1429 
1430  _prm_->_typeMap_.insert(t->name(), t);
1431 
1432  _prm_->_types_.insert(t);
1433  _stack_.pop_back();
1434  }
1435 
1436  template < typename GUM_SCALAR >
1437  INLINE void PRMFactory< GUM_SCALAR >::startDiscretizedType(const std::string& name) {
1438  std::string real_name = _addPrefix_(name);
1439  if (_prm_->_typeMap_.exists(real_name)) {
1440  GUM_ERROR(DuplicateElement, "'" << real_name << "' is already used.")
1441  }
1442  auto var = DiscretizedVariable< double >(real_name, "");
1443  auto t = new PRMType(var);
1444  _stack_.push_back(t);
1445  }
1446 
1447  template < typename GUM_SCALAR >
1448  INLINE void PRMFactory< GUM_SCALAR >::addTick(double tick) {
1449  PRMType* t = static_cast< PRMType* >(_checkStack_(1, PRMObject::prm_type::TYPE));
1450  DiscretizedVariable< double >* var = dynamic_cast< DiscretizedVariable< double >* >(t->_var_);
1451 
1452  if (!var) { GUM_ERROR(FatalError, "the current type's variable is not a LabelizedVariable.") }
1453 
1454  try {
1455  var->addTick(tick);
1456  } catch (DefaultInLabel&) {
1457  GUM_ERROR(OperationNotAllowed, "tick already in used for this variable")
1458  }
1459  }
1460 
1461  template < typename GUM_SCALAR >
1462  INLINE void PRMFactory< GUM_SCALAR >::endDiscretizedType() {
1463  PRMType* t = static_cast< PRMType* >(_checkStack_(1, PRMObject::prm_type::TYPE));
1464 
1465  if (t->variable().domainSize() < 2) {
1466  GUM_ERROR(OperationNotAllowed, "current type is not a valid discrete type")
1467  }
1468 
1469  _prm_->_typeMap_.insert(t->name(), t);
1470 
1471  _prm_->_types_.insert(t);
1472  _stack_.pop_back();
1473  }
1474 
1475  template < typename GUM_SCALAR >
1476  INLINE void
1477  PRMFactory< GUM_SCALAR >::addRangeType(const std::string& name, long minVal, long maxVal) {
1478  std::string real_name = _addPrefix_(name);
1479  if (_prm_->_typeMap_.exists(real_name)) {
1480  std::stringstream msg;
1481  msg << "\"" << real_name << "' is already used.";
1482  GUM_ERROR(DuplicateElement, msg.str())
1483  }
1484 
1485  auto var = RangeVariable(real_name, "", minVal, maxVal);
1486  auto t = new PRMType(var);
1487 
1488  if (t->variable().domainSize() < 2) {
1489  GUM_ERROR(OperationNotAllowed, "current type is not a valid discrete type")
1490  }
1491 
1492  _prm_->_typeMap_.insert(t->name(), t);
1493  _prm_->_types_.insert(t);
1494  }
1495 
1496  template < typename GUM_SCALAR >
1497  INLINE void PRMFactory< GUM_SCALAR >::endInterface() {
1498  _checkStack_(1, PRMObject::prm_type::PRM_INTERFACE);
1499  _stack_.pop_back();
1500  }
1501 
1502  template < typename GUM_SCALAR >
1503  INLINE void PRMFactory< GUM_SCALAR >::addAttribute(const std::string& type,
1504  const std::string& name) {
1505  _checkStack_(1, PRMObject::prm_type::PRM_INTERFACE);
1506  startAttribute(type, name);
1507  endAttribute();
1508  }
1509 
1510  template < typename GUM_SCALAR >
1511  INLINE void PRMFactory< GUM_SCALAR >::startAttribute(const std::string& type,
1512  const std::string& name,
1513  bool scalar_attr) {
1514  PRMClassElementContainer< GUM_SCALAR >* c = _checkStackContainter_(1);
1515  PRMAttribute< GUM_SCALAR >* a = nullptr;
1516 
1517  if (PRMObject::isClass(*c) && (!scalar_attr)) {
1518  a = new PRMFormAttribute< GUM_SCALAR >(static_cast< PRMClass< GUM_SCALAR >& >(*c),
1519  name,
1520  *_retrieveType_(type));
1521 
1522  } else {
1523  a = new PRMScalarAttribute< GUM_SCALAR >(name, *_retrieveType_(type));
1524  }
1525 
1526  std::string dot = ".";
1527 
1528  try {
1529  try {
1530  c->add(a);
1531  } catch (DuplicateElement&) { c->overload(a); }
1532  } catch (Exception&) {
1533  if (a != nullptr && (!c->exists(a->id()))) { delete a; }
1534  }
1535 
1536  _stack_.push_back(a);
1537  }
1538 
1539  template < typename GUM_SCALAR >
1540  INLINE void PRMFactory< GUM_SCALAR >::continueAttribute(const std::string& name) {
1541  PRMClassElementContainer< GUM_SCALAR >* c = _checkStackContainter_(1);
1542 
1543  if (!c->exists(name)) GUM_ERROR(NotFound, "Attribute " << name << "not found")
1544 
1545  auto& a = c->get(name);
1546 
1547  if (!PRMClassElement< GUM_SCALAR >::isAttribute(a))
1548  GUM_ERROR(OperationNotAllowed, "Element " << name << " not an attribute")
1549 
1550  _stack_.push_back(&a);
1551  }
1552 
1553  template < typename GUM_SCALAR >
1554  INLINE void PRMFactory< GUM_SCALAR >::endAttribute() {
1555  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_attribute);
1556  _stack_.pop_back();
1557  }
1558 
1559  template < typename GUM_SCALAR >
1560  INLINE void PRMFactory< GUM_SCALAR >::startSystem(const std::string& name) {
1561  if (_prm_->_systemMap_.exists(name)) {
1562  GUM_ERROR(DuplicateElement, "'" << name << "' is already used.")
1563  }
1564  PRMSystem< GUM_SCALAR >* model = new PRMSystem< GUM_SCALAR >(_addPrefix_(name));
1565  _stack_.push_back(model);
1566  _prm_->_systemMap_.insert(model->name(), model);
1567  _prm_->_systems_.insert(model);
1568  }
1569 
1570  template < typename GUM_SCALAR >
1571  INLINE void PRMFactory< GUM_SCALAR >::endSystem() {
1572  try {
1573  PRMSystem< GUM_SCALAR >* model
1574  = static_cast< PRMSystem< GUM_SCALAR >* >(_checkStack_(1, PRMObject::prm_type::SYSTEM));
1575  _stack_.pop_back();
1576  model->instantiate();
1577  } catch (Exception&) { GUM_ERROR(FatalError, "could not create system") }
1578  }
1579 
1580  template < typename GUM_SCALAR >
1581  INLINE void PRMFactory< GUM_SCALAR >::addInstance(const std::string& type,
1582  const std::string& name) {
1583  auto c = _retrieveClass_(type);
1584 
1585  // If class contains parameters, calls the proper addIsntance method
1586  if (c->parameters().size() > 0) {
1587  HashTable< std::string, double > params;
1588  addInstance(type, name, params);
1589 
1590  } else {
1591  _addInstance_(c, name);
1592  }
1593  }
1594 
1595  template < typename GUM_SCALAR >
1596  INLINE void
1597  PRMFactory< GUM_SCALAR >::addInstance(const std::string& type,
1598  const std::string& name,
1599  const HashTable< std::string, double >& params) {
1600  auto c = _retrieveClass_(type);
1601 
1602  if (c->parameters().empty()) {
1603  if (params.empty()) {
1604  _addInstance_(c, name);
1605  } else {
1606  GUM_ERROR(OperationNotAllowed, "Class " + type + " does not have parameters")
1607  }
1608 
1609  } else {
1610  auto my_params = params;
1611  // Adding all parameters to my_params
1612  for (const auto& p: c->parameters()) {
1613  if (!my_params.exists(p->name())) { my_params.insert(p->name(), p->value()); }
1614  }
1615 
1616  // Building sub class name using my_params
1617  std::stringstream sBuff;
1618  sBuff << c->name() << "<";
1619 
1620  for (const auto& p: my_params) {
1621  sBuff << p.first << "=" << p.second << ",";
1622  }
1623 
1624  // Removing last , and adding closing >
1625  std::string sub_c = sBuff.str().substr(0, sBuff.str().size() - 1) + ">";
1626 
1627  // Adding class in current package
1628  try {
1629  auto pck_cpy = _packages_;
1630  _packages_.clear();
1631 
1632  startClass(sub_c, c->name());
1633 
1634  // Update inherited parameters
1635  for (auto p: my_params) {
1636  auto type = static_cast< PRMParameter< GUM_SCALAR >& >(c->get(p.first)).valueType();
1637  if (type == PRMParameter< GUM_SCALAR >::ParameterType::INT) {
1638  addParameter("int", p.first, p.second);
1639 
1640  } else {
1641  addParameter("real", p.first, p.second);
1642  }
1643  }
1644 
1645  endClass();
1646 
1647  _packages_ = pck_cpy;
1648 
1649  } catch (DuplicateElement&) {
1650  // Sub Class already exists in this system
1651  }
1652  c = _retrieveClass_(sub_c);
1653  _addInstance_(c, name);
1654  }
1655  }
1656 
1657  template < typename GUM_SCALAR >
1658  INLINE void PRMFactory< GUM_SCALAR >::_addInstance_(PRMClass< GUM_SCALAR >* type,
1659  const std::string& name) {
1660  PRMInstance< GUM_SCALAR >* i = nullptr;
1661  try {
1662  auto s
1663  = static_cast< PRMSystem< GUM_SCALAR >* >(_checkStack_(1, PRMObject::prm_type::SYSTEM));
1664  i = new PRMInstance< GUM_SCALAR >(name, *type);
1665  s->add(i);
1666 
1667  } catch (OperationNotAllowed&) {
1668  if (i) { delete i; }
1669  throw;
1670  }
1671  }
1672 
1673  template < typename GUM_SCALAR >
1674  INLINE std::string PRMFactory< GUM_SCALAR >::_addPrefix_(const std::string& str) const {
1675  if (!_packages_.empty()) {
1676  std::string full_name = _packages_.back();
1677  full_name.append(".");
1678  full_name.append(str);
1679  return full_name;
1680  } else {
1681  return str;
1682  }
1683  }
1684 
1685  template < typename GUM_SCALAR >
1686  INLINE PRMObject* PRMFactory< GUM_SCALAR >::_checkStack_(Idx i, PRMObject::prm_type obj_type) {
1687  // Don't forget that Idx are unsigned int
1688  if (_stack_.size() - i > _stack_.size()) {
1689  GUM_ERROR(FactoryInvalidState, "illegal sequence of calls")
1690  }
1691 
1692  PRMObject* obj = _stack_[_stack_.size() - i];
1693 
1694  if (obj->obj_type() != obj_type) {
1695  GUM_ERROR(FactoryInvalidState, "illegal sequence of calls")
1696  }
1697 
1698  return obj;
1699  }
1700 
1701  template < typename GUM_SCALAR >
1702  INLINE PRMClassElementContainer< GUM_SCALAR >*
1703  PRMFactory< GUM_SCALAR >::_checkStackContainter_(Idx i) {
1704  // Don't forget that Idx are unsigned int
1705  if (_stack_.size() - i > _stack_.size()) {
1706  GUM_ERROR(FactoryInvalidState, "illegal sequence of calls")
1707  }
1708 
1709  PRMObject* obj = _stack_[_stack_.size() - i];
1710 
1711  if ((obj->obj_type() == PRMObject::prm_type::CLASS)
1712  || (obj->obj_type() == PRMObject::prm_type::PRM_INTERFACE)) {
1713  return static_cast< PRMClassElementContainer< GUM_SCALAR >* >(obj);
1714  } else {
1715  GUM_ERROR(FactoryInvalidState, "illegal sequence of calls")
1716  }
1717  }
1718 
1719  template < typename GUM_SCALAR >
1720  INLINE PRMClassElement< GUM_SCALAR >* PRMFactory< GUM_SCALAR >::_checkStack_(
1721  Idx i,
1722  typename PRMClassElement< GUM_SCALAR >::ClassElementType elt_type) {
1723  // Don't forget that Idx are unsigned int
1724  if (_stack_.size() - i > _stack_.size()) {
1725  GUM_ERROR(FactoryInvalidState, "illegal sequence of calls")
1726  }
1727 
1728  PRMClassElement< GUM_SCALAR >* obj
1729  = dynamic_cast< PRMClassElement< GUM_SCALAR >* >(_stack_[_stack_.size() - i]);
1730 
1731  if (obj == 0) { GUM_ERROR(FactoryInvalidState, "illegal sequence of calls") }
1732 
1733  if (obj->elt_type() != elt_type) {
1734  GUM_ERROR(FactoryInvalidState, "illegal sequence of calls")
1735  }
1736 
1737  return obj;
1738  }
1739 
1740  template < typename GUM_SCALAR >
1741  INLINE int PRMFactory< GUM_SCALAR >::_typeDepth_(const PRMType* t) {
1742  int depth = 0;
1743  const PRMType* current = t;
1744 
1745  while (current->isSubType()) {
1746  ++depth;
1747  current = &(current->superType());
1748  }
1749 
1750  return depth;
1751  }
1752 
1753  template < typename GUM_SCALAR >
1754  INLINE void PRMFactory< GUM_SCALAR >::pushPackage(const std::string& name) {
1755  _packages_.push_back(name);
1756  _namespaces_.push_back(new List< std::string >());
1757  }
1758 
1759  template < typename GUM_SCALAR >
1760  INLINE std::string PRMFactory< GUM_SCALAR >::popPackage() {
1761  std::string plop = currentPackage();
1762 
1763  if (!_packages_.empty()) {
1764  std::string s = _packages_.back();
1765  _packages_.pop_back();
1766 
1767  if (_namespaces_.size() > 0) {
1768  delete _namespaces_.back();
1769  _namespaces_.pop_back();
1770  }
1771  return s;
1772  }
1773 
1774  return plop;
1775  }
1776 
1777  template < typename GUM_SCALAR >
1778  INLINE void PRMFactory< GUM_SCALAR >::addImport(const std::string& name) {
1779  if (name.size() == 0) { GUM_ERROR(OperationNotAllowed, "illegal import name") }
1780  if (_namespaces_.empty()) { _namespaces_.push_back(new List< std::string >()); }
1781  _namespaces_.back()->push_back(name);
1782  }
1783 
1784  template < typename GUM_SCALAR >
1785  INLINE void PRMFactory< GUM_SCALAR >::setReferenceSlot(const std::string& l_i,
1786  const std::string& r_i) {
1787  size_t pos = l_i.find_last_of('.');
1788 
1789  if (pos != std::string::npos) {
1790  std::string l_ref = l_i.substr(pos + 1, std::string::npos);
1791  setReferenceSlot(l_i.substr(0, pos), l_ref, r_i);
1792  } else {
1793  GUM_ERROR(NotFound, "left value does not name an instance or an array")
1794  }
1795  }
1796 
1797  template < typename GUM_SCALAR >
1798  INLINE PRMClass< GUM_SCALAR >&
1799  PRMFactory< GUM_SCALAR >::retrieveClass(const std::string& name) {
1800  return *_retrieveClass_(name);
1801  }
1802 
1803  template < typename GUM_SCALAR >
1804  INLINE PRMType& PRMFactory< GUM_SCALAR >::retrieveType(const std::string& name) {
1805  return *_retrieveType_(name);
1806  }
1807 
1808  template < typename GUM_SCALAR >
1809  INLINE PRMType& PRMFactory< GUM_SCALAR >::retrieveCommonType(
1810  const std::vector< PRMClassElement< GUM_SCALAR >* >& elts) {
1811  return *(_retrieveCommonType_(elts));
1812  }
1813 
1814 
1815  template < typename GUM_SCALAR >
1816  INLINE bool PRMFactory< GUM_SCALAR >::isClassOrInterface(const std::string& type) const {
1817  try {
1818  _retrieveClass_(type);
1819  return true;
1820 
1821  } catch (NotFound&) {
1822  } catch (DuplicateElement&) {}
1823 
1824  try {
1825  _retrieveInterface_(type);
1826  return true;
1827 
1828  } catch (NotFound&) {
1829  } catch (DuplicateElement&) {}
1830 
1831  return false;
1832  }
1833 
1834  template < typename GUM_SCALAR >
1835  INLINE bool PRMFactory< GUM_SCALAR >::isArrayInCurrentSystem(const std::string& name) const {
1836  const PRMSystem< GUM_SCALAR >* system
1837  = static_cast< const PRMSystem< GUM_SCALAR >* >(getCurrent());
1838  return (system && system->isArray(name));
1839  }
1840 
1841  template < typename GUM_SCALAR >
1842  INLINE void
1843  PRMFactory< GUM_SCALAR >::setRawCPFByColumns(const std::vector< std::string >& array) {
1844  _checkStack_(2, PRMObject::prm_type::CLASS);
1845 
1846  auto a = static_cast< PRMFormAttribute< GUM_SCALAR >* >(
1847  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_attribute));
1848 
1849  if (a->formulas().domainSize() != array.size()) {
1850  GUM_ERROR(OperationNotAllowed, "illegal CPF size")
1851  }
1852 
1853  if (a->formulas().nbrDim() == 1) {
1854  setRawCPFByLines(array);
1855 
1856  } else {
1857  Instantiation inst(a->formulas());
1858  Instantiation jnst;
1859  for (auto idx = inst.variablesSequence().rbegin(); idx != inst.variablesSequence().rend();
1860  --idx) {
1861  jnst.add(**idx);
1862  }
1863 
1864  jnst.setFirst();
1865  auto idx = (std::size_t)0;
1866  while ((!jnst.end()) && idx < array.size()) {
1867  inst.setVals(jnst);
1868  a->formulas().set(inst, array[idx]);
1869  jnst.inc();
1870  ++idx;
1871  }
1872 
1873  // Generate cpf by calling it
1874  a->cpf();
1875  }
1876  }
1877 
1878  template < typename GUM_SCALAR >
1879  INLINE void
1880  PRMFactory< GUM_SCALAR >::setRawCPFByLines(const std::vector< std::string >& array) {
1881  _checkStack_(2, PRMObject::prm_type::CLASS);
1882 
1883  auto a = static_cast< PRMFormAttribute< GUM_SCALAR >* >(
1884  _checkStack_(1, PRMClassElement< GUM_SCALAR >::prm_attribute));
1885 
1886  if (a->formulas().domainSize() != array.size()) {
1887  GUM_ERROR(OperationNotAllowed, "illegal CPF size")
1888  }
1889 
1890  a->formulas().populate(array);
1891 
1892  /// Generate CPF
1893  a->cpf();
1894  }
1895 
1896  } /* namespace prm */
1897 } /* namespace gum */