Floyd-Warshall algorithm: Difference between revisions
Content added Content deleted
Thundergnat (talk | contribs) (Rename Perl 6 -> Raku, alphabetize, minor clean-up) |
(Add source for Rust) |
||
Line 174: | Line 174: | ||
typedef struct{ |
typedef struct{ |
||
int sourceVertex, destVertex; |
|||
int edgeWeight; |
|||
}edge; |
}edge; |
||
typedef struct{ |
typedef struct{ |
||
int vertices, edges; |
|||
edge* edgeMatrix; |
|||
}graph; |
}graph; |
||
graph loadGraph(char* fileName){ |
graph loadGraph(char* fileName){ |
||
FILE* fp = fopen(fileName,"r"); |
|||
graph G; |
|||
int i; |
|||
fscanf(fp,"%d%d",&G.vertices,&G.edges); |
|||
G.edgeMatrix = (edge*)malloc(G.edges*sizeof(edge)); |
|||
for(i=0;i<G.edges;i++) |
|||
fscanf(fp,"%d%d%d",&G.edgeMatrix[i].sourceVertex,&G.edgeMatrix[i].destVertex,&G.edgeMatrix[i].edgeWeight); |
|||
fclose(fp); |
|||
return G; |
|||
} |
} |
||
void floydWarshall(graph g){ |
void floydWarshall(graph g){ |
||
int processWeights[g.vertices][g.vertices], processedVertices[g.vertices][g.vertices]; |
|||
int i,j,k; |
|||
for(i=0;i<g.vertices;i++) |
|||
for(j=0;j<g.vertices;j++){ |
|||
processWeights[i][j] = SHRT_MAX; |
|||
processedVertices[i][j] = (i!=j)?j+1:0; |
|||
} |
|||
} |
|||
for(i=0;i<g.edges;i++) |
|||
processWeights[g.edgeMatrix[i].sourceVertex-1][g.edgeMatrix[i].destVertex-1] = g.edgeMatrix[i].edgeWeight; |
|||
for(i=0;i<g.vertices;i++) |
|||
for(j=0;j<g.vertices;j++) |
|||
for(k=0;k<g.vertices;k++){ |
|||
if(processWeights[j][i] + processWeights[i][k] < processWeights[j][k]){ |
|||
processWeights[j][k] = processWeights[j][i] + processWeights[i][k]; |
|||
processedVertices[j][k] = processedVertices[j][i]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
printf("pair dist path"); |
|||
for(i=0;i<g.vertices;i++) |
|||
for(j=0;j<g.vertices;j++){ |
|||
if(i!=j){ |
|||
printf("\n%d -> %d %3d %5d",i+1,j+1,processWeights[i][j],i+1); |
|||
k = i+1; |
|||
do{ |
|||
do{ |
|||
k = processedVertices[k-1][j]; |
|||
printf("->%d",k); |
|||
}while(k!=j+1); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
} |
||
int main(int argC,char* argV[]){ |
int main(int argC,char* argV[]){ |
||
if(argC!=2) |
|||
printf("Usage : %s <file containing graph data>"); |
|||
else |
|||
floydWarshall(loadGraph(argV[1])); |
|||
return 0; |
|||
} |
} |
||
</lang> |
</lang> |
||
Line 529: | Line 529: | ||
(define (floyd-with-path n dist next (d 0)) |
(define (floyd-with-path n dist next (d 0)) |
||
(for* ((k n) (i n) (j n)) |
|||
#:break (< (array-ref dist j j) 0) => 'negative-cycle |
|||
(set! d (+ (array-ref dist i k) (array-ref dist k j))) |
|||
(when (< d (array-ref dist i j)) |
|||
(array-set! dist i j d) |
|||
(array-set! next i j (array-ref next i k))))) |
|||
;; utilities |
;; utilities |
||
Line 541: | Line 541: | ||
(define (init-edges n dist next) |
(define (init-edges n dist next) |
||
(for* ((i n) (j n)) |
(for* ((i n) (j n)) |
||
(array-set! dist i i 0) |
|||
(array-set! next i j null) |
|||
#:continue (= j i) |
|||
(array-set! dist i j Infinity) |
|||
#:continue (< (random) 0.3) |
|||
(array-set! dist i j (1+ (random 100))) |
|||
(array-set! next i j j))) |
|||
;; show path from u to v |
;; show path from u to v |
||
(define (path u v) |
(define (path u v) |
||
(cond |
|||
((= u v) (list u)) |
|||
((null? (array-ref next u v)) null) |
|||
(else (cons u (path (array-ref next u v) v))))) |
|||
(define( mdist u v) ;; show computed distance |
(define( mdist u v) ;; show computed distance |
||
(array-ref dist u v)) |
|||
(define (task) |
(define (task) |
||
(init-edges n dist next) |
|||
(array-print dist) ;; show init distances |
|||
(floyd-with-path n dist next)) |
|||
</lang> |
</lang> |
||
{{out}} |
{{out}} |
||
Line 904: | Line 904: | ||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
pair |
pair dist path |
||
1 -> 2 |
1 -> 2 -1 1 -> 3 -> 4 -> 2 |
||
1 -> 3 |
1 -> 3 -2 1 -> 3 |
||
1 -> 4 |
1 -> 4 0 1 -> 3 -> 4 |
||
2 -> 1 |
2 -> 1 4 2 -> 1 |
||
2 -> 3 |
2 -> 3 2 2 -> 1 -> 3 |
||
2 -> 4 |
2 -> 4 4 2 -> 1 -> 3 -> 4 |
||
3 -> 1 |
3 -> 1 5 3 -> 4 -> 2 -> 1 |
||
3 -> 2 |
3 -> 2 1 3 -> 4 -> 2 |
||
3 -> 4 |
3 -> 4 2 3 -> 4 |
||
4 -> 1 |
4 -> 1 3 4 -> 2 -> 1 |
||
4 -> 2 |
4 -> 2 -1 4 -> 2 |
||
4 -> 3 |
4 -> 3 1 4 -> 2 -> 1 -> 3 |
||
</pre> |
</pre> |
||
Line 1,252: | Line 1,252: | ||
reduce $nodes[] as $u (.; |
reduce $nodes[] as $u (.; |
||
reduce $nodes[] as $v (.; |
reduce $nodes[] as $v (.; |
||
(.[$u][$w] + .[$w][$v]) as $x |
|||
| if .[$u][$v] > $x then .[$u][$v] = $x |
|||
else . end ))) |
|||
; |
; |
||
Line 1,577: | Line 1,577: | ||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
<lang perl6>sub FloydWarshall{ |
<lang perl6>sub FloydWarshall{ |
||
my $edges = shift; |
|||
my (@dist, @seq); |
|||
my $num_vert = 0; |
|||
# insert given dists into dist matrix |
|||
map { |
|||
$dist[$_->[0] - 1][$_->[1] - 1] = $_->[2]; |
|||
$num_vert = $_->[0] if $num_vert < $_->[0]; |
|||
$num_vert = $_->[1] if $num_vert < $_->[1]; |
|||
} @$edges; |
|||
my @vertices = 0..($num_vert - 1); |
|||
# init sequence/"next" table |
|||
for my $i(@vertices){ |
|||
for my $j(@vertices){ |
|||
$seq[$i][$j] = $j if $i != $j; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
# diagonal of dists matrix |
|||
#map {$dist[$_][$_] = 0} @vertices; |
|||
for my $k(@vertices){ |
|||
for my $i(@vertices){ |
|||
next unless defined $dist[$i][$k]; |
|||
for my $j(@vertices){ |
|||
next unless defined $dist[$k][$j]; |
|||
if($i != $j && (!defined($dist[$i][$j]) |
|||
|| $dist[$i][$j] > $dist[$i][$k] + $dist[$k][$j])){ |
|||
$dist[$i][$j] = $dist[$i][$k] + $dist[$k][$j]; |
|||
$seq[$i][$j] = $seq[$i][$k]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
# print table |
|||
print "pair dist path\n"; |
|||
for my $i(@vertices){ |
|||
for my $j(@vertices){ |
|||
next if $i == $j; |
|||
my @path = ($i + 1); |
|||
while($seq[$path[-1] - 1][$j] != $j){ |
|||
push @path, $seq[$path[-1] - 1][$j] + 1; |
|||
} |
|||
} |
|||
push @path, $j + 1; |
|||
printf "%d -> %d %4d %s\n", |
|||
$path[0], $path[-1], $dist[$i][$j], join(' -> ', @path); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
} |
||
Line 2,089: | Line 2,089: | ||
4 -> 2 -1 4 -> 2 |
4 -> 2 -1 4 -> 2 |
||
4 -> 3 1 4 -> 2 -> 1 -> 3 |
4 -> 3 1 4 -> 2 -> 1 -> 3 |
||
</pre> |
|||
=={{header|Rust}}== |
|||
The lack of built-in support for multi-dimensional arrays makes the task in Rust |
|||
a bit lengthy (without additional crates). The used graph representation leverages |
|||
Rust's generics, so that it works with any type that defines addition and ordering |
|||
and it requires no special value for infinity. |
|||
<lang rust>pub type Edge = (usize, usize); |
|||
#[derive(Clone, Debug, PartialEq, Eq, Hash)] |
|||
pub struct Graph<T> { |
|||
size: usize, |
|||
edges: Vec<Option<T>>, |
|||
} |
|||
impl<T> Graph<T> { |
|||
pub fn new(size: usize) -> Self { |
|||
Self { |
|||
size, |
|||
edges: std::iter::repeat_with(|| None).take(size * size).collect(), |
|||
} |
|||
} |
|||
pub fn new_with(size: usize, f: impl FnMut(Edge) -> Option<T>) -> Self { |
|||
let edges = (0..size) |
|||
.flat_map(|i| (0..size).map(move |j| (i, j))) |
|||
.map(f) |
|||
.collect(); |
|||
Self { size, edges } |
|||
} |
|||
pub fn with_diagonal(mut self, mut f: impl FnMut(usize) -> Option<T>) -> Self { |
|||
self.edges |
|||
.iter_mut() |
|||
.step_by(self.size + 1) |
|||
.enumerate() |
|||
.for_each(move |(vertex, edge)| *edge = f(vertex)); |
|||
self |
|||
} |
|||
pub fn size(&self) -> usize { |
|||
self.size |
|||
} |
|||
pub fn edge(&self, edge: Edge) -> &Option<T> { |
|||
let index = self.edge_index(edge); |
|||
&self.edges[index] |
|||
} |
|||
pub fn edge_mut(&mut self, edge: Edge) -> &mut Option<T> { |
|||
let index = self.edge_index(edge); |
|||
&mut self.edges[index] |
|||
} |
|||
fn edge_index(&self, (row, col): Edge) -> usize { |
|||
assert!(row < self.size && col < self.size); |
|||
row * self.size() + col |
|||
} |
|||
} |
|||
impl<T> std::ops::Index<Edge> for Graph<T> { |
|||
type Output = Option<T>; |
|||
fn index(&self, index: Edge) -> &Self::Output { |
|||
self.edge(index) |
|||
} |
|||
} |
|||
impl<T> std::ops::IndexMut<Edge> for Graph<T> { |
|||
fn index_mut(&mut self, index: Edge) -> &mut Self::Output { |
|||
self.edge_mut(index) |
|||
} |
|||
} |
|||
#[derive(Clone, Debug, PartialEq, Eq)] |
|||
pub struct Paths(Graph<usize>); |
|||
impl Paths { |
|||
pub fn new<T>(graph: &Graph<T>) -> Self { |
|||
Self(Graph::new_with(graph.size(), |(i, j)| { |
|||
graph[(i, j)].as_ref().map(|_| j) |
|||
})) |
|||
} |
|||
pub fn vertices(&self, from: usize, to: usize) -> Path<'_> { |
|||
assert!(from < self.0.size() && to < self.0.size()); |
|||
Path { |
|||
graph: &self.0, |
|||
from: Some(from), |
|||
to, |
|||
} |
|||
} |
|||
fn update(&mut self, from: usize, to: usize, via: usize) { |
|||
self.0[(from, to)] = self.0[(from, via)]; |
|||
} |
|||
} |
|||
#[derive(Clone, Copy, Debug, PartialEq, Eq)] |
|||
pub struct Path<'a> { |
|||
graph: &'a Graph<usize>, |
|||
from: Option<usize>, |
|||
to: usize, |
|||
} |
|||
impl<'a> Iterator for Path<'a> { |
|||
type Item = usize; |
|||
fn next(&mut self) -> Option<Self::Item> { |
|||
self.from.map(|from| { |
|||
let result = from; |
|||
self.from = if result != self.to { |
|||
self.graph[(result, self.to)] |
|||
} else { |
|||
None |
|||
}; |
|||
result |
|||
}) |
|||
} |
|||
} |
|||
pub fn floyd_warshall<W>(mut result: Graph<W>) -> (Graph<W>, Option<Paths>) |
|||
where |
|||
W: Copy + std::ops::Add<W, Output = W> + std::cmp::Ord + Default, |
|||
{ |
|||
let mut without_negative_cycles = true; |
|||
let mut paths = Paths::new(&result); |
|||
let n = result.size(); |
|||
for k in 0..n { |
|||
for i in 0..n { |
|||
for j in 0..n { |
|||
// Negative cycle detection with T::default as the negative boundary |
|||
if i == j && result[(i, j)].filter(|&it| it < W::default()).is_some() { |
|||
without_negative_cycles = false; |
|||
continue; |
|||
} |
|||
if let (Some(ik_weight), Some(kj_weight)) = (result[(i, k)], result[(k, j)]) { |
|||
let ij_edge = result.edge_mut((i, j)); |
|||
let ij_weight = ik_weight + kj_weight; |
|||
if ij_edge.is_none() { |
|||
*ij_edge = Some(ij_weight); |
|||
paths.update(i, j, k); |
|||
} else { |
|||
ij_edge |
|||
.as_mut() |
|||
.filter(|it| ij_weight < **it) |
|||
.map_or((), |it| { |
|||
*it = ij_weight; |
|||
paths.update(i, j, k); |
|||
}); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
(result, Some(paths).filter(|_| without_negative_cycles)) // No paths for negative cycles |
|||
} |
|||
fn format_path<T: ToString>(path: impl Iterator<Item = T>) -> String { |
|||
path.fold(String::new(), |mut acc, x| { |
|||
if !acc.is_empty() { |
|||
acc.push_str(" -> "); |
|||
} |
|||
acc.push_str(&x.to_string()); |
|||
acc |
|||
}) |
|||
} |
|||
fn print_results<W, V>(weights: &Graph<W>, paths: Option<&Paths>, vertex: impl Fn(usize) -> V) |
|||
where |
|||
W: std::fmt::Display + Default + Eq, |
|||
V: std::fmt::Display, |
|||
{ |
|||
let n = weights.size(); |
|||
for from in 0..n { |
|||
for to in 0..n { |
|||
if let Some(weight) = &weights[(from, to)] { |
|||
// Skip trivial information (i.e., default weight on the diagonal) |
|||
if from == to && *weight == W::default() { |
|||
continue; |
|||
} |
|||
println!( |
|||
"{} -> {}: {} \t{}", |
|||
vertex(from), |
|||
vertex(to), |
|||
weight, |
|||
format_path(paths.iter().flat_map(|p| p.vertices(from, to)).map(&vertex)) |
|||
); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
fn main() { |
|||
let graph = { |
|||
let mut g = Graph::new(4).with_diagonal(|_| Some(0)); |
|||
g[(0, 2)] = Some(-2); |
|||
g[(1, 0)] = Some(4); |
|||
g[(1, 2)] = Some(3); |
|||
g[(2, 3)] = Some(2); |
|||
g[(3, 1)] = Some(-1); |
|||
g |
|||
}; |
|||
let (weights, paths) = floyd_warshall(graph); |
|||
// Fixup the vertex name (as we use zero-based indices) |
|||
print_results(&weights, paths.as_ref(), |index| index + 1); |
|||
} |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
1 -> 2: -1 1 -> 3 -> 4 -> 2 |
|||
1 -> 3: -2 1 -> 3 |
|||
1 -> 4: 0 1 -> 3 -> 4 |
|||
2 -> 1: 4 2 -> 1 |
|||
2 -> 3: 2 2 -> 1 -> 3 |
|||
2 -> 4: 4 2 -> 1 -> 3 -> 4 |
|||
3 -> 1: 5 3 -> 4 -> 2 -> 1 |
|||
3 -> 2: 1 3 -> 4 -> 2 |
|||
3 -> 4: 2 3 -> 4 |
|||
4 -> 1: 3 4 -> 2 -> 1 |
|||
4 -> 2: -1 4 -> 2 |
|||
4 -> 3: 1 4 -> 2 -> 1 -> 3 |
|||
</pre> |
</pre> |
||
Line 2,159: | Line 2,396: | ||
{{trans|Ruby}} |
{{trans|Ruby}} |
||
<lang ruby>func floyd_warshall(n, edge) { |
<lang ruby>func floyd_warshall(n, edge) { |
||
var dist = n.of {|i| n.of { |j| i == j |
var dist = n.of {|i| n.of { |j| i == j ? 0 : Inf }} |
||
var nxt = n.of { n.of(nil) } |
var nxt = n.of { n.of(nil) } |
||
for u,v,w in edge { |
for u,v,w in edge { |
||
Line 2,172: | Line 2,409: | ||
} |
} |
||
} |
} |
||
var summary = "pair dist path\n" |
var summary = "pair dist path\n" |
||
for i,j (^n ~X ^n) { |
for i,j (^n ~X ^n) { |
||
Line 2,178: | Line 2,415: | ||
var u = i |
var u = i |
||
var path = [u] |
var path = [u] |
||
while (u |
while (u != j) { |
||
path << (u = nxt[u][j]) |
path << (u = nxt[u][j]) |
||
} |
} |
||
path.map!{|u| u+1 }.join!(" -> ") |
path.map!{|u| u+1 }.join!(" -> ") |
||
summary += ("%d -> |
summary += ("%d -> %d %4d %s\n" % (i+1, j+1, dist[i][j], path)) |
||
} |
} |
||
Line 2,337: | Line 2,574: | ||
a,b,c:=dist[i][j],dist[i][k],dist[k][j]; |
a,b,c:=dist[i][j],dist[i][k],dist[k][j]; |
||
if( (a!=Void and b!=Void and c!=Void and a>b+c) or // Inf math |
if( (a!=Void and b!=Void and c!=Void and a>b+c) or // Inf math |
||
(a==Void and b!=Void and c!=Void) ){ |
|||
dist[i][j] = b+c; |
|||
next[i][j] = next[i][k]; |
|||
} |
} |
||
} |
} |
||
Line 2,354: | Line 2,591: | ||
<lang zkl>const V=4; |
<lang zkl>const V=4; |
||
dist:=V.pump(List,V.pump(List,Void.copy).copy); // VxV matrix of Void |
dist:=V.pump(List,V.pump(List,Void.copy).copy); // VxV matrix of Void |
||
foreach i in (V){ dist[i][i] = 0 } |
foreach i in (V){ dist[i][i] = 0 } // zero vertexes |
||
/* Graph from the Wikipedia: |
/* Graph from the Wikipedia: |
||
Line 2,368: | Line 2,605: | ||
dist,next:=FloydWarshallWithPathReconstruction(dist); |
dist,next:=FloydWarshallWithPathReconstruction(dist); |
||
println("Shortest distance array:"); printM(dist); |
println("Shortest distance array:"); printM(dist); |
||
println("\nPath array:"); |
println("\nPath array:"); printM(next); |
||
println("\nAll paths:"); |
println("\nAll paths:"); |
||
foreach u,v in (V,V){ |
foreach u,v in (V,V){ |