aGrUM  0.16.0
defaultJunctionTreeStrategy.cpp
Go to the documentation of this file.
1 
30 #include <numeric>
31 
32 #include <agrum/agrum.h>
35 
36 namespace gum {
37 
38  // default constructor
40  // for debugging purposes
41  GUM_CONSTRUCTOR(DefaultJunctionTreeStrategy);
42  }
43 
44  // copy constructor
46  const DefaultJunctionTreeStrategy& from) :
51  // for debugging purposes
52  GUM_CONS_CPY(DefaultJunctionTreeStrategy);
53  }
54 
55  // move constructor
58  JunctionTreeStrategy(std::move(from)),
60  __junction_tree(std::move(from.__junction_tree)),
62  // for debugging purposes
63  GUM_CONS_MOV(DefaultJunctionTreeStrategy);
64  }
65 
66  // destructor
68  // for debugging purposes
69  GUM_DESTRUCTOR(DefaultJunctionTreeStrategy);
70  }
71 
72  // clone factory
74  return new DefaultJunctionTreeStrategy;
75  }
76 
77  // virtual copy constructor
80  if (tr == nullptr) {
81  return new DefaultJunctionTreeStrategy(*this);
82  } else {
83  // here, we need to assign new triangulation "tr" to the new strategy
84 
85  // if there was already a triangulation associated with the current
86  // strategy, 2 cases can obtain:
87  // 1/ both __triangulation and tr point toward the same graph to be
88  // triangulated. In this case, no need to recompute anything
89  // 2/ they point toward different graphs. Then, we must indicate that
90  // the new strategy has not computed anything yet
91  if ((_triangulation != nullptr)
92  && (tr->originalGraph() == _triangulation->originalGraph())) {
93  auto new_strategy = new DefaultJunctionTreeStrategy(*this); // case 1/
94  new_strategy->_triangulation = tr;
95  return new_strategy;
96  } else { // case 2/
97  auto new_strategy = new DefaultJunctionTreeStrategy;
98  new_strategy->setTriangulation(tr);
99  return new_strategy;
100  }
101  }
102  }
103 
104  // indicates whether the junction tree strategy needs fill-ins to work
105  // properly
106  bool DefaultJunctionTreeStrategy::requiresFillIns() const { return false; }
107 
108  // assign the triangulation to the junction tree strategy
110  clear();
111  _triangulation = tr;
112  }
113 
114  // returns, for each node, the clique which was created by its deletion
116  // compute the junction tree only if it does not already exist
118 
120  }
121 
122  // returns the Id of the clique created by the elimination of a given
123  // node during the triangulation process */
125  // compute the junction tree only if it does not already exist
127 
128  return __node_2_junction_clique[id];
129  }
130 
131  // returns the junction tree asked by the triangulation
133  // compute the junction tree only if it does not already exist
135 
136  return __junction_tree;
137  }
138 
139  // resets the current junction tree strategy data structures
141  __has_junction_tree = false;
143  __node_2_junction_clique.clear();
144  }
145 
146  // computes a junction tree from an elimination tree
148  // if no triangulation is assigned to the strategy, we cannot compute
149  // the junction tree, so raise an exception
150  if (_triangulation == nullptr)
152  "No triangulation has been assigned to "
153  "the DefaultJunctionTreeStrategy");
154 
155  // copy the elimination tree into the junction tree
157 
158  // mark all the edges of the junction tree to false
160 
161  // create a vector indicating by which clique a given clique has been
162  // substituted during the transformation from the elimination tree to the
163  // junction tree. Assume that clique J of the elmination tree has been
164  // substituted by clique K of the elimination tree, and that clique J
165  // (resp. K) was the jth (resp. kth) one created during the triangulation
166  // process. Then, in the vector below, substitution[j] = k.
167  const std::vector< NodeId >& elim_order = _triangulation->eliminationOrder();
168 
169  auto size = elim_order.size();
170  std::vector< NodeId > substitution(size);
171  std::iota(substitution.begin(), substitution.end(), 0);
172 
173  // for all cliques C_i, from the last one created to the first one, check
174  // if there exists a parent C_j (a neighbor created before C_i) such that
175  // |C_j| = |C_i| + 1 and such that the edge is not marked. In this case,
176  // this means that C_j contains C_i. Hence, we should remove C_i, and link
177  // all of its neighbors to C_j. These links will be marked to true as no
178  // such neighbor can be included in C_j (and conversely).
179  if (size > 0) {
180  for (auto i = size; i >= 1; --i) {
181  const NodeId C_i = NodeId(i - 1);
182  const auto card_C_i_plus_1 = __junction_tree.clique(C_i).size() + 1;
183 
184  // search for C_j such that |C_j| = [C_i| + 1
185  NodeId C_j = C_i;
186 
187  for (const auto C_jj : __junction_tree.neighbours(C_i))
188  if ((C_i > C_jj) && !mark[Edge(C_jj, C_i)]
189  && (__junction_tree.clique(C_jj).size() == card_C_i_plus_1)) {
190  // ok, here we found a parent such that |C_jj| = [C_i| + 1
191  C_j = C_jj;
192  __junction_tree.eraseEdge(Edge(C_j, C_i));
193  break;
194  }
195 
196  // if we found a C_j, link the neighbors of C_i to C_j
197  if (C_j != C_i) {
198  for (const auto nei : __junction_tree.neighbours(C_i)) {
199  __junction_tree.addEdge(C_j, nei);
200  mark.insert(Edge(C_j, nei), true);
201  }
202 
203  // remove C_i
204  substitution[C_i] = C_j;
206  }
207  }
208  }
209 
210  // compute the transitive closure of vector substitution
211  for (std::size_t i = 0; i < size; ++i)
212  substitution[i] = substitution[substitution[i]];
213 
214  // using the transitive closure of vector substitution, compute for each
215  // node the clique of the junction tree that was created by its
216  // elimination during the triangulation
217  for (NodeId i = NodeId(0); i < size; ++i) {
218  __node_2_junction_clique.insert(elim_order[i], substitution[i]);
219  }
220 
221  __has_junction_tree = true;
222  }
223 
224 } /* namespace gum */
virtual NodeId createdClique(const NodeId id) final
returns the Id of the clique of the junction tree created by the elimination of a given node during t...
const UndiGraph * originalGraph() const
returns the graph to be triangulated
virtual DefaultJunctionTreeStrategy * copyFactory(StaticTriangulation *triangulation=nullptr) const final
virtual copy constructor
virtual void eraseNode(const NodeId node)
removes a given clique from the clique graph
virtual DefaultJunctionTreeStrategy * newFactory() const final
create a clone not assigned to any triangulation algorithm
STL namespace.
virtual void clear()
removes all the cliques and separators from the graph (as well as their adjacent edges) ...
virtual void setTriangulation(StaticTriangulation *triangulation) final
assigns the triangulation to the junction tree strategy
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
StaticTriangulation * _triangulation
the triangulation to which the junction tree is associated
The class for generic Hash Tables.
Definition: hashTable.h:679
void __computeJunctionTree()
computes a junction tree from an elimination tree
const NodeSet & neighbours(const NodeId id) const
returns the set of edges adjacent to a given node
EdgeProperty< VAL > edgesProperty(VAL(*f)(const Edge &), Size size=0) const
a method to create a hashMap of VAL from a set of edges (using for every edge, say x...
const CliqueGraph & eliminationTree()
returns the elimination tree of a compatible ordering
NodeProperty< NodeId > __node_2_junction_clique
indicates which clique of the junction tree was created by the elimination of a given node (the key o...
virtual const NodeProperty< NodeId > & createdCliques() final
returns, for each node, the clique of the junction tree which was created by its deletion ...
const std::vector< NodeId > & eliminationOrder()
returns an elimination ordering compatible with the triangulated graph
virtual void eraseEdge(const Edge &edge)
removes an edge (and its separator) from the clique graph
Base Class for all the algorithms producing a junction given a set of cliques/subcliques resulting fr...
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
virtual bool requiresFillIns() const final
indicates whether the junction tree strategy needs fill-ins to work properly
virtual void addEdge(const NodeId first, const NodeId second)
inserts a new edge between two cliques
const NodeSet & clique(const NodeId idClique) const
returns the set of nodes included into a given clique
Basic graph of cliques.
Definition: cliqueGraph.h:58
CliqueGraph __junction_tree
the junction tree computed by the algorithm
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
The base class for all undirected edges.
virtual void clear() final
resets the current junction tree strategy data structures
base class for all non-incremental triangulation methods
virtual const CliqueGraph & junctionTree() final
returns the junction tree computed
Size size() const noexcept
Returns the number of elements in the set.
Definition: set_tpl.h:701
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
bool __has_junction_tree
a boolean indicating whether the junction tree has been constructed
Size NodeId
Type for node ids.
Definition: graphElements.h:98
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55
An algorithm producing a junction given the elimination tree produced by a triangulation algorithm...