You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: Code/Graph+Algorithms/Graph+AncestorCount.swift
+7-1Lines changed: 7 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,13 @@ import SwiftyToolz
3
3
publicextensionGraph
4
4
{
5
5
/**
6
-
Find the total number of all ancestors (predecessors / sources) for every node of an **acyclic** graph.
6
+
Find the total (recursive) number of ancestors for each ``GraphNode`` of an **acyclic** `Graph`
7
+
8
+
The ancestor count of a node is basically the number of other nodes from which the node can be reached. This only works on acyclic graphs right now and might return incorrect results for nodes in cycles.
9
+
10
+
Ancestor counts can serve as a proxy for [topological sorting](https://en.wikipedia.org/wiki/Topological_sorting).
11
+
12
+
- Returns: Every ``GraphNode`` of the `Graph` together with its ancestor count
Copy file name to clipboardExpand all lines: Code/Graph+Algorithms/Graph+CondensationGraph.swift
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -4,9 +4,9 @@ import OrderedCollections
4
4
publicextensionGraph
5
5
{
6
6
/**
7
-
Creates the acyclic condensation graph, contracting strongly connected components into single nodes.
7
+
Creates the acyclic [condensation graph](https://en.wikipedia.org/wiki/Strongly_connected_component) of the `Graph`
8
8
9
-
See <https://en.wikipedia.org/wiki/Strongly_connected_component>
9
+
The condensation graph is the graph in which the [strongly connected components](https://en.wikipedia.org/wiki/Strongly_connected_component) of the original graph have been collapsed into single nodes, so the resulting condensation graph is acyclic.
Copy file name to clipboardExpand all lines: Code/Graph/Graph.swift
+101-2Lines changed: 101 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -2,22 +2,35 @@ import OrderedCollections
2
2
import SwiftyToolz
3
3
4
4
/**
5
-
Holds values in nodes which can be connected through edges. Nodes maintain an order, and so the graph can be sorted.
5
+
Holds `Value`s in unique ``GraphNode``s which can be connected through ``GraphEdge``s
6
+
7
+
You create `GraphNode`s by inserting `NodeValue`s into the `Graph`, whereby the `Graph` generates the IDs for new nodes according to the closure passed to- or implied by its initializer, see ``Graph/init(nodes:makeNodeIDForValue:)`` and the convenience initializers.
8
+
9
+
Nodes maintain an order, and so the graph can be sorted, see ``Graph/sort(by:)``.
6
10
*/
7
11
publicclassGraph<NodeID:Hashable, NodeValue>
8
12
{
9
13
// MARK: - Initialize
10
14
15
+
/**
16
+
Uses the `NodeValue.ID` of a value as the ``GraphNode/id`` for its corresponding node
Creates a `Graph` that generates ``GraphNode/id``s for new ``GraphNode``s with the given closure
33
+
*/
21
34
publicinit(nodes:OrderedNodes=[],
22
35
makeNodeIDForValue:@escaping(NodeValue)->NodeID)
23
36
{
@@ -27,22 +40,35 @@ public class Graph<NodeID: Hashable, NodeValue>
27
40
28
41
// MARK: - Edges
29
42
43
+
/**
44
+
Removes the corresponding ``GraphEdge``, see ``Graph/remove(_:)``
45
+
*/
30
46
publicfunc removeEdge(from sourceID:NodeID, to targetID:NodeID)
31
47
{
32
48
removeEdge(with:.init(sourceID, targetID))
33
49
}
34
50
51
+
/**
52
+
Removes the corresponding ``GraphEdge``, see ``Graph/remove(_:)``
53
+
*/
35
54
publicfunc removeEdge(from source:Node, to target:Node)
36
55
{
37
56
removeEdge(with:.init(source, target))
38
57
}
39
58
59
+
/**
60
+
Removes the corresponding ``GraphEdge``, see ``Graph/remove(_:)``
61
+
*/
40
62
publicfunc removeEdge(with id:Edge.ID)
41
63
{
42
64
guardlet edge =edgesByID[id]else{return}
43
65
remove(edge)
44
66
}
45
67
68
+
/**
69
+
Removes the ``GraphEdge``, also removing it from the caches of its ``GraphEdge/source`` and ``GraphEdge/target``
70
+
71
+
*/
46
72
publicfunc remove(_ edge:Edge)
47
73
{
48
74
// remove from node caches
@@ -54,6 +80,11 @@ public class Graph<NodeID: Hashable, NodeValue>
54
80
edgesByID[edge.id]=nil
55
81
}
56
82
83
+
/**
84
+
Adds a ``GraphEdge`` from one ``GraphNode`` to another, see ``Graph/addEdge(from:to:count:)-mz60``
85
+
86
+
- Returns: `nil` if no ``GraphNode`` exists for `sourceID` or `targetID`
87
+
*/
57
88
@discardableResult
58
89
publicfunc addEdge(from sourceID:NodeID,
59
90
to targetID:NodeID,
@@ -68,6 +99,13 @@ public class Graph<NodeID: Hashable, NodeValue>
68
99
returnaddEdge(from: source, to: target, count: count)
69
100
}
70
101
102
+
/**
103
+
Adds a ``GraphEdge`` from one ``GraphNode`` to another
104
+
105
+
This also adds `source` and `target` to each other's neighbour caches, see ``GraphNode``
106
+
107
+
- Returns: The new ``GraphEdge`` if none existed from `source` to `target`, otherwise the existing ``GraphEdge`` with its ``GraphEdge/count`` increased by the given `count`
108
+
*/
71
109
@discardableResult
72
110
publicfunc addEdge(from source:Node,
73
111
to target:Node,
@@ -96,30 +134,47 @@ public class Graph<NodeID: Hashable, NodeValue>
96
134
}
97
135
}
98
136
137
+
/**
138
+
The ``GraphEdge`` from `source` to `target` if it exists, otherwise `nil`
139
+
*/
99
140
publicfunc edge(from source:Node, to target:Node)->Edge?
The ``GraphEdge`` between the corresponding nodes if it exists, otherwise `nil`
148
+
*/
105
149
publicfunc edge(from sourceID:NodeID, to targetID:NodeID)->Edge?
106
150
{
107
151
edgesByID[.init(sourceID, targetID)]
108
152
}
109
153
154
+
/**
155
+
All ``GraphEdge``s of the `Graph`
156
+
*/
110
157
publicvaredges:Dictionary<Edge.ID,Edge>.Values
111
158
{
112
159
edgesByID.values
113
160
}
114
161
162
+
/**
163
+
All ``GraphEdge``s of the `Graph` hashable by their ``GraphEdge/id-swift.property``
164
+
*/
115
165
publicprivate(set)varedgesByID=[Edge.ID: Edge]()
116
166
167
+
/**
168
+
Shorthand for the full generic type name `GraphEdge<NodeID, NodeValue>`
169
+
*/
117
170
publictypealiasEdge=GraphEdge<NodeID,NodeValue>
118
171
119
172
// MARK: - Node Values
120
173
121
174
/**
122
-
Inserts a new node with the given value into the graph and returns the new node. If a node with the same generated node id already exists, the function returns the existing node.
175
+
Insert a `NodeValue` and get the (new) ``GraphNode`` that stores it
176
+
177
+
- Returns: The existing ``GraphNode`` if one with the generated ``GraphNode/id`` already exists (see ``Graph/init(nodes:makeNodeIDForValue:)``), otherwise a newly created ``GraphNode``.
123
178
*/
124
179
@discardableResult
125
180
publicfunc insert(_ value:NodeValue)->Node
@@ -133,61 +188,105 @@ public class Graph<NodeID: Hashable, NodeValue>
133
188
134
189
internalletmakeNodeIDForValue:(NodeValue)->NodeID
135
190
191
+
/**
192
+
``GraphNode/value`` of the ``GraphNode`` with the given ``GraphNode/id`` if one exists, otherwise `nil`
193
+
*/
136
194
publicfunc value(for nodeID:NodeID)->NodeValue?
137
195
{
138
196
node(for: nodeID)?.value
139
197
}
140
198
199
+
/**
200
+
All `NodeValue`s of the `Graph`
201
+
*/
141
202
publicvarvalues:[NodeValue]
142
203
{
143
204
nodes.map{ $0.value }
144
205
}
145
206
146
207
// MARK: - Nodes
147
208
209
+
/**
210
+
All source nodes of the `Graph`, see ``GraphNode/isSource``
211
+
*/
148
212
publicvarsources:[Node]
149
213
{
150
214
nodesByID.values.filter{ $0.isSource }
151
215
}
152
216
217
+
/**
218
+
All sink nodes of the `Graph`, see ``GraphNode/isSink``
219
+
*/
153
220
publicvarsinks:[Node]
154
221
{
155
222
nodesByID.values.filter{ $0.isSink }
156
223
}
157
224
225
+
/**
226
+
Whether the `Graph` contains a ``GraphNode`` with the given ``GraphNode/id``
227
+
*/
158
228
publicfunc contains(_ nodeID:NodeID)->Bool
159
229
{
160
230
node(for: nodeID)!=nil
161
231
}
162
232
233
+
/**
234
+
Whether the `Graph` contains the given ``GraphNode``
235
+
*/
163
236
publicfunc contains(_ node:Node)->Bool
164
237
{
165
238
self.node(for: node.id)=== node
166
239
}
167
240
241
+
/**
242
+
``GraphNode`` with the given ``GraphNode/id`` if one exists, otherwise `nil`
243
+
*/
168
244
publicfunc node(for nodeID:NodeID)->Node?
169
245
{
170
246
nodesByID[nodeID]
171
247
}
172
248
249
+
/**
250
+
Sort the ``GraphNode``s of the `Graph` with the given closure
0 commit comments