containers/digraph.hpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
#ifndef STLPLUS_DIGRAPH
#define STLPLUS_DIGRAPH
////////////////////////////////////////////////////////////////////////////////
 
//   Author:    Andy Rushton
//   Copyright: (c) Southampton University 1999-2004
//              (c) Andy Rushton           2004 onwards
//   License:   BSD License, see ../docs/license.html
 
//   STL-style Directed graph template component
//   Digraph stands for directed-graph, i.e. all arcs have a direction
 
////////////////////////////////////////////////////////////////////////////////
#include "containers_fixes.hpp"
#include "safe_iterator.hpp"
#include "exceptions.hpp"
#include <vector>
#include <map>
#include <set>
#include <iterator>
 
namespace stlplus
{
 
  ////////////////////////////////////////////////////////////////////////////////
  // Internals
 
  template<typename NT, typename AT> class digraph_node;
  template<typename NT, typename AT> class digraph_arc;
  template<typename NT, typename AT> class digraph;
 
  ////////////////////////////////////////////////////////////////////////////////
  // The Digraph iterator classes
  // a digraph_iterator points to a node whilst a digraph_arc_iterator points to an arc
  // Note that these are redefined as:
  //   digraph<NT,AT>::iterator           - points to a non-const node
  //   digraph<NT,AT>::const_iterator     - points to a const node
  //   digraph<NT,AT>::arc_iterator       - points to a non-const arc
  //   digraph<NT,AT>::const_arc_iterator - points to a const arc
  // and this is the form in which they should be used
 
  template<typename NT, typename AT, typename NRef, typename NPtr>
  class digraph_iterator : public safe_iterator<digraph<NT,AT>, digraph_node<NT,AT> >
  {
  public:
    friend class digraph<NT,AT>;
 
    // iterator traits, were inherited from std::iterator but inheriting from that was deprecated in C++17
    // the digraph iterators are bidirectional but not random-access
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef NT value_type;
    typedef NPtr pointer;
    typedef NRef reference;
    // this is not random access, so declare a void difference type, not sure this is supported by everything
    // typedef std::ptrdiff_t  difference_type;
    typedef void difference_type;
 
    // local type definitions
    // an iterator points to an object whilst a const_iterator points to a const object
    typedef digraph_iterator<NT,AT,NT&,NT*> iterator;
    typedef digraph_iterator<NT,AT,const NT&,const NT*> const_iterator;
    typedef digraph_iterator<NT,AT,NRef,NPtr> this_iterator;
 
    // constructor to create a null iterator - you must assign a valid value to this iterator before using it
    digraph_iterator(void);
    ~digraph_iterator(void);
 
    // Type conversion methods allow const_iterator and iterator to be converted
    // convert an iterator/const_iterator to a const_iterator
    const_iterator constify(void) const;
    // convert an iterator/const_iterator to an iterator
    iterator deconstify(void) const;
 
    // increment/decrement operators used to step through the set of all nodes in a graph
    // it is only legal to increment a valid iterator
    // pre-increment
    // exceptions: null_dereference,end_dereference
    this_iterator& operator ++ (void);
    // post-increment
    // exceptions: null_dereference,end_dereference
    this_iterator operator ++ (int);
    // pre-decrement
    // exceptions: null_dereference,end_dereference
    this_iterator& operator -- (void);
    // post-decrement
    // exceptions: null_dereference,end_dereference
    this_iterator operator -- (int);
 
    // test useful for testing whether iteration has completed and for inclusion in other containers
    // Note: this class also inherits the safe_iterator methods: valid(), null(), end()
    bool operator == (const this_iterator& r) const;
    bool operator != (const this_iterator& r) const;
    bool operator < (const this_iterator& r) const;
 
    // access the node data - a const_iterator gives you a const element, an iterator a non-const element
    // it is illegal to dereference an invalid (i.e. null or end) iterator
    // exceptions: null_dereference,end_dereference
    reference operator*(void) const;
    // exceptions: null_dereference,end_dereference
    pointer operator->(void) const;
 
