aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
O3ClassFactory_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2026 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41#pragma once
42
43
51
53
54namespace gum {
55 namespace prm {
56 namespace o3prm {
57
58 template < GUM_Numeric GUM_SCALAR >
60 O3PRM& o3_prm,
62 ErrorsContainer& errors) :
63 _prm_(&prm), _o3_prm_(&o3_prm), _solver_(&solver), _errors_(&errors) {
64 GUM_CONSTRUCTOR(O3ClassFactory);
65 }
66
67 template < GUM_Numeric GUM_SCALAR >
74
75 template < GUM_Numeric GUM_SCALAR >
77 _prm_(std::move(src._prm_)), _o3_prm_(std::move(src._o3_prm_)),
78 _solver_(std::move(src._solver_)), _errors_(std::move(src._errors_)),
79 _nameMap_(std::move(src._nameMap_)), _classMap_(std::move(src._classMap_)),
80 _nodeMap_(std::move(src._nodeMap_)), _dag_(std::move(src._dag_)),
81 _o3Classes_(std::move(src._o3Classes_)) {
82 GUM_CONS_MOV(O3ClassFactory);
83 }
84
85 template < GUM_Numeric GUM_SCALAR >
89
90 template < GUM_Numeric GUM_SCALAR >
93 if (this == &src) { return *this; }
94 _prm_ = src._prm_;
95 _o3_prm_ = src._o3_prm_;
96 _solver_ = src._solver_;
97 _errors_ = src._errors_;
98 _nameMap_ = src._nameMap_;
100 _nodeMap_ = src._nodeMap_;
101 _dag_ = src._dag_;
103 return *this;
104 }
105
106 template < GUM_Numeric GUM_SCALAR >
109 if (this == &src) { return *this; }
110 _prm_ = std::move(src._prm_);
111 _o3_prm_ = std::move(src._o3_prm_);
112 _solver_ = std::move(src._solver_);
113 _errors_ = std::move(src._errors_);
114 _nameMap_ = std::move(src._nameMap_);
115 _classMap_ = std::move(src._classMap_);
116 _nodeMap_ = std::move(src._nodeMap_);
117 _dag_ = std::move(src._dag_);
118 _o3Classes_ = std::move(src._o3Classes_);
119 return *this;
120 }
121
122 template < GUM_Numeric GUM_SCALAR >
125
126 // Class with a super class must be declared after
127 if (_checkO3Classes_()) {
129
130 for (auto c: _o3Classes_) {
131 // Soving interfaces
132 auto implements = Set< std::string >();
133 for (auto& i: c->interfaces()) {
134 if (_solver_->resolveInterface(i)) { implements.insert(i.label()); }
135 }
136
137 // Adding the class
138 if (_solver_->resolveClass(c->superLabel())) {
139 factory.startClass(c->name().label(), c->superLabel().label(), &implements, true);
140 factory.endClass(false);
141 }
142 }
143 }
144 }
145
146 template < GUM_Numeric GUM_SCALAR >
148 auto topo_order = _dag_.topologicalOrder();
149
150 for (auto id = topo_order.rbegin(); id != topo_order.rend(); --id) {
151 _o3Classes_.push_back(_nodeMap_[*id]);
152 }
153 }
154
155 template < GUM_Numeric GUM_SCALAR >
159
160 template < GUM_Numeric GUM_SCALAR >
162 for (auto& c: _o3_prm_->classes()) {
163 auto id = _dag_.addNode();
164
165 try {
166 _nameMap_.insert(c->name().label(), id);
167 _classMap_.insert(c->name().label(), c.get());
168 _nodeMap_.insert(id, c.get());
169
170 } catch (DuplicateElement const&) {
171 O3PRM_CLASS_DUPLICATE(c->name(), *_errors_);
172 return false;
173 }
174 }
175
176 return true;
177 }
178
179 template < GUM_Numeric GUM_SCALAR >
181 for (auto& c: _o3_prm_->classes()) {
182 if (c->superLabel().label() != "") {
183 if (!_solver_->resolveClass(c->superLabel())) { return false; }
184
185 auto head = _nameMap_[c->superLabel().label()];
186 auto tail = _nameMap_[c->name().label()];
187
188 try {
189 _dag_.addArc(tail, head);
190 } catch (InvalidDirectedCycle const&) {
191 // Cyclic inheritance
192 O3PRM_CLASS_CYLIC_INHERITANCE(c->name(), c->superLabel(), *_errors_);
193 return false;
194 }
195 }
196 }
197
198 return true;
199 }
200
201 template < GUM_Numeric GUM_SCALAR >
203 for (auto& c: _o3_prm_->classes()) {
204 if (_checkImplementation_(*c)) {
205 _prm_->getClass(c->name().label()).initializeInheritance();
206 }
207 }
208 }
209
213
214 template < GUM_Numeric GUM_SCALAR >
216 // Saving attributes names for fast lookup
217 auto attr_map = AttrMap();
218 for (auto& a: c.attributes()) {
219 attr_map.insert(a->name().label(), a.get());
220 }
221
222 // Saving aggregates names for fast lookup
223 auto agg_map = AggMap();
224 for (auto& agg: c.aggregates()) {
225 agg_map.insert(agg.name().label(), &agg);
226 }
227
228 auto ref_map = RefMap();
229 for (auto& ref: c.referenceSlots()) {
230 ref_map.insert(ref.name().label(), &ref);
231 }
232
233 // Cheking interface implementation
234 for (auto& i: c.interfaces()) {
235 if (_solver_->resolveInterface(i)) {
236 if (!_checkImplementation_(c, i, attr_map, agg_map, ref_map)) { return false; }
237 }
238 }
239
240 return true;
241 }
242
243 template < GUM_Numeric GUM_SCALAR >
245 O3Label& i,
246 AttrMap& attr_map,
247 AggMap& agg_map,
248 RefMap& ref_map) {
249 const auto& real_i = _prm_->getInterface(i.label());
250
251 auto counter = (Size)0;
252 for (const auto& a: real_i.attributes()) {
253 if (attr_map.exists(a->name())) {
254 ++counter;
255
256 if (!_checkImplementation_(attr_map[a->name()]->type(), a->type())) {
257 O3PRM_CLASS_ATTR_IMPLEMENTATION(c.name(), i, attr_map[a->name()]->name(), *_errors_);
258 return false;
259 }
260 }
261
262 if (agg_map.exists(a->name())) {
263 ++counter;
264
265 if (!_checkImplementation_(agg_map[a->name()]->variableType(), a->type())) {
266 O3PRM_CLASS_AGG_IMPLEMENTATION(c.name(), i, agg_map[a->name()]->name(), *_errors_);
267 return false;
268 }
269 }
270 }
271
272 if (counter != real_i.attributes().size()) {
273 O3PRM_CLASS_MISSING_ATTRIBUTES(c.name(), i, *_errors_);
274 return false;
275 }
276
277 counter = 0;
278 for (const auto& r: real_i.referenceSlots()) {
279 if (ref_map.exists(r->name())) {
280 ++counter;
281
282 if (!_checkImplementation_(ref_map[r->name()]->type(), r->slotType())) {
283 O3PRM_CLASS_REF_IMPLEMENTATION(c.name(), i, ref_map[r->name()]->name(), *_errors_);
284 return false;
285 }
286 }
287 }
288 return true;
289 }
290
291 template < GUM_Numeric GUM_SCALAR >
293 const PRMType& type) {
294 if (!_solver_->resolveType(o3_type)) { return false; }
295
296 return _prm_->type(o3_type.label()).isSubTypeOf(type);
297 }
298
299 template < GUM_Numeric GUM_SCALAR >
301 O3Label& o3_type,
303 if (!_solver_->resolveSlotType(o3_type)) { return false; }
304
305 if (_prm_->isInterface(o3_type.label())) {
306 return _prm_->getInterface(o3_type.label()).isSubTypeOf(type);
307 } else {
308 return _prm_->getClass(o3_type.label()).isSubTypeOf(type);
309 }
310 }
311
312 template < GUM_Numeric GUM_SCALAR >
315 // Class with a super class must be declared after
316 for (auto c: _o3Classes_) {
317 _prm_->getClass(c->name().label()).inheritParameters();
318
319 factory.continueClass(c->name().label());
320
321 _addParameters_(factory, *c);
322
323 factory.endClass(false);
324 }
325 }
326
327 template < GUM_Numeric GUM_SCALAR >
329 O3Class& c) {
330 for (auto& p: c.parameters()) {
331 switch (p.type()) {
333 factory.addParameter("int", p.name().label(), p.value().value());
334 break;
335 }
336
338 factory.addParameter("real", p.name().label(), p.value().value());
339 break;
340 }
341
342 default : {
343 GUM_ERROR(FatalError, "unknown O3Parameter type")
344 }
345 }
346 }
347 }
348
349 template < GUM_Numeric GUM_SCALAR >
351 // Class with a super class must be declared after
352 for (auto c: _o3Classes_) {
353 _prm_->getClass(c->name().label()).inheritReferenceSlots();
355 }
356 }
357
358 template < GUM_Numeric GUM_SCALAR >
361
362 factory.continueClass(c.name().label());
363
364 // References
365 for (auto& ref: c.referenceSlots()) {
366 if (_checkReferenceSlot_(c, ref)) {
367 factory.addReferenceSlot(ref.type().label(), ref.name().label(), ref.isArray());
368 }
369 }
370
371 factory.endClass(false);
372 }
373
374 template < GUM_Numeric GUM_SCALAR >
376 if (!_solver_->resolveSlotType(ref.type())) { return false; }
377
378 const auto& real_c = _prm_->getClass(c.name().label());
379
380 // Check for dupplicates
381 if (real_c.exists(ref.name().label())) {
382 const auto& elt = real_c.get(ref.name().label());
383
385 auto slot_type = (PRMClassElementContainer< GUM_SCALAR >*)nullptr;
386
387 if (_prm_->isInterface(ref.type().label())) {
388 slot_type = &(_prm_->getInterface(ref.type().label()));
389
390 } else {
391 slot_type = &(_prm_->getClass(ref.type().label()));
392 }
393
394 auto real_ref = static_cast< const PRMReferenceSlot< GUM_SCALAR >* >(&elt);
395
396 if (slot_type->name() == real_ref->slotType().name()) {
397 O3PRM_CLASS_DUPLICATE_REFERENCE(ref.name(), *_errors_);
398 return false;
399
400 } else if (!slot_type->isSubTypeOf(real_ref->slotType())) {
401 O3PRM_CLASS_ILLEGAL_OVERLOAD(ref.name(), c.name(), *_errors_);
402 return false;
403 }
404
405 } else {
406 O3PRM_CLASS_DUPLICATE_REFERENCE(ref.name(), *_errors_);
407 return false;
408 }
409 }
410
411 // If class we need to check for illegal references
412 if (_prm_->isClass(ref.type().label())) {
413 const auto& ref_type = _prm_->getClass(ref.type().label());
414
415 // No recursive reference
416 if ((&ref_type) == (&real_c)) {
417 O3PRM_CLASS_SELF_REFERENCE(c.name(), ref.name(), *_errors_);
418 return false;
419 }
420
421 // No reference to subclasses
422 if (ref_type.isSubTypeOf(real_c)) {
423 O3PRM_CLASS_ILLEGAL_SUB_REFERENCE(c.name(), ref.type(), *_errors_);
424 return false;
425 }
426 }
427
428 return true;
429 }
430
431 template < GUM_Numeric GUM_SCALAR >
433 // Class with a super class must be declared after
434 for (auto c: _o3Classes_) {
435 _prm_->getClass(c->name().label()).inheritAttributes();
437 }
438 }
439
440 template < GUM_Numeric GUM_SCALAR >
442 // Class with a super class must be declared after
443 for (auto c: _o3Classes_) {
444 _prm_->getClass(c->name().label()).inheritAggregates();
446 }
447 }
448
449 template < GUM_Numeric GUM_SCALAR >
452 factory.continueClass(c.name().label());
453
454 for (auto& attr: c.attributes()) {
455 if (_checkAttributeForDeclaration_(c, *attr)) {
456 factory.startAttribute(attr->type().label(), attr->name().label());
457 factory.endAttribute();
458 }
459 }
460
461 factory.endClass(false);
462 }
463
464 template < GUM_Numeric GUM_SCALAR >
466 O3Attribute& attr) {
467 // Check type
468 if (!_solver_->resolveType(attr.type())) { return false; }
469
470 // Checking type legality if overload
471 if (c.superLabel().label() != "") {
472 const auto& super = _prm_->getClass(c.superLabel().label());
473
474 if (!super.exists(attr.name().label())) { return true; }
475
476 const auto& super_type = super.get(attr.name().label()).type();
477 const auto& type = _prm_->type(attr.type().label());
478
479 if (!type.isSubTypeOf(super_type)) {
480 O3PRM_CLASS_ILLEGAL_OVERLOAD(attr.name(), c.superLabel(), *_errors_);
481 return false;
482 }
483 }
484 return true;
485 }
486
487 template < GUM_Numeric GUM_SCALAR >
490
491 // Class with a super class must be declared in order
492 for (auto c: _o3Classes_) {
493 _prm_->getClass(c->name().label()).inheritSlotChains();
494 factory.continueClass(c->name().label());
495
496 _completeAttribute_(factory, *c);
497
498 if (c->superLabel().label() != "") {
499 auto& super = _prm_->getClass(c->superLabel().label());
500 auto to_complete = Set< std::string >();
501
502 for (auto a: super.attributes()) {
503 to_complete.insert(a->safeName());
504 }
505
506 for (auto a: super.aggregates()) {
507 to_complete.insert(a->safeName());
508 }
509
510 for (auto& a: c->attributes()) {
511 to_complete.erase(
512 _prm_->getClass(c->name().label()).get(a->name().label()).safeName());
513 }
514
515 for (auto& a: c->aggregates()) {
516 to_complete.erase(
517 _prm_->getClass(c->name().label()).get(a.name().label()).safeName());
518 }
519
520 for (auto a: to_complete) {
521 _prm_->getClass(c->name().label()).completeInheritance(a);
522 }
523 }
524
525 factory.endClass(true);
526 }
527 }
528
529 template < GUM_Numeric GUM_SCALAR >
532
533 // Class with a super class must be declared in order
534 for (auto c: _o3Classes_) {
535 factory.continueClass(c->name().label());
536
537 _completeAggregates_(factory, *c);
538
539 factory.endClass(false);
540 }
541 }
542
543 template < GUM_Numeric GUM_SCALAR >
545 O3Class& c) {
546 // Attributes
547 for (auto& agg: c.aggregates()) {
548 if (_checkAggregateForCompletion_(c, agg)) {
549 factory.continueAggregator(agg.name().label());
550
551 for (const auto& parent: agg.parents()) {
552 factory.addParent(parent.label());
553 }
554
555 factory.endAggregator();
556 }
557 }
558 }
559
560 template < GUM_Numeric GUM_SCALAR >
562 O3Aggregate& agg) {
563 // Checking parents
564 auto t = _checkAggParents_(c, agg);
565 if (t == nullptr) { return false; }
566
567 // Checking parameters numbers
568 if (!_checkAggParameters_(c, agg, t)) { return false; }
569
570 return true;
571 }
572
573 template < GUM_Numeric GUM_SCALAR >
575 O3Class& c) {
576 // Attributes
577 for (auto& attr: c.attributes()) {
578 if (_checkAttributeForCompletion_(c, *attr)) {
579 factory.continueAttribute(attr->name().label());
580
581 for (const auto& parent: attr->parents()) {
582 factory.addParent(parent.label());
583 }
584
585 if (auto raw = dynamic_cast< const O3RawCPT* >(attr.get())) {
586 auto values = std::vector< std::string >();
587 for (const auto& val: raw->values()) {
588 values.push_back(val.formula().formula());
589 }
590 factory.setRawCPFByColumns(values);
591 }
592
593 if (auto rule_cpt = dynamic_cast< const O3RuleCPT* >(attr.get())) {
594 for (const auto& rule: rule_cpt->rules()) {
595 auto labels = std::vector< std::string >();
596 auto values = std::vector< std::string >();
597
598 for (const auto& lbl: rule.first) {
599 labels.push_back(lbl.label());
600 }
601
602 for (const auto& form: rule.second) {
603 values.push_back(form.formula().formula());
604 }
605
606 factory.setCPFByRule(labels, values);
607 }
608 }
609
610 factory.endAttribute();
611 }
612 }
613 }
614
615 template < GUM_Numeric GUM_SCALAR >
617 O3Attribute& attr) {
618 // Check for parents existence
619 const auto& c = _prm_->getClass(o3_c.name().label());
620 for (auto& prnt: attr.parents()) {
621 if (!_checkParent_(c, prnt)) { return false; }
622 }
623
624 // Check that CPT sums to 1
625 if (auto raw = dynamic_cast< O3RawCPT* >(&attr)) { return _checkRawCPT_(c, *raw); }
626
627 if (auto rule = dynamic_cast< O3RuleCPT* >(&attr)) { return _checkRuleCPT_(c, *rule); }
628
629 return true;
630 }
631
632 template < GUM_Numeric GUM_SCALAR >
634 const O3Label& prnt) {
635 if (prnt.label().find('.') == std::string::npos) {
636 return _checkLocalParent_(c, prnt);
637
638 } else {
639 return _checkRemoteParent_(c, prnt);
640 }
641 }
642
643 template < GUM_Numeric GUM_SCALAR >
645 const O3Label& prnt) {
646 if (!c.exists(prnt.label())) {
647 O3PRM_CLASS_PARENT_NOT_FOUND(prnt, *_errors_);
648 return false;
649 }
650
651 const auto& elt = c.get(prnt.label());
655 O3PRM_CLASS_ILLEGAL_PARENT(prnt, *_errors_);
656 return false;
657 }
658
659 return true;
660 }
661
662 template < GUM_Numeric GUM_SCALAR >
665 const O3Label& prnt) {
666 if (_resolveSlotChain_(c, prnt) == nullptr) { return false; }
667 return true;
668 }
669
670 template < GUM_Numeric GUM_SCALAR >
672 const O3RuleCPT::O3Rule& rule) {
673 // Check that the number of labels is correct
674 if (rule.first.size() != attr.parents().size()) {
675 O3PRM_CLASS_ILLEGAL_RULE_SIZE(rule, rule.first.size(), attr.parents().size(), *_errors_);
676 return false;
677 }
678 return true;
679 }
680
681 template < GUM_Numeric GUM_SCALAR >
683 const O3RuleCPT& attr,
684 const O3RuleCPT::O3Rule& rule) {
685 bool errors = false;
686 for (std::size_t i = 0; i < attr.parents().size(); ++i) {
687 auto label = rule.first[i];
688 auto prnt = attr.parents()[i];
689 try {
690 auto real_labels = _resolveSlotChain_(c, prnt)->type()->labels();
691 // c.get(prnt.label()).type()->labels();
692 if (label.label() != "*"
693 && std::find(real_labels.begin(), real_labels.end(), label.label())
694 == real_labels.end()) {
695 O3PRM_CLASS_ILLEGAL_RULE_LABEL(rule, label, prnt, *_errors_);
696 errors = true;
697 }
698 } catch (Exception const&) {
699 // parent does not exists and is already reported
700 }
701 }
702 return errors == false;
703 }
704
705 template < GUM_Numeric GUM_SCALAR >
707 const HashTable< std::string, const PRMParameter< GUM_SCALAR >* >& scope,
708 O3RuleCPT::O3Rule& rule) {
709 // Add parameters to formulas
710 for (auto& f: rule.second) {
711 f.formula().variables().clear();
712 for (const auto& values: scope) {
713 f.formula().variables().insert(values.first, values.second->value());
714 }
715 }
716 }
717
718 template < GUM_Numeric GUM_SCALAR >
720 const O3RuleCPT& attr,
721 const O3RuleCPT::O3Rule& rule) {
722 bool errors = false;
723 // Check that formulas are valid and sums to 1
724 GUM_SCALAR sum = 0.0;
725 for (const auto& f: rule.second) {
726 try {
727 auto value = GUM_SCALAR(f.formula().result());
728 sum += value;
729 if (value < 0.0 || 1.0 < value) {
730 O3PRM_CLASS_ILLEGAL_CPT_VALUE(c.name(), attr.name(), f, *_errors_);
731 errors = true;
732 }
733 } catch (OperationNotAllowed const&) {
734 O3PRM_CLASS_ILLEGAL_CPT_VALUE(c.name(), attr.name(), f, *_errors_);
735 errors = true;
736 }
737 }
738
739 // Check that CPT sums to 1
740 if (std::abs(sum - 1.0) > 1e-3) {
741 O3PRM_CLASS_CPT_DOES_NOT_SUM_TO_1(c.name(), attr.name(), float(sum), *_errors_);
742 errors = true;
743 } else if (std::abs(sum - 1.0f) > 1e-6) {
744 O3PRM_CLASS_CPT_DOES_NOT_SUM_TO_1_WARNING(c.name(), attr.name(), float(sum), *_errors_);
745 }
746 return errors == false;
747 }
748
749 template < GUM_Numeric GUM_SCALAR >
751 O3RuleCPT& attr) {
752 const auto& scope = c.scope();
753 bool errors = false;
754 for (auto& rule: attr.rules()) {
755 try {
756 if (!_checkLabelsNumber_(attr, rule)) { errors = true; }
757 if (!_checkLabelsValues_(c, attr, rule)) { errors = true; }
758 _addParamsToForms_(scope, rule);
759 if (!_checkRuleCPTSumsTo1_(c, attr, rule)) { errors = true; }
760 } catch (Exception& e) {
761 GUM_SHOWERROR(e);
762 errors = true;
763 }
764 }
765
766 return errors == false;
767 }
768
769 template < GUM_Numeric GUM_SCALAR >
771 O3RawCPT& attr) {
772 const auto& type = _prm_->type(attr.type().label());
773
774 auto domainSize = type->domainSize();
775 for (auto& prnt: attr.parents()) {
776 if (c.exists(prnt.label())) {
777 domainSize *= c.get(prnt.label()).type()->domainSize();
778 } else {
779 // If we are here, all parents have been check so _resolveSlotChain_
780 // will not raise an error and not return a nullptr
781 domainSize *= _resolveSlotChain_(c, prnt)->type()->domainSize();
782 }
783 }
784
785 // Check for CPT size
786 if (domainSize != attr.values().size()) {
787 O3PRM_CLASS_ILLEGAL_CPT_SIZE(c.name(),
788 attr.name(),
789 Size(attr.values().size()),
790 domainSize,
791 *_errors_);
792 return false;
793 }
794
795 // Add parameters to formulas
796 const auto& scope = c.scope();
797 for (auto& f: attr.values()) {
798 f.formula().variables().clear();
799
800 for (const auto& values: scope) {
801 f.formula().variables().insert(values.first, values.second->value());
802 }
803 }
804
805 // Check that CPT sums to 1
806 Size parent_size = domainSize / type->domainSize();
807 auto values = std::vector< GUM_SCALAR >(parent_size, 0.0f);
808
809 for (std::size_t i = 0; i < attr.values().size(); ++i) {
810 try {
811 auto idx = i % parent_size;
812 auto val = (GUM_SCALAR)attr.values()[i].formula().result();
813 values[idx] += val;
814
815 if (val < 0.0 || 1.0 < val) {
816 O3PRM_CLASS_ILLEGAL_CPT_VALUE(c.name(), attr.name(), attr.values()[i], *_errors_);
817 return false;
818 }
819 } catch (Exception const&) {
820 O3PRM_CLASS_ILLEGAL_CPT_VALUE(c.name(), attr.name(), attr.values()[i], *_errors_);
821 return false;
822 }
823 }
824
825 for (auto f: values) {
826 if (std::abs(f - GUM_SCALAR(1.0)) > 1.0e-3) {
827 O3PRM_CLASS_CPT_DOES_NOT_SUM_TO_1(c.name(), attr.name(), float(f), *_errors_);
828 return false;
829 } else if (std::abs(f - GUM_SCALAR(1.0)) > 1.0e-6) {
830 O3PRM_CLASS_CPT_DOES_NOT_SUM_TO_1_WARNING(c.name(), attr.name(), float(f), *_errors_);
831 }
832 }
833 return true;
834 }
835
836 template < GUM_Numeric GUM_SCALAR >
839 const O3Label& chain) {
840 auto s = chain.label();
841 auto current = &c;
842 std::vector< std::string > v;
843
844 decomposePath(chain.label(), v);
845
846 for (size_t i = 0; i < v.size(); ++i) {
847 auto link = v[i];
848
849 if (!_checkSlotChainLink_(*current, chain, link)) { return nullptr; }
850
851 auto elt = &(current->get(link));
852
853 if (i == v.size() - 1) {
854 // last link, should be an attribute or aggregate
855 return elt;
856
857 } else {
858 // should be a reference slot
859
860 if (auto ref = dynamic_cast< const PRMReferenceSlot< GUM_SCALAR >* >(elt)) {
861 current = &(ref->slotType());
862 } else {
863 return nullptr; // failsafe to prevent infinite loop
864 }
865 }
866 }
867
868 // Encountered only reference slots
869
870 return nullptr;
871 }
872
873 template < GUM_Numeric GUM_SCALAR >
876 const O3Label& chain,
877 std::string_view s) {
878 if (!c.exists(s)) {
879 O3PRM_CLASS_LINK_NOT_FOUND(chain, s, *_errors_);
880 return false;
881 }
882 return true;
883 }
884
885 template < GUM_Numeric GUM_SCALAR >
888 factory.continueClass(c.name().label());
889
890 for (auto& agg: c.aggregates()) {
891 if (_checkAggregateForDeclaration_(c, agg)) {
892 auto params = std::vector< std::string >();
893 for (auto& p: agg.parameters()) {
894 params.push_back(p.label());
895 }
896
897 factory.startAggregator(agg.name().label(),
898 agg.aggregateType().label(),
899 agg.variableType().label(),
900 params);
901 factory.endAggregator();
902 }
903 }
904
905 factory.endClass(false);
906 }
907
908 template < GUM_Numeric GUM_SCALAR >
910 O3Aggregate& agg) {
911 if (!_solver_->resolveType(agg.variableType())) { return false; }
912
913 // Checking type legality if overload
914 if (!_checkAggTypeLegality_(o3class, agg)) { return false; }
915
916 return true;
917 }
918
919 template < GUM_Numeric GUM_SCALAR >
921 O3Aggregate& agg) {
922 const auto& c = _prm_->getClass(o3class.name().label());
923 auto t = (const PRMType*)nullptr;
924
925 for (const auto& prnt: agg.parents()) {
926 auto elt = _resolveSlotChain_(c, prnt);
927
928 if (elt == nullptr) {
929 O3PRM_CLASS_PARENT_NOT_FOUND(prnt, *_errors_);
930 return nullptr;
931
932 } else {
933 if (t == nullptr) {
934 try {
935 t = &(elt->type());
936
937 } catch (OperationNotAllowed const&) {
938 O3PRM_CLASS_WRONG_PARENT(prnt, *_errors_);
939 return nullptr;
940 }
941
942 } else if ((*t) != elt->type()) {
943 // Wront type in chain
944 O3PRM_CLASS_WRONG_PARENT_TYPE(prnt, t->name(), elt->type().name(), *_errors_);
945 return nullptr;
946 }
947 }
948 }
949 return t;
950 }
951
952 template < GUM_Numeric GUM_SCALAR >
954 O3Aggregate& agg) {
955 if (_prm_->isClass(o3class.superLabel().label())) {
956 const auto& super = _prm_->getClass(o3class.superLabel().label());
957 const auto& agg_type = _prm_->type(agg.variableType().label());
958
959 if (super.exists(agg.name().label())
960 && !agg_type.isSubTypeOf(super.get(agg.name().label()).type())) {
961 O3PRM_CLASS_ILLEGAL_OVERLOAD(agg.name(), o3class.superLabel(), *_errors_);
962 return false;
963 }
964 }
965
966 return true;
967 }
968
969 template < GUM_Numeric GUM_SCALAR >
971 O3Aggregate& agg,
972 const PRMType* t) {
973 bool ok = false;
974
983 ok = _checkParametersNumber_(agg, 0);
984 break;
985 }
986
990 ok = _checkParametersNumber_(agg, 1);
991 break;
992 }
993
994 default : {
995 GUM_ERROR(FatalError, "unknown aggregate type")
996 }
997 }
998
999 if (!ok) { return false; }
1000
1001 // Checking parameters type
1006 ok = _checkParameterValue_(agg, *t);
1007 break;
1008 }
1009
1010 default : { /* Nothing to do */
1011 }
1012 }
1013
1014 return ok;
1015 }
1016
1017 template < GUM_Numeric GUM_SCALAR >
1019 if (agg.parameters().size() != n) {
1020 O3PRM_CLASS_AGG_PARAMETERS(agg.name(), Size(n), Size(agg.parameters().size()), *_errors_);
1021 return false;
1022 }
1023
1024 return true;
1025 }
1026
1027 template < GUM_Numeric GUM_SCALAR >
1029 const gum::prm::PRMType& t) {
1030 const auto& param = agg.parameters().front();
1031 bool found = false;
1032 for (Size idx = 0; idx < t.variable().domainSize(); ++idx) {
1033 if (t.variable().label(idx) == param.label()) {
1034 found = true;
1035 break;
1036 }
1037 }
1038
1039 if (!found) {
1040 O3PRM_CLASS_AGG_PARAMETER_NOT_FOUND(agg.name(), param, *_errors_);
1041 return false;
1042 }
1043
1044 return true;
1045 }
1046
1047 } // namespace o3prm
1048 } // namespace prm
1049} // namespace gum
Headers for the O3ClassFactory class.
virtual std::string label(Idx i) const =0
get the indice-th label. This method is pure virtual.
Exception : a similar element already exists.
This class is used contain and manipulate gum::ParseError.
Base class for all aGrUM's exceptions.
Definition exceptions.h:122
Exception : fatal (unknown ?) error.
The class for generic Hash Tables.
Definition hashTable.h:640
bool exists(const Key &key) const
Checks whether there exists an element with a given key in the hashtable.
Exception : existence of a directed cycle in a graph.
Exception : operation not allowed.
static AggregateType str2enum(std::string_view str)
Static method which returns the AggregateType given its string representation.
<agrum/PRM/classElementContainer.h>
virtual bool exists(std::string_view name) const
Returns true if a member with the given name exists in this PRMClassElementContainer or in the PRMCla...
Abstract class representing an element of PRM class.
static INLINE bool isAggregate(const PRMClassElement< GUM_SCALAR > &elt)
Return true if obj is of type PRMAggregate.
static INLINE bool isReferenceSlot(const PRMClassElement< GUM_SCALAR > &elt)
Returns true if obj_ptr is of type PRMReferenceSlot.
static INLINE bool isAttribute(const PRMClassElement< GUM_SCALAR > &elt)
Returns true if obj_ptr is of type PRMAttribute.
static INLINE bool isSlotChain(const PRMClassElement< GUM_SCALAR > &elt)
Return true if obj is of type PRMSlotChain.
A PRMClass is an object of a PRM representing a fragment of a Bayesian network which can be instantia...
Definition PRMClass.h:77
PRMClassElement< GUM_SCALAR > & get(NodeId id) override
See gum::prm::PRMClassElementContainer<GUM_SCALAR>::get(NodeId).
HashTable< std::string, const PRMParameter< GUM_SCALAR > * > scope() const
Returns all the parameters in the scope of this class.
Factory which builds a PRM<GUM_SCALAR>.
Definition PRMFactory.h:90
void addReferenceSlot(std::string_view type, std::string_view name, bool isArray) override
Tells the factory that we started declaring a slot.
void endAggregator()
Finishes an aggregate declaration.
void setRawCPFByColumns(const std::vector< GUM_SCALAR > &array)
Gives the factory the CPF in its raw form.
void continueAttribute(std::string_view name) override
Continues the declaration of an attribute.
virtual void setCPFByRule(const std::vector< std::string > &labels, const std::vector< GUM_SCALAR > &values)
Fills the CPF using a rule.
void startAttribute(std::string_view type, std::string_view name, bool scalar_atttr=false) override
Tells the factory that we start an attribute declaration.
void endClass(bool checkImplementations=true) override
Tells the factory that we finished a class declaration.
void continueAggregator(std::string_view name)
Conitnues an aggregator declaration.
void addParameter(std::string_view type, std::string_view name, double value) override
Add a parameter to the current class with a default value.
void startClass(std::string_view c, std::string_view ext="", const Set< std::string > *implements=nullptr, bool delayInheritance=false) override
Tells the factory that we start a class declaration.
void endAttribute() override
Tells the factory that we finished declaring an attribute.
void startAggregator(std::string_view name, std::string_view agg_type, std::string_view rv_type, const std::vector< std::string > &params)
Start an aggregator declaration.
void addParent(std::string_view name) override
Tells the factory that we add a parent to the current declared attribute.
void continueClass(std::string_view c) override
Continue the declaration of a class.
const std::string & name() const
Returns the name of this object.
PRMParameter is a member of a Class in a PRM.
A PRMReferenceSlot represent a relation between two PRMClassElementContainer.
This is a decoration of the DiscreteVariable class.
Definition PRMType.h:78
DiscreteVariable & variable()
Return a reference on the DiscreteVariable contained in this.
Definition PRMType_inl.h:65
This class represents a Probabilistic Relational PRMSystem<GUM_SCALAR>.
Definition PRM.h:74
The O3Aggregate is part of the AST of the O3PRM language.
Definition O3prm.h:600
O3LabelList & parameters()
Definition O3prm.cpp:1162
O3LabelList & parents()
Definition O3prm.cpp:1158
The O3Attribute is part of the AST of the O3PRM language.
Definition O3prm.h:488
virtual O3Label & type()
Definition O3prm.cpp:743
virtual O3Label & name()
Definition O3prm.cpp:747
virtual O3LabelList & parents()
Definition O3prm.cpp:751
Builds gum::prm::Class from gum::prm::o3prm::O3Class.
bool _checkParent_(const PRMClass< GUM_SCALAR > &c, const O3Label &prnt)
O3NameSolver< GUM_SCALAR > * _solver_
bool _checkLabelsValues_(const PRMClass< GUM_SCALAR > &c, const O3RuleCPT &attr, const O3RuleCPT::O3Rule &rule)
void _addParamsToForms_(const HashTable< std::string, const PRMParameter< GUM_SCALAR > * > &scope, O3RuleCPT::O3Rule &rule)
O3ClassFactory(PRM< GUM_SCALAR > &prm, O3PRM &o3_prm, O3NameSolver< GUM_SCALAR > &solver, ErrorsContainer &errors)
HashTable< std::string, gum::NodeId > _nameMap_
bool _checkAggTypeLegality_(O3Class &o3class, O3Aggregate &agg)
void _completeAggregates_(PRMFactory< GUM_SCALAR > &factory, O3Class &c)
bool _checkLocalParent_(const PRMClass< GUM_SCALAR > &c, const O3Label &prnt)
std::vector< O3Class * > _o3Classes_
const PRMClassElement< GUM_SCALAR > * _resolveSlotChain_(const PRMClassElementContainer< GUM_SCALAR > &c, const O3Label &chain)
bool _checkAggParameters_(O3Class &o3class, O3Aggregate &agg, const PRMType *t)
bool _checkLabelsNumber_(const O3RuleCPT &attr, const O3RuleCPT::O3Rule &rule)
const PRMType * _checkAggParents_(O3Class &o3class, O3Aggregate &agg)
bool _checkParameterValue_(O3Aggregate &agg, const gum::prm::PRMType &t)
bool _checkAttributeForCompletion_(const O3Class &o3_c, O3Attribute &attr)
bool _checkAttributeForDeclaration_(O3Class &o3_c, O3Attribute &attr)
O3ClassFactory< GUM_SCALAR > & operator=(const O3ClassFactory< GUM_SCALAR > &src)
bool _checkAggregateForCompletion_(O3Class &o3class, O3Aggregate &agg)
bool _checkRemoteParent_(const PRMClassElementContainer< GUM_SCALAR > &c, const O3Label &prnt)
void _completeAttribute_(PRMFactory< GUM_SCALAR > &factory, O3Class &c)
bool _checkRuleCPT_(const PRMClass< GUM_SCALAR > &c, O3RuleCPT &attr)
void _addParameters_(PRMFactory< GUM_SCALAR > &factory, O3Class &c)
bool _checkParametersNumber_(O3Aggregate &agg, Size n)
HashTable< std::string, O3Class * > _classMap_
HashTable< NodeId, O3Class * > _nodeMap_
bool _checkReferenceSlot_(O3Class &c, O3ReferenceSlot &ref)
bool _checkRawCPT_(const PRMClass< GUM_SCALAR > &c, O3RawCPT &attr)
bool _checkRuleCPTSumsTo1_(const PRMClass< GUM_SCALAR > &c, const O3RuleCPT &attr, const O3RuleCPT::O3Rule &rule)
bool _checkAggregateForDeclaration_(O3Class &o3class, O3Aggregate &agg)
bool _checkSlotChainLink_(const PRMClassElementContainer< GUM_SCALAR > &c, const O3Label &chain, std::string_view s)
The O3Class is part of the AST of the O3PRM language.
Definition O3prm.h:642
O3ParameterList & parameters()
Definition O3prm.cpp:970
O3AggregateList & aggregates()
Definition O3prm.cpp:980
O3LabelList & interfaces()
Definition O3prm.cpp:966
O3ReferenceSlotList & referenceSlots()
Definition O3prm.cpp:974
O3Label & superLabel()
Definition O3prm.cpp:962
O3AttributeList & attributes()
Definition O3prm.cpp:976
The O3Label is part of the AST of the O3PRM language.
Definition O3prm.h:194
std::string & label()
Definition O3prm.cpp:286
Resolves names for the different O3PRM factories.
The O3PRM is part of the AST of the O3PRM language.
Definition O3prm.h:915
The O3RawCPT is part of the AST of the O3PRM language.
Definition O3prm.h:525
virtual O3FormulaList & values()
Definition O3prm.cpp:798
The O3ReferenceSlot is part of the AST of the O3PRM language.
Definition O3prm.h:455
The O3RuleCPT is part of the AST of the O3PRM language.
Definition O3prm.h:561
std::pair< O3LabelList, O3FormulaList > O3Rule
Definition O3prm.h:565
virtual O3RuleList & rules()
Definition O3prm.cpp:850
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
#define GUM_SHOWERROR(e)
Definition exceptions.h:89
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
HashTable< std::string, O3Aggregate * > AggMap
HashTable< std::string, O3ReferenceSlot * > RefMap
HashTable< std::string, O3Attribute * > AttrMap
namespace for all probabilistic relational models entities
Definition agrum.h:68
void decomposePath(std::string_view path, std::vector< std::string > &v)
Decompose a string in a vector of strings using "." as separators.
Definition utils_prm.cpp:48
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
STL namespace.