Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I want to use algorithm::graphs::transitive closure qw /floyd_warshall/; to find paths in an adjacency graph. Can anyone tell me how I get the number of nodes that are needed in a path from 1 to 2? choco

Replies are listed 'Best First'.
Re: floyd warshall trans closure
by Abigail-II (Bishop) on Oct 21, 2003 at 10:43 UTC
    I don't think the Floyd Warshall algorithm gives you a quick answer to this problem, and I'm pretty sure the implementation on Algorithm::Graphs::Transitive_Closure isn't going to give you that answer.

    The algorithm to use to find the (shortest) path from one node in a graph to another node is Dijkstra's algorithm, which is linear in the number of edges in the graph. Floyd Warshall is cubic in the number of vertices, and solves the connectivity problem for all pairs of nodes at once.

    I presume the Graph module on CPAN has a method for applying Dijkstra's algorithm.

    Abigail

      Thank you Abigail and hello other monks, I think I will try to go from scratch. I want to build a matrix using a hash of hashes so that I can delete items easily afterwards without the matrix getting illformed. I find it hard to use the packages, because they require a certain input format. But I'm wondering now... can I do multiplication with a matrix that is built as a hash of hashes? -Choco
        I want to build a matrix using a hash of hashes so that I can delete items easily afterwards without the matrix getting illformed. I find it hard to use the packages, because they require a certain input format.
        I find this remark curious as the floyd_warshall sub can take a reference to a hash of hashes as argument.
        can I do multiplication with a matrix that is built as a hash of hashes?
        Sure, but you probably have to code it yourself.

        Abigail

Re: floyd warshall trans closure (SOLUTION)
by Abigail-II (Bishop) on Oct 22, 2003 at 00:03 UTC
    #!/usr/bin/perl use strict; use warnings; no warnings qw /syntax/; sub min { my $min; map {$min = $_ if defined ($_) && (!defined ($min) || $_ < $min)} +@_; $min; } sub add { my $sum = 0; map {$sum += $_ // return} @_; # Defined-or! $sum } sub display { my $graph = shift; my $count = @{$graph}; # Print top line. print " |"; printf " %3d" => $_ for 1 .. $count; print "\n"; print "----+", "-" x ($count * 4), "\n"; foreach my $x (1 .. $count) { printf "%3d |", $x; foreach my $y (1 .. $count) { my $val = $graph -> [$x - 1] [$y - 1]; defined ($val) ? printf " %3d" => $val : print " Inf"; } print "\n"; } } # Takes a ref to an array of arrays as argument. $ref -> [$x] [$y] is # the weigth of the edge from $x to $y. This should be 0 if $x == $y, # and undef if there's no edge from $x to $y. Negative weigths are # possible, as long as there are no cycles with a negative length. # The passed datastructure will be *modified*; the resulting array # will contain the lengths of the shortest path - an undefined value # will indicate there's no path. # To find the number of edges that need to be taken, give all edges # a weigth of 1. sub floyd_warshall ($) { my $graph = shift; my $count = @{$graph}; for (my $k = 0; $k < $count; $k ++) { for (my $i = 0; $i < $count; $i ++) { for (my $j = 0; $j < $count; $j ++) { $graph -> [$i] [$j] = min $graph -> [$i] [$j], add $graph -> [$k] [$j], $graph -> [$i] [$k]; } } } $graph; } my $graph1 = [[ 0, undef, undef, undef], [undef, 0, 1, 1], [undef, 1, 0, undef], [ 1, undef, 1, 0]]; my $graph2 = [[ 0, 3, 8, undef, -4], [undef, 0, undef, 1, 7], [undef, 4, 0, undef, undef], [ 2, undef, -5, 0, undef], [undef, undef, undef, 6, 0]]; floyd_warshall $graph1; floyd_warshall $graph2; display $graph1; print "\n"; display $graph2; __END__ | 1 2 3 4 ----+---------------- 1 | 0 Inf Inf Inf 2 | 2 0 1 1 3 | 3 1 0 2 4 | 1 2 1 0 | 1 2 3 4 5 ----+-------------------- 1 | 0 1 -3 2 -4 2 | 3 0 -4 1 -1 3 | 7 4 0 5 3 4 | 2 -1 -5 0 -2 5 | 8 5 1 6 0

    Abigail

      Thank you, this works very well for me. I have subscribed as a perl monk too now - hope I will be able to help others (one day).