  public:
    // constructor used by digraph to create a non-null iterator
    explicit digraph_iterator(digraph_node<NT,AT>* node);
    // constructor used by digraph to create an end iterator
    explicit digraph_iterator(const digraph<NT,AT>* owner);
    // used to create an alias of an iterator
    explicit digraph_iterator(const safe_iterator<digraph<NT,AT>, digraph_node<NT,AT> >& iterator);
  };
 
  ////////////////////////////////////////////////////////////////////////////////
 
  template<typename NT, typename AT, typename ARef, typename APtr>
  class digraph_arc_iterator : public safe_iterator<digraph<NT,AT>, digraph_arc<NT,AT> >
  {
  public:
    friend class digraph<NT,AT>;
 
    // iterator traits, were inherited from std::iterator but inheriting from that was deprecated in C++17
    // the digraph iterators are bidirectional but not random-access
    typedef std::bidirectional_iterator_tag iterator_category;
    typedef AT value_type;
    typedef APtr pointer;
    typedef ARef reference;
    // this is not random access, so declare a void difference type, not sure this is supported by everything
    // typedef std::ptrdiff_t difference_type;
    typedef void difference_type;
 
    // local type definitions
    // an iterator points to an object whilst a const_iterator points to a const object
    typedef digraph_arc_iterator<NT,AT,AT&,AT*> iterator;
    typedef digraph_arc_iterator<NT,AT,const AT&,const AT*> const_iterator;
    typedef digraph_arc_iterator<NT,AT,ARef,APtr> this_iterator;
 
    // constructor to create a null iterator - you must assign a valid value to this iterator before using it
    digraph_arc_iterator(void);
    ~digraph_arc_iterator(void);
 
    // Type conversion methods allow const_iterator and iterator to be converted
    // convert an iterator/const_iterator to a const_iterator
    const_iterator constify(void) const;
    // convert an iterator/const_iterator to an iterator
    iterator deconstify(void) const;
 
    // increment/decrement operators used to step through the set of all nodes in a graph
    // it is only legal to increment a valid iterator
    // pre-increment
    // exceptions: null_dereference,end_dereference
    this_iterator& operator ++ (void);
    // post-increment
    // exceptions: null_dereference,end_dereference
    this_iterator operator ++ (int);
    // pre-decrement
    // exceptions: null_dereference,end_dereference
    this_iterator& operator -- (void);
    // post-decrement
    // exceptions: null_dereference,end_dereference
    this_iterator operator -- (int);
 
    // test useful for testing whether iteration has completed and for inclusion in other containers
    // Note: this class also inherits the safe_iterator methods: valid(), null(), end()
    bool operator == (const this_iterator&) const;
    bool operator != (const this_iterator&) const;
    bool operator < (const this_iterator&) const;
 
    // access the node data - a const_iterator gives you a const element, an iterator a non-const element
    // it is illegal to dereference an invalid (i.e. null or end) iterator
    // exceptions: null_dereference,end_dereference
    reference operator*(void) const;
    // exceptions: null_dereference,end_dereference
    pointer operator->(void) const;
 
  public:
    // constructor used by digraph to create a non-null iterator
    explicit digraph_arc_iterator(digraph_arc<NT,AT>* arc);
    // constructor used by digraph to create an end iterator
    explicit digraph_arc_iterator(const digraph<NT,AT>* owner);
    // used to create an alias of an iterator
    explicit digraph_arc_iterator(const safe_iterator<digraph<NT,AT>, digraph_arc<NT,AT> >& iterator);
  };
 
  ////////////////////////////////////////////////////////////////////////////////
  // The Graph class
  // NT is the Node type and AT is the Arc type
  ////////////////////////////////////////////////////////////////////////////////
 
