Task: Floyd-Warshall algorithm




Go: package main
 
import (
  "fmt"
  "strconv"
)
 


type Graph interface {
  Vertices() []Vertex
  Neighbors(v Vertex) []Vertex
  Weight(u, v Vertex) int
}
 

type Vertex int
 

type ig struct {
  vert  []Vertex
  edges map[Vertex]map[Vertex]int
}
 
func (g ig) edge(u, v Vertex, w int) {
  if _, ok := g.edges[u]; !ok {
    g.edges[u] = make(map[Vertex]int)
  }
  g.edges[u][v] = w
}
func (g ig) Vertices() []Vertex { return g.vert }
func (g ig) Neighbors(v Vertex) (vs []Vertex) {
  for k := range g.edges[v] {
    vs = append(vs, k)
  }
  return vs
}
func (g ig) Weight(u, v Vertex) int { return g.edges[u][v] }
func (g ig) path(vv []Vertex) (s string) {
  if len(vv) == 0 {
    return ""
  }
  s = strconv.Itoa(int(vv[0]))
  for _, v := range vv[1:] {
    s += " -> " + strconv.Itoa(int(v))
  }
  return s
}
 
const Infinity = int(^uint(0) >> 1)
 
func FloydWarshall(g Graph) (dist map[Vertex]map[Vertex]int, next map[Vertex]map[Vertex]*Vertex) {
  vert := g.Vertices()
  dist = make(map[Vertex]map[Vertex]int)
  next = make(map[Vertex]map[Vertex]*Vertex)
  for _, u := range vert {
    dist[u] = make(map[Vertex]int)
    next[u] = make(map[Vertex]*Vertex)
    for _, v := range vert {
      dist[u][v] = Infinity
    }
    dist[u][u] = 0
    for _, v := range g.Neighbors(u) {
      v := v
      dist[u][v] = g.Weight(u, v)
      next[u][v] = &v
    }
  }
  for _, k := range vert {
    for _, i := range vert {
      for _, j := range vert {
        if dist[i][k] < Infinity && dist[k][j] < Infinity {
          if dist[i][j] > dist[i][k]+dist[k][j] {
            dist[i][j] = dist[i][k] + dist[k][j]
            next[i][j] = next[i][k]
          }
        }
      }
    }
  }
  return dist, next
}
 
func Path(u, v Vertex, next map[Vertex]map[Vertex]*Vertex) (path []Vertex) {
  if next[u][v] == nil {
    return
  }
  path = []Vertex{u}
  for u != v {
    u = *next[u][v]
    path = append(path, u)
  }
  return path
}
 
func main() {
  g := ig{[]Vertex{1, 2, 3, 4}, make(map[Vertex]map[Vertex]int)}
  g.edge(1, 3, -2)
  g.edge(3, 4, 2)
  g.edge(4, 2, -1)
  g.edge(2, 1, 4)
  g.edge(2, 3, 3)
 
  dist, next := FloydWarshall(g)
  fmt.Println("pair\tdist\tpath")
  for u, m := range dist {
    for v, d := range m {
      if u != v {
        fmt.Printf("%d -> %d\t%3d\t%s\n", u, v, d, g.path(Path(u, v, next)))
      }
    }
  }
}








Ada: 





with Ada.Containers.Vectors;
with Ada.Text_IO; use Ada.Text_IO;
with Interfaces;  use Interfaces;

with Ada.Numerics.Generic_Elementary_Functions;

