Skip to content

Commit 076ad6f

Browse files
committed
feat: add split_labelled_edge function
1 parent 460cdfd commit 076ad6f

File tree

1 file changed

+40
-23
lines changed

1 file changed

+40
-23
lines changed

lib/graph.ex

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1070,47 +1070,64 @@ defmodule Graph do
10701070
...> g = Graph.split_edge(g, :a, :c, :b)
10711071
...> Graph.edges(g)
10721072
[%Graph.Edge{v1: :a, v2: :b, weight: 2}, %Graph.Edge{v1: :b, v2: :c, weight: 2}]
1073+
1074+
iex> g = Graph.new |> Graph.add_vertices([:a, :c]) |> Graph.add_edge(:a, :c, label: :first_label, weight: 2) |> Graph.add_edge(:a, :c, label: :second_label, weight: 2)
1075+
...> g = Graph.split_edge(g, :a, :c, :b)
1076+
...> Graph.edges(g)
1077+
[%Graph.Edge{v1: :a, v2: :b, label: :first_label, weight: 2}, %Graph.Edge{v1: :a, v2: :b, label: :second_label, weight: 2}, %Graph.Edge{v1: :b, v2: :c, label: :first_label, weight: 2}, %Graph.Edge{v1: :b, v2: :c, label: :second_label, weight: 2}]
10731078
"""
10741079
@spec split_edge(t, vertex, vertex, vertex) :: t | {:error, :no_such_edge}
1075-
def split_edge(%__MODULE__{type: :undirected} = g, v1, v2, v3) do
1080+
def split_edge(%__MODULE__{} = g, v1, v2, v3) do
1081+
split_labelled_edge(g, v1, v2, v3, nil)
1082+
end
1083+
1084+
@doc """
1085+
Like `split_edge/4`, but requires you to specify the labelled edge to split.
1086+
1087+
Th implementation of `splt_edge/4` is actually `split_labelled_edge(g, v1, v2, v3, nil)`.
1088+
1089+
## Example
1090+
1091+
iex> g = Graph.new |> Graph.add_vertices([:a, :c]) |> Graph.add_edge(:a, :c, label: :first_label, weight: 2) |> Graph.add_edge(:a, :c, label: :second_label, weight: 2)
1092+
...> g = Graph.split_labelled_edge(g, :a, :c, :b, :first_label)
1093+
...> Graph.edges(g)
1094+
[%Graph.Edge{v1: :a, v2: :b, label: :first_label, weight: 2}, %Graph.Edge{v1: :a, v2: :c, label: :second_label, weight: 2}, %Graph.Edge{v1: :b, v2: :c, label: :first_label, weight: 2}]
1095+
"""
1096+
def split_labelled_edge(%__MODULE__{type: :undirected} = g, v1, v2, v3, label) do
10761097
if v1 > v2 do
1077-
do_split_edge(g, v2, v1, v3)
1098+
do_split_labelled_edge(g, v2, v1, v3, label)
10781099
else
1079-
do_split_edge(g, v1, v2, v3)
1100+
do_split_labelled_edge(g, v1, v2, v3, label)
10801101
end
10811102
end
10821103

1083-
def split_edge(%__MODULE__{} = g, v1, v2, v3) do
1084-
do_split_edge(g, v1, v2, v3)
1104+
def split_labelled_edge(%__MODULE__{} = g, v1, v2, v3, label) do
1105+
do_split_labelled_edge(g, v1, v2, v3, label)
10851106
end
10861107

1087-
defp do_split_edge(
1088-
%__MODULE__{in_edges: ie, out_edges: oe, edges: em, vertex_identifier: vertex_identifier} =
1108+
defp do_split_labelled_edge(
1109+
%__MODULE__{out_edges: oe, edges: em, vertex_identifier: vertex_identifier} =
10891110
g,
10901111
v1,
10911112
v2,
1092-
v3
1113+
v3,
1114+
label
10931115
) do
10941116
with v1_id <- vertex_identifier.(v1),
10951117
v2_id <- vertex_identifier.(v2),
10961118
{:ok, v1_out} <- Map.fetch(oe, v1_id),
1097-
{:ok, v2_in} <- Map.fetch(ie, v2_id),
10981119
true <- MapSet.member?(v1_out, v2_id),
1099-
meta <- Map.get(em, {v1_id, v2_id}),
1100-
v1_out <- MapSet.delete(v1_out, v2_id),
1101-
v2_in <- MapSet.delete(v2_in, v1_id) do
1102-
g = %__MODULE__{
1103-
g
1104-
| in_edges: Map.put(ie, v2_id, v2_in),
1105-
out_edges: Map.put(oe, v1_id, v1_out)
1106-
}
1107-
1120+
meta <- Map.get(em, {v1_id, v2_id}) do
11081121
g = add_vertex(g, v3)
1109-
1110-
Enum.reduce(meta, g, fn {label, weight}, acc ->
1111-
acc
1112-
|> add_edge(v1, v3, label: label, weight: weight)
1113-
|> add_edge(v3, v2, label: label, weight: weight)
1122+
Enum.reduce(meta, g, fn {edge_label, weight}, acc ->
1123+
if edge_label == label or label == nil do
1124+
acc
1125+
|> add_edge(v1, v3, label: edge_label, weight: weight)
1126+
|> add_edge(v3, v2, label: edge_label, weight: weight)
1127+
|> delete_edge(v1, v2, edge_label)
1128+
else
1129+
acc
1130+
end
11141131
end)
11151132
else
11161133
_ -> {:error, :no_such_edge}

0 commit comments

Comments
 (0)