  template<typename NT, typename AT>
  class digraph
  {
  public:
    // STL-like typedefs for the types and iterators
    typedef NT node_type;
    typedef AT arc_type;
    typedef digraph_iterator<NT,AT,NT&,NT*> iterator;
    typedef digraph_iterator<NT,AT,const NT&,const NT*> const_iterator;
    typedef digraph_arc_iterator<NT,AT,AT&,AT*> arc_iterator;
    typedef digraph_arc_iterator<NT,AT,const AT&,const AT*> const_arc_iterator;
 
    // iterator ownership - can check whether the graph owns an iterator
    bool owns(iterator) const;
    bool owns(const_iterator) const;
    bool owns(arc_iterator) const;
    bool owns(const_arc_iterator) const;
 
    // supplementary types used throughout
 
    // a path is represented as a vector of arcs so the forward traversal is
    // done by going from begin() to end() or 0 to size-1 - of course a backward
    // traversal can be done by traversing the vector backwards
    typedef std::vector<arc_iterator> arc_vector;
    typedef std::vector<const_arc_iterator> const_arc_vector;
    // exceptions: wrong_object,null_dereference,end_dereference
    const_arc_vector constify_arcs(const arc_vector&) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    arc_vector deconstify_arcs(const const_arc_vector&) const;
 
    // a path vector is a vector of paths used to represent all the paths from one node to another
    // there is no particular ordering to the paths in the vector
    typedef std::vector<arc_vector> path_vector;
    typedef std::vector<const_arc_vector> const_path_vector;
    // exceptions: wrong_object,null_dereference,end_dereference
    const_path_vector constify_paths(const path_vector&) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    path_vector deconstify_paths(const const_path_vector&) const;
 
    // a node vector is a simple vector of nodes used to represent the reachable sets
    // there is no particular ordering to the nodes in the vector
    typedef std::vector<iterator> node_vector;
    typedef std::vector<const_iterator> const_node_vector;
    // exceptions: wrong_object,null_dereference,end_dereference
    const_node_vector constify_nodes(const node_vector&) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    node_vector deconstify_nodes(const const_node_vector&) const;
 
    // callback used in the path algorithms to select which arcs to consider
    typedef bool (*arc_select_fn) (const digraph<NT,AT>&, const_arc_iterator);
 
    // a value representing an unknown offset
    // Note that it's static so use in the form digraph<NT,AT>::npos()
    static unsigned npos(void);
 
    //////////////////////////////////////////////////////////////////////////
    // Constructors, destructors and copies
 
    digraph(void);
    ~digraph(void);
 
    // copy constructor and assignment both copy the graph
    digraph(const digraph<NT,AT>&);
    digraph<NT,AT>& operator=(const digraph<NT,AT>&);
 
    //////////////////////////////////////////////////////////////////////////
    // Basic Node functions
    // Nodes are referred to by iterators created when the node is inserted.
    // Iterators remain valid unless the node is erased (they are list iterators, so no resize problems)
    // It is also possible to walk through all the nodes using a list-like start() to end() loop
    // Each node has a set of input arcs and output arcs. These are indexed by an unsigned i.e. they form a vector.
    // The total number of inputs is the fanin and the total number of outputs is the fanout.
    // The contents of the node (type NT) are accessed, of course, by dereferencing the node iterator.
 
    // tests for the number of nodes and the special test for zero nodes
    bool empty(void) const;
    unsigned size(void) const;
 
    // add a new node and return its iterator
    iterator insert(const NT& node_data);
 
    // remove a node and return the iterator to the next node
    // erasing a node erases its arcs
    // exceptions: wrong_object,null_dereference,end_dereference
    iterator erase(iterator);
    // remove all nodes
    void clear(void);
 
    // traverse all the nodes in no particular order using STL-style iteration
    const_iterator begin(void) const;
    iterator begin(void);
    const_iterator end(void) const;
    iterator end(void);
 
