1 /** 2 * 3 * Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_AMU) 4 * info_at_agrum_dot_org 5 * 6 * This library is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU Lesser General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public License 17 * along with this library. If not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 22 /** @file 23 * @brief Base node set class for graphs 24 * 25 * @author Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_AMU) 26 */ 27 #ifndef GUM_NODE_GRAPH_PART_H 28 #define GUM_NODE_GRAPH_PART_H 29 30 #include <algorithm> 31 #include <utility> 32 33 #include <agrum/agrum.h> 34 35 #include <agrum/tools/graphs/graphElements.h> 36 37 #include <agrum/tools/core/signal/listener.h> 38 #include <agrum/tools/core/signal/signaler.h> 39 40 #ifndef DOXYGEN_SHOULD_SKIP_THIS 41 42 namespace gum_tests { 43 44 class NodeGraphPartTestSuite; 45 } 46 47 #endif 48 49 namespace gum { 50 51 class NodeGraphPart; 52 53 /** 54 * @class NodeGraphPartIterator 55 * @brief Unsafe iterator on the node set of a graph. 56 */ 57 class NodeGraphPartIterator { 58 friend class NodeGraphPart; 59 60 public: 61 /// types for STL compliance 62 /// @{ 63 using iterator_category = std::forward_iterator_tag; 64 using value_type = NodeId; 65 using reference = value_type&; 66 using const_reference = const value_type&; 67 using pointer = value_type*; 68 using const_pointer = const value_type*; 69 using difference_type = std::ptrdiff_t; 70 /// @} 71 72 // ############################################################################ 73 /// @name Constructors / Destructors 74 // ############################################################################ 75 /// @{ 76 77 /** 78 * @brief Default constructor. 79 */ 80 NodeGraphPartIterator(const NodeGraphPart& nodes) noexcept; 81 82 /// copy constructor 83 NodeGraphPartIterator(const NodeGraphPartIterator& it) noexcept; 84 85 /// move constructor 86 NodeGraphPartIterator(NodeGraphPartIterator&& it) noexcept; 87 88 /// destructor 89 virtual ~NodeGraphPartIterator() noexcept; 90 91 /// @} 92 93 // ############################################################################ 94 /// @name Operators 95 // ############################################################################ 96 /// @{ 97 98 /// copy assignment operator 99 NodeGraphPartIterator& operator=(const NodeGraphPartIterator& it) noexcept; 100 101 /// move assignment operator 102 NodeGraphPartIterator& operator=(NodeGraphPartIterator&& it) noexcept; 103 104 /// checks whether two iterators point toward the same node 105 bool operator==(const NodeGraphPartIterator& it) const noexcept; 106 107 /// checks whether two iterators point toward different nodes 108 bool operator!=(const NodeGraphPartIterator& it) const noexcept; 109 110 /// increment the iterator 111 NodeGraphPartIterator& operator++() noexcept; 112 113 /// dereferencing operator 114 value_type operator*() const; 115 116 /// @} 117 118 protected: 119 /// @brief this function is used by @ref NodeGraphPart to update 120 void setPos_(NodeId id) noexcept; 121 122 /// ensure that the nodeId is either end() either a valid NodeId 123 void validate_() noexcept; 124 125 /// the nodegraphpart on which points the iterator 126 const NodeGraphPart* nodes_; 127 128 /// the nodeid on which the iterator points currently 129 NodeId pos_{0}; 130 131 // is this iterator still valid ? 132 bool valid_{false}; 133 }; 134 135 /** 136 * @class NodeGraphPartIteratorSafe 137 * @brief Safe iterator on the node set of a graph. 138 */ 139 class NodeGraphPartIteratorSafe: public NodeGraphPartIterator, public Listener { 140 friend class NodeGraphPart; 141 142 public: 143 /// types for STL compliance 144 /// @{ 145 using iterator_category = std::forward_iterator_tag; 146 using value_type = NodeId; 147 using reference = value_type&; 148 using const_reference = const value_type&; 149 using pointer = value_type*; 150 using const_pointer = const value_type*; 151 using difference_type = std::ptrdiff_t; 152 /// @} 153 154 // ############################################################################ 155 /// @name Constructors / Destructors 156 // ############################################################################ 157 /// @{ 158 159 /// default constructor 160 NodeGraphPartIteratorSafe(const NodeGraphPart& nodes); 161 162 /// copy constructor 163 NodeGraphPartIteratorSafe(const NodeGraphPartIteratorSafe& it); 164 165 /// move constructor 166 NodeGraphPartIteratorSafe(NodeGraphPartIteratorSafe&& it); 167 168 /// destructor 169 ~NodeGraphPartIteratorSafe(); 170 171 /// @} 172 173 // ############################################################################ 174 /// @name Operators 175 // ############################################################################ 176 /// @{ 177 178 /// copy assignment operator 179 NodeGraphPartIteratorSafe& operator=(const NodeGraphPartIteratorSafe& it); 180 181 /// move assignment operator 182 NodeGraphPartIteratorSafe& operator=(NodeGraphPartIteratorSafe&& it); 183 184 /// @} 185 186 // ############################################################################ 187 /// @name Accessors / Modifiers 188 // ############################################################################ 189 /// @{ 190 191 /// called when a node is deleted in the iterated NodeGraphPart 192 /** 193 * @param src the NodeGraphPart 194 * @param id id of deleted node 195 */ 196 void whenNodeDeleted(const void* src, NodeId id); 197 198 /// @} 199 }; 200 201 /** 202 * @class NodeGraphPart 203 * @brief Class for node sets in graph 204 * 205 * @ingroup graph_group 206 * 207 * NodeGraphPart represents the set of nodes of all the graphs. It is built to 208 * be as light as possible and it implements its own NodeId factory. 209 * The set of NodeId is 0 ... ( _bound_-1) minus the NodeIds in 210 * _holes_. 211 * 212 * @author Pierre-Henri WUILLEMIN(_at_LIP6) & Christophe GONZALES(_at_AMU) 213 * 214 * 215 * @par Usage example: 216 * @code 217 * // create an empty node list 218 * NodeGraphPart nodes1; 219 * 220 * // add 2 elements 221 * NodeId id_a=nodes1.addNode( ); 222 * NodeId id_b=nodes1.addNode( ); 223 * 224 * // checks if there exists a node with ID = 6 225 * if ( !nodes1.exists( 6 ) ) std::cerr << "no node with ID 6" << std::endl; 226 * 227 * // check if the set of nodes is empty 228 * if ( !nodes1.empty() || ( nodes1.size() != 0 ) ) 229 * std::cerr << "nodes1 is not empty" << std::endl; 230 * 231 * // copy a set of nodes 232 * NodeGraphPart nodes2 = nodes1, nodes3; 233 * nodes3 = nodes1; 234 * 235 * // remove elements from list3 236 * nodes3.eraseNode( id_a ); 237 * nodes3.eraseNode( id_b ); 238 * 239 * // remove all the elements from the list 240 * nodes1.clear(); 241 * 242 * for ( NodeGraphPart::iterator it=nodes2.beginNodes(); 243 * it!=nodes2.endNodes();++it ) { 244 * std::cerr<<*it<<" "; 245 * } 246 * 247 * std::cerr<<"list : "<<nodes2.listMapNodes(getDouble)<<std::endl; 248 * 249 * std::cerr<<"hashmap : "<<nodes2.hashMapNodes(getDouble)<<std::endl; 250 * @endcode 251 */ 252 253 class NodeGraphPart { 254 public: 255 /// types for STL compliance 256 /// @{ 257 using node_iterator = NodeGraphPartIterator; 258 using node_const_iterator = NodeGraphPartIterator; 259 using node_iterator_safe = NodeGraphPartIteratorSafe; 260 using node_const_iterator_safe = NodeGraphPartIteratorSafe; 261 /// @} 262 263 // something strange with SWIG (with "using", these definitions cored dump 264 // the 265 // swig process) 266 typedef NodeGraphPartIterator NodeIterator; 267 typedef NodeGraphPartIterator NodeConstIterator; 268 typedef NodeGraphPartIteratorSafe NodeIteratorSafe; 269 typedef NodeGraphPartIteratorSafe NodeConstIteratorSafe; 270 271 Signaler1< NodeId > onNodeAdded; 272 Signaler1< NodeId > onNodeDeleted; 273 274 // ############################################################################ 275 /// @name Constructors / Destructors 276 // ############################################################################ 277 /// @{ 278 279 /// default constructor 280 /** A NodeGrphPart does not store all its nodes. To be lighter in terms of 281 * memory consumption, it store its maximal NodeId and the set of NodeIds 282 * between 0 and this maximum that do not actually belong to the set of its 283 * nodes (the so-called set of holes). In practice, it turns out that the 284 * set of holes is most often very small. 285 * @param holes_size the size of the hash table used to store all holes 286 * @param holes_resize_policy the resizing policy of this hash table**/ 287 explicit NodeGraphPart(Size holes_size = HashTableConst::default_size, 288 bool holes_resize_policy = true); 289 290 /// copy constructor 291 /** @param s the NodeGraphPart to be copied */ 292 NodeGraphPart(const NodeGraphPart& s); 293 294 /// destructor 295 virtual ~NodeGraphPart(); 296 297 /// @} 298 299 // ############################################################################ 300 /// @name Operators 301 // ############################################################################ 302 /// @{ 303 304 /// copy operator 305 /** @param p the NodeGraphPart to be copied */ 306 NodeGraphPart& operator=(const NodeGraphPart& p); 307 308 /// check whether two NodeGraphParts contain the same nodes 309 /** @param p the NodeGraphPart to be compared with "this" */ 310 bool operator==(const NodeGraphPart& p) const; 311 312 /// check whether two NodeGraphParts contain different nodes 313 /** @param p the NodeGraphPart to be compared with "this" */ 314 bool operator!=(const NodeGraphPart& p) const; 315 316 /// @} 317 318 // ############################################################################ 319 /// @name Accessors/Modifiers 320 // ############################################################################ 321 /// @{ 322 323 /// populateNodes clears *this and fills it with the same nodes as "s" 324 /** populateNodes should basically be the preferred way to insert nodes with 325 * IDs not selected by the internal idFactory. 326 * @param s the NodeGraphPart to be copied */ 327 void populateNodes(const NodeGraphPart& s); 328 329 /// populateNodesFromProperty clears *this and fills it with the keys of "h" 330 /** populateNodes should basically be the preferred way to insert nodes with 331 * IDs not selected by the internal idFactory. */ 332 template < typename T > 333 void populateNodesFromProperty(const NodeProperty< T >& h); 334 335 /** returns a new node id, not yet used by any node 336 * @warning a code like @code id=nextNodeId();addNode(id); @endcode is 337 * basically not thread safe !! 338 * @return a node id not yet used by any node within the NodeGraphPart */ 339 NodeId nextNodeId() const; 340 341 /// insert a new node and return its id 342 /** @return the id chosen by the internal idFactory */ 343 virtual NodeId addNode(); 344 345 /** insert n nodes 346 * 347 * @param n the number of nodes to add 348 * @return the vector of chosen ids 349 */ 350 std::vector< NodeId > addNodes(Size n); 351 352 /// try to insert a node with the given id 353 /** @warning This method should be carefully used. Please prefer 354 * @ref populateNodes or @ref populateNodesFromProperty when possible 355 * @throws DuplicateElement exception if the id already exists 356 */ 357 virtual void addNodeWithId(const NodeId id); 358 359 /// erase the node with the given id 360 /** If the NodeGraphPart does not contain the nodeId, then nothing is done. 361 * In 362 * particular, no exception is raised. However, the signal onNodeDeleted is 363 * fired only if a node is effectively removed. */ 364 virtual void eraseNode(const NodeId id); 365 366 /// returns true iff the NodeGraphPart contains the given nodeId 367 bool existsNode(const NodeId id) const; 368 369 /// alias for @ref existsNode 370 bool exists(const NodeId id) const; 371 372 /// indicates whether there exists nodes in the NodeGraphPart 373 bool emptyNodes() const; 374 375 /// alias for @ref emptyNodes 376 bool empty() const; 377 378 /// remove all the nodes from the NodeGraphPart 379 virtual void clearNodes(); 380 381 /// alias for @ref clearNodes 382 virtual void clear(); 383 384 /// returns the number of nodes in the NodeGraphPart 385 Size sizeNodes() const; 386 387 /// alias for @ref sizeNodes 388 Size size() const; 389 390 /// returns a number n such that all node ids are strictly lower than n 391 NodeId bound() const; 392 393 /// returns a copy of the set of nodes represented by the NodeGraphPart 394 /** @warning this function is o(n) where n is the number of nodes. In space 395 * and 396 * in time. Usually, when you need to parse the nodes of a NodeGraphPart, 397 * prefer 398 * using @code for(const auto n : nodes()) @endcode rather than 399 * @code for(const auto n : asNodeSet()) @endcode as this is faster and 400 * consumes much less memory. */ 401 NodeSet asNodeSet() const; 402 403 /// return *this as a NodeGraphPart 404 const NodeGraphPart& nodes() const; 405 406 /// a begin iterator to parse the set of nodes contained in the 407 /// NodeGraphPart 408 node_iterator_safe beginSafe() const; 409 410 /// the end iterator to parse the set of nodes contained in the 411 /// NodeGraphPart 412 const node_iterator_safe& endSafe() const noexcept; 413 414 /// a begin iterator to parse the set of nodes contained in the 415 /// NodeGraphPart 416 node_iterator begin() const noexcept; 417 418 /// the end iterator to parse the set of nodes contained in the 419 /// NodeGraphPart 420 const node_iterator& end() const noexcept; 421 422 virtual /// a function to display the set of nodes 423 std::string 424 toString() const; 425 426 /// a method to create a HashTable with key:NodeId and value:VAL 427 /** VAL are computed from the nodes using for all node x, VAL f(x). 428 * This method is a wrapper of the same method in HashTable. 429 * @see HashTable::map. 430 * @param f a function assigning a VAL to any node 431 * @param size an optional parameter enabling to fine-tune the returned 432 * Property. Roughly speaking, it is a good practice to have a size equal to 433 * half the number of nodes. If you do not specify this parameter, the 434 * method 435 * will assign it for you. */ 436 template < typename VAL > 437 NodeProperty< VAL > nodesProperty(VAL (*f)(const NodeId&), Size size = 0) const; 438 439 /// a method to create a hashMap with key:NodeId and value:VAL 440 /** for all nodes, the value stored is a. This method is a wrapper of the 441 * same 442 * method in HashTable. 443 * @see HashTable::map. 444 * @param a the default value assigned to each edge in the returned Property 445 * @param size an optional parameter enabling to fine-tune the returned 446 * Property. Roughly speaking, it is a good practice to have a size equal to 447 * half the number of nodes. If you do not specify this parameter, the 448 * method 449 * will assign it for you. */ 450 template < typename VAL > 451 NodeProperty< VAL > nodesProperty(const VAL& a, Size size = 0) const; 452 453 /** @brief a method to create a list of VAL from a set of nodes 454 * (using for every nodee, say x, the VAL f(x)) 455 * @param f a function assigning a VAL to any node */ 456 template < typename VAL > 457 List< VAL > listMapNodes(VAL (*f)(const NodeId&)) const; 458 459 /// @} 460 461 private: 462 friend class NodeGraphPartIterator; 463 friend class NodeGraphPartIteratorSafe; 464 465 /// to enable testunits to use _check_ 466 467 friend class gum_tests::NodeGraphPartTestSuite; 468 469 /// updating endIterator (always at _max_+1) 470 void _updateEndIteratorSafe_(); 471 472 /// code for clearing nodes (called twice) 473 void _clearNodes_(); 474 475 /// to delete hole. 476 /// @warning the hole is assumed to be existing. 477 void _eraseHole_(NodeId id); 478 479 /// to add a hole. 480 /// @warning id is assumed not to be already a hole 481 void _addHole_(NodeId id); 482 483 // ############################################################################ 484 /// @name Introspection 485 // ############################################################################ 486 /// @{ 487 488 /// @return true if id is part of _holes_ 489 bool _inHoles_(NodeId id) const; 490 491 /// @return the size of _holes_ 492 Size _sizeHoles_() const; 493 494 /// @} 495 496 /** @brief the set of nodes not contained in the NodeGraphPart in the 497 * interval 1.. _max_ 498 * @warning _holes_ may be nullptr. */ 499 NodeSet* _holes_; 500 501 /// value for _holes_ configuration 502 Size _holes_size_; 503 504 /// value for _holes_ configuration 505 bool _holes_resize_policy_; 506 507 /// the end iterator (used to speed-up parsings of the NodeGraphPart) 508 NodeGraphPartIteratorSafe _endIteratorSafe_; 509 510 /** @brief the id below which NodeIds may belong to the NodeGraphPart */ 511 NodeId _boundVal_; 512 }; 513 514 /// for friendly displaying the content of node set 515 std::ostream& operator<<(std::ostream&, const NodeGraphPart&); 516 517 } /* namespace gum */ 518 519 #ifndef GUM_NO_INLINE 520 # include <agrum/tools/graphs/parts/nodeGraphPart_inl.h> 521 #endif // GUM_NOINLINE 522 523 #include <agrum/tools/graphs/parts/nodeGraphPart_tpl.h> 524 525 #endif // GUM_NODE_GRAPH_PART_H 526