Skip to content

Commit ab4305e

Browse files
committed
update multigraph index on update/delete
1 parent 3d65693 commit ab4305e

2 files changed

Lines changed: 79 additions & 32 deletions

File tree

lib/graph.ex

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,30 +1202,7 @@ defmodule Graph do
12021202
if g.multigraph do
12031203
edge = Edge.new(v1, v2, label: label, weight: options_meta.weight, properties: opts)
12041204

1205-
partition = g.partition_by.(edge)
1206-
1207-
edge_partition = Map.get(g.edge_index, partition, %{})
1208-
1209-
v1_set = Map.get(edge_partition, v1_id, MapSet.new())
1210-
v2_set = Map.get(edge_partition, v2_id, MapSet.new())
1211-
1212-
new_edge_partition =
1213-
edge_partition
1214-
|> Map.put(
1215-
v1_id,
1216-
MapSet.put(v1_set, {v1_id, v2_id})
1217-
)
1218-
|> Map.put(
1219-
v2_id,
1220-
MapSet.put(v2_set, {v1_id, v2_id})
1221-
)
1222-
1223-
%__MODULE__{
1224-
g
1225-
| edge_index:
1226-
g.edge_index
1227-
|> Map.put(partition, new_edge_partition)
1228-
}
1205+
index_multigraph_edge(g, {v1_id, v2_id}, edge)
12291206
else
12301207
g
12311208
end
@@ -1238,6 +1215,37 @@ defmodule Graph do
12381215
}
12391216
end
12401217

1218+
defp index_multigraph_edge(
1219+
%__MODULE__{multigraph: true, edge_index: edge_index} = g,
1220+
{v1_id, v2_id},
1221+
%Edge{} = edge
1222+
) do
1223+
partition = g.partition_by.(edge)
1224+
1225+
edge_partition = Map.get(edge_index, partition, %{})
1226+
1227+
v1_set = Map.get(edge_partition, v1_id, MapSet.new())
1228+
v2_set = Map.get(edge_partition, v2_id, MapSet.new())
1229+
1230+
new_edge_partition =
1231+
edge_partition
1232+
|> Map.put(
1233+
v1_id,
1234+
MapSet.put(v1_set, {v1_id, v2_id})
1235+
)
1236+
|> Map.put(
1237+
v2_id,
1238+
MapSet.put(v2_set, {v1_id, v2_id})
1239+
)
1240+
1241+
%__MODULE__{
1242+
g
1243+
| edge_index:
1244+
edge_index
1245+
|> Map.put(partition, new_edge_partition)
1246+
}
1247+
end
1248+
12411249
@doc """
12421250
This function is like `add_edge/3`, but for multiple edges at once, it also accepts edge specifications
12431251
in a few different ways to make it easy to generate graphs succinctly.
@@ -1421,7 +1429,20 @@ defmodule Graph do
14211429

14221430
_ ->
14231431
new_meta = Map.put(Map.delete(meta, old_label), new_label, new_attrs)
1424-
%__MODULE__{g | edges: Map.put(em, edge_key, new_meta)}
1432+
1433+
if g.multigraph do
1434+
g =
1435+
g
1436+
|> prune_edge_index({v1_id, v1}, {v2_id, v2}, old_label)
1437+
|> index_multigraph_edge(
1438+
{v1_id, v2_id},
1439+
Edge.new(v1, v2, label: new_label, weight: new_attrs.weight, properties: opts)
1440+
)
1441+
1442+
%__MODULE__{g | edges: Map.put(em, edge_key, new_meta)}
1443+
else
1444+
%__MODULE__{g | edges: Map.put(em, edge_key, new_meta)}
1445+
end
14251446
end
14261447
else
14271448
_ ->
@@ -1549,13 +1570,20 @@ defmodule Graph do
15491570

15501571
edge_p = partition_by.(edge)
15511572

1552-
v1_key = {v1_id, edge_p}
1553-
v2_key = {v2_id, edge_p}
1573+
partition =
1574+
edge_index
1575+
|> Map.get(edge_p, %{})
1576+
|> Map.reject(fn {k, v} ->
1577+
(k == v1_id and MapSet.member?(v, {v1_id, v2_id})) or
1578+
(k == v2_id and MapSet.member?(v, {v1_id, v2_id}))
1579+
end)
15541580

15551581
edge_index =
1556-
edge_index
1557-
|> Map.delete(v1_key)
1558-
|> Map.delete(v2_key)
1582+
if not Enum.empty?(partition) do
1583+
Map.put(edge_index, edge_p, partition)
1584+
else
1585+
Map.delete(edge_index, edge_p)
1586+
end
15591587

15601588
%__MODULE__{
15611589
g

test/graph_test.exs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,27 @@ defmodule GraphTest do
114114
])
115115

116116
g = Graph.delete_edge(g, :a, :b, :foo)
117-
refute Map.has_key?(g.edge_index, {g.vertex_identifier.(:a), :foo})
118-
refute Map.has_key?(g.edge_index, {g.vertex_identifier.(:b), :foo})
117+
118+
refute Map.has_key?(g.edge_index, :foo)
119+
assert Enum.empty?(Graph.out_edges(g, :a, by: :foo))
120+
assert Enum.empty?(Graph.edges(g, by: :foo))
121+
end
122+
123+
test "update_labelled_edge/3 updates an indexed adge with new label" do
124+
g =
125+
Graph.new(multigraph: true)
126+
|> Graph.add_edges([
127+
{:a, :b},
128+
{:a, :b, label: :foo},
129+
{:a, :b, label: :bar},
130+
{:b, :c, weight: 3},
131+
{:b, :a, label: {:complex, :label}}
132+
])
133+
134+
g = Graph.update_labelled_edge(g, :a, :b, :foo, label: :baz)
135+
136+
refute Map.has_key?(g.edge_index, :foo)
137+
assert Map.has_key?(g.edge_index[:baz], g.vertex_identifier.(:a))
119138
end
120139

121140
test "traversal using indexed keys" do

0 commit comments

Comments
 (0)