    // access the inputs of this node
    // the fanin is the number of inputs and the inputs are accessed using an index from 0..fanin-1
    // exceptions: wrong_object,null_dereference,end_dereference
    unsigned fanin(const_iterator) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    unsigned fanin(iterator);
    // exceptions: wrong_object,null_dereference,end_dereference,std::out_of_range
    const_arc_iterator input(const_iterator, unsigned) const;
    // exceptions: wrong_object,null_dereference,end_dereference,std::out_of_range
    arc_iterator input(iterator, unsigned);
 
    // access the outputs of this node
    // the fanout is the number of outputs and the outputs are accessed using an index from 0..fanout-1
    // exceptions: wrong_object,null_dereference,end_dereference
    unsigned fanout(const_iterator) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    unsigned fanout(iterator);
    // exceptions: wrong_object,null_dereference,end_dereference,std::out_of_range
    const_arc_iterator output(const_iterator, unsigned) const;
    // exceptions: wrong_object,null_dereference,end_dereference,std::out_of_range
    arc_iterator output(iterator, unsigned);
 
    // convenience routines for getting the set of all inputs or all outputs as vectors
    // exceptions: wrong_object,null_dereference,end_dereference
    const_arc_vector inputs(const_iterator) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    arc_vector inputs(iterator);
    // exceptions: wrong_object,null_dereference,end_dereference
    const_arc_vector outputs(const_iterator) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    arc_vector outputs(iterator);
 
    // find the output index of an arc which goes from this node
    // returns digraph<NT,AT>::npos if the arc is not an output of from
    // exceptions: wrong_object,null_dereference,end_dereference
    unsigned output_offset(const_iterator from, const_arc_iterator arc) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    unsigned output_offset(iterator from, arc_iterator arc);
    // ditto for an input arc
    // exceptions: wrong_object,null_dereference,end_dereference
    unsigned input_offset(const_iterator to, const_arc_iterator arc) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    unsigned input_offset(iterator to, arc_iterator arc);
 
    //////////////////////////////////////////////////////////////////////////
    // Basic Arc functions
    // to avoid name conflicts, arc functions have the arc_ prefix
    // Arcs, like nodes, are referred to by a list iterator which is returned by the arc_insert function
    // They may also be visited from arc_begin() to arc_end()
    // Each arc has a from field and a to field which contain the node iterators of the endpoints of the arc
    // Of course, the arc data can be accessed by simply dereferencing the iterator
 
    // tests for the number of arcs and the special test for zero arcs
    bool arc_empty (void) const;
    unsigned arc_size(void) const;
 
    // add a new arc and return its iterator
    // exceptions: wrong_object,null_dereference,end_dereference
    arc_iterator arc_insert(iterator from, iterator to, const AT& arc_data = AT());
 
    // remove an arc and return the iterator to the next arc
    // exceptions: wrong_object,null_dereference,end_dereference
    arc_iterator arc_erase(arc_iterator);
    // remove all arcs
    void arc_clear(void);
 
    // traverse all the arcs in no particular order using STL-style iteration
    const_arc_iterator arc_begin(void) const;
    arc_iterator arc_begin(void);
    const_arc_iterator arc_end(void) const;
    arc_iterator arc_end(void);
 
    // find the node that an arc points from or to
    // exceptions: wrong_object,null_dereference,end_dereference
    const_iterator arc_from(const_arc_iterator) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    iterator arc_from(arc_iterator);
    // exceptions: wrong_object,null_dereference,end_dereference
    const_iterator arc_to(const_arc_iterator) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    iterator arc_to(arc_iterator);
 
    // reconnect an arc to a different from and to node
    // exceptions: wrong_object,null_dereference,end_dereference
    void arc_move(arc_iterator arc, iterator from, iterator to);
    // reconnect just the from node
    // exceptions: wrong_object,null_dereference,end_dereference
    void arc_move_from(arc_iterator arc, iterator from);
    // reconnect just the to node
    // exceptions: wrong_object,null_dereference,end_dereference
    void arc_move_to(arc_iterator arc, iterator to);
    // reverse the arc direction so that to becomes from and vice-versa
    // exceptions: wrong_object,null_dereference,end_dereference
    void arc_flip(arc_iterator arc);
 
