@@ -45,6 +45,93 @@ def deps do
4545end
4646```
4747
48+ ## Multigraphs
49+
50+ Libgraph supports multigraphs — graphs where multiple edges with different labels can exist between
51+ the same pair of vertices. When ` multigraph: true ` is enabled, an edge adjacency index is maintained
52+ that allows O(1) lookup of edges by partition key, avoiding full edge scans.
53+
54+ ### Creating a multigraph
55+
56+ ``` elixir
57+ g =
58+ Graph .new (multigraph: true )
59+ |> Graph .add_edges ([
60+ {:a , :b , label: :uses },
61+ {:a , :b , label: :contains },
62+ {:b , :c , label: :uses },
63+ {:b , :c , label: :owns , weight: 3 }
64+ ])
65+ ```
66+
67+ ### Querying by partition
68+
69+ By default, edges are partitioned by their label (via ` Graph.Utils.by_edge_label/1 ` ). You can
70+ query edges belonging to a specific partition:
71+
72+ ``` elixir
73+ # Get only :uses edges
74+ Graph .edges (g, by: :uses )
75+ # => [%Graph.Edge{v1: :a, v2: :b, label: :uses}, %Graph.Edge{v1: :b, v2: :c, label: :uses}]
76+
77+ # Get out edges from :a with label :contains
78+ Graph .out_edges (g, :a , by: :contains )
79+ # => [%Graph.Edge{v1: :a, v2: :b, label: :contains}]
80+
81+ # Filter edges with a predicate
82+ Graph .edges (g, where: fn edge -> edge.weight > 2 end )
83+ # => [%Graph.Edge{v1: :b, v2: :c, label: :owns, weight: 3}]
84+ ```
85+
86+ ### Custom partition functions
87+
88+ You can provide a custom ` partition_by ` function to control how edges are indexed:
89+
90+ ``` elixir
91+ g = Graph .new (multigraph: true , partition_by: fn edge -> [edge.weight] end )
92+ |> Graph .add_edges ([{:a , :b , weight: 1 }, {:b , :c , weight: 2 }])
93+
94+ Graph .edges (g, by: 1 )
95+ # => [%Graph.Edge{v1: :a, v2: :b, weight: 1}]
96+ ```
97+
98+ ### Partition-filtered traversals
99+
100+ BFS, DFS, Dijkstra, A* , and Bellman-Ford all support a ` by: ` option to restrict traversal to
101+ edges in specific partitions:
102+
103+ ``` elixir
104+ g =
105+ Graph .new (multigraph: true )
106+ |> Graph .add_edges ([
107+ {:a , :b , label: :fast , weight: 1 },
108+ {:a , :c , label: :slow , weight: 10 },
109+ {:b , :d , label: :fast , weight: 1 },
110+ {:c , :d , label: :slow , weight: 1 }
111+ ])
112+
113+ # Shortest path using only :fast edges
114+ Graph .dijkstra (g, :a , :d , by: :fast )
115+ # => [:a, :b, :d]
116+
117+ # BFS following only :fast edges
118+ Graph .Reducers .Bfs .map (g, & &1 , by: :fast )
119+ # => [:a, :b, :d]
120+ ```
121+
122+ ### Edge properties
123+
124+ Edges now support an arbitrary ` properties ` map for storing additional metadata:
125+
126+ ``` elixir
127+ g = Graph .new ()
128+ |> Graph .add_edge (:a , :b , label: :link , properties: %{color: " red" , style: :dashed })
129+
130+ [edge] = Graph .edges (g)
131+ edge.properties
132+ # => %{color: "red", style: :dashed}
133+ ```
134+
48135## Rationale
49136
50137The original motivation for me to start working on this library is the fact that ` :digraph ` requires a
0 commit comments