/
WeightedGraph.swift
156 lines (142 loc) · 6.51 KB
/
WeightedGraph.swift
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
//
// WeightedGraph.swift
// SwiftGraph
//
// Copyright (c) 2014-2019 David Kopec
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/// A subclass of Graph that has convenience methods for adding and removing WeightedEdges. All added Edges should have the same generic Comparable type W as the WeightedGraph itself.
open class WeightedGraph<V: Equatable & Codable, W: Equatable & Codable>: Graph {
public var vertices: [V] = [V]()
public var edges: [[WeightedEdge<W>]] = [[WeightedEdge<W>]]() //adjacency lists
public init() {
}
required public init(vertices: [V]) {
for vertex in vertices {
_ = self.addVertex(vertex)
}
}
}
extension Graph where E: WeightedEdgeProtocol {
public typealias W = E.Weight
/// Find all of the neighbors of a vertex at a given index.
///
/// - parameter index: The index for the vertex to find the neighbors of.
/// - returns: An array of tuples including the vertices as the first element and the weights as the second element.
public func neighborsForIndexWithWeights(_ index: Int) -> [(V, W)] {
var distanceTuples: [(V, W)] = [(V, W)]();
for edge in edges[index] {
distanceTuples += [(vertices[edge.v], edge.weight)]
}
return distanceTuples;
}
/// This is a convenience method that adds a weighted edge.
///
/// - parameter from: The starting vertex's index.
/// - parameter to: The ending vertex's index.
/// - parameter directed: Is the edge directed? (default false)
/// - parameter weight: the Weight of the edge to add.
public func addEdge(fromIndex: Int, toIndex: Int, weight: W, directed: Bool = false) {
addEdge(E(u: fromIndex, v: toIndex, directed: directed, weight: weight), directed: directed)
}
/// This is a convenience method that adds a weighted edge between the first occurence of two vertices. It takes O(n) time.
///
/// - parameter from: The starting vertex.
/// - parameter to: The ending vertex.
/// - parameter directed: Is the edge directed? (default false)
/// - parameter weight: the Weight of the edge to add.
public func addEdge(from: V, to: V, weight: W, directed: Bool = false) {
if let u = indexOfVertex(from), let v = indexOfVertex(to) {
addEdge(fromIndex: u, toIndex: v, weight: weight, directed: directed)
}
}
/// Check whether there is an edge from one vertex to another vertex with a specific weight.
///
/// - parameter from: The index of the starting vertex of the edge.
/// - parameter to: The index of the ending vertex of the edge.
/// - returns: True if there is an edge from the starting vertex to the ending vertex.
public func edgeExists(fromIndex: Int, toIndex: Int, withWeight weight: W) -> Bool {
// The directed property of this fake edge is ignored, since it's not taken into account
// for equality.
return edgeExists(E(u: fromIndex, v: toIndex, directed: true, weight: weight))
}
/// Check whether there is an edge from one vertex to another vertex with a specific weight.
///
/// Note this will look at the first occurence of each vertex.
/// Also returns false if either of the supplied vertices cannot be found in the graph.
///
/// - parameter from: The starting vertex of the edge.
/// - parameter to: The ending vertex of the edge.
/// - returns: True if there is an edge from the starting vertex to the ending vertex.
public func edgeExists(from: V, to: V, withWeight weight: W) -> Bool {
if let u = indexOfVertex(from) {
if let v = indexOfVertex(to) {
return edgeExists(fromIndex: u, toIndex: v, withWeight: weight)
}
}
return false
}
/// Check whether there is an edge from one vertex to another vertex.
///
/// - parameter from: The index of the starting vertex of the edge.
/// - parameter to: The index of the ending vertex of the edge.
/// - returns: True if there is an edge from the starting vertex to the ending vertex.
public func edgeExists(fromIndex: Int, toIndex: Int) -> Bool {
return edges[fromIndex].map({$0.v}).contains(toIndex)
}
/// Check whether there is an edge from one vertex to another vertex.
///
/// Note this will look at the first occurence of each vertex.
/// Also returns false if either of the supplied vertices cannot be found in the graph.
///
/// - parameter from: The starting vertex of the edge.
/// - parameter to: The ending vertex of the edge.
/// - returns: True if there is an edge from the starting vertex to the ending vertex.
public func edgeExists(from: V, to: V) -> Bool {
if let u = indexOfVertex(from) {
if let v = indexOfVertex(to) {
return edgeExists(fromIndex: u, toIndex: v)
}
}
return false
}
/// Returns all the weights associated to the edges between two vertex indices.
///
/// - Parameters:
/// - from: The starting vertex index
/// - to: The ending vertex index
/// - Returns: An array with all the weights associated to edges between the provided indexes.
public func weights(from: Int, to: Int) -> [W] {
return edges[from].filter { $0.v == to }.map { $0.weight }
}
/// Returns all the weights associated to the edges between two vertices.
///
/// - Parameters:
/// - from: The starting vertex
/// - to: The ending vertex
/// - Returns: An array with all the weights associated to edges between the provided vertices.
public func weights(from: V, to: V) -> [W] {
if let u = indexOfVertex(from), let v = indexOfVertex(to) {
return edges[u].filter { $0.v == v }.map { $0.weight }
}
return []
}
// Implement Printable protocol
public var description: String {
var d: String = ""
for i in 0..<vertices.count {
d += "\(vertices[i]) -> \(neighborsForIndexWithWeights(i))\n"
}
return d
}
}