SwiftGraph
repository·master·Indexed 21 days ago
https://github.com/davecom/swiftgraphA generic Swift implementation of graph data structures supporting weighted, unweighted, directed, and undirected graphs for iOS, macOS, and Linux. It includes built-in algorithms for Dijkstra's shortest path, Minimum Spanning Tree (MST), cycle detection, topological sort, DAG detection, and breadth-first/depth-first search.
What's inside SwiftGraph
- When building your graph, note that inserting an edge using vertex indices is significantly faster than inserting an edge using vertex objects. This is because inserting by object requires the graph to perform a lookup to find the corresponding index, which is an $O(n)$ operation where $n$ is the number of vertices.
Understand Graph implementations and usage
masterGraphs are the core data structures in SwiftGraph. Vertices are assigned an integer index upon insertion; referring to vertices by index is generally faster than using the vertex objects themselves.
Core Properties
- Protocols: Graphs implement
Collection(allowing iteration and subscripting by index) andCodable. - Thread Safety: Graphs are not thread-safe for mutations. However, once constructed, read-only operations (lookups and searches) can be performed from multiple threads.
- Vertex Requirements: Vertices must conform to
EquatableandCodable.
Implementation Types
Graph(Protocol): The base protocol. It is recommended to use canonical implementations rather than custom ones.UnweightedGraph: A generic class for unweighted graphs usingUnweightedEdge.WeightedGraph: A generic class for weighted graphs usingWeightedEdge. It includes methods to return neighbor vertices along with their weights as tuples.UniqueElementsGraph: A graph implementation that supports union operations and ensures all vertices and edges are unique.
// Iterating through vertices for v in g { // g is a Graph<String> print(v) } // Accessing a vertex by its index print(g[23]) // g is a Graph<String>- Protocols: Graphs implement
Perform graph operations and searches
masterSwiftGraph provides several algorithms for traversing and analyzing graphs:
- Dijkstra's Algorithm: Use
dijkstra(root:startDistance:)to find shortest paths in a weighted graph. It returns a tuple containing distances and a path dictionary. - Minimum Spanning Tree (MST): Use
mst()to find the minimum spanning tree connecting all vertices. - Cycle Detection: Use
detectCycles()to enumerate all cycles in the graph. - DAG Detection: Use the
isDAGproperty to check if the graph is a Directed Acyclic Graph. - Breadth-First/Depth-First Search: Use
bfs()anddfs()to find routes between vertices, or usefindAll(from:predicate:)to find vertices matching a specific condition starting from a root.
// Dijkstra's algorithm example let (distances, pathDict) = cityGraph.dijkstra(root: "New York", startDistance: 0) // Find Minimum Spanning Tree let mst = cityGraph.mst() // Detect cycles let cycles = cityGraph.detectCycles() // Check if Directed Acyclic Graph let isADAG = cityGraph.isDAG // Breadth-first search with a predicate let result = cityGraph.findAll(from: "New York") { v in return v.characters.first == "S" }- Dijkstra's Algorithm: Use
Understand Edges in SwiftGraph
masterEdges represent the connections between vertices in a graph. In SwiftGraph, vertices are identified by their integer index.
Key types:
Edge(Protocol): The base protocol for all edges. All edges must beCodable.UnweightedEdge: A concrete implementation for unweighted graphs.WeightedEdge: A concrete implementation for weighted graphs. Weights must conform toComparable,Numeric, andCodable(e.g.,IntorFloat).
Install SwiftGraph
masterSwiftGraph can be installed using several dependency managers or manually:
- Swift Package Manager (SPM): Add the repository URL as a dependency in your
Package.swift. - CocoaPods: Add
pod 'SwiftGraph'to your Podfile. - Carthage: Add the following to your
Cartfile:github "davecom/SwiftGraph" ~> 4.0 - Manual: Copy all files from the
Sourcesfolder directly into your project.
Version Compatibility:
- SwiftGraph 3.0+ requires Swift 5 (Xcode 10.2).
- For older Swift versions, use SwiftGraph 2.0 (Swift 4.2), 1.5.1 (Swift 4.1), 1.4.1 (Swift 3), 1.0.6 (Swift 2), or 1.0.0 (Swift 1.2).
github "davecom/SwiftGraph" ~> 4.0- Swift Package Manager (SPM): Add the repository URL as a dependency in your
Create a WeightedGraph in SwiftGraph
masterSwiftGraph uses generics to abstract both the vertex type and the weight type. A
WeightedGraph<Vertex, Weight>allows you to define a graph where edges have associated values (like distance or cost).Example of initializing a graph with
Stringvertices andIntweights:let cityGraph: WeightedGraph<String, Int> = WeightedGraph<String, Int>(vertices: ["Seattle", "San Francisco", "Los Angeles", "Denver", "Kansas City", "Chicago", "Boston", "New York", "Atlanta", "Miami", "Dallas", "Houston"])Perform Graph Search operations
masterSwiftGraph provides several search algorithms via extensions on
GraphandWeightedGraph.Breadth-First and Depth-First Search
bfs(): Finds a path from a source to a destination using breadth-first search. Returns an array ofEdges or an empty array if no path exists. Supports agoalTest()function to find the first vertex matching a criteria.dfs(): Finds a path using depth-first search. Returns an array ofEdges or an empty array. Supports agoalTest()function.findAll(): Uses BFS to find all connected vertices that satisfy agoalTest()function. Returns an array of paths.- Traversal: Both
bfs()anddfs()have versions that allow a visit function to execute at each step.
Shortest Path
dijkstra(): (Available onWeightedGraph) Finds the shortest path from a starting vertex to every other vertex. Returns a tuple containing:- An array of distances to each vertex (arranged by index).
- A dictionary mapping indices to the previous
Edgeused to reach them. UsepathDictToPath()to reconstruct a specific path from this dictionary.
Find Minimum Spanning Trees (MST)
masterFor
WeightedGraphinstances, you can find a minimum-spanning tree using Jarnik's Algorithm (Prim's Algorithm).mst(): Returns an array ofWeightedEdges that form the tree with the minimum cumulative weight.
Constraints & Usage:
- Assumes the graph is undirected and connected.
- If the graph is directed, results may be incorrect.
- If the graph is not fully connected, it returns the MST for the connected component containing the starting vertex.
- Use utility functions
totalWeight()andprintMST()to inspect the results. - Complexity: $O(n ext{ lg } n)$.
Reverse all edges in a graph
masterAn extension toGraphprovides a method to reverse the direction of all edges in the graph.Detect Cycles in a Graph
masterThe
detectCycles()method finds all cycles within a graph using the Liu/Wang algorithm.detectCycles(upToLength:): Optionally accepts anupToLengthparameter to limit the search depth.- Example:
upToLength: 3will find 1-vertex cycles (self-loops) and 3-vertex cycles, but will not search for longer cycles.
- Example:
Perform Topological Sort and DAG detection
masterExtensions to
Graphprovide utilities for analyzing directed graphs:topologicalSort(): Performs a topological sort of the vertices. Returns a sorted list of vertices, ornilif a cycle is detected. Complexity: $O(n)$.isDAG: A property that returnstrueif the graph is a Directed Acyclic Graph (DAG) by checking if a topological sort is possible. Complexity: $O(n)$.