aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
PRMInterface_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
52
53namespace gum {
54 namespace prm {
55
56 template < GUM_Numeric GUM_SCALAR >
59 GUM_CONSTRUCTOR(PRMInterface);
60 }
61
62 template < GUM_Numeric GUM_SCALAR >
65 bool delayInheritance) :
67 GUM_CONSTRUCTOR(PRMInterface);
68 if (!delayInheritance) { _inheritInterface_(super); }
69 }
70
71 template < GUM_Numeric GUM_SCALAR >
73 PRMClassElementContainer< GUM_SCALAR >(source.name()), _dag_(source._dag_),
75 GUM_CONS_CPY(PRMInterface);
76 GUM_ERROR(FatalError, "don't copy an interface")
77 }
78
79 template < GUM_Numeric GUM_SCALAR >
81 GUM_DESTRUCTOR(PRMInterface);
82
83 for (const auto& elt: _nodeIdMap_) {
84 delete elt.second;
85 }
86 }
87
88 template < GUM_Numeric GUM_SCALAR >
92
93 template < GUM_Numeric GUM_SCALAR >
95 // Copying attributes
96 for (const auto i_attr: i._attributes_) {
97 auto attr = new PRMScalarAttribute< GUM_SCALAR >(i_attr->name(), i_attr->type());
98 attr->setId(i_attr->id());
99 _nodeIdMap_.insert(attr->id(), attr);
100 _attributes_.insert(attr);
101
102 if (i._nameMap_[i_attr->name()] == i._nameMap_[i_attr->safeName()]) {
103 _nameMap_.insert(attr->name(), attr);
104 }
105
106 _nameMap_.insert(attr->safeName(), attr);
107 _dag_.addNodeWithId(attr->id());
108 }
109
110 // Copying reference slots
111 for (const auto i_ref: i._referenceSlots_) {
112 auto ref = new PRMReferenceSlot< GUM_SCALAR >(
113 i_ref->name(),
114 const_cast< PRMClassElementContainer< GUM_SCALAR >& >(i_ref->slotType()),
115 i_ref->isArray());
116
117 ref->setId(i_ref->id());
118 _nodeIdMap_.insert(ref->id(), ref);
119 _referenceSlots_.insert(ref);
120
121 if (i._nameMap_.exists(ref->name())) { _nameMap_.insert(ref->name(), ref); }
122
123 _nameMap_.insert(ref->safeName(), ref);
124 _dag_.addNodeWithId(ref->id());
125 }
126 }
127
128 template < GUM_Numeric GUM_SCALAR >
130 if (_nameMap_.exists(elt->name())) {
132 "name '" << elt->name() << "' is already used by another ClassElement");
133 }
134
136 PRMAttribute< GUM_SCALAR >* attr = static_cast< PRMAttribute< GUM_SCALAR >* >(elt);
137 _nameMap_.insert(attr->name(), attr);
138
139 while (true) {
140 attr->setId(nextNodeId());
141 _dag_.addNodeWithId(attr->id());
142 _nodeIdMap_.insert(attr->id(), attr);
143 _nameMap_.insert(attr->safeName(), attr);
144 _attributes_.insert(attr);
145
146 if (attr->type().isSubType()) {
147 attr = attr->getCastDescendant();
148 } else {
149 break;
150 }
151 }
153 elt->setId(nextNodeId());
154 _dag_.addNodeWithId(elt->id());
155 _nodeIdMap_.insert(elt->id(), elt);
156 _referenceSlots_.insert(static_cast< PRMReferenceSlot< GUM_SCALAR >* >(elt));
157 _nameMap_.insert(elt->name(), elt);
158 _nameMap_.insert(elt->safeName(), elt);
159 } else {
160 GUM_ERROR(WrongClassElement, "illegal ClassElement<GUM_SCALAR> for an Interface")
161 }
162
163 return elt->id();
164 }
165
166 template < GUM_Numeric GUM_SCALAR >
168 if (!_superInterface_)
169 GUM_ERROR(OperationNotAllowed, "overload is possible only with sub interfaces")
170
171 if (!super().exists(overloader->name()))
172 GUM_ERROR(OperationNotAllowed, "found no ClassElement<GUM_SCALAR> to overload")
173
174 PRMClassElement< GUM_SCALAR >* overloaded = _nameMap_[overloader->name()];
175 if (overloaded == overloader)
176 GUM_ERROR(DuplicateElement, "duplicate ClassElement '" << overloader->name() << "'")
177
178 if (!_checkOverloadLegality_(overloaded, overloader))
179 GUM_ERROR(OperationNotAllowed, "illegal overload")
180
181 switch (overloader->elt_type()) {
183 auto attr_overloader = static_cast< PRMAttribute< GUM_SCALAR >* >(overloader);
184 auto attr_overloaded = static_cast< PRMAttribute< GUM_SCALAR >* >(overloaded);
185 _overloadAttribute_(attr_overloader, attr_overloaded);
186 break;
187 }
188
190 auto ref_overloader = static_cast< PRMReferenceSlot< GUM_SCALAR >* >(overloader);
191 auto ref_overloaded = static_cast< PRMReferenceSlot< GUM_SCALAR >* >(overloaded);
192 _overloadReferenceSlot_(ref_overloader, ref_overloaded);
193 break;
194 }
195
199 "Element " << overloader->name() << " can not be overloaded")
200 default :
201 GUM_ERROR(FatalError, "Unknown ClassElement<GUM_SCALAR> type for " << overloader->name())
202 }
203
204 return overloader->id();
205 }
206
207 template < GUM_Numeric GUM_SCALAR >
209 PRMAttribute< GUM_SCALAR >* overloaded) {
210 if (overloader->type() != overloaded->type()) {
211 overloader->setId(nextNodeId());
212 _dag_.addNodeWithId(overloader->id());
213 _nodeIdMap_.insert(overloader->id(), overloader);
214 _nameMap_[overloader->name()] = overloader;
215 _nameMap_.insert(overloader->safeName(), overloader);
216 _attributes_.insert(overloader);
217 _addCastDescendants_(overloader, overloaded);
218 } else {
219 overloader->setId(overloaded->id());
220 _nodeIdMap_[overloader->id()] = overloader;
221 _nameMap_[overloader->name()] = overloader;
222 _nameMap_[overloader->safeName()] = overloader;
223 _attributes_.erase(overloaded);
224 _attributes_.insert(overloader);
225 // Swapping types, ugly but necessary to preserve the
226 // PRMType<GUM_SCALAR>
227 // pointer of overloaded
228 overloader->overload(overloaded);
229 delete overloaded;
230 }
231 }
232
233 template < GUM_Numeric GUM_SCALAR >
236 PRMReferenceSlot< GUM_SCALAR >* overloaded) {
237 // Adding overloading reference
238 overloader->setId(overloaded->id());
239 _nodeIdMap_[overloader->id()] = overloader;
240 _nameMap_[overloader->name()] = overloader;
241 _nameMap_.insert(overloader->safeName(), overloader);
242 _referenceSlots_.insert(overloader);
243 // Removing overloaded PRMReferenceSlot<GUM_SCALAR>
244 _referenceSlots_.erase(overloaded);
245 _nameMap_.erase(overloaded->safeName());
246 delete overloaded;
247 }
248
249 template < GUM_Numeric GUM_SCALAR >
252 PRMAttribute< GUM_SCALAR >* parent = start;
253 PRMAttribute< GUM_SCALAR >* child = nullptr;
254
255 while (parent->type().superType() != end->type()) {
256 child = parent->getCastDescendant();
257 child->setId(nextNodeId());
258 _dag_.addNodeWithId(child->id());
259 _nodeIdMap_.insert(child->id(), child);
260 // Only use child's safe name when adding to the name map!
261 _nameMap_.insert(child->safeName(), child);
262 _attributes_.insert(child);
263 // Do ! use Class<GUM_SCALAR>::insertArc(), child's CPF is already
264 // initialized properly
265 parent = child;
266 }
267
268 parent->setAsCastDescendant(end);
269 }
270
271 template < GUM_Numeric GUM_SCALAR >
273 const PRMClassElement< GUM_SCALAR >* overloaded,
274 const PRMClassElement< GUM_SCALAR >* overloader) {
275 if (overloaded->elt_type() != overloader->elt_type()) { return false; }
276
278 if (!overloader->type().isSubTypeOf(overloaded->type())) { return false; }
279 } else if (overloaded->elt_type() == PRMClassElement< GUM_SCALAR >::prm_refslot) {
280 auto ref_overloader = static_cast< const PRMReferenceSlot< GUM_SCALAR >* >(overloader);
281 auto ref_overloaded = static_cast< const PRMReferenceSlot< GUM_SCALAR >* >(overloaded);
282 if (!ref_overloader->slotType().isSubTypeOf(ref_overloaded->slotType())) { return false; }
283 } else {
284 return false;
285 }
286 return true;
287 }
288
289 template < GUM_Numeric GUM_SCALAR >
292 switch (cec.obj_type()) {
294 return false;
295 }
296
298 const PRMInterface* current = this;
299
300 while (current != 0) {
301 if (current == &(cec)) return true;
302
303 current = current->_superInterface_;
304 }
305
306 return false;
307 }
308
309 default : {
310 GUM_ERROR(FatalError, "unknown ClassElementContainer<GUM_SCALAR>")
311 }
312 }
313 }
314
315 template < GUM_Numeric GUM_SCALAR >
317 // for ( const auto ext : _extensions_ )
318 // if ( !ext->isOutputNode( elt ) ) ext->setOutputNode( elt, true );
319
320 // for ( const auto impl : _implementations_ ) {
321 // // Because of cyclic dependencies we must use a reinterpret cast.
322 // PRMClassElementContainer<GUM_SCALAR>* c =
323 // reinterpret_cast<PRMClassElementContainer<GUM_SCALAR>*>( impl );
324
325 // if ( ! c->isOutputNode( elt ) ) c->setOutputNode( elt, true );
326 //}
327 }
328
329 template < GUM_Numeric GUM_SCALAR >
333
334 template < GUM_Numeric GUM_SCALAR >
338
339 template < GUM_Numeric GUM_SCALAR >
342 return _nodeIdMap_.begin();
343 }
344
345 template < GUM_Numeric GUM_SCALAR >
348 return _nodeIdMap_.end();
349 }
350
351 template < GUM_Numeric GUM_SCALAR >
352 void PRMInterface< GUM_SCALAR >::addArc(std::string_view tail, std::string_view head) {
353 GUM_ERROR(OperationNotAllowed, "an Interface does ! have arcs")
354 }
355
356 template < GUM_Numeric GUM_SCALAR >
359 else GUM_ERROR(NotFound, "this Interface is ! a sub interface")
360 }
361
362 template < GUM_Numeric GUM_SCALAR >
365 else GUM_ERROR(NotFound, "this Interface is ! a sub interface")
366 }
367
368 template < GUM_Numeric GUM_SCALAR >
372
373 template < GUM_Numeric GUM_SCALAR >
377
378 template < GUM_Numeric GUM_SCALAR >
382
383 template < GUM_Numeric GUM_SCALAR >
387
388 template < GUM_Numeric GUM_SCALAR >
392
393 template < GUM_Numeric GUM_SCALAR >
396 return get(name);
397 }
398
399 template < GUM_Numeric GUM_SCALAR >
403
404 template < GUM_Numeric GUM_SCALAR >
406 return _dag_;
407 }
408
409 template < GUM_Numeric GUM_SCALAR >
413
414 template < GUM_Numeric GUM_SCALAR >
416 auto p = _nodeIdMap_.tryGet(id);
417 if (!p) { GUM_ERROR(NotFound, "no ClassElement<GUM_SCALAR> with the given NodeId") }
418 return **p;
419 }
420
421 template < GUM_Numeric GUM_SCALAR >
423 auto p = _nodeIdMap_.tryGet(id);
424 if (!p) { GUM_ERROR(NotFound, "no ClassElement<GUM_SCALAR> with the given NodeId") }
425 return **p;
426 }
427
428 template < GUM_Numeric GUM_SCALAR >
430 auto p = _nameMap_.tryGet(name);
431 if (!p) { GUM_ERROR(NotFound, "no ClassElement<GUM_SCALAR> with the given name") }
432 return **p;
433 }
434
435 template < GUM_Numeric GUM_SCALAR >
437 PRMInterface< GUM_SCALAR >::get(std::string_view name) const {
438 auto p = _nameMap_.tryGet(name);
439 if (!p) { GUM_ERROR(NotFound, "no ClassElement<GUM_SCALAR> with the given name") }
440 return **p;
441 }
442
443 template < GUM_Numeric GUM_SCALAR >
447
448 template < GUM_Numeric GUM_SCALAR >
453
454 template < GUM_Numeric GUM_SCALAR >
458
459 template < GUM_Numeric GUM_SCALAR >
463
464 template < GUM_Numeric GUM_SCALAR >
467 for (const auto impl: _implementations_) {
468 set.insert(impl);
469 impl->findAllSubtypes_(set);
470 }
471
472 for (const auto ext: _extensions_) {
473 set.insert(ext);
474 ext->findAllSubtypes_(set);
475 }
476 }
477
478 template < GUM_Numeric GUM_SCALAR >
480 try {
481 if (!this->getIOFlag_(elt).second) {
482 for (auto i: _implementations_) {
483 if (i->isOutputNode(elt)) { return true; }
484 }
485
486 if (_superInterface_ && _superInterface_->isOutputNode(elt)) { return true; }
487
488 } else {
489 return true;
490 }
491 } catch (NotFound const&) {}
492 return false;
493 }
494 } /* namespace prm */
495} /* namespace gum */
Headers of gum::prm::Class<GUM_SCALAR>.
Headers of gum::prm::PRMInterface.
Base class for dag.
Definition DAG.h:121
Exception : a similar element already exists.
Exception : fatal (unknown ?) error.
Exception : the element we looked for cannot be found.
Exception : operation not allowed.
Representation of a set.
Definition set.h:129
Exception: wrong PRMClassElement for this operation.
PRMAttribute is a member of a Class in a PRM.
virtual void overload(PRMAttribute< GUM_SCALAR > *source)
Set this as overload of source (necessayr to preserver internal pointers for MultiDims).
virtual void setAsCastDescendant(PRMAttribute< GUM_SCALAR > *attr)=0
Define attr as a cast descendant of this PRMAttribute.
PRMType & type() override=0
See gum::PRMClassElement::type().
PRMAttribute< GUM_SCALAR > * getCastDescendant() const override=0
Returns a proper cast descendant of this PRMAttribute.
PRMClassElementContainer(std::string_view name)
Default constructor.
virtual std::pair< bool, bool > & getIOFlag_(const PRMClassElement< GUM_SCALAR > &elt)
Returns the IO flags of a PRMClassElement<GUM_SCALAR>.
virtual bool exists(std::string_view name) const
Returns true if a member with the given name exists in this PRMClassElementContainer or in the PRMCla...
Abstract class representing an element of PRM class.
static INLINE bool isReferenceSlot(const PRMClassElement< GUM_SCALAR > &elt)
Returns true if obj_ptr is of type PRMReferenceSlot.
virtual ClassElementType elt_type() const =0
Return the type of class element this object is.
virtual PRMType & type()=0
Return a reference over the gum::PRMType of this class element.
static INLINE bool isAttribute(const PRMClassElement< GUM_SCALAR > &elt)
Returns true if obj_ptr is of type PRMAttribute.
virtual void setId(NodeId id)
Used to assign the id of this element.
NodeId id() const
Returns the NodeId of this element in it's class DAG.
const std::string & safeName() const
Returns the safe name of this PRMClassElement, if any.
typename NodeProperty< PRMClassElement< GUM_SCALAR > * >::const_iterator const_ClassEltIterator
void _addImplementation_(PRMClass< GUM_SCALAR > *c)
Add an Class<GUM_SCALAR> to the set of Class<GUM_SCALAR> which implements this PRMInterface.
Set< PRMAttribute< GUM_SCALAR > * > _attributes_
The sequence of PRMAttribute<GUM_SCALAR>s.
HashTable< std::string, PRMClassElement< GUM_SCALAR > * > _nameMap_
Mapping between a member's name and itself. Used for fast access to a member given it's name.
void _inheritInterface_(const PRMInterface< GUM_SCALAR > &i)
Proceed with the copy of i in this.
PRMInterface< GUM_SCALAR > * _superInterface_
The alternate PRMClassElementContainer<GUM_SCALAR> searched for elements defined in this....
const Set< PRMAttribute< GUM_SCALAR > * > & attributes() const
Returns the set of PRMAttribute<GUM_SCALAR> of this Class<GUM_SCALAR>.
bool isOutputNode(const PRMClassElement< GUM_SCALAR > &elt) const override
See gum::prm::PRMClassElementContainer<GUM_SCALAR>::get(conststd::string&).
void _overloadReferenceSlot_(PRMReferenceSlot< GUM_SCALAR > *overloader, PRMReferenceSlot< GUM_SCALAR > *overloaded)
The alternate PRMClassElementContainer<GUM_SCALAR> searched for elements defined in this....
NodeId add(PRMClassElement< GUM_SCALAR > *elt) override
See gum::prm::PRMClassElementContainer<GUM_SCALAR>::add(PRMClassElement<GUM_SCALAR>*).
Set< PRMClass< GUM_SCALAR > * > & implementations()
Returns the set of Class<GUM_SCALAR> implementing this PRMInterface.
void addArc(std::string_view tail, std::string_view head) override
An Interfance doesn't have any arc, this will raise an OperationNotAllowed exception.
Set< PRMReferenceSlot< GUM_SCALAR > * > _referenceSlots_
The sequence of PRMReferenceSlot<GUM_SCALAR>.
PRMInterface< GUM_SCALAR > & super()
Returns the superInterface of this PRMInterface.
void inheritInterface()
Inherits from this interface super interface, this should only be done when this inteface inheritance...
NodeProperty< PRMClassElement< GUM_SCALAR > * > _nodeIdMap_
Mapping between node's id and their name (being an attribute or a slot). Used for fast access to a me...
const ClassEltIterator & end()
PRMClassElement< GUM_SCALAR > & operator[](NodeId id) override
See gum::prm::PRMClassElementContainer<GUM_SCALAR>::operator[](NodeId).
typename NodeProperty< PRMClassElement< GUM_SCALAR > * >::iterator ClassEltIterator
PRMClassElement< GUM_SCALAR > & get(NodeId id) override
See gum::prm::PRMClassElementContainer<GUM_SCALAR>::get(NodeId).
void _overloadAttribute_(PRMAttribute< GUM_SCALAR > *overloader, PRMAttribute< GUM_SCALAR > *overloaded)
The alternate PRMClassElementContainer<GUM_SCALAR> searched for elements defined in this....
NodeId overload(PRMClassElement< GUM_SCALAR > *elt) override
Add a new PRMClassElement<GUM_SCALAR> which overload an inherited PRMClassElement<GUM_SCALAR>.
PRMObject::prm_type obj_type() const override
Implementation of pure virtual method of PRMObject.
bool _checkOverloadLegality_(const PRMClassElement< GUM_SCALAR > *overloaded, const PRMClassElement< GUM_SCALAR > *overloader)
The alternate PRMClassElementContainer<GUM_SCALAR> searched for elements defined in this....
const DAG & dag_() const override
Returns a constant reference over this PRMInterface's DAG.
~PRMInterface() override
Destructor.
void _addCastDescendants_(PRMAttribute< GUM_SCALAR > *start, PRMAttribute< GUM_SCALAR > *end)
The alternate PRMClassElementContainer<GUM_SCALAR> searched for elements defined in this....
ClassEltIterator begin()
void updateDescendants_(const PRMClassElement< GUM_SCALAR > &elt) override
See gum::prm::PRMClassElementContainer<GUM_SCALAR>(constPRMClassElement<GUM_SCALAR>&).
PRMInterface(std::string_view name)
Default constructor.
void _addExtension_(PRMInterface< GUM_SCALAR > *c)
Add an Class<GUM_SCALAR> to the set of Class<GUM_SCALAR> which implements this PRMInterface.
const Set< PRMReferenceSlot< GUM_SCALAR > * > & referenceSlots() const
Returns the set of PRMAggregate of this Class<GUM_SCALAR>.
friend class PRMClass< GUM_SCALAR >
Set< PRMClass< GUM_SCALAR > * > _implementations_
The set of Class<GUM_SCALAR> which implements this PRMInterface.
DAG _dag_
The dag representing dependencies between formal attributes and slots.
bool isSubTypeOf(const PRMClassElementContainer< GUM_SCALAR > &cec) const override
Test if this PRMInterface is a sub PRMInterface of cec.
Set< PRMInterface< GUM_SCALAR > * > _extensions_
The set of Class<GUM_SCALAR> which implements this PRMInterface.
void findAllSubtypes_(Set< PRMClassElementContainer< GUM_SCALAR > * > &set) override
Fills set with all the subtypes of this PRMInterface, this includes extensions and implementations.
const std::string & name() const
Returns the name of this object.
prm_type
Enumeration of the different types of objects handled by a PRM.
Definition PRMObject.h:90
virtual prm_type obj_type() const =0
Returns the type of this object.
A PRMReferenceSlot represent a relation between two PRMClassElementContainer.
PRMClassElementContainer< GUM_SCALAR > & slotType()
Returns the type of this slot, which is a PRMClassElementContainer (it is not the type of PRMObject).
<agrum/PRM/elements/scalarAttribute.h>
PRMType & superType()
Returns the super type of this type.
Definition PRMType_inl.h:57
bool isSubTypeOf(const PRMType &super) const
Returns true if this is a subtype of super.
Definition PRMType.cpp:114
bool isSubType() const
Returns true if this type is a sub-type.
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
Size NodeId
Type for node ids.
namespace for all probabilistic relational models entities
Definition agrum.h:68
NodeId nextNodeId()
Returns the next value of an unique counter for PRM's node id.
Definition utils_prm.cpp:84
gum is the global namespace for all aGrUM entities
Definition agrum.h:46