aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
credalNet_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
43#include <agrum/agrum.h>
44
45#include <agrum/CN/credalNet.h>
46
48
49namespace gum {
50 namespace credal {
51
52 template < typename GUM_SCALAR >
55
56 _src_bn_ = BayesNet< GUM_SCALAR >();
57 _src_bn_min_ = BayesNet< GUM_SCALAR >();
58 _src_bn_max_ = BayesNet< GUM_SCALAR >();
59
60 GUM_CONSTRUCTOR(CredalNet);
61 }
62
63 template < typename GUM_SCALAR >
64 NodeId CredalNet< GUM_SCALAR >::addVariable(const std::string& name, const Size& card) {
65 LabelizedVariable var(name, "node " + name, card);
66
67 NodeId a = _src_bn_.add(var);
68 NodeId b = _src_bn_min_.add(var);
69 NodeId c = _src_bn_max_.add(var);
70
71 if (a != b || a != c /*|| b != c*/)
73 "addVariable : not the same id over all networks : " << a << ", " << b << ", "
74 << c);
75
76 return a;
77 }
78
79 template < typename GUM_SCALAR >
80 void CredalNet< GUM_SCALAR >::addArc(const NodeId& tail, const NodeId& head) {
81 _src_bn_.addArc(tail, head);
82 _src_bn_min_.addArc(tail, head);
83 _src_bn_max_.addArc(tail, head);
84 }
85
86 template < typename GUM_SCALAR >
88 const NodeId& id,
89 const std::vector< std::vector< std::vector< GUM_SCALAR > > >& cpt) {
90 const Tensor< GUM_SCALAR >* const tensor(&_src_bn_.cpt(id));
91
92 auto var_dSize = _src_bn_.variable(id).domainSize();
93 auto entry_size = tensor->domainSize() / var_dSize;
94
95 if (cpt.size() != entry_size)
97 "setCPTs : entry sizes of cpts does not match for node id : "
98 << id << " : " << cpt.size() << " != " << entry_size);
99
100 for (const auto& cset: cpt) {
101 if (cset.size() == 0)
103 "setCPTs : vertices in credal set does not match for node id : "
104 << id << " with 0 vertices");
105
106 for (const auto& vertex: cset) {
107 if (vertex.size() != var_dSize)
109 "setCPTs : variable modalities in cpts does "
110 "not match for node id : "
111 << id << " with vertex " << vertex << " : " << vertex.size()
112 << " != " << var_dSize);
113
114 GUM_SCALAR sum = 0;
115
116 for (const auto& prob: vertex) {
117 sum += prob;
118 }
119
120 if (std::fabs(sum - 1) > 1e-6)
122 "setCPTs : a vertex coordinates does not "
123 "sum to one for node id : "
124 << id << " with vertex " << vertex);
125 }
126 }
127
128 _credalNet_src_cpt_.insert(id, cpt);
129 }
130
131 template < typename GUM_SCALAR >
133 Size& entry,
134 const std::vector< std::vector< GUM_SCALAR > >& cpt) {
135 const Tensor< GUM_SCALAR >* const tensor(&_src_bn_.cpt(id));
136
137 auto var_dSize = _src_bn_.variable(id).domainSize();
138 auto entry_size = tensor->domainSize() / var_dSize;
139
140 if (entry >= entry_size)
142 "setCPT : entry is greater or equal than entry size "
143 "(entries start at 0 up to entry_size - 1) : "
144 << entry << " >= " << entry_size);
145
146 if (cpt.size() == 0) GUM_ERROR(SizeError, "setCPT : empty credal set for entry : " << entry)
147
148 for (const auto& vertex: cpt) {
149 if (vertex.size() != var_dSize)
151 "setCPT : variable modalities in cpts does not "
152 "match for node id : "
153 << id << " with vertex " << vertex << " at entry " << entry << " : "
154 << vertex.size() << " != " << var_dSize);
155
156 GUM_SCALAR sum = 0;
157
158 for (const auto& prob: vertex) {
159 sum += prob;
160 }
161
162 if (std::fabs(sum - 1) > 1e-6)
164 "setCPT : a vertex coordinates does not sum to one for node id : "
165 << id << " at entry " << entry << " with vertex " << vertex);
166 }
167
168 // !! auto does NOT use adress (if available) unless explicitly asked !!
169 auto& node_cpt = _credalNet_src_cpt_.getWithDefault(
170 id,
171 std::vector< std::vector< std::vector< GUM_SCALAR > > >(entry_size));
172
173 if (node_cpt[entry].size() != 0)
175 "setCPT : vertices of entry id " << entry
176 << " already set to : " << node_cpt[entry]
177 << ", cannot insert : " << cpt);
178
179 node_cpt[entry] = cpt;
180
182 }
183
184 template < typename GUM_SCALAR >
186 Instantiation ins,
187 const std::vector< std::vector< GUM_SCALAR > >& cpt) {
188 const Tensor< GUM_SCALAR >* const tensor(&_src_bn_.cpt(id));
189
190 auto var_dSize = _src_bn_.variable(id).domainSize();
191 auto entry_size = tensor->domainSize() / var_dSize;
192
193 // to be sure of entry index reorder ins according to the bayes net
194 // tensors
195 // ( of the credal net )
196 // it WONT throw an error if the sequences are not equal not because of
197 // order
198 // but content, so we double check (before & after order correction)
199 // beware of slaves & master
200 Instantiation ref(tensor);
201 ref.forgetMaster();
202
203 ins.forgetMaster();
204
205 const auto& vseq = ref.variablesSequence();
206
207 if (ins.variablesSequence() != vseq) {
208 ins.reorder(ref);
209
210 if (ins.variablesSequence() != vseq)
212 "setCPT : instantiation : "
213 << ins << " is not valid for node id " << id
214 << " which accepts instantiations such as (order is not "
215 "important) : "
216 << ref);
217 }
218
219 Idx entry = 0, jump = 1;
220
221 for (Idx i = 0, end = ins.nbrDim(); i < end; i++) {
222 if (_src_bn_.nodeId(ins.variable(i)) == id) continue;
223
224 entry += ins.val(i) * jump;
225
226 jump *= ins.variable(i).domainSize();
227 }
228
229 if (entry >= entry_size)
231 "setCPT : entry is greater or equal than entry size "
232 "(entries start at 0 up to entry_size - 1) : "
233 << entry << " >= " << entry_size);
234
235 if (cpt.size() == 0) GUM_ERROR(SizeError, "setCPT : empty credal set for entry : " << entry)
236
237 for (const auto& vertex: cpt) {
238 if (vertex.size() != var_dSize)
240 "setCPT : variable modalities in cpts does not "
241 "match for node id : "
242 << id << " with vertex " << vertex << " at entry " << entry << " : "
243 << vertex.size() << " != " << var_dSize);
244
245 GUM_SCALAR sum = 0;
246
247 for (const auto& prob: vertex) {
248 sum += prob;
249 }
250
251 if (std::fabs(sum - 1) > 1e-6)
253 "setCPT : a vertex coordinates does not sum to one for node id : "
254 << id << " at entry " << entry << " with vertex " << vertex);
255 }
256
257 auto& node_cpt = _credalNet_src_cpt_.getWithDefault(
258 id,
259 std::vector< std::vector< std::vector< GUM_SCALAR > > >(entry_size));
260
261 if (node_cpt[entry].size() != 0)
263 "setCPT : vertices of entry : " << ins << " id " << entry
264 << " already set to : " << node_cpt[entry]
265 << ", cannot insert : " << cpt);
266
267 node_cpt[entry] = cpt;
268
270 }
271
272 template < typename GUM_SCALAR >
274 const std::vector< GUM_SCALAR >& lower,
275 const std::vector< GUM_SCALAR >& upper) {
276 try {
277 _src_bn_min_.cpt(id).fillWith(lower);
278 _src_bn_max_.cpt(id).fillWith(upper);
279 } catch (const SizeError&) {
281 "fillConstraints : sizes does not match in fillWith for node id : " << id);
282 }
283 }
284
285 template < typename GUM_SCALAR >
287 const Idx& entry,
288 const std::vector< GUM_SCALAR >& lower,
289 const std::vector< GUM_SCALAR >& upper) {
290 Tensor< GUM_SCALAR >* const tensor_min(
291 const_cast< Tensor< GUM_SCALAR >* const >(&_src_bn_min_.cpt(id)));
292 Tensor< GUM_SCALAR >* const tensor_max(
293 const_cast< Tensor< GUM_SCALAR >* const >(&_src_bn_max_.cpt(id)));
294
295 auto var_dSize = _src_bn_.variable(id).domainSize();
296
297 if (lower.size() != var_dSize || upper.size() != var_dSize)
299 "setCPT : variable modalities in cpts does not match for node id : "
300 << id << " with sizes of constraints : ( " << lower.size() << " || "
301 << upper.size() << " ) != " << var_dSize);
302
303 auto entry_size = tensor_min->domainSize() / var_dSize;
304
305 if (entry >= entry_size)
307 "setCPT : entry is greater or equal than entry size "
308 "(entries start at 0 up to entry_size - 1) : "
309 << entry << " >= " << entry_size);
310
311 Instantiation min(tensor_min);
312 Instantiation max(tensor_max);
313 min.setFirst();
314 max.setFirst();
315
316 Idx pos = 0;
317
318 while (pos != entry) {
319 ++min;
320 ++max;
321 ++pos;
322 }
323
324 for (Size i = 0; i < var_dSize; i++) {
325 tensor_min->set(min, lower[i]);
326 tensor_max->set(max, upper[i]);
327 ++min;
328 ++max;
329 }
330 }
331
332 template < typename GUM_SCALAR >
334 Instantiation ins,
335 const std::vector< GUM_SCALAR >& lower,
336 const std::vector< GUM_SCALAR >& upper) {
337 const Tensor< GUM_SCALAR >* const tensor(&_src_bn_.cpt(id));
338 /*
339 auto var_dSize = _src_bn_.variable ( id ).domainSize();
340 auto entry_size = tensor->domainSize() / var_dSize;
341 */
342 // to be sure of entry index reorder ins according to the bayes net
343 // tensors
344 // ( of the credal net )
345 // it WONT throw an error if the sequences are not equal not because of
346 // order
347 // but content, so we double check (before & after order correction)
348 // beware of slaves & master
349 Instantiation ref(tensor);
350 ref.forgetMaster();
351
352 ins.forgetMaster();
353
354 const auto& vseq = ref.variablesSequence();
355
356 if (ins.variablesSequence() != vseq) {
357 ins.reorder(ref);
358
359 if (ins.variablesSequence() != vseq)
361 "setCPT : instantiation : "
362 << ins << " is not valid for node id " << id
363 << " which accepts instantiations such as (order is not "
364 "important) : "
365 << ref);
366 }
367
368 Idx entry = 0, jump = 1;
369
370 for (Idx i = 0, end = ins.nbrDim(); i < end; i++) {
371 if (_src_bn_.nodeId(ins.variable(i)) == id) continue;
372
373 entry += ins.val(i) * jump;
374
375 jump *= ins.variable(i).domainSize();
376 }
377
378 /*
379 if ( entry >= entry_size )
380 GUM_ERROR ( SizeError, "setCPT : entry is greater or equal than entry
381 size
382 (entries start at 0 up to entry_size - 1) : " << entry << " >= " <<
383 entry_size
384 );
385
386 if ( lower.size() != var_dSize || upper.size() != var_dSize )
387 GUM_ERROR ( SizeError, "setCPT : variable modalities in cpts does not
388 match
389 for node id : " << id << " with sizes of constraints : ( "<< lower.size()
390 << "
391 || " << upper.size() << " ) != " << var_dSize );
392 */
393 fillConstraint(id, entry, lower, upper);
394 }
395
398
399 template < typename GUM_SCALAR >
403
404 template < typename GUM_SCALAR >
406 return _src_bn_.variable(id).domainSize();
407 }
408
410
411 template < typename GUM_SCALAR >
412 CredalNet< GUM_SCALAR >::CredalNet(const std::string& src_min_num,
413 const std::string& src_max_den) {
414 _initParams_();
415 _initCNNets_(src_min_num, src_max_den);
416
417 GUM_CONSTRUCTOR(CredalNet);
418 }
419
420 template < typename GUM_SCALAR >
421 CredalNet< GUM_SCALAR >::CredalNet(const BayesNet< GUM_SCALAR >& src_min_num,
422 const BayesNet< GUM_SCALAR >& src_max_den) {
423 _initParams_();
424 _initCNNets_(src_min_num, src_max_den);
425
426 GUM_CONSTRUCTOR(CredalNet);
427 }
428
429 template < typename GUM_SCALAR >
431 if (_current_bn_ != nullptr) delete _current_bn_;
432
434
435 if (_current_nodeType_ != nullptr) delete _current_nodeType_;
436
437 GUM_DESTRUCTOR(CredalNet);
438 }
439
440 // from BNs with numerators & denominators or cpts & denominators to credal
441 template < typename GUM_SCALAR >
442 void CredalNet< GUM_SCALAR >::bnToCredal(GUM_SCALAR beta, bool oneNet) {
443 this->bnToCredal(beta, oneNet, false);
444 }
445
446 template < typename GUM_SCALAR >
447 void CredalNet< GUM_SCALAR >::bnToCredal(GUM_SCALAR beta, bool oneNet, bool keepZeroes) {
448 GUM_SCALAR epsi_min = 1.;
449 GUM_SCALAR epsi_max = 0.;
450 GUM_SCALAR epsi_moy = 0.;
451 GUM_SCALAR epsi_den = 0.;
452
453 for (auto node: src_bn().nodes()) {
454 const Tensor< GUM_SCALAR >* const tensor(&_src_bn_.cpt(node));
455
456 Tensor< GUM_SCALAR >* const tensor_min(
457 const_cast< Tensor< GUM_SCALAR >* const >(&_src_bn_min_.cpt(node)));
458 Tensor< GUM_SCALAR >* const tensor_max(
459 const_cast< Tensor< GUM_SCALAR >* const >(&_src_bn_max_.cpt(node)));
460
461 Size var_dSize = _src_bn_.variable(node).domainSize();
462 Size entry_size = tensor->domainSize() / var_dSize;
463
464 Instantiation ins(tensor);
465 Instantiation ins_min(tensor_min);
466 Instantiation ins_max(tensor_max);
467
468 ins.setFirst();
469 ins_min.setFirst();
470 ins_max.setFirst();
471
472 std::vector< GUM_SCALAR > vertex(var_dSize);
473
474 for (Size entry = 0; entry < entry_size; entry++) {
475 GUM_SCALAR den;
476
477 if (oneNet) den = 0;
478 else den = tensor_max->get(ins_max);
479
480 Size nbm = 0;
481
482 for (Size modality = 0; modality < var_dSize; modality++) {
483 vertex[modality] = tensor->get(ins);
484
485 if (oneNet) {
486 den += vertex[modality];
487
488 if (vertex[modality] < 1 && vertex[modality] > 0)
490 "bnToCredal : the BayesNet contains "
491 "probabilities and not event counts "
492 "although user precised oneNet = "
493 << oneNet);
494 }
495
496 if (vertex[modality] > 0) nbm++;
497
498 ++ins;
499 }
500
502 if (!oneNet) {
503 GUM_SCALAR sum = 0;
504
505 for (auto modality = vertex.cbegin(), theEnd = vertex.cend(); modality != theEnd;
506 ++modality) {
507 sum += *modality;
508 }
509
510 if (std::fabs(1. - sum) > _epsRedund_) {
512 _src_bn_.variable(node).name()
513 << "(" << _epsRedund_ << ") does not sum to one for" << " " << entry
514 << std::endl
515 << vertex << std::endl
516 << ins << std::endl);
517 }
518 }
519
521
522 GUM_SCALAR epsilon;
523
524 if (beta == 0) epsilon = 0;
525 else if (den == 0 || beta == 1) epsilon = GUM_SCALAR(1.0);
526 else epsilon = GUM_SCALAR(std::pow(beta, std::log1p(den)));
527
528 epsi_moy += epsilon;
529 epsi_den += 1;
530
531 if (epsilon > epsi_max) epsi_max = epsilon;
532
533 if (epsilon < epsi_min) epsi_min = epsilon;
534
535 GUM_SCALAR min, max;
536
537 for (Size modality = 0; modality < var_dSize; modality++) {
538 if ((vertex[modality] > 0 && nbm > 1) || !keepZeroes) {
539 min = GUM_SCALAR((1. - epsilon) * vertex[modality]);
540
541 if (oneNet) min = GUM_SCALAR(min * 1.0 / den);
542
543 max = GUM_SCALAR(min + epsilon);
544 } else { // if ( ( vertex[modality] == 0 && keepZeroes ) || (
545 // vertex[modality] > 0 && nbm <= 1 ) || ( vertex[modality] == 0
546 // && nbm <= 1 ) ) {
547 min = vertex[modality];
548
549 if (oneNet) min = GUM_SCALAR(min * 1.0 / den);
550
551 max = min;
552 }
553
554 tensor_min->set(ins_min, min);
555 tensor_max->set(ins_max, max);
556
557 ++ins_min;
558 ++ins_max;
559 } // end of : for each modality
560
561 } // end of : for each entry
562
563 } // end of : for each variable
564
565 _epsilonMin_ = epsi_min;
566 _epsilonMax_ = epsi_max;
567 _epsilonMoy_ = (GUM_SCALAR)epsi_moy / (GUM_SCALAR)epsi_den;
568
570 }
571
572 template < typename GUM_SCALAR >
574 for (auto node: _src_bn_.nodes()) {
575 const Tensor< GUM_SCALAR >* const tensor(&_src_bn_.cpt(node));
576
577 auto var_dSize = _src_bn_.variable(node).domainSize();
578 auto entry_size = tensor->domainSize() / var_dSize;
579
580 Instantiation ins(tensor);
581
582 ins.setFirst();
583
584 std::vector< GUM_SCALAR > vertex(var_dSize);
585
586 for (Size entry = 0; entry < entry_size; entry++) {
587 GUM_SCALAR den = 0;
588 bool zeroes = false;
589 Instantiation ins_prev = ins;
590
591 for (Size modality = 0; modality < var_dSize; modality++) {
592 vertex[modality] = tensor->get(ins);
593
594 if (vertex[modality] < 1 && vertex[modality] > 0)
596 "lagrangeNormalization : the BayesNet "
597 "contains probabilities and not event "
598 "counts.");
599
600 den += vertex[modality];
601
602 if (!zeroes && vertex[modality] == 0) { zeroes = true; }
603
604 ++ins;
605 }
606
607 if (zeroes) {
608 ins = ins_prev;
609
610 for (Size modality = 0; modality < var_dSize; modality++) {
611 tensor->set(ins, tensor->get(ins) + 1);
612 ++ins;
613 }
614 }
615
616 } // end of : for each entry
617
618 } // end of : for each variable
619 }
620
621 template < typename GUM_SCALAR >
622 void CredalNet< GUM_SCALAR >::idmLearning(const Idx s, const bool keepZeroes) {
623 for (auto node: _src_bn_.nodes()) {
624 const Tensor< GUM_SCALAR >* const tensor(&_src_bn_.cpt(node));
625
626 Tensor< GUM_SCALAR >* const tensor_min(
627 const_cast< Tensor< GUM_SCALAR >* const >(&_src_bn_min_.cpt(node)));
628 Tensor< GUM_SCALAR >* const tensor_max(
629 const_cast< Tensor< GUM_SCALAR >* const >(&_src_bn_max_.cpt(node)));
630
631 Size var_dSize = _src_bn_.variable(node).domainSize();
632 Size entry_size = tensor->domainSize() / var_dSize;
633
634 Instantiation ins(tensor);
635 Instantiation ins_min(tensor_min);
636 Instantiation ins_max(tensor_max);
637
638 ins.setFirst();
639 ins_min.setFirst();
640 ins_max.setFirst();
641
642 std::vector< GUM_SCALAR > vertex(var_dSize);
643
644 for (Size entry = 0; entry < entry_size; entry++) {
645 GUM_SCALAR den = 0;
646 Size nbm = 0;
647
648 for (Size modality = 0; modality < var_dSize; modality++) {
649 vertex[modality] = tensor->get(ins);
650
651 if (vertex[modality] < 1 && vertex[modality] > 0)
653 "idmLearning : the BayesNet contains "
654 "probabilities and not event counts.");
655
656 den += vertex[modality];
657
658 if (vertex[modality] > 0) nbm++;
659
660 ++ins;
661 }
662
663 if (nbm > 1 || !keepZeroes) den += s;
664
665 GUM_SCALAR min, max;
666
667 for (Size modality = 0; modality < var_dSize; modality++) {
668 min = vertex[modality];
669 max = min;
670
671 if ((vertex[modality] > 0 && nbm > 1) || !keepZeroes) { max += s; }
672
673 min = GUM_SCALAR(min * 1.0 / den);
674 max = GUM_SCALAR(max * 1.0 / den);
675
676 tensor_min->set(ins_min, min);
677 tensor_max->set(ins_max, max);
678
679 ++ins_min;
680 ++ins_max;
681 } // end of : for each modality
682
683 } // end of : for each entry
684
685 } // end of : for each variable
686
687 _epsilonMin_ = GUM_SCALAR(s);
688 _epsilonMax_ = GUM_SCALAR(s);
689 _epsilonMoy_ = GUM_SCALAR(s);
691 }
692
693 /* no need for lrs : (max ... min ... max) vertices from bnToCredal() */
694 template < typename GUM_SCALAR >
696 if (!_credalNet_src_cpt_.empty()) _credalNet_src_cpt_.clear();
697
698 _credalNet_src_cpt_.resize(_src_bn_.size());
699
700 for (auto node: _src_bn_.nodes()) {
701 const Tensor< GUM_SCALAR >* const tensor_min(&_src_bn_min_.cpt(node));
702 const Tensor< GUM_SCALAR >* const tensor_max(&_src_bn_max_.cpt(node));
703
704 Size var_dSize = _src_bn_.variable(node).domainSize();
705 Size entry_size = tensor_min->domainSize() / var_dSize;
706
707 std::vector< std::vector< std::vector< GUM_SCALAR > > > var_cpt(entry_size);
708
709 Instantiation ins_min(tensor_min);
710 Instantiation ins_max(tensor_max);
711
712 ins_min.setFirst();
713 ins_max.setFirst();
714
715 std::vector< GUM_SCALAR > lower(var_dSize);
716 std::vector< GUM_SCALAR > upper(var_dSize);
717
718 for (Size entry = 0; entry < entry_size; entry++) {
719 for (Size modality = 0; modality < var_dSize; modality++, ++ins_min, ++ins_max) {
720 lower[modality] = tensor_min->get(ins_min);
721 upper[modality] = tensor_max->get(ins_max);
722 }
723
724 bool all_equals = true;
725 std::vector< std::vector< GUM_SCALAR > > vertices;
726
727 for (Size modality = 0; modality < var_dSize; modality++) {
728 if (std::fabs(upper[modality] - lower[modality]) < 1e-6) continue;
729
730 all_equals = false;
731 std::vector< GUM_SCALAR > vertex(var_dSize);
732 vertex[modality] = upper[modality];
733
734 for (Size mod = 0; mod < var_dSize; mod++) {
735 if (modality != mod) vertex[mod] = lower[mod];
736 }
737
738 GUM_SCALAR total = 0;
739
740 auto vsize = vertex.size();
741
742 for (Size i = 0; i < vsize; i++)
743 total += vertex[i];
744
745 if (std::fabs(total - 1.) > 1e-6)
747 _src_bn_.variable(node).name()
748 << " does not sum to one for " << entry << std::endl
749 << vertex << std::endl);
750
751 vertices.push_back(vertex);
752 }
753
754 if (all_equals) {
755 std::vector< GUM_SCALAR > vertex(var_dSize);
756
757 for (Size modality = 0; modality < var_dSize; modality++)
758 vertex[modality] = lower[modality];
759
760 GUM_SCALAR total = 0.;
761
762 auto vsize = vertex.size();
763
764 for (Size i = 0; i < vsize; i++)
765 total += vertex[i];
766
767 if (std::fabs(total - 1.) > 1e-6)
769 _src_bn_.variable(node).name()
770 << " does not sum to one for " << entry << std::endl
771 << vertex << std::endl);
772
773 vertices.push_back(vertex);
774 }
775
776 var_cpt[entry] = vertices;
777 }
778
779 _credalNet_src_cpt_.insert(node, var_cpt);
780
781 } // end of : for each variable (node)
782
783 // get precise/credal/vacuous status of each variable
786 }
787
788 /* uses lrsWrapper */
789 template < typename GUM_SCALAR >
791 if (!_credalNet_src_cpt_.empty()) _credalNet_src_cpt_.clear();
792
793 _credalNet_src_cpt_.resize(_src_bn_.size());
794
795 LRSWrapper< GUM_SCALAR > lrsWrapper;
796
797 for (auto node: _src_bn_.nodes()) {
798 const Tensor< GUM_SCALAR >* const tensor_min(&_src_bn_min_.cpt(node));
799 const Tensor< GUM_SCALAR >* const tensor_max(&_src_bn_max_.cpt(node));
800
801 Size var_dSize = _src_bn_.variable(node).domainSize();
802 Size entry_size = tensor_min->domainSize() / var_dSize;
803
804 std::vector< std::vector< std::vector< GUM_SCALAR > > > var_cpt(entry_size);
805
806 Instantiation ins_min(tensor_min);
807 Instantiation ins_max(tensor_max);
808
809 ins_min.setFirst();
810 ins_max.setFirst();
811
812 lrsWrapper.setUpH(var_dSize);
813
814 for (Size entry = 0; entry < entry_size; entry++) {
815 for (Size modality = 0; modality < var_dSize; modality++) {
816 if (tensor_min->get(ins_min) > tensor_max->get(ins_max)) {
818 "For variable "
819 << _src_bn_.variable(node).name() << " (at " << ins_min
820 << "), the min is greater than the max : " << tensor_min->get(ins_min)
821 << ">" << tensor_max->get(ins_max) << ".");
822 }
823 lrsWrapper.fillH(tensor_min->get(ins_min), tensor_max->get(ins_max), modality);
824 ++ins_min;
825 ++ins_max;
826 }
827
828 lrsWrapper.H2V();
829 var_cpt[entry] = lrsWrapper.getOutput();
830 lrsWrapper.nextHInput();
831 }
832
833 _credalNet_src_cpt_.insert(node, var_cpt);
834
835 } // end of : for each variable (node)
836
837 // get precise/credal/vacuous status of each variable
840 }
841
842 /* call lrs */
843 template < typename GUM_SCALAR >
845 if (!_credalNet_src_cpt_.empty()) _credalNet_src_cpt_.clear();
846
847 _credalNet_src_cpt_.resize(_src_bn_.size());
848
849 for (auto node: _src_bn_.nodes()) {
850 const Tensor< GUM_SCALAR >* const tensor_min(&_src_bn_min_.cpt(node));
851 const Tensor< GUM_SCALAR >* const tensor_max(&_src_bn_max_.cpt(node));
852
853 auto var_dSize = _src_bn_.variable(node).domainSize();
854 auto entry_size = tensor_min->domainSize() / var_dSize;
855
856 std::vector< std::vector< std::vector< GUM_SCALAR > > > var_cpt(entry_size);
857
858 Instantiation ins_min(tensor_min);
859 Instantiation ins_max(tensor_max);
860
861 ins_min.setFirst();
862 ins_max.setFirst();
863
864 // use iterator
865 for (Size entry = 0; entry < entry_size; entry++) {
866 std::vector< std::vector< GUM_SCALAR > > vertices;
867 std::vector< GUM_SCALAR > vertex(var_dSize); // if not interval
868
869 std::vector< std::vector< GUM_SCALAR > > inequalities(
870 var_dSize * 2,
871 std::vector< GUM_SCALAR >(var_dSize + 1, 0));
872
873 std::vector< GUM_SCALAR > sum_ineq1(var_dSize + 1, -1);
874 std::vector< GUM_SCALAR > sum_ineq2(var_dSize + 1, 1);
875 sum_ineq1[0] = 1;
876 sum_ineq2[0] = -1;
877
878 bool isInterval = false;
879
880 for (Size modality = 0; modality < var_dSize; modality++) {
881 inequalities[modality * 2][0] = -tensor_min->get(ins_min);
882 inequalities[modality * 2 + 1][0] = tensor_max->get(ins_max);
883 inequalities[modality * 2][modality + 1] = 1;
884 inequalities[modality * 2 + 1][modality + 1] = -1;
885
886 vertex[modality] = inequalities[modality * 2 + 1][0];
887
888 if (!isInterval
889 && (-inequalities[modality * 2][0] != inequalities[modality * 2 + 1][0]))
890 isInterval = true;
891
892 ++ins_min;
893 ++ins_max;
894 }
895
896 inequalities.push_back(sum_ineq1);
897 inequalities.push_back(sum_ineq2);
898
899 if (!isInterval) {
900 vertices.push_back(vertex);
901 } else {
902 try {
903 _H2Vlrs_(inequalities, vertices);
904 // __H2Vcdd ( inequalities, vertices );
905 } catch (const std::exception& err) {
906 std::cout << err.what() << std::endl;
907 throw;
908 }
909
910 } // end of : is interval
911
912 if (entry == 0 && vertices.size() >= 2) {
913 auto tmp = vertices[0];
914 vertices[0] = vertices[1];
915 vertices[1] = tmp;
916 }
917
918 var_cpt[entry] = vertices;
919
920 } // end of : for each entry
921
922 _credalNet_src_cpt_.insert(node, var_cpt);
923 // std::cout << _src_bn_.variable(node_idIt).name() << std::endl;
924 // std::cout << var_cpt << std::endl;
925
926 } // end of : for each variable (node)
927
928 // get precise/credal/vacuous status of each variable
931 }
932
937 template < typename GUM_SCALAR >
938 void CredalNet< GUM_SCALAR >::saveBNsMinMax(const std::string& min_path,
939 const std::string& max_path) const {
941
942 std::string minfilename = min_path; //"min.bif";
943 std::string maxfilename = max_path; //"max.bif";
944 std::ofstream min_file(minfilename.c_str(), std::ios::out | std::ios::trunc);
945 std::ofstream max_file(maxfilename.c_str(), std::ios::out | std::ios::trunc);
946
947 if (!min_file.good())
948 GUM_ERROR(IOError, "bnToCredal() : could not open stream : min_file : " << minfilename);
949
950 if (!max_file.good()) {
951 min_file.close();
952 GUM_ERROR(IOError, "bnToCredal() : could not open stream : min_file : " << maxfilename);
953 }
954
955 try {
956 writer.write(min_file, _src_bn_min_);
957 writer.write(max_file, _src_bn_max_);
958 } catch (Exception& err) {
959 GUM_SHOWERROR(err);
960 min_file.close();
961 max_file.close();
962 throw(err);
963 }
964
965 min_file.close();
966 max_file.close();
967 }
968
969 template < typename GUM_SCALAR >
971 // don't forget to delete the old one ( _current_), if necessary at the end
972 auto bin_bn = new BayesNet< GUM_SCALAR >();
973
974 // __bnCopy ( * _bin_bn_ );
975 // delete old one too
976 auto credalNet_bin_cpt
978
979 // delete old one too
980 auto bin_nodeType = new NodeProperty< NodeType >();
981
982 const BayesNet< GUM_SCALAR >* current_bn;
984 credalNet_current_cpt;
985
986 if (this->_current_bn_ == nullptr) current_bn = &this->_src_bn_;
987 else current_bn = this->_current_bn_;
988
989 if (this->_credalNet_current_cpt_ == nullptr)
990 credalNet_current_cpt = &this->_credalNet_src_cpt_;
991 else credalNet_current_cpt = this->_credalNet_current_cpt_;
992
993 if (!_var_bits_.empty()) _var_bits_.clear();
994
995 bin_bn->beginTopologyTransformation();
996
997 for (auto node: current_bn->nodes()) {
998 auto var_dSize = current_bn->variable(node).domainSize();
999
1000 if (var_dSize != 2) {
1001 unsigned long b;
1002 unsigned long c;
1003 superiorPow(static_cast< unsigned long >(var_dSize), b, c);
1004 Size nb_bits{b};
1005
1006 std::string bit_name;
1007 std::vector< NodeId > bits(nb_bits);
1008
1009 for (Size bit = 0; bit < nb_bits; bit++) {
1010 bit_name = current_bn->variable(node).name() + "-b";
1011 std::stringstream ss;
1012 ss << bit;
1013 bit_name += ss.str();
1014
1015 LabelizedVariable var_bit(bit_name, "node " + bit_name, 2);
1016 NodeId iD = bin_bn->add(var_bit);
1017
1018 bits[bit] = iD;
1019 } // end of : for each bit
1020
1021 _var_bits_.insert(node, bits);
1022
1023 } // end of : if variable is not binary
1024 else {
1025 const std::string bit_name = current_bn->variable(node).name();
1026 LabelizedVariable var_bit(bit_name, "node " + bit_name, 2);
1027 const NodeId iD = bin_bn->add(var_bit);
1028
1029 _var_bits_.insert(node, std::vector< NodeId >(1, iD));
1030 }
1031
1032 } // end of : for each original variable
1033
1034 for (auto node: current_bn->nodes()) {
1035 if (NodeSet parents = current_bn->parents(node); !parents.empty()) {
1036 for (auto par: current_bn->parents(node)) {
1037 for (Size parent_bit = 0, spbits = static_cast< Size >(_var_bits_[par].size());
1038 parent_bit < spbits;
1039 parent_bit++)
1040 for (Size var_bit = 0, mbits = static_cast< Size >(_var_bits_[node].size());
1041 var_bit < mbits;
1042 var_bit++)
1043 bin_bn->addArc(_var_bits_[par][parent_bit], _var_bits_[node][var_bit]);
1044 }
1045 }
1046
1047 // arcs with one's bits
1048 const auto bitsize = _var_bits_[node].size();
1049
1050 for (Size bit_c = 1; bit_c < bitsize; bit_c++)
1051 for (Size bit_p = 0; bit_p < bit_c; bit_p++)
1052 bin_bn->addArc(_var_bits_[node][bit_p], _var_bits_[node][bit_c]);
1053
1054 } // end of : for each original variable
1055
1056 bin_bn->endTopologyTransformation();
1057
1058 // binarization of cpts
1059
1060 const auto varsize = current_bn->size();
1061
1062 for (Size var = 0; var < varsize; var++) {
1063 const auto bitsize = _var_bits_[var].size();
1064
1065 for (Size i = 0; i < bitsize; i++) {
1066 Tensor< GUM_SCALAR > const* tensor(&bin_bn->cpt(_var_bits_[var][i]));
1067 Instantiation ins(tensor);
1068 ins.setFirst();
1069
1070 auto entry_size = tensor->domainSize() / 2;
1071 std::vector< std::vector< std::vector< GUM_SCALAR > > > var_cpt(entry_size);
1072
1073 Size old_conf = 0;
1074
1075 for (Size conf = 0; conf < entry_size; conf++) {
1076 std::vector< std::vector< GUM_SCALAR > > pvar_cpt;
1077 auto verticessize = (*credalNet_current_cpt)[var][old_conf].size();
1078
1079 for (Size old_distri = 0; old_distri < verticessize; old_distri++) {
1080 const std::vector< GUM_SCALAR >& vertex
1081 = (*credalNet_current_cpt)[var][old_conf][old_distri];
1082 auto vertexsize = vertex.size();
1083
1084 std::vector< Idx > incc(vertexsize, 0);
1085
1086 for (Size preced = 0; preced < i; preced++) {
1087 auto bit_pos = ins.pos(bin_bn->variable(_var_bits_[var][preced]));
1088 auto val = ins.val(bit_pos);
1089
1090 Size pas = Size(int2Pow(preced));
1091 Size elem;
1092
1093 if (val == 0) elem = 0;
1094 else elem = pas;
1095
1096 while (elem < vertexsize) {
1097 incc[elem]++;
1098 elem++;
1099
1100 if (elem % pas == 0) elem += pas;
1101 }
1102 }
1103
1104 Size pas = Size(int2Pow(i));
1105
1106 std::vector< GUM_SCALAR > distri(2, 0);
1107 int pos = 1;
1108
1109 for (Size elem = 0; elem < vertexsize; elem++) {
1110 if (elem % pas == 0) pos = -pos;
1111
1112 if (incc[elem] == i)
1113 (pos < 0) ? (distri[0] += vertex[elem]) : (distri[1] += vertex[elem]);
1114 }
1115
1116 if (i > 0) {
1117 GUM_SCALAR den = distri[0] + distri[1];
1118
1119 if (den == 0) {
1120 distri[0] = 0;
1121 distri[1] = 0;
1122 } else {
1123 distri[0] /= den;
1124 distri[1] /= den;
1125 }
1126 }
1127
1128 pvar_cpt.push_back(distri);
1129
1130 } // end of old distris
1131
1132 // get min/max approx, 2 vertices
1133 std::vector< std::vector< GUM_SCALAR > > vertices(2, std::vector< GUM_SCALAR >(2, 1));
1134 vertices[1][1] = 0;
1135
1136 const auto new_verticessize = pvar_cpt.size();
1137
1138 for (Size v = 0; v < new_verticessize; v++) {
1139 if (pvar_cpt[v][1] < vertices[0][1]) vertices[0][1] = pvar_cpt[v][1];
1140
1141 if (pvar_cpt[v][1] > vertices[1][1]) vertices[1][1] = pvar_cpt[v][1];
1142 }
1143
1144 vertices[0][0] = 1 - vertices[0][1];
1145 vertices[1][0] = 1 - vertices[1][1];
1146
1147 pvar_cpt = vertices;
1148
1149 var_cpt[conf] = pvar_cpt;
1150
1151 ++ins;
1152 ++ins;
1153
1154 old_conf++;
1155
1156 if (old_conf == (*credalNet_current_cpt)[var].size()) old_conf = 0;
1157
1158 } // end of new parent conf
1159
1160 credalNet_bin_cpt->insert(_var_bits_[var][i], var_cpt);
1161
1162 } // end of bit i
1163
1164 } // end of old variable
1165
1166 bin_bn->beginTopologyTransformation();
1167
1168 /* indicatrices variables */
1169 const auto old_varsize = _var_bits_.size();
1170
1171 for (Size i = 0; i < old_varsize; i++) {
1172 auto bitsize = _var_bits_[i].size();
1173
1174 // binary variable
1175 if (bitsize == 1) continue;
1176
1177 auto old_card = _src_bn_.variable(i).domainSize();
1178
1179 for (Size mod = 0; mod < old_card; mod++) {
1180 std::stringstream ss;
1181 ss << _src_bn_.variable(i).name();
1182 ss << "-v";
1183 ss << mod;
1184
1185 LabelizedVariable var(ss.str(), "node " + ss.str(), 2);
1186 const NodeId indic = bin_bn->add(var);
1187
1188 // arcs from one's bits
1189 for (Size bit = 0; bit < bitsize; bit++)
1190 bin_bn->addArc(_var_bits_[i][bit], indic);
1191
1192 // cpt
1193 Size num = Size(int2Pow(long(bitsize)));
1194
1195 std::vector< std::vector< std::vector< GUM_SCALAR > > > icpt(num);
1196
1197 for (Size entry = 0; entry < num; entry++) {
1198 std::vector< std::vector< GUM_SCALAR > > vertices(1, std::vector< GUM_SCALAR >(2, 0));
1199
1200 if (mod == entry) vertices[0][1] = 1;
1201 else vertices[0][0] = 1;
1202
1203 icpt[entry] = vertices;
1204 }
1205
1206 credalNet_bin_cpt->insert(indic, icpt);
1207
1208 bin_nodeType->insert(indic, NodeType::Indic);
1209 } // end of each modality, i.e. as many indicatrice
1210 }
1211
1212 bin_bn->endTopologyTransformation();
1213
1214 if (this->_current_bn_ != nullptr) delete this->_current_bn_;
1215
1216 this->_current_bn_ = bin_bn;
1217
1218 if (this->_credalNet_current_cpt_ != nullptr) delete this->_credalNet_current_cpt_;
1219
1220 this->_credalNet_current_cpt_ = credalNet_bin_cpt;
1221
1222 if (this->_current_nodeType_ != nullptr) delete this->_current_nodeType_;
1223
1224 this->_current_nodeType_ = bin_nodeType;
1225
1226 _sort_varType_(); // will fill _bin_nodeType_ except for NodeType::Indic
1227 // variables
1228
1230 }
1231
1232 template < typename GUM_SCALAR >
1239
1240 template < typename GUM_SCALAR >
1245
1246 template < typename GUM_SCALAR >
1249 if (_current_nodeType_ != nullptr) return (*(_current_nodeType_))[id];
1250
1251 return _original_nodeType_[id];
1252 }
1253
1254 template < typename GUM_SCALAR >
1257 return _original_nodeType_[id];
1258 }
1259
1260 template < typename GUM_SCALAR >
1264
1265 template < typename GUM_SCALAR >
1269
1270 // only if CN is binary !!
1271 template < typename GUM_SCALAR >
1273 _binCptMin_.resize(current_bn().size());
1274 _binCptMax_.resize(current_bn().size());
1275
1276 for (auto node: current_bn().nodes()) {
1277 auto pConf = credalNet_currentCpt()[node].size();
1278 std::vector< GUM_SCALAR > min(pConf);
1279 std::vector< GUM_SCALAR > max(pConf);
1280
1281 for (Size pconf = 0; pconf < pConf; pconf++) {
1282 GUM_SCALAR v1, v2;
1283 v1 = credalNet_currentCpt()[node][pconf][0][1];
1284
1285 if (credalNet_currentCpt()[node][pconf].size() > 1)
1286 v2 = credalNet_currentCpt()[node][pconf][1][1];
1287 else v2 = v1;
1288
1289 GUM_SCALAR delta = v1 - v2;
1290 min[pconf] = (delta >= 0) ? v2 : v1;
1291 max[pconf] = (delta >= 0) ? v1 : v2;
1292 }
1293
1294 _binCptMin_[node] = min;
1295 _binCptMax_[node] = max;
1296 }
1297
1299 }
1300
1301 template < typename GUM_SCALAR >
1302 const std::vector< std::vector< GUM_SCALAR > >&
1306
1307 template < typename GUM_SCALAR >
1308 const std::vector< std::vector< GUM_SCALAR > >&
1312
1313 template < typename GUM_SCALAR >
1314 const GUM_SCALAR& CredalNet< GUM_SCALAR >::epsilonMin() const {
1315 return _epsilonMin_;
1316 }
1317
1318 template < typename GUM_SCALAR >
1319 const GUM_SCALAR& CredalNet< GUM_SCALAR >::epsilonMax() const {
1320 return _epsilonMax_;
1321 }
1322
1323 template < typename GUM_SCALAR >
1324 const GUM_SCALAR& CredalNet< GUM_SCALAR >::epsilonMean() const {
1325 return _epsilonMoy_;
1326 }
1327
1328 template < typename GUM_SCALAR >
1330 std::stringstream output;
1331 const BayesNet< GUM_SCALAR >* _current_bn_;
1334
1335 if (this->_current_bn_ == nullptr) _current_bn_ = &this->_src_bn_;
1336 else _current_bn_ = this->_current_bn_;
1337
1338 if (this->_credalNet_current_cpt_ == nullptr)
1340 else _credalNet_current_cpt_ = this->_credalNet_current_cpt_;
1341
1342 for (auto node: _current_bn_->nodes()) {
1343 const Tensor< GUM_SCALAR >* tensor(&_current_bn_->cpt(node));
1344 auto pconfs = tensor->domainSize() / _current_bn_->variable(node).domainSize();
1345
1346 output << "\n" << _current_bn_->variable(node) << "\n";
1347
1348 Instantiation ins(tensor);
1349 ins.forgetMaster();
1350 ins.erase(_current_bn_->variable(node));
1351 ins.setFirst();
1352
1353 for (Size pconf = 0; pconf < pconfs; pconf++) {
1354 output << ins << " : ";
1355 output << (*_credalNet_current_cpt_)[node][pconf] << "\n";
1356
1357 if (pconf < pconfs - 1) ++ins;
1358 }
1359 }
1360
1361 output << "\n";
1362
1363 return output.str();
1364 }
1365
1366 template < typename GUM_SCALAR >
1367 const BayesNet< GUM_SCALAR >& CredalNet< GUM_SCALAR >::current_bn() const {
1368 if (_current_bn_ != nullptr) return *_current_bn_;
1369
1370 return _src_bn_;
1371 }
1372
1373 template < typename GUM_SCALAR >
1374 const BayesNet< GUM_SCALAR >& CredalNet< GUM_SCALAR >::src_bn() const {
1375 return _src_bn_;
1376 }
1377
1379
1381
1382 template < typename GUM_SCALAR >
1384 _epsilonMin_ = 0;
1385 _epsilonMax_ = 0;
1386 _epsilonMoy_ = 0;
1387
1388 _epsRedund_ = GUM_SCALAR(1e-6);
1389
1390 // farey algorithm
1391 _epsF_ = GUM_SCALAR(1e-6);
1392 _denMax_ = GUM_SCALAR(1e6); // beware LRSWrapper
1393
1394 // continued fractions, beware LRSWrapper
1395 // decimal paces ( _epsC_ * _precisionC_ == 1)
1396 _precisionC_ = GUM_SCALAR(1e6);
1397 _deltaC_ = 5;
1398
1399 // old custom algorithm
1400 _precision_ = GUM_SCALAR(1e6); // beware LRSWrapper
1401
1402 _current_bn_ = nullptr;
1403 _credalNet_current_cpt_ = nullptr;
1404 _current_nodeType_ = nullptr;
1405
1407 }
1408
1409 template < typename GUM_SCALAR >
1410 void CredalNet< GUM_SCALAR >::_initCNNets_(const std::string& src_min_num,
1411 const std::string& src_max_den) {
1412 BIFReader< GUM_SCALAR > reader(&_src_bn_, src_min_num);
1413 std::string other;
1414
1415 if (src_max_den.compare("") != 0) other = src_max_den;
1416 else other = src_min_num;
1417
1418 BIFReader< GUM_SCALAR > reader_min(&_src_bn_min_, src_min_num);
1419 BIFReader< GUM_SCALAR > reader_max(&_src_bn_max_, other);
1420
1421 reader.proceed();
1422 reader_min.proceed();
1423 reader_max.proceed();
1424 }
1425
1426 template < typename GUM_SCALAR >
1427 void CredalNet< GUM_SCALAR >::_initCNNets_(const BayesNet< GUM_SCALAR >& src_min_num,
1428 const BayesNet< GUM_SCALAR >& src_max_den) {
1429 _src_bn_ = src_min_num;
1430 _src_bn_min_ = src_min_num;
1431
1432 if (src_max_den.size() > 0) _src_bn_max_ = src_max_den;
1433 else _src_bn_max_ = src_min_num;
1434 }
1435
1436 template < typename GUM_SCALAR >
1438 const std::vector< std::vector< std::vector< GUM_SCALAR > > >& var_cpt) const {
1439 Size vertices_size = 0;
1440
1441 for (auto entry = var_cpt.cbegin(), theEnd = var_cpt.cend(); entry != theEnd; ++entry) {
1442 if (entry->size() > vertices_size) vertices_size = Size(entry->size());
1443 }
1444
1445 return int(vertices_size);
1446 }
1447
1448 template < typename GUM_SCALAR >
1449 void CredalNet< GUM_SCALAR >::_bnCopy_(BayesNet< GUM_SCALAR >& dest) {
1450 const BayesNet< GUM_SCALAR >* _current_bn_;
1451
1452 if (this->_current_bn_ == nullptr) _current_bn_ = &this->_src_bn_;
1453 else _current_bn_ = this->_current_bn_;
1454
1455 for (auto node: _current_bn_->nodes())
1456 dest.add(_current_bn_->variable(node));
1457
1458 dest.beginTopologyTransformation();
1459
1460 for (auto node: _current_bn_->nodes()) {
1461 for (auto parent_idIt: _current_bn_->cpt(node).variablesSequence()) {
1462 if (_current_bn_->nodeId(*parent_idIt) != node)
1463 dest.addArc(_current_bn_->nodeId(*parent_idIt), node);
1464 } // end of : for each parent in order of appearence
1465 } // end of : for each variable
1466
1467 dest.endTopologyTransformation();
1468 }
1469
1470 /*
1471 // cdd can use real values, not just rationals / integers
1472 template< typename GUM_SCALAR >
1473 void CredalNet< GUM_SCALAR >:: _H2Vcdd_ ( const std::vector< std::vector<
1474 GUM_SCALAR > > & h_rep, std::vector< std::vector< GUM_SCALAR > > & v_rep )
1475 const {
1476 dd_set_global_constants();
1477
1478 dd_MatrixPtr M, G;
1479 dd_PolyhedraPtr poly;
1480 dd_ErrorType err;
1481
1482 unsigned int rows = h_rep.size();
1483 unsigned int cols = 0;
1484 if( h_rep.size() > 0 )
1485 cols = h_rep[0].size();
1486
1487 M = dd_CreateMatrix( rows, cols);
1488
1489 for ( unsigned int row = 0; row < rows; row++ )
1490 for ( unsigned int col = 0; col < cols; col++ )
1491 dd_set_d( M->matrix[row][col], h_rep[row][col] );
1492
1493 M->representation = dd_Inequality;
1494
1495 poly = dd_DDMatrix2Poly(M, &err);
1496 G = dd_CopyGenerators(poly);
1497
1498 rows = G->rowsize;
1499 cols = G->colsize;
1500
1501 v_rep.clear();
1502 for ( unsigned int row = 0; row < rows; row++ ) {
1503 std::vector< GUM_SCALAR > aRow(cols - 1);
1504
1505 if ( *G->matrix[row][0] != 1 )
1506 GUM_ERROR(OperationNotAllowed, " __H2Vcdd : not reading a vertex")
1507
1508 for ( unsigned int col = 0; col < cols - 1; col++ )
1509 aRow[col] = *G->matrix[row][ col + 1 ];
1510
1511 v_rep.push_back(aRow);
1512 }
1513
1514 dd_FreeMatrix(M);
1515 dd_FreeMatrix(G);
1516 dd_FreePolyhedra(poly);
1517
1518 dd_free_global_constants();
1519 }
1520 */
1521
1522 template < typename GUM_SCALAR >
1523 void CredalNet< GUM_SCALAR >::_H2Vlrs_(const std::vector< std::vector< GUM_SCALAR > >& h_rep,
1524 std::vector< std::vector< GUM_SCALAR > >& v_rep) const {
1525 // write H rep file
1526 int64_t num, den;
1527
1528 std::string sinefile = getUniqueFileName(); // generate unique file name, we
1529 // need to add .ine or .ext for lrs
1530 // to know which input it is (Hrep
1531 // to Vrep or Vrep to Hrep)
1532 sinefile += ".ine";
1533
1534 std::ofstream h_file(sinefile.c_str(), std::ios::out | std::ios::trunc);
1535
1536 if (!h_file.good())
1537 GUM_ERROR(IOError, " __H2Vlrs : could not open lrs input file : " << sinefile)
1538
1539 h_file << "H - representation\n";
1540 h_file << "begin\n";
1541 h_file << h_rep.size() << ' ' << h_rep[0].size() << " rational\n";
1542
1543 for (auto it = h_rep.cbegin(), theEnd = h_rep.cend(); it != theEnd; ++it) {
1544 for (auto it2 = it->cbegin(), theEnd2 = it->cend(); it2 != theEnd2; ++it2) {
1545 // get integer fraction from decimal value
1546 // smallest numerator & denominator is farley, also
1547 // best precision
1549 den,
1550 ((*it2 > 0) ? *it2 : -*it2),
1551 int64_t(_denMax_),
1552 _epsF_);
1553
1554 h_file << ((*it2 > 0) ? num : -num) << '/' << den << ' ';
1555 }
1556
1557 h_file << '\n';
1558 }
1559
1560 h_file << "end\n";
1561 h_file.close();
1562
1563 // call lrs
1564 // lrs arguments
1565 char* args[3];
1566
1567 std::string soft_name = "lrs";
1568 std::string extfile(sinefile);
1569 extfile += ".ext";
1570
1571 args[0] = new char[soft_name.size()];
1572 args[1] = new char[sinefile.size()];
1573 args[2] = new char[extfile.size()];
1574
1575 strcpy(args[0], soft_name.c_str());
1576 strcpy(args[1], sinefile.c_str());
1577 strcpy(args[2], extfile.c_str());
1578
1579 // it may need to redirect stdout to a file
1580 lrs_main(3, args);
1581
1582 delete[] args[2];
1583 delete[] args[1];
1584 delete[] args[0];
1585
1586 // read V rep file
1587 std::ifstream v_file(extfile.c_str() /*extfilename.c_str()*/, std::ios::in);
1588
1589 if (!v_file.good()) GUM_ERROR(IOError, " __H2Vlrs : could not open lrs ouput file : ")
1590
1591 std::string line, tmp;
1592 char * cstr, *p;
1593 GUM_SCALAR probability;
1594
1595 std::string::size_type pos;
1596 bool keep_going = true;
1597 // int vertices;
1598
1599 std::vector< GUM_SCALAR > vertex;
1600
1601 v_file.ignore(256, 'l');
1602
1603 while (v_file.good() && keep_going) {
1604 getline(v_file, line);
1605
1606 if (line.size() == 0) continue;
1607 else if (line.compare("end") == 0) {
1608 keep_going = false;
1609 // this is to get vertices number :
1610 /*getline ( v_file, line );
1611 std::string::size_type pos, end_pos;
1612 pos = line.find ( "vertices = " );
1613 end_pos = line.find ( "rays", pos + 9 );
1614 vertices = atoi ( line.substr ( pos + 9, end_pos - pos - 9 ).c_str()
1615 );*/
1616 break;
1617 } else if (line[1] != '1') {
1619 " __H2Vlrs : reading something other than a vertex from "
1620 "lrs output file : ");
1621 }
1622
1623 line = line.substr(2);
1624 cstr = new char[line.size() + 1];
1625 strcpy(cstr, line.c_str());
1626
1627 p = strtok(cstr, " ");
1628
1629 while (p != nullptr) {
1630 tmp = p;
1631
1632 if (tmp.compare("1") == 0 || tmp.compare("0") == 0)
1633 probability = GUM_SCALAR(atof(tmp.c_str()));
1634 else {
1635 pos = tmp.find("/");
1636 probability = GUM_SCALAR(atof(tmp.substr(0, pos).c_str())
1637 / atof(tmp.substr(pos + 1, tmp.size()).c_str()));
1638 }
1639
1640 vertex.push_back(probability);
1641 p = strtok(nullptr, " ");
1642 } // end of : for all tokens
1643
1644 delete[] p;
1645 delete[] cstr;
1646
1647 // compute is_redund using multiple threads:
1648 // compute the max number of threads to use (avoid nested threads)
1649 const Size nb_threads = ThreadExecutor::nbRunningThreadsExecutors() == 0
1651 : 1; // no nested multithreading
1652
1653 const auto nsize = v_rep.size();
1654 const auto real_nb_threads = std::min(nb_threads, nsize);
1655
1656 // prepare the data used by the threads
1657 const auto ranges = gum::dispatchRangeToThreads(0, nsize, (unsigned int)(real_nb_threads));
1658 std::vector< Size > t_redund(real_nb_threads); // use Size to avoid false sharing
1659
1660 // create the function to be executed by the threads
1661 auto threadedExec = [this, ranges, &t_redund, vertex, v_rep](const std::size_t this_thread,
1662 const std::size_t nb_threads) {
1663 const auto vsize = vertex.size();
1664 auto& thread_redund = t_redund[this_thread];
1665
1666 for (Idx i = ranges[this_thread].first, end = ranges[this_thread].second; i < end; i++) {
1667 thread_redund = 1;
1668 for (Idx modality = 0; modality < vsize; ++modality) {
1669 if (std::fabs(vertex[modality] - v_rep[i][modality]) > _epsRedund_) {
1670 thread_redund = 0;
1671 break;
1672 }
1673 }
1674
1675 if (thread_redund) return;
1676 }
1677 };
1678
1679 // launch the threads
1680 ThreadExecutor::execute(real_nb_threads, threadedExec);
1681
1682 // aggregate the results
1683 bool is_redund = false;
1684 for (const auto thread_redund: t_redund) {
1685 if (thread_redund) {
1686 is_redund = true;
1687 break;
1688 }
1689 }
1690
1691
1692 /*
1693 // old openMP code:
1694 #pragma omp parallel
1695 {
1696 int this_thread = threadsOMP::getThreadNumber();
1697 int num_threads = threadsOMP::getNumberOfRunningThreads();
1698
1699 auto begin_pos = (this_thread + 0) * v_rep.size() / num_threads;
1700 auto end_pos = (this_thread + 1) * v_rep.size() / num_threads;
1701
1702 for (auto p = begin_pos; p < end_pos; p++) {
1703 #pragma omp flush(is_redund)
1704
1705 if (is_redund) break;
1706
1707 bool thread_redund = true;
1708
1709 auto vsize = vertex.size();
1710
1711 for (Size modality = 0; modality < vsize; modality++) {
1712 if (std::fabs(vertex[modality] - v_rep[p][modality]) > _epsRedund_) {
1713 thread_redund = false;
1714 break;
1715 }
1716 }
1717
1718 if (thread_redund) {
1719 is_redund = true;
1720 #pragma omp flush(is_redund)
1721 int i=0; // this line to work around a weird syntax error with msvc
1722 }
1723 } // end of : each thread for
1724 } // end of : parallel
1725 */
1726
1727 if (!is_redund) v_rep.push_back(vertex);
1728
1729 vertex.clear();
1730
1731 } // end of : file
1732
1733 v_file.close();
1734
1735 if (std::remove(sinefile.c_str()) != 0) GUM_ERROR(IOError, "error removing : " + sinefile)
1736
1737 if (std::remove(extfile.c_str()) != 0) GUM_ERROR(IOError, "error removing : " + extfile)
1738 }
1739
1740 template < typename GUM_SCALAR >
1745
1746 const BayesNet< GUM_SCALAR >* _current_bn_;
1747
1748 if (this->_current_bn_ == nullptr) _current_bn_ = &_src_bn_;
1749 else _current_bn_ = this->_current_bn_;
1750
1751 if (this->_credalNet_current_cpt_ == nullptr) _credalNet_current_cpt_ = &_credalNet_src_cpt_;
1752 else _credalNet_current_cpt_ = this->_credalNet_current_cpt_;
1753
1754 if (this->_current_nodeType_ == nullptr) _current_nodeType_ = &_original_nodeType_;
1755 else _current_nodeType_ = this->_current_nodeType_;
1756
1757 /*if ( ! _current_nodeType_->empty() )
1758 _current_nodeType_->clear();*/
1759
1760 for (auto node: _current_bn_->nodes()) {
1761 // indicatrices are already present
1762 if (_current_nodeType_->exists(node)) continue;
1763
1764 bool precise = true, vacuous = true;
1765
1766 for (auto entry = (*_credalNet_current_cpt_)[node].cbegin(),
1767 theEnd2 = (*_credalNet_current_cpt_)[node].cend();
1768 entry != theEnd2;
1769 ++entry) {
1770 auto vertices = entry->size();
1771 auto var_dSize = (*entry)[0].size();
1772
1773 if (precise && vertices > 1) precise = false;
1774
1775 if (vacuous && vertices == var_dSize) {
1776 std::vector< bool > elem(var_dSize, false);
1777
1778 for (auto vertex = entry->cbegin(), vEnd = entry->cend(); vertex != vEnd; ++vertex) {
1779 for (auto probability = vertex->cbegin(), pEnd = vertex->cend(); probability != pEnd;
1780 ++probability) {
1781 if (*probability == 1) {
1782 elem[probability - vertex->begin()] = true;
1783 break;
1784 }
1785 } // end of : for each modality
1786
1787 break; // not vacuous
1788 } // end of : for each vertex
1789
1790 for (auto /*std::vector< bool >::const_iterator*/ probability = elem.cbegin();
1791 probability != elem.cend();
1792 ++probability)
1793 if (*probability == false) vacuous = false;
1794
1795 } // end of : if vertices == dSize
1796 else
1797 vacuous = false;
1798
1799 if (vacuous == false && precise == false) {
1800 _current_nodeType_->insert(node, NodeType::Credal);
1801 break;
1802 }
1803
1804 } // end of : for each parents entry
1805
1806 if (vacuous) _current_nodeType_->insert(node, NodeType::Vacuous);
1807 else if (precise) _current_nodeType_->insert(node, NodeType::Precise);
1808
1809 } // end of : for each variable
1810 }
1811
1812 } // namespace credal
1813} // namespace gum
Definition of templatized reader of BIF files for Bayesian networks.
Definition BIFReader.h:143
Size proceed()
parse.
Writes a IBayesNet in the BIF format.
Definition BIFWriter.h:79
void write(std::ostream &output, const IBayesNet< GUM_SCALAR > &bn)
Writes a Bayesian network in the output stream.
Exception base for CPT error.
virtual Size domainSize() const =0
Exception : a similar element already exists.
Base class for all aGrUM's exceptions.
Definition exceptions.h:118
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
Exception : input/output problem.
Class for assigning/browsing values to tuples of discrete variables.
const Sequence< const DiscreteVariable * > & variablesSequence() const final
Returns the sequence of DiscreteVariable of this instantiation.
Idx pos(const DiscreteVariable &v) const final
Returns the position of the variable v.
void erase(const DiscreteVariable &v) final
Removes a variable from the Instantiation.
void reorder(const Sequence< const DiscreteVariable * > &v)
Reorder vars of this instantiation giving the order in 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.
const DiscreteVariable & variable(Idx i) const final
Returns the variable at position i in the tuple.
Idx nbrDim() const final
Returns the number of variables in the Instantiation.
bool forgetMaster()
Deassociate the master MultiDimAdressable, if any.
class LabelizedVariable
Exception : operation not allowed.
static void farey(int64_t &numerator, int64_t &denominator, const GUM_SCALAR &number, const int64_t &den_max=1000000L, const GUM_SCALAR &zero=1e-6)
Find the rational close enough to a given ( decimal ) number in [-1,1] and whose denominator is not h...
Exception : problem with size.
void _H2Vlrs_(const std::vector< std::vector< GUM_SCALAR > > &h_rep, std::vector< std::vector< GUM_SCALAR > > &v_rep) const
void _initParams_()
Initialize private constant variables after the Constructor has been called.
GUM_SCALAR _epsilonMoy_
The average perturbation of the BayesNet provided as input for this CredalNet.
Definition credalNet.h:566
void setCPTs(const NodeId &id, const std::vector< std::vector< std::vector< GUM_SCALAR > > > &cpt)
Set the vertices of the credal sets ( all of the conditionals ) of a given node
GUM_SCALAR _deltaC_
5 by default, used by fracC as number of decimals.
Definition credalNet.h:553
BayesNet< GUM_SCALAR > _src_bn_max_
BayesNet used to store upper probabilities.
Definition credalNet.h:596
NodeId addVariable(const std::string &name, const Size &card)
Adds a discrete node into the network.
BayesNet< GUM_SCALAR > * _current_bn_
Up-to-date BayesNet (used as a DAG).
Definition credalNet.h:599
void _intervalToCredal_()
Computes the vertices of each credal set according to their interval definition (does not use lrs).
void saveBNsMinMax(const std::string &min_path, const std::string &max_path) const
If this CredalNet was built over a perturbed BayesNet, one can save the intervals as two BayesNet.
std::string toString() const
bool _hasComputedBinaryCPTMinMax_
Used by L2U, to know if lower and upper probabilities over the second modality has been stored in ord...
Definition credalNet.h:618
Size domainSize(const NodeId &id)
Get the cardinality of a node
NodeProperty< std::vector< std::vector< std::vector< GUM_SCALAR > > > > _credalNet_src_cpt_
This CredalNet original CPTs.
Definition credalNet.h:602
const GUM_SCALAR & epsilonMax() const
void _bnCopy_(BayesNet< GUM_SCALAR > &bn_dest)
bool hasComputedBinaryCPTMinMax() const
GUM_SCALAR _precision_
Precision used by frac.
Definition credalNet.h:583
const NodeProperty< std::vector< std::vector< std::vector< GUM_SCALAR > > > > & credalNet_currentCpt() const
Instantiation instantiation(const NodeId &id)
Get an Instantiation from a node id, usefull to fill the constraints of the network
void bnToCredal(GUM_SCALAR beta, bool oneNet, bool keepZeroes)
Perturbates the BayesNet provided as input for this CredalNet by generating intervals instead of poin...
void intervalToCredal()
Computes the vertices of each credal set according to their interval definition (uses lrs).
const GUM_SCALAR & epsilonMean() const
std::vector< std::vector< GUM_SCALAR > > _binCptMin_
Used with binary networks to speed-up L2U inference.
Definition credalNet.h:625
void approximatedBinarization()
Approximate binarization.
const BayesNet< GUM_SCALAR > & src_bn() const
int _find_dNode_card_(const std::vector< std::vector< std::vector< GUM_SCALAR > > > &var_cpt) const
BayesNet< GUM_SCALAR > _src_bn_
Original BayesNet (used as a DAG).
Definition credalNet.h:591
void computeBinaryCPTMinMax()
Used with binary networks to speed-up L2U inference.
const NodeProperty< std::vector< std::vector< std::vector< GUM_SCALAR > > > > & credalNet_srcCpt() const
NodeType currentNodeType(const NodeId &id) const
NodeProperty< NodeType > _original_nodeType_
The NodeType of each node from the ORIGINAL network.
Definition credalNet.h:612
void lagrangeNormalization()
Normalize counts of a BayesNet storing counts of each events such that no probability is 0.
NodeProperty< std::vector< std::vector< std::vector< GUM_SCALAR > > > > * _credalNet_current_cpt_
This CredalNet up-to-date CPTs.
Definition credalNet.h:606
bool isSeparatelySpecified() const
void _sort_varType_()
Set the NodeType of each node
void _initCNNets_(const std::string &src_min_num, const std::string &src_max_den)
Initialize private BayesNet variables after the Constructor has been called.
void idmLearning(const Idx s=0, const bool keepZeroes=false)
Learns parameters from a BayesNet storing counts of events.
GUM_SCALAR _epsilonMax_
The highest perturbation of the BayesNet provided as input for this CredalNet.
Definition credalNet.h:562
std::vector< std::vector< GUM_SCALAR > > _binCptMax_
Used with binary networks to speed-up L2U inference.
Definition credalNet.h:633
NodeType nodeType(const NodeId &id) const
void setCPT(const NodeId &id, Size &entry, const std::vector< std::vector< GUM_SCALAR > > &cpt)
Set the vertices of one credal set of a given node ( any instantiation index )
bool _separatelySpecified_
TRUE if this CredalNet is separately and interval specified, FALSE otherwise.
Definition credalNet.h:588
NodeProperty< std::vector< NodeId > > _var_bits_
Corresponding bits of each variable.
Definition credalNet.h:609
const std::vector< std::vector< GUM_SCALAR > > & get_binaryCPT_max() const
Used with binary networks to speed-up L2U inference.
BayesNet< GUM_SCALAR > _src_bn_min_
BayesNet used to store lower probabilities.
Definition credalNet.h:594
const BayesNet< GUM_SCALAR > & current_bn() const
void addArc(const NodeId &tail, const NodeId &head)
Adds an arc between two nodes.
const std::vector< std::vector< GUM_SCALAR > > & get_binaryCPT_min() const
Used with binary networks to speed-up L2U inference.
void fillConstraints(const NodeId &id, const std::vector< GUM_SCALAR > &lower, const std::vector< GUM_SCALAR > &upper)
Set the interval constraints of the credal sets of a given node (all instantiations )
GUM_SCALAR _epsilonMin_
The lowest perturbation of the BayesNet provided as input for this CredalNet.
Definition credalNet.h:558
const GUM_SCALAR & epsilonMin() const
NodeProperty< NodeType > * _current_nodeType_
The NodeType of each node from the up-to-date network.
Definition credalNet.h:614
GUM_SCALAR _denMax_
Highest possible denominator allowed when using farey.
Definition credalNet.h:580
void fillConstraint(const NodeId &id, const Idx &entry, const std::vector< GUM_SCALAR > &lower, const std::vector< GUM_SCALAR > &upper)
Set the interval constraints of a credal set of a given node ( from an instantiation index )
GUM_SCALAR _epsRedund_
Value under which a decimal number is considered to be zero when computing redundant vertices.
Definition credalNet.h:571
GUM_SCALAR _precisionC_
1e6 by default, used by fracC as precision.
Definition credalNet.h:551
NodeType
NodeType to speed-up computations in some algorithms.
Definition credalNet.h:100
CredalNet()
Constructor used to create a CredalNet step by step, i.e.
GUM_SCALAR _epsF_
Value under which a decimal number is considered to be zero when using farey.
Definition credalNet.h:576
Class template acting as a wrapper for Lexicographic Reverse Search by David Avis.
Definition LrsWrapper.h:119
const matrix & getOutput() const
Get the output matrix solution of the problem.
void H2V()
H-representation to V-representation.
void fillH(const GUM_SCALAR &min, const GUM_SCALAR &max, const Size &modal)
Creates the H-representation of min <= p(X=modal | .) <= max and add it to the problem input _input_.
void setUpH(const Size &card)
Sets up an H-representation.
void nextHInput()
Reset the wrapper for next computation for a H-representation with the same variable cardinality and ...
Class representing Credal Networks.
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
#define GUM_SHOWERROR(e)
Definition exceptions.h:85
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.
HashTable< NodeId, VAL > NodeProperty
Property on graph elements.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
unsigned long int2Pow(unsigned long exponent)
Specialized base 2 pow function with integer.
Definition pow_inl.h:69
void superiorPow(unsigned long card, unsigned long &num_bits, unsigned long &new_card)
Compute the superior and closest power of two of an integer.
Definition pow_inl.h:75
std::string getUniqueFileName()
Returns a path to a unique file name.
namespace for all credal networks entities
Definition agrum.h:61
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
std::vector< std::pair< Idx, Idx > > dispatchRangeToThreads(Idx beg, Idx end, unsigned int nb_threads)
returns a vector equally splitting elements of a range among threads
Definition threads.cpp:76
unsigned int getNumberOfThreads()
returns the max number of threads used by default when entering the next parallel region
static void execute(std::size_t nb_threads, FUNCTION exec_func, ARGS &&... func_args)
executes a function using several threads
static int nbRunningThreadsExecutors()
indicates how many threadExecutors are currently running
Utilities for manipulating strings.