SwiftGraph

repository·master·Indexed 21 days ago

https://github.com/davecom/swiftgraph

A 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.

Tokens
1.9K
Snippets
4
Records
11
Agent score
24%

What's inside SwiftGraph

  1. Optimize edge insertion performance

    master
    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.
  2. Understand Graph implementations and usage

    master

    Graphs 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) and Codable.
    • 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 Equatable and Codable.

    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 using UnweightedEdge.
    • WeightedGraph: A generic class for weighted graphs using WeightedEdge. 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>
  3. Perform graph operations and searches

    master

    SwiftGraph 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 isDAG property to check if the graph is a Directed Acyclic Graph.
    • Breadth-First/Depth-First Search: Use bfs() and dfs() to find routes between vertices, or use findAll(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"
    }
  4. Understand Edges in SwiftGraph

    master

    Edges 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 be Codable.
    • UnweightedEdge: A concrete implementation for unweighted graphs.
    • WeightedEdge: A concrete implementation for weighted graphs. Weights must conform to Comparable, Numeric, and Codable (e.g., Int or Float).
  5. Install SwiftGraph

    master

    SwiftGraph 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 Sources folder 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
  6. Create a WeightedGraph in SwiftGraph

    master

    SwiftGraph 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 String vertices and Int weights:

    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"])
  7. Perform Graph Search operations

    master

    SwiftGraph provides several search algorithms via extensions on Graph and WeightedGraph.

    • bfs(): Finds a path from a source to a destination using breadth-first search. Returns an array of Edges or an empty array if no path exists. Supports a goalTest() function to find the first vertex matching a criteria.
    • dfs(): Finds a path using depth-first search. Returns an array of Edges or an empty array. Supports a goalTest() function.
    • findAll(): Uses BFS to find all connected vertices that satisfy a goalTest() function. Returns an array of paths.
    • Traversal: Both bfs() and dfs() have versions that allow a visit function to execute at each step.

    Shortest Path

    • dijkstra(): (Available on WeightedGraph) Finds the shortest path from a starting vertex to every other vertex. Returns a tuple containing:
      1. An array of distances to each vertex (arranged by index).
      2. A dictionary mapping indices to the previous Edge used to reach them. Use pathDictToPath() to reconstruct a specific path from this dictionary.
  8. Find Minimum Spanning Trees (MST)

    master

    For WeightedGraph instances, you can find a minimum-spanning tree using Jarnik's Algorithm (Prim's Algorithm).

    • mst(): Returns an array of WeightedEdges 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() and printMST() to inspect the results.
    • Complexity: $O(n ext{ lg } n)$.
  9. Detect Cycles in a Graph

    master

    The detectCycles() method finds all cycles within a graph using the Liu/Wang algorithm.

    • detectCycles(upToLength:): Optionally accepts an upToLength parameter to limit the search depth.
      • Example: upToLength: 3 will find 1-vertex cycles (self-loops) and 3-vertex cycles, but will not search for longer cycles.
  10. Perform Topological Sort and DAG detection

    master

    Extensions to Graph provide utilities for analyzing directed graphs:

    • topologicalSort(): Performs a topological sort of the vertices. Returns a sorted list of vertices, or nil if a cycle is detected. Complexity: $O(n)$.
    • isDAG: A property that returns true if the graph is a Directed Acyclic Graph (DAG) by checking if a topological sort is possible. Complexity: $O(n)$.