aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
gum::BinaryJoinTreeConverterDefault Class Reference

#include <binaryJoinTreeConverterDefault.h>

Collaboration diagram for gum::BinaryJoinTreeConverterDefault:

Public Member Functions

Constructors / Destructors
 BinaryJoinTreeConverterDefault ()
 default constructor
virtual ~BinaryJoinTreeConverterDefault ()
 destructor
Accessors/Modifiers
CliqueGraph convert (const CliqueGraph &JT, const NodeProperty< Size > &domain_sizes, const NodeSet &roots)
 returns a binary join tree corresponding to clique graph JT
const NodeSetroots () const
 returns all the roots considered for all the connected components

Private Member Functions

 BinaryJoinTreeConverterDefault (const BinaryJoinTreeConverterDefault &)
 forbid copy constructor
BinaryJoinTreeConverterDefaultoperator= (const BinaryJoinTreeConverterDefault &)
 forbid copy operator
void _markConnectedComponent_ (const CliqueGraph &JT, NodeId root, NodeProperty< bool > &mark) const
 a function used to mark the nodes belonging to a given connected component
void _convertConnectedComponent_ (CliqueGraph &JT, NodeId current_node, NodeId from, const NodeProperty< Size > &domain_sizes, NodeProperty< bool > &mark) const
 convert a whole connected component into a binary join tree
void _convertClique_ (CliqueGraph &JT, NodeId clique, NodeId from, const NodeProperty< Size > &domain_sizes) const
 convert a clique and its adjacent cliques into a binary join tree
float _combinedSize_ (const NodeSet &nodes1, const NodeSet &nodes2, const NodeProperty< Size > &domain_sizes) const
 returns the domain size of the union of two cliques

Private Attributes

NodeSet _roots_
 the new roots that have been created to compute the last query

Detailed Description

Definition at line 54 of file binaryJoinTreeConverterDefault.h.

Constructor & Destructor Documentation

◆ BinaryJoinTreeConverterDefault() [1/2]

gum::BinaryJoinTreeConverterDefault::BinaryJoinTreeConverterDefault ( )

default constructor

Definition at line 56 of file binaryJoinTreeConverterDefault.cpp.

56 {
57 GUM_CONSTRUCTOR(BinaryJoinTreeConverterDefault);
58 }

References BinaryJoinTreeConverterDefault().

Referenced by BinaryJoinTreeConverterDefault(), BinaryJoinTreeConverterDefault(), ~BinaryJoinTreeConverterDefault(), and operator=().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ~BinaryJoinTreeConverterDefault()

gum::BinaryJoinTreeConverterDefault::~BinaryJoinTreeConverterDefault ( )
virtual

destructor

Definition at line 61 of file binaryJoinTreeConverterDefault.cpp.

61 {
62 GUM_DESTRUCTOR(BinaryJoinTreeConverterDefault);
63 }

References BinaryJoinTreeConverterDefault().

Here is the call graph for this function:

◆ BinaryJoinTreeConverterDefault() [2/2]

gum::BinaryJoinTreeConverterDefault::BinaryJoinTreeConverterDefault ( const BinaryJoinTreeConverterDefault & )
private

forbid copy constructor

References BinaryJoinTreeConverterDefault().

Here is the call graph for this function:

Member Function Documentation

◆ _combinedSize_()

float gum::BinaryJoinTreeConverterDefault::_combinedSize_ ( const NodeSet & nodes1,
const NodeSet & nodes2,
const NodeProperty< Size > & domain_sizes ) const
private

returns the domain size of the union of two cliques

Definition at line 101 of file binaryJoinTreeConverterDefault.cpp.

104 {
105 float result = 1;
106
107 for (const auto node: nodes1)
108 result *= domain_sizes[node];
109
110 for (const auto node: nodes2)
111 if (!nodes1.exists(node)) result *= domain_sizes[node];
112
113 return result;
114 }

References gum::Set< Key >::exists().

Referenced by _convertClique_().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _convertClique_()

void gum::BinaryJoinTreeConverterDefault::_convertClique_ ( CliqueGraph & JT,
NodeId clique,
NodeId from,
const NodeProperty< Size > & domain_sizes ) const
private

