51#ifndef DOXYGEN_SHOULD_SKIP_THIS
67 template <
typename GUM_SCALAR >
71 bool use_binary_join_tree) :
73 _use_binary_join_tree_(use_binary_join_tree) {
75 _findRelevantTensors_ = &LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation2_;
76 setRelevantTensorsFinderType(relevant_type);
77 setFindBarrenNodesType(barren_type);
80 _triangulation_ =
new DefaultTriangulation;
83 GUM_CONSTRUCTOR(LazyPropagation);
87 template <
typename GUM_SCALAR >
88 INLINE LazyPropagation< GUM_SCALAR >::~LazyPropagation() {
90 for (
const auto& pots: _arc_to_created_tensors_)
91 for (
const auto pot: pots.second)
95 for (
const auto& pots: _clique_tensors_)
96 for (
const auto pot: pots.second)
100 for (
const auto& pot: _target_posteriors_)
102 for (
const auto& pot: _joint_target_posteriors_)
106 if (_JT_ !=
nullptr)
delete _JT_;
107 if (_junctionTree_ !=
nullptr)
delete _junctionTree_;
108 delete _triangulation_;
110 GUM_DESTRUCTOR(LazyPropagation);
114 template <
typename GUM_SCALAR >
115 void LazyPropagation< GUM_SCALAR >::setTriangulation(
const Triangulation& new_triangulation) {
116 delete _triangulation_;
117 _triangulation_ = new_triangulation.newFactory();
118 _is_new_jt_needed_ =
true;
119 this->setOutdatedStructureState_();
123 template <
typename GUM_SCALAR >
124 INLINE
const JoinTree* LazyPropagation< GUM_SCALAR >::joinTree() {
125 if (_is_new_jt_needed_) _createNewJT_();
131 template <
typename GUM_SCALAR >
132 INLINE
const JunctionTree* LazyPropagation< GUM_SCALAR >::junctionTree() {
133 if (_is_new_jt_needed_) _createNewJT_();
135 return _junctionTree_;
139 template <
typename GUM_SCALAR >
140 void LazyPropagation< GUM_SCALAR >::setRelevantTensorsFinderType(RelevantTensorsFinderType type) {
141 if (type != _find_relevant_tensor_type_) {
143 case RelevantTensorsFinderType::DSEP_BAYESBALL_TENSORS :
144 _findRelevantTensors_
145 = &LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation2_;
148 case RelevantTensorsFinderType::DSEP_BAYESBALL_NODES :
149 _findRelevantTensors_
150 = &LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation_;
153 case RelevantTensorsFinderType::DSEP_KOLLER_FRIEDMAN_2009 :
154 _findRelevantTensors_
155 = &LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation3_;
158 case RelevantTensorsFinderType::FIND_ALL :
159 _findRelevantTensors_ = &LazyPropagation< GUM_SCALAR >::_findRelevantTensorsGetAll_;
164 "setRelevantTensorsFinderType for type " << (
unsigned int)type
165 <<
" is not implemented yet");
168 _find_relevant_tensor_type_ = type;
172 _invalidateAllMessages_();
177 template <
typename GUM_SCALAR >
178 INLINE
void LazyPropagation< GUM_SCALAR >::_setProjectionFunction_(
179 Tensor< GUM_SCALAR > (*proj)(
const Tensor< GUM_SCALAR >&,
const gum::VariableSet&)) {
180 _projection_op_ = proj;
184 _invalidateAllMessages_();
188 template <
typename GUM_SCALAR >
189 INLINE
void LazyPropagation< GUM_SCALAR >::_setCombinationFunction_(
190 Tensor< GUM_SCALAR > (*comb)(
const Tensor< GUM_SCALAR >&,
const Tensor< GUM_SCALAR >&)) {
191 _combination_op_ = comb;
195 _invalidateAllMessages_();
199 template <
typename GUM_SCALAR >
200 void LazyPropagation< GUM_SCALAR >::_invalidateAllMessages_() {
202 for (
auto& potset: _separator_tensors_)
203 potset.second.clear();
204 for (
auto& mess_computed: _messages_computed_)
205 mess_computed.second =
false;
208 for (
const auto& potset: _arc_to_created_tensors_)
209 for (
const auto pot: potset.second)
211 _arc_to_created_tensors_.clear();
214 for (
const auto& pot: _target_posteriors_)
216 _target_posteriors_.clear();
217 for (
const auto& pot: _joint_target_posteriors_)
219 _joint_target_posteriors_.clear();
222 if (this->isInferenceReady() || this->isInferenceDone()) this->setOutdatedTensorsState_();
226 template <
typename GUM_SCALAR >
227 void LazyPropagation< GUM_SCALAR >::setFindBarrenNodesType(FindBarrenNodesType type) {
228 if (type != _barren_nodes_type_) {
232 case FindBarrenNodesType::FIND_BARREN_NODES :
233 case FindBarrenNodesType::FIND_NO_BARREN_NODES :
break;
237 "setFindBarrenNodesType for type " << (
unsigned int)type
238 <<
" is not implemented yet");
241 _barren_nodes_type_ = type;
244 this->setOutdatedStructureState_();
249 template <
typename GUM_SCALAR >
250 INLINE
void LazyPropagation< GUM_SCALAR >::onEvidenceAdded_(
const NodeId
id,
251 bool isHardEvidence) {
255 if (isHardEvidence || !_graph_.exists(
id)) _is_new_jt_needed_ =
true;
258 _evidence_changes_.insert(
id, EvidenceChangeType::EVIDENCE_ADDED);
264 _evidence_changes_[id] = EvidenceChangeType::EVIDENCE_MODIFIED;
270 template <
typename GUM_SCALAR >
271 INLINE
void LazyPropagation< GUM_SCALAR >::onEvidenceErased_(
const NodeId
id,
272 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 <
typename 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 <
typename GUM_SCALAR >
316 INLINE
void LazyPropagation< GUM_SCALAR >::onEvidenceChanged_(
const NodeId
id,
317 bool hasChangedSoftHard) {
318 if (hasChangedSoftHard) _is_new_jt_needed_ =
true;
321 _evidence_changes_.insert(
id, EvidenceChangeType::EVIDENCE_MODIFIED);
331 template <
typename GUM_SCALAR >
332 INLINE
void LazyPropagation< GUM_SCALAR >::onModelChanged_(
const GraphicalModel* bn) {}
335 template <
typename GUM_SCALAR >
336 INLINE
void LazyPropagation< GUM_SCALAR >::onMarginalTargetAdded_(
const NodeId
id) {
341 if (!_graph_.exists(
id) && !_hard_ev_nodes_.contains(
id)) { _is_new_jt_needed_ =
true; }
345 template <
typename GUM_SCALAR >
346 INLINE
void LazyPropagation< GUM_SCALAR >::onMarginalTargetErased_(
const NodeId
id) {}
349 template <
typename GUM_SCALAR >
350 void LazyPropagation< GUM_SCALAR >::onJointTargetAdded_(
const NodeSet& set) {
352 if (_JT_ ==
nullptr) {
353 _is_new_jt_needed_ =
true;
360 NodeId first_eliminated_node = std::numeric_limits< NodeId >::max();
361 int elim_number = std::numeric_limits< int >::max();
362 const std::vector< NodeId >& JT_elim_order = _triangulation_->eliminationOrder();
363 NodeProperty< int > elim_order(Size(JT_elim_order.size()));
364 for (std::size_t i = std::size_t(0), size = JT_elim_order.size(); i < size; ++i)
365 elim_order.insert(JT_elim_order[i], (
int)i);
366 NodeSet unobserved_set(set.size());
367 for (
const auto node: set) {
368 if (!_graph_.exists(node)) {
369 if (!_hard_ev_nodes_.contains(node)) {
370 _is_new_jt_needed_ =
true;
374 unobserved_set.insert(node);
375 if (elim_order[node] < elim_number) {
376 elim_number = elim_order[node];
377 first_eliminated_node = node;
382 if (!unobserved_set.empty()) {
386 const auto clique_id = _node_to_clique_[first_eliminated_node];
387 const auto& clique = _JT_->clique(clique_id);
388 for (
const auto node: unobserved_set) {
389 if (!clique.contains(node)) {
390 _is_new_jt_needed_ =
true;
398 template <
typename GUM_SCALAR >
399 INLINE
void LazyPropagation< GUM_SCALAR >::onJointTargetErased_(
const NodeSet& set) {}
402 template <
typename GUM_SCALAR >
403 INLINE
void LazyPropagation< GUM_SCALAR >::onAllMarginalTargetsAdded_() {
404 for (
const auto node: this->BN().dag()) {
409 if (!_graph_.exists(node) && !_hard_ev_nodes_.contains(node)) {
410 _is_new_jt_needed_ =
true;
417 template <
typename GUM_SCALAR >
418 INLINE
void LazyPropagation< GUM_SCALAR >::onAllMarginalTargetsErased_() {}
421 template <
typename GUM_SCALAR >
422 INLINE
void LazyPropagation< GUM_SCALAR >::onAllJointTargetsErased_() {}
425 template <
typename GUM_SCALAR >
426 INLINE
void LazyPropagation< GUM_SCALAR >::onAllTargetsErased_() {}
429 template <
typename GUM_SCALAR >
430 bool LazyPropagation< GUM_SCALAR >::_isNewJTNeeded_()
const {
433 if ((_JT_ ==
nullptr) || _is_new_jt_needed_)
return true;
441 const auto& hard_ev_nodes = this->hardEvidenceNodes();
442 for (
const auto node: this->targets()) {
443 if (!_graph_.exists(node) && !hard_ev_nodes.exists(node))
return true;
447 const std::vector< NodeId >& JT_elim_order = _triangulation_->eliminationOrder();
448 NodeProperty< int > elim_order(Size(JT_elim_order.size()));
449 for (std::size_t i = std::size_t(0), size = JT_elim_order.size(); i < size; ++i)
450 elim_order.insert(JT_elim_order[i], (
int)i);
453 for (
const auto& joint_target: this->jointTargets()) {
456 NodeId first_eliminated_node = std::numeric_limits< NodeId >::max();
457 int elim_number = std::numeric_limits< int >::max();
458 unobserved_set.clear();
459 for (
const auto node: joint_target) {
460 if (!_graph_.exists(node)) {
461 if (!hard_ev_nodes.exists(node))
return true;
463 unobserved_set.insert(node);
464 if (elim_order[node] < elim_number) {
465 elim_number = elim_order[node];
466 first_eliminated_node = node;
470 if (!unobserved_set.empty()) {
474 const auto clique_id = _node_to_clique_[first_eliminated_node];
475 const auto& clique = _JT_->clique(clique_id);
476 for (
const auto node: unobserved_set) {
477 if (!clique.contains(node))
return true;
484 for (
const auto& change: _evidence_changes_) {
485 if ((change.second == EvidenceChangeType::EVIDENCE_ADDED) && !_graph_.exists(change.first))
494 template <
typename GUM_SCALAR >
495 void LazyPropagation< GUM_SCALAR >::_createNewJT_() {
511 const auto& bn = this->BN();
513 for (
const auto node: bn.dag())
514 _graph_.addNodeWithId(node);
517 NodeSet target_nodes = this->targets();
518 for (
const auto& nodeset: this->jointTargets()) {
519 target_nodes += nodeset;
527 if ((this->nbrTargets() != bn.dag().size())
528 && (_barren_nodes_type_ == FindBarrenNodesType::FIND_BARREN_NODES)) {
531 if (target_nodes.size() != bn.size()) {
532 BarrenNodesFinder finder(&(bn.dag()));
533 finder.setTargets(&target_nodes);
535 NodeSet evidence_nodes(this->evidence().size());
536 for (
const auto& pair: this->evidence()) {
537 evidence_nodes.insert(pair.first);
540 finder.setEvidence(&evidence_nodes);
543 NodeSet barren_nodes = finder.barrenNodes();
546 for (
const auto node: barren_nodes) {
547 _graph_.eraseNode(node);
555 if (this->nbrTargets() != bn.dag().size()) {
557 bool dsep_analysis =
false;
558 switch (_find_relevant_tensor_type_) {
559 case RelevantTensorsFinderType::DSEP_BAYESBALL_TENSORS :
560 case RelevantTensorsFinderType::DSEP_BAYESBALL_NODES : {
561 BayesBall::requisiteNodes(bn.dag(),
563 this->hardEvidenceNodes(),
564 this->softEvidenceNodes(),
566 dsep_analysis =
true;
569 case RelevantTensorsFinderType::DSEP_KOLLER_FRIEDMAN_2009 : {
570 dSeparationAlgorithm dsep;
571 dsep.requisiteNodes(bn.dag(),
573 this->hardEvidenceNodes(),
574 this->softEvidenceNodes(),
576 dsep_analysis =
true;
579 case RelevantTensorsFinderType::FIND_ALL :
break;
586 for (
auto iter = _graph_.beginSafe(); iter != _graph_.endSafe(); ++iter) {
587 if (!requisite_nodes.contains(*iter) && !this->hardEvidenceNodes().contains(*iter)) {
588 _graph_.eraseNode(*iter);
595 for (
const auto node: _graph_) {
596 const NodeSet& parents = bn.parents(node);
597 for (
auto iter1 = parents.cbegin(); iter1 != parents.cend(); ++iter1) {
602 if (_graph_.existsNode(*iter1)) {
603 _graph_.addEdge(*iter1, node);
606 for (++iter2; iter2 != parents.cend(); ++iter2) {
611 if (_graph_.existsNode(*iter2)) _graph_.addEdge(*iter1, *iter2);
620 for (
const auto& nodeset: this->jointTargets()) {
621 for (
auto iter1 = nodeset.cbegin(); iter1 != nodeset.cend(); ++iter1) {
623 for (++iter2; iter2 != nodeset.cend(); ++iter2) {
624 _graph_.addEdge(*iter1, *iter2);
630 _hard_ev_nodes_ = this->hardEvidenceNodes();
631 for (
const auto node: _hard_ev_nodes_) {
632 _graph_.eraseNode(node);
639 if (_JT_ !=
nullptr)
delete _JT_;
640 if (_junctionTree_ !=
nullptr)
delete _junctionTree_;
642 _triangulation_->setGraph(&_graph_, &(this->domainSizes()));
643 const JunctionTree& triang_jt = _triangulation_->junctionTree();
644 if (_use_binary_join_tree_) {
645 BinaryJoinTreeConverterDefault bjt_converter;
647 _JT_ =
new CliqueGraph(bjt_converter.convert(triang_jt, this->domainSizes(), emptyset));
649 _JT_ =
new CliqueGraph(triang_jt);
651 _junctionTree_ =
new CliqueGraph(triang_jt);
656 _node_to_clique_.clear();
657 const std::vector< NodeId >& JT_elim_order = _triangulation_->eliminationOrder();
658 NodeProperty< int > elim_order(Size(JT_elim_order.size()));
659 for (std::size_t i = std::size_t(0), size = JT_elim_order.size(); i < size; ++i)
660 elim_order.insert(JT_elim_order[i], (
int)i);
661 const DAG& dag = bn.dag();
662 for (
const auto node: _graph_) {
664 NodeId first_eliminated_node = node;
665 int elim_number = elim_order[first_eliminated_node];
667 for (
const auto parent: dag.parents(node)) {
668 if (_graph_.existsNode(parent) && (elim_order[parent] < elim_number)) {
669 elim_number = elim_order[parent];
670 first_eliminated_node = parent;
678 _node_to_clique_.insert(node,
679 _triangulation_->createdJunctionTreeClique(first_eliminated_node));
685 for (
const auto node: _hard_ev_nodes_) {
686 NodeId first_eliminated_node = std::numeric_limits< NodeId >::max();
687 int elim_number = std::numeric_limits< int >::max();
689 for (
const auto parent: dag.parents(node)) {
690 if (_graph_.exists(parent) && (elim_order[parent] < elim_number)) {
691 elim_number = elim_order[parent];
692 first_eliminated_node = parent;
700 if (elim_number != std::numeric_limits< int >::max()) {
701 _node_to_clique_.insert(node,
702 _triangulation_->createdJunctionTreeClique(first_eliminated_node));
706 _joint_target_to_clique_.clear();
707 for (
const auto& set: this->jointTargets()) {
708 NodeId first_eliminated_node = std::numeric_limits< NodeId >::max();
709 int elim_number = std::numeric_limits< int >::max();
713 for (
const auto node: set) {
714 if (!_hard_ev_nodes_.contains(node)) {
717 if (elim_order[node] < elim_number) {
718 elim_number = elim_order[node];
719 first_eliminated_node = node;
724 if (elim_number != std::numeric_limits< int >::max()) {
725 _joint_target_to_clique_.insert(
727 _triangulation_->createdJunctionTreeClique(first_eliminated_node));
732 _computeJoinTreeRoots_();
737 for (
const auto& potlist: _clique_tensors_)
738 for (
const auto pot: potlist.second)
740 _clique_tensors_.clear();
743 for (
const auto& potlist: _arc_to_created_tensors_)
744 for (
const auto pot: potlist.second)
746 _arc_to_created_tensors_.clear();
751 _node_to_hard_ev_projected_CPTs_.clear();
754 _node_to_soft_evidence_.clear();
758 _ScheduleMultiDimSet_ empty_set;
759 for (
const auto node: *_JT_) {
760 _clique_tensors_.insert(node, empty_set);
769 _separator_tensors_.clear();
770 _messages_computed_.clear();
771 for (
const auto& edge: _JT_->edges()) {
772 const Arc arc1(edge.first(), edge.second());
773 _separator_tensors_.insert(arc1, empty_set);
774 _messages_computed_.insert(arc1,
false);
775 const Arc arc2(edge.second(), edge.first());
776 _separator_tensors_.insert(arc2, empty_set);
777 _messages_computed_.insert(arc2,
false);
781 for (
const auto& pot: _target_posteriors_)
783 _target_posteriors_.clear();
784 for (
const auto& pot: _joint_target_posteriors_)
786 _joint_target_posteriors_.clear();
791 double overall_size = 0;
792 for (
const auto clique: *_JT_) {
793 double clique_size = 1.0;
794 for (
const auto node: _JT_->clique(clique))
795 clique_size *= this->domainSizes()[node];
796 overall_size += clique_size;
798 _use_schedules_ = (overall_size > _schedule_threshold_);
804 if (_use_schedules_) {
806 _initializeJTCliques_(schedule);
808 _initializeJTCliques_();
813 const NodeProperty< const Tensor< GUM_SCALAR >* >& evidence = this->evidence();
814 for (
const auto node: this->softEvidenceNodes()) {
815 if (_node_to_clique_.exists(node)) {
816 auto ev_pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(*evidence[node],
false);
817 _node_to_soft_evidence_.insert(node, ev_pot);
818 _clique_tensors_[_node_to_clique_[node]].insert(ev_pot);
824 _evidence_changes_.clear();
825 _is_new_jt_needed_ =
false;
829 template <
typename GUM_SCALAR >
830 void LazyPropagation< GUM_SCALAR >::_initializeJTCliques_() {
831 const auto& bn = this->BN();
832 const DAG& dag = bn.dag();
838 const NodeProperty< const Tensor< GUM_SCALAR >* >& evidence = this->evidence();
839 const NodeProperty< Idx >& hard_evidence = this->hardEvidence();
841 for (
const auto node: dag) {
842 if (_graph_.exists(node) || _hard_ev_nodes_.contains(node)) {
843 const Tensor< GUM_SCALAR >& cpt = bn.cpt(node);
847 const auto& variables = cpt.variablesSequence();
848 bool graph_contains_nodes =
false;
849 for (
const auto var: variables) {
850 NodeId xnode = bn.nodeId(*var);
851 if (_hard_ev_nodes_.contains(xnode)) hard_nodes.insert(xnode);
852 else if (_graph_.exists(xnode)) graph_contains_nodes =
true;
858 if (hard_nodes.empty()) {
859 auto sched_cpt =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(cpt,
false);
860 _clique_tensors_[_node_to_clique_[node]].insert(sched_cpt);
866 if (hard_nodes.size() == variables.size()) {
867 Instantiation inst(cpt);
868 for (Size i = 0; i < hard_nodes.size(); ++i) {
869 inst.chgVal(*variables[i], hard_evidence[bn.nodeId(*(variables[i]))]);
871 _constants_.insert(node, cpt.get(inst));
876 if (!graph_contains_nodes)
continue;
880 _TensorSet_ marg_cpt_set(1 + hard_nodes.size());
881 marg_cpt_set.insert(&cpt);
882 for (
const auto xnode: hard_nodes) {
883 marg_cpt_set.insert(evidence[xnode]);
884 hard_variables.
insert(&(bn.variable(xnode)));
888 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(
892 _TensorSet_ new_cpt_list = combine_and_project.execute(marg_cpt_set, hard_variables);
895 if (new_cpt_list.size() != 1) {
896 for (
const auto pot: new_cpt_list) {
897 if (!marg_cpt_set.contains(pot))
delete pot;
900 "the projection of a tensor containing " <<
"hard evidence is empty!");
902 auto new_pot =
const_cast< Tensor< GUM_SCALAR >*
>(*(new_cpt_list.begin()));
903 auto projected_pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(std::move(*new_pot));
906 _clique_tensors_[_node_to_clique_[node]].insert(projected_pot);
907 _node_to_hard_ev_projected_CPTs_.insert(node, projected_pot);
915 template <
typename GUM_SCALAR >
916 void LazyPropagation< GUM_SCALAR >::_initializeJTCliques_(Schedule& schedule) {
917 const auto& bn = this->BN();
918 const DAG& dag = bn.dag();
924 const NodeProperty< const Tensor< GUM_SCALAR >* >& evidence = this->evidence();
925 const NodeProperty< Idx >& hard_evidence = this->hardEvidence();
927 for (
const auto node: dag) {
928 if (_graph_.exists(node) || _hard_ev_nodes_.contains(node)) {
929 const Tensor< GUM_SCALAR >& cpt = bn.cpt(node);
933 const auto& variables = cpt.variablesSequence();
934 bool graph_contains_nodes =
false;
935 for (
const auto var: variables) {
936 NodeId xnode = bn.nodeId(*var);
937 if (_hard_ev_nodes_.contains(xnode)) hard_nodes.insert(xnode);
938 else if (_graph_.exists(xnode)) graph_contains_nodes =
true;
944 if (hard_nodes.empty()) {
945 auto sched_cpt =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(cpt,
false);
946 _clique_tensors_[_node_to_clique_[node]].insert(sched_cpt);
952 if (hard_nodes.size() == variables.size()) {
953 Instantiation inst(cpt);
954 for (Size i = 0; i < hard_nodes.size(); ++i) {
955 inst.chgVal(*variables[i], hard_evidence[bn.nodeId(*(variables[i]))]);
957 _constants_.insert(node, cpt.get(inst));
962 if (!graph_contains_nodes)
continue;
966 _ScheduleMultiDimSet_ marg_cpt_set(1 + hard_nodes.size());
967 const IScheduleMultiDim* sched_cpt
968 = schedule.insertTable< Tensor< GUM_SCALAR > >(cpt,
false);
969 marg_cpt_set.insert(sched_cpt);
971 for (
const auto xnode: hard_nodes) {
972 const IScheduleMultiDim* pot
973 = schedule.insertTable< Tensor< GUM_SCALAR > >(*evidence[xnode],
false);
974 marg_cpt_set.insert(pot);
975 hard_variables.
insert(&(bn.variable(xnode)));
979 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(
983 _ScheduleMultiDimSet_ new_cpt_list
984 = combine_and_project.schedule(schedule, marg_cpt_set, hard_variables);
987 if (new_cpt_list.size() != 1) {
989 "the projection of a tensor containing " <<
"hard evidence is empty!");
991 auto projected_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
992 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
993 *new_cpt_list.begin()));
994 const_cast< ScheduleOperator*
>(schedule.scheduleMultiDimCreator(projected_pot))
995 ->makeResultsPersistent(
true);
996 _clique_tensors_[_node_to_clique_[node]].insert(projected_pot);
997 _node_to_hard_ev_projected_CPTs_.insert(node, projected_pot);
1002 this->scheduler().execute(schedule);
1006 template <
typename GUM_SCALAR >
1007 void LazyPropagation< GUM_SCALAR >::updateOutdatedStructure_() {
1009 if (_isNewJTNeeded_()) {
1015 updateOutdatedTensors_();
1020 template <
typename GUM_SCALAR >
1021 void LazyPropagation< GUM_SCALAR >::_diffuseMessageInvalidations_(NodeId from_id,
1023 NodeSet& invalidated_cliques) {
1025 invalidated_cliques.insert(to_id);
1028 const Arc arc(from_id, to_id);
1029 bool& message_computed = _messages_computed_[arc];
1030 if (message_computed) {
1031 message_computed =
false;
1032 _separator_tensors_[arc].clear();
1033 if (_arc_to_created_tensors_.exists(arc)) {
1034 _ScheduleMultiDimSet_& arc_created_tensors = _arc_to_created_tensors_[arc];
1035 for (
const auto pot: arc_created_tensors)
1037 arc_created_tensors.clear();
1041 for (
const auto node_id: _JT_->neighbours(to_id)) {
1042 if (node_id != from_id) _diffuseMessageInvalidations_(to_id, node_id, invalidated_cliques);
1049 template <
typename GUM_SCALAR >
1050 void LazyPropagation< GUM_SCALAR >::updateOutdatedTensors_() {
1060 NodeSet hard_nodes_changed(_hard_ev_nodes_.size());
1061 for (
const auto node: _hard_ev_nodes_)
1062 if (_evidence_changes_.exists(node)) hard_nodes_changed.insert(node);
1064 NodeSet nodes_with_projected_CPTs_changed;
1065 const auto& bn = this->BN();
1066 for (
auto pot_iter = _node_to_hard_ev_projected_CPTs_.beginSafe();
1067 pot_iter != _node_to_hard_ev_projected_CPTs_.endSafe();
1069 for (
const auto var: bn.cpt(pot_iter.key()).variablesSequence()) {
1070 if (hard_nodes_changed.contains(bn.nodeId(*var))) {
1071 nodes_with_projected_CPTs_changed.insert(pot_iter.key());
1072 delete pot_iter.val();
1073 _clique_tensors_[_node_to_clique_[pot_iter.key()]].erase(pot_iter.val());
1074 _node_to_hard_ev_projected_CPTs_.erase(pot_iter);
1088 NodeSet invalidated_cliques(_JT_->size());
1089 for (
const auto& pair: _evidence_changes_) {
1090 if (_node_to_clique_.exists(pair.first)) {
1091 const auto clique = _node_to_clique_[pair.first];
1092 invalidated_cliques.insert(clique);
1093 for (
const auto neighbor: _JT_->neighbours(clique)) {
1094 _diffuseMessageInvalidations_(clique, neighbor, invalidated_cliques);
1101 for (
const auto node: nodes_with_projected_CPTs_changed) {
1102 const auto clique = _node_to_clique_[node];
1103 invalidated_cliques.insert(clique);
1104 for (
const auto neighbor: _JT_->neighbours(clique)) {
1105 _diffuseMessageInvalidations_(clique, neighbor, invalidated_cliques);
1114 for (
auto iter = _target_posteriors_.beginSafe(); iter != _target_posteriors_.endSafe();
1116 if (_graph_.exists(iter.key())
1117 && (invalidated_cliques.exists(_node_to_clique_[iter.key()]))) {
1119 _target_posteriors_.erase(iter);
1124 for (
auto iter = _target_posteriors_.beginSafe(); iter != _target_posteriors_.endSafe();
1126 if (hard_nodes_changed.contains(iter.key())) {
1128 _target_posteriors_.erase(iter);
1134 for (
auto iter = _joint_target_posteriors_.beginSafe();
1135 iter != _joint_target_posteriors_.endSafe();
1137 if (invalidated_cliques.exists(_joint_target_to_clique_[iter.key()])) {
1139 _joint_target_posteriors_.erase(iter);
1142 bool has_unevidenced_node =
false;
1143 for (
const auto node: iter.key()) {
1144 if (!hard_nodes_changed.exists(node)) {
1145 has_unevidenced_node =
true;
1149 if (!has_unevidenced_node) {
1151 _joint_target_posteriors_.erase(iter);
1158 for (
const auto& pot_pair: _node_to_soft_evidence_) {
1159 delete pot_pair.second;
1160 _clique_tensors_[_node_to_clique_[pot_pair.first]].erase(pot_pair.second);
1162 _node_to_soft_evidence_.clear();
1164 const auto& evidence = this->evidence();
1165 for (
const auto node: this->softEvidenceNodes()) {
1166 auto ev_pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(*evidence[node],
false);
1167 _node_to_soft_evidence_.insert(node, ev_pot);
1168 _clique_tensors_[_node_to_clique_[node]].insert(ev_pot);
1178 if (_use_schedules_) {
1180 for (
const auto node: nodes_with_projected_CPTs_changed) {
1182 const Tensor< GUM_SCALAR >& cpt = bn.cpt(node);
1183 const auto& variables = cpt.variablesSequence();
1184 _ScheduleMultiDimSet_ marg_cpt_set;
1185 const auto sched_cpt = schedule.insertTable< Tensor< GUM_SCALAR > >(cpt,
false);
1186 marg_cpt_set.insert(sched_cpt);
1189 for (
const auto var: variables) {
1190 NodeId xnode = bn.nodeId(*var);
1191 if (_hard_ev_nodes_.exists(xnode)) {
1192 const auto pot = schedule.insertTable< Tensor< GUM_SCALAR > >(*evidence[xnode],
false);
1193 marg_cpt_set.insert(pot);
1194 hard_variables.
insert(var);
1199 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(
1203 _ScheduleMultiDimSet_ new_cpt_list
1204 = combine_and_project.schedule(schedule, marg_cpt_set, hard_variables);
1207 if (new_cpt_list.size() != 1) {
1209 "the projection of a tensor containing " <<
"hard evidence is empty!");
1211 auto projected_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
1212 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(*new_cpt_list.begin()));
1213 const_cast< ScheduleOperator*
>(schedule.scheduleMultiDimCreator(projected_pot))
1214 ->makeResultsPersistent(
true);
1215 _clique_tensors_[_node_to_clique_[node]].insert(projected_pot);
1216 _node_to_hard_ev_projected_CPTs_.insert(node, projected_pot);
1218 this->scheduler().execute(schedule);
1220 for (
const auto node: nodes_with_projected_CPTs_changed) {
1222 const Tensor< GUM_SCALAR >& cpt = bn.cpt(node);
1223 const auto& variables = cpt.variablesSequence();
1224 _TensorSet_ marg_cpt_set(1 + variables.size());
1225 marg_cpt_set.insert(&cpt);
1228 for (
const auto var: variables) {
1229 NodeId xnode = bn.nodeId(*var);
1230 if (_hard_ev_nodes_.exists(xnode)) {
1231 marg_cpt_set.insert(evidence[xnode]);
1232 hard_variables.
insert(var);
1237 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(
1241 _TensorSet_ new_cpt_list = combine_and_project.execute(marg_cpt_set, hard_variables);
1244 if (new_cpt_list.size() != 1) {
1246 "the projection of a tensor containing " <<
"hard evidence is empty!");
1248 Tensor< GUM_SCALAR >* sched_pot
1249 =
const_cast< Tensor< GUM_SCALAR >*
>(*new_cpt_list.begin());
1250 auto projected_pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(std::move(*sched_pot));
1252 _clique_tensors_[_node_to_clique_[node]].insert(projected_pot);
1253 _node_to_hard_ev_projected_CPTs_.insert(node, projected_pot);
1259 const auto& hard_evidence = this->hardEvidence();
1260 for (
auto& node_cst: _constants_) {
1261 const Tensor< GUM_SCALAR >& cpt = bn.cpt(node_cst.first);
1262 const auto& variables = cpt.variablesSequence();
1263 Instantiation inst(cpt);
1264 for (
const auto var: variables) {
1265 inst.chgVal(*var, hard_evidence[bn.nodeId(*var)]);
1267 node_cst.second = cpt.get(inst);
1271 _evidence_changes_.clear();
1275 template <
typename GUM_SCALAR >
1276 void LazyPropagation< GUM_SCALAR >::_computeJoinTreeRoots_() {
1281 for (
const auto node: this->targets()) {
1283 clique_targets.insert(_node_to_clique_[node]);
1284 }
catch (Exception
const&) {}
1286 for (
const auto& set: this->jointTargets()) {
1288 clique_targets.insert(_joint_target_to_clique_[set]);
1289 }
catch (Exception
const&) {}
1293 std::vector< std::pair< NodeId, Size > > possible_roots(clique_targets.size());
1294 const auto& bn = this->BN();
1296 for (
const auto clique_id: clique_targets) {
1297 const auto& clique = _JT_->clique(clique_id);
1299 for (
const auto node: clique) {
1300 dom_size *= bn.variable(node).domainSize();
1302 possible_roots[i] = std::pair< NodeId, Size >(clique_id, dom_size);
1307 std::sort(possible_roots.begin(),
1308 possible_roots.end(),
1309 [](
const std::pair< NodeId, Size >& a,
const std::pair< NodeId, Size >& b) ->
bool {
1310 return a.second < b.second;
1314 NodeProperty< bool > marked = _JT_->nodesPropertyFromVal(
false);
1315 std::function< void(NodeId, NodeId) > diffuse_marks
1316 = [&marked, &diffuse_marks,
this](NodeId node, NodeId from) {
1317 if (!marked[node]) {
1318 marked[node] =
true;
1319 for (
const auto neigh: _JT_->neighbours(node))
1320 if ((neigh != from) && !marked[neigh]) diffuse_marks(neigh, node);
1324 for (
const auto& xclique: possible_roots) {
1325 NodeId clique = xclique.first;
1326 if (!marked[clique]) {
1327 _roots_.insert(clique);
1328 diffuse_marks(clique, clique);
1334 template <
typename GUM_SCALAR >
1335 void LazyPropagation< GUM_SCALAR >::_findRelevantTensorsGetAll_(
1336 Set< const IScheduleMultiDim* >& pot_list,
1340 template <
typename GUM_SCALAR >
1341 void LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation_(
1342 Set< const IScheduleMultiDim* >& pot_list,
1346 const auto& bn = this->BN();
1347 for (
const auto var: kept_vars) {
1348 kept_ids.insert(bn.nodeId(*var));
1353 BayesBall::requisiteNodes(bn.dag(),
1355 this->hardEvidenceNodes(),
1356 this->softEvidenceNodes(),
1358 for (
auto iter = pot_list.beginSafe(); iter != pot_list.endSafe(); ++iter) {
1359 const Sequence< const DiscreteVariable* >& vars = (*iter)->variablesSequence();
1361 for (
const auto var: vars) {
1362 if (requisite_nodes.exists(bn.nodeId(*var))) {
1368 if (!found) { pot_list.erase(iter); }
1373 template <
typename GUM_SCALAR >
1374 void LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation2_(
1375 Set< const IScheduleMultiDim* >& pot_list,
1379 const auto& bn = this->BN();
1380 for (
const auto var: kept_vars) {
1381 kept_ids.insert(bn.nodeId(*var));
1385 BayesBall::relevantTensors(bn,
1387 this->hardEvidenceNodes(),
1388 this->softEvidenceNodes(),
1393 template <
typename GUM_SCALAR >
1394 void LazyPropagation< GUM_SCALAR >::_findRelevantTensorsWithdSeparation3_(
1395 Set< const IScheduleMultiDim* >& pot_list,
1399 const auto& bn = this->BN();
1400 for (
const auto var: kept_vars) {
1401 kept_ids.insert(bn.nodeId(*var));
1405 dSeparationAlgorithm dsep;
1406 dsep.relevantTensors(bn,
1408 this->hardEvidenceNodes(),
1409 this->softEvidenceNodes(),
1414 template <
typename GUM_SCALAR >
1415 void LazyPropagation< GUM_SCALAR >::_findRelevantTensorsXX_(
1416 Set< const IScheduleMultiDim* >& pot_list,
1418 switch (_find_relevant_tensor_type_) {
1419 case RelevantTensorsFinderType::DSEP_BAYESBALL_TENSORS :
1420 _findRelevantTensorsWithdSeparation2_(pot_list, kept_vars);
1423 case RelevantTensorsFinderType::DSEP_BAYESBALL_NODES :
1424 _findRelevantTensorsWithdSeparation_(pot_list, kept_vars);
1427 case RelevantTensorsFinderType::DSEP_KOLLER_FRIEDMAN_2009 :
1428 _findRelevantTensorsWithdSeparation3_(pot_list, kept_vars);
1431 case RelevantTensorsFinderType::FIND_ALL :
1432 _findRelevantTensorsGetAll_(pot_list, kept_vars);
1440 template <
typename GUM_SCALAR >
1441 Set< const IScheduleMultiDim* >
1442 LazyPropagation< GUM_SCALAR >::_removeBarrenVariables_(Schedule& schedule,
1443 _ScheduleMultiDimSet_& pot_list,
1448 for (
auto iter = the_del_vars.
beginSafe(); iter != the_del_vars.
endSafe(); ++iter) {
1449 NodeId
id = this->BN().nodeId(**iter);
1450 if (this->hardEvidenceNodes().exists(
id) || this->softEvidenceNodes().exists(
id)) {
1451 the_del_vars.
erase(iter);
1456 HashTable< const DiscreteVariable*, _ScheduleMultiDimSet_ > var2pots(the_del_vars.
size());
1457 _ScheduleMultiDimSet_ empty_pot_set;
1458 for (
const auto pot: pot_list) {
1459 const auto& vars = pot->variablesSequence();
1460 for (
const auto var: vars) {
1461 if (the_del_vars.
exists(var)) {
1462 if (!var2pots.exists(var)) { var2pots.insert(var, empty_pot_set); }
1463 var2pots[var].insert(pot);
1470 HashTable< const IScheduleMultiDim*, gum::VariableSet > pot2barren_var;
1472 for (
const auto& elt: var2pots) {
1473 if (elt.second.size() == 1) {
1474 const IScheduleMultiDim* pot = *(elt.second.begin());
1475 if (!pot2barren_var.exists(pot)) { pot2barren_var.insert(pot, empty_var_set); }
1476 pot2barren_var[pot].insert(elt.first);
1483 MultiDimProjection< Tensor< GUM_SCALAR > > projector(_projection_op_);
1484 _ScheduleMultiDimSet_ projected_pots;
1485 for (
const auto& elt: pot2barren_var) {
1487 const IScheduleMultiDim* pot = elt.first;
1488 pot_list.erase(pot);
1492 if (pot->variablesSequence().size() != elt.second.size()) {
1493 const IScheduleMultiDim* new_pot = projector.schedule(schedule, pot, elt.second);
1497 pot_list.insert(new_pot);
1498 projected_pots.insert(new_pot);
1502 return projected_pots;
1506 template <
typename GUM_SCALAR >
1507 Set< const Tensor< GUM_SCALAR >* >
1508 LazyPropagation< GUM_SCALAR >::_removeBarrenVariables_(_TensorSet_& pot_list,
1513 for (
auto iter = the_del_vars.
beginSafe(); iter != the_del_vars.
endSafe(); ++iter) {
1514 NodeId
id = this->BN().nodeId(**iter);
1515 if (this->hardEvidenceNodes().exists(
id) || this->softEvidenceNodes().exists(
id)) {
1516 the_del_vars.
erase(iter);
1521 HashTable< const DiscreteVariable*, _TensorSet_ > var2pots;
1522 _TensorSet_ empty_pot_set;
1523 for (
const auto pot: pot_list) {
1524 const Sequence< const DiscreteVariable* >& vars = pot->variablesSequence();
1525 for (
const auto var: vars) {
1526 if (the_del_vars.
exists(var)) {
1527 if (!var2pots.exists(var)) { var2pots.insert(var, empty_pot_set); }
1528 var2pots[var].insert(pot);
1537 for (
const auto& elt: var2pots) {
1538 if (elt.second.size() == 1) {
1539 const Tensor< GUM_SCALAR >* pot = *(elt.second.begin());
1540 if (!pot2barren_var.exists(pot)) { pot2barren_var.insert(pot, empty_var_set); }
1541 pot2barren_var[pot].insert(elt.first);
1548 MultiDimProjection< Tensor< GUM_SCALAR > > projector(_projection_op_);
1549 _TensorSet_ projected_pots;
1550 for (
const auto& elt: pot2barren_var) {
1552 const Tensor< GUM_SCALAR >* pot = elt.first;
1553 pot_list.erase(pot);
1557 if (pot->variablesSequence().size() != elt.second.size()) {
1558 const Tensor< GUM_SCALAR >* new_pot = projector.execute(*pot, elt.second);
1559 pot_list.insert(new_pot);
1560 projected_pots.insert(new_pot);
1564 return projected_pots;
1568 template <
typename GUM_SCALAR >
1570 LazyPropagation< GUM_SCALAR >::_collectMessage_(Schedule& schedule, NodeId
id, NodeId from) {
1571 for (
const auto other: _JT_->neighbours(
id)) {
1572 if ((other != from) && !_messages_computed_[Arc(other,
id)])
1573 _collectMessage_(schedule, other,
id);
1576 if ((
id != from) && !_messages_computed_[Arc(
id, from)]) {
1577 _produceMessage_(schedule,
id, from);
1582 template <
typename GUM_SCALAR >
1583 INLINE
void LazyPropagation< GUM_SCALAR >::_collectMessage_(NodeId
id, NodeId from) {
1584 for (
const auto other: _JT_->neighbours(
id)) {
1585 if ((other != from) && !_messages_computed_[Arc(other,
id)]) _collectMessage_(other,
id);
1588 if ((
id != from) && !_messages_computed_[Arc(
id, from)]) { _produceMessage_(
id, from); }
1592 template <
typename GUM_SCALAR >
1593 Set< const IScheduleMultiDim* >
1594 LazyPropagation< GUM_SCALAR >::_marginalizeOut_(Schedule& schedule,
1595 Set< const IScheduleMultiDim* > pot_list,
1602 if (pot_list.empty()) {
return _ScheduleMultiDimSet_(); }
1606 for (
const auto pot: pot_list) {
1607 if (!schedule.existsScheduleMultiDim(pot->id())) schedule.emplaceScheduleMultiDim(*pot);
1612 _ScheduleMultiDimSet_ barren_projected_tensors;
1613 if (_barren_nodes_type_ == FindBarrenNodesType::FIND_BARREN_NODES) {
1614 barren_projected_tensors = _removeBarrenVariables_(schedule, pot_list, del_vars);
1618 _ScheduleMultiDimSet_ new_pot_list;
1619 if (pot_list.size() == 1) {
1620 MultiDimProjection< Tensor< GUM_SCALAR > > projector(_projection_op_);
1621 auto xpot = projector.schedule(schedule, *(pot_list.begin()), del_vars);
1622 new_pot_list.insert(xpot);
1623 }
else if (pot_list.size() > 1) {
1626 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(_combination_op_,
1628 new_pot_list = combine_and_project.schedule(schedule, pot_list, del_vars);
1634 for (
auto barren_pot: barren_projected_tensors) {
1635 if (!new_pot_list.exists(barren_pot))
1636 schedule.emplaceDeletion(
1637 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>& >(*barren_pot));
1640 return new_pot_list;
1644 template <
typename GUM_SCALAR >
1645 Set< const IScheduleMultiDim* >
1646 LazyPropagation< GUM_SCALAR >::_marginalizeOut_(Set< const IScheduleMultiDim* >& pot_list,
1650 if (pot_list.empty()) {
return _ScheduleMultiDimSet_(); }
1652 _TensorSet_ xpot_list(pot_list.size());
1653 for (
auto pot: pot_list)
1655 &(
static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(pot)->multiDim()));
1662 _TensorSet_ barren_projected_tensors;
1663 if (_barren_nodes_type_ == FindBarrenNodesType::FIND_BARREN_NODES) {
1664 barren_projected_tensors = _removeBarrenVariables_(xpot_list, del_vars);
1668 _TensorSet_ xnew_pot_list;
1669 _ScheduleMultiDimSet_ new_pot_list;
1670 if (xpot_list.size() == 1) {
1671 MultiDimProjection< Tensor< GUM_SCALAR > > projector(_projection_op_);
1672 auto xpot = projector.execute(**(xpot_list.begin()), del_vars);
1673 ScheduleMultiDim< Tensor< GUM_SCALAR > >* pot;
1674 if (xpot_list.contains(xpot))
1675 pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(*xpot,
false);
1677 pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(
1678 std::move(
const_cast< Tensor< GUM_SCALAR >&
>(*xpot)));
1681 new_pot_list.insert(pot);
1682 }
else if (xpot_list.size() > 1) {
1685 MultiDimCombineAndProjectDefault< Tensor< GUM_SCALAR > > combine_and_project(_combination_op_,
1687 xnew_pot_list = combine_and_project.execute(xpot_list, del_vars);
1689 for (
auto xpot: xnew_pot_list) {
1690 ScheduleMultiDim< Tensor< GUM_SCALAR > >* pot;
1691 if (xpot_list.contains(xpot))
1692 pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(*xpot,
false);
1694 pot =
new ScheduleMultiDim< Tensor< GUM_SCALAR > >(
1695 std::move(
const_cast< Tensor< GUM_SCALAR >&
>(*xpot)));
1698 new_pot_list.insert(pot);
1705 for (
const auto barren_pot: barren_projected_tensors) {
1706 if (!xnew_pot_list.exists(barren_pot))
delete barren_pot;
1709 return new_pot_list;
1713 template <
typename GUM_SCALAR >
1714 void LazyPropagation< GUM_SCALAR >::_produceMessage_(Schedule& schedule,
1718 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[from_id];
1721 for (
const auto other_id: _JT_->neighbours(from_id)) {
1722 if (other_id != to_id) pot_list += _separator_tensors_[Arc(other_id, from_id)];
1726 const NodeSet& from_clique = _JT_->clique(from_id);
1727 const NodeSet& separator = _JT_->separator(from_id, to_id);
1730 const auto& bn = this->BN();
1732 for (
const auto node: from_clique) {
1733 if (!separator.contains(node)) {
1734 del_vars.
insert(&(bn.variable(node)));
1736 kept_vars.
insert(&(bn.variable(node)));
1742 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(schedule, pot_list, del_vars, kept_vars);
1749 const Arc arc(from_id, to_id);
1751 if (!_arc_to_created_tensors_.exists(arc))
1752 _arc_to_created_tensors_.insert(arc, _ScheduleMultiDimSet_());
1754 for (
auto iter = new_pot_list.beginSafe(); iter != new_pot_list.endSafe(); ++iter) {
1755 const auto pot = *iter;
1757 if (!pot_list.exists(pot)) {
1758 _arc_to_created_tensors_[arc].insert(pot);
1761 auto op = schedule.scheduleMultiDimCreator(pot);
1762 if (op !=
nullptr)
const_cast< ScheduleOperator*
>(op)->makeResultsPersistent(
true);
1766 _separator_tensors_[arc] = std::move(new_pot_list);
1767 _messages_computed_[arc] =
true;
1771 template <
typename GUM_SCALAR >
1772 void LazyPropagation< GUM_SCALAR >::_produceMessage_(NodeId from_id, NodeId to_id) {
1774 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[from_id];
1777 for (
const auto other_id: _JT_->neighbours(from_id)) {
1778 if (other_id != to_id) pot_list += _separator_tensors_[Arc(other_id, from_id)];
1782 const NodeSet& from_clique = _JT_->clique(from_id);
1783 const NodeSet& separator = _JT_->separator(from_id, to_id);
1786 const auto& bn = this->BN();
1788 for (
const auto node: from_clique) {
1789 if (!separator.contains(node)) {
1790 del_vars.
insert(&(bn.variable(node)));
1792 kept_vars.
insert(&(bn.variable(node)));
1798 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(pot_list, del_vars, kept_vars);
1805 const Arc arc(from_id, to_id);
1807 if (!_arc_to_created_tensors_.exists(arc))
1808 _arc_to_created_tensors_.insert(arc, _ScheduleMultiDimSet_());
1810 for (
const auto pot: new_pot_list) {
1811 if (!pot_list.exists(pot)) { _arc_to_created_tensors_[arc].insert(pot); }
1814 _separator_tensors_[arc] = std::move(new_pot_list);
1815 _messages_computed_[arc] =
true;
1819 template <
typename GUM_SCALAR >
1820 INLINE
void LazyPropagation< GUM_SCALAR >::makeInference_() {
1821 if (_use_schedules_) {
1825 for (
const auto node: this->targets()) {
1829 if (_graph_.exists(node)) {
1830 _collectMessage_(schedule, _node_to_clique_[node], _node_to_clique_[node]);
1838 for (
const auto& set: _joint_target_to_clique_)
1839 _collectMessage_(schedule, set.second, set.second);
1842 this->scheduler().execute(schedule);
1845 for (
const auto node: this->targets()) {
1849 if (_graph_.exists(node)) {
1850 _collectMessage_(_node_to_clique_[node], _node_to_clique_[node]);
1858 for (
const auto& set: _joint_target_to_clique_)
1859 _collectMessage_(set.second, set.second);
1864 template <
typename GUM_SCALAR >
1865 Tensor< GUM_SCALAR >* LazyPropagation< GUM_SCALAR >::unnormalizedJointPosterior_(NodeId
id) {
1866 if (_use_schedules_) {
1868 return _unnormalizedJointPosterior_(schedule,
id);
1870 return _unnormalizedJointPosterior_(
id);
1875 template <
typename GUM_SCALAR >
1876 Tensor< GUM_SCALAR >*
1877 LazyPropagation< GUM_SCALAR >::_unnormalizedJointPosterior_(Schedule& schedule, NodeId
id) {
1878 const auto& bn = this->BN();
1882 if (this->hardEvidenceNodes().contains(
id)) {
1883 return new Tensor< GUM_SCALAR >(*(this->evidence()[
id]));
1886 auto& scheduler = this->scheduler();
1890 const NodeId clique_of_id = _node_to_clique_[id];
1891 _collectMessage_(schedule, clique_of_id, clique_of_id);
1896 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[clique_of_id];
1899 for (
const auto other: _JT_->neighbours(clique_of_id))
1900 pot_list += _separator_tensors_[Arc(other, clique_of_id)];
1903 const NodeSet& nodes = _JT_->clique(clique_of_id);
1906 for (
const auto node: nodes) {
1907 if (node !=
id) del_vars.
insert(&(bn.variable(node)));
1912 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(schedule, pot_list, del_vars, kept_vars);
1913 Tensor< GUM_SCALAR >* joint =
nullptr;
1914 ScheduleMultiDim< Tensor< GUM_SCALAR > >* resulting_pot =
nullptr;
1916 if (new_pot_list.size() == 0) {
1917 joint =
new Tensor< GUM_SCALAR >;
1918 for (
const auto var: kept_vars)
1921 if (new_pot_list.size() == 1) {
1922 scheduler.execute(schedule);
1923 resulting_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
1924 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(*new_pot_list.begin()));
1926 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
1927 const IScheduleMultiDim* pot = fast_combination.schedule(schedule, new_pot_list);
1928 scheduler.execute(schedule);
1929 resulting_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
1930 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(pot));
1935 if (pot_list.exists(resulting_pot)) {
1936 joint =
new Tensor< GUM_SCALAR >(resulting_pot->multiDim());
1938 joint = resulting_pot->exportMultiDim();
1945 bool nonzero_found =
false;
1946 for (Instantiation inst(*joint); !inst.end(); ++inst) {
1947 if (joint->get(inst)) {
1948 nonzero_found =
true;
1952 if (!nonzero_found) {
1956 "some evidence entered into the Bayes "
1957 "net are incompatible (their joint proba = 0)");
1963 template <
typename GUM_SCALAR >
1964 Tensor< GUM_SCALAR >* LazyPropagation< GUM_SCALAR >::_unnormalizedJointPosterior_(NodeId
id) {
1965 const auto& bn = this->BN();
1969 if (this->hardEvidenceNodes().contains(
id)) {
1970 return new Tensor< GUM_SCALAR >(*(this->evidence()[
id]));
1975 NodeId clique_of_id = _node_to_clique_[id];
1976 _collectMessage_(clique_of_id, clique_of_id);
1981 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[clique_of_id];
1984 for (
const auto other: _JT_->neighbours(clique_of_id))
1985 pot_list += _separator_tensors_[Arc(other, clique_of_id)];
1988 const NodeSet& nodes = _JT_->clique(clique_of_id);
1991 for (
const auto node: nodes) {
1992 if (node !=
id) del_vars.
insert(&(bn.variable(node)));
1997 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(pot_list, del_vars, kept_vars);
1998 Tensor< GUM_SCALAR >* joint =
nullptr;
2000 if (new_pot_list.size() == 0) {
2001 joint =
new Tensor< GUM_SCALAR >;
2002 for (
const auto var: kept_vars)
2004 }
else if (new_pot_list.size() == 1) {
2005 auto sched_joint =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
2006 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(*(new_pot_list.begin())));
2010 if (pot_list.exists(sched_joint)) {
2011 joint =
new Tensor< GUM_SCALAR >(sched_joint->multiDim());
2013 joint = sched_joint->exportMultiDim();
2018 new_pot_list.clear();
2021 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
2024 _TensorSet_ xnew_pot_list(new_pot_list.size());
2025 for (
auto xpot: new_pot_list) {
2026 xnew_pot_list.insert(
2027 &(
static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(xpot)->multiDim()));
2030 joint = fast_combination.execute(xnew_pot_list);
2036 for (
const auto pot: new_pot_list)
2037 if (!pot_list.exists(pot))
delete pot;
2042 bool nonzero_found =
false;
2043 for (Instantiation inst(*joint); !inst.end(); ++inst) {
2044 if (joint->get(inst)) {
2045 nonzero_found =
true;
2049 if (!nonzero_found) {
2053 "some evidence entered into the Bayes "
2054 "net are incompatible (their joint proba = 0)");
2060 template <
typename GUM_SCALAR >
2061 const Tensor< GUM_SCALAR >& LazyPropagation< GUM_SCALAR >::posterior_(NodeId
id) {
2063 if (_target_posteriors_.exists(
id)) {
return *(_target_posteriors_[id]); }
2066 auto joint = unnormalizedJointPosterior_(
id);
2067 if (joint->sum() != 1)
2069 _target_posteriors_.insert(
id, joint);
2075 template <
typename GUM_SCALAR >
2076 Tensor< GUM_SCALAR >*
2077 LazyPropagation< GUM_SCALAR >::unnormalizedJointPosterior_(
const NodeSet& set) {
2078 if (_use_schedules_) {
2080 return _unnormalizedJointPosterior_(schedule, set);
2082 return _unnormalizedJointPosterior_(set);
2087 template <
typename GUM_SCALAR >
2088 Tensor< GUM_SCALAR >*
2089 LazyPropagation< GUM_SCALAR >::_unnormalizedJointPosterior_(Schedule& schedule,
2090 const NodeSet& set) {
2093 NodeSet targets = set, hard_ev_nodes;
2094 for (
const auto node: this->hardEvidenceNodes()) {
2095 if (targets.contains(node)) {
2096 targets.erase(node);
2097 hard_ev_nodes.insert(node);
2101 auto& scheduler = this->scheduler();
2105 const auto& evidence = this->evidence();
2106 if (targets.empty()) {
2107 if (set.size() == 1) {
2108 return new Tensor< GUM_SCALAR >(*evidence[*set.begin()]);
2110 _ScheduleMultiDimSet_ pot_list;
2111 for (
const auto node: set) {
2112 auto new_pot_ev = schedule.insertTable< Tensor< GUM_SCALAR > >(*evidence[node],
false);
2113 pot_list.insert(new_pot_ev);
2117 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
2118 const IScheduleMultiDim* pot = fast_combination.schedule(schedule, pot_list);
2119 auto schedule_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
2120 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(pot));
2121 scheduler.execute(schedule);
2122 auto result = schedule_pot->exportMultiDim();
2132 NodeId clique_of_set;
2134 clique_of_set = _joint_target_to_clique_[set];
2141 for (
const auto node: targets) {
2142 if (!_graph_.exists(node)) {
2144 "The variable " << this->BN().variable(node).name() <<
"(" << node
2145 <<
") does not belong to this optimized inference.")
2151 const std::vector< NodeId >& JT_elim_order = _triangulation_->eliminationOrder();
2153 NodeProperty< int > elim_order(Size(JT_elim_order.size()));
2154 for (std::size_t i = std::size_t(0), size = JT_elim_order.size(); i < size; ++i)
2155 elim_order.insert(JT_elim_order[i], (
int)i);
2156 NodeId first_eliminated_node = *(targets.begin());
2157 int elim_number = elim_order[first_eliminated_node];
2158 for (
const auto node: targets) {
2159 if (elim_order[node] < elim_number) {
2160 elim_number = elim_order[node];
2161 first_eliminated_node = node;
2165 clique_of_set = _triangulation_->createdJunctionTreeClique(first_eliminated_node);
2169 const NodeSet& clique_nodes = _JT_->clique(clique_of_set);
2170 for (
const auto node: targets) {
2171 if (!clique_nodes.contains(node)) {
2173 this->BN().names(set) <<
"(" << set <<
")"
2174 <<
" is not addressable in this optimized inference.")
2179 _joint_target_to_clique_.
insert(set, clique_of_set);
2183 _collectMessage_(schedule, clique_of_set, clique_of_set);
2188 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[clique_of_set];
2191 for (
const auto other: _JT_->neighbours(clique_of_set))
2192 pot_list += _separator_tensors_[Arc(other, clique_of_set)];
2195 const NodeSet& nodes = _JT_->clique(clique_of_set);
2198 const auto& bn = this->BN();
2199 for (
const auto node: nodes) {
2200 if (!targets.contains(node)) {
2201 del_vars.
insert(&(bn.variable(node)));
2203 kept_vars.
insert(&(bn.variable(node)));
2209 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(schedule, pot_list, del_vars, kept_vars);
2210 ScheduleMultiDim< Tensor< GUM_SCALAR > >* resulting_pot =
nullptr;
2211 Tensor< GUM_SCALAR >* joint =
nullptr;
2213 if (new_pot_list.size() == 0) {
2214 joint =
new Tensor< GUM_SCALAR >();
2215 for (
const auto var: kept_vars)
2218 if ((new_pot_list.size() == 1) && hard_ev_nodes.empty()) {
2219 scheduler.execute(schedule);
2220 resulting_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
2221 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(*new_pot_list.begin()));
2225 for (
const auto node: hard_ev_nodes) {
2226 auto new_pot_ev = schedule.insertTable< Tensor< GUM_SCALAR > >(*evidence[node],
false);
2227 new_pot_list.insert(new_pot_ev);
2229 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
2230 const auto pot = fast_combination.schedule(schedule, new_pot_list);
2231 scheduler.execute(schedule);
2232 resulting_pot =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
2233 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(pot));
2238 if (pot_list.exists(resulting_pot)) {
2239 joint =
new Tensor< GUM_SCALAR >(resulting_pot->multiDim());
2241 joint = resulting_pot->exportMultiDim();
2248 bool nonzero_found =
false;
2249 for (Instantiation inst(*joint); !inst.end(); ++inst) {
2250 if ((*joint)[inst]) {
2251 nonzero_found =
true;
2255 if (!nonzero_found) {
2259 "some evidence entered into the Bayes "
2260 "net are incompatible (their joint proba = 0)");
2267 template <
typename GUM_SCALAR >
2268 Tensor< GUM_SCALAR >*
2269 LazyPropagation< GUM_SCALAR >::_unnormalizedJointPosterior_(
const NodeSet& set) {
2274 for (
const auto node: this->hardEvidenceNodes()) {
2275 if (targets.contains(node)) {
2276 targets.erase(node);
2277 hard_ev_nodes.insert(node);
2283 const auto& evidence = this->evidence();
2284 if (targets.empty()) {
2285 if (set.size() == 1) {
2286 return new Tensor< GUM_SCALAR >(*evidence[*set.begin()]);
2288 _TensorSet_ pot_list;
2289 for (
const auto node: set) {
2290 pot_list.insert(evidence[node]);
2294 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
2295 const Tensor< GUM_SCALAR >* pot = fast_combination.execute(pot_list);
2297 return const_cast< Tensor< GUM_SCALAR >*
>(pot);
2305 NodeId clique_of_set;
2307 clique_of_set = _joint_target_to_clique_[set];
2314 for (
const auto node: targets) {
2315 if (!_graph_.exists(node)) {
2317 "The variable " << this->BN().variable(node).name() <<
"(" << node
2318 <<
") does not belong to this optimized inference.")
2324 const std::vector< NodeId >& JT_elim_order = _triangulation_->eliminationOrder();
2326 NodeProperty< int > elim_order(Size(JT_elim_order.size()));
2327 for (std::size_t i = std::size_t(0), size = JT_elim_order.size(); i < size; ++i)
2328 elim_order.insert(JT_elim_order[i], (
int)i);
2329 NodeId first_eliminated_node = *(targets.begin());
2330 int elim_number = elim_order[first_eliminated_node];
2331 for (
const auto node: targets) {
2332 if (elim_order[node] < elim_number) {
2333 elim_number = elim_order[node];
2334 first_eliminated_node = node;
2338 clique_of_set = _triangulation_->createdJunctionTreeClique(first_eliminated_node);
2342 const NodeSet& clique_nodes = _JT_->clique(clique_of_set);
2343 for (
const auto node: targets) {
2344 if (!clique_nodes.contains(node)) {
2346 this->BN().names(set) <<
"(" << set <<
")"
2347 <<
" is not addressable in this optimized inference.")
2352 _joint_target_to_clique_.
insert(set, clique_of_set);
2356 _collectMessage_(clique_of_set, clique_of_set);
2361 _ScheduleMultiDimSet_ pot_list = _clique_tensors_[clique_of_set];
2364 for (
const auto other: _JT_->neighbours(clique_of_set))
2365 pot_list += _separator_tensors_[Arc(other, clique_of_set)];
2368 const NodeSet& nodes = _JT_->clique(clique_of_set);
2371 const auto& bn = this->BN();
2372 for (
const auto node: nodes) {
2373 if (!targets.contains(node)) {
2374 del_vars.
insert(&(bn.variable(node)));
2376 kept_vars.
insert(&(bn.variable(node)));
2382 _ScheduleMultiDimSet_ new_pot_list = _marginalizeOut_(pot_list, del_vars, kept_vars);
2383 Tensor< GUM_SCALAR >* joint =
nullptr;
2384 if (new_pot_list.empty()) {
2385 joint =
new Tensor< GUM_SCALAR >();
2386 for (
const auto var: kept_vars)
2389 if ((new_pot_list.size() == 1) && hard_ev_nodes.empty()) {
2390 auto sched_joint =
const_cast< ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(
2391 static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(*new_pot_list.begin()));
2395 if (pot_list.exists(sched_joint)) {
2396 joint =
new Tensor< GUM_SCALAR >(sched_joint->multiDim());
2398 joint = sched_joint->exportMultiDim();
2403 new_pot_list.clear();
2408 _TensorSet_ xnew_pot_list(new_pot_list.size());
2409 for (
auto xpot: new_pot_list) {
2410 xnew_pot_list.insert(
2411 &(
static_cast< const ScheduleMultiDim< Tensor< GUM_SCALAR >
>* >(xpot)->multiDim()));
2413 for (
const auto node: hard_ev_nodes) {
2414 xnew_pot_list.insert(evidence[node]);
2416 MultiDimCombinationDefault< Tensor< GUM_SCALAR > > fast_combination(_combination_op_);
2417 joint = fast_combination.execute(xnew_pot_list);
2424 for (
const auto pot: new_pot_list)
2425 if (!pot_list.exists(pot))
delete pot;
2429 bool nonzero_found =
false;
2430 for (Instantiation inst(*joint); !inst.end(); ++inst) {
2431 if ((*joint)[inst]) {
2432 nonzero_found =
true;
2436 if (!nonzero_found) {
2440 "some evidence entered into the Bayes "
2441 "net are incompatible (their joint proba = 0)");
2448 template <
typename GUM_SCALAR >
2449 const Tensor< GUM_SCALAR >& LazyPropagation< GUM_SCALAR >::jointPosterior_(
const NodeSet& set) {
2451 if (_joint_target_posteriors_.exists(set)) {
return *(_joint_target_posteriors_[set]); }
2454 auto joint = unnormalizedJointPosterior_(set);
2456 _joint_target_posteriors_.insert(set, joint);
2462 template <
typename GUM_SCALAR >
2463 const Tensor< GUM_SCALAR >&
2464 LazyPropagation< GUM_SCALAR >::jointPosterior_(
const NodeSet& wanted_target,
2465 const NodeSet& declared_target) {
2467 if (_joint_target_posteriors_.exists(wanted_target))
2468 return *(_joint_target_posteriors_[wanted_target]);
2474 if (!_joint_target_posteriors_.exists(declared_target)) { jointPosterior_(declared_target); }
2477 const auto& bn = this->BN();
2479 for (
const auto node: declared_target)
2480 if (!wanted_target.contains(node)) del_vars.
insert(&(bn.variable(node)));
2482 =
new Tensor< GUM_SCALAR >(_joint_target_posteriors_[declared_target]->sumOut(del_vars));
2485 _joint_target_posteriors_.insert(wanted_target, pot);
2490 template <
typename GUM_SCALAR >
2491 GUM_SCALAR LazyPropagation< GUM_SCALAR >::evidenceProbability() {
2494 RelevantTensorsFinderType old_relevant_type = _find_relevant_tensor_type_;
2499 if (old_relevant_type != RelevantTensorsFinderType::FIND_ALL) {
2500 _find_relevant_tensor_type_ = RelevantTensorsFinderType::FIND_ALL;
2501 _is_new_jt_needed_ =
true;
2502 this->setOutdatedStructureState_();
2506 this->makeInference();
2514 GUM_SCALAR prob_ev = 1;
2515 for (
const auto root: _roots_) {
2517 NodeId node = *(_JT_->clique(root).begin());
2518 Tensor< GUM_SCALAR >* tmp = unnormalizedJointPosterior_(node);
2519 prob_ev *= tmp->sum();
2523 for (
const auto& projected_cpt: _constants_)
2524 prob_ev *= projected_cpt.second;
2527 _find_relevant_tensor_type_ = old_relevant_type;
2532 template <
typename GUM_SCALAR >
2533 Instantiation LazyPropagation< GUM_SCALAR >::mpe() {
2536 RelevantTensorsFinderType old_relevant_type = _find_relevant_tensor_type_;
2541 if (old_relevant_type != RelevantTensorsFinderType::FIND_ALL) {
2542 _find_relevant_tensor_type_ = RelevantTensorsFinderType::FIND_ALL;
2543 _is_new_jt_needed_ =
true;
2544 this->setOutdatedStructureState_();
2548 auto old_projection_op = _projection_op_;
2549 auto new_projection_op = LPMaxprojTensor< GUM_SCALAR >;
2550 bool projection_op_changed = old_projection_op != new_projection_op;
2551 if (projection_op_changed) { this->_setProjectionFunction_(new_projection_op); }
2554 const auto in_target_mode = this->isInTargetMode();
2556 Set< NodeSet > old_joint_targets;
2557 if (in_target_mode) {
2558 old_targets = this->targets();
2559 old_joint_targets = this->jointTargets();
2560 this->eraseAllTargets();
2564 this->makeInference();
2567 Instantiation instantiations;
2568 for (
const auto& ev: this->hardEvidence()) {
2569 const auto& variable = this->BN().variable(ev.first);
2570 instantiations.add(variable);
2571 instantiations.chgVal(variable, ev.second);
2575 NodeProperty< bool > clique2marked = _JT_->nodesPropertyFromVal(
false);
2576 std::function< void(NodeId, NodeId) > diffuse_marks =
2577 [&clique2marked, &diffuse_marks, &instantiations,
this](NodeId clique, NodeId clique_from) {
2578 clique2marked[clique] =
true;
2583 auto clique_nodes = _JT_->clique(clique);
2584 auto pot = unnormalizedJointPosterior_(clique_nodes);
2585 auto pot_argmax = pot->extract(instantiations).argmax();
2587 const auto& new_instantiation = *(pot_argmax.first.begin());
2590 for (
const auto node: clique_nodes) {
2591 const auto& variable = this->BN().variable(node);
2592 if (!instantiations.contains(variable)) {
2593 instantiations.add(variable);
2594 instantiations.chgVal(variable, new_instantiation.val(variable));
2599 for (
const auto neigh: _JT_->neighbours(clique))
2600 if ((neigh != clique_from) && !clique2marked[neigh]) diffuse_marks(neigh, clique);
2605 for (
const auto& cliqueProp: clique2marked) {
2606 const auto clique = cliqueProp.first;
2607 if (!clique2marked[clique]) diffuse_marks(clique, clique);
2612 _find_relevant_tensor_type_ = old_relevant_type;
2615 if (projection_op_changed) { this->_setProjectionFunction_(old_projection_op); }
2618 if (in_target_mode) {
2619 for (
const auto node: old_targets) {
2620 this->addTarget(node);
2622 for (
const auto& set: old_joint_targets) {
2623 this->addJointTarget(set);
2628 return instantiations;
2631 template <
typename GUM_SCALAR >
2632 std::pair< Instantiation, GUM_SCALAR > LazyPropagation< GUM_SCALAR >::mpeLog2Posterior() {
2634 const auto instantiation = mpe();
2643 auto proba = (GUM_SCALAR)0.0;
2644 auto node_proba = (GUM_SCALAR)0.0;
2646 for (
const auto node: this->BN().dag()) {
2647 const auto& cpt = this->BN().cpt(node);
2648 if (!this->hasSoftEvidence(node)) {
2649 node_proba = cpt[instantiation];
2651 const auto& ev = *(this->evidence()[node]);
2652 node_proba = cpt[instantiation] * ev[instantiation];
2655 if (node_proba == (GUM_SCALAR)0)
2656 return {instantiation, std::numeric_limits< GUM_SCALAR >::lowest()};
2657 proba += (GUM_SCALAR)std::log2(node_proba);
2660 if (!this->hasEvidence())
return {instantiation, proba};
2661 else return {instantiation, proba - std::log2(this->evidenceProbability())};
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
Exception : the element we looked for cannot be found.
Size size() const noexcept
Returns the number of elements in the set.
iterator_safe beginSafe() const
The usual safe begin iterator to parse the set.
const iterator_safe & endSafe() const noexcept
The usual safe end iterator to parse the set.
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.
void erase(const Key &k)
Erases an element from 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 ...
Header files of gum::Instantiation.
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...