1: #!/usr/bin/perl 
   2: 
   3: # Hello All!
   4: # This is my first real perl code, all I coded before, were # the examples out of the Llama-Book! (-;
   5: # So PLEASE give me some hint (-;
   6: 
   7: # This little program uses the Dijkstra-Algorith to find the # shortest route through a given graph.
   8: # The graph has to be orientated and weighted(damn, I am not # native so this are maybe are the wrong expressions.
   9: 
  10: # The program in the current state needs the Graph in a 
  11: # Input file for which the user is asked. 
  12: # At the moment the nodes of the graph should be 
  13: # alphabetically sorted with s as the initial point, a
  14: # and z the goal!
  15: 
  16: # A sample Graph-file is provided below...
  17: 
  18: use strict;
  19: 
  20: my (
  21:     $s, $v, $vstar, $graphfile,
  22:     @route, @S, @V, @sortnachdist,
  23:     %distance, %previous
  24:     );
  25: 
  26: # (V are all Nodes, S the ones where a shortest route to is 
  27: # already found, the program finishes when z is in S)
  28: 
  29: sub bowlength
  30: # This sub goes through the graph-file and searches if there # is a connection between the two points. 
  31: # If there isn't any, a large number is used, to prevent the # program from using this route!
  32: {
  33:     my($s,$v)=@_;
  34:     seek(GRAPH,0,0);
  35:     while(<GRAPH>)
  36:     {	
  37: 	return $1 if (/$s:(\d):$v/); 	
  38:     }
  39:     return 99999;
  40: }
  41: 
  42: 
  43: 
  44: sub includes
  45: # This is something I am absolutely unsure about!
  46: # Isn't there any way in Perl to find out if an Array #includes a certain element?? (as default, i mean)
  47: {
  48:     my($a,@b)=@_;
  49:     foreach (@b)
  50:     {
  51: 	return 1 if $_ eq $a;
  52:     }
  53: }
  54: 
  55: sub V_without_S
  56: # For the noed which have to be examined
  57: {
  58:     my @c;   
  59:     foreach (@V)
  60:     {
  61: 	push(@c, $_) unless &includes($_,@S);
  62:     }
  63:     return (@c);
  64: }
  65: 
  66: 
  67: $s="s";
  68: $distance{$s}=0;
  69: push(@S,"s");
  70: 
  71: print "Graph-File:";
  72: chomp($graphfile=<STDIN>);
  73: 
  74: open GRAPH, "< $graphfile" 
  75:     or die "Could not open graph-description: $!"; 
  76: 
  77: seek(GRAPH,0,0);
  78: while(<GRAPH>)
  79: {	
  80:     push(@V, $1) if ((/(\w+):\d+:\w+/)&&((&includes($1,@V)-1)));
  81:     push(@V, $1) if ((/\w+:\d+:(\w+)/)&&((&includes($1,@V)-1)));
  82: }
  83: 
  84: # So, this is juste the Dijkstra Algorithm itself!
  85: # I took a Algorithmic-Description out of a book!
  86: # (Das Geheimnis des kürzesten Weges)
  87: # (its german, and exept the Dijkstra-Algorith-Description 
  88: # absolutely boring!!-we HAD to read it)
  89: 
  90: # Maybe some short lines about the Dijkstra Algorithm..
  91: # It finds the shortest way trough a given graph, by 
  92: # examining local nodes, and going to the node
  93: # which has the lowest value. It is not bound to one route, # and will jump between different routes
  94: # (depending on the graph) until it reaches the goal. 
  95: # But when he reaches it, it is sure that it has the lowest # value! Too prevent loosing the knowledge about 
  96: # the other routes, we need the %previous hash... 
  97: # I hope this helps you understanding better what it does!
  98:   
  99: 
 100: foreach $v (grep {$_ ne $s} (@V))
 101: {
 102:     $distance{$v} = &bowlength($s,$v);
 103:     $previous{$v}=$s;
 104: }
 105: 
 106: while($S[-1] ne "z")
 107: {
 108:     @sortnachdist = sort({$distance{$a}<=>$distance{$b}} (&V_without_S)); 
 109:     $vstar = shift @sortnachdist;
 110:     push(@S,$vstar);
 111:     foreach $v (&V_without_S)
 112:     {
 113: 	if ($distance{$vstar} + &bowlength($vstar,$v) < $distance{$v})
 114: 	{
 115: 	    $distance{$v}=$distance{$vstar}+&bowlength($vstar,$v);
 116: 	    $previous{$v}=$vstar;
 117: 	}
 118:     }    
 119: }
 120: 
 121: push(@route, "z");
 122: $_="z";
 123: until ($_ eq "s")
 124: {
 125:     $_=$previous{$_};
 126:     push(@route,$_);
 127: }
 128: print "The shortest route is:\n";
 129: print join " -> ", reverse @route;
 130: print "\nAnd its length is $distance{z}.\n";
 131: 
 132: # And now a sample graph!
 133: # If you would draw it, you would make the s point.
 134: # Then a line with value 3 to a and one with value 5 to b
 135: # From a a line with value 1 to b .... and so on!
 136: # If you find a graph where the algorithm(or more likely my # code) fails please contact me!
 137: # Oh yes, you should copy this line sinto a plain text-file # and remove the #'s (-;
 138: 
 139: #s:3:a
 140: #s:5:b
 141: #a:1:b
 142: #a:10:c
 143: #a:11:d
 144: #b:3:a
 145: #b:2:c
 146: #b:3:d
 147: #c:2:d
 148: #c:7:e
 149: #c:12:f
 150: #d:15:a
 151: #d:7:b
 152: #d:2:f
 153: #e:11:d
 154: #e:2:z
 155: #f:3:e
 156: #f:2:z