convert a clique and its adjacent cliques into a binary join tree

Definition at line 120 of file binaryJoinTreeConverterDefault.cpp.

124 {
125 // get the neighbors of clique. If there are fewer than 3 neighbors,
126 // there is nothing to do
127 const NodeSet& neighbors = JT.neighbours(clique);
128
129 if (neighbors.size() <= 2) return;
130
131 if ((neighbors.size() == 3) && (clique != from)) return;
132
133 // here we need to transform the neighbors into a binary tree
134 // create a vector with all the ids of the cliques to combine
135 std::vector< NodeId > cliques;
136 cliques.reserve(neighbors.size());
137
138 for (const auto nei: neighbors)
139 if (nei != from) cliques.push_back(nei);
140
141 // create a vector indicating wether the elements in cliques contain
142 // relevant information or not (during the execution of the for
143 // loop below, a cell of vector cliques may actually contain only
144 // trash data)
145 std::vector< bool > is_cliques_relevant(cliques.size(), true);
146
147 // for each pair of cliques (i,j), compute the size of the clique that would
148 // result from the combination of clique i with clique j and store the
149 // result
150 // into a priorityQueue
151 std::pair< NodeId, NodeId > pair;
152
153 PriorityQueue< std::pair< NodeId, NodeId >, float > queue;
154
155 for (NodeId i = 0; i < cliques.size(); ++i) {
156 pair.first = i;
157 const NodeSet& nodes1 = JT.separator(cliques[i], clique);
158
159 for (NodeId j = i + 1; j < cliques.size(); ++j) {
160 pair.second = j;
161 queue.insert(pair, _combinedSize_(nodes1, JT.separator(cliques[j], clique), domain_sizes));
162 }
163 }
164
165 // now parse the priority queue: the top element (i,j) gives the combination
166 // to perform. When the result R has been computed, substitute i by R,
167 // remove
168 // table j and recompute all the priorities of all the pairs (R,k) still
169 // available.
170 for (NodeId k = 2; k < cliques.size(); ++k) {
171 // get the combination to perform and do it
172 pair = queue.pop();
173 NodeId ti = pair.first;
174 NodeId tj = pair.second;
175
176 // create a new clique that will become adjacent to ti and tj
177 // and remove the edges between ti, tj and clique
178 const NodeSet& nodes1 = JT.separator(cliques[ti], clique);
179 const NodeSet& nodes2 = JT.separator(cliques[tj], clique);
180 NodeId new_node = JT.addNode(nodes1 + nodes2);
181 JT.addEdge(cliques[ti], new_node);
182 JT.addEdge(cliques[tj], new_node);
183 JT.addEdge(clique, new_node);
184 JT.eraseEdge(Edge(cliques[ti], clique));
185 JT.eraseEdge(Edge(cliques[tj], clique));
186
187 // substitute cliques[pair.first] by the result
188 cliques[ti] = new_node;
189 is_cliques_relevant[tj] = false; // now tj is no more a neighbor of clique
190
191 // remove all the pairs involving tj in the priority queue
192
193 for (NodeId ind = 0; ind < tj; ++ind) {
194 if (is_cliques_relevant[ind]) {
195 pair.first = ind;
196 queue.erase(pair);
197 }
198 }
199
200 pair.first = tj;
201
202 for (NodeId ind = tj + 1; ind < cliques.size(); ++ind) {
203 if (is_cliques_relevant[ind]) {
204 pair.second = ind;
205 queue.erase(pair);
206 }
207 }
208
209 // update the "combined" size of all the pairs involving "new_node"
210 {
211 const NodeSet& nodes1 = JT.separator(cliques[ti], clique);
212 pair.second = ti;
213 float newsize;
214
215 for (NodeId ind = 0; ind < ti; ++ind) {
216 if (is_cliques_relevant[ind]) {
217 pair.first = ind;
218 newsize = _combinedSize_(nodes1, JT.separator(cliques[ind], clique), domain_sizes);
219 queue.setPriority(pair, newsize);
220 }
221 }
222
223 pair.first = ti;
224
225 for (NodeId ind = ti + 1; ind < cliques.size(); ++ind) {
226 if (is_cliques_relevant[ind]) {
227 pair.second = ind;
228 newsize = _combinedSize_(nodes1, JT.separator(cliques[ind], clique), domain_sizes);
229 queue.setPriority(pair, newsize);
230 }
231 }
232 }
233 }
234 }
float _combinedSize_(const NodeSet &nodes1, const NodeSet &nodes2, const NodeProperty< Size > &domain_sizes) const
returns the domain size of the union of two cliques
Size NodeId
Type for node ids.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...

