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