aGrUM 2.3.2
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-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#pragma once
41
42
51
52namespace gum {
53 namespace prm {
54
55 template < typename GUM_SCALAR >
58 GUM_CONSTRUCTOR(PRMInterface);
59 }
60
61 template < typename GUM_SCALAR >
64 bool delayInheritance) :
66 GUM_CONSTRUCTOR(PRMInterface);
67 if (!delayInheritance) { _inheritInterface_(super); }
68 }
69
70 template < typename GUM_SCALAR >
72 PRMClassElementContainer< GUM_SCALAR >(source.name()), _dag_(source._dag_),
74 GUM_CONS_CPY(PRMInterface);
75 GUM_ERROR(FatalError, "don't copy an interface")
76 }
77
78 template < typename GUM_SCALAR >
80 GUM_DESTRUCTOR(PRMInterface);
81
82 for (const auto& elt: _nodeIdMap_) {
83 delete elt.second;
84 }
85 }
86
87 template < typename GUM_SCALAR >
91
92 template < typename GUM_SCALAR >
94 // Copying attributes
95 for (const auto i_attr: i._attributes_) {
96 auto attr = new PRMScalarAttribute< GUM_SCALAR >(i_attr->name(), i_attr->type());
97 attr->setId(i_attr->id());
98 _nodeIdMap_.insert(attr->id(), attr);
99 _attributes_.insert(attr);
100
101 if (i._nameMap_[i_attr->name()] == i._nameMap_[i_attr->safeName()]) {
102 _nameMap_.insert(attr->name(), attr);
103 }
104
105 _nameMap_.insert(attr->safeName(), attr);
106 _dag_.addNodeWithId(attr->id());
107 }
108
109 // Copying reference slots
110 for (const auto i_ref: i._referenceSlots_) {
112 i_ref->name(),
113 const_cast< PRMClassElementContainer< GUM_SCALAR >& >(i_ref->slotType()),
114 i_ref->isArray());
115
116 ref->setId(i_ref->id());
117 _nodeIdMap_.insert(ref->id(), ref);
118 _referenceSlots_.insert(ref);
119
120 if (i._nameMap_.exists(ref->name())) { _nameMap_.insert(ref->name(), ref); }
121
122 _nameMap_.insert(ref->safeName(), ref);
123 _dag_.addNodeWithId(ref->id());
124 }
125 }
126
127 template < typename GUM_SCALAR >
129 if (_nameMap_.exists(elt->name())) {
131 "name '" << elt->name() << "' is already used by another ClassElement");
132 }
133
135 PRMAttribute< GUM_SCALAR >* attr = static_cast< PRMAttribute< GUM_SCALAR >* >(elt);
136 _nameMap_.insert(attr->name(), attr);
138 while (true) {
139 attr->setId(nextNodeId());
140 _dag_.addNodeWithId(attr->id());
141 _nodeIdMap_.insert(attr->id(), attr);
142 _nameMap_.insert(attr->safeName(), attr);
143 _attributes_.insert(attr);
144
145 if (attr->type().isSubType()) {
146 attr = attr->getCastDescendant();
147 } else {
148 break;
149 }
150 }
152 elt->setId(nextNodeId());
153 _dag_.addNodeWithId(elt->id());
154 _nodeIdMap_.insert(elt->id(), elt);
155 _referenceSlots_.insert(static_cast< PRMReferenceSlot< GUM_SCALAR >* >(elt));
156 _nameMap_.insert(elt->name(), elt);
157 _nameMap_.insert(elt->safeName(), elt);
158 } else {
159 GUM_ERROR(WrongClassElement, "illegal ClassElement<GUM_SCALAR> for an Interface")
161
162 return elt->id();
163 }
164
165 template < typename GUM_SCALAR >
167 try {
168 if (!super().exists(overloader->name()))
169 GUM_ERROR(OperationNotAllowed, "found no ClassElement<GUM_SCALAR> to overload")
171 } catch (NotFound const&) {
172 GUM_ERROR(OperationNotAllowed, "overload is possible only with sub interfaces")
173 }
174
175 PRMClassElement< GUM_SCALAR >* overloaded = _nameMap_[overloader->name()];
176 if (overloaded == overloader)
177 GUM_ERROR(DuplicateElement, "duplicate ClassElement '" << overloader->name() << "'")
178
179 if (!_checkOverloadLegality_(overloaded, overloader))
180 GUM_ERROR(OperationNotAllowed, "illegal overload")
181
182 switch (overloader->elt_type()) {
184 auto attr_overloader = static_cast< PRMAttribute< GUM_SCALAR >* >(overloader);
185 auto attr_overloaded = static_cast< PRMAttribute< GUM_SCALAR >* >(overloaded);
186 _overloadAttribute_(attr_overloader, attr_overloaded);
187 break;
188 }
189
191 auto ref_overloader = static_cast< PRMReferenceSlot< GUM_SCALAR >* >(overloader);
192 auto ref_overloaded = static_cast< PRMReferenceSlot< GUM_SCALAR >* >(overloaded);
193 _overloadReferenceSlot_(ref_overloader, ref_overloaded);
194 break;
195 }
196
199 GUM_ERROR(OperationNotAllowed,
200 "Element " << overloader->name() << " can not be overloaded")
201 default :
202 GUM_ERROR(FatalError, "Unknown ClassElement<GUM_SCALAR> type for " << overloader->name())
203 }
204
205 return overloader->id();
206 }
207
208 template < typename GUM_SCALAR >
209 void PRMInterface< GUM_SCALAR >::_overloadAttribute_(PRMAttribute< GUM_SCALAR >* overloader,
210 PRMAttribute< GUM_SCALAR >* overloaded) {
211 if (overloader->type() != overloaded->type()) {
212 overloader->setId(nextNodeId());
213 _dag_.addNodeWithId(overloader->id());
214 _nodeIdMap_.insert(overloader->id(), overloader);
215 _nameMap_[overloader->name()] = overloader;
216 _nameMap_.insert(overloader->safeName(), overloader);
217 _attributes_.insert(overloader);
218 _addCastDescendants_(overloader, overloaded);
219 } else {
220 overloader->setId(overloaded->id());
221 _nodeIdMap_[overloader->id()] = overloader;
222 _nameMap_[overloader->name()] = overloader;
223 _nameMap_[overloader->safeName()] = overloader;
224 _attributes_.erase(overloaded);
225 _attributes_.insert(overloader);
226 // Swapping types, ugly but necessary to preserve the
227 // PRMType<GUM_SCALAR>
228 // pointer of overloaded
229 overloader->overload(overloaded);
230 delete overloaded;
231 }
232 }
233
234 template < typename GUM_SCALAR >
237 PRMReferenceSlot< GUM_SCALAR >* overloaded) {
238 // Adding overloading reference
239 overloader->setId(overloaded->id());
240 _nodeIdMap_[overloader->id()] = overloader;
241 _nameMap_[overloader->name()] = overloader;
242 _nameMap_.insert(overloader->safeName(), overloader);
243 _referenceSlots_.insert(overloader);
244 // Removing overloaded PRMReferenceSlot<GUM_SCALAR>
245 _referenceSlots_.erase(overloaded);
246 _nameMap_.erase(overloaded->safeName());
247 delete overloaded;
248 }
249
250 template < typename GUM_SCALAR >
253 PRMAttribute< GUM_SCALAR >* parent = start;
255
256 while (parent->type().superType() != end->type()) {
257 child = parent->getCastDescendant();
258 child->setId(nextNodeId());
259 _dag_.addNodeWithId(child->id());
260 _nodeIdMap_.insert(child->id(), child);
261 // Only use child's safe name when adding to the name map!
262 _nameMap_.insert(child->safeName(), child);
263 _attributes_.insert(child);
264 // Do ! use Class<GUM_SCALAR>::insertArc(), child's CPF is already
265 // initialized properly
266 parent = child;
267 }
268
269 parent->setAsCastDescendant(end);
270 }
271
272 template < typename GUM_SCALAR >
274 const PRMClassElement< GUM_SCALAR >* overloaded,
275 const PRMClassElement< GUM_SCALAR >* overloader) {
276 if (overloaded->elt_type() != overloader->elt_type()) { return false; }
277
279 if (!overloader->type().isSubTypeOf(overloaded->type())) { return false; }
280 } else if (overloaded->elt_type() == PRMClassElement< GUM_SCALAR >::prm_refslot) {
281 auto ref_overloader = static_cast< const PRMReferenceSlot< GUM_SCALAR >* >(overloader);
282 auto ref_overloaded = static_cast< const PRMReferenceSlot< GUM_SCALAR >* >(overloaded);
283 if (!ref_overloader->slotType().isSubTypeOf(ref_overloaded->slotType())) { return false; }
284 } else {
285 return false;
286 }
287 return true;
288 }
289
290 template < typename GUM_SCALAR >
293 switch (cec.obj_type()) {
295 return false;
299 const PRMInterface* current = this;
300
301 while (current != 0) {
302 if (current == &(cec)) return true;
303
304 current = current->_superInterface_;
305 }
306
307 return false;
309
310 default : {
311 GUM_ERROR(FatalError, "unknown ClassElementContainer<GUM_SCALAR>")
312 }
313 }
314 }
315
316 template < typename GUM_SCALAR >
318 // for ( const auto ext : _extensions_ )
319 // if ( !ext->isOutputNode( elt ) ) ext->setOutputNode( elt, true );
321 // for ( const auto impl : _implementations_ ) {
322 // // Because of cyclic dependencies we must use a reinterpret cast.
323 // PRMClassElementContainer<GUM_SCALAR>* c =
324 // reinterpret_cast<PRMClassElementContainer<GUM_SCALAR>*>( impl );
325
326 // if ( ! c->isOutputNode( elt ) ) c->setOutputNode( elt, true );
327 //}
328 }
329
330 template < typename GUM_SCALAR >
333 return _nodeIdMap_.begin();
334 }
335
336 template < typename GUM_SCALAR >
339 return _nodeIdMap_.end();
340 }
341
342 template < typename GUM_SCALAR >
345 return _nodeIdMap_.begin();
346 }
347
348 template < typename GUM_SCALAR >
351 return _nodeIdMap_.end();
352 }
353
354 template < typename GUM_SCALAR >
355 INLINE void PRMInterface< GUM_SCALAR >::addArc(const std::string& tail,
356 const std::string& head) {
357 GUM_ERROR(OperationNotAllowed, "an Interface does ! have arcs")
358 }
359
360 template < typename GUM_SCALAR >
363 else GUM_ERROR(NotFound, "this Interface is ! a sub interface")
364 }
365
366 template < typename GUM_SCALAR >
369 else GUM_ERROR(NotFound, "this Interface is ! a sub interface")
370 }
371
372 template < typename GUM_SCALAR >
377 template < typename GUM_SCALAR >
381
382 template < typename GUM_SCALAR >
384 return get(id);
385 }
387 template < typename GUM_SCALAR >
390 return get(id);
391 }
393 template < typename GUM_SCALAR >
396 return get(name);
397 }
398
399 template < typename GUM_SCALAR >
402 return get(name);
403 }
404
405 template < typename GUM_SCALAR >
409
410 template < typename GUM_SCALAR >
411 INLINE const DAG& PRMInterface< GUM_SCALAR >::dag_() const {
412 return _dag_;
413 }
414
415 template < typename GUM_SCALAR >
417 return _dag_;
418 }
419
420 template < typename GUM_SCALAR >
422 try {
423 return *(_nodeIdMap_[id]);
424 } catch (NotFound const&) {
425 GUM_ERROR(NotFound, "no ClassElement<GUM_SCALAR> with the given NodeId")
426 }
427 }
428
429 template < typename GUM_SCALAR >
431 try {
432 return *(_nodeIdMap_[id]);
433 } catch (NotFound const&) {
434 GUM_ERROR(NotFound, "no ClassElement<GUM_SCALAR> with the given NodeId")
435 }
436 }
437
438 template < typename GUM_SCALAR >
440 try {
441 return *(_nameMap_[name]);
442 } catch (NotFound const&) {
443 GUM_ERROR(NotFound, "no ClassElement<GUM_SCALAR> with the given name")
444 }
445 }
446
447 template < typename GUM_SCALAR >
449 PRMInterface< GUM_SCALAR >::get(const std::string& name) const {
450 try {
451 return *(_nameMap_[name]);
452 } catch (NotFound const&) {
453 GUM_ERROR(NotFound, "no ClassElement<GUM_SCALAR> with the given name")
454 }
455 }
456
457 template < typename GUM_SCALAR >
458 INLINE const Set< PRMAttribute< GUM_SCALAR >* >&
462
463 template < typename GUM_SCALAR >
468
469 template < typename GUM_SCALAR >
473
474 template < typename GUM_SCALAR >
475 INLINE const Set< PRMClass< GUM_SCALAR >* >&
479
480 template < typename GUM_SCALAR >
483 for (const auto impl: _implementations_) {
484 set.insert(impl);
485 impl->findAllSubtypes_(set);
486 }
487
488 for (const auto ext: _extensions_) {
489 set.insert(ext);
490 ext->findAllSubtypes_(set);
491 }
492 }
493
494 template < typename GUM_SCALAR >
495 INLINE bool
497 try {
498 if (!this->getIOFlag_(elt).second) {
499 for (auto i: _implementations_) {
500 if (i->isOutputNode(elt)) { return true; }
501 }
502
503 if (_superInterface_ && _superInterface_->isOutputNode(elt)) { return true; }
504
505 } else {
506 return true;
507 }
508 } catch (NotFound const&) {}
509 return false;
510 }
511 } /* namespace prm */
512} /* 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:131
PRMAttribute is a member of a Class in a PRM.
virtual void setAsCastDescendant(PRMAttribute< GUM_SCALAR > *attr)=0
Define attr as a cast descendant of this PRMAttribute.
virtual PRMAttribute< GUM_SCALAR > * getCastDescendant() const =0
Returns a proper cast descendant of this PRMAttribute.
virtual PRMType & type()=0
See gum::PRMClassElement::type().
virtual std::pair< bool, bool > & getIOFlag_(const PRMClassElement< GUM_SCALAR > &elt)
Returns the IO flags of a PRMClassElement<GUM_SCALAR>.
PRMClassElementContainer(const std::string &name)
Default constructor.
virtual bool exists(const std::string &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.
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.
virtual ClassElementType elt_type() const =0
Return the type of class element this object is.
static INLINE bool isReferenceSlot(const PRMClassElement< GUM_SCALAR > &elt)
Returns true if obj_ptr is of type PRMReferenceSlot.
virtual PRMType & type()=0
Return a reference over the gum::PRMType of this class element.
const std::string & safeName() const
Returns the safe name of this PRMClassElement, if any.
static INLINE bool isAttribute(const PRMClassElement< GUM_SCALAR > &elt)
Returns true if obj_ptr is of type PRMAttribute.
void findAllSubtypes_(Set< PRMClassElementContainer< GUM_SCALAR > * > &set)
Fills set with all the subtypes of this PRMInterface, this includes extensions and implementations.
typename NodeProperty< PRMClassElement< GUM_SCALAR > * >::const_iterator const_ClassEltIterator
PRMInterface(const std::string &name)
Default constructor.
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....
void _overloadReferenceSlot_(PRMReferenceSlot< GUM_SCALAR > *overloader, PRMReferenceSlot< GUM_SCALAR > *overloaded)
The alternate PRMClassElementContainer<GUM_SCALAR> searched for elements defined in this....
virtual bool isSubTypeOf(const PRMClassElementContainer< GUM_SCALAR > &cec) const
Test if this PRMInterface is a sub PRMInterface of cec.
virtual PRMClassElement< double > & get(NodeId id)
void _addImplementation_(PRMClass< GUM_SCALAR > *c)
Add an Class<GUM_SCALAR> to the set of Class<GUM_SCALAR> which implements this PRMInterface.
void _addExtension_(PRMInterface< GUM_SCALAR > *c)
Add an Class<GUM_SCALAR> to the set of Class<GUM_SCALAR> which implements this PRMInterface.
virtual ~PRMInterface()
Destructor.
Set< PRMReferenceSlot< GUM_SCALAR > * > _referenceSlots_
The sequence of PRMReferenceSlot<GUM_SCALAR>.
virtual PRMObject::prm_type obj_type() const
Implementation of pure virtual method of PRMObject.
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...
typename NodeProperty< PRMClassElement< GUM_SCALAR > * >::iterator ClassEltIterator
ClassEltIterator begin()
void _overloadAttribute_(PRMAttribute< GUM_SCALAR > *overloader, PRMAttribute< GUM_SCALAR > *overloaded)
The alternate PRMClassElementContainer<GUM_SCALAR> searched for elements defined in this....
bool _checkOverloadLegality_(const PRMClassElement< GUM_SCALAR > *overloaded, const PRMClassElement< GUM_SCALAR > *overloader)
The alternate PRMClassElementContainer<GUM_SCALAR> searched for elements defined in this....
PRMClassElement< GUM_SCALAR > & operator[](NodeId id)
See gum::prm::PRMClassElementContainer<GUM_SCALAR>::operator[](NodeId).
const Set< PRMAttribute< GUM_SCALAR > * > & attributes() const
Returns the set of PRMAttribute<GUM_SCALAR> of this Class<GUM_SCALAR>.
void _addCastDescendants_(PRMAttribute< GUM_SCALAR > *start, PRMAttribute< GUM_SCALAR > *end)
The alternate PRMClassElementContainer<GUM_SCALAR> searched for elements defined in this....
void updateDescendants_(const PRMClassElement< GUM_SCALAR > &elt)
See gum::prm::PRMClassElementContainer<GUM_SCALAR>(constPRMClassElement<GUM_SCALAR>&).
const DAG & dag_() const
Returns a constant reference over this PRMInterface's DAG.
const ClassEltIterator & end()
virtual bool isOutputNode(const PRMClassElement< GUM_SCALAR > &elt) const
See gum::prm::PRMClassElementContainer<GUM_SCALAR>::get(conststd::string&).
friend class PRMClass< GUM_SCALAR >
void addArc(const std::string &tail, const std::string &head)
An Interfance doesn't have any arc, this will raise an OperationNotAllowed exception.
Set< PRMClass< GUM_SCALAR > * > _implementations_
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>.
DAG _dag_
The dag representing dependencies between formal attributes and slots.
PRMInterface< GUM_SCALAR > & super()
Returns the superInterface of this PRMInterface.
NodeId add(PRMClassElement< GUM_SCALAR > *elt)
See gum::prm::PRMClassElementContainer<GUM_SCALAR>::add(PRMClassElement<GUM_SCALAR>*).
Set< PRMInterface< GUM_SCALAR > * > _extensions_
The set of Class<GUM_SCALAR> which implements this PRMInterface.
NodeId overload(PRMClassElement< GUM_SCALAR > *elt)
Add a new PRMClassElement<GUM_SCALAR> which overload an inherited PRMClassElement<GUM_SCALAR>.
Set< PRMClass< GUM_SCALAR > * > & implementations()
Returns the set of Class<GUM_SCALAR> implementing this PRMInterface.
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:88
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:56
bool isSubTypeOf(const PRMType &super) const
Returns true if this is a subtype of super.
Definition PRMType.cpp:116
bool isSubType() const
Returns true if this type is a sub-type.
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
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