@@ -1117,6 +1117,62 @@ defmodule Graph do
11171117 end
11181118 end
11191119
1120+ @ doc """
1121+ Like `split_edge/4`, but requires you to specify the labelled edge to split.
1122+
1123+ ## Example
1124+ 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)
1125+ iex> g = Graph.split_labelled_edge(g, :a, :c, :b, :first_label)
1126+ iex> Graph.edges(g)
1127+ [%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}]
1128+ iex> Graph.split_labelled_edge(g, :a, :c, :b, :unknown_label)
1129+ {:error, :no_such_edge}
1130+ """
1131+ @ spec split_labelled_edge ( t , vertex , vertex , vertex , label ) :: t | { :error , :no_such_edge }
1132+ def split_labelled_edge ( % __MODULE__ { type: :undirected } = g , v1 , v2 , v3 , label ) do
1133+ if v1 > v2 do
1134+ do_split_labelled_edge ( g , v2 , v1 , v3 , label )
1135+ else
1136+ do_split_labelled_edge ( g , v1 , v2 , v3 , label )
1137+ end
1138+ end
1139+
1140+ def split_labelled_edge ( % __MODULE__ { } = g , v1 , v2 , v3 , label ) do
1141+ do_split_labelled_edge ( g , v1 , v2 , v3 , label )
1142+ end
1143+
1144+ defp do_split_labelled_edge (
1145+ % __MODULE__ { out_edges: oe , edges: em , vertex_identifier: vertex_identifier } =
1146+ g ,
1147+ v1 ,
1148+ v2 ,
1149+ v3 ,
1150+ label
1151+ ) do
1152+ with v1_id <- vertex_identifier . ( v1 ) ,
1153+ v2_id <- vertex_identifier . ( v2 ) ,
1154+ { :ok , v1_out } <- Map . fetch ( oe , v1_id ) ,
1155+ true <- MapSet . member? ( v1_out , v2_id ) ,
1156+ meta <- Map . get ( em , { v1_id , v2_id } ) ,
1157+ true <- Enum . any? ( meta , fn { edge_label , _ } -> edge_label == label end ) do
1158+
1159+ g = add_vertex ( g , v3 )
1160+
1161+ Enum . reduce ( meta , g , fn { edge_label , weight } , acc ->
1162+ if edge_label == label do
1163+ acc
1164+ |> add_edge ( v1 , v3 , label: label , weight: weight )
1165+ |> add_edge ( v3 , v2 , label: label , weight: weight )
1166+ |> delete_edge ( v1 , v2 , label )
1167+ else
1168+ acc
1169+ end
1170+ end )
1171+ else
1172+ _ -> { :error , :no_such_edge }
1173+ end
1174+ end
1175+
11201176 @ doc """
11211177 Given two vertices, this function updates the metadata (weight/label) for the unlabelled
11221178 edge between those two vertices. If no unlabelled edge exists between them, an error
0 commit comments