References _combinedSize_(), gum::CliqueGraph::addEdge(), gum::CliqueGraph::addNode(), gum::PriorityQueueImplementation< Val, Priority, Cmp, Gen >::erase(), gum::CliqueGraph::eraseEdge(), gum::PriorityQueueImplementation< Val, Priority, Cmp, Gen >::insert(), gum::EdgeGraphPart::neighbours(), gum::PriorityQueueImplementation< Val, Priority, Cmp, Gen >::pop(), gum::CliqueGraph::separator(), gum::PriorityQueueImplementation< Val, Priority, Cmp, Gen >::setPriority(), and gum::Set< Key >::size().

Referenced by _convertConnectedComponent_().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _convertConnectedComponent_()

void gum::BinaryJoinTreeConverterDefault::_convertConnectedComponent_ ( CliqueGraph & JT,
NodeId current_node,
NodeId from,
const NodeProperty< Size > & domain_sizes,
NodeProperty< bool > & mark ) const
private

convert a whole connected component into a binary join tree

Definition at line 237 of file binaryJoinTreeConverterDefault.cpp.

242 {
243 // first, indicate that the node has been marked (this avoids looping
244 // if JT is not a tree
245 mark[current_node] = true;
246
247 // parse all the neighbors except nodes already converted and convert them
248 for (const auto neigh: JT.neighbours(current_node)) {
249 if (!mark[neigh]) {
250 _convertConnectedComponent_(JT, neigh, current_node, domain_sizes, mark);
251 }
252 }
253
254 // convert the current node
255 _convertClique_(JT, current_node, from, domain_sizes);
256 }
void _convertClique_(CliqueGraph &JT, NodeId clique, NodeId from, const NodeProperty< Size > &domain_sizes) const
convert a clique and its adjacent cliques into a binary join tree
void _convertConnectedComponent_(CliqueGraph &JT, NodeId current_node, NodeId from, const NodeProperty< Size > &domain_sizes, NodeProperty< bool > &mark) const
convert a whole connected component into a binary join tree

References _convertClique_(), _convertConnectedComponent_(), and gum::EdgeGraphPart::neighbours().

Referenced by _convertConnectedComponent_(), and convert().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ _markConnectedComponent_()

void gum::BinaryJoinTreeConverterDefault::_markConnectedComponent_ ( const CliqueGraph & JT,
NodeId root,
NodeProperty< bool > & mark ) const
private

a function used to mark the nodes belonging to a given connected component

Definition at line 67 of file binaryJoinTreeConverterDefault.cpp.

69 {
70 // we mark the nodes in a depth first search manner. To avoid a recursive
71 // algorithm, use a vector to simulate a stack of nodes to inspect.
72 // stack => depth first search
73 std::vector< NodeId > nodes_to_inspect;
74 nodes_to_inspect.reserve(JT.sizeNodes());
75
76 // the idea to populate the marks is to use the stack: root is
77 // put onto the stack. Then, while the stack is not empty, remove
78 // the top of the stack and mark it and put into the stack its
79 // adjacent nodes.
80 nodes_to_inspect.push_back(root);
81
82 while (!nodes_to_inspect.empty()) {
83 // process the top of the stack
84 NodeId current_node = nodes_to_inspect.back();
85 nodes_to_inspect.pop_back();
86
87 // only process the node if it has not been processed yet (actually,
88 // this should not occur unless the clique graph is not singly connected)
89
90 if (!mark[current_node]) {
91 mark[current_node] = true;
92
93 // put the neighbors onto the stack
94 for (const auto neigh: JT.neighbours(current_node))
95 if (!mark[neigh]) nodes_to_inspect.push_back(neigh);
96 }
97 }
98 }