    ////////////////////////////////////////////////////////////////////////////////
    // whole graph manipulations
 
    // move one graph into another by moving all its nodes/arcs
    // this leaves the source graph empty
    // all iterators to nodes/arcs in the source graph will still work and will be owned by this
    void move(digraph<NT,AT>& source);
 
    ////////////////////////////////////////////////////////////////////////////////
    // Adjacency algorithms
 
    // test whether the nodes are adjacent i.e. whether there is an arc going from from to to
    // exceptions: wrong_object,null_dereference,end_dereference
    bool adjacent(const_iterator from, const_iterator to) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    bool adjacent(iterator from, iterator to);
 
    // as above, but returns the arc that makes the nodes adjacent
    // returns the first arc if there's more than one, returns arc_end() if there are none
    // exceptions: wrong_object,null_dereference,end_dereference
    const_arc_iterator adjacent_arc(const_iterator from, const_iterator to) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    arc_iterator adjacent_arc(iterator from, iterator to);
 
    // as above, but returns the set of all arcs that make two nodes adjacent (there may be more than one)
    // returns an empty vector if there are none
    // exceptions: wrong_object,null_dereference,end_dereference
    const_arc_vector adjacent_arcs(const_iterator from, const_iterator to) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    arc_vector adjacent_arcs(iterator from, iterator to);
 
    // return the adjacency sets for the node inputs or outputs, i.e. the set of nodes adjacent to this node
    // each adjacent node will only be entered once even if there are multiple arcs between the nodes
    // exceptions: wrong_object,null_dereference,end_dereference
    const_node_vector input_adjacencies(const_iterator to) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    node_vector input_adjacencies(iterator to);
    // exceptions: wrong_object,null_dereference,end_dereference
    const_node_vector output_adjacencies(const_iterator from) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    node_vector output_adjacencies(iterator from);
 
    ////////////////////////////////////////////////////////////////////////////////
    // Topographical Sort Algorithm
    // This generates a node ordering such that each node is visited after its fanin nodes.
 
    // This only generates a valid ordering for a Directed Acyclic Graph (DAG).
 
    // The return value is a pair :
    //  - the node vector which is a set of iterators to the nodes in sorted order
    //  - the arc vector is the set of backward arcs that were broken to achieve the sort
    // If the arc vector is empty then the graph formed a DAG.
 
    // The arc selection callback can be used to ignore arcs that are not part
    // of the ordering, i.e. arcs that are meant to be backwards arcs
 
    std::pair<const_node_vector,const_arc_vector> sort(arc_select_fn = 0) const;
    std::pair<node_vector,arc_vector> sort(arc_select_fn = 0);
 
    // Simplified variant of above for graphs that are known to be DAGs.
    // If the sort fails due to backward arcs, the
    // return vector is empty. Note that this will also be empty if the graph
    // has no nodes in it, so use the empty() method to differentiate.
 
    const_node_vector dag_sort(arc_select_fn = 0) const;
    node_vector dag_sort(arc_select_fn = 0);
 
    ////////////////////////////////////////////////////////////////////////////////
    // Basic Path Algorithms
    // A path is a series of arcs - you can use arc_from and arc_to to convert
    // that into a series of nodes. All the path algorithms take an arc_select
    // which allows arcs to be selected or rejected for consideration in a path.
 
    // A selection callback function is applied to each arc in the traversal and
    // returns true if the arc is to be selected and false if the arc is to be
    // rejected. If no function is provided the arc is selected. If you want to
    // use arc selection you should create a function with the type profile given
    // by the arc_select_fn type. The select function is passed both the graph and
    // the arc iterator so that it is possible to select an arc on the basis of
    // the nodes it is connected to.
 
