aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
defaultJunctionTreeStrategy.cpp
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2025 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2025 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40
41
48
49#include <numeric>
50
51#include <agrum/agrum.h>
52
55
56namespace gum {
57
58 // default constructor
62
63 // copy constructor
71
72 // move constructor
79
80 // destructor
85
86 // clone factory
90
91 // virtual copy constructor
94 if (tr == nullptr) {
95 return new DefaultJunctionTreeStrategy(*this);
96 } else {
97 // here, we need to assign new triangulation "tr" to the new strategy
98
99 // if there was already a triangulation associated with the current
100 // strategy, 2 cases can obtain:
101 // 1/ both _triangulation_ and tr point toward the same graph to be
102 // triangulated. In this case, no need to recompute anything
103 // 2/ they point toward different graphs. Then, we must indicate that
104 // the new strategy has not computed anything yet
105 if ((triangulation_ != nullptr) && (tr->originalGraph() == triangulation_->originalGraph())) {
106 auto new_strategy = new DefaultJunctionTreeStrategy(*this); // case 1/
107 new_strategy->triangulation_ = tr;
108 return new_strategy;
109 } else { // case 2/
110 auto new_strategy = new DefaultJunctionTreeStrategy;
111 new_strategy->setTriangulation(tr);
112 return new_strategy;
113 }
114 }
115 }
116
117 // indicates whether the junction tree strategy needs fill-ins to work
118 // properly
119 bool DefaultJunctionTreeStrategy::requiresFillIns() const { return false; }
120
121 // assign the triangulation to the junction tree strategy
126
127 // returns, for each node, the clique which was created by its deletion
129 // compute the junction tree only if it does not already exist
131
133 }
134
135 // returns the Id of the clique created by the elimination of a given
136 // node during the triangulation process */
138 // compute the junction tree only if it does not already exist
140
141 return _node_2_junction_clique_[id];
142 }
143
144 // returns the junction tree asked by the triangulation
146 // compute the junction tree only if it does not already exist
148
149 return _junction_tree_;
150 }
151
152 // resets the current junction tree strategy data structures
158
159 // computes a junction tree from an elimination tree
161 // if no triangulation is assigned to the strategy, we cannot compute
162 // the junction tree, so raise an exception
163 if (triangulation_ == nullptr)
165 "No triangulation has been assigned to "
166 "the DefaultJunctionTreeStrategy")
167
168 // copy the elimination tree into the junction tree
169 _junction_tree_ = triangulation_->eliminationTree();
170
171 // mark all the edges of the junction tree to false
172 EdgeProperty< bool > mark = _junction_tree_.edgesProperty(false);
173
174 // create a vector indicating by which clique a given clique has been
175 // substituted during the transformation from the elimination tree to the
176 // junction tree. Assume that clique J of the elimination tree has been
177 // substituted by clique K of the elimination tree, and that clique J
178 // (resp. K) was the jth (resp. kth) one created during the triangulation
179 // process. Then, in the vector below, substitution[j] = k.
180 const std::vector< NodeId >& elim_order = triangulation_->eliminationOrder();
181
182 auto size = elim_order.size();
183 std::vector< NodeId > substitution(size);
184 std::iota(substitution.begin(), substitution.end(), 0);
185
186 // for all cliques C_i, from the last one created to the first one, check
187 // if there exists a parent C_j (a neighbor created before C_i) such that
188 // |C_j| = |C_i| + 1 and such that the edge is not marked. In this case,
189 // this means that C_j contains C_i. Hence, we should remove C_i, and link
190 // all of its neighbors to C_j. These links will be marked to true as no
191 // such neighbor can be included in C_j (and conversely).
192 if (size > 0) {
193 for (auto i = size; i >= 1; --i) {
194 const NodeId C_i = NodeId(i - 1);
195 const auto card_C_i_plus_1 = _junction_tree_.clique(C_i).size() + 1;
196
197 // search for C_j such that |C_j| = [C_i| + 1
198 NodeId C_j = C_i;
199
200 for (const auto C_jj: _junction_tree_.neighbours(C_i))
201 if ((C_i > C_jj) && !mark[Edge(C_jj, C_i)]
202 && (_junction_tree_.clique(C_jj).size() == card_C_i_plus_1)) {
203 // ok, here we found a parent such that |C_jj| = [C_i| + 1
204 C_j = C_jj;
205 _junction_tree_.eraseEdge(Edge(C_j, C_i));
206 break;
207 }
208
209 // if we found a C_j, link the neighbors of C_i to C_j
210 if (C_j != C_i) {
211 for (const auto nei: _junction_tree_.neighbours(C_i)) {
212 _junction_tree_.addEdge(C_j, nei);
213 mark.insert(Edge(C_j, nei), true);
214 }
215
216 // remove C_i
217 substitution[C_i] = C_j;
218 _junction_tree_.eraseNode(C_i);
219 }
220 }
221 }
222
223 // compute the transitive closure of vector substitution
224 for (std::size_t i = 0; i < size; ++i)
225 substitution[i] = substitution[substitution[i]];
226
227 // using the transitive closure of vector substitution, compute for each
228 // node the clique of the junction tree that was created by its
229 // elimination during the triangulation
230 for (NodeId i = NodeId(0); i < size; ++i) {
231 _node_2_junction_clique_.insert(elim_order[i], substitution[i]);
232 }
233
234 _has_junction_tree_ = true;
235 }
236
237} /* namespace gum */
Basic graph of cliques.
Definition cliqueGraph.h:77
An algorithm producing a junction given the elimination tree produced by a triangulation algorithm.
virtual const NodeProperty< NodeId > & createdCliques() final
returns, for each node, the clique of the junction tree which was created by its deletion
bool _has_junction_tree_
a boolean indicating whether the junction tree has been constructed
virtual DefaultJunctionTreeStrategy * newFactory() const final
create a clone not assigned to any triangulation algorithm
virtual DefaultJunctionTreeStrategy * copyFactory(StaticTriangulation *triangulation=nullptr) const final
virtual copy constructor
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...
void _computeJunctionTree_()
computes a junction tree from an elimination tree
CliqueGraph _junction_tree_
the junction tree computed by the algorithm
virtual void setTriangulation(StaticTriangulation *triangulation) final
assigns the triangulation to the junction tree strategy
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...
virtual bool requiresFillIns() const final
indicates whether the junction tree strategy needs fill-ins to work properly
virtual void clear() final
resets the current junction tree strategy data structures
virtual const CliqueGraph & junctionTree() final
returns the junction tree computed
The base class for all undirected edges.
value_type & insert(const Key &key, const Val &val)
Adds a new element (actually a copy of this element) into the hash table.
JunctionTreeStrategy()
default constructor
StaticTriangulation * triangulation_
the triangulation to which the junction tree is associated
base class for all non-incremental triangulation methods
const UndiGraph * originalGraph() const
returns the graph to be triangulated
Exception : a looked-for element could not be found.
An algorithms producing a junction given the elimination tree produced by the triangulation algorithm...
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
Size NodeId
Type for node ids.
HashTable< Edge, VAL > EdgeProperty
Property on graph elements.
HashTable< NodeId, VAL > NodeProperty
Property on graph elements.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
STL namespace.
base class for all non-incremental triangulations.