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