aGrUM 3.1.1
a C++ library for (probabilistic) graphical models
nodeGraphPart.cpp
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
49
50#ifdef GUM_NO_INLINE
52#endif // GU%_NO_INLINE
53
54namespace gum {
55
57 NodeGraphPart::NodeGraphPart(Size holes_size, bool holes_resize_policy) :
58 _holes_size_(holes_size), _holes_resize_policy_(holes_resize_policy),
59 _endIteratorSafe_(*this), _boundVal_(0) {
60 _holes_ = nullptr;
61 GUM_CONSTRUCTOR(NodeGraphPart);
63 }
64
78
83 s._holes_ = nullptr;
84 s._boundVal_ = 0;
85
87
88 GUM_CONS_MOV(NodeGraphPart);
89 }
90
92 if (_holes_) delete _holes_;
93
94 GUM_DESTRUCTOR(NodeGraphPart);
95 }
96
98 clear(); // "virtual" flush of the nodes set
101
102 if (s._holes_) _holes_ = new NodeSet(*s._holes_);
103
104 _names_ = s._cloneNames_();
105
107
109 }
110
111 // id is assumed to belong to NodeGraphPart
113 // we assume that the node exists
114 if (node + 1 == _boundVal_) {
115 // we remove the max : no new hole and maybe a bunch of holes to remove
116 --_boundVal_;
117
118 if (_holes_) {
119 while (_holes_->contains(_boundVal_ - 1)) {
120 // a bunch of holes to remove. We do not use inHoles for optimisation
121 // :
122 // not to repeat the test if ( _holes_) each time
123 _holes_->erase(--_boundVal_);
124 }
125
126 if (_holes_->empty()) {
127 delete _holes_;
128 _holes_ = nullptr;
129 }
130 }
131
133 } else {
135
136 _holes_->insert(node);
137 }
138 }
139
140 std::string NodeGraphPart::toString() const {
141 std::string s = "{";
142 bool first = true;
143
144 const bool hasNames = (_names_ != nullptr);
145 for (NodeId id = 0; id < _boundVal_; ++id) {
146 if (_inHoles_(id)) continue;
147
148 if (!first) s += ",";
149 first = false;
150
151 if (hasNames && _names_->existsFirst(id)) s += std::format("{}<{}>", id, _names_->second(id));
152 else s += std::format("{}", id);
153 }
154
155 s += "}";
156
157 return s;
158 }
159
160 std::string NodeGraphPart::nameFromId(NodeId id) const {
161 if (_names_ && _names_->existsFirst(id)) return _names_->second(id);
162 return std::to_string(id);
163 }
164
165 std::optional< NodeId > NodeGraphPart::idFromName(const std::string& name) const {
166 if (_names_ && _names_->existsSecond(name)) return _names_->first(name);
167 return std::nullopt;
168 }
169
170 void NodeGraphPart::setName(NodeId id, const std::string& name) {
171 if (!existsNode(id)) GUM_ERROR(InvalidNode, "node " << id << " does not exist")
172 if (_names_) {
173 auto owner = _names_->tryFirst(name);
174 if (owner.has_value()) {
175 if (*owner != id)
176 GUM_ERROR(DuplicateElement, "name '" << name << "' already used by node " << *owner)
177 return;
178 }
179 if (_names_->existsFirst(id)) _names_->eraseFirst(id);
180 } else {
181 _names_ = std::make_unique< Bijection< NodeId, std::string > >();
182 }
183 _names_->insert(id, name);
184 }
185
186 bool NodeGraphPart::hasName(NodeId id) const { return _names_ && _names_->existsFirst(id); }
187
188 std::string NodeGraphPart::dotNodeLabel(NodeId id) const {
189 if (!hasName(id)) return "";
190 const std::string& name = _names_->second(id);
191 std::string result;
192 result.reserve(name.size() * 2 + 24);
193 result = " [label=\"(";
194 result += std::to_string(id);
195 result += ") ";
196 for (const char c: name) {
197 switch (c) {
198 case '"' : result += "\\\""; break;
199 case '\\' : result += "\\\\"; break;
200 case '\n' : result += "\\n"; break;
201 case '\r' : result += "\\r"; break;
202 default : result += c;
203 }
204 }
205 result += "\"]";
206 return result;
207 }
208
209 std::ostream& operator<<(std::ostream& stream, const NodeGraphPart& set) {
210 stream << set.toString();
211 return stream;
212 }
213
215 if (id >= _boundVal_) {
216 if (id > _boundVal_) { // we have to add holes
218
219 for (NodeId i = _boundVal_; i < id; ++i)
220 _holes_->insert(i);
221 }
222
223 _boundVal_ = id + 1;
224
226 } else {
227 if (_inHoles_(id)) { // we fill a hole
228 _eraseHole_(id);
229 } else {
230 GUM_ERROR(DuplicateElement, "Id " << id << " is already used")
231 }
232 }
233
235 }
236
239 _boundVal_ = 0;
240
241 if (onNodeDeleted.hasListener()) {
242 for (NodeId n = 0; n < bound; ++n) {
243 if (!_inHoles_(n)) GUM_EMIT1(onNodeDeleted, n);
244 }
245 }
246
248
249 delete (_holes_);
250 _holes_ = nullptr;
251 _names_.reset();
252 }
253
255 if (id == pos_) { // we just deleted the pos_ in NodeGraphPart
256 valid_ = false;
257 }
258
259 if (pos_ >= nodes_->bound()) { // moreover, it was the last position
260 pos_ = nodes_->bound();
261 valid_ = false;
262 }
263 }
264
265} /* namespace gum */
Exception : a similar element already exists.
Exception : node does not exist.
void whenNodeDeleted(const void *src, NodeId id)
called when a node is deleted in the iterated NodeGraphPart
const NodeGraphPart * nodes_
the nodegraphpart on which points the iterator
NodeId pos_
the nodeid on which the iterator points currently
Class for node sets in graph.
NodeGraphPartIteratorSafe _endIteratorSafe_
the end iterator (used to speed-up parsings of the NodeGraphPart)
void populateNodes(const NodeGraphPart &s)
populateNodes clears *this and fills it with the same nodes as "s"
Signaler< NodeId > onNodeDeleted
void _clearNodes_()
code for clearing nodes (called twice)
virtual void clear()
alias for clearNodes
std::unique_ptr< Bijection< NodeId, std::string > > _names_
optional node names — null when no name has been set
NodeId bound() const
returns a number n such that all node ids are strictly lower than n
bool hasName(NodeId id) const
returns true iff node id has an explicit name
void _eraseHole_(NodeId id)
to delete hole.
std::string nameFromId(NodeId id) const
returns the name of node id, or "<id>" if no name is set
void _updateEndIteratorSafe_()
updating endIterator (always at max+1)
void setName(NodeId id, const std::string &name)
sets the name of node id
Size _holes_size_
value for holes configuration
virtual std::string toString() const
a function to display the set of nodes
std::string dotNodeLabel(NodeId id) const
returns " [label=\"...\"]" with DOT-escaped name, or "" if no name
bool _holes_resize_policy_
value for holes configuration
virtual ~NodeGraphPart()
destructor
std::unique_ptr< Bijection< NodeId, std::string > > _cloneNames_() const
clone the names bijection (returns nullptr when no name has been set)
NodeSet * _holes_
the set of nodes not contained in the NodeGraphPart in the interval 1.
Signaler< NodeId > onNodeAdded
NodeId _boundVal_
the id below which NodeIds may belong to the NodeGraphPart
std::optional< NodeId > idFromName(const std::string &name) const
returns the id of the node with the given name, or std::nullopt
NodeGraphPart(Size holes_size=HashTableConst::default_size, bool holes_resize_policy=true)
default constructor
void _addHole_(NodeId id)
to add a hole.
bool _inHoles_(NodeId id) const
bool existsNode(const NodeId id) const
returns true iff the NodeGraphPart contains the given nodeId
virtual void addNodeWithId(const NodeId id)
try to insert a node with the given id
#define GUM_ERROR(type, msg)
Definition exceptions.h:76
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Definition types.h:74
Size NodeId
Type for node ids.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
std::ostream & operator<<(std::ostream &stream, const AVLTree< Val, Cmp > &tree)
display the content of a tree
STL namespace.
Base node set class for graphs.
Inline implementation of the base node set class for graphs.
#define GUM_EMIT1(signal, arg1)
Definition signaler.h:289