diff --git a/doc/attr.xml b/doc/attr.xml index 9c880fdab..f2862fc47 100644 --- a/doc/attr.xml +++ b/doc/attr.xml @@ -902,6 +902,37 @@ gap> DigraphShortestDistances(D); <#/GAPDoc> +<#GAPDoc Label="UnweightedBellmanFord"> + + + A list of integers or fail. + + If digraph is a digraph with n vertices, then this + function returns a list with two sublists of n entries, where each entry is + either a non-negative integer, or fail.

+ + If there is a directed path from source to vertex i, then for each i-th entry the first sublist contains + the length of the shortest directed path to that i-th vertex and second sublist contains the vertex preceding that i-th + vertex. If no such directed path exists, then the value of i is fail. + We use the convention that the distance from every vertex to + itself is 0 for all vertices i. +

+ + D := Digraph([[1, 2], [3], [1, 2], [4]]); + +gap> UnweightedBellmanFord(D, 2) +[ [ 2, 0, 1, fail ], [ 3, fail, 2, fail ] ] +gap> D := CycleDigraph(IsMutableDigraph, 3); + +gap> UnweightedBellmanFord(D, 3); +[ [ 1, 2, 0 ], [ 3, 1, fail ] ] +]]> + + +<#/GAPDoc> + + <#GAPDoc Label="DigraphDiameter"> diff --git a/gap/attr.gd b/gap/attr.gd index bf22fd30d..b67221290 100644 --- a/gap/attr.gd +++ b/gap/attr.gd @@ -45,6 +45,7 @@ DeclareAttribute("DigraphDegeneracy", IsDigraph); DeclareAttribute("DigraphDegeneracyOrdering", IsDigraph); DeclareAttribute("DIGRAPHS_Degeneracy", IsDigraph); DeclareAttribute("DigraphShortestDistances", IsDigraph); +DeclareOperation("UnweightedBellmanFord", [IsDigraph, IsPosInt]); DeclareAttribute("DigraphDiameter", IsDigraph); DeclareAttribute("DigraphGirth", IsDigraph); DeclareAttribute("DigraphOddGirth", IsDigraph); diff --git a/gap/attr.gi b/gap/attr.gi index 2c721ee9d..045e842b8 100644 --- a/gap/attr.gi +++ b/gap/attr.gi @@ -700,6 +700,52 @@ end); # returns the vertices (i.e. numbers) of ordered so that there are no # edges from to for all greater than . +InstallMethod(UnweightedBellmanFord, "for a digraph by out-neighbours", +[IsDigraph, IsPosInt], +function(digraph, source) + local distance, n, predecessor, i, inf, u, v, edge, w; + n := DigraphNrVertices(digraph); + # wouldn't work for weighted digraphs + inf := n + 1; + distance := List([1 .. n], x -> 0); + predecessor := List([1 .. n], x -> 0); + for i in DigraphVertices(digraph) do + distance[i] := inf; + predecessor[i] := 0; + od; + distance[source] := 0; + for i in [1 .. n - 1] do + for edge in DigraphEdges(digraph) do + u := edge[1]; + v := edge[2]; + # only works for unweighted graphs, w needs to be changed into a variable + w := 1; + if distance[u] + w < distance[v] then + distance[v] := distance[u] + w; + predecessor[v] := u; + fi; + od; + od; + for edge in DigraphEdges(digraph) do + u := edge[1]; + v := edge[2]; + # only works for unweighted graphs, w needs to be changed into a variable + w := 1; + if distance[u] + w < distance[v] then + Print("Graph contains a negative-weight cycle"); + fi; + od; + for i in DigraphVertices(digraph) do + if distance[i] >= inf then + distance[i] := fail; + fi; + if predecessor[i] = 0 then + predecessor[i] := fail; + fi; + od; + return [distance, predecessor]; +end); + InstallMethod(DigraphTopologicalSort, "for a digraph by out-neighbours", [IsDigraphByOutNeighboursRep], D -> DIGRAPH_TOPO_SORT(OutNeighbours(D))); diff --git a/tst/standard/attr.tst b/tst/standard/attr.tst index ba1ced5d9..919543dfd 100644 --- a/tst/standard/attr.tst +++ b/tst/standard/attr.tst @@ -486,6 +486,24 @@ gap> DIGRAPH_ConnectivityDataForVertex(gr, 2);; gap> DigraphShortestDistances(gr); [ [ 0, 1, 1 ], [ 1, 0, 1 ], [ 1, 1, 0 ] ] +# UnweightedBellmanFord +gap> gr := Digraph([[1, 2], [3], [1, 2], [4]]); + +gap> UnweightedBellmanFord(gr, 2); +[ [ 2, 0, 1, fail ], [ 3, fail, 2, fail ] ] +gap> gr := CycleDigraph(IsMutableDigraph, 3); + +gap> UnweightedBellmanFord(gr, 3); +[ [ 1, 2, 0 ], [ 3, 1, fail ] ] +gap> gr := Digraph([[], []]); + +gap> UnweightedBellmanFord(gr, 2); +[ [ fail, 0 ], [ fail, fail ] ] +gap> gr := Digraph([[1], [2], [3], [4]]); + +gap> UnweightedBellmanFord(gr, 2); +[ [ fail, 0, fail, fail ], [ fail, fail, fail, fail ] ] + # OutNeighbours and InNeighbours gap> gr := Digraph(rec(DigraphNrVertices := 10, > DigraphSource := [1, 1, 5, 5, 7, 10],