63#ifndef DOXYGEN_SHOULD_SKIP_THIS
71 Triangulation(domsizes), _triangulation_(triang_algo.newFactory()) {
72 GUM_CONSTRUCTOR(IncrementalTriangulation);
75 _triangulation_->clear();
80 for (
const auto node: *theGraph)
81 addNode(node, (*domsizes)[node]);
85 for (
const auto& edge: theGraph->edges())
86 addEdge(edge.first(), edge.second());
90 IncrementalTriangulation::IncrementalTriangulation(
91 const UnconstrainedTriangulation& triang_algo) : _triangulation_(triang_algo.newFactory()) {
92 GUM_CONSTRUCTOR(IncrementalTriangulation);
95 _triangulation_->clear();
99 IncrementalTriangulation::IncrementalTriangulation(
const IncrementalTriangulation& from) :
100 Triangulation(from), _graph_(from._graph_), _junction_tree_(from._junction_tree_),
101 _T_mpd_(from._T_mpd_), _mps_of_node_(from._mps_of_node_),
102 _cliques_of_mps_(from._cliques_of_mps_), _mps_of_clique_(from._mps_of_clique_),
103 _mps_affected_(from._mps_affected_), _triangulation_(from._triangulation_->newFactory()),
104 _require_update_(from._require_update_),
105 _require_elimination_order_(from._require_elimination_order_),
106 _elimination_order_(from._elimination_order_),
107 _reverse_elimination_order_(from._reverse_elimination_order_),
108 _require_created_JT_cliques_(from._require_created_JT_cliques_),
109 _created_JT_cliques_(from._created_JT_cliques_) {
110 GUM_CONS_CPY(IncrementalTriangulation);
112 _domain_sizes_ = from._domain_sizes_;
115 IncrementalTriangulation::IncrementalTriangulation(IncrementalTriangulation&& from) :
116 Triangulation(
std::move(from)), _graph_(
std::move(from._graph_)),
117 _junction_tree_(
std::move(from._junction_tree_)), _T_mpd_(
std::move(from._T_mpd_)),
118 _mps_of_node_(
std::move(from._mps_of_node_)),
119 _cliques_of_mps_(
std::move(from._cliques_of_mps_)),
120 _mps_of_clique_(
std::move(from._mps_of_clique_)),
121 _mps_affected_(
std::move(from._mps_affected_)), _triangulation_(from._triangulation_),
122 _require_update_(from._require_update_),
123 _require_elimination_order_(from._require_elimination_order_),
124 _elimination_order_(
std::move(from._elimination_order_)),
125 _reverse_elimination_order_(
std::move(from._reverse_elimination_order_)),
126 _require_created_JT_cliques_(from._require_created_JT_cliques_),
127 _created_JT_cliques_(
std::move(from._created_JT_cliques_)) {
128 from._triangulation_ =
nullptr;
129 _domain_sizes_ = std::move(from._domain_sizes_);
130 GUM_CONS_MOV(IncrementalTriangulation);
134 IncrementalTriangulation::~IncrementalTriangulation() {
135 GUM_DESTRUCTOR(IncrementalTriangulation);
138 delete _triangulation_;
142 IncrementalTriangulation* IncrementalTriangulation::newFactory()
const {
143 return new IncrementalTriangulation(*_triangulation_);
147 IncrementalTriangulation* IncrementalTriangulation::copyFactory()
const {
148 return new IncrementalTriangulation(*
this);
152 IncrementalTriangulation&
153 IncrementalTriangulation::operator=(
const IncrementalTriangulation& from) {
156 GUM_OP_CPY(IncrementalTriangulation)
159 _graph_ = from._graph_;
160 _domain_sizes_ = from._domain_sizes_;
161 _junction_tree_ = from._junction_tree_;
162 _T_mpd_ = from._T_mpd_;
163 _mps_of_node_ = from._mps_of_node_;
164 _cliques_of_mps_ = from._cliques_of_mps_;
165 _mps_of_clique_ = from._mps_of_clique_;
166 _mps_affected_ = from._mps_affected_;
167 _require_update_ = from._require_update_;
168 _require_elimination_order_ = from._require_elimination_order_;
169 _elimination_order_ = from._elimination_order_;
170 _reverse_elimination_order_ = from._reverse_elimination_order_;
171 _require_created_JT_cliques_ = from._require_created_JT_cliques_;
172 _created_JT_cliques_ = from._created_JT_cliques_;
176 delete _triangulation_;
177 _triangulation_ = from._triangulation_->newFactory();
184 IncrementalTriangulation& IncrementalTriangulation::operator=(IncrementalTriangulation&& from) {
186 GUM_OP_MOV(IncrementalTriangulation);
188 _graph_ = std::move(from._graph_);
189 _domain_sizes_ = std::move(from._domain_sizes_);
190 _junction_tree_ = std::move(from._junction_tree_);
191 _T_mpd_ = std::move(from._T_mpd_);
192 _mps_of_node_ = std::move(from._mps_of_node_);
193 _cliques_of_mps_ = std::move(from._cliques_of_mps_);
194 _mps_of_clique_ = std::move(from._mps_of_clique_);
195 _mps_affected_ = std::move(from._mps_affected_);
196 _require_update_ = from._require_update_;
197 _require_elimination_order_ = from._require_elimination_order_;
198 _elimination_order_ = std::move(from._elimination_order_);
199 _reverse_elimination_order_ = std::move(from._reverse_elimination_order_);
200 _require_created_JT_cliques_ = from._require_created_JT_cliques_;
201 _created_JT_cliques_ = std::move(from._created_JT_cliques_);
203 delete _triangulation_;
204 _triangulation_ = from._triangulation_;
205 from._triangulation_ =
nullptr;
212 void IncrementalTriangulation::addNode(
const NodeId node, Size modal) {
214 if (_graph_.existsNode(node))
return;
217 _graph_.addNodeWithId(node);
218 _domain_sizes_.insert(node, modal);
222 clique_nodes.insert(node);
224 NodeId MPS = _T_mpd_.addNode(clique_nodes);
225 NodeId new_clique = _junction_tree_.addNode(clique_nodes);
228 List< NodeId >& list_of_mps = _mps_of_node_.insert(node, List< NodeId >()).second;
229 list_of_mps.insert(MPS);
232 std::vector< NodeId >& cliquesMPS
233 = _cliques_of_mps_.insert(MPS, std::vector< NodeId >()).second;
235 cliquesMPS.push_back(new_clique);
236 _mps_of_clique_.insert(new_clique, MPS);
239 _mps_affected_.insert(MPS,
false);
242 _elimination_order_.push_back(node);
244 if (!_reverse_elimination_order_.exists(node))
245 _reverse_elimination_order_.insert(node, Size(_elimination_order_.size()));
247 if (!_created_JT_cliques_.exists(node)) _created_JT_cliques_.insert(node, new_clique);
252 void IncrementalTriangulation::_markAffectedMPSsByRemoveLink_(
const NodeId My,
256 _mps_affected_[My] =
true;
259 for (
const auto nei: _T_mpd_.neighbours(My))
261 const NodeSet& Syk = _T_mpd_.separator(
Edge(nei, My));
263 if (Syk.contains(edge.first()) && Syk.contains(edge.second()))
264 _markAffectedMPSsByRemoveLink_(nei, My, edge);
270 void IncrementalTriangulation::eraseEdge(
const Edge& edge) {
272 if (!_graph_.existsEdge(edge))
return;
275 const NodeId X = edge.first();
276 const NodeId Y = edge.second();
278 const List< NodeId >& mps1 = _mps_of_node_[X];
279 const List< NodeId >& mps2 = _mps_of_node_[Y];
283 if (mps1.size() <= mps2.size()) {
284 for (
const auto node: mps1)
285 if (_T_mpd_.clique(node).contains(Y)) {
290 for (
const auto node: mps2)
291 if (_T_mpd_.clique(node).contains(X)) {
298 _markAffectedMPSsByRemoveLink_(Mx, Mx, edge);
300 _require_update_ =
true;
302 _require_elimination_order_ =
true;
304 _require_created_JT_cliques_ =
true;
307 _graph_.eraseEdge(edge);
313 void IncrementalTriangulation::eraseNode(
const NodeId X) {
315 if (!_graph_.existsNode(X))
return;
319 const NodeSet& neighbours = _graph_.neighbours(X);
321 for (
auto neighbour_edge = neighbours.beginSafe();
322 neighbour_edge != neighbours.endSafe();
324 eraseEdge(
Edge(*neighbour_edge, X));
328 auto& MPS_of_X = _mps_of_node_[X];
331 for (
const auto node: MPS_of_X) {
332 _T_mpd_.eraseFromClique(node, X);
336 auto& neighbours = _T_mpd_.neighbours(node);
338 for (
auto it_neighbour = neighbours.beginSafe(); it_neighbour != neighbours.endSafe();
340 Edge neigh(*it_neighbour, node);
342 if (_T_mpd_.separator(neigh).size() == 0) _T_mpd_.eraseEdge(neigh);
347 for (
const auto clique: MPS_of_X) {
348 const std::vector< NodeId >& cliques_of_X = _cliques_of_mps_[clique];
350 for (
unsigned int i = 0; i < cliques_of_X.size(); ++i) {
351 _junction_tree_.eraseFromClique(cliques_of_X[i], X);
356 auto& neighbours = _junction_tree_.neighbours(cliques_of_X[i]);
358 for (
auto it_neighbour = neighbours.beginSafe(); it_neighbour != neighbours.endSafe();
360 Edge neigh(*it_neighbour, cliques_of_X[i]);
362 if (_junction_tree_.separator(neigh).size() == 0) {
365 bool hasCommonEdge =
false;
367 for (
const auto node1: _junction_tree_.clique(neigh.first()))
368 for (
const auto node2: _junction_tree_.clique(neigh.second()))
369 if (_graph_.existsEdge(node1, node2)) {
370 hasCommonEdge =
true;
374 if (!hasCommonEdge) { _junction_tree_.eraseEdge(neigh); }
382 if ((MPS_of_X.size() == 1) && (_T_mpd_.clique(MPS_of_X[0]).size() == 0)) {
383 _junction_tree_.eraseNode(_cliques_of_mps_[MPS_of_X[0]][0]);
384 _T_mpd_.eraseNode(MPS_of_X[0]);
385 _mps_of_clique_.erase(_cliques_of_mps_[MPS_of_X[0]][0]);
386 _cliques_of_mps_.erase(MPS_of_X[0]);
387 _mps_affected_.erase(MPS_of_X[0]);
390 _mps_of_node_.erase(X);
394 if (!_require_update_) {
395 if (!_reverse_elimination_order_.exists(X))
397 for (Idx i = _reverse_elimination_order_[X] + 1; i < _reverse_elimination_order_.size(); ++i)
398 _elimination_order_[i - 1] = _elimination_order_[i];
400 _elimination_order_.pop_back();
402 _reverse_elimination_order_.erase(X);
404 _created_JT_cliques_.erase(X);
408 _graph_.eraseNode(X);
410 _domain_sizes_.erase(X);
415 int IncrementalTriangulation::_markAffectedMPSsByAddLink_(const NodeId Mx,
424 const NodeSet& cliqueMX = _T_mpd_.clique(Mx);
426 if (cliqueMX.contains(Y)) {
427 _mps_affected_[Mx] = true;
429 if (cliqueMX.contains(X)) return 2;
435 for (
const auto other_node: _T_mpd_.neighbours(Mx))
436 if (other_node != Mz) {
437 int neighbourStatus = _markAffectedMPSsByAddLink_(other_node, Mx, X, Y);
439 if (neighbourStatus == 2)
return 2;
440 else if (neighbourStatus == 1) {
441 _mps_affected_[Mx] =
true;
443 if (cliqueMX.contains(X))
return 2;
455 void IncrementalTriangulation::addEdge(
const NodeId X,
const NodeId Y) {
457 if ((X == Y) || !_graph_.existsNode(X) || !_graph_.existsNode(Y)
458 || _graph_.existsEdge(
Edge(X, Y)))
462 _graph_.addEdge(X, Y);
465 NodeId& mps_X = _mps_of_node_[X][0];
467 int found = _markAffectedMPSsByAddLink_(mps_X, mps_X, X, Y);
472 NodeId& mps_Y = _mps_of_node_[Y][0];
477 const std::vector< NodeId >& cliques_X = _cliques_of_mps_[mps_X];
478 const std::vector< NodeId >& cliques_Y = _cliques_of_mps_[mps_Y];
479 NodeId c_X = 0, c_Y = 0;
481 for (
unsigned int i = 0; i < cliques_X.size(); ++i) {
482 if (_junction_tree_.clique(cliques_X[i]).contains(X)) {
488 for (
unsigned int i = 0; i < cliques_Y.size(); ++i) {
489 if (_junction_tree_.clique(cliques_Y[i]).contains(Y)) {
502 NodeId newNode = _junction_tree_.addNode(nodes);
504 _junction_tree_.addEdge(newNode, c_X);
505 _junction_tree_.addEdge(newNode, c_Y);
507 NodeId newMPS = _T_mpd_.addNode(nodes);
509 _T_mpd_.addEdge(newMPS, mps_X);
510 _T_mpd_.addEdge(newMPS, mps_Y);
516 if (_T_mpd_.clique(mps_X).size() == 1) {
517 _junction_tree_.eraseNode(c_X);
518 _T_mpd_.eraseNode(mps_X);
519 _mps_affected_.erase(mps_X);
520 _mps_of_clique_.erase(c_X);
521 _cliques_of_mps_.erase(mps_X);
522 _created_JT_cliques_[X] = newNode;
524 }
else _mps_of_node_[X].insert(newMPS);
527 if (_T_mpd_.clique(mps_Y).size() == 1) {
528 _junction_tree_.eraseNode(c_Y);
529 _T_mpd_.eraseNode(mps_Y);
530 _mps_affected_.erase(mps_Y);
531 _mps_of_clique_.erase(c_Y);
532 _cliques_of_mps_.erase(mps_Y);
533 _created_JT_cliques_[Y] = newNode;
535 }
else _mps_of_node_[Y].insert(newMPS);
537 std::vector< NodeId >& cl = _cliques_of_mps_.insert(newMPS, std::vector< NodeId >()).second;
539 cl.push_back(newNode);
541 _mps_of_clique_.insert(newNode, newMPS);
543 _mps_affected_.insert(newMPS,
false);
545 _require_update_ =
true;
546 _require_created_JT_cliques_ =
true;
550 _require_elimination_order_ =
true;
553 bool IncrementalTriangulation::checkConsistency() {
555 updateTriangulation();
561 NodeProperty< bool > nodesProp = _graph_.nodesPropertyFromVal<
bool >(
false);
563 for (
const auto cliq: _junction_tree_.nodes())
564 for (
const auto node: _junction_tree_.clique(cliq))
565 nodesProp[node] =
true;
567 for (
const auto& elt: nodesProp)
569 std::cerr <<
"check nodes" << std::endl
570 << _graph_ << std::endl
571 << _junction_tree_ << std::endl;
575 if (!OK)
return false;
580 std::pair< NodeId, NodeId > thePair;
581 EdgeProperty< bool > edgesProp = _graph_.edgesProperty(
false);
583 for (
const auto cliq: _junction_tree_.nodes()) {
584 const NodeSet& clique = _junction_tree_.clique(cliq);
586 for (
auto iter2 = clique.begin(); iter2 != clique.end(); ++iter2) {
589 for (++iter3; iter3 != clique.end(); ++iter3) {
590 thePair.first = std::min(*iter2, *iter3);
591 thePair.second = std::max(*iter2, *iter3);
593 if (_graph_.existsEdge(thePair.first, thePair.second))
594 edgesProp[
Edge(thePair.first, thePair.second)] =
true;
599 for (
const auto& elt: edgesProp)
601 std::cerr <<
"check edges" << std::endl
602 << _graph_ << std::endl
603 << _junction_tree_ << std::endl;
607 if (!OK)
return false;
612 NodeProperty< bool > nodesProp = _graph_.nodesPropertyFromVal<
bool >(
false);
614 for (
const auto cliq: _T_mpd_.nodes())
615 for (
const auto node: _T_mpd_.clique(cliq))
616 nodesProp[node] =
true;
618 for (
const auto& elt: nodesProp)
620 std::cerr <<
"check nodes" << std::endl << _graph_ << std::endl << _T_mpd_ << std::endl;
624 if (!OK)
return false;
629 std::pair< NodeId, NodeId > thePair;
630 EdgeProperty< bool > edgesProp = _graph_.edgesProperty(
false);
632 for (
const auto cliq: _T_mpd_.nodes()) {
633 const NodeSet& clique = _T_mpd_.clique(cliq);
635 for (
auto iter2 = clique.begin(); iter2 != clique.end(); ++iter2) {
638 for (++iter3; iter3 != clique.end(); ++iter3) {
639 thePair.first = std::min(*iter2, *iter3);
640 thePair.second = std::max(*iter2, *iter3);
642 if (_graph_.existsEdge(thePair.first, thePair.second))
643 edgesProp[
Edge(thePair.first, thePair.second)] =
true;
648 for (
const auto& elt: edgesProp)
650 std::cerr <<
"check edges" << std::endl << _graph_ << std::endl << _T_mpd_ << std::endl;
654 if (!OK)
return false;
659 NodeProperty< NodeProperty< bool > > chk;
661 for (
const auto node: _graph_.nodes())
662 chk.insert(node, HashTable< NodeId, bool >());
664 for (
const auto cliq: _T_mpd_.nodes())
665 for (
auto node: _T_mpd_.clique(cliq))
666 chk[node].insert(cliq,
false);
668 for (
const auto& elt: _mps_of_node_) {
669 HashTable< NodeId, bool >& hash = chk[elt.first];
671 for (
const auto cell: elt.second) {
672 if (!hash.exists(cell)) {
673 std::cerr <<
"check mps of nodes" << std::endl
674 << _T_mpd_ << std::endl
675 << _mps_of_node_ << std::endl;
683 for (
const auto& elt: chk)
684 for (
const auto& elt2: elt.second)
686 std::cerr <<
"check mps of nodes2" << std::endl
687 << _T_mpd_ << std::endl
688 << _mps_of_node_ << std::endl;
692 if (!OK)
return false;
697 if (!_junction_tree_.isJoinTree()) {
698 std::cerr <<
"check join tree _junction_tree_" << std::endl
699 << _junction_tree_ << std::endl;
703 if (!_T_mpd_.isJoinTree()) {
704 std::cerr <<
"check join tree _T_mpd_" << std::endl << _T_mpd_ << std::endl;
713 if (_elimination_order_.size() != _graph_.size()) {
714 std::cerr <<
"check elimination order" << std::endl << _elimination_order_ << std::endl;
720 for (
const auto node: _graph_.nodes()) {
721 if (nodes.exists(node)) {
722 std::cerr <<
"check elimination order" << std::endl << _elimination_order_ << std::endl;
724 }
else nodes.insert(node);
727 if (nodes.size() != _graph_.size()) {
728 std::cerr <<
"check elimination order" << std::endl << _elimination_order_ << std::endl;
732 if (_reverse_elimination_order_.size() != _graph_.size()) {
733 std::cerr <<
"check reverse elimination order" << std::endl
734 << _reverse_elimination_order_ << std::endl;
738 for (
const auto node: _graph_.nodes()) {
739 if (!_reverse_elimination_order_.exists(node)) {
740 std::cerr <<
"check reverse elimination order" << std::endl
741 << _reverse_elimination_order_ << std::endl;
749 createdJunctionTreeCliques();
751 if (_created_JT_cliques_.size() != _graph_.size()) {
752 std::cerr <<
"check creating JT cliques" << std::endl << _created_JT_cliques_ << std::endl;
756 for (
const auto node: _graph_.nodes()) {
757 if (!_created_JT_cliques_.exists(node)
758 || !_junction_tree_.existsNode(_created_JT_cliques_[node])) {
759 std::cerr <<
"check created JT cliques" << std::endl << _created_JT_cliques_ << std::endl;
770 void IncrementalTriangulation::_setUpConnectedTriangulation_(
774 std::vector< Edge >& notAffectedneighbourCliques,
775 HashTable< NodeId, bool >& cliques_affected) {
777 cliques_affected[Mx] =
false;
780 for (
const auto node: _junction_tree_.clique(Mx))
781 if (!theGraph.exists(node)) theGraph.addNodeWithId(node);
784 for (
const auto othernode: _junction_tree_.neighbours(Mx))
785 if (othernode != Mfrom) {
786 if (cliques_affected.exists(othernode)) {
787 _setUpConnectedTriangulation_(othernode,
790 notAffectedneighbourCliques,
795 notAffectedneighbourCliques.push_back(
Edge(othernode, Mx));
802 void IncrementalTriangulation::_updateJunctionTree_(NodeProperty< bool >& all_cliques_affected,
803 NodeSet& new_nodes_in_junction_tree) {
811 std::vector< Edge > notAffectedneighbourCliques;
815 for (
const auto& elt: _mps_affected_)
818 const std::vector< NodeId >& cliques = _cliques_of_mps_[elt.first];
820 for (
unsigned int i = 0; i < cliques.size(); ++i)
821 all_cliques_affected.insert(cliques[i],
true);
826 for (
const auto& elt: all_cliques_affected) {
831 notAffectedneighbourCliques.clear();
832 _setUpConnectedTriangulation_(elt.first,
835 notAffectedneighbourCliques,
836 all_cliques_affected);
839 for (
auto edge: _graph_.edges()) {
841 tmp_graph.addEdge(edge.first(), edge.second());
842 }
catch (Exception
const&) {}
850 for (
const auto node: tmp_graph.nodes()) {
851 List< NodeId >& mps = _mps_of_node_[node];
853 for (HashTableConstIteratorSafe< NodeId, bool > iter_mps
854 = _mps_affected_.beginSafe();
855 iter_mps != _mps_affected_.endSafe();
857 if (iter_mps.val()) mps.eraseByVal(iter_mps.key());
863 _triangulation_->setGraph(&tmp_graph, &_domain_sizes_);
865 const CliqueGraph& tmp_junction_tree = _triangulation_->junctionTree();
871 NodeProperty< NodeId > tmp2global_junction_tree(tmp_junction_tree.size());
873 for (
const auto cliq: tmp_junction_tree.nodes()) {
877 NodeId new_id = _junction_tree_.addNode(tmp_junction_tree.clique(cliq));
879 tmp2global_junction_tree.insert(cliq, new_id);
880 new_nodes_in_junction_tree.insert(new_id);
884 for (
const auto& edge: tmp_junction_tree.edges())
885 _junction_tree_.addEdge(tmp2global_junction_tree[edge.first()],
886 tmp2global_junction_tree[edge.second()]);
898 for (
unsigned int i = 0; i < notAffectedneighbourCliques.size(); ++i) {
901 const NodeSet& sep = _junction_tree_.separator(notAffectedneighbourCliques[i]);
903 if (sep.size() != 0) {
905 Size _elim_order_ = tmp_graph.bound() + 1;
906 NodeId elim_node = 0;
908 for (
const auto id: sep) {
909 Size new_order = _triangulation_->eliminationOrder(
id);
911 if (new_order < _elim_order_) {
912 _elim_order_ = new_order;
923 = tmp2global_junction_tree[_triangulation_->createdJunctionTreeClique(elim_node)];
926 = all_cliques_affected.exists(notAffectedneighbourCliques[i].first())
927 ? notAffectedneighbourCliques[i].second()
928 : notAffectedneighbourCliques[i].first();
930 _junction_tree_.addEdge(not_affected, to_connect);
932 if (!new_nodes_in_junction_tree.contains(to_connect)) {
933 _T_mpd_.addEdge(_mps_of_clique_[to_connect], _mps_of_clique_[not_affected]);
939 if (_junction_tree_.separator(not_affected, to_connect).size()
940 == _junction_tree_.clique(to_connect).size()) {
941 _junction_tree_.eraseEdge(
Edge(not_affected, to_connect));
943 for (
const auto neighbour: _junction_tree_.neighbours(to_connect)) {
944 _junction_tree_.addEdge(neighbour, not_affected);
946 if (!new_nodes_in_junction_tree.contains(neighbour))
947 _T_mpd_.addEdge(_mps_of_clique_[neighbour], _mps_of_clique_[not_affected]);
950 _junction_tree_.eraseNode(to_connect);
952 to_connect = not_affected;
960 for (
const auto& elt: all_cliques_affected) {
961 _mps_of_clique_.erase(elt.first);
962 _junction_tree_.eraseNode(elt.first);
965 for (
const auto& elt: _mps_affected_)
967 _cliques_of_mps_.erase(elt.first);
968 _T_mpd_.eraseNode(elt.first);
974 void IncrementalTriangulation::_computeMaxPrimeMergings_(
977 std::vector< std::pair< NodeId, NodeId > >& merged_cliques,
978 HashTable< NodeId, bool >& mark,
979 const NodeSet& new_nodes_in_junction_tree)
const {
983 for (
const auto other_node: _junction_tree_.neighbours(node))
984 if (other_node != from) {
985 const NodeSet& separator = _junction_tree_.separator(
Edge(other_node, node));
988 bool complete =
true;
990 for (
auto iter_sep1 = separator.begin(); iter_sep1 != separator.end() && complete;
992 auto iter_sep2 = iter_sep1;
994 for (++iter_sep2; iter_sep2 != separator.end(); ++iter_sep2) {
995 if (!_graph_.existsEdge(*iter_sep1, *iter_sep2)) {
1003 if (!complete) merged_cliques.push_back(std::pair< NodeId, NodeId >(other_node, node));
1005 if (new_nodes_in_junction_tree.contains(other_node))
1006 _computeMaxPrimeMergings_(other_node,
1010 new_nodes_in_junction_tree);
1016 void IncrementalTriangulation::_updateMaxPrimeSubgraph_(
1017 NodeProperty< bool >& all_cliques_affected,
1018 const NodeSet& new_nodes_in_junction_tree) {
1027 HashTable< NodeId, NodeId > T_mpd_cliques(all_cliques_affected.size());
1029 for (
const auto clik: _junction_tree_.nodes())
1030 if (new_nodes_in_junction_tree.contains(clik)) T_mpd_cliques.insert(clik, clik);
1034 std::vector< std::pair< NodeId, NodeId > > merged_cliques;
1036 HashTable< NodeId, bool > mark = T_mpd_cliques.map(
false);
1038 for (
const auto& elt: mark)
1040 _computeMaxPrimeMergings_(elt.first,
1044 new_nodes_in_junction_tree);
1049 for (
unsigned int i = 0; i < merged_cliques.size(); ++i) {
1050 if (T_mpd_cliques.exists(merged_cliques[i].second))
1051 T_mpd_cliques[merged_cliques[i].first] = T_mpd_cliques[merged_cliques[i].second];
1052 else T_mpd_cliques[merged_cliques[i].first] = _mps_of_clique_[merged_cliques[i].second];
1059 NodeProperty< NodeId > clique2MPS(T_mpd_cliques.size());
1063 for (
const auto& elt: T_mpd_cliques)
1064 if (elt.first == elt.second) {
1065 NodeId newId = _T_mpd_.addNode(_junction_tree_.clique(elt.second));
1066 clique2MPS.insert(elt.second, newId);
1067 std::vector< NodeId >& vect_of_cliques
1068 = _cliques_of_mps_.insert(newId, std::vector< NodeId >()).second;
1069 vect_of_cliques.push_back(elt.second);
1074 for (
const auto& elt: T_mpd_cliques)
1075 if ((elt.first != elt.second) && (new_nodes_in_junction_tree.contains(elt.second))) {
1076 const NodeId idMPS = clique2MPS[elt.second];
1078 for (
const auto node: _junction_tree_.clique(elt.first)) {
1080 _T_mpd_.addToClique(idMPS, node);
1084 _cliques_of_mps_[idMPS].push_back(elt.first);
1088 for (
const auto& elt: T_mpd_cliques) {
1089 const NodeId idMPS = clique2MPS[elt.second];
1090 _mps_of_clique_.insert(elt.first, idMPS);
1092 if (elt.first == elt.second)
1093 for (
const auto node: _T_mpd_.clique(idMPS))
1094 _mps_of_node_[node].insert(idMPS);
1098 for (
const auto& elt: T_mpd_cliques) {
1099 NodeId clique = clique2MPS[elt.second];
1101 for (
const auto othernode: _junction_tree_.neighbours(elt.first))
1102 if (T_mpd_cliques.exists(othernode)) {
1105 NodeId otherClique = clique2MPS[T_mpd_cliques[othernode]];
1108 if (clique > otherClique) { _T_mpd_.addEdge(clique, otherClique); }
1110 _T_mpd_.addEdge(clique, _mps_of_clique_[othernode]);
1117 void IncrementalTriangulation::updateTriangulation() {
1118 if (!_require_update_)
return;
1121 NodeProperty< bool > all_cliques_affected(_junction_tree_.size());
1129 NodeSet new_nodes_in_junction_tree;
1131 _updateJunctionTree_(all_cliques_affected, new_nodes_in_junction_tree);
1134 _updateMaxPrimeSubgraph_(all_cliques_affected, new_nodes_in_junction_tree);
1137 _mps_affected_.clear();
1139 for (
const auto node: _T_mpd_.nodes())
1140 _mps_affected_.insert(node,
false);
1143 _triangulation_->clear();
1145 _require_update_ =
false;
1150 void IncrementalTriangulation::clear() {
1152 _domain_sizes_.clear();
1153 _junction_tree_.clear();
1155 _mps_of_node_.clear();
1156 _cliques_of_mps_.clear();
1157 _mps_of_clique_.clear();
1158 _mps_affected_.clear();
1159 _triangulation_->clear();
1160 _require_update_ =
false;
1161 _require_elimination_order_ =
false;
1162 _elimination_order_.clear();
1163 _reverse_elimination_order_.clear();
1164 _require_created_JT_cliques_ =
false;
1165 _created_JT_cliques_.clear();
1170 void IncrementalTriangulation::_collectJTCliques_(
const NodeId clique,
1172 NodeProperty< bool >& examined) {
1174 for (
const auto otherclique: _junction_tree_.neighbours(clique))
1175 if (otherclique != from) _collectJTCliques_(otherclique, clique, examined);
1178 examined[clique] =
true;
1180 const NodeSet& cliquenodes = _junction_tree_.clique(clique);
1182 if (from != clique) {
1183 const NodeSet& separator = _junction_tree_.separator(clique, from);
1185 for (
const auto cli: cliquenodes)
1186 if (!separator.contains(cli)) _created_JT_cliques_.
insert(cli, clique);
1188 for (
const auto cli: cliquenodes)
1189 _created_JT_cliques_.insert(cli, clique);
1196 const NodeProperty< NodeId >& IncrementalTriangulation::createdJunctionTreeCliques() {
1198 if (!_require_created_JT_cliques_)
return _created_JT_cliques_;
1201 updateTriangulation();
1203 _created_JT_cliques_.clear();
1205 _require_created_JT_cliques_ =
false;
1207 if (_junction_tree_.size() == 0) {
return _created_JT_cliques_; }
1210 NodeProperty< bool > examined = _junction_tree_.nodesPropertyFromVal<
bool >(
false);
1212 for (
const auto& elt: examined)
1213 if (!elt.second) _collectJTCliques_(elt.first, elt.first, examined);
1215 return _created_JT_cliques_;
1220 NodeId IncrementalTriangulation::createdJunctionTreeClique(NodeId
id) {
1221 createdJunctionTreeCliques();
1222 return _created_JT_cliques_[id];
1228 NodeId IncrementalTriangulation::createdMaxPrimeSubgraph(
const NodeId
id) {
1230 return _mps_of_clique_[createdJunctionTreeClique(
id)];
1235 void IncrementalTriangulation::setGraph(
const UndiGraph* graph,
1236 const NodeProperty< Size >* dom_sizes) {
1239 if (((graph !=
nullptr) && (dom_sizes ==
nullptr))
1240 || ((graph ==
nullptr) && (dom_sizes !=
nullptr))) {
1242 "one of the graph or the set of domain sizes "
1243 "is a null pointer.");
1251 if (graph !=
nullptr) {
1252 for (
const auto node: *graph)
1253 addNode(node, (*dom_sizes)[node]);
1255 for (
const auto& edge: graph->edges())
1256 addEdge(edge.first(), edge.second());
1262 void IncrementalTriangulation::_collectEliminationOrder_(
const NodeId node,
1264 NodeProperty< bool >& examined,
1267 for (
const auto othernode: _junction_tree_.neighbours(node))
1268 if (othernode != from) _collectEliminationOrder_(othernode, node, examined, index);
1271 examined[node] =
true;
1273 const NodeSet& clique = _junction_tree_.clique(node);
1276 const NodeSet& separator = _junction_tree_.separator(node, from);
1278 for (
const auto cli: clique) {
1279 if (!separator.contains(cli)) {
1280 _elimination_order_[index] = cli;
1281 _reverse_elimination_order_.insert(cli, index);
1286 for (
const auto cli: clique) {
1287 _elimination_order_[index] = cli;
1288 _reverse_elimination_order_.insert(cli, index);
1296 const std::vector< NodeId >& IncrementalTriangulation::eliminationOrder() {
1298 if (!_require_elimination_order_)
return _elimination_order_;
1301 updateTriangulation();
1303 _elimination_order_.resize(_graph_.size());
1305 _reverse_elimination_order_.clear();
1307 _require_elimination_order_ =
false;
1309 if (_junction_tree_.size() == Size(0)) {
return _elimination_order_; }
1314 NodeProperty< bool > examined = _junction_tree_.nodesPropertyFromVal<
bool >(
false);
1316 for (
const auto& elt: examined)
1317 if (!elt.second) _collectEliminationOrder_(elt.first, elt.first, examined, index);
1319 return _elimination_order_;
1325 Idx IncrementalTriangulation::eliminationOrder(
const NodeId node) {
1326 if (!_graph_.existsNode(node)) {
GUM_ERROR(
NotFound,
"the node " << node <<
" does not exist") }
1331 return _reverse_elimination_order_[node];
Exception : a similar element already exists.
Exception base for graph error.
IncrementalTriangulation(const UnconstrainedTriangulation &triang_algo, const UndiGraph *theGraph, const NodeProperty< Size > *modal)
constructor
Exception : the element we looked for cannot be found.
void insert(const Key &k)
Inserts a new element into the set.
Interface for all the triangulation methods.
Interface for all triangulation methods without constraints on node elimination orderings.
Base class for undirected graphs.
#define GUM_ERROR(type, msg)
HashTable< NodeId, VAL > NodeProperty
Property on graph elements.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
Class for computing default triangulations of graphs.
Inline implementations for computing default triangulations of graphs.
Generic class for manipulating lists.
gum is the global namespace for all aGrUM entities
Base classes for undirected graphs.