procedure floyd_warshall_task
is
  Floyd_Warshall_Exception : exception;

  
  subtype FloatPt is IEEE_Float_32;
  package FloatPt_Elementary_Functions is new Ada.Numerics
   .Generic_Elementary_Functions
   (FloatPt);
  use FloatPt_Elementary_Functions;

  
  
  
  
  ENORMOUS_FloatPt : constant FloatPt :=
   (FloatPt (1.0) / FloatPt (1.0e-37))**1.0e37;

  
  
  
  
  

  type edge is record
    u      : Positive;
    weight : FloatPt;
    v      : Positive;
  end record;

  package Edge_Vectors is new Ada.Containers.Vectors
   (Index_Type => Positive, Element_Type => edge);
  use Edge_Vectors;
  subtype edge_vector is Edge_Vectors.Vector;

  
  
  

  type distance_array is
   array (Positive range <>, Positive range <>) of FloatPt;

  type next_vertex_array is
   array (Positive range <>, Positive range <>) of Natural;
  Nil_Vertex : constant Natural := 0;

  function find_max_vertex      
   (edges : in edge_vector)
    return Positive
  is
    max_vertex : Positive;
  begin
    if Is_Empty (edges) then
      raise Floyd_Warshall_Exception with "no edges";
    end if;
    max_vertex := 1;
    for i in edges.First_Index .. edges.Last_Index loop
      max_vertex := Positive'Max (max_vertex, edges.Element (i).u);
      max_vertex := Positive'Max (max_vertex, edges.Element (i).v);
    end loop;
    return max_vertex;
  end find_max_vertex;

  procedure floyd_warshall      
   (edges       : in     edge_vector;
    max_vertex  : in     Positive;
    distance    :    out distance_array;
    next_vertex :    out next_vertex_array)
  is
    u, v     : Positive;
    dist_ikj : FloatPt;
  begin

    

    for i in 1 .. max_vertex loop
      for j in 1 .. max_vertex loop
        distance (i, j)    := ENORMOUS_FloatPt;
        next_vertex (i, j) := Nil_Vertex;
      end loop;
    end loop;
    for i in edges.First_Index .. edges.Last_Index loop
      u                  := edges.Element (i).u;
      v                  := edges.Element (i).v;
      distance (u, v)    := edges.Element (i).weight;
      next_vertex (u, v) := v;
    end loop;
    for i in 1 .. max_vertex loop
      distance (i, i) :=
       FloatPt (0.0);           
      next_vertex (i, i) := i;
    end loop;

    

    for k in 1 .. max_vertex loop
      for i in 1 .. max_vertex loop
        for j in 1 .. max_vertex loop
          dist_ikj := distance (i, k) + distance (k, j);
          if dist_ikj < distance (i, j) then
            distance (i, j)    := dist_ikj;
            next_vertex (i, j) := next_vertex (i, k);
          end if;
        end loop;
      end loop;
    end loop;

  end floyd_warshall;

  
  
  

  procedure put_path
   (next_vertex : in next_vertex_array;
    u, v        : in Positive)
  is
    i : Positive;
  begin
    if next_vertex (u, v) /= Nil_Vertex then
      i := u;
      Put (Positive'Image (i));
      while i /= v loop
        Put (" ->");
        i := next_vertex (i, v);
        Put (Positive'Image (i));
      end loop;
    end if;
  end put_path;

  example_graph : edge_vector;
  max_vertex    : Positive;

begin
  Append (example_graph, (u => 1, weight => FloatPt (-2.0), v => 3));
  Append (example_graph, (u => 3, weight => FloatPt (+2.0), v => 4));
  Append (example_graph, (u => 4, weight => FloatPt (-1.0), v => 2));
  Append (example_graph, (u => 2, weight => FloatPt (+4.0), v => 1));
  Append (example_graph, (u => 2, weight => FloatPt (+3.0), v => 3));

  max_vertex := find_max_vertex (example_graph);

  declare

    distance    : distance_array (1 .. max_vertex, 1 .. max_vertex);
    next_vertex : next_vertex_array
     (1 .. max_vertex, 1 .. max_vertex);

  begin

    floyd_warshall (example_graph, max_vertex, distance, next_vertex);

    Put_Line ("  pair       distance        path");
    Put_Line ("
    for u in 1 .. max_vertex loop
      for v in 1 .. max_vertex loop
        if u /= v then
          Put (Positive'Image (u));
          Put (" ->");
          Put (Positive'Image (v));
          Put ("    ");
          Put (FloatPt'Image (distance (u, v)));
          Put ("    ");
          put_path (next_vertex, u, v);
          Put_Line ("");
        end if;
      end loop;
    end loop;

  end;
end floyd_warshall_task;