    // Note: I used a callback because the STL-like predicate idea wasn't working for me...
 
    // test for the existence of a path from from to to
    // exceptions: wrong_object,null_dereference,end_dereference
    bool path_exists(const_iterator from, const_iterator to, arc_select_fn = 0) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    bool path_exists(iterator from, iterator to, arc_select_fn = 0);
 
    // get the set of all paths from from to to
    // exceptions: wrong_object,null_dereference,end_dereference
    const_path_vector all_paths(const_iterator from, const_iterator to, arc_select_fn = 0) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    path_vector all_paths(iterator from, iterator to, arc_select_fn = 0);
 
    // get the set of all nodes that can be reached by any path from from
    // exceptions: wrong_object,null_dereference,end_dereference
    const_node_vector reachable_nodes(const_iterator from, arc_select_fn = 0) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    node_vector reachable_nodes(iterator from, arc_select_fn = 0);
 
    // get the set of all nodes that can reach to to by any path
    // exceptions: wrong_object,null_dereference,end_dereference
    const_node_vector reaching_nodes(const_iterator to, arc_select_fn = 0) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    node_vector reaching_nodes(iterator to, arc_select_fn = 0);
 
    ////////////////////////////////////////////////////////////////////////////////
    // Unweighted Shortest path algorithms
 
    // find the shortest path from from to to
    // This is an unweighted shortest path algorithm, i.e. the weight of each
    // arc is assumed to be 1, so just counts the number of arcs
    // if there is more than one shortest path it returns the first one
    // If there are no paths, returns an empty path
    // exceptions: wrong_object,null_dereference,end_dereference
    const_arc_vector shortest_path(const_iterator from, const_iterator to, arc_select_fn = 0) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    arc_vector shortest_path(iterator from, iterator to, arc_select_fn = 0);
 
    // find the set of shortest paths from from to any other node in the graph
    // that is reachable (i.e. for which path_exists() is true)
    // This is an unweighted shortest path, so just counts the number of arcs
    // if there is more than one shortest path to a node it returns the first one
    // If there are no paths, returns an empty list
    // exceptions: wrong_object,null_dereference,end_dereference
    const_path_vector shortest_paths(const_iterator from, arc_select_fn = 0) const;
    // exceptions: wrong_object,null_dereference,end_dereference
    path_vector shortest_paths(iterator from, arc_select_fn = 0);
 
  private:
    friend class digraph_iterator<NT,AT,NT&,NT*>;
    friend class digraph_iterator<NT,AT,const NT&,const NT*>;
    friend class digraph_arc_iterator<NT,AT,AT&,AT*>;
    friend class digraph_arc_iterator<NT,AT,const AT&, const AT*>;
 
    typedef std::set<const_iterator> const_iterator_set;
    typedef typename const_iterator_set::iterator const_iterator_set_iterator;
 
    // exceptions: wrong_object,null_dereference,end_dereference
    bool path_exists_r(const_iterator from, const_iterator to, const_iterator_set& visited, arc_select_fn) const;
 
    // exceptions: wrong_object,null_dereference,end_dereference
    void all_paths_r(const_iterator from, const_iterator to, const_arc_vector& so_far, const_path_vector& result, arc_select_fn) const;
 
    // exceptions: wrong_object,null_dereference,end_dereference
    void reachable_nodes_r(const_iterator from, const_iterator_set& visited, arc_select_fn) const;
 
    // exceptions: wrong_object,null_dereference,end_dereference
    void reaching_nodes_r(const_iterator to, const_iterator_set& visited, arc_select_fn) const;
 
    digraph_node<NT,AT>* m_nodes_begin;
    digraph_node<NT,AT>* m_nodes_end;
    digraph_arc<NT,AT>* m_arcs_begin;
    digraph_arc<NT,AT>* m_arcs_end;
  };
 
  ////////////////////////////////////////////////////////////////////////////////
 
} // end namespace stlplus
 
#include "digraph.tpp"
#endif