Algebraic graphs for MoonBit — directed graph trait and algorithm library inspired by Haskell's alga
Dependencies
moon add dowdiness/alga// Build a graph: 1 → 2 → 3 → 4
let g = @alga.AdjacencyMap::from_edges([(1, 2), (2, 3), (3, 4)])
// Traverse
let r = @alga.reachable(g, 1) // [1, 2, 3, 4]
let order = @alga.toposort(g) // Some([1, 2, 3, 4])
let cyclic = @alga.has_cycle(g) // false
// Strongly connected components
let sccs = @alga.tarjan_scc(g) // [[4], [3], [2], [1]]
// DFS with edge classification
for event in @alga.dfs_events(g) {
match event {
@alga.BackEdge(u, v) => println("cycle: \{u} → \{v}")
_ => ()
}
}
// Reverse traversal: "what can reach vertex 4?"
let ancestors = @alga.reachable(@alga.reversed(g), 4) // [4, 3, 2, 1]
// Algebraic construction
let expr = @alga.Graph::path([1, 2, 3])
let am = expr.to_adjacency_map()Observation layer Construction layer
(DirectedGraph + Predecessors) (GraphSym + Graph enum)
┌─────────────────┐ ┌──────────────────┐
│ DirectedGraph │ │ GraphSym │
│ iter │ │ empty, vertex │
│ successors │ │ overlay, connect│
│ (+ 4 defaults) │ └──────┬───────────┘
├─────────────────┤ │
│ Predecessors │ ┌────┴────┐
│ predecessors │ bridge: │ Graph │
└──────┬──────────┘ foldg │ (enum) │
│ └──────────┘
┌─────┴─────┐ ┌────────────┐
│AdjacencyMap│ │ DenseGraph │
└────────────┘ └────────────┘| Algorithm | Function | Time |
|---|---|---|
| DFS fold | dfs_fold(g, start, init, f) | O(V+E) |
| BFS fold | bfs_fold(g, start, init, f) | O(V+E) |
| Multi-source DFS/BFS | dfs_fold_multi, bfs_fold_multi | O(V+E) |
| Reachability | reachable(g, v) | O(V+E) |
| DFS edge classification | dfs_events(g) | O(V+E) |
| Topological sort | toposort(g) | O(V+E) |
| Topological levels | topo_levels(g) | O(V+E) |
| Cycle detection | has_cycle(g) | O(V+E) |
| SCC (Tarjan) | tarjan_scc(g) | O(V+E) |
| SCC (Kosaraju) | g.scc() | O(V+E) |
| Condensation | g.condensation() | O(V+E) |
| Reversed view | reversed(g) | O(1) |
| Degree queries | outdegree(g, v), indegree(g, v) | O(deg) / O(V+E) |
struct MyGraph { edges : Array[Array[Int]] }
impl @alga.DirectedGraph for MyGraph with iter(self) {
(0).until(self.edges.length())
}
impl @alga.DirectedGraph for MyGraph with successors(self, v) {
self.edges[v].iter()
}
// Now available: toposort(g), tarjan_scc(g), reachable(g, 0),
// has_cycle(g), dfs_events(g), dfs_fold(g, ...), bfs_fold(g, ...), etc.| Combinator | Result |
|---|---|
| Graph::vertices([1, 2, 3]) | Three isolated vertices |
| Graph::edges([(1,2), (3,4)]) | Edges 1→2, 3→4 |
| Graph::path([1, 2, 3]) | Chain 1→2→3 |
| Graph::circuit([1, 2, 3]) | Loop 1→2→3→1 |
| Graph::clique([1, 2, 3]) | Complete: 1→2, 1→3, 2→3 |
| Graph::star(1, [2, 3, 4]) | Hub: 1→2, 1→3, 1→4 |
src/
traits.mbt DirectedGraph, Predecessors traits
adjacency_map.mbt AdjacencyMap — sparse representation
dense_graph.mbt DenseGraph — dense, high-performance representation
reversed.mbt Reversed[G] — zero-cost reverse-direction adaptor
graph_expr.mbt Graph enum — algebraic expression tree + foldg
graph_sym.mbt GraphSym trait — algebraic construction interface
dfs.mbt DFS fold, DFS events (edge classification)
bfs.mbt BFS fold
toposort.mbt Topological sort, topo levels, cycle detection
scc.mbt Kosaraju SCC, Tarjan SCC, condensation
degree.mbt Indegree, outdegree
experiment/ Performance experiments (DenseGraph, visited sets)
docs/
philosophy.md Why algebraic graphs, the axiom system, design principles
architecture.md Two-layer design, trait system, algorithm details
TODO.md Active backlogstruct MyGraph { edges : Array[Array[Int]] }
impl DirectedGraph for MyGraph with iter(self) {
(0).until(self.edges.length())
}
impl DirectedGraph for MyGraph with successors(self, v) {
self.edges[v].iter()
}
// vertex_count, has_vertex, each_vertex, each_successor all work via defaults.pub(open) trait GraphSym {
empty() -> Self
vertex(Int) -> Self
overlay(Self, Self) -> Self
connect(Self, Self) -> Self
}| Operation | Time complexity |
|---|---|
| from_edges | O(E) amortized |
| has_vertex | O(1) |
| has_edge | O(degree) |
| overlay | O(V + E) |
| connect | O(V1 * V2 + E) |
| transpose | O(1) |
| vertex_count | O(1) |
| edge_count | O(V) |
impl DirectedGraph for AdjacencyMapimpl GraphSym for AdjacencyMapimpl Predecessors for AdjacencyMapimpl Eq for AdjacencyMapimpl Show for AdjacencyMapimpl Debug for AdjacencyMap| Operation | AdjacencyMap | DenseGraph |
|---|---|---|
| successor lookup | O(log V) (Map) | O(1) (Array) |
| transpose | O(1) | O(1) |
| DFS reachable | ~94 µs (1000V) | ~7 µs (1000V) |
| SCC | ~460 µs (1000V) | ~50 µs (1000V) |
impl DirectedGraph for DenseGraphimpl Predecessors for DenseGraphimpl Show for DenseGraphimpl Debug for DenseGraphpub(all) enum DfsEvent {
Discover(Int)
Finish(Int)
TreeEdge(Int, Int)
BackEdge(Int, Int)
CrossForwardEdge(Int, Int)
} derive(Eq)pub struct Reversed[G] {
graph : G
}impl DirectedGraph for Reversed[G]impl Predecessors for Reversed[G]fn[G : DirectedGraph, Acc] bfs_fold(graph : G, start : Int, init : Acc, f : (Acc, Int) -> (Acc, Bool)) -> Accfn[G : DirectedGraph, Acc] bfs_fold_multi(graph : G, starts : Array[Int], init : Acc, f : (Acc, Int) -> (Acc, Bool)) -> Accfn[G : DirectedGraph, Acc] dfs_fold(graph : G, start : Int, init : Acc, f : (Acc, Int) -> (Acc, Bool)) -> Accfn[G : DirectedGraph, Acc] dfs_fold_multi(graph : G, starts : Array[Int], init : Acc, f : (Acc, Int) -> (Acc, Bool)) -> Accfn[B] foldg(graph : Graph, empty : B, vertex : (Int) -> B, overlay : (B, B) -> B, connect : (B, B) -> B) -> Bfn[B] foldg_iter(graph : Graph, empty : B, vertex : (Int) -> B, overlay : (B, B) -> B, connect : (B, B) -> B) -> BAlgebraic graphs for MoonBit — directed graph trait and algorithm library inspired by Haskell's alga
Dependencies