aGrUM  0.14.2
staticTriangulation.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005 by Christophe GONZALES and Pierre-Henri WUILLEMIN *
3  * {prenom.nom}_at_lip6.fr *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
30 
31 #ifdef GUM_NO_INLINE
33 #endif // GUM_NO_INLINE
34 
35 namespace gum {
36 
37  // default constructor
39  const UndiGraph* theGraph,
40  const NodeProperty< Size >* domsizes,
41  const EliminationSequenceStrategy& elimSeq,
42  const JunctionTreeStrategy& JTStrategy,
43  bool minimality) :
44  Triangulation(domsizes),
45  _elimination_sequence_strategy(elimSeq.newFactory()),
46  _junction_tree_strategy(JTStrategy.newFactory()), __original_graph(theGraph),
47  __minimality_required(minimality) {
48  // for debugging purposes
49  GUM_CONSTRUCTOR(StaticTriangulation);
50 
51  // if the graph is not empty, resize several structures in order to speed-up
52  // their fillings.
53  if (theGraph != nullptr) {
54  __elim_order.resize(theGraph->size());
55  __reverse_elim_order.resize(theGraph->size());
56  __elim_cliques.resize(theGraph->size());
57  __node_2_max_prime_clique.resize(theGraph->size());
58  __added_fill_ins.resize(theGraph->size());
59  }
60 
61  // register the triangulation to its junction tree strategy
63  }
64 
65  // default constructor
67  const EliminationSequenceStrategy& elimSeq,
68  const JunctionTreeStrategy& JTStrategy,
69  bool minimality) :
71  _junction_tree_strategy(JTStrategy.newFactory()),
72  __minimality_required(minimality) {
73  // for debugging purposes
74  GUM_CONSTRUCTOR(StaticTriangulation);
75 
76  // register the triangulation to its junction tree strategy
78  }
79 
80  // copy constructor
98  // copy the strategies
102 
103  // if from has a junction tree, copy it
104  if (from.__junction_tree != nullptr) {
106  }
107 
108  // for debugging purposes
109  GUM_CONS_CPY(StaticTriangulation);
110  }
111 
112  // move constructor
114  Triangulation(std::move(from)),
119  __fill_ins(std::move(from.__fill_ins)),
120  __elim_order(std::move(from.__elim_order)),
122  __elim_cliques(std::move(from.__elim_cliques)),
123  __elim_tree(std::move(from.__elim_tree)),
135  // move the factories contained in from
136  from._elimination_sequence_strategy = new DefaultEliminationSequenceStrategy;
137  from._junction_tree_strategy = new DefaultJunctionTreeStrategy;
139 
140  // if from has a junction tree, copy it
141  if (from.__junction_tree != nullptr) {
143  }
144 
145  // for debugging purposes
146  GUM_CONS_MOV(StaticTriangulation);
147  }
148 
151  // for debugging purposes
152  GUM_DESTRUCTOR(StaticTriangulation);
153 
156 
157  // no need to deallocate __original_graph nor __junction_tree because
158  // they are not owned by the static triangulation class
159  }
160 
163  // clear the factories
166 
167  // remove the current graphs
168  __original_graph = nullptr;
169  __junction_tree = nullptr;
171  __elim_tree.clear();
173  __elim_cliques.clear();
175 
176  // remove all fill-ins and orderings
177  __fill_ins.clear();
178  __added_fill_ins.clear();
179  __elim_order.clear();
180  __reverse_elim_order.clear();
181 
182  // indicates that the junction tree, the max prime tree, etc, are updated
183  __has_triangulation = true;
185  __has_elimination_tree = true;
186  __has_junction_tree = true;
188  __has_fill_ins = true;
189  }
190 
191  // removes redondant fill-ins and compute proper elimination cliques and order
193  // apply recursive thinning (fmint, see Kjaerulff (90), "triangulation of
194  // graphs - algorithms giving small total state space")
195  NodeId node1, node2;
196  bool incomplete;
197  std::vector< NodeId > adj;
198  EdgeSet T_prime;
200 
201  for (const auto node : __triangulated_graph)
202  R.insert(node, 0);
203 
204  // the FMINT loop
205  if (__added_fill_ins.size() > 0) {
206  for (auto iter = __added_fill_ins.rbegin(); iter != __added_fill_ins.rend();
207  ++iter) {
208  if (iter->size()) {
209  // here apply MINT to T_i = __added_fill_ins[i]
210  EdgeSet& T = *iter;
211 
212  // compute R: by default, R is equal to all the nodes in the graph
213  // when R[...] >= j (see the j in the loop below), this means that the
214  // node belongs to an extremal edge in R
215  for (std::size_t k = 0; k < __elim_order.size(); ++k)
216  R[__elim_order[k]] =
217  0; // WARNING: do not replace R[__elim_order[k]] by
218 
219  // R[k] because the node ids may not be
220  // consecutive numbers
221 
222  // apply MINT while some edges can possibly be deleted
223  bool require_mint = true;
224 
225  for (unsigned int j = 0; require_mint; ++j) {
226  // find T' (it is equal to the edges (v,w) of T such that
227  // the intersection of adj(v,G) and adj(w,G) is complete and such
228  // that
229  // v and/or w belongs to an extremal node in R
230  for (const auto& edge : T) {
231  node1 = edge.first();
232  node2 = edge.second();
233 
234  // check if at least one extremal node belongs to R
235  if ((R[node1] < j) && (R[node2] < j)) continue;
236 
237  // check if the intersection of adj(v,G) and adj(w,G) is a
238  // complete subgraph
239  if (__triangulated_graph.neighbours(node2).size()
240  < __triangulated_graph.neighbours(node1).size()) {
241  NodeId tmp = node1;
242  node1 = node2;
243  node2 = tmp;
244  }
245 
246  incomplete = false;
247 
248  // find the nodes belonging to the intersection of adj(v,G)
249  // and adj(w,G)
250  for (const auto adjnode : __triangulated_graph.neighbours(node1))
251  if (__triangulated_graph.existsEdge(node2, adjnode))
252  adj.push_back(adjnode);
253 
254  // check if the intersection is complete
255  for (unsigned int k = 0; k < adj.size() && !incomplete; ++k) {
256  for (unsigned int m = k + 1; m < adj.size(); ++m) {
257  if (!__triangulated_graph.existsEdge(adj[k], adj[m])) {
258  incomplete = true;
259  break;
260  }
261  }
262  }
263 
264  adj.clear();
265 
266  if (!incomplete) {
267  T_prime.insert(edge);
268  R[node1] = j + 1;
269  R[node2] = j + 1;
270  }
271  }
272 
273  // compute the new value of T (i.e. T\T') and update the
274  // triangulated graph
275  for (const auto& edge : T_prime) {
276  T.erase(edge);
277  __triangulated_graph.eraseEdge(edge);
278 
279  if (__has_fill_ins) __fill_ins.erase(edge);
280  }
281 
282  if (T_prime.size() == 0) require_mint = false;
283 
284  T_prime.clear();
285  }
286  }
287  }
288  }
289 
290  // here, the recursive thinning has removed all the superfluous edges.
291  // Hence some cliques have been split and, as a result, the elimination
292  // order has changed. We should thus compute a new perfect ordering. To
293  // do so, we use a Maximal Cardinality Search: it has indeed the nice
294  // property that, when the graph is already triangulated, it finds a
295  // compatible order of elimination that does not require any edge addition
296 
297  // a structure storing the number of neighbours previously processed
299  numbered_neighbours(std::greater< unsigned int >(),
300  __triangulated_graph.size());
301 
302  for (Size i = 0; i < __elim_order.size(); ++i)
303  numbered_neighbours.insert(__elim_order[i], 0);
304 
305  // perform the maximum cardinality search
306  if (__elim_order.size() > 0) {
307  for (Size i = Size(__elim_order.size()); i >= 1; --i) {
308  NodeId ni = NodeId(i - 1);
309  NodeId node = numbered_neighbours.pop();
310  __elim_order[ni] = node;
311  __reverse_elim_order[node] = ni;
312 
313  for (const auto neighbour : __triangulated_graph.neighbours(node)) {
314  try {
315  numbered_neighbours.setPriority(
316  neighbour, 1 + numbered_neighbours.priority(neighbour));
317  } catch (NotFound&) {}
318  }
319  }
320  }
321 
322  // here the elimination order is ok. We now need to update the
323  // __elim_cliques
324  for (Size i = 0; i < __elim_order.size(); ++i) {
325  NodeSet& cliques = __elim_cliques.insert(__elim_order[i], NodeSet()).second;
326  cliques << __elim_order[i];
327 
328  for (const auto neighbour : __triangulated_graph.neighbours(__elim_order[i]))
329  if (__reverse_elim_order[neighbour] > i) cliques << neighbour;
330  }
331  }
332 
335  // if there already exists an elimination tree, no need to compute it again
336  if (__has_elimination_tree) return;
337 
338  // if the graph is not triangulated, triangulate it
340 
341  // create the nodes of the elimination tree
342  __elim_tree.clear();
343 
344  Size size = Size(__elim_order.size());
345  for (NodeId i = NodeId(0); i < size; ++i)
347 
348  // create the edges of the elimination tree: join a node to the one in
349  // its clique that is eliminated first
350  for (NodeId i = NodeId(0); i < size; ++i) {
351  NodeId clique_i_creator = __elim_order[i];
352  const NodeSet& list_of_nodes = __elim_cliques[clique_i_creator];
353  Idx child = __original_graph->bound() + 1;
354 
355  for (const auto node : list_of_nodes) {
356  Idx it_elim_step = __reverse_elim_order[node];
357 
358  if ((node != clique_i_creator) && (child > it_elim_step))
359  child = it_elim_step;
360  }
361 
362  if (child <= __original_graph->bound()) {
363  // WARNING: here, we assume that the nodes of the elimination tree are
364  // indexed from 0 to n-1
365  __elim_tree.addEdge(i, child);
366  }
367  }
368 
369  __has_elimination_tree = true;
370  }
371 
374  const NodeId node,
375  const NodeId from,
376  std::vector< Arc >& merged_cliques,
377  NodeSet& mark) const {
378  mark << node;
379 
380  for (const auto other_node : __junction_tree->neighbours(node))
381  if (other_node != from) {
382  const NodeSet& separator = __junction_tree->separator(node, other_node);
383  // check that the separator between node and other_node is complete
384  bool complete = true;
385 
386  for (auto iter_sep1 = separator.begin();
387  iter_sep1 != separator.end() && complete;
388  ++iter_sep1) {
389  auto iter_sep2 = iter_sep1;
390 
391  for (++iter_sep2; iter_sep2 != separator.end(); ++iter_sep2) {
392  if (!__original_graph->existsEdge(*iter_sep1, *iter_sep2)) {
393  complete = false;
394  break;
395  }
396  }
397  }
398 
399  // here complete indicates whether the separator is complete or not
400  if (!complete) merged_cliques.push_back(Arc(other_node, node));
401 
402  __computeMaxPrimeMergings(other_node, node, merged_cliques, mark);
403  }
404  }
405 
408  // if there already exists a max prime junction tree, no need
409  // to recompute it
410  if (__has_max_prime_junction_tree) return;
411 
412  // if there is no junction tree, create it
414 
415  // the maximal prime subgraph join tree is created by aggregation of some
416  // cliques. More precisely, when the separator between 2 cliques is not
417  // complete in the original graph, then the two cliques must be merged.
418  // Create a hashtable indicating which clique has been absorbed by some
419  // other
420  // clique.
421  NodeProperty< NodeId > T_mpd_cliques(__junction_tree->size());
422 
423  for (const auto clik : __junction_tree->nodes())
424  T_mpd_cliques.insert(clik, clik);
425 
426  // parse all the separators of the junction tree and test those that are not
427  // complete in the orginal graph
428  std::vector< Arc > merged_cliques;
429 
430  NodeSet mark;
431 
432  for (const auto clik : __junction_tree->nodes())
433  if (!mark.contains(clik))
434  __computeMaxPrimeMergings(clik, clik, merged_cliques, mark);
435 
436  // compute the transitive closure of merged_cliques. This one will contain
437  // pairs (X,Y) indicating that clique X must be merged with clique Y.
438  // Actually clique X will be inserted into clique Y.
439  for (unsigned int i = 0; i < merged_cliques.size(); ++i) {
440  T_mpd_cliques[merged_cliques[i].tail()] =
441  T_mpd_cliques[merged_cliques[i].head()];
442  }
443 
444  // now we can create the max prime junction tree. First, create the cliques
445  for (const auto& elt : T_mpd_cliques)
446  if (elt.first == elt.second)
448  __junction_tree->clique(elt.second));
449 
450  // add to the cliques previously created the nodes of the cliques that were
451  // merged into them
452  for (const auto& elt : T_mpd_cliques)
453  if (elt.first != elt.second)
454  for (const auto node : __junction_tree->clique(elt.first)) {
455  try {
456  __max_prime_junction_tree.addToClique(elt.second, node);
457  } catch (DuplicateElement&) {}
458  }
459 
460  // add the edges to the graph
461  for (const auto& edge : __junction_tree->edges()) {
462  NodeId node1 = T_mpd_cliques[edge.first()];
463  NodeId node2 = T_mpd_cliques[edge.second()];
464 
465  if (node1 != node2) {
466  try {
467  __max_prime_junction_tree.addEdge(node1, node2);
468  } catch (DuplicateElement&) {}
469  }
470  }
471 
472  // compute for each node which clique of the max prime junction tree was
473  // created by the elimination of the node
474  const NodeProperty< NodeId >& node_2_junction_clique =
476 
477  for (const auto& elt : node_2_junction_clique)
478  __node_2_max_prime_clique.insert(elt.first, T_mpd_cliques[elt.second]);
479 
481  }
482 
486 
487  // if we did not construct the triangulated graph during the triangulation,
488  // that is, we just constructed the junction tree, we shall construct it now
490  // just in case, be sure that the junction tree has been constructed
492 
493  // copy the original graph
495 
496  for (const auto clik_id : *__junction_tree) {
497  // for each clique, add the edges necessary to make it complete
498  const NodeSet& clique = __junction_tree->clique(clik_id);
499  std::vector< NodeId > clique_nodes(clique.size());
500  unsigned int i = 0;
501 
502  for (const auto node : clique) {
503  clique_nodes[i] = node;
504  i += 1;
505  }
506 
507  for (i = 0; i < clique_nodes.size(); ++i) {
508  for (unsigned int j = i + 1; j < clique_nodes.size(); ++j) {
509  try {
510  __triangulated_graph.addEdge(clique_nodes[i], clique_nodes[j]);
511  } catch (DuplicateElement&) {}
512  }
513  }
514  }
515 
517  }
518 
519  return __triangulated_graph;
520  }
521 
522  // initialize the triangulation algorithm for a new graph
524  const NodeProperty< Size >* domsizes) {
525  // remove the old graph
526  clear();
527 
528  if (graph != nullptr) {
529  // prepare the size of the data for the new graph
530  __elim_order.resize(graph->size());
531  __reverse_elim_order.resize(graph->size());
532  __elim_cliques.resize(graph->size());
533  __added_fill_ins.resize(graph->size());
534  __node_2_max_prime_clique.resize(graph->size());
535  }
536 
537  // keep track of the variables passed in argument
538  __original_graph = graph;
539  _domain_sizes = domsizes;
540 
541  // indicate that no triangulation was performed for this graph
542  __has_triangulation = false;
543  __has_triangulated_graph = false;
544  __has_elimination_tree = false;
545  __has_junction_tree = false;
547  __has_fill_ins = false;
548  }
549 
552  // if the graph is already triangulated, no need to triangulate it again
553  if (__has_triangulation) return;
554 
555  // copy the graph to be triangulated, so that we can modify it
556  UndiGraph tmp_graph = *__original_graph;
557 
558  _initTriangulation(tmp_graph);
560 
561  // if we are to do recursive thinning, we will have to add fill-ins to the
562  // triangulated graph each time we eliminate a node. Hence, we shall
563  // initialize the triangulated graph by a copy of the original graph
564  if (__minimality_required) {
567  }
568 
569  // perform the triangulation
570  NodeId removable_node = 0;
571 
572  for (unsigned int nb_elim = 0; tmp_graph.size() != 0; ++nb_elim) {
574 
575  // when minimality is not required, i.e., we won't apply recursive
576  // thinning, the cliques sets can be computed
577  if (!__minimality_required) {
578  NodeSet& cliques = __elim_cliques.insert(removable_node, NodeSet()).second;
579  cliques.resize(tmp_graph.neighbours(removable_node).size() / 2);
580  cliques << removable_node;
581  for (const auto clik : tmp_graph.neighbours(removable_node))
582  cliques << clik;
583  } else {
584  // here recursive thinning will be applied, hence we need store the
585  // fill-ins added by the current node removal
586  EdgeSet& current_fill = __added_fill_ins[nb_elim];
587  NodeId node1, node2;
588 
589  const NodeSet& nei = tmp_graph.neighbours(removable_node);
590 
591  for (auto iter_edges1 = nei.begin(); iter_edges1 != nei.end();
592  ++iter_edges1) {
593  node1 = *iter_edges1;
594  auto iter_edges2 = iter_edges1;
595 
596  for (++iter_edges2; iter_edges2 != nei.end(); ++iter_edges2) {
597  node2 = *iter_edges2;
598  Edge edge(node1, node2);
599 
600  if (!tmp_graph.existsEdge(edge)) {
601  current_fill.insert(edge);
602  __triangulated_graph.addEdge(node1, node2);
603  }
604  }
605  }
606  }
607 
608  // if we want fill-ins but the elimination sequence strategy does not
609  // compute them, we shall compute them here
612  NodeId node1, node2;
613 
614  // add edges between removable_node's neighbours in order to create
615  // a clique
616  const NodeSet& nei = tmp_graph.neighbours(removable_node);
617 
618  for (auto iter_edges1 = nei.begin(); iter_edges1 != nei.end();
619  ++iter_edges1) {
620  node1 = *iter_edges1;
621  auto iter_edges2 = iter_edges1;
622 
623  for (++iter_edges2; iter_edges2 != nei.end(); ++iter_edges2) {
624  node2 = *iter_edges2;
625  Edge edge(node1, node2);
626 
627  if (!tmp_graph.existsEdge(edge)) { __fill_ins.insert(edge); }
628  }
629  }
630 
631  // delete removable_node and its adjacent edges
632  tmp_graph.eraseNode(removable_node);
633  }
634 
635  // inform the elimination sequence that we are actually removing
636  // removable_node (this enables, for instance, to update the weights of
637  // the nodes in the graph)
639 
641  NodeId node1, node2;
642 
643  const NodeSet& nei = tmp_graph.neighbours(removable_node);
644 
645  for (auto iter_edges1 = nei.begin(); iter_edges1 != nei.end();
646  ++iter_edges1) {
647  node1 = *iter_edges1;
648  auto iter_edges2 = iter_edges1;
649 
650  for (++iter_edges2; iter_edges2 != nei.end(); ++iter_edges2) {
651  node2 = *iter_edges2;
652  Edge edge(node1, node2);
653 
654  if (!tmp_graph.existsEdge(edge)) { tmp_graph.addEdge(node1, node2); }
655  }
656  }
657 
658  tmp_graph.eraseNode(removable_node);
659  }
660 
661  // update the elimination order
662  __elim_order[nb_elim] = removable_node;
663  __reverse_elim_order.insert(removable_node, nb_elim);
664  }
665 
666  // indicate whether we actually computed fill-ins
668 
669  // if minimality is required, remove the redondant edges
671 
672  __has_triangulation = true;
673  }
674 
677  // if we did not compute the triangulation yet, do it and commpute
678  // the fill-ins at the same time
679  if (!__has_triangulation) {
680  bool want_fill_ins = __we_want_fill_ins;
681  __we_want_fill_ins = true;
682  __triangulate();
683  __we_want_fill_ins = want_fill_ins;
684  __has_fill_ins = true;
685  }
686 
687  // here, we already computed a triangulation and we already computed
688  // the fill-ins, so return them
689  if (__has_fill_ins) {
692  else
693  return __fill_ins;
694  } else {
695  // ok, here, we shall compute the fill-ins as they were not precomputed
696  if (!__original_graph) return __fill_ins;
697 
698  // just in case, be sure that the junction tree has been constructed
700 
701  for (const auto clik_id : __junction_tree->nodes()) {
702  // for each clique, add the edges necessary to make it complete
703  const NodeSet& clique = __junction_tree->clique(clik_id);
704  std::vector< NodeId > clique_nodes(clique.size());
705  unsigned int i = 0;
706 
707  for (const auto node : clique) {
708  clique_nodes[i] = node;
709  i += 1;
710  }
711 
712  for (i = 0; i < clique_nodes.size(); ++i) {
713  for (unsigned int j = i + 1; j < clique_nodes.size(); ++j) {
714  Edge edge(clique_nodes[i], clique_nodes[j]);
715 
716  if (!__original_graph->existsEdge(edge)) {
717  try {
718  __fill_ins.insert(edge);
719  } catch (DuplicateElement&) {}
720  }
721  }
722  }
723  }
724 
725  return __fill_ins;
726  }
727  }
728 
732  }
733 
734 } /* namespace gum */
const CliqueGraph & junctionTree()
returns a compatible junction tree
bool contains(const Key &k) const
Indicates whether a given elements belong to the set.
Definition: set_tpl.h:578
virtual void clear()
clears the sequence (to prepare, for instance, a new elimination sequence)
const UndiGraph & triangulatedGraph()
returns the triangulated graph
virtual void eliminationUpdate(const NodeId node)
performs all the graph/fill-ins updates provided (if any)
virtual const EdgeSet & fillIns()
in case fill-ins are provided, this function returns the fill-ins due to all the nodes eliminated so ...
NodeId addNode(const NodeSet &clique)
adds a new clique to the graph
virtual const NodeProperty< NodeId > & createdCliques()=0
returns, for each node, the clique of the junction tree which was created by its deletion ...
virtual void clear()
removes all the nodes and edges from the graph
Definition: undiGraph_inl.h:40
void clear()
reinitialize the graph to be triangulated to an empty graph
virtual EliminationSequenceStrategy * copyFactory() const =0
virtual copy constructor
NodeProperty< NodeId > __node_2_max_prime_clique
indicates which clique of the max prime junction tree was created by the elmination of a given node (...
void __triangulate()
the function that performs the triangulation
bool __has_max_prime_junction_tree
indicates whether a maximal prime subgraph junction tree has been constructed
const NodeSet & separator(const Edge &edge) const
returns the separator included in a given edge
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
virtual ~StaticTriangulation()
destructor
EliminationSequenceStrategy * _elimination_sequence_strategy
the elimination sequence strategy used by the triangulation
const UndiGraph * __original_graph
a pointer to the (external) original graph (which will be triangulated)
virtual void _initTriangulation(UndiGraph &graph)
the function called to initialize the triangulation process
Size size() const
alias for sizeNodes
virtual void addEdge(const NodeId first, const NodeId second)
insert a new edge into the undirected graph
Definition: undiGraph_inl.h:32
const EdgeSet & fillIns()
returns the fill-ins added by the triangulation algorithm
STL namespace.
void __computeMaxPrimeJunctionTree()
computes the junction tree of the maximal prime subgraphs
bool __has_triangulated_graph
a boolean indicating whether we have constructed the triangulated graph
virtual void clear()
removes all the cliques and separators from the graph (as well as their adjacent edges) ...
JunctionTreeStrategy * _junction_tree_strategy
the junction tree strategy used by the triangulation
void erase(const Key &k)
Erases an element from the set.
Definition: set_tpl.h:653
UndiGraph __triangulated_graph
the triangulated graph
gum is the global namespace for all aGrUM entities
Definition: agrum.h:25
NodeProperty< NodeId > __reverse_elim_order
the elimination order (access by NodeId)
const iterator & end() const noexcept
The usual unsafe end iterator to parse the set.
Definition: set_tpl.h:527
iterator begin() const
The usual unsafe begin iterator to parse the set.
Definition: set_tpl.h:514
std::vector< EdgeSet > __added_fill_ins
a vector containing the set of fill-ins added after each node elimination (used by recursive thinning...
The class for generic Hash Tables.
Definition: hashTable.h:676
An efficient unconstrained elimination sequence algorithm.
const NodeProperty< Size > * _domain_sizes
the domain sizes of the variables/nodes of the graph
const NodeSet & neighbours(const NodeId id) const
returns the set of edges adjacent to a given node
virtual void eraseNode(const NodeId id)
remove a node and its adjacent edges from the graph
Definition: undiGraph_inl.h:55
bool __has_triangulation
a boolean indicating whether we have parformed a triangulation
virtual void clear()=0
resets the current junction tree strategy data structures
const EdgeSet & edges() const
returns the set of edges stored within the EdgeGraphPart
A priorityQueue is a heap in which each element has a mutable priorityA priority queue is quite simil...
Definition: priorityQueue.h:48
virtual JunctionTreeStrategy * copyFactory(StaticTriangulation *triangulation=nullptr) const =0
virtual copy constructor
virtual void addToClique(const NodeId clique_id, const NodeId node_id)
changes the set of nodes included into a given clique and returns the new set
bool __has_junction_tree
a boolean indicating whether the junction tree has been constructed
bool existsEdge(const Edge &edge) const
indicates whether a given edge exists
void resize(Size new_capacity)
Changes the size of the underlying hash table containing the set.
Definition: set_tpl.h:549
virtual void setTriangulation(StaticTriangulation *triangulation)=0
assigns the triangulation to the junction tree strategy
The base class for all directed edgesThis class is used as a basis for manipulating all directed edge...
CliqueGraph __max_prime_junction_tree
the maximal prime subgraph junction tree computed from the junction tree
Base Class for all the algorithms producing a junction given a set of cliques/subcliques resulting fr...
const NodeGraphPart & nodes() const
return *this as a NodeGraphPart
base class for all non-incremental triangulations.
virtual bool providesGraphUpdate() const =0
indicates whether the elimination sequence updates by itself the graph after a node has been eliminat...
virtual NodeId nextNodeToEliminate()=0
returns the new node to be eliminated within the triangulation algorithm
virtual void addEdge(const NodeId first, const NodeId second)
inserts a new edge between two cliques
NodeProperty< NodeSet > __elim_cliques
the cliques formed by the elimination of the nodes
Size insert(const Val &val, const Priority &priority)
Inserts a new (a copy) element in the priority queue.
const NodeSet & clique(const NodeId idClique) const
returns the set of nodes included into a given clique
priority queues (in which an element cannot appear more than once)
An algorithms producing a junction given the elimination tree produced by the triangulation algorithm...
virtual StaticTriangulation * newFactory() const =0
returns a fresh triangulation of the same type as the current object but over an empty graph ...
virtual bool setGraph(UndiGraph *graph, const NodeProperty< Size > *dom_sizes)
sets a new graph to be triangulated
The base class for all elimination sequence algorithms used by triangulation algorithms.
The base class for all undirected edges.
bool __we_want_fill_ins
a boolean indicating if we want fill-ins list with the standard triangulation method ...
bool __has_fill_ins
indicates whether we actually computed fill-ins
bool __minimality_required
indicates whether the triangulation must be minimal
NodeId bound() const
returns a number n such that all node ids are strictly lower than n
base class for all non-incremental triangulation methods
const CliqueGraph * __junction_tree
the junction tree computed by the algorithm
void __computeEliminationTree()
returns an elimination tree from a triangulated graph
Base class for undirected graphs.
Definition: undiGraph.h:106
Size Idx
Type for indexes.
Definition: types.h:50
bool __has_elimination_tree
a boolean indicating whether the elimination tree has been computed
An efficient unconstrained elimination sequence algorithm.
virtual void setGraph(const UndiGraph *graph, const NodeProperty< Size > *domsizes)
initialize the triangulation data structures for a new graph
void clear()
Removes all the elements, if any, from the set.
Definition: set_tpl.h:372
void __computeMaxPrimeMergings(const NodeId node, const NodeId from, std::vector< Arc > &merged_cliques, NodeSet &mark) const
used for computing the junction tree of the maximal prime subgraphs
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition: types.h:45
EdgeSet __fill_ins
the fill-ins added during the whole triangulation process
Interface for all the triangulation methods.
Definition: triangulation.h:44
Size size() const noexcept
Returns the number of elements in the set.
Definition: set_tpl.h:698
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
void __computeRecursiveThinning()
removes redondant fill-ins and compute proper elimination cliques and order
virtual const CliqueGraph & junctionTree()=0
returns the junction tree computed
std::vector< NodeId > __elim_order
the order in which nodes are eliminated by the algorithm
virtual void moveTriangulation(StaticTriangulation *triangulation)
assigns a new triangulation to the junction tree strategy during a move construction ...
Size NodeId
Type for node ids.
Definition: graphElements.h:97
void insert(const Key &k)
Inserts a new element into the set.
Definition: set_tpl.h:610
virtual bool providesFillIns() const =0
indicates whether the fill-ins generated by the eliminated nodes, if needed, will be computed by the ...
CliqueGraph __elim_tree
the elimination tree computed by the algorithm
StaticTriangulation(const EliminationSequenceStrategy &elimSeq, const JunctionTreeStrategy &JTStrategy, bool minimality=false)
default constructor: without any graph
Inline implementations for computing default triangulations of graphs.
virtual void askFillIns(bool do_it)=0
if the elimination sequence is able to compute fill-ins, we indicate whether we want this feature to ...
An algorithm producing a junction given the elimination tree produced by a triangulation algorithm...