Skip to content

Commit 8826cd5

Browse files
committed
Add documentation comments and adjust API in some details
1 parent a77a4e8 commit 8826cd5

10 files changed

+265
-16
lines changed

Code/Graph+Algorithms/Graph+AncestorCount.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,13 @@ import SwiftyToolz
33
public extension Graph
44
{
55
/**
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
713
*/
814
func findNumberOfNodeAncestors() -> [(Node, Int)]
915
{

Code/Graph+Algorithms/Graph+Components.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ import SwiftyToolz
22

33
public extension Graph
44
{
5+
/**
6+
Find the [components](https://en.wikipedia.org/wiki/Component_(graph_theory)) of the `Graph`
7+
8+
- Returns: Multiple sets of nodes which represent the components of the graph
9+
*/
510
func findComponents() -> Set<Nodes>
611
{
712
unmarkNodes()

Code/Graph+Algorithms/Graph+CondensationGraph.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import OrderedCollections
44
public extension Graph
55
{
66
/**
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`
88

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.
1010
*/
1111
func makeCondensationGraph() -> CondensationGraph
1212
{

Code/Graph+Algorithms/Graph+MinimumEquivalentGraph.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,9 @@ import SwiftyToolz
33
public extension Graph
44
{
55
/**
6-
Finds the minumum equivalent graph of an **acyclic** graph.
6+
Find the [minumum equivalent graph](https://en.wikipedia.org/wiki/Transitive_reduction) of an **acyclic** `Graph`
77

8-
🛑 If the graph is cyclic, this algorithm might hang or crash!
9-
10-
See <https://en.wikipedia.org/wiki/Transitive_reduction>
8+
🛑 This only works on acyclic graphs and might even hang or crash on cyclic ones!
119
*/
1210
func makeMinimumEquivalentGraph() -> Graph<NodeID, NodeValue>
1311
{

Code/Graph+Algorithms/Graph+Node.Marking.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ import SwiftyToolz
22

33
public extension Graph
44
{
5+
/**
6+
Sets ``GraphNode/marking-swift.property`` of all the `Graph`'s ``GraphNode``s back to `nil`
7+
*/
58
func unmarkNodes()
69
{
710
setNodeMarkings(to: nil)
811
}
912

13+
/**
14+
Mark all the `Graph`'s ``GraphNode``s with the given ``GraphNode/Marking-swift.class`` or unmark them passing `nil`
15+
*/
1016
func setNodeMarkings(to marking: Node.Marking?)
1117
{
1218
for node in nodesByID.values
@@ -18,8 +24,14 @@ public extension Graph
1824

1925
public extension GraphNode
2026
{
27+
/**
28+
Whether ``GraphNode/marking-swift.property`` is not `nil`
29+
*/
2130
var isMarked: Bool { marking != nil }
2231

32+
/**
33+
Mark the `GraphNode` with a given ``GraphNode/Marking-swift.class`` or just call `mark()` to mark it with ``GraphNode/Marking-swift.class/zero``
34+
*/
2335
@discardableResult
2436
func mark(with marking: Marking = .zero) -> Marking
2537
{
@@ -30,5 +42,8 @@ public extension GraphNode
3042

3143
public extension GraphNode.Marking
3244
{
45+
/**
46+
Empty `GraphNode.Marking` for generally marking a ``GraphNode``, see ``GraphNode/mark(with:)``
47+
*/
3348
static var zero: GraphNode.Marking { .init() }
3449
}

Code/Graph+Algorithms/Graph+StronglyConnectedComponents.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ import SwiftyToolz
22

33
extension Graph
44
{
5+
/**
6+
Find the [strongly connected components](https://en.wikipedia.org/wiki/Strongly_connected_component) of the `Graph`
7+
8+
- Returns: Multiple sets of nodes which represent the strongly connected components of the graph
9+
*/
510
func findStronglyConnectedComponents() -> Set<Nodes>
611
{
712
unmarkNodes()

Code/Graph/Graph.swift

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,35 @@ import OrderedCollections
22
import SwiftyToolz
33

44
/**
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:)``.
610
*/
711
public class Graph<NodeID: Hashable, NodeValue>
812
{
913
// MARK: - Initialize
1014

15+
/**
16+
Uses the `NodeValue.ID` of a value as the ``GraphNode/id`` for its corresponding node
17+
*/
1118
public convenience init(nodes: OrderedNodes = []) where NodeValue: Identifiable, NodeValue.ID == NodeID
1219
{
1320
self.init(nodes: nodes) { $0.id }
1421
}
1522

23+
/**
24+
Uses a `NodeValue` itself as the ``GraphNode/id`` for its corresponding node
25+
*/
1626
public convenience init(nodes: OrderedNodes = []) where NodeID == NodeValue
1727
{
1828
self.init(nodes: nodes) { $0 }
1929
}
2030

31+
/**
32+
Creates a `Graph` that generates ``GraphNode/id``s for new ``GraphNode``s with the given closure
33+
*/
2134
public init(nodes: OrderedNodes = [],
2235
makeNodeIDForValue: @escaping (NodeValue) -> NodeID)
2336
{
@@ -27,22 +40,35 @@ public class Graph<NodeID: Hashable, NodeValue>
2740

2841
// MARK: - Edges
2942

43+
/**
44+
Removes the corresponding ``GraphEdge``, see ``Graph/remove(_:)``
45+
*/
3046
public func removeEdge(from sourceID: NodeID, to targetID: NodeID)
3147
{
3248
removeEdge(with: .init(sourceID, targetID))
3349
}
3450

51+
/**
52+
Removes the corresponding ``GraphEdge``, see ``Graph/remove(_:)``
53+
*/
3554
public func removeEdge(from source: Node, to target: Node)
3655
{
3756
removeEdge(with: .init(source, target))
3857
}
3958

59+
/**
60+
Removes the corresponding ``GraphEdge``, see ``Graph/remove(_:)``
61+
*/
4062
public func removeEdge(with id: Edge.ID)
4163
{
4264
guard let edge = edgesByID[id] else { return }
4365
remove(edge)
4466
}
4567

68+
/**
69+
Removes the ``GraphEdge``, also removing it from the caches of its ``GraphEdge/source`` and ``GraphEdge/target``
70+
71+
*/
4672
public func remove(_ edge: Edge)
4773
{
4874
// remove from node caches
@@ -54,6 +80,11 @@ public class Graph<NodeID: Hashable, NodeValue>
5480
edgesByID[edge.id] = nil
5581
}
5682

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+
*/
5788
@discardableResult
5889
public func addEdge(from sourceID: NodeID,
5990
to targetID: NodeID,
@@ -68,6 +99,13 @@ public class Graph<NodeID: Hashable, NodeValue>
6899
return addEdge(from: source, to: target, count: count)
69100
}
70101

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+
*/
71109
@discardableResult
72110
public func addEdge(from source: Node,
73111
to target: Node,
@@ -96,30 +134,47 @@ public class Graph<NodeID: Hashable, NodeValue>
96134
}
97135
}
98136

137+
/**
138+
The ``GraphEdge`` from `source` to `target` if it exists, otherwise `nil`
139+
*/
99140
public func edge(from source: Node, to target: Node) -> Edge?
100141
{
101142
guard contains(source), contains(target) else { return nil }
102143
return edge(from: source.id, to: target.id)
103144
}
104145

146+
/**
147+
The ``GraphEdge`` between the corresponding nodes if it exists, otherwise `nil`
148+
*/
105149
public func edge(from sourceID: NodeID, to targetID: NodeID) -> Edge?
106150
{
107151
edgesByID[.init(sourceID, targetID)]
108152
}
109153

154+
/**
155+
All ``GraphEdge``s of the `Graph`
156+
*/
110157
public var edges: Dictionary<Edge.ID, Edge>.Values
111158
{
112159
edgesByID.values
113160
}
114161

162+
/**
163+
All ``GraphEdge``s of the `Graph` hashable by their ``GraphEdge/id-swift.property``
164+
*/
115165
public private(set) var edgesByID = [Edge.ID: Edge]()
116166

167+
/**
168+
Shorthand for the full generic type name `GraphEdge<NodeID, NodeValue>`
169+
*/
117170
public typealias Edge = GraphEdge<NodeID, NodeValue>
118171

119172
// MARK: - Node Values
120173

121174
/**
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``.
123178
*/
124179
@discardableResult
125180
public func insert(_ value: NodeValue) -> Node
@@ -133,61 +188,105 @@ public class Graph<NodeID: Hashable, NodeValue>
133188

134189
internal let makeNodeIDForValue: (NodeValue) -> NodeID
135190

191+
/**
192+
``GraphNode/value`` of the ``GraphNode`` with the given ``GraphNode/id`` if one exists, otherwise `nil`
193+
*/
136194
public func value(for nodeID: NodeID) -> NodeValue?
137195
{
138196
node(for: nodeID)?.value
139197
}
140198

199+
/**
200+
All `NodeValue`s of the `Graph`
201+
*/
141202
public var values: [NodeValue]
142203
{
143204
nodes.map { $0.value }
144205
}
145206

146207
// MARK: - Nodes
147208

209+
/**
210+
All source nodes of the `Graph`, see ``GraphNode/isSource``
211+
*/
148212
public var sources: [Node]
149213
{
150214
nodesByID.values.filter { $0.isSource }
151215
}
152216

217+
/**
218+
All sink nodes of the `Graph`, see ``GraphNode/isSink``
219+
*/
153220
public var sinks: [Node]
154221
{
155222
nodesByID.values.filter { $0.isSink }
156223
}
157224

225+
/**
226+
Whether the `Graph` contains a ``GraphNode`` with the given ``GraphNode/id``
227+
*/
158228
public func contains(_ nodeID: NodeID) -> Bool
159229
{
160230
node(for: nodeID) != nil
161231
}
162232

233+
/**
234+
Whether the `Graph` contains the given ``GraphNode``
235+
*/
163236
public func contains(_ node: Node) -> Bool
164237
{
165238
self.node(for: node.id) === node
166239
}
167240

241+
/**
242+
``GraphNode`` with the given ``GraphNode/id`` if one exists, otherwise `nil`
243+
*/
168244
public func node(for nodeID: NodeID) -> Node?
169245
{
170246
nodesByID[nodeID]
171247
}
172248

249+
/**
250+
Sort the ``GraphNode``s of the `Graph` with the given closure
251+
*/
173252
public func sort(by nodesAreInOrder: (Node, Node) -> Bool)
174253
{
175254
nodesByID.values.sort(by: nodesAreInOrder)
176255
}
177256

257+
/**
258+
The ``GraphNode/id``s of all ``GraphNode``s of the `Graph`
259+
*/
178260
public var nodesIDs: OrderedSet<NodeID>
179261
{
180262
nodesByID.keys
181263
}
182264

265+
/**
266+
All ``GraphNode``s of the `Graph`
267+
*/
183268
public var nodes: OrderedDictionary<NodeID, Node>.Values
184269
{
185270
nodesByID.values
186271
}
187272

273+
/**
274+
All ``GraphNode``s of the `Graph` hashable by their ``GraphNode/id``s
275+
*/
188276
public private(set) var nodesByID = OrderedDictionary<NodeID, Node>()
189277

278+
/**
279+
Shorthand for `OrderedSet<Node>`
280+
*/
190281
public typealias OrderedNodes = OrderedSet<Node>
282+
283+
/**
284+
Shorthand for `Set<Node>`
285+
*/
191286
public typealias Nodes = Set<Node>
287+
288+
/**
289+
Shorthand for the `Graph`'s full generic node type `GraphNode<NodeID, NodeValue>`
290+
*/
192291
public typealias Node = GraphNode<NodeID, NodeValue>
193292
}

0 commit comments

Comments
 (0)