53#ifndef DOXYGEN_SHOULD_SKIP_THIS
69 template < GUM_Numeric GUM_SCALAR >
73 bool use_binary_join_tree) :
75 _use_binary_join_tree_(use_binary_join_tree) {
77 _findRelevantTensors_ = &LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation2_;
78 setRelevantTensorsFinderType(relevant_type);
79 setFindBarrenNodesType(barren_type);
82 _triangulation_ =
new DefaultTriangulation;
85 GUM_CONSTRUCTOR(LazyPropagation);
89 template < GUM_Numeric GUM_SCALAR >
90 LazyPropagation< GUM_SCALAR >::~LazyPropagation() {
92 for (
const auto& pots: _arc_to_created_tensors_)
93 for (
const auto pot: pots.second)
97 for (
const auto& pots: _clique_tensors_)
98 for (
const auto pot: pots.second)
102 for (
const auto& pot: _target_posteriors_)
104 for (
const auto& pot: _joint_target_posteriors_)
108 if (_JT_ !=
nullptr)
delete _JT_;
109 if (_junctionTree_ !=
nullptr)
delete _junctionTree_;
110 delete _triangulation_;
112 GUM_DESTRUCTOR(LazyPropagation);
116 template < GUM_Numeric GUM_SCALAR >
117 void LazyPropagation< GUM_SCALAR >::setTriangulation(
const Triangulation& new_triangulation) {
118 delete _triangulation_;
119 _triangulation_ = new_triangulation.newFactory();
120 _is_new_jt_needed_ =
true;
121 this->setOutdatedStructureState_();
125 template < GUM_Numeric GUM_SCALAR >
126 const JoinTree* LazyPropagation< GUM_SCALAR >::joinTree() {
127 if (_is_new_jt_needed_) _createNewJT_();
133 template < GUM_Numeric GUM_SCALAR >
134 const JunctionTree* LazyPropagation< GUM_SCALAR >::junctionTree() {
135 if (_is_new_jt_needed_) _createNewJT_();
137 return _junctionTree_;
141 template < GUM_Numeric GUM_SCALAR >
142 void LazyPropagation< GUM_SCALAR >::setRelevantTensorsFinderType(RelevantTensorsFinderType type) {
143 if (type != _find_relevant_tensor_type_) {
145 case RelevantTensorsFinderType::DSEP_BAYESBALL_TENSORS :
146 _findRelevantTensors_
147 = &LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation2_;
150 case RelevantTensorsFinderType::DSEP_BAYESBALL_NODES :
151 _findRelevantTensors_
152 = &LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation_;
155 case RelevantTensorsFinderType::DSEP_KOLLER_FRIEDMAN_2009 :
156 _findRelevantTensors_
157 = &LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation3_;
160 case RelevantTensorsFinderType::FIND_ALL :
161 _findRelevantTensors_ = &LazyPropagation< GUM_SCALAR >::_findRelevantTensorsGetAll_;
166 "setRelevantTensorsFinderType for type " << (
unsigned int)type
167 <<
" is not implemented yet");
170 _find_relevant_tensor_type_ = type;
174 _invalidateAllMessages_();
179 template < GUM_Numeric GUM_SCALAR >
180 void LazyPropagation< GUM_SCALAR >::_setProjectionFunction_(
181 Tensor< GUM_SCALAR > (*proj)(
const Tensor< GUM_SCALAR >&,
const gum::VariableSet&)) {
182 _projection_op_ = proj;
186 _invalidateAllMessages_();
190 template < GUM_Numeric GUM_SCALAR >
191 void LazyPropagation< GUM_SCALAR >::_setCombinationFunction_(
192 Tensor< GUM_SCALAR > (*comb)(
const Tensor< GUM_SCALAR >&,
const Tensor< GUM_SCALAR >&)) {
193 _combination_op_ = comb;
197 _invalidateAllMessages_();
201 template < GUM_Numeric GUM_SCALAR >
202 void LazyPropagation< GUM_SCALAR >::_invalidateAllMessages_() {
204 for (
auto& potset: _separator_tensors_)
205 potset.second.clear();
206 for (
auto& mess_computed: _messages_computed_)
207 mess_computed.second =
false;
210 for (
const auto& potset: _arc_to_created_tensors_)
211 for (
const auto pot: potset.second)
213 _arc_to_created_tensors_.clear();
216 for (
const auto& pot: _target_posteriors_)
218 _target_posteriors_.clear();
219 for (
const auto& pot: _joint_target_posteriors_)
221 _joint_target_posteriors_.clear();
224 if (this->isInferenceReady() || this->isInferenceDone()) this->setOutdatedTensorsState_();
228 template < GUM_Numeric GUM_SCALAR >
229 void LazyPropagation< GUM_SCALAR >::setFindBarrenNodesType(FindBarrenNodesType type) {
230 if (type != _barren_nodes_type_) {
234 case FindBarrenNodesType::FIND_BARREN_NODES :
235 case FindBarrenNodesType::FIND_NO_BARREN_NODES :
break;
239 "setFindBarrenNodesType for type " << (
unsigned int)type
240 <<
" is not implemented yet");
243 _barren_nodes_type_ = type;
246 this->setOutdatedStructureState_();
251 template < GUM_Numeric GUM_SCALAR >
252 void LazyPropagation< GUM_SCALAR >::onEvidenceAdded_(
const NodeId
id,
bool isHardEvidence) {
256 if (isHardEvidence || !_graph_.exists(
id)) _is_new_jt_needed_ =
true;
259 _evidence_changes_.insert(
id, EvidenceChangeType::EVIDENCE_ADDED);
265 _evidence_changes_[id] = EvidenceChangeType::EVIDENCE_MODIFIED;
271 template < GUM_Numeric GUM_SCALAR >
272 void LazyPropagation< GUM_SCALAR >::onEvidenceErased_(
const NodeId
id,
bool isHardEvidence) {
275 if (isHardEvidence) _is_new_jt_needed_ =
true;
278 _evidence_changes_.insert(
id, EvidenceChangeType::EVIDENCE_ERASED);
285 if (_evidence_changes_[
id] == EvidenceChangeType::EVIDENCE_ADDED)
286 _evidence_changes_.erase(
id);
287 else _evidence_changes_[id] = EvidenceChangeType::EVIDENCE_ERASED;
293 template < GUM_Numeric GUM_SCALAR >
294 void LazyPropagation< GUM_SCALAR >::onAllEvidenceErased_(
bool has_hard_evidence) {
295 if (has_hard_evidence || !this->hardEvidenceNodes().empty()) _is_new_jt_needed_ =
true;
297 for (
const auto node: this->softEvidenceNodes()) {
299 _evidence_changes_.insert(node, EvidenceChangeType::EVIDENCE_ERASED);
306 if (_evidence_changes_[node] == EvidenceChangeType::EVIDENCE_ADDED)
307 _evidence_changes_.erase(node);
308 else _evidence_changes_[node] = EvidenceChangeType::EVIDENCE_ERASED;
315 template < GUM_Numeric GUM_SCALAR >
316 void LazyPropagation< GUM_SCALAR >::onEvidenceChanged_(
const NodeId
id,
bool hasChangedSoftHard) {
317 if (hasChangedSoftHard) _is_new_jt_needed_ =
true;
320 _evidence_changes_.insert(
id, EvidenceChangeType::EVIDENCE_MODIFIED);
330 template < GUM_Numeric GUM_SCALAR >
331 void LazyPropagation< GUM_SCALAR >::onModelChanged_(
const GraphicalModel* bn) {}
334 template < GUM_Numeric GUM_SCALAR >
335 void LazyPropagation< GUM_SCALAR >::onMarginalTargetAdded_(
const NodeId
id) {
340 if (!_graph_.exists(
id) && !_hard_ev_nodes_.contains(
id)) { _is_new_jt_needed_ =
true; }
344 template < GUM_Numeric GUM_SCALAR >
345 void LazyPropagation< GUM_SCALAR >::onMarginalTargetErased_(
const NodeId
id) {}
348 template < GUM_Numeric GUM_SCALAR >
349 void LazyPropagation< GUM_SCALAR >::onJointTargetAdded_(
const NodeSet& set) {
351 if (_JT_ ==
nullptr) {
352 _is_new_jt_needed_ =
true;
359 NodeId first_eliminated_node = std::numeric_limits< NodeId >::max();
360 int elim_number = std::numeric_limits< int >::max();
361 const std::vector< NodeId >& JT_elim_order = _triangulation_->eliminationOrder();
362 NodeProperty< int > elim_order(Size(JT_elim_order.size()));
363 for (std::size_t i = std::size_t(0), size = JT_elim_order.size(); i < size; ++i)
364 elim_order.insert(JT_elim_order[i], (
int)i);
365 NodeSet unobserved_set(set.size());
366 for (
const auto node: set) {
367 if (!_graph_.exists(node)) {
368 if (!_hard_ev_nodes_.contains(node)) {
369 _is_new_jt_needed_ =
true;
373 unobserved_set.insert(node);
374 if (elim_order[node] < elim_number) {
375 elim_number = elim_order[node];
376 first_eliminated_node = node;
381 if (!unobserved_set.empty()) {
385 const auto clique_id = _node_to_clique_[first_eliminated_node];
386 const auto& clique = _JT_->clique(clique_id);
387 for (
const auto node: unobserved_set) {
388 if (!clique.contains(node)) {
389 _is_new_jt_needed_ =
true;
397 template < GUM_Numeric GUM_SCALAR >
398 void LazyPropagation< GUM_SCALAR >::onJointTargetErased_(
const NodeSet& set) {}
401 template < GUM_Numeric GUM_SCALAR >
402 void LazyPropagation< GUM_SCALAR >::onAllMarginalTargetsAdded_() {
403 for (
const auto node: this->BN().internalDag()) {
408 if (!_graph_.exists(node) && !_hard_ev_nodes_.contains(node)) {
409 _is_new_jt_needed_ =
true;
416 template < GUM_Numeric GUM_SCALAR >
417 void LazyPropagation< GUM_SCALAR >::onAllMarginalTargetsErased_() {}
420 template < GUM_Numeric GUM_SCALAR >
421 void LazyPropagation< GUM_SCALAR >::onAllJointTargetsErased_() {}
424 template < GUM_Numeric GUM_SCALAR >
425 void LazyPropagation< GUM_SCALAR >::onAllTargetsErased_() {}
428 template < GUM_Numeric GUM_SCALAR >
429 bool LazyPropagation< GUM_SCALAR >::_isNewJTNeeded_()
const {
432 if ((_JT_ ==
nullptr) || _is_new_jt_needed_)
return true;
440 const auto& hard_ev_nodes = this->hardEvidenceNodes();
441 for (
const auto node: this->targets()) {
442 if (!_graph_.exists(node) && !hard_ev_nodes.exists(node))
return true;
446 const std::vector< NodeId >& JT_elim_order = _triangulation_->eliminationOrder();
447 NodeProperty< int > elim_order(Size(JT_elim_order.size()));
448 for (std::size_t i = std::size_t(0), size = JT_elim_order.size(); i < size; ++i)
449 elim_order.insert(JT_elim_order[i], (
int)i);
452 for (
const auto& joint_target: this->jointTargets()) {
455 NodeId first_eliminated_node = std::numeric_limits< NodeId >::max();
456 int elim_number = std::numeric_limits< int >::max();
457 unobserved_set.clear();
458 for (
const auto node: joint_target) {
459 if (!_graph_.exists(node)) {
460 if (!hard_ev_nodes.exists(node))
return true;
462 unobserved_set.insert(node);
463 if (elim_order[node] < elim_number) {
464 elim_number = elim_order[node];
465 first_eliminated_node = node;
469 if (!unobserved_set.empty()) {
473 const auto clique_id = _node_to_clique_[first_eliminated_node];
474 const auto& clique = _JT_->clique(clique_id);
475 for (
const auto node: unobserved_set) {
476 if (!clique.contains(node))
return true;
483 for (
const auto& change: _evidence_changes_) {
484 if ((change.second == EvidenceChangeType::EVIDENCE_ADDED) && !_graph_.exists(change.first))
493 template < GUM_Numeric GUM_SCALAR >
494 void LazyPropagation< GUM_SCALAR >::_createNewJT_() {
510 const auto& bn = this->BN();
512 for (
const auto node: bn.internalDag())
513 _graph_.addNodeWithId(node);
516 NodeSet target_nodes = this->targets();
517 for (
const auto& nodeset: this->jointTargets()) {
518 target_nodes += nodeset;
526 if ((this->nbrTargets() != bn.internalDag().size())
527 && (_barren_nodes_type_ == FindBarrenNodesType::FIND_BARREN_NODES)) {
530 if (target_nodes.size() != bn.size()) {
531 BarrenNodesFinder finder(&bn.internalDag());
532 finder.setTargets(&target_nodes);
534 NodeSet evidence_nodes(this->evidence().size());
535 for (
const auto& pair: this->evidence()) {
536 evidence_nodes.insert(pair.first);
539 finder.setEvidence(&evidence_nodes);
542 NodeSet barren_nodes = finder.barrenNodes();
545 for (
const auto node: barren_nodes) {
546 _graph_.eraseNode(node);
554 if (this->nbrTargets() != bn.internalDag().size()) {
556 bool dsep_analysis =
false;
557 switch (_find_relevant_tensor_type_) {
558 case RelevantTensorsFinderType::DSEP_BAYESBALL_TENSORS :
559 case RelevantTensorsFinderType::DSEP_BAYESBALL_NODES : {
560 BayesBall::requisiteNodes(bn.internalDag(),
562 this->hardEvidenceNodes(),
563 this->softEvidenceNodes(),
565 dsep_analysis =
true;
568 case RelevantTensorsFinderType::DSEP_KOLLER_FRIEDMAN_2009 : {
569 dSeparationAlgorithm dsep;
570 dsep.requisiteNodes(bn.internalDag(),
572 this->hardEvidenceNodes(),
573 this->softEvidenceNodes(),
575 dsep_analysis =
true;
578 case RelevantTensorsFinderType::FIND_ALL :
break;
585 for (
auto iter = _graph_.beginSafe(); iter != _graph_.endSafe(); ++iter) {
586 if (!requisite_nodes.contains(*iter) && !this->hardEvidenceNodes().contains(*iter)) {
587 _graph_.eraseNode(*iter);
594 for (
const auto node: _graph_) {
595 const NodeSet& parents = bn.parents(node);
596 for (
auto iter1 = parents.cbegin(); iter1 != parents.cend(); ++iter1) {
601 if (_graph_.existsNode(*iter1)) {
602 _graph_.addEdge(*iter1, node);
605 for (++iter2; iter2 != parents.cend(); ++iter2) {
610 if (_graph_.existsNode(*iter2)) _graph_.addEdge(*iter1, *iter2);
619 for (
const auto& nodeset: this->jointTargets()) {
620 for (
auto iter1 = nodeset.cbegin(); iter1 != nodeset.cend(); ++iter1) {
622 for (++iter2; iter2 != nodeset.cend(); ++iter2) {
623 _graph_.addEdge(*iter1, *iter2);
629 _hard_ev_nodes_ = this->hardEvidenceNodes();
630 for (
const auto node: _hard_ev_nodes_) {
631 _graph_.eraseNode(node);
638 if (_JT_ !=
nullptr)
delete _JT_;
639 if (_junctionTree_ !=
nullptr)
delete _junctionTree_;
641 _triangulation_->setGraph(&_graph_, &(this->domainSizes()));
642 const JunctionTree& triang_jt = _triangulation_->junctionTree();
643 if (_use_binary_join_tree_) {
644 BinaryJoinTreeConverterDefault bjt_converter;
646 _JT_ =
new CliqueGraph(bjt_converter.convert(triang_jt, this->domainSizes(), emptyset));
648 _JT_ =
new CliqueGraph(triang_jt);
650 _junctionTree_ =
new CliqueGraph(triang_jt);
655 _node_to_clique_.clear();
656 const std::vector< NodeId >& JT_elim_order = _triangulation_->eliminationOrder();
657 NodeProperty< int > elim_order(Size(JT_elim_order.size()));
658 for (std::size_t i = std::size_t(0), size = JT_elim_order.size(); i < size; ++i)
659 elim_order.insert(JT_elim_order[i], (
int)i);
660 const DAG& dag = bn.internalDag();
661 for (
const auto node: _graph_) {
663 NodeId first_eliminated_node = node;
664 int elim_number = elim_order[first_eliminated_node];
666 for (
const auto parent: dag.parents(node)) {
667 if (_graph_.existsNode(parent) && (elim_order[parent] < elim_number)) {
668 elim_number = elim_order[parent];
669 first_eliminated_node = parent;
677 _node_to_clique_.insert(node,
678 _triangulation_->createdJunctionTreeClique(first_eliminated_node));
684 for (
const auto node: _hard_ev_nodes_) {
685 NodeId first_eliminated_node = std::numeric_limits< NodeId >::max();
686 int elim_number = std::numeric_limits< int >::max();
688 for (
const auto parent: dag.parents(node)) {
689 if (_graph_.exists(parent) && (elim_order[parent] < elim_number)) {
690 elim_number = elim_order[parent];
691 first_eliminated_node = parent;
699 if (elim_number != std::numeric_limits< int >::max()) {
700 _node_to_clique_.insert(node,
701 _triangulation_->createdJunctionTreeClique(first_eliminated_node));
705 _joint_target_to_clique_.clear();
706 for (
const auto& set: this->jointTargets()) {
707 NodeId first_eliminated_node = std::numeric_limits< NodeId >::max();
708 int elim_number = std::numeric_limits< int >::max();
712 for (
const auto node: set) {
713 if (!_hard_ev_nodes_.contains(node)) {
716 if (elim_order[node] < elim_number) {
717 elim_number = elim_order[node];
718 first_eliminated_node = node;
723 if (elim_number != std::numeric_limits< int >::max()) {
724 _joint_target_to_clique_.insert(
726 _triangulation_->createdJunctionTreeClique(first_eliminated_node));
731 _computeJoinTreeRoots_();
736 for (
const auto& potlist: _clique_tensors_)
737 for (
const auto pot: potlist.second)
739 _clique_tensors_.clear();
742 for (
const auto& potlist: _arc_to_created_tensors_)
743 for (
const auto pot: potlist.second)
745 _arc_to_created_tensors_.clear();
750 _node_to_hard_ev_projected_CPTs_.clear();
753 _node_to_soft_evidence_.clear();
757 _ScheduleMultiDimSet_ empty_set;
758 for (
const auto node: *_JT_) {
759 _clique_tensors_.insert(node, empty_set);
768 _separator_tensors_.clear();
769 _messages_computed_.clear();
770 for (
const auto& edge: _JT_->edges()) {
771 const Arc arc1(edge.first(), edge.second());
772 _separator_tensors_.insert(arc1, empty_set);
773 _messages_computed_.insert(arc1,
false);
774 const Arc arc2(edge.second(), edge.first());
775 _separator_tensors_.insert(arc2, empty_set);
776 _messages_computed_.insert(arc2,
false);
780 for (
const auto& pot: _target_posteriors_)
782 _target_posteriors_.clear();
783 for (
const auto& pot: _joint_target_posteriors_)
785 _joint_target_posteriors_.clear();
790 double overall_size = 0;
791 for (
const auto clique: *_JT_) {
792 double clique_size = 1.0;
793 for (
const auto node: _JT_->clique(clique))
794 clique_size *= this->domainSizes()[node];
795 overall_size += clique_size;
797 _use_schedules_ = (overall_size > _schedule_threshold_);
803 if (_use_schedules_) {
805 _initializeJTCliques_(schedule);
807 _initializeJTCliques_();
812 const NodeProperty< const Tensor< GUM_SCALAR >* >& evidence = this->evidence();
813 for (
const auto node: this->softEvidenceNodes()) {
814 if (
auto ptr_clique = _node_to_clique_.tryGet(node)) {
815 auto ev_pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(*evidence[node],
false);
816 _node_to_soft_evidence_.insert(node, ev_pot);
817 _clique_tensors_[*ptr_clique].insert(ev_pot);
823 _evidence_changes_.clear();
824 _is_new_jt_needed_ =
false;
828 template < GUM_Numeric GUM_SCALAR >
829 void LazyPropagation< GUM_SCALAR >::_initializeJTCliques_() {
830 const auto& bn = this->BN();
831 const DAG& dag = bn.internalDag();
837 const NodeProperty< const Tensor< GUM_SCALAR >* >& evidence = this->evidence();
838 const NodeProperty< Idx >& hard_evidence = this->hardEvidence();
840 for (
const auto node: dag) {
841 if (_graph_.exists(node) || _hard_ev_nodes_.contains(node)) {
842 const Tensor< GUM_SCALAR >& cpt = bn.cpt(node);
846 const auto& variables = cpt.variablesSequence();
847 bool graph_contains_nodes =
false;
848 for (
const auto var: variables) {
849 NodeId xnode = bn.nodeId(*var);
850 if (_hard_ev_nodes_.contains(xnode)) hard_nodes.insert(xnode);
851 else if (_graph_.exists(xnode)) graph_contains_nodes =
true;
857 if (hard_nodes.empty()) {
858 auto sched_cpt =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(cpt,
false);
859 _clique_tensors_[_node_to_clique_[node]].insert(sched_cpt);
865 if (hard_nodes.size() == variables.size()) {
866 Instantiation inst(cpt);
867 for (Size i = 0; i < hard_nodes.size(); ++i) {
868 inst.chgVal(*variables[i], hard_evidence[bn.nodeId(*(variables[i]))]);
870 _constants_.insert(node, cpt.get(inst));
875 if (!graph_contains_nodes)
continue;
879 _TensorSet_ marg_cpt_set(1 + hard_nodes.size());
880 marg_cpt_set.insert(&cpt);
881 for (
const auto xnode: hard_nodes) {
882 marg_cpt_set.insert(evidence[xnode]);
883 hard_variables.
insert(&(bn.variable(xnode)));
887 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(
891 _TensorSet_ new_cpt_list = combine_and_project.execute(marg_cpt_set, hard_variables);
894 if (new_cpt_list.size() != 1) {
895 for (
const auto pot: new_cpt_list) {
896 if (!marg_cpt_set.contains(pot))
delete pot;
899 "the projection of a tensor containing " <<
"hard evidence is empty!");
901 auto new_pot =
const_cast< Tensor< GUM_SCALAR >*
>(*(new_cpt_list.begin()));
902 auto projected_pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(std::move(*new_pot));
905 _clique_tensors_[_node_to_clique_[node]].insert(projected_pot);
906 _node_to_hard_ev_projected_CPTs_.insert(node, projected_pot);
914 template < GUM_Numeric GUM_SCALAR >
915 void LazyPropagation< GUM_SCALAR >::_initializeJTCliques_(Schedule& schedule) {
916 const auto& bn = this->BN();
917 const DAG& dag = bn.internalDag();
923 const NodeProperty< const Tensor< GUM_SCALAR >* >& evidence = this->evidence();
924 const NodeProperty< Idx >& hard_evidence = this->hardEvidence();
926 for (
const auto node: dag) {
927 if (_graph_.exists(node) || _hard_ev_nodes_.contains(node)) {
928 const Tensor< GUM_SCALAR >& cpt = bn.cpt(node);
932 const auto& variables = cpt.variablesSequence();
933 bool graph_contains_nodes =
false;
934 for (
const auto var: variables) {
935 NodeId xnode = bn.nodeId(*var);
936 if (_hard_ev_nodes_.contains(xnode)) hard_nodes.insert(xnode);
937 else if (_graph_.exists(xnode)) graph_contains_nodes =
true;
943 if (hard_nodes.empty()) {
944 auto sched_cpt =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(cpt,
false);
945 _clique_tensors_[_node_to_clique_[node]].insert(sched_cpt);
951 if (hard_nodes.size() == variables.size()) {
952 Instantiation inst(cpt);
953 for (Size i = 0; i < hard_nodes.size(); ++i) {
954 inst.chgVal(*variables[i], hard_evidence[bn.nodeId(*(variables[i]))]);
956 _constants_.insert(node, cpt.get(inst));
961 if (!graph_contains_nodes)
continue;
965 _ScheduleMultiDimSet_ marg_cpt_set(1 + hard_nodes.size());
966 const IScheduleMultiDim* sched_cpt
967 = schedule.insertTable< Tensor< GUM_SCALAR > >(cpt,
false);
968 marg_cpt_set.insert(sched_cpt);
970 for (
const auto xnode: hard_nodes) {
971 const IScheduleMultiDim* pot
972 = schedule.insertTable< Tensor< GUM_SCALAR > >(*evidence[xnode],
false);
973 marg_cpt_set.insert(pot);
974 hard_variables.
insert(&(bn.variable(xnode)));
978 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(
982 _ScheduleMultiDimSet_ new_cpt_list
983 = combine_and_project.schedule(schedule, marg_cpt_set, hard_variables);
986 if (new_cpt_list.size() != 1) {
988 "the projection of a tensor containing " <<
"hard evidence is empty!");
990 auto projected_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
991 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
992 *new_cpt_list.begin()));
993 const_cast< ScheduleOperator*
>(schedule.scheduleMultiDimCreator(projected_pot))
994 ->makeResultsPersistent(
true);
995 _clique_tensors_[_node_to_clique_[node]].insert(projected_pot);
996 _node_to_hard_ev_projected_CPTs_.insert(node, projected_pot);
1001 this->scheduler().execute(schedule);
1005 template < GUM_Numeric GUM_SCALAR >
1006 void LazyPropagation< GUM_SCALAR >::updateOutdatedStructure_() {
1008 if (_isNewJTNeeded_()) {
1014 updateOutdatedTensors_();
1019 template < GUM_Numeric GUM_SCALAR >
1020 void LazyPropagation< GUM_SCALAR >::_diffuseMessageInvalidations_(NodeId from_id,
1022 NodeSet& invalidated_cliques) {
1024 invalidated_cliques.insert(to_id);
1027 const Arc arc(from_id, to_id);
1028 bool& message_computed = _messages_computed_[arc];
1029 if (message_computed) {
1030 message_computed =
false;
1031 _separator_tensors_[arc].clear();
1032 if (_arc_to_created_tensors_.exists(arc)) {
1033 _ScheduleMultiDimSet_& arc_created_tensors = _arc_to_created_tensors_[arc];
1034 for (
const auto pot: arc_created_tensors)
1036 arc_created_tensors.clear();
1040 for (
const auto node_id: _JT_->neighbours(to_id)) {
1041 if (node_id != from_id) _diffuseMessageInvalidations_(to_id, node_id, invalidated_cliques);
1048 template < GUM_Numeric GUM_SCALAR >
1049 void LazyPropagation< GUM_SCALAR >::updateOutdatedTensors_() {
1059 NodeSet hard_nodes_changed(_hard_ev_nodes_.size());
1060 for (
const auto node: _hard_ev_nodes_)
1061 if (_evidence_changes_.exists(node)) hard_nodes_changed.insert(node);
1063 NodeSet nodes_with_projected_CPTs_changed;
1064 const auto& bn = this->BN();
1065 for (
auto pot_iter = _node_to_hard_ev_projected_CPTs_.beginSafe();
1066 pot_iter != _node_to_hard_ev_projected_CPTs_.endSafe();
1068 for (
const auto var: bn.cpt(pot_iter.key()).variablesSequence()) {
1069 if (hard_nodes_changed.contains(bn.nodeId(*var))) {
1070 nodes_with_projected_CPTs_changed.insert(pot_iter.key());
1071 delete pot_iter.val();
1072 _clique_tensors_[_node_to_clique_[pot_iter.key()]].erase(pot_iter.val());
1073 _node_to_hard_ev_projected_CPTs_.erase(pot_iter);
1087 NodeSet invalidated_cliques(_JT_->size());
1088 for (
const auto& pair: _evidence_changes_) {
1089 if (
auto ptr_clique = _node_to_clique_.tryGet(pair.first)) {
1090 const auto clique = *ptr_clique;
1091 invalidated_cliques.insert(clique);
1092 for (
const auto neighbor: _JT_->neighbours(clique)) {
1093 _diffuseMessageInvalidations_(clique, neighbor, invalidated_cliques);
1100 for (
const auto node: nodes_with_projected_CPTs_changed) {
1101 const auto clique = _node_to_clique_[node];
1102 invalidated_cliques.insert(clique);
1103 for (
const auto neighbor: _JT_->neighbours(clique)) {
1104 _diffuseMessageInvalidations_(clique, neighbor, invalidated_cliques);
1113 for (
auto iter = _target_posteriors_.beginSafe(); iter != _target_posteriors_.endSafe();
1115 if (_graph_.exists(iter.key())
1116 && (invalidated_cliques.exists(_node_to_clique_[iter.key()]))) {
1118 _target_posteriors_.erase(iter);
1123 for (
auto iter = _target_posteriors_.beginSafe(); iter != _target_posteriors_.endSafe();
1125 if (hard_nodes_changed.contains(iter.key())) {
1127 _target_posteriors_.erase(iter);
1133 for (
auto iter = _joint_target_posteriors_.beginSafe();
1134 iter != _joint_target_posteriors_.endSafe();
1136 if (invalidated_cliques.exists(_joint_target_to_clique_[iter.key()])) {
1138 _joint_target_posteriors_.erase(iter);
1141 bool has_unevidenced_node =
false;
1142 for (
const auto node: iter.key()) {
1143 if (!hard_nodes_changed.exists(node)) {
1144 has_unevidenced_node =
true;
1148 if (!has_unevidenced_node) {
1150 _joint_target_posteriors_.erase(iter);
1157 for (
const auto& pot_pair: _node_to_soft_evidence_) {
1158 delete pot_pair.second;
1159 _clique_tensors_[_node_to_clique_[pot_pair.first]].erase(pot_pair.second);
1161 _node_to_soft_evidence_.clear();
1163 const auto& evidence = this->evidence();
1164 for (
const auto node: this->softEvidenceNodes()) {
1165 auto ev_pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(*evidence[node],
false);
1166 _node_to_soft_evidence_.insert(node, ev_pot);
1167 _clique_tensors_[_node_to_clique_[node]].insert(ev_pot);
1177 if (_use_schedules_) {
1179 for (
const auto node: nodes_with_projected_CPTs_changed) {
1181 const Tensor< GUM_SCALAR >& cpt = bn.cpt(node);
1182 const auto& variables = cpt.variablesSequence();
1183 _ScheduleMultiDimSet_ marg_cpt_set;
1184 const auto sched_cpt = schedule.insertTable< Tensor< GUM_SCALAR > >(cpt,
false);
1185 marg_cpt_set.insert(sched_cpt);
1188 for (
const auto var: variables) {
1189 NodeId xnode = bn.nodeId(*var);
1190 if (_hard_ev_nodes_.exists(xnode)) {
1191 const auto pot = schedule.insertTable< Tensor< GUM_SCALAR > >(*evidence[xnode],
false);
1192 marg_cpt_set.insert(pot);
1193 hard_variables.
insert(var);
1198 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(
1202 _ScheduleMultiDimSet_ new_cpt_list
1203 = combine_and_project.schedule(schedule, marg_cpt_set, hard_variables);
1206 if (new_cpt_list.size() != 1) {
1208 "the projection of a tensor containing " <<
"hard evidence is empty!");
1210 auto projected_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
1211 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(*new_cpt_list.begin()));
1212 const_cast< ScheduleOperator*
>(schedule.scheduleMultiDimCreator(projected_pot))
1213 ->makeResultsPersistent(
true);
1214 _clique_tensors_[_node_to_clique_[node]].insert(projected_pot);
1215 _node_to_hard_ev_projected_CPTs_.insert(node, projected_pot);
1217 this->scheduler().execute(schedule);
1219 for (
const auto node: nodes_with_projected_CPTs_changed) {
1221 const Tensor< GUM_SCALAR >& cpt = bn.cpt(node);
1222 const auto& variables = cpt.variablesSequence();
1223 _TensorSet_ marg_cpt_set(1 + variables.size());
1224 marg_cpt_set.insert(&cpt);
1227 for (
const auto var: variables) {
1228 NodeId xnode = bn.nodeId(*var);
1229 if (_hard_ev_nodes_.exists(xnode)) {
1230 marg_cpt_set.insert(evidence[xnode]);
1231 hard_variables.
insert(var);
1236 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(
1240 _TensorSet_ new_cpt_list = combine_and_project.execute(marg_cpt_set, hard_variables);
1243 if (new_cpt_list.size() != 1) {
1245 "the projection of a tensor containing " <<
"hard evidence is empty!");
1247 Tensor< GUM_SCALAR >* sched_pot
1248 =
const_cast< Tensor< GUM_SCALAR >*
>(*new_cpt_list.begin());
1249 auto projected_pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(std::move(*sched_pot));
1251 _clique_tensors_[_node_to_clique_[node]].insert(projected_pot);
1252 _node_to_hard_ev_projected_CPTs_.insert(node, projected_pot);
1258 const auto& hard_evidence = this->hardEvidence();
1259 for (
auto& node_cst: _constants_) {
1260 const Tensor< GUM_SCALAR >& cpt = bn.cpt(node_cst.first);
1261 const auto& variables = cpt.variablesSequence();
1262 Instantiation inst(cpt);
1263 for (
const auto var: variables) {
1264 inst.chgVal(*var, hard_evidence[bn.nodeId(*var)]);
1266 node_cst.second = cpt.get(inst);
1270 _evidence_changes_.clear();
1274 template < GUM_Numeric GUM_SCALAR >
1275 void LazyPropagation< GUM_SCALAR >::_computeJoinTreeRoots_() {
1280 for (
const auto node: this->targets()) {
1281 if (
auto ptr_clique = _node_to_clique_.tryGet(node)) { clique_targets.insert(*ptr_clique); }
1283 for (
const auto& set: this->jointTargets()) {
1284 if (
auto ptr_clique = _joint_target_to_clique_.tryGet(set)) {
1285 clique_targets.insert(*ptr_clique);
1290 std::vector< std::pair< NodeId, Size > > possible_roots(clique_targets.size());
1291 const auto& bn = this->BN();
1293 for (
const auto clique_id: clique_targets) {
1294 const auto& clique = _JT_->clique(clique_id);
1296 for (
const auto node: clique) {
1297 dom_size *= bn.variable(node).domainSize();
1299 possible_roots[i] = std::pair< NodeId, Size >(clique_id, dom_size);
1304 std::sort(possible_roots.begin(),
1305 possible_roots.end(),
1306 [](
const std::pair< NodeId, Size >& a,
const std::pair< NodeId, Size >& b) ->
bool {
1307 return a.second < b.second;
1311 NodeProperty< bool > marked = _JT_->nodesPropertyFromVal(
false);
1312 std::function< void(NodeId, NodeId) > diffuse_marks
1313 = [&marked, &diffuse_marks,
this](NodeId node, NodeId from) {
1314 if (!marked[node]) {
1315 marked[node] =
true;
1316 for (
const auto neigh: _JT_->neighbours(node))
1317 if ((neigh != from) && !marked[neigh]) diffuse_marks(neigh, node);
1321 for (
const auto& xclique: possible_roots) {
1322 NodeId clique = xclique.first;
1323 if (!marked[clique]) {
1324 _roots_.insert(clique);
1325 diffuse_marks(clique, clique);
1331 template < GUM_Numeric GUM_SCALAR >
1332 void LazyPropagation< GUM_SCALAR >::_findRelevantTensorsGetAll_(
1333 Set< const IScheduleMultiDim* >& pot_list,
1337 template < GUM_Numeric GUM_SCALAR >
1338 void LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation_(
1339 Set< const IScheduleMultiDim* >& pot_list,
1343 const auto& bn = this->BN();
1344 for (
const auto var: kept_vars) {
1345 kept_ids.insert(bn.nodeId(*var));
1350 BayesBall::requisiteNodes(bn.internalDag(),
1352 this->hardEvidenceNodes(),
1353 this->softEvidenceNodes(),
1355 for (
auto iter = pot_list.beginSafe(); iter != pot_list.endSafe(); ++iter) {
1356 const Sequence< const DiscreteVariable* >& vars = (*iter)->variablesSequence();
1358 for (
const auto var: vars) {
1359 if (requisite_nodes.exists(bn.nodeId(*var))) {
1365 if (!found) { pot_list.erase(iter); }
1370 template < GUM_Numeric GUM_SCALAR >
1371 void LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation2_(
1372 Set< const IScheduleMultiDim* >& pot_list,
1376 const auto& bn = this->BN();
1377 for (
const auto var: kept_vars) {
1378 kept_ids.insert(bn.nodeId(*var));
1382 BayesBall::relevantTensors(bn,
1384 this->hardEvidenceNodes(),
1385 this->softEvidenceNodes(),
1390 template < GUM_Numeric GUM_SCALAR >
1391 void LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation3_(
1392 Set< const IScheduleMultiDim* >& pot_list,
1396 const auto& bn = this->BN();
1397 for (
const auto var: kept_vars) {
1398 kept_ids.insert(bn.nodeId(*var));
1402 dSeparationAlgorithm dsep;
1403 dsep.relevantTensors(bn,
1405 this->hardEvidenceNodes(),
1406 this->softEvidenceNodes(),
1411 template < GUM_Numeric GUM_SCALAR >
1412 void LazyPropagation< GUM_SCALAR >::_findRelevantTensorsXX_(
1413 Set< const IScheduleMultiDim* >& pot_list,
1415 switch (_find_relevant_tensor_type_) {
1416 case RelevantTensorsFinderType::DSEP_BAYESBALL_TENSORS :
1417 _findRelevantTensorsWithdSeparation2_(pot_list, kept_vars);
1420 case RelevantTensorsFinderType::DSEP_BAYESBALL_NODES :
1421 _findRelevantTensorsWithdSeparation_(pot_list, kept_vars);
1424 case RelevantTensorsFinderType::DSEP_KOLLER_FRIEDMAN_2009 :
1425 _findRelevantTensorsWithdSeparation3_(pot_list, kept_vars);
1428 case RelevantTensorsFinderType::FIND_ALL :
1429 _findRelevantTensorsGetAll_(pot_list, kept_vars);
1437 template < GUM_Numeric GUM_SCALAR >
1438 Set< const IScheduleMultiDim* >
1439 LazyPropagation< GUM_SCALAR >::_removeBarrenVariables_(Schedule& schedule,
1440 _ScheduleMultiDimSet_& pot_list,
1445 for (
auto iter = the_del_vars.
beginSafe(); iter != the_del_vars.
endSafe(); ++iter) {
1446 NodeId
id = this->BN().nodeId(**iter);
1447 if (this->hardEvidenceNodes().exists(
id) || this->softEvidenceNodes().exists(
id)) {
1448 the_del_vars.
erase(iter);
1453 HashTable< const DiscreteVariable*, _ScheduleMultiDimSet_ > var2pots(the_del_vars.
size());
1454 _ScheduleMultiDimSet_ empty_pot_set;
1455 for (
const auto pot: pot_list) {
1456 const auto& vars = pot->variablesSequence();
1457 for (
const auto var: vars) {
1458 if (the_del_vars.
exists(var)) {
1459 if (!var2pots.exists(var)) { var2pots.insert(var, empty_pot_set); }
1460 var2pots[var].insert(pot);
1467 HashTable< const IScheduleMultiDim*, gum::VariableSet > pot2barren_var;
1469 for (
const auto& elt: var2pots) {
1470 if (elt.second.size() == 1) {
1471 const IScheduleMultiDim* pot = *(elt.second.begin());
1472 if (!pot2barren_var.exists(pot)) { pot2barren_var.insert(pot, empty_var_set); }
1473 pot2barren_var[pot].insert(elt.first);
1480 MultiDimProjection< Tensor< GUM_SCALAR > > projector(_projection_op_);
1481 _ScheduleMultiDimSet_ projected_pots;
1482 for (
const auto& elt: pot2barren_var) {
1484 const IScheduleMultiDim* pot = elt.first;
1485 pot_list.erase(pot);
1489 if (pot->variablesSequence().size() != elt.second.size()) {
1490 const IScheduleMultiDim* new_pot = projector.schedule(schedule, pot, elt.second);
1494 pot_list.insert(new_pot);
1495 projected_pots.insert(new_pot);
1499 return projected_pots;
1503 template < GUM_Numeric GUM_SCALAR >
1504 Set< const Tensor< GUM_SCALAR >* >
1505 LazyPropagation< GUM_SCALAR >::_removeBarrenVariables_(_TensorSet_& pot_list,
1510 for (
auto iter = the_del_vars.
beginSafe(); iter != the_del_vars.
endSafe(); ++iter) {
1511 NodeId
id = this->BN().nodeId(**iter);
1512 if (this->hardEvidenceNodes().exists(
id) || this->softEvidenceNodes().exists(
id)) {
1513 the_del_vars.
erase(iter);
1518 HashTable< const DiscreteVariable*, _TensorSet_ > var2pots;
1519 _TensorSet_ empty_pot_set;
1520 for (
const auto pot: pot_list) {
1521 const Sequence< const DiscreteVariable* >& vars = pot->variablesSequence();
1522 for (
const auto var: vars) {
1523 if (the_del_vars.
exists(var)) {
1524 if (!var2pots.exists(var)) { var2pots.insert(var, empty_pot_set); }
1525 var2pots[var].insert(pot);
1534 for (
const auto& elt: var2pots) {
1535 if (elt.second.size() == 1) {
1536 const Tensor< GUM_SCALAR >* pot = *(elt.second.begin());
1537 if (!pot2barren_var.exists(pot)) { pot2barren_var.insert(pot, empty_var_set); }
1538 pot2barren_var[pot].insert(elt.first);
1545 MultiDimProjection< Tensor< GUM_SCALAR > > projector(_projection_op_);
1546 _TensorSet_ projected_pots;
1547 for (
const auto& elt: pot2barren_var) {
1549 const Tensor< GUM_SCALAR >* pot = elt.first;
1550 pot_list.erase(pot);
1554 if (pot->variablesSequence().size() != elt.second.size()) {
1555 const Tensor< GUM_SCALAR >* new_pot = projector.execute(*pot, elt.second);
1556 pot_list.insert(new_pot);
1557 projected_pots.insert(new_pot);
1561 return projected_pots;
1565 template < GUM_Numeric GUM_SCALAR >
1566 void LazyPropagation< GUM_SCALAR >::_collectMessage_(Schedule& schedule, NodeId
id, NodeId from) {
1567 for (
const auto other: _JT_->neighbours(
id)) {
1568 if ((other != from) && !_messages_computed_[
Arc(other,
id)])
1569 _collectMessage_(schedule, other,
id);
1572 if ((
id != from) && !_messages_computed_[
Arc(
id, from)]) {
1573 _produceMessage_(schedule,
id, from);
1578 template < GUM_Numeric GUM_SCALAR >
1579 void LazyPropagation< GUM_SCALAR >::_collectMessage_(NodeId
id, NodeId from) {
1580 for (
const auto other: _JT_->neighbours(
id)) {
1581 if ((other != from) && !_messages_computed_[
Arc(other,
id)]) _collectMessage_(other,
id);
1584 if ((
id != from) && !_messages_computed_[
Arc(
id, from)]) { _produceMessage_(
id, from); }
1588 template < GUM_Numeric GUM_SCALAR >
1589 Set< const IScheduleMultiDim* >
1590 LazyPropagation< GUM_SCALAR >::_marginalizeOut_(Schedule& schedule,
1591 Set< const IScheduleMultiDim* > pot_list,
1598 if (pot_list.empty()) {
return _ScheduleMultiDimSet_(); }
1602 for (
const auto pot: pot_list) {
1603 if (!schedule.existsScheduleMultiDim(pot->id())) schedule.emplaceScheduleMultiDim(*pot);
1608 _ScheduleMultiDimSet_ barren_projected_tensors;
1609 if (_barren_nodes_type_ == FindBarrenNodesType::FIND_BARREN_NODES) {
1610 barren_projected_tensors = _removeBarrenVariables_(schedule, pot_list, del_vars);
1614 _ScheduleMultiDimSet_ new_pot_list;
1615 if (pot_list.size() == 1) {
1616 MultiDimProjection< Tensor< GUM_SCALAR > > projector(_projection_op_);
1617 auto xpot = projector.schedule(schedule, *(pot_list.begin()), del_vars);
1618 new_pot_list.insert(xpot);
1619 }
else if (pot_list.size() > 1) {
1622 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(_combination_op_,
1624 new_pot_list = combine_and_project.schedule(schedule, pot_list, del_vars);
1630 for (
auto barren_pot: barren_projected_tensors) {
1631 if (!new_pot_list.exists(barren_pot))
1632 schedule.emplaceDeletion(
1633 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>& >(*barren_pot));
1636 return new_pot_list;
1640 template < GUM_Numeric GUM_SCALAR >
1641 Set< const IScheduleMultiDim* >
1642 LazyPropagation< GUM_SCALAR >::_marginalizeOut_(Set< const IScheduleMultiDim* >& pot_list,
1646 if (pot_list.empty()) {
return _ScheduleMultiDimSet_(); }
1648 _TensorSet_ xpot_list(pot_list.size());
1649 for (
auto pot: pot_list)
1651 &(
static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(pot)->multiDim()));
1658 _TensorSet_ barren_projected_tensors;
1659 if (_barren_nodes_type_ == FindBarrenNodesType::FIND_BARREN_NODES) {
1660 barren_projected_tensors = _removeBarrenVariables_(xpot_list, del_vars);
1664 _TensorSet_ xnew_pot_list;
1665 _ScheduleMultiDimSet_ new_pot_list;
1666 if (xpot_list.size() == 1) {
1667 MultiDimProjection< Tensor< GUM_SCALAR > > projector(_projection_op_);
1668 auto xpot = projector.execute(**(xpot_list.begin()), del_vars);
1669 ScheduleMultiDim< Tensor< GUM_SCALAR > >* pot;
1670 if (xpot_list.contains(xpot))
1671 pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(*xpot,
false);
1673 pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(
1674 std::move(
const_cast< Tensor< GUM_SCALAR >&
>(*xpot)));
1677 new_pot_list.insert(pot);
1678 }
else if (xpot_list.size() > 1) {
1681 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(_combination_op_,
1683 xnew_pot_list = combine_and_project.execute(xpot_list, del_vars);
1685 for (
auto xpot: xnew_pot_list) {
1686 ScheduleMultiDim< Tensor< GUM_SCALAR > >* pot;
1687 if (xpot_list.contains(xpot))
1688 pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(*xpot,
false);
1690 pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(
1691 std::move(
const_cast< Tensor< GUM_SCALAR >&
>(*xpot)));
1694 new_pot_list.insert(pot);
1701 for (
const auto barren_pot: barren_projected_tensors) {
1702 if (!xnew_pot_list.exists(barren_pot))
delete barren_pot;
1705 return new_pot_list;
1709 template < GUM_Numeric GUM_SCALAR >
1710 void LazyPropagation< GUM_SCALAR >::_produceMessage_(Schedule& schedule,
1714 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[from_id];
1717 for (
const auto other_id: _JT_->neighbours(from_id)) {
1718 if (other_id != to_id) pot_list += _separator_tensors_[
Arc(other_id, from_id)];
1722 const NodeSet& from_clique = _JT_->clique(from_id);
1723 const NodeSet& separator = _JT_->separator(from_id, to_id);
1726 const auto& bn = this->BN();
1728 for (
const auto node: from_clique) {
1729 if (!separator.contains(node)) {
1730 del_vars.
insert(&(bn.variable(node)));
1732 kept_vars.
insert(&(bn.variable(node)));
1738 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(schedule, pot_list, del_vars, kept_vars);
1745 const Arc arc(from_id, to_id);
1747 if (!_arc_to_created_tensors_.exists(arc))
1748 _arc_to_created_tensors_.insert(arc, _ScheduleMultiDimSet_());
1750 for (
auto iter = new_pot_list.beginSafe(); iter != new_pot_list.endSafe(); ++iter) {
1751 const auto pot = *iter;
1753 if (!pot_list.exists(pot)) {
1754 _arc_to_created_tensors_[arc].insert(pot);
1757 auto op = schedule.scheduleMultiDimCreator(pot);
1758 if (op !=
nullptr)
const_cast< ScheduleOperator*
>(op)->makeResultsPersistent(
true);
1762 _separator_tensors_[arc] = std::move(new_pot_list);
1763 _messages_computed_[arc] =
true;
1767 template < GUM_Numeric GUM_SCALAR >
1768 void LazyPropagation< GUM_SCALAR >::_produceMessage_(NodeId from_id, NodeId to_id) {
1770 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[from_id];
1773 for (
const auto other_id: _JT_->neighbours(from_id)) {
1774 if (other_id != to_id) pot_list += _separator_tensors_[
Arc(other_id, from_id)];
1778 const NodeSet& from_clique = _JT_->clique(from_id);
1779 const NodeSet& separator = _JT_->separator(from_id, to_id);
1782 const auto& bn = this->BN();
1784 for (
const auto node: from_clique) {
1785 if (!separator.contains(node)) {
1786 del_vars.
insert(&(bn.variable(node)));
1788 kept_vars.
insert(&(bn.variable(node)));
1794 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(pot_list, del_vars, kept_vars);
1801 const Arc arc(from_id, to_id);
1803 if (!_arc_to_created_tensors_.exists(arc))
1804 _arc_to_created_tensors_.insert(arc, _ScheduleMultiDimSet_());
1806 for (
const auto pot: new_pot_list) {
1807 if (!pot_list.exists(pot)) { _arc_to_created_tensors_[arc].insert(pot); }
1810 _separator_tensors_[arc] = std::move(new_pot_list);
1811 _messages_computed_[arc] =
true;
1815 template < GUM_Numeric GUM_SCALAR >
1816 void LazyPropagation< GUM_SCALAR >::makeInference_() {
1817 if (_use_schedules_) {
1821 for (
const auto node: this->targets()) {
1825 if (_graph_.exists(node)) {
1826 _collectMessage_(schedule, _node_to_clique_[node], _node_to_clique_[node]);
1834 for (
const auto& set: _joint_target_to_clique_)
1835 _collectMessage_(schedule, set.second, set.second);
1838 this->scheduler().execute(schedule);
1841 for (
const auto node: this->targets()) {
1845 if (_graph_.exists(node)) {
1846 _collectMessage_(_node_to_clique_[node], _node_to_clique_[node]);
1854 for (
const auto& set: _joint_target_to_clique_)
1855 _collectMessage_(set.second, set.second);
1860 template < GUM_Numeric GUM_SCALAR >
1861 Tensor< GUM_SCALAR >* LazyPropagation< GUM_SCALAR >::unnormalizedJointPosterior_(NodeId
id) {
1862 if (_use_schedules_) {
1864 return _unnormalizedJointPosterior_(schedule,
id);
1866 return _unnormalizedJointPosterior_(
id);
1871 template < GUM_Numeric GUM_SCALAR >
1872 Tensor< GUM_SCALAR >*
1873 LazyPropagation< GUM_SCALAR >::_unnormalizedJointPosterior_(Schedule& schedule, NodeId
id) {
1874 const auto& bn = this->BN();
1878 if (this->hardEvidenceNodes().
contains(
id)) {
1879 return new Tensor< GUM_SCALAR >(*(this->evidence()[
id]));
1882 auto& scheduler = this->scheduler();
1886 const NodeId clique_of_id = _node_to_clique_[id];
1887 _collectMessage_(schedule, clique_of_id, clique_of_id);
1892 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[clique_of_id];
1895 for (
const auto other: _JT_->neighbours(clique_of_id))
1896 pot_list += _separator_tensors_[
Arc(other, clique_of_id)];
1899 const NodeSet& nodes = _JT_->clique(clique_of_id);
1902 for (
const auto node: nodes) {
1903 if (node !=
id) del_vars.
insert(&(bn.variable(node)));
1908 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(schedule, pot_list, del_vars, kept_vars);
1909 Tensor< GUM_SCALAR >* joint =
nullptr;
1910 ScheduleMultiDim< Tensor< GUM_SCALAR > >* resulting_pot =
nullptr;
1912 if (new_pot_list.size() == 0) {
1913 joint =
new Tensor< GUM_SCALAR >;
1914 for (
const auto var: kept_vars)
1917 if (new_pot_list.size() == 1) {
1918 scheduler.execute(schedule);
1919 resulting_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
1920 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(*new_pot_list.begin()));
1922 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
1923 const IScheduleMultiDim* pot = fast_combination.schedule(schedule, new_pot_list);
1924 scheduler.execute(schedule);
1925 resulting_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
1926 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(pot));
1931 if (pot_list.exists(resulting_pot)) {
1932 joint =
new Tensor< GUM_SCALAR >(resulting_pot->multiDim());
1934 joint = resulting_pot->exportMultiDim();
1941 bool nonzero_found =
false;
1942 for (Instantiation inst(*joint); !inst.end(); ++inst) {
1943 if (joint->get(inst)) {
1944 nonzero_found =
true;
1948 if (!nonzero_found) {
1952 "some evidence entered into the Bayes "
1953 "net are incompatible (their joint proba = 0)");
1959 template < GUM_Numeric GUM_SCALAR >
1960 Tensor< GUM_SCALAR >* LazyPropagation< GUM_SCALAR >::_unnormalizedJointPosterior_(NodeId
id) {
1961 const auto& bn = this->BN();
1965 if (this->hardEvidenceNodes().
contains(
id)) {
1966 return new Tensor< GUM_SCALAR >(*(this->evidence()[
id]));
1971 NodeId clique_of_id = _node_to_clique_[id];
1972 _collectMessage_(clique_of_id, clique_of_id);
1977 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[clique_of_id];
1980 for (
const auto other: _JT_->neighbours(clique_of_id))
1981 pot_list += _separator_tensors_[
Arc(other, clique_of_id)];
1984 const NodeSet& nodes = _JT_->clique(clique_of_id);
1987 for (
const auto node: nodes) {
1988 if (node !=
id) del_vars.
insert(&(bn.variable(node)));
1993 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(pot_list, del_vars, kept_vars);
1994 Tensor< GUM_SCALAR >* joint =
nullptr;
1996 if (new_pot_list.size() == 0) {
1997 joint =
new Tensor< GUM_SCALAR >;
1998 for (
const auto var: kept_vars)
2000 }
else if (new_pot_list.size() == 1) {
2001 auto sched_joint =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
2002 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(*(new_pot_list.begin())));
2006 if (pot_list.exists(sched_joint)) {
2007 joint =
new Tensor< GUM_SCALAR >(sched_joint->multiDim());
2009 joint = sched_joint->exportMultiDim();
2014 new_pot_list.clear();
2017 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
2020 _TensorSet_ xnew_pot_list(new_pot_list.size());
2021 for (
auto xpot: new_pot_list) {
2022 xnew_pot_list.insert(
2023 &(
static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(xpot)->multiDim()));
2026 joint = fast_combination.execute(xnew_pot_list);
2032 for (
const auto pot: new_pot_list)
2033 if (!pot_list.exists(pot))
delete pot;
2038 bool nonzero_found =
false;
2039 for (Instantiation inst(*joint); !inst.end(); ++inst) {
2040 if (joint->get(inst)) {
2041 nonzero_found =
true;
2045 if (!nonzero_found) {
2049 "some evidence entered into the Bayes "
2050 "net are incompatible (their joint proba = 0)");
2056 template < GUM_Numeric GUM_SCALAR >
2057 const Tensor< GUM_SCALAR >& LazyPropagation< GUM_SCALAR >::posterior_(NodeId
id) {
2059 if (
auto p = _target_posteriors_.tryGet(
id)) {
return *(*p); }
2062 auto joint = unnormalizedJointPosterior_(
id);
2063 if (joint->sum() != 1)
2065 _target_posteriors_.insert(
id, joint);
2071 template < GUM_Numeric GUM_SCALAR >
2072 Tensor< GUM_SCALAR >*
2073 LazyPropagation< GUM_SCALAR >::unnormalizedJointPosterior_(
const NodeSet& set) {
2074 if (_use_schedules_) {
2076 return _unnormalizedJointPosterior_(schedule, set);
2078 return _unnormalizedJointPosterior_(set);
2083 template < GUM_Numeric GUM_SCALAR >
2084 Tensor< GUM_SCALAR >*
2085 LazyPropagation< GUM_SCALAR >::_unnormalizedJointPosterior_(Schedule& schedule,
2086 const NodeSet& set) {
2089 NodeSet targets = set, hard_ev_nodes;
2090 for (
const auto node: this->hardEvidenceNodes()) {
2091 if (targets.contains(node)) {
2092 targets.erase(node);
2093 hard_ev_nodes.insert(node);
2097 auto& scheduler = this->scheduler();
2101 const auto& evidence = this->evidence();
2102 if (targets.empty()) {
2103 if (set.size() == 1) {
2104 return new Tensor< GUM_SCALAR >(*evidence[*set.begin()]);
2106 _ScheduleMultiDimSet_ pot_list;
2107 for (
const auto node: set) {
2108 auto new_pot_ev = schedule.insertTable< Tensor< GUM_SCALAR > >(*evidence[node],
false);
2109 pot_list.insert(new_pot_ev);
2113 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
2114 const IScheduleMultiDim* pot = fast_combination.schedule(schedule, pot_list);
2115 auto schedule_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
2116 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(pot));
2117 scheduler.execute(schedule);
2118 auto result = schedule_pot->exportMultiDim();
2128 NodeId clique_of_set;
2129 if (
auto p_clique = _joint_target_to_clique_.tryGet(set)) {
2130 clique_of_set = *p_clique;
2137 for (
const auto node: targets) {
2138 if (!_graph_.exists(node)) {
2140 "The variable " << this->BN().variable(node).name() <<
"(" << node
2141 <<
") does not belong to this optimized inference.")
2147 const std::vector< NodeId >& JT_elim_order = _triangulation_->eliminationOrder();
2149 NodeProperty< int > elim_order(Size(JT_elim_order.size()));
2150 for (std::size_t i = std::size_t(0), size = JT_elim_order.size(); i < size; ++i)
2151 elim_order.insert(JT_elim_order[i], (
int)i);
2152 NodeId first_eliminated_node = *(targets.begin());
2153 int elim_number = elim_order[first_eliminated_node];
2154 for (
const auto node: targets) {
2155 if (elim_order[node] < elim_number) {
2156 elim_number = elim_order[node];
2157 first_eliminated_node = node;
2161 clique_of_set = _triangulation_->createdJunctionTreeClique(first_eliminated_node);
2165 const NodeSet& clique_nodes = _JT_->clique(clique_of_set);
2166 for (
const auto node: targets) {
2167 if (!clique_nodes.contains(node)) {
2169 this->BN().names(set) <<
"(" << set <<
")"
2170 <<
" is not addressable in this optimized inference.")
2175 _joint_target_to_clique_.
insert(set, clique_of_set);
2179 _collectMessage_(schedule, clique_of_set, clique_of_set);
2184 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[clique_of_set];
2187 for (
const auto other: _JT_->neighbours(clique_of_set))
2188 pot_list += _separator_tensors_[
Arc(other, clique_of_set)];
2191 const NodeSet& nodes = _JT_->clique(clique_of_set);
2194 const auto& bn = this->BN();
2195 for (
const auto node: nodes) {
2196 if (!targets.contains(node)) {
2197 del_vars.
insert(&(bn.variable(node)));
2199 kept_vars.
insert(&(bn.variable(node)));
2205 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(schedule, pot_list, del_vars, kept_vars);
2206 ScheduleMultiDim< Tensor< GUM_SCALAR > >* resulting_pot =
nullptr;
2207 Tensor< GUM_SCALAR >* joint =
nullptr;
2209 if (new_pot_list.size() == 0) {
2210 joint =
new Tensor< GUM_SCALAR >();
2211 for (
const auto var: kept_vars)
2214 if ((new_pot_list.size() == 1) && hard_ev_nodes.empty()) {
2215 scheduler.execute(schedule);
2216 resulting_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
2217 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(*new_pot_list.begin()));
2221 for (
const auto node: hard_ev_nodes) {
2222 auto new_pot_ev = schedule.insertTable< Tensor< GUM_SCALAR > >(*evidence[node],
false);
2223 new_pot_list.insert(new_pot_ev);
2225 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
2226 const auto pot = fast_combination.schedule(schedule, new_pot_list);
2227 scheduler.execute(schedule);
2228 resulting_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
2229 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(pot));
2234 if (pot_list.exists(resulting_pot)) {
2235 joint =
new Tensor< GUM_SCALAR >(resulting_pot->multiDim());
2237 joint = resulting_pot->exportMultiDim();
2244 bool nonzero_found =
false;
2245 for (Instantiation inst(*joint); !inst.end(); ++inst) {
2246 if ((*joint)[inst]) {
2247 nonzero_found =
true;
2251 if (!nonzero_found) {
2255 "some evidence entered into the Bayes "
2256 "net are incompatible (their joint proba = 0)");
2263 template < GUM_Numeric GUM_SCALAR >
2264 Tensor< GUM_SCALAR >*
2265 LazyPropagation< GUM_SCALAR >::_unnormalizedJointPosterior_(
const NodeSet& set) {
2270 for (
const auto node: this->hardEvidenceNodes()) {
2271 if (targets.contains(node)) {
2272 targets.erase(node);
2273 hard_ev_nodes.insert(node);
2279 const auto& evidence = this->evidence();
2280 if (targets.empty()) {
2281 if (set.size() == 1) {
2282 return new Tensor< GUM_SCALAR >(*evidence[*set.begin()]);
2284 _TensorSet_ pot_list;
2285 for (
const auto node: set) {
2286 pot_list.insert(evidence[node]);
2290 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
2291 const Tensor< GUM_SCALAR >* pot = fast_combination.execute(pot_list);
2293 return const_cast< Tensor< GUM_SCALAR >*
>(pot);
2301 NodeId clique_of_set;
2302 if (
auto p_clique = _joint_target_to_clique_.tryGet(set)) {
2303 clique_of_set = *p_clique;
2310 for (
const auto node: targets) {
2311 if (!_graph_.exists(node)) {
2313 "The variable " << this->BN().variable(node).name() <<
"(" << node
2314 <<
") does not belong to this optimized inference.")
2320 const std::vector< NodeId >& JT_elim_order = _triangulation_->eliminationOrder();
2322 NodeProperty< int > elim_order(Size(JT_elim_order.size()));
2323 for (std::size_t i = std::size_t(0), size = JT_elim_order.size(); i < size; ++i)
2324 elim_order.insert(JT_elim_order[i], (
int)i);
2325 NodeId first_eliminated_node = *(targets.begin());
2326 int elim_number = elim_order[first_eliminated_node];
2327 for (
const auto node: targets) {
2328 if (elim_order[node] < elim_number) {
2329 elim_number = elim_order[node];
2330 first_eliminated_node = node;
2334 clique_of_set = _triangulation_->createdJunctionTreeClique(first_eliminated_node);
2338 const NodeSet& clique_nodes = _JT_->clique(clique_of_set);
2339 for (
const auto node: targets) {
2340 if (!clique_nodes.contains(node)) {
2342 this->BN().names(set) <<
"(" << set <<
")"
2343 <<
" is not addressable in this optimized inference.")
2348 _joint_target_to_clique_.
insert(set, clique_of_set);
2352 _collectMessage_(clique_of_set, clique_of_set);
2357 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[clique_of_set];
2360 for (
const auto other: _JT_->neighbours(clique_of_set))
2361 pot_list += _separator_tensors_[
Arc(other, clique_of_set)];
2364 const NodeSet& nodes = _JT_->clique(clique_of_set);
2367 const auto& bn = this->BN();
2368 for (
const auto node: nodes) {
2369 if (!targets.contains(node)) {
2370 del_vars.
insert(&(bn.variable(node)));
2372 kept_vars.
insert(&(bn.variable(node)));
2378 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(pot_list, del_vars, kept_vars);
2379 Tensor< GUM_SCALAR >* joint =
nullptr;
2380 if (new_pot_list.empty()) {
2381 joint =
new Tensor< GUM_SCALAR >();
2382 for (
const auto var: kept_vars)
2385 if ((new_pot_list.size() == 1) && hard_ev_nodes.empty()) {
2386 auto sched_joint =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
2387 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(*new_pot_list.begin()));
2391 if (pot_list.exists(sched_joint)) {
2392 joint =
new Tensor< GUM_SCALAR >(sched_joint->multiDim());
2394 joint = sched_joint->exportMultiDim();
2399 new_pot_list.clear();
2404 _TensorSet_ xnew_pot_list(new_pot_list.size());
2405 for (
auto xpot: new_pot_list) {
2406 xnew_pot_list.insert(
2407 &(
static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(xpot)->multiDim()));
2409 for (
const auto node: hard_ev_nodes) {
2410 xnew_pot_list.insert(evidence[node]);
2412 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
2413 joint = fast_combination.execute(xnew_pot_list);
2420 for (
const auto pot: new_pot_list)
2421 if (!pot_list.exists(pot))
delete pot;
2425 bool nonzero_found =
false;
2426 for (Instantiation inst(*joint); !inst.end(); ++inst) {
2427 if ((*joint)[inst]) {
2428 nonzero_found =
true;
2432 if (!nonzero_found) {
2436 "some evidence entered into the Bayes "
2437 "net are incompatible (their joint proba = 0)");
2444 template < GUM_Numeric GUM_SCALAR >
2445 const Tensor< GUM_SCALAR >& LazyPropagation< GUM_SCALAR >::jointPosterior_(
const NodeSet& set) {
2447 if (
auto p = _joint_target_posteriors_.tryGet(set)) {
return *(*p); }
2450 auto joint = unnormalizedJointPosterior_(set);
2452 _joint_target_posteriors_.insert(set, joint);
2458 template < GUM_Numeric GUM_SCALAR >
2459 const Tensor< GUM_SCALAR >&
2460 LazyPropagation< GUM_SCALAR >::jointPosterior_(
const NodeSet& wanted_target,
2461 const NodeSet& declared_target) {
2463 if (
auto p = _joint_target_posteriors_.tryGet(wanted_target))
return *(*p);
2469 if (!_joint_target_posteriors_.exists(declared_target)) { jointPosterior_(declared_target); }
2472 const auto& bn = this->BN();
2474 for (
const auto node: declared_target)
2475 if (!wanted_target.contains(node)) del_vars.
insert(&(bn.variable(node)));
2477 =
new Tensor< GUM_SCALAR >(_joint_target_posteriors_[declared_target]->sumOut(del_vars));
2480 _joint_target_posteriors_.insert(wanted_target, pot);
2485 template < GUM_Numeric GUM_SCALAR >
2486 GUM_SCALAR LazyPropagation< GUM_SCALAR >::evidenceProbability() {
2489 RelevantTensorsFinderType old_relevant_type = _find_relevant_tensor_type_;
2494 if (old_relevant_type != RelevantTensorsFinderType::FIND_ALL) {
2495 _find_relevant_tensor_type_ = RelevantTensorsFinderType::FIND_ALL;
2496 _is_new_jt_needed_ =
true;
2497 this->setOutdatedStructureState_();
2501 this->makeInference();
2509 GUM_SCALAR prob_ev = 1;
2510 for (
const auto root: _roots_) {
2512 NodeId node = *(_JT_->clique(root).begin());
2513 Tensor< GUM_SCALAR >* tmp = unnormalizedJointPosterior_(node);
2514 prob_ev *= tmp->sum();
2518 for (
const auto& projected_cpt: _constants_)
2519 prob_ev *= projected_cpt.second;
2522 _find_relevant_tensor_type_ = old_relevant_type;
2527 template < GUM_Numeric GUM_SCALAR >
2528 Instantiation LazyPropagation< GUM_SCALAR >::mpe() {
2531 RelevantTensorsFinderType old_relevant_type = _find_relevant_tensor_type_;
2536 if (old_relevant_type != RelevantTensorsFinderType::FIND_ALL) {
2537 _find_relevant_tensor_type_ = RelevantTensorsFinderType::FIND_ALL;
2538 _is_new_jt_needed_ =
true;
2539 this->setOutdatedStructureState_();
2543 auto old_projection_op = _projection_op_;
2544 auto new_projection_op = LPMaxprojTensor< GUM_SCALAR >;
2545 bool projection_op_changed = old_projection_op != new_projection_op;
2546 if (projection_op_changed) { this->_setProjectionFunction_(new_projection_op); }
2549 const auto in_target_mode = this->isInTargetMode();
2551 Set< NodeSet > old_joint_targets;
2552 if (in_target_mode) {
2553 old_targets = this->targets();
2554 old_joint_targets = this->jointTargets();
2555 this->eraseAllTargets();
2559 this->makeInference();
2562 Instantiation instantiations;
2563 for (
const auto& ev: this->hardEvidence()) {
2564 const auto& variable = this->BN().variable(ev.first);
2565 instantiations.add(variable);
2566 instantiations.chgVal(variable, ev.second);
2570 NodeProperty< bool > clique2marked = _JT_->nodesPropertyFromVal(
false);
2571 std::function< void(NodeId, NodeId) > diffuse_marks =
2572 [&clique2marked, &diffuse_marks, &instantiations,
this](NodeId clique, NodeId clique_from) {
2573 clique2marked[clique] =
true;
2578 auto clique_nodes = _JT_->clique(clique);
2579 auto pot = unnormalizedJointPosterior_(clique_nodes);
2580 auto pot_argmax = pot->extract(instantiations).argmax();
2582 const auto& new_instantiation = *(pot_argmax.first.begin());
2585 for (
const auto node: clique_nodes) {
2586 const auto& variable = this->BN().variable(node);
2587 if (!instantiations.contains(variable)) {
2588 instantiations.add(variable);
2589 instantiations.chgVal(variable, new_instantiation.val(variable));
2594 for (
const auto neigh: _JT_->neighbours(clique))
2595 if ((neigh != clique_from) && !clique2marked[neigh]) diffuse_marks(neigh, clique);
2600 for (
const auto& cliqueProp: clique2marked) {
2601 const auto clique = cliqueProp.first;
2602 if (!clique2marked[clique]) diffuse_marks(clique, clique);
2607 _find_relevant_tensor_type_ = old_relevant_type;
2610 if (projection_op_changed) { this->_setProjectionFunction_(old_projection_op); }
2613 if (in_target_mode) {
2614 for (
const auto node: old_targets) {
2615 this->addTarget(node);
2617 for (
const auto& set: old_joint_targets) {
2618 this->addJointTarget(set);
2623 return instantiations;
2626 template < GUM_Numeric GUM_SCALAR >
2627 std::pair< Instantiation, GUM_SCALAR > LazyPropagation< GUM_SCALAR >::mpeLog2Posterior() {
2629 const auto instantiation = mpe();
2638 auto proba = (GUM_SCALAR)0.0;
2639 auto node_proba = (GUM_SCALAR)0.0;
2641 for (
const auto node: this->BN().internalDag()) {
2642 const auto& cpt = this->BN().cpt(node);
2643 if (!this->hasSoftEvidence(node)) {
2644 node_proba = cpt[instantiation];
2646 const auto& ev = *(this->evidence()[node]);
2647 node_proba = cpt[instantiation] * ev[instantiation];
2650 if (node_proba == (GUM_SCALAR)0)
2651 return {instantiation, std::numeric_limits< GUM_SCALAR >::lowest()};
2652 proba += (GUM_SCALAR)std::log2(node_proba);
2655 if (!this->hasEvidence())
return {instantiation, proba};
2656 else return {instantiation, proba - std::log2(this->evidenceProbability())};
2659 template < GUM_Numeric GUM_SCALAR >
2660 Tensor< GUM_SCALAR > LPNewmultiTensor(
const Tensor< GUM_SCALAR >& t1,
2661 const Tensor< GUM_SCALAR >& t2) {
2665 template < GUM_Numeric GUM_SCALAR >
2666 Tensor< GUM_SCALAR > LPNewprojTensor(
const Tensor< GUM_SCALAR >& t1,
2668 return t1.sumOut(del_vars);
2671 template < GUM_Numeric GUM_SCALAR >
2672 Tensor< GUM_SCALAR > LPMaxprojTensor(
const Tensor< GUM_SCALAR >& t1,
2674 return t1.maxOut(del_vars);
2677 template < GUM_Numeric GUM_SCALAR >
2678 void LazyPropagation< GUM_SCALAR >::onStateChanged_() {}
The BayesBall algorithm (as described by Schachter).
Detect barren nodes for inference in Bayesian networks.
An algorithm for converting a join tree into a binary join tree.
Exception : a similar element already exists.
<agrum/BN/inference/evidenceInference.h>
Exception : fatal (unknown ?) error.
Class representing the minimal interface for Bayesian network with no numerical data.
Exception : several evidence are incompatible together (proba=0).
Exception: at least one argument passed to a function is not what was expected.
<agrum/BN/inference/jointTargetedInference.h>
LazyPropagation(const IBayesNet< GUM_SCALAR > *BN, RelevantTensorsFinderType=RelevantTensorsFinderType::DSEP_BAYESBALL_TENSORS, FindBarrenNodesType=FindBarrenNodesType::FIND_BARREN_NODES, bool use_binary_join_tree=true)
default constructor
bool exists(const Key &k) const
Indicates whether a given elements belong to the set.
void insert(const Key &k)
Inserts a new element into the set.
iterator_safe beginSafe() const
The usual safe begin iterator to parse the set.
void erase(const Key &k)
Erases an element from the set.
Size size() const noexcept
Returns the number of elements in the set.
static const iterator_safe & endSafe() noexcept
The usual safe end iterator to parse the set.
Exception : a looked-for element could not be found.
d-separation analysis (as described in Koller & Friedman 2009)
#define GUM_ERROR(type, msg)
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
bool contains(std::string_view s, std::string_view needle)
true if needle in s
Header files of gum::Instantiation.
Implementation of a Shafer-Shenoy's-like version of lazy propagation for inference in Bayesian networ...
gum is the global namespace for all aGrUM entities
FindBarrenNodesType
type of algorithm to determine barren nodes
Set< const DiscreteVariable * > VariableSet
CliqueGraph JoinTree
a join tree is a clique graph satisfying the running intersection property (but some cliques may be i...
CliqueGraph JunctionTree
a junction tree is a clique graph satisfying the running intersection property and such that no cliqu...
RelevantTensorsFinderType
type of algorithm for determining the relevant tensors for combinations using some d-separation analy...