aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
BayesNetFactory_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
56 // Default constructor.
57 // @param bn A pointer over the BayesNet filled by this factory.
58 // @throw DuplicateElement Raised if two variables in bn share the same
59 // name.
60 template < GUM_Numeric GUM_SCALAR >
62 _parents_(nullptr), _impl_(0), _bn_(bn) {
63 GUM_CONSTRUCTOR(BayesNetFactory);
65
66 for (auto node: bn->nodes()) {
67 if (_varNameMap_.exists(bn->variable(node).name()))
68 GUM_ERROR(DuplicateElement, "Name already used: " << bn->variable(node).name())
69
70 _varNameMap_.insert(bn->variable(node).name(), node);
71 }
72
74 }
75
76 // Copy constructor.
77 // The copy will have an exact copy of the constructed BayesNet in source.
78 template < GUM_Numeric GUM_SCALAR >
80 _parents_(nullptr), _impl_(nullptr), _bn_(nullptr) {
81 GUM_CONS_CPY(BayesNetFactory);
82
83 if (source.state() != factory_state::NONE) {
84 GUM_ERROR(OperationNotAllowed, "Illegal state to proceed make a copy.")
85 } else {
86 _states_ = source._states_;
87 _bn_ = new BayesNet< GUM_SCALAR >(*(source._bn_));
88 }
89 }
90
91 // Destructor
92 template < GUM_Numeric GUM_SCALAR >
94 GUM_DESTRUCTOR(BayesNetFactory);
95
96 if (_parents_ != nullptr) delete _parents_;
97
98 if (_impl_ != nullptr) {
99 //@todo better than throwing an exception from inside a destructor but
100 // still ...
101 std::cerr << "[BN factory] Implementation defined for a variable but not used. "
102 "You should call endVariableDeclaration() before "
103 "deleting me."
104 << std::endl;
105 exit(1);
106 }
107 }
108
109 // Returns the BayesNet created by this factory.
110 template < GUM_Numeric GUM_SCALAR >
111 BayesNet< GUM_SCALAR >* BayesNetFactory< GUM_SCALAR >::bayesNet() {
112 return _bn_;
113 }
114
115 template < GUM_Numeric GUM_SCALAR >
117 return _bn_->variable(id);
118 }
119
120 // Returns the current state of the factory.
121 template < GUM_Numeric GUM_SCALAR >
123 // This is ok because there is always at least the state NONE in the stack.
124 return _states_.back();
125 }
126
127 // Returns the NodeId of a variable given it's name.
128 // @throw NotFound Raised if no variable matches the name.
129 template < GUM_Numeric GUM_SCALAR >
131 auto p = _varNameMap_.tryGet(name);
132 if (!p) { GUM_ERROR(NotFound, name) }
133 return *p;
134 }
135
136 // Returns a constant reference on a variable given it's name.
137 // @throw NotFound Raised if no variable matches the name.
138 template < GUM_Numeric GUM_SCALAR >
139 const DiscreteVariable& BayesNetFactory< GUM_SCALAR >::variable(std::string_view name) const {
140 auto p = _varNameMap_.tryGet(name);
141 if (!p) { GUM_ERROR(NotFound, name) }
142 return _bn_->variable(*p);
143 }
144
145 // Returns the domainSize of the cpt for the node n.
146 // @throw NotFound raised if no such NodeId exists.
147 // @throw OperationNotAllowed if there is no Bayesian networks.
148 template < GUM_Numeric GUM_SCALAR >
150 return _bn_->cpt(n).domainSize();
151 }
152
153 // Tells the factory that we're in a network declaration.
154 template < GUM_Numeric GUM_SCALAR >
156 if (state() != factory_state::NONE) {
157 _illegalStateError_("startNetworkDeclaration");
158 } else {
160 }
161 }
162
163 // Tells the factory to add a property to the current network.
164 template < GUM_Numeric GUM_SCALAR >
166 std::string_view propValue) {
167 _bn_->setProperty(propName, propValue);
168 }
169
170 // Tells the factory that we're out of a network declaration.
171 template < GUM_Numeric GUM_SCALAR >
173 if (state() != factory_state::NETWORK) {
174 _illegalStateError_("endNetworkDeclaration");
175 } else {
176 _states_.pop_back();
177 }
178 }
179
180 // Tells the factory that we're in a variable declaration.
181 // A variable is considered as a LabelizedVariable while its type is not defined.
182 template < GUM_Numeric GUM_SCALAR >
184 if (state() != factory_state::NONE) {
185 _illegalStateError_("startVariableDeclaration");
186 } else {
188 _stringBag_.emplace_back("name");
189 _stringBag_.emplace_back("desc");
190 _stringBag_.emplace_back("L");
191 }
192 }
193
194 // Tells the factory the current variable's name.
195 template < GUM_Numeric GUM_SCALAR >
198 _illegalStateError_("variableName");
199 } else {
200 if (_varNameMap_.exists(name)) { GUM_ERROR(DuplicateElement, "Name already used: " << name) }
201
202 _foo_flag_ = true;
203 _stringBag_[0] = name;
204 }
205 }
206
207 // Tells the factory the current variable's description.
208 template < GUM_Numeric GUM_SCALAR >
211 _illegalStateError_("variableDescription");
212 } else {
213 _bar_flag_ = true;
214 _stringBag_[1] = desc;
215 }
216 }
217
218 // Tells the factory the current variable's type.
219 // L : Labelized
220 // R : Range
221 // C : Continuous
222 // D : Discretized
223 template < GUM_Numeric GUM_SCALAR >
226 _illegalStateError_("variableType");
227 } else {
228 switch (type) {
229 case VarType::DISCRETIZED : _stringBag_[2] = "D"; break;
230 case VarType::RANGE : _stringBag_[2] = "R"; break;
231 case VarType::INTEGER : _stringBag_[2] = "I"; break;
232 case VarType::LABELIZED : _stringBag_[2] = "L"; break;
235 "Continuous variable (" + _stringBag_[0]
236 + ") are not supported in Bayesian networks.")
237 default : GUM_ERROR(OperationNotAllowed, "Unknown type for (" + _stringBag_[0] + ")")
238 }
239 }
240 }
241
242 // Adds a modality to the current variable.
243 // @throw DuplicateElement If the current variable already has a modality
244 // with the same name.
245 template < GUM_Numeric GUM_SCALAR >
246 void BayesNetFactory< GUM_SCALAR >::addModality(std::string_view name) {
248 _illegalStateError_("addModality");
249 } else {
251 _stringBag_.emplace_back(name);
252 }
253 }
254
255 // Adds a modality to the current variable.
256 // @throw DuplicateElement If the current variable already has a modality
257 // with the same name.
258 template < GUM_Numeric GUM_SCALAR >
261 _illegalStateError_("addMin");
262 } else {
263 _stringBag_.push_back(std::to_string(min));
264 }
265 }
266
267 // Adds a modality to the current variable.
268 // @throw DuplicateElement If the current variable already has a modality
269 // with the same name.
270 template < GUM_Numeric GUM_SCALAR >
273 _illegalStateError_("addMax");
274 } else {
275 _stringBag_.push_back(std::to_string(max));
276 }
277 }
278
279 // Adds a modality to the current variable.
280 // @throw DuplicateElement If the current variable already has a modality
281 // with the same name.
282 template < GUM_Numeric GUM_SCALAR >
283 void BayesNetFactory< GUM_SCALAR >::addTick(const GUM_SCALAR& tick) {
285 _illegalStateError_("addTick");
286 } else {
287 _stringBag_.push_back(std::to_string(tick));
288 }
289 }
290
291 // @brief Defines the implementation to use for Tensor.
292 // @warning The implementation must be empty.
293 // @warning The pointer is always delegated to Tensor! No copy of it
294 // is made.
295 // @todo When copy of a MultiDimImplementation is available use a copy
296 // behaviour for this method.
297 // @throw NotFound Raised if no variable matches var.
298 // @throw OperationNotAllowed Raised if impl is not empty.
299 // @throw OperationNotAllowed If an implementation is already defined for the
300 // current variable.
301 template < GUM_Numeric GUM_SCALAR >
303 auto impl = dynamic_cast< MultiDimImplementation< GUM_SCALAR >* >(adressable);
304
306 _illegalStateError_("setVariableCPTImplementation");
307 } else {
308 if (impl == nullptr) {
310 "An implementation for this variable is already "
311 "defined.")
312 } else if (impl->nbrDim() > 0) {
313 GUM_ERROR(OperationNotAllowed, "This implementation is not empty.")
314 }
315
316 _impl_ = impl;
317 }
318 }
319
320 // Tells the factory that we're out of a variable declaration.
321 template < GUM_Numeric GUM_SCALAR >
324 _illegalStateError_("endVariableDeclaration");
325 } else if (_foo_flag_ && (_stringBag_.size() > 4)) {
326 DiscreteVariable* var = nullptr;
327
328 // if the current variable is a LabelizedVariable
329 if (_stringBag_[2] == "L") {
330 const auto l = new LabelizedVariable(_stringBag_[0], (_bar_flag_) ? _stringBag_[1] : "", 0);
331
332 for (size_t i = 3; i < _stringBag_.size(); ++i) {
333 l->addLabel(_stringBag_[i]);
334 }
335
336 var = l;
337 // if the current variable is a RangeVariable
338 } else if (_stringBag_[2] == "I") {
339 // try to create the domain of the variable
340 std::vector< int > domain;
341 for (size_t i = 3; i < _stringBag_.size(); ++i) {
342 domain.push_back(std::stoi(_stringBag_[i]));
343 }
344
345 const auto v
346 = new IntegerVariable(_stringBag_[0], _bar_flag_ ? _stringBag_[1] : "", domain);
347 var = v;
348 } else if (_stringBag_[2] == "R") {
349 const auto r = new RangeVariable(_stringBag_[0],
350 _bar_flag_ ? _stringBag_[1] : "",
351 std::stol(_stringBag_[3]),
352 std::stol(_stringBag_[4]));
353
354 var = r;
355 // if the current variable is a DiscretizedVariable
356 } else if (_stringBag_[2] == "D") {
358 _bar_flag_ ? _stringBag_[1] : "");
359
360 for (size_t i = 3; i < _stringBag_.size(); ++i) {
361 d->addTick(std::stof(_stringBag_[i]));
362 }
363
364 var = d;
365 }
366
367 if (var == nullptr) {
368 GUM_ERROR(OperationNotAllowed, "Unknown variable type for variable " + _stringBag_[0])
369 }
370
371 if (_impl_ != 0) {
372 _varNameMap_.insert(var->name(), _bn_->add(*var, _impl_));
373 _impl_ = 0;
374 } else {
375 _varNameMap_.insert(var->name(), _bn_->add(*var));
376 }
377
378 NodeId retVal = _varNameMap_[var->name()];
379
380 delete var;
381
382 _resetParts_();
383 _states_.pop_back();
384
385 return retVal;
386 } else {
387 const auto errMsg
388 = std::format("Not enough modalities ({}) declared for variable {}",
389 _stringBag_.size() > 3 ? _stringBag_.size() - 3 : std::size_t(0),
390 _foo_flag_ ? _stringBag_[0] : std::string("unknown"));
391 _resetParts_();
392
393 _states_.pop_back();
395 }
396
397 // For noisy compilers
398 return 0;
399 }
400
401 // Tells the factory that we're declaring parents for some variable.
402 // @var The concerned variable's name.
403 template < GUM_Numeric GUM_SCALAR >
405 if (state() != factory_state::NONE) {
406 _illegalStateError_("startParentsDeclaration");
407 } else {
409 _stringBag_.insert(_stringBag_.begin(), std::string(var));
411 }
412 }
413
414 // Tells the factory for which variable we're declaring parents.
415 // @var The parent's name.
416 // @throw NotFound Raised if var does not exists.
417 template < GUM_Numeric GUM_SCALAR >
418 void BayesNetFactory< GUM_SCALAR >::addParent(std::string_view var) {
419 if (state() != factory_state::PARENTS) {
420 _illegalStateError_("addParent");
421 } else {
423 _stringBag_.emplace_back(var);
424 }
425 }
426
427 // Tells the factory that we've finished declaring parents for some
428 // variable. When parents exist, endParentsDeclaration creates some arcs.
429 // These arcs are created in the inverse order of the order of the parent
430 // specification.
431 template < GUM_Numeric GUM_SCALAR >
433 if (state() != factory_state::PARENTS) {
434 _illegalStateError_("endParentsDeclaration");
435 } else {
437
438 // PLEASE NOTE THAT THE ORDER IS INVERSE
439
440 for (size_t i = _stringBag_.size() - 1; i > 0; --i) {
441 _bn_->addArc(_varNameMap_[_stringBag_[i]], id);
442 }
443
444 _resetParts_();
445
446 _states_.pop_back();
447 }
448 }
449
450 // Tells the factory that we're declaring a conditional probability table
451 // for some variable.
452 // @param var The concerned variable's name.
453 template < GUM_Numeric GUM_SCALAR >
455 if (state() != factory_state::NONE) {
456 _illegalStateError_("startRawProbabilityDeclaration");
457 } else {
459 _stringBag_.emplace_back(var);
461 }
462 }
463
464 // @brief Fills the variable's table with the values in rawTable.
465 // Parse the parents in the same order in which they were added to the
466 // variable.
467 // Given a sequence [var, p_1, p_2, ...,p_n-1, p_n] of parents, modalities are
468 // parsed
469 // in the given order (if all p_i are binary):
470 // [0, 0, ..., 0, 0], [0, 0, ..., 0, 1],
471 // [0, 0, ..., 1, 0], [0, 0, ..., 1, 1],
472 // ...,
473 // [1, 1, ..., 1, 0], [1, 1, ..., 1, 1].
474 // @param rawTable The raw table.
475 template < GUM_Numeric GUM_SCALAR >
477 const std::vector< std::string >& variables,
478 const std::vector< float >& rawTable) {
479 if (state() != factory_state::RAW_CPT) {
480 _illegalStateError_("rawConditionalTable");
481 } else {
482 _fillProbaWithValuesTable_(variables, rawTable);
483 }
484 }
485
486 template < GUM_Numeric GUM_SCALAR >
488 const std::vector< std::string >& variables,
489 const std::vector< float >& rawTable) {
490 const Tensor< GUM_SCALAR >& table = _bn_->cpt(_varNameMap_[_stringBag_[0]]);
491 Instantiation cptInst(table);
492
494 table.fillWith(GUM_SCALAR(0.0));
495
496 for (size_t i = 0; i < variables.size(); ++i) {
497 varList.pushBack(&(_bn_->variable(_varNameMap_[variables[i]])));
498 }
499
500 Idx nbrVar = varList.size();
501
502 std::vector< Idx > modCounter;
503
504 // initializing the array
505 for (NodeId i = 0; i < nbrVar; i++) {
506 modCounter.push_back(Idx(0));
507 }
508
509 for (Idx j = 0; j < rawTable.size(); j++) {
510 for (NodeId i = 0; i < nbrVar; i++) {
511 cptInst.chgVal(*(varList[i]), modCounter[i]);
512 }
513
514 table.set(cptInst, static_cast< GUM_SCALAR >(rawTable[j]));
515 if (!_increment_(modCounter, varList)) { break; } // too many values (just not read)
516 }
517 }
518
519 template < GUM_Numeric GUM_SCALAR >
520 void BayesNetFactory< GUM_SCALAR >::rawConditionalTable(const std::vector< float >& rawTable) {
521 if (state() != factory_state::RAW_CPT) {
522 _illegalStateError_("rawConditionalTable");
523 } else {
525 }
526 }
527
528 template < GUM_Numeric GUM_SCALAR >
530 const std::vector< float >& rawTable) {
531 const Tensor< GUM_SCALAR >& table = _bn_->cpt(_varNameMap_[_stringBag_[0]]);
532
533 Instantiation cptInst(table);
534
535 // the main loop is on the first variables. The others are in the right
536 // order.
537 const DiscreteVariable& first = table.variable(0);
538 Idx j = 0;
539
540 for (cptInst.setFirstVar(first); !cptInst.end(); cptInst.incVar(first)) {
541 for (cptInst.setFirstNotVar(first); !cptInst.end(); cptInst.incNotVar(first))
542 table.set(cptInst,
543 (j < rawTable.size()) ? static_cast< GUM_SCALAR >(rawTable[j++])
544 : static_cast< GUM_SCALAR >(0));
545
546 cptInst.unsetEnd();
547 }
548 }
549
550 template < GUM_Numeric GUM_SCALAR >
551 bool BayesNetFactory< GUM_SCALAR >::_increment_(std::vector< gum::Idx >& modCounter,
552 List< const DiscreteVariable* >& varList) const {
553 bool last = true;
554
555 for (NodeId j = 0; j < modCounter.size(); j++) {
556 last = (modCounter[j] == (varList[j]->domainSize() - 1)) && last;
557
558 if (!last) break;
559 }
560
561 if (last) { return false; }
562
563 bool add = false;
564
565 auto i = NodeId(varList.size() - 1);
566
567 do {
568 if (modCounter[i] == (varList[i]->domainSize() - 1)) {
569 modCounter[i] = 0;
570 add = true;
571 } else {
572 modCounter[i] += 1;
573 add = false;
574 }
575
576 i--;
577 } while (add);
578
579 return true;
580 }
581
582 // Tells the factory that we finished declaring a conditional probability
583 // table.
584 template < GUM_Numeric GUM_SCALAR >
586 if (state() != factory_state::RAW_CPT) {
587 _illegalStateError_("endRawProbabilityDeclaration");
588 } else {
589 _resetParts_();
590 _states_.pop_back();
591 }
592 }
593
594 // Tells the factory that we're starting a factorized declaration.
595 template < GUM_Numeric GUM_SCALAR >
597 if (state() != factory_state::NONE) {
598 _illegalStateError_("startFactorizedProbabilityDeclaration");
599 } else {
601 _stringBag_.insert(_stringBag_.begin(), std::string(var));
603 }
604 }
605
606 // Tells the factory that we start an entry of a factorized conditional
607 // probability table.
608 template < GUM_Numeric GUM_SCALAR >
611 _illegalStateError_("startFactorizedEntry");
612 } else {
613 _parents_ = new Instantiation();
615 }
616 }
617
618 // Tells the factory that we finished declaring a conditional probability
619 // table.
620 template < GUM_Numeric GUM_SCALAR >
623 _illegalStateError_("endFactorizedEntry");
624 } else {
625 delete _parents_;
626 _parents_ = nullptr;
627 _states_.pop_back();
628 }
629 }
630
631 // Tells the factory on which modality we want to instantiate one of
632 // variable's parent.
633 template < GUM_Numeric GUM_SCALAR >
635 std::string_view modality) {
637 _illegalStateError_("string");
638 } else {
639 _checkVariableName_(parent);
640 Idx id = _checkVariableModality_(parent, modality);
641 const DiscreteVariable& parentVar = _bn_->variable(*_varNameMap_.tryGet(parent));
642 (*_parents_) << parentVar;
643 _parents_->chgVal(parentVar, id);
644 }
645 }
646
647 // @brief Gives the values of the variable with respect to precedent
648 // parents modality.
649 // If some parents have no modality set, then we apply values for all
650 // instantiations of that parent.
651 //
652 // This means you can declare a default value for the table by doing
653 // @code
654 // BayesNetFactory factory;
655 // // Do stuff
656 // factory.startVariableDeclaration();
657 // factory.variableName("foo");
658 // factory.endVariableDeclaration();
659 // factory.startParentsDeclaration("foo");
660 // // add parents
661 // factory.endParentsDeclaration();
662 // factory.startFactorizedProbabilityDeclaration("foo");
663 // std::vector<float> seq;
664 // seq.insert(0.4); // if foo true
665 // seq.insert(O.6); // if foo false
666 // factory.setVariableValues(seq); // fills the table with a default value
667 // // finish your stuff
668 // factory.endFactorizedProbabilityDeclaration();
669 // @code
670 // as for raw Probability, if value's size is different than the number of
671 // modalities of the current variable, we don't use the supplementary values and
672 // we fill by 0 the missing values.
673 template < GUM_Numeric GUM_SCALAR >
675 const std::vector< float >& values) {
677 _illegalStateError_("setVariableValues");
678 } else {
679 const DiscreteVariable& var = _bn_->variable(_varNameMap_[_stringBag_[0]]);
680 NodeId varId = _varNameMap_[_stringBag_[0]];
681
682 if (_parents_->domainSize() > 0) {
683 Instantiation inst(_bn_->cpt(_varNameMap_[var.name()]));
684 inst.setVals(*_parents_);
685 // Creating an instantiation containing all the variables not ins
686 // _parents_.
687 Instantiation inst_default;
688 inst_default << var;
689
690 for (auto node: _bn_->parents(varId)) {
691 if (!_parents_->contains(_bn_->variable(node))) { inst_default << _bn_->variable(node); }
692 }
693
694 // Filling the variable's table.
695 for (inst.setFirstIn(inst_default); !inst.end(); inst.incIn(inst_default)) {
696 (_bn_->cpt(varId))
697 .set(inst,
698 inst.val(var) < values.size() ? static_cast< GUM_SCALAR >(values[inst.val(var)])
699 : static_cast< GUM_SCALAR >(0));
700 }
701 } else {
702 Instantiation inst(_bn_->cpt(_varNameMap_[var.name()]));
703 Instantiation var_inst;
704 var_inst << var;
705
706 for (var_inst.setFirst(); !var_inst.end(); ++var_inst) {
707 inst.setVals(var_inst);
708
709 for (inst.setFirstOut(var_inst); !inst.end(); inst.incOut(var_inst)) {
710 (_bn_->cpt(varId))
711 .set(inst,
712 inst.val(var) < values.size()
713 ? static_cast< GUM_SCALAR >(values[inst.val(var)])
714 : static_cast< GUM_SCALAR >(0));
715 }
716 }
717 }
718 }
719 }
720
721 template < GUM_Numeric GUM_SCALAR >
722 void BayesNetFactory< GUM_SCALAR >::setVariableValues(const std::vector< float >& values) {
724 _illegalStateError_("setVariableValues");
725 } else {
726 // Checking consistency between values and var.
727 if (const DiscreteVariable& var = _bn_->variable(_varNameMap_[_stringBag_[0]]);
728 values.size() != var.domainSize()) {
730 var.name() << " : invalid number of modalities: found " << values.size()
731 << " while needed " << var.domainSize())
732 }
733
735 }
736 }
737
738 // Tells the factory that we finished declaring a conditional probability
739 // table.
740 template < GUM_Numeric GUM_SCALAR >
743 _illegalStateError_("endFactorizedProbabilityDeclaration");
744 } else {
745 _resetParts_();
746 _states_.pop_back();
747 }
748 }
749
750 // @brief Define a variable.
751 // You can only call this method is the factory is in the NONE or NETWORK
752 // state.
753 // The variable is added by copy.
754 // @param var The pointer over a DiscreteVariable used to define a new
755 // variable in the built BayesNet.
756 // @throw DuplicateElement Raised if a variable with the same name already
757 // exists.
758 // @throw OperationNotAllowed Raised if redefineParents == false and if table
759 // is not a valid CPT for var in the current state
760 // of the BayesNet.
761 template < GUM_Numeric GUM_SCALAR >
763 if (state() != factory_state::NONE) {
764 _illegalStateError_("setVariable");
765 } else {
766 if (_varNameMap_.exists(var.name())) {
767 GUM_ERROR(DuplicateElement, "Name already used: " << var.name())
768 }
769 // The var name is unused
770 _varNameMap_.insert(var.name(), _bn_->add(var));
771 }
772 }
773
774 // @brief Define a variable's CPT.
775 // You can only call this method if the factory is in the NONE or NETWORK
776 // state.
777 // Be careful that table is given to the built BayesNet, so it will be
778 // deleted with it, and you should not directly access it after you call
779 // this method.
780 // When the redefineParents flag is set to true the constructed BayesNet's
781 // DAG is changed to fit with table's definition.
782 // @param var The name of the concerned variable.
783 // @param table A pointer over the CPT used for var.
784 // @param redefineParents If true redefine parents of the variable to match
785 // table's
786 // variables set.
787 //
788 // @throw NotFound Raised if no variable matches var.
789 // @throw OperationNotAllowed Raised if redefineParents == false and if table
790 // is not a valid CPT for var in the current state
791 // of the BayesNet.
792 template < GUM_Numeric GUM_SCALAR >
794 MultiDimAdressable* table,
795 bool redefineParents) {
796 auto pot = dynamic_cast< Tensor< GUM_SCALAR >* >(table);
797
798 if (state() != factory_state::NONE) {
799 _illegalStateError_("setVariableCPT");
800 } else {
801 _checkVariableName_(varName);
802 NodeId varId = *_varNameMap_.tryGet(varName);
803 const DiscreteVariable& var = _bn_->variable(varId);
804 // If we have to change the structure of the BayesNet, then we call a sub
805 // method.
806
807 if (redefineParents) {
808 _setCPTAndParents_(var, pot);
809 } else if (pot->contains(var)) {
810 for (auto node: _bn_->parents(varId)) {
811 if (!pot->contains(_bn_->variable(node))) {
812 GUM_ERROR(OperationNotAllowed, "The CPT is not valid in the current BayesNet.")
813 }
814 }
815
816 // CPT are created when a variable is added.
817 _bn_->_unsafeChangeTensor_(varId, pot);
818 }
819 }
820 }
821
822 // Raise an OperationNotAllowed with the message "Illegal state."
823 template < GUM_Numeric GUM_SCALAR >
825 std::string msg = "Illegal state call (";
826 msg += s;
827 msg += ") in state ";
828
829 switch (state()) {
830 case factory_state::NONE : {
831 msg += "NONE";
832 break;
833 }
834
836 msg += "NETWORK";
837 break;
838 }
839
841 msg += "VARIABLE";
842 break;
843 }
844
846 msg += "PARENTS";
847 break;
848 }
849
851 msg += "RAW_CPT";
852 break;
853 }
854
856 msg += "FACT_CPT";
857 break;
858 }
859
861 msg += "FACT_ENTRY";
862 break;
863 }
864
865 default : {
866 msg += "Unknown state";
867 }
868 }
869
871 }
872
873 // Check if a variable with the given name exists, if not raise an NotFound
874 // exception.
875 template < GUM_Numeric GUM_SCALAR >
876 void BayesNetFactory< GUM_SCALAR >::_checkVariableName_(std::string_view name) const {
877 if (!_varNameMap_.exists(name)) { GUM_ERROR(NotFound, name) }
878 }
879
880 // Check if var exists and if mod is one of it's modality, if not raise an
881 // NotFound exception.
882 template < GUM_Numeric GUM_SCALAR >
884 std::string_view mod) {
885 auto p = _varNameMap_.tryGet(name);
886 if (!p) { GUM_ERROR(NotFound, name) }
887 const DiscreteVariable& var = _bn_->variable(*p);
888
889 for (Idx i = 0; i < var.domainSize(); ++i) {
890 if (mod == var.label(i)) { return i; }
891 }
892
893 GUM_ERROR(NotFound, mod)
894 }
895
896 // Check if in _stringBag_ there is no other modality with the same name.
897 template < GUM_Numeric GUM_SCALAR >
899 for (size_t i = 3; i < _stringBag_.size(); ++i) {
900 if (mod == _stringBag_[i]) { GUM_ERROR(DuplicateElement, "Label already used: " << mod) }
901 }
902 }
903
904 // Sub method of setVariableCPT() which redefine the BayesNet's DAG with
905 // respect to table.
906 template < GUM_Numeric GUM_SCALAR >
908 Tensor< GUM_SCALAR >* table) {
909 NodeId varId = _varNameMap_[var.name()];
910 _bn_->dag_.eraseParents(varId);
911
912 for (auto v: table->variablesSequence()) {
913 if (v != (&var)) {
914 _checkVariableName_(v->name());
915 _bn_->dag_.addArc(_varNameMap_[v->name()], varId);
916 }
917 }
918
919 // CPT are created when a variable is added.
920 _bn_->_unsafeChangeTensor_(varId, table);
921 }
922
923 // Reset the different parts used to constructed the BayesNet.
924 template < GUM_Numeric GUM_SCALAR >
926 _foo_flag_ = false;
927 _bar_flag_ = false;
928 _stringBag_.clear();
929 }
930} /* namespace gum */
Headers of the BayesNetFactory class.
const DiscreteVariable & varInBN(NodeId id) final
short-cut accessor for a DiscreveVariable in the BN
std::vector< factory_state > _states_
State stack.
void startFactorizedProbabilityDeclaration(std::string_view var) final
Tells the factory that we're starting a factorized declaration.
void _checkVariableName_(std::string_view name) const
Check if a variable with the given name exists, if not raise an NotFound exception.
bool _bar_flag_
Depending on the context this flag is used for some VERY important reasons.
void endParentsDeclaration() final
Tells the factory that we've finished declaring parents for some variable.
BayesNet< GUM_SCALAR > * bayesNet()
Returns the BayesNet created by this factory.
Size cptDomainSize(NodeId n) const final
Returns the domainSize of the cpt for the node n.
bool _increment_(std::vector< gum::Idx > &modCounter, List< const DiscreteVariable * > &varList) const
Increment a modality counter for the fillProbaWithValuesTable method.
void _fillProbaWithValuesTable_(const std::vector< std::string > &variables, const std::vector< float > &rawTable)
Fill a tensor from a raw CPT.
HashTable< std::string, NodeId > _varNameMap_
Mapping between a declared variable's name and it's node id.
void setVariableCPT(std::string_view varName, MultiDimAdressable *table, bool redefineParents) final
Define a variable's CPT.
void setVariableValuesUnchecked(const std::vector< float > &values) final
Gives the values of the variable with respect to precedent parents modality.
void addModality(std::string_view name) final
Adds a modality to the current labelized variable.
void endNetworkDeclaration() final
Tells the factory that we're out of a network declaration.
void rawConditionalTable(const std::vector< std::string > &variables, const std::vector< float > &rawTable) final
Fills the variable's table with the values in rawTable.
BayesNet< GUM_SCALAR > * _bn_
The constructed BayesNet.
~BayesNetFactory() override
Destructor.
void _setCPTAndParents_(const DiscreteVariable &var, Tensor< GUM_SCALAR > *table)
Sub method of setVariableCPT() which redefine the BayesNet's DAG with respect to table.
const DiscreteVariable & variable(std::string_view name) const
Returns a constant reference on a variable given it's name.
void addParent(std::string_view var) final
Tells the factory for which variable we're declaring parents.
void endFactorizedProbabilityDeclaration() final
Tells the factory that we finished declaring a conditional probability table.
void setVariable(const DiscreteVariable &var) final
Define a variable.
std::vector< std::string > _stringBag_
Just to keep track of strings between two start/end calls.
NodeId variableId(std::string_view name) const final
Returns the NodeId of a variable given it's name.
void startFactorizedEntry() final
Tells the factory that we start an entry of a factorized conditional probability table.
void startRawProbabilityDeclaration(std::string_view var) final
Tells the factory that we're declaring a conditional probability table for some variable.
void endFactorizedEntry() final
Tells the factory that we end an entry of a factorized conditional probability table.
bool _foo_flag_
Depending on the context this flag is used for some VERY important reasons.
void _resetParts_()
Reset the different parts used to constructed the BayesNet.
factory_state state() const final
Returns the current state of the factory.
void _checkModalityInBag_(std::string_view mod)
Check if in stringBag there is no other modality with the same name.
void addMax(const long &max) override
Adds the max value of the current range variable.
Idx _checkVariableModality_(std::string_view name, std::string_view mod)
Check if var exists and if mod is one of it's modality, if not raise an NotFound exception.
Instantiation * _parents_
Used when a factorized CPT is built.
void endRawProbabilityDeclaration() final
Tells the factory that we finished declaring a conditional probability table.
void variableType(const VarType &type) override
Tells the factory the current variable's type.
void setVariableValues(const std::vector< float > &values) final
same than below with gum::OperationNotAllowed exception if value's size not OK.
void startNetworkDeclaration() final
Tells the factory that we're in a network declaration.
void startParentsDeclaration(std::string_view var) final
Tells the factory that we're declaring parents for some variable.
void variableDescription(std::string_view desc) final
Tells the factory the current variable's description.
void addNetworkProperty(std::string_view propName, std::string_view propValue) final
Tells the factory to add a property to the current network.
void setVariableCPTImplementation(MultiDimAdressable *adressable) final
Defines the implementation to use for var's Tensor.
MultiDimImplementation< GUM_SCALAR > * _impl_
Implementation of variable between two startVariableDeclaration/endVariableDeclaration calls.
void addTick(const GUM_SCALAR &tick)
Adds a tick to the current Discretized variable.
void startVariableDeclaration() final
Tells the factory that we're in a variable declaration.
void addMin(const long &min) override
Adds the min value of the current range variable.
void _illegalStateError_(std::string_view s)
Raise an OperationNotAllowed with the message "Illegal state.".
void setParentModality(std::string_view parent, std::string_view modality) final
Tells the factory on which modality we want to instantiate one of variable's parent.
NodeId endVariableDeclaration() final
Tells the factory that we're out of a variable declaration.
void variableName(std::string_view name) final
Tells the factory the current variable's name.
BayesNetFactory(BayesNet< GUM_SCALAR > *bn)
Use this constructor if you want to use an already created BayesNet.
Base class for discrete random variable.
virtual std::string label(Idx i) const =0
get the indice-th label. This method is pure virtual.
virtual Size domainSize() const =0
Class for discretized random variable.
Exception : a similar element already exists.
factory_state
The enumeration of states in which the factory can be in.
Class for assigning/browsing values to tuples of discrete variables.
Instantiation & chgVal(const DiscreteVariable &v, Idx newval)
Assign newval to variable v in the Instantiation.
bool end() const
Returns true if the Instantiation reached the end.
void incOut(const Instantiation &i)
Operator increment for the variables not in i.
void incVar(const DiscreteVariable &v)
Operator increment for variable v only.
void setFirstNotVar(const DiscreteVariable &v)
Assign the first values to variables different of v.
void setFirstIn(const Instantiation &i)
Assign the first values in the Instantiation for the variables in i.
Instantiation & setVals(const Instantiation &i)
Assign the values from i in the Instantiation.
void setFirstVar(const DiscreteVariable &v)
Assign the first value in the Instantiation for var v.
void incNotVar(const DiscreteVariable &v)
Operator increment for vars which are not v.
void incIn(const Instantiation &i)
Operator increment for the variables in i.
Idx val(Idx i) const
Returns the current value of the variable at position i.
void setFirst()
Assign the first values to the tuple of the Instantiation.
void setFirstOut(const Instantiation &i)
Assign the first values in the Instantiation for the variables not in i.
void unsetEnd()
Alias for unsetOverflow().
class IntegerVariable
class LabelizedVariable
Generic doubly linked lists.
Definition list.h:378
Size size() const noexcept
Returns the number of elements in the list.
Definition list_tpl.h:1710
Val & pushBack(const Val &val)
Inserts a new element (a copy) at the end of the chained list.
Definition list_tpl.h:1481
Abstract base class for all multi dimensionnal addressable.
Exception : the element we looked for cannot be found.
Exception : operation not allowed.
Defines a discrete random variable over an integer interval.
const std::string & name() const
returns the name of the variable
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
Size Idx
Type for indexes.
Definition types.h:79
Size NodeId
Type for node ids.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
VarType
Definition variable.h:62