Skip to content

Commit 2bfdbfc

Browse files
committed
Fixed bug in directed_graph_base. Added methods, converted getters to functions.
1 parent e2e32c3 commit 2bfdbfc

17 files changed

Lines changed: 1121 additions & 323 deletions

CHANGELOG.md

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,35 @@
11

2+
## 0.5.0
3+
- *Breaking changes*:
4+
The following *getters have been converted to functions*, to
5+
reflect the fact that a potentially long computation is be needed to
6+
calculate the result:
7+
* `stronglyConnectedComponents({bool sorted, Comparator <T> comparator})`
8+
and the function return type has been
9+
changed to `List<Set>` to show the fact that each scc is a set
10+
of vertices and to make searching a component for a specify vertex more
11+
efficient,
12+
* `topologicalOrdering({bool sorted})`,
13+
* `cycle()`,
14+
* `localSource()`.
15+
- The getters `cycleVertex` and `isAcyclic` were kept, but are now cached and
16+
only updated if vertices or edges are added/removed.
17+
18+
- The getter `sortedTopologicalOrdering` was removed. To get the equivalent
19+
result call `topologicalOrdering(sorted:true)`.
20+
- *New additions*:
21+
* `addEdge({vertex, connectedVertex})` was added to `DirectedGraph` and
22+
`BiDirectedGraph` to make
23+
it consistent with `WeightedDirectedGraph`,
24+
* `reverseTopologicalOrdering({bool sorted})`, for the meaning of
25+
quasi-topological ordering see Section Terminology of README.md.
26+
* `quasiTopologicalOrdering({bool sorted})`,
27+
* `reverseQuasiTopologicalOrdering({bool sorted})`.
28+
- Fixed a bug related to the addition of a default comparator if the
29+
generic type `T` of `DirectedGraph<T>` is `Comparable<T>`.
30+
- Updated dependencies.
31+
32+
233
## 0.4.5
334
- Updated dependencies.
435
- Updated benchmark report.
@@ -77,7 +108,7 @@
77108

78109
* Added null-safety features.
79110
* Tightened the definition of path.
80-
A path \[v<sub>i</sub>, ..., v<sub>n</sub>\] is an ordered list of at least two connected vertices where each **inner** vertex is **distinct**.
111+
A path \[v<sub>i</sub>, ..., v<sub>n</sub>\] is an ordered list of at least two connected vertices where each *inner* vertex is *distinct*.
81112
* Functions returning a topological ordering now return an ordered set of vertices, reflecting the fact that in a topological ordering
82113
each vertex must be distinct.
83114
* Added the classes [`WeightedDirectedGraph`][WeightedDirectedGraph] and `BiDirectedGraph`.

README.md

Lines changed: 170 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,11 @@
88
An integral part of storing, manipulating, and retrieving numerical data are *data structures* or as they are called in Dart: [collections].
99
Arguably the most common data structure is the *list*. It enables efficient storage and retrieval of sequential data that can be associated with an index.
1010

11-
A more general (non-linear) data structure where an element may be connected to one, several, or none of the other elements is called a **graph**.
11+
A more general (non-linear) data structure where an element may be connected to one, several, or none of the other elements is called a *graph*.
1212

1313
Graphs are useful when keeping track of elements that are linked to or are dependent on other elements.
14-
Examples include: network connections, links in a document pointing to other paragraphs or documents, foreign keys in a relational database, file dependencies in a build system, etc.
14+
Examples include: network connections, links in a document pointing to other paragraphs or documents,
15+
foreign keys in a relational database, file dependencies in a build system, etc.
1516

1617
The package [`directed_graph`][directed_graph] contains an implementation of a Dart graph that follows the
1718
recommendations found in [graphs-examples] and is compatible with the algorithms provided by [`graphs`][graphs].
@@ -26,36 +27,42 @@ for finding:
2627
* all paths connecting two vertices,
2728
* the shortest paths from a vertex to all connected vertices,
2829
* cycles,
29-
* a topological ordering of the graph vertices.
30+
* a topological ordering of the graph vertices,
31+
* a reverse topological ordering of the graph vertices.
3032

3133
The class [`GraphCrawler`][GraphCrawler] can be used to retrieve *paths* or *walks* connecting two vertices.
3234

3335
## Terminology
3436

35-
Elements of a graph are called **vertices** (or nodes) and neighbouring vertices are connected by **edges**.
36-
The figure below shows a **directed graph** with unidirectional edges depicted as arrows.
37-
Graph edges are emanating from a vertex and ending at a vertex. In a **weighted directed graph** each
37+
Elements of a graph are called *vertices* (or nodes) and neighbouring vertices are connected by *edges*.
38+
The figure below shows a *directed graph* with unidirectional edges depicted as arrows.
39+
Graph edges are emanating from a vertex and ending at a vertex. In a *weighted directed graph* each
3840
edge is assigned a weight.
3941