References gum::EdgeGraphPart::neighbours(), and gum::NodeGraphPart::sizeNodes().

Referenced by convert().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ convert()

CliqueGraph gum::BinaryJoinTreeConverterDefault::convert ( const CliqueGraph & JT,
const NodeProperty< Size > & domain_sizes,
const NodeSet & roots )

returns a binary join tree corresponding to clique graph JT

computes the binary join tree

This method creates and returns a new binary join tree compatible with that passed in argument (JT) and optimized for inference. As such, this requires knowing the join tree to be converted (of course), but also which roots will be used by the collect/diffusion inference engine and the domain size of the variables contained in the cliques of JT (to optimize the combination of the tensors contained in the cliques.

Exceptions
InvalidNodeexception is thrown if some roots do not belong to JT or if several roots belong to the same connected component.
Warning
If you do not pass in argument a root for each connected component, then for those with unspecified roots, an arbitrary root will be computed and used for the binarization.

Definition at line 259 of file binaryJoinTreeConverterDefault.cpp.

261 {
262 // first, we copy the current clique graph. By default, this is what we
263 // will return
264 CliqueGraph binJT = JT;
265
266 // check that there is no connected component without a root. In such a
267 // case,
268 // assign an arbitrary root to it
269 _roots_ = specified_roots;
270
271 NodeProperty< bool > mark = JT.nodesPropertyFromVal(false, JT.sizeNodes());
272
273 // for each specified root, populate its connected component
274 for (const auto root: specified_roots) {
275 // check that the root has not already been marked
276 // in this case, this means that more than one root has been specified
277 // for a given connected component
278 if (mark[root])
279 GUM_ERROR(InvalidNode,
280 "several roots have been specified for a given "
281 "connected component (last : "
282 << root << ")");
283
284 _markConnectedComponent_(JT, root, mark);
285 }
286
287 // check that all nodes have been marked. If this is not the case, then
288 // this means that we need to add new roots
289 for (const auto& elt: mark)
290 if (!elt.second) {
291 _roots_ << elt.first;
292 _markConnectedComponent_(JT, elt.first, mark);
293 }
294
295 // here, we know that each connected component has one and only one root.
296 // Now we can apply a recursive collect algorithm starting from root
297 // that transforms each clique with more than 3 neighbors into a set of
298 // cliques having at most 3 neighbors.
299 NodeProperty< bool > mark2 = JT.nodesPropertyFromVal(false, JT.sizeNodes());
300
301 for (const auto root: _roots_)
302 _convertConnectedComponent_(binJT, root, root, domain_sizes, mark2);
303
304 // binJT is now a binary join tree, so we can return it
305 return binJT;
306 }
NodeSet _roots_
the new roots that have been created to compute the last query
void _markConnectedComponent_(const CliqueGraph &JT, NodeId root, NodeProperty< bool > &mark) const
a function used to mark the nodes belonging to a given connected component
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
HashTable< NodeId, VAL > NodeProperty
Property on graph elements.

References _convertConnectedComponent_(), _markConnectedComponent_(), _roots_, GUM_ERROR, gum::NodeGraphPart::nodesPropertyFromVal(), and gum::NodeGraphPart::sizeNodes().

Here is the call graph for this function:

◆ operator=()

BinaryJoinTreeConverterDefault & gum::BinaryJoinTreeConverterDefault::operator= ( const BinaryJoinTreeConverterDefault & )
private

forbid copy operator

References BinaryJoinTreeConverterDefault().

Here is the call graph for this function:

◆ roots()

const NodeSet & gum::BinaryJoinTreeConverterDefault::roots ( ) const

returns all the roots considered for all the connected components

Definition at line 117 of file binaryJoinTreeConverterDefault.cpp.

117{ return _roots_; }

References _roots_.

Member Data Documentation

◆ _roots_

NodeSet gum::BinaryJoinTreeConverterDefault::_roots_
private

the new roots that have been created to compute the last query

Definition at line 98 of file binaryJoinTreeConverterDefault.h.

Referenced by convert(), and roots().


The documentation for this class was generated from the following files: