@@ -1117,6 +1117,62 @@ defmodule Graph do
1117
1117
end
1118
1118
end
1119
1119
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
+
1120
1176
@ doc """
1121
1177
Given two vertices, this function updates the metadata (weight/label) for the unlabelled
1122
1178
edge between those two vertices. If no unlabelled edge exists between them, an error
0 commit comments