aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
searchStrategy_tpl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2026 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-2026 *
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#pragma once
42
43
51
52namespace gum {
53 namespace prm {
54 namespace gspan {
55
56 template < GUM_Numeric GUM_SCALAR >
58 double cost = 0;
60 = *(this->tree_->data(p).iso_map.begin().val());
62
63 for (const auto inst: seq) {
64 for (const auto input: inst->type().slotChains())
65 for (const auto inst2: inst->getInstances(input->id()))
66 if ((!seq.exists(inst2))
67 && (!input_set.exists(&(inst2->get(input->lastElt().safeName()))))) {
68 cost += std::log(input->type().variable().domainSize());
69 input_set.insert(&(inst2->get(input->lastElt().safeName())));
70 }
71
72 for (auto vec = inst->beginInvRef(); vec != inst->endInvRef(); ++vec)
73 for (const auto& inverse: *vec.val())
74 if (!seq.exists(inverse.first)) {
75 cost += std::log(inst->get(vec.key()).type().variable().domainSize());
76 break;
77 }
78 }
79
80 return cost;
81 }
82
83 template < GUM_Numeric GUM_SCALAR >
86 Set< Tensor< GUM_SCALAR >* >& pool,
87 const Sequence< PRMInstance< GUM_SCALAR >* >& match) {
88 for (const auto inst: match) {
89 for (const auto& elt: *inst) {
90 // Adding the node
91 NodeId id = data.graph.addNode();
92 data.node2attr.insert(id, _str_(inst, elt.second));
93 data.mod.insert(id, elt.second->type()->domainSize());
94 data.vars.insert(id, &elt.second->type().variable());
95 pool.insert(const_cast< Tensor< GUM_SCALAR >* >(&(elt.second->cpf())));
96 }
97 }
98
99 // Second we add edges and nodes to inners or outputs
100 for (const auto inst: match)
101 for (const auto& elt: *inst) {
102 NodeId node = data.node2attr.first(_str_(inst, elt.second));
103 bool found = false; // If this is set at true, then node is an outer node
104
105 // Children existing in the instance type's DAG
106 for (const auto chld: inst->type().containerDag().children(elt.second->id())) {
107 data.graph.addEdge(node, data.node2attr.first(_str_(inst, inst->get(chld))));
108 }
109
110 // Parents existing in the instance type's DAG
111 for (const auto par: inst->type().containerDag().parents(elt.second->id())) {
112 switch (inst->type().get(par).elt_type()) {
115 data.graph.addEdge(node, data.node2attr.first(_str_(inst, inst->get(par))));
116 break;
117 }
118
120 for (const auto inst2: inst->getInstances(par))
121 if (match.exists(inst2))
122 data.graph.addEdge(node,
123 data.node2attr.first(
124 _str_(inst2,
125 static_cast< const PRMSlotChain< GUM_SCALAR >& >(
126 inst->type().get(par)))));
127
128 break;
129 }
130
131 default : { /* Do nothing */
132 }
133 }
134 }
135
136 // Referring PRMAttribute<GUM_SCALAR>
137 if (inst->hasRefAttr(elt.second->id())) {
138 const std::vector< std::pair< PRMInstance< GUM_SCALAR >*, std::string > >& ref_attr
139 = inst->getRefAttr(elt.second->id());
140
141 for (auto pair = ref_attr.begin(); pair != ref_attr.end(); ++pair) {
142 if (match.exists(pair->first)) {
143 NodeId id = pair->first->type().get(pair->second).id();
144
145 for (const auto child: pair->first->type().containerDag().children(id))
146 data.graph.addEdge(
147 node,
148 data.node2attr.first(_str_(pair->first, pair->first->get(child))));
149 } else {
150 found = true;
151 }
152 }
153 }
154
155 if (found) data.outputs.insert(node);
156 else data.inners.insert(node);
157 }
158 }
159
160 template < GUM_Numeric GUM_SCALAR >
163 Set< Tensor< GUM_SCALAR >* >& pool) {
164 List< NodeSet > partial_order;
165
166 if (data.inners.size()) partial_order.insert(data.inners);
167
168 if (data.outputs.size()) partial_order.insert(data.outputs);
169
170 PartialOrderedTriangulation t(&(data.graph), &(data.mod), &partial_order);
171 const std::vector< NodeId >& elim_order = t.eliminationOrder();
172 Size max(0), max_count(1);
174 Tensor< GUM_SCALAR >* pot = 0;
175
176 for (size_t idx = 0; idx < data.inners.size(); ++idx) {
177 pot = new Tensor< GUM_SCALAR >(new MultiDimSparse< GUM_SCALAR >(0));
178 pot->add(*(data.vars.second(elim_order[idx])));
179 trash.insert(pot);
180 Set< Tensor< GUM_SCALAR >* > toRemove;
181
182 for (const auto p: pool)
183 if (p->contains(*(data.vars.second(elim_order[idx])))) {
184 for (auto var = p->variablesSequence().begin(); var != p->variablesSequence().end();
185 ++var) {
186 try {
187 pot->add(**var);
188 } catch (DuplicateElement const&) {}
189 }
190
191 toRemove.insert(p);
192 }
193
194 if (pot->domainSize() > max) {
195 max = pot->domainSize();
196 max_count = 1;
197 } else if (pot->domainSize() == max) {
198 ++max_count;
199 }
200
201 for (const auto p: toRemove)
202 pool.erase(p);
203
204 pot->erase(*(data.vars.second(elim_order[idx])));
205 }
206
207 for (const auto pot: trash)
208 delete pot;
209
210 return std::make_pair(max, max_count);
211 }
212
213 // The SearchStrategy class
214 template < GUM_Numeric GUM_SCALAR >
218
219 template < GUM_Numeric GUM_SCALAR >
224
225 template < GUM_Numeric GUM_SCALAR >
229
230 template < GUM_Numeric GUM_SCALAR >
233 = default;
234
235 template < GUM_Numeric GUM_SCALAR >
236 void SearchStrategy< GUM_SCALAR >::setTree(DFSTree< GUM_SCALAR >* tree) {
237 this->tree_ = tree;
238 }
239
240 // FrequenceSearch
241
242 // The FrequenceSearch class
243 template < GUM_Numeric GUM_SCALAR >
245 SearchStrategy< GUM_SCALAR >(), _freq_(freq) {
246 GUM_CONSTRUCTOR(FrequenceSearch);
247 }
248
249 template < GUM_Numeric GUM_SCALAR >
251 SearchStrategy< GUM_SCALAR >(from), _freq_(from._freq_) {
252 GUM_CONS_CPY(FrequenceSearch);
253 }
254
255 template < GUM_Numeric GUM_SCALAR >
259
260 template < GUM_Numeric GUM_SCALAR >
266
267 template < GUM_Numeric GUM_SCALAR >
269 return this->tree_->frequency(*r) >= _freq_;
270 }
271
272 template < GUM_Numeric GUM_SCALAR >
274 const Pattern* child,
275 const EdgeGrowth< GUM_SCALAR >& growh) {
276 return this->tree_->frequency(*child) >= _freq_;
277 }
278
279 template < GUM_Numeric GUM_SCALAR >
281 // We want a descending order
282 return this->tree_->frequency(*i) > this->tree_->frequency(*j);
283 }
284
285 template < GUM_Numeric GUM_SCALAR >
287 return (this->tree_->internalGraph().size(i) > this->tree_->internalGraph().size(j));
288 }
289
290 // StrictSearch
291
292 // The StrictSearch class
293 template < GUM_Numeric GUM_SCALAR >
295 SearchStrategy< GUM_SCALAR >(), _freq_(freq), _dot_(".") {
296 GUM_CONSTRUCTOR(StrictSearch);
297 }
298
299 template < GUM_Numeric GUM_SCALAR >
301 SearchStrategy< GUM_SCALAR >(from), _freq_(from._freq_) {
302 GUM_CONS_CPY(StrictSearch);
303 }
304
305 template < GUM_Numeric GUM_SCALAR >
309
310 template < GUM_Numeric GUM_SCALAR >
313 _freq_ = from._freq_;
314 return *this;
315 }
316
317 template < GUM_Numeric GUM_SCALAR >
319 return (this->tree_->frequency(*r) >= _freq_);
320 }
321
322 template < GUM_Numeric GUM_SCALAR >
324 const Pattern* child,
325 const EdgeGrowth< GUM_SCALAR >& growth) {
326 return _inner_cost_(child) + this->tree_->frequency(*child) * _outer_cost_(child)
327 < this->tree_->frequency(*child) * _outer_cost_(parent);
328 }
329
330 template < GUM_Numeric GUM_SCALAR >
332 return _inner_cost_(i) + this->tree_->frequency(*i) * _outer_cost_(i)
333 < _inner_cost_(j) + this->tree_->frequency(*j) * _outer_cost_(j);
334 }
335
336 template < GUM_Numeric GUM_SCALAR >
338 return i->tree_width * this->tree_->internalGraph().size(i)
339 < j->tree_width * this->tree_->internalGraph().size(j);
340 }
341
342 template < GUM_Numeric GUM_SCALAR >
344 auto pm = _map_.tryGet(p);
345 if (!pm) {
347 pm = _map_.tryGet(p);
348 }
349 return pm->first;
350 }
351
352 template < GUM_Numeric GUM_SCALAR >
354 auto pm = _map_.tryGet(p);
355 if (!pm) {
357 pm = _map_.tryGet(p);
358 }
359 return pm->second;
360 }
361
362 template < GUM_Numeric GUM_SCALAR >
364 const PRMAttribute< GUM_SCALAR >* a) const {
365 return i->name() + _dot_ + a->safeName();
366 }
367
368 template < GUM_Numeric GUM_SCALAR >
370 const PRMAttribute< GUM_SCALAR >& a) const {
371 return i->name() + _dot_ + a.safeName();
372 }
373
374 template < GUM_Numeric GUM_SCALAR >
376 const PRMSlotChain< GUM_SCALAR >& a) const {
377 return i->name() + _dot_ + a.lastElt().safeName();
378 }
379
380 template < GUM_Numeric GUM_SCALAR >
384 _buildPatternGraph_(data, pool, *(this->tree_->data(*p).iso_map.begin().val()));
385 double inner = std::log(_elimination_cost_(data, pool).first);
386 double outer = this->computeCost_(*p);
387 _map_.insert(p, std::make_pair(inner, outer));
388 }
389
390 // TreeWidthSearch
391
392 template < GUM_Numeric GUM_SCALAR >
394 GUM_CONSTRUCTOR(TreeWidthSearch);
395 }
396
397 template < GUM_Numeric GUM_SCALAR >
402
403 template < GUM_Numeric GUM_SCALAR >
407
408 template < GUM_Numeric GUM_SCALAR >
413
414 template < GUM_Numeric GUM_SCALAR >
416 auto pm = _map_.tryGet(&p);
417 if (!pm) {
418 _map_.insert(&p, this->computeCost_(p));
419 pm = _map_.tryGet(&p);
420 }
421 return *pm;
422 }
423
424 template < GUM_Numeric GUM_SCALAR >
426 Size tree_width = 0;
427
428 for (const auto n: r->nodes())
429 tree_width += r->label(n).tree_width;
430
431 return tree_width >= cost(*r);
432 }
433
434 template < GUM_Numeric GUM_SCALAR >
436 const Pattern* child,
437 const EdgeGrowth< GUM_SCALAR >& growth) {
438 return cost(*parent) >= cost(*child);
439 }
440
441 template < GUM_Numeric GUM_SCALAR >
445
446 template < GUM_Numeric GUM_SCALAR >
450
451 } /* namespace gspan */
452 } /* namespace prm */
453} /* namespace gum */
Exception : a similar element already exists.
Generic doubly linked lists.
Definition list.h:378
Val & insert(const Val &val)
Inserts a new element at the end of the chained list (alias of pushBack).
Definition list_tpl.h:1508
Multidimensional matrix stored as a sparse array in memory.
virtual NodeId addNode()
insert a new node and return its id
class for graph triangulations for which we enforce a given partial ordering on the nodes elimination...
void insert(const Key &k)
Insert an element at the end of the sequence.
bool exists(const Key &k) const
Check the existence of k in the sequence.
The generic class for storing (ordered) sequences of objects.
Definition sequence.h:994
Representation of a set.
Definition set.h:129
void insert(const Key &k)
Inserts a new element into the set.
Definition set_tpl.h:510
void erase(const Key &k)
Erases an element from the set.
Definition set_tpl.h:553
Size size() const noexcept
Returns the number of elements in the set.
Definition set_tpl.h:607
const std::vector< NodeId > & eliminationOrder() override
returns an elimination ordering compatible with the triangulated graph
void addEdge(NodeId first, NodeId second) override
insert a new edge into the undirected graph
PRMAttribute is a member of a Class in a PRM.
const std::string & safeName() const
Returns the safe name of this PRMClassElement, if any.
An PRMInstance is a Bayesian network fragment defined by a Class and used in a PRMSystem.
Definition PRMInstance.h:79
const std::string & name() const
Returns the name of this object.
A PRMSlotChain represents a sequence of gum::prm::PRMClassElement<GUM_SCALAR> where the n-1 first gum...
PRMClassElement< GUM_SCALAR > & lastElt()
Returns the last element of the slot chain, typically this is an gum::PRMAttribute or a gum::PRMAggre...
This class is used to define an edge growth of a pattern in this DFSTree.
Definition edgeGrowth.h:73
This is class is an implementation of a simple serach strategy for the gspan algorithm: it accept a g...
bool accept_growth(const Pattern *parent, const Pattern *child, const EdgeGrowth< GUM_SCALAR > &growth) override
FrequenceSearch(Size freq)
Default constructor.
bool accept_root(const Pattern *r) override
bool operator()(LabelData *i, LabelData *j) override
FrequenceSearch & operator=(const FrequenceSearch &from)
Copy operator.
This contains all the information we want for a node in a DFSTree.
Definition pattern.h:90
const NodeGraphPart & nodes() const
LabelData & label(NodeId node)
Returns the LabelData assigned to node.
Definition pattern_inl.h:78
This is an abstract class used to tune search strategies in the gspan algorithm.
double computeCost_(const Pattern &p)
SearchStrategy< GUM_SCALAR > & operator=(const SearchStrategy< GUM_SCALAR > &from)
Copy operator.
DFSTree< GUM_SCALAR > * tree_
void setTree(DFSTree< GUM_SCALAR > *tree)
This is class is an implementation of a strict strategy for the GSpan algorithm.
StrictSearch(Size freq=2)
Default constructor.
bool accept_root(const Pattern *r) override
bool operator()(LabelData *i, LabelData *j) override
HashTable< const Pattern *, std::pair< double, double > > _map_
double _inner_cost_(const Pattern *p)
StrictSearch & operator=(const StrictSearch &from)
Copy operator.
~StrictSearch() override
Destructor.
void _buildPatternGraph_(typename StrictSearch< GUM_SCALAR >::PData &data, Set< Tensor< GUM_SCALAR > * > &pool, const Sequence< PRMInstance< GUM_SCALAR > * > &match)
void _compute_costs_(const Pattern *p)
std::pair< Size, Size > _elimination_cost_(typename StrictSearch< GUM_SCALAR >::PData &data, Set< Tensor< GUM_SCALAR > * > &pool)
bool accept_growth(const Pattern *parent, const Pattern *child, const EdgeGrowth< GUM_SCALAR > &growth) override
double _outer_cost_(const Pattern *p)
std::string _str_(const PRMInstance< GUM_SCALAR > *i, const PRMAttribute< GUM_SCALAR > *a) const
A growth is accepted if and only if the new growth has a tree width less large or equal than its fath...
HashTable< const Pattern *, double > _map_
TreeWidthSearch & operator=(const TreeWidthSearch &from)
Copy operator.
bool accept_root(const Pattern *r) override
bool accept_growth(const Pattern *parent, const Pattern *child, const EdgeGrowth< GUM_SCALAR > &growth) override
bool operator()(LabelData *i, LabelData *j) override
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
Size NodeId
Type for node ids.
namespace for all probabilistic relational models entities
Definition agrum.h:68
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
Headers of the SearchStrategy class and child.
Inner class to handle data about labels in this interface graph.
Size tree_width
The size in terms of tree width of the given label.
Private structure to represent data about a pattern.
Bijection< NodeId, std::string > node2attr
A bijection to easily keep track between graph and attributes, its of the form instance_name DOT attr...
NodeProperty< Size > mod
The pattern's variables modalities.
UndiGraph graph
A yet to be triangulated undigraph.
NodeSet outputs
Returns the set of outputs nodes given all the matches of pattern.
NodeSet inners
Returns the set of inner nodes.
Bijection< NodeId, const DiscreteVariable * > vars
Bijection between graph's nodes and their corresponding DiscreteVariable, for inference purpose.