Replies are listed 'Best First'.
Re: Dijkstra-Algorithm
by Discipulus (Canon) on Jun 20, 2019 at 11:15 UTC
    ok this node is a bit aged.. but I ended here looking for Dijkstra and Perl, so as future reference I put my discoveries

    in short: use Graph::Weighted SP_Dijkstra method. There is also Graph::Dijkstra but its matrix of failing test removed it from the competition.

    Paths::Graph must have some serious problem: it eat up a lot of memory and stop working even with small graphs. Here the code I used:

    use strict; use warnings; use Paths::Graph; use Graph::Weighted; use Data::Dump; use Benchmark 'cmpthese'; my $max = $ARGV[0] || 4; my $dest = $max.'_'.$max; my @aoa = map{ [ map{ int(rand(4))+1 }0..$max ] } 0..$max; my %graph = build_graph(); dd %graph; foreach my $row (0..$#aoa){ foreach my $col( 0..$#{$aoa[$row]} ){ print $aoa[$row][$col]; } print "\n"; } cmpthese( -2, { 'Paths::Graph' => sub { my $obj = Paths::Graph->new(-origin=>"0_0",-destiny=>$dest,-gr +aph=>\%graph); my @paths = $obj->shortest_path(); }, 'Graph::Weighted' => sub { my $g = Graph::Weighted->new(); $g->populate(\%graph); my @pathbis = $g->SP_Dijkstra( "0_0", $dest ); dd @pathbis; }, }); sub build_graph{ my %graph; foreach my $row (0..$#aoa){ foreach my $col( 0..$#{$aoa[$row]} ){ #print $row."_".$col." is current..\n"; map{ $graph{$row."_".$col}{$_->[0].'_'.$_->[1]} = $aoa[$_-> +[0]][$_->[1]] if $_->[0] >= 0 and $_->[0] <= $#{$aoa[$row]} and $_->[1] >= 0 and $_->[1] <= $#aoa } ([$row-1,$col],[$row+1,$col],[$row,$col-1],[$row,$col+1] +); } } return %graph; }

    Which with the deafault of a 5x5 grid gives:

    Rate Paths::Graph Graph::Weighted Paths::Graph 2.46/s -- -97% Graph::Weighted 92.2/s 3646% --

    while with a bigger grids, commenting out Paths::Graph subs who stuck the program;

    perl pathsingraph.pl 5 Rate Graph::Weighted Graph::Weighted 60.8/s -- perl pathsingraph.pl 15 Rate Graph::Weighted Graph::Weighted 8.60/s -- perl pathsingraph.pl 29 Rate Graph::Weighted Graph::Weighted 2.29/s --

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Dijkstra-Algorithm
by cristian (Hermit) on Sep 28, 2004 at 15:58 UTC
    CPAN Paths::Graph