4042
![Directed Graph Image](https://github.com/simphotonics/directed_graph/raw/main/images/directed_graph.svg?sanitize=true)
4143

42-
- **In-degree** of a vertex: Number of edges ending at this vertex. For example, vertex H has in-degree 3.
43-
- **Out-degree** of a vertex: Number of edges starting at this vertex. For example, vertex F has out-degree 1.
44-
- **Source**: A vertex with in-degree zero is called (local) source. Vertices A and D in the graph above are local sources.
45-
- **Directed Edge**: An ordered pair of connected vertices (v<sub>i</sub>, v<sub>j</sub>). For example, the edge (A, C) starts at vertex A and ends at vertex C.
46-
- **Path**: A path \[v<sub>i</sub>, ..., v<sub>n</sub>\] is an ordered list of at least two connected vertices where each **inner** vertex is **distinct**.
44+
- *In-degree* of a vertex: Number of edges ending at this vertex. For example, vertex H has in-degree 3.
45+
- *Out-degree* of a vertex: Number of edges starting at this vertex. For example, vertex F has out-degree 1.
46+
- *Source*: A vertex with in-degree zero is called (local) source. Vertices A and D in the graph above are local sources.
47+
- *Directed Edge*: An ordered pair of connected vertices (v<sub>i</sub>, v<sub>j</sub>). For example, the edge (A, C) starts at vertex A and ends at vertex C.
48+
- *Path*: A path \[v<sub>i</sub>, ..., v<sub>n</sub>\] is an ordered list of at least two connected vertices where each *inner* vertex is *distinct*.
4749
The path \[A, E, G\] starts at vertex A and ends at vertex G.
48-
- **Cycle**: A cycle is an ordered *list* of connected vertices where each inner vertex is distinct and the
50+
- *Cycle*: A cycle is an ordered *list* of connected vertices where each inner vertex is distinct and the
4951
first and last vertices are identical. The sequence \[F, I, K, F\] completes a cycle.
50-
- **Walk**: A walk is an ordered *list* of at least two connected vertices.
52+
- *Walk*: A walk is an ordered *list* of at least two connected vertices.
5153
\[D, F, I, K, F\] is a walk but not a path since the vertex F is listed twice.
52-
- **DAG**: An acronym for **Directed Acyclic Graph**, a directed graph without cycles.
53-
- **Topological ordering**: An ordered *set* of all vertices in a graph such that v<sub>i</sub>
54+
- *DAG*: An acronym for *Directed Acyclic Graph*, a directed graph without cycles.
55+
- *Topological ordering*: An ordered *set* of all vertices in a graph such that v<sub>i</sub>
5456
occurs before v<sub>j</sub> if there is a directed edge (v<sub>i</sub>, v<sub>j</sub>).
5557
A topological ordering of the graph above is: \{A, D, B, C, E, K, F, G, H, I, L\}.
5658
Hereby, dashed edges were disregarded since a cyclic graph does not have a topological ordering.
59+
- *Quasi-Topological ordering*: An ordered *sub-set* of graph vertices
60+
such that v<sub>i</sub>
61+
occurs before v<sub>j</sub> if there is a directed edge (v<sub>i</sub>, v<sub>j</sub>).
62+
For a quasi-topological ordering to exist, any two vertices belonging to the *sub-set* must not have mutually connecting edges.
63+
5764

58-
**Note**: In the context of this package the definition of *edge* might be more lax compared to a
65+
*Note*: In the context of this package the definition of *edge* might be more lax compared to a
5966
rigorous mathematical definition.
6067
For example, self-loops, that is edges connecting a vertex to itself are explicitly allowed.
6168

@@ -67,38 +74,40 @@ example below shows how to construct an object of type [`DirectedGraph`][Directe
6774
The graph classes provided by this library are generic with type argument
6875
`T extends Object`, that is `T` must be non-nullable.
6976
Graph vertices can be sorted if `T is Comparable` or
70-
if a custom comparator function is provided. In the example below, a custom
71-
comparator is used to sort vertices in inverse lexicographical order.
77+
if a custom comparator function is provided.
78+
79+
Note: If `T is Comparable` and no comparator is provided, then
80+
the following default comparator is added:
81+
```Dart
82+
(T left, T right) => (left as Comparable<T>).compareTo(right);
83+
```
84+
Compared to an explicit comparator this function contains a cast and
85+
the benchmarks show that is approximatly 3 &times; slower.
86+
For large graphs it is advisable to follow the example below and
87+
explicitly provide a comparator.
88+
89+
In the example below, a custom
90+
comparator is used to sort vertices in lexicographical order.
7291

7392
```Dart
7493
import 'package:directed_graph/directed_graph.dart';
75-
// To run this program navigate to
76-
// the folder 'directed_graph/example'
77-
// in your terminal and type:
78-
//
79-
// # dart bin/directed_graph_example.dart
80-
//
81-
// followed by enter.
8294
void main() {
83-
8495
int comparator(String s1, String s2) => s1.compareTo(s2);
8596
int inverseComparator(String s1, String s2) => -comparator(s1, s2);
8697
8798
// Constructing a graph from vertices.
88-
final graph = DirectedGraph<String>(
89-
{
90-
'a': {'b', 'h', 'c', 'e'},
91-
'b': {'h'},
92-
'c': {'h', 'g'},
93-
'd': {'e', 'f'},
94-
'e': {'g'},
95-
'f': {'i'},
96-
'i': {'l'},
97-
'k': {'g', 'f'}
98-
},
99-
// Custom comparators can be specified here:
100-
// comparator: comparator,
101-
);
99+
100+
final graph = DirectedGraph<String>({
101+
'a': {'b', 'h', 'c', 'e'},
102+
'b': {'h'},
103+
'c': {'h', 'g'},
104+
'd': {'e', 'f'},
105+
'e': {'g'},
106+
'f': {'i'},
107+
//g': {'a'},
108+
'i': {'l'},
109+
'k': {'g', 'f'},
110+
}, comparator: comparator);
102111
103112
print('Example Directed Graph...');
104113
print('graph.toString():');
@@ -108,10 +117,16 @@ void main() {
108117
print(graph.isAcyclic);
109118
110119
print('\nStrongly connected components:');
111-
print(graph.stronglyConnectedComponents);
120+
print(graph.stronglyConnectedComponents());
121+
122+
print('\nLocal sources:');
123+
print(graph.localSources());
124+
125+
print('\nshortestPath(d, l):');
126+
print(graph.shortestPath('d', 'l'));
112127
113-
print('\nShortestPath(d, l):');
114-
print(graph.shortestPath('d', 'l');
128+
print('\nshortestPaths(a)');
129+
print(graph.shortestPaths('a'));
115130
116131
print('\nInDegree(C):');
117132
print(graph.inDegree('c'));
@@ -131,27 +146,69 @@ void main() {
131146
print(graph.inDegreeMap);
132147
133148
print('\nSorted Topological Ordering:');
134-
print(graph.sortedTopologicalOrdering);
149+
print(graph.topologicalOrdering(sorted: true));
135150
136151
print('\nTopological Ordering:');
137-
print(graph.topologicalOrdering);
152+
print(graph.topologicalOrdering());
153+
154+
print('\nReverse Topological Ordering:');
155+
print(graph.reverseTopologicalOrdering());
156+
157+
print('\nReverse Topological Ordering, sorted: true');
158+
print(graph.reverseTopologicalOrdering(sorted: true));
138159
139160
print('\nLocal Sources:');
140-
print(graph.localSources);
161+
print(graph.localSources());
162+
163+
print('\nAdding edges: i -> k and i -> d');
141164
142165
// Add edge to render the graph cyclic
143-
graph.addEdges('i', {'k'});
144-
graph.addEdges('l', {'l'});
145-
graph.addEdges('i', {'d'});
166+
graph.addEdge('i', 'k');
167+
//graph.addEdge('l', 'l');
168+
graph.addEdge('i', 'd');
169+
170+
print('\nCyclic graph:');
171+
print(graph);
146172
147173
print('\nCycle:');
148-
print(graph.cycle);
174+
print(graph.cycle());
175+
176+
print('\nCycle vertex:');
177+
print(graph.cycleVertex);
178+
179+
print('\ngraph.isAcyclic: ');
180+
print(graph.isAcyclic);
149181
150182
print('\nShortest Paths:');
151183
print(graph.shortestPaths('a'));
152184
153185
print('\nEdge exists: a->b');
154186
print(graph.edgeExists('a', 'b'));
187+
188+
print('\nStrongly connected components:');
189+
print(graph.stronglyConnectedComponents());
190+
191+
print('\nStrongly connected components, sorted:');
192+
print(
193+
graph.stronglyConnectedComponents(sorted: true, comparator: comparator),
194+
);
195+
196+
print('\nStrongly connected components, sorted, inverse:');
197+
print(
198+
graph.stronglyConnectedComponents(
199+
sorted: true,
200+
comparator: inverseComparator,
201+
),
202+
);
203+
204+
print('\nQuasi-Topological Ordering:');
205+
print(graph.quasiTopologicalOrdering({'d', 'e', 'a'}));
206+
207+
print('\nQuasi-Topological Ordering, sorted:');
208+
print(graph.quasiTopologicalOrdering({'d', 'e', 'a'}, sorted: true));
209+
210+
print('\nReverse-Quasi-Topological Ordering, sorted:');
211+
print(graph.reverseQuasiTopologicalOrdering({'d', 'e', 'a'}, sorted: true));
155212
}
156213
157214
```
@@ -165,37 +222,43 @@ graph.toString():
165222
{
166223
'a': {'b', 'h', 'c', 'e'},
167224
'b': {'h'},
225+
'h': {},
168226
'c': {'h', 'g'},
169-
'd': {'e', 'f'},
170227
'e': {'g'},
171-
'f': {'i'},
172228
'g': {},
173-
'h': {},
229+
'd': {'e', 'f'},
230+
'f': {'i'},
174231
'i': {'l'},
175-
'k': {'g', 'f'},
176232
'l': {},
233+
'k': {'g', 'f'},
177234
}
178235

179236
Is Acylic:
180237
true
181238

182239
Strongly connected components:
183-
[[h], [b], [g], [c], [e], [a], [l], [i], [f], [d], [k]]
240+
[{h}, {b}, {g}, {c}, {e}, {a}, {l}, {i}, {f}, {d}, {k}]
184241

185-
ShortestPath(d, l):
242+
Local sources:
243+
[{a, d, k}, {b, c, e, f}, {g, h, i}, {l}]
244+
245+
shortestPath(d, l):
186246
[d, f, i, l]
187247

248+
shortestPaths(a)
249+
{b: [b], h: [h], c: [c], e: [e], g: [c, g]}
250+
188251
InDegree(C):
189252
1
190253

191254
OutDegree(C)
192255
2
193256

194257
Vertices sorted in lexicographical order:
195-
[a, b, c, d, e, f, g, h, i, k, l]
258+
{a, b, c, d, e, f, g, h, i, k, l}
196259

197260
Vertices sorted in inverse lexicographical order:
198-
[l, k, i, h, g, f, e, d, c, b, a]
261+
{l, k, i, h, g, f, e, d, c, b, a}
199262

200263
InDegreeMap:
201264
{a: 0, b: 1, h: 3, c: 1, e: 2, g: 3, d: 0, f: 2, i: 1, l: 1, k: 0}
@@ -206,18 +269,64 @@ Sorted Topological Ordering:
206269
Topological Ordering:
207270
{a, b, c, d, e, h, k, f, i, g, l}
208271

272+
Reverse Topological Ordering:
273+
{l, g, i, f, k, h, e, d, c, b, a}
274+
275+
Reverse Topological Ordering, sorted: true
276+
{h, b, g, c, e, a, l, i, f, d, k}
277+
209278
Local Sources:
210-
[[a, d, k], [b, c, e, f], [g, h, i], [l]]
279+
[{a, d, k}, {b, c, e, f}, {g, h, i}, {l}]
280+
281+
Adding edges: i -> k and i -> d
282+
283+
Cyclic graph:
284+
{
285+
'a': {'b', 'h', 'c', 'e'},
286+
'b': {'h'},
287+
'h': {},
288+
'c': {'h', 'g'},
289+
'e': {'g'},
290+
'g': {},
291+
'd': {'e', 'f'},
292+
'f': {'i'},
293+
'i': {'l', 'k', 'd'},
294+
'l': {},
295+
'k': {'g', 'f'},
296+
}
211297

212298
Cycle:
213-
[l, l]
299+
[f, i, k, f]
300+
301+
Cycle vertex:
302+
f
303+
304+
graph.isAcyclic:
305+
false
214306

215307
Shortest Paths:
216-
{e: (e), c: (c), h: (h), a: (), g: (c, g), b: (b)}
308+
{b: [b], h: [h], c: [c], e: [e], g: [c, g]}
217309

218310
Edge exists: a->b
219311
true
220312

313+
Strongly connected components:
314+
[{h}, {b}, {g}, {c}, {e}, {a}, {l}, {k, i, f, d}]
315+
316+
Strongly connected components, sorted:
317+
[{h}, {b}, {g}, {c}, {e}, {a}, {l}, {d, f, i, k}]
318+
319+
Strongly connected components, sorted, inverse:
320+
[{l}, {g}, {e}, {k, i, f, d}, {h}, {c}, {b}, {a}]
321+
322+
Quasi-Topological Ordering:
323+
{d, a, e}
324+
325+
Quasi-Topological Ordering, sorted:
326+
{a, d, e}
327+
328+
Reverse-Quasi-Topological Ordering, sorted:
329+
{e, a, d}
221330
```
222331
</details>
223332

0 commit comments

Comments
 (0)