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

Howdy,

I am trying to implement a program that is given a network map. From this map I have to trace the path from a user's workstation to a server.

Can anyone point me in the right direction on where to start with this project? The Network map implements the connections as a many-to-many relationship table in a database so I should be able to coerce it any data structure that I want.

Update: Changed the Title

Replies are listed 'Best First'.
Re: Finding a Path
by Thelonius (Priest) on Jan 24, 2007 at 14:27 UTC
    There's a Graph module on CPAN. I haven't used it, but it looks like it's depth-first traversal would do for you.

    Of course there's not usually just one path from a user's workstation to a server and the actual path depends on the state of each router's tables as the packet passes through them. But often--usually--the shortest path (in terms of # of edges or nodes) is the one taken.

      I have taken a look at Graph before. The problem I have is that I cannot find any tutorials on how to use it. Most of what I seen in the way of examples, the programmer refers to everything in a way that imply you know what he is talking about.

      If you could point me at a tutorial for Graph I would certainly appreciate it.

        The tutorial for the Graph module is Mastering Algorithms with Perl by Jon Orwant, Jarkko Hietaniemi, and John Macdonald. I enjoyed this book very much and I use it as a reference for the Graph modules, which I use a lot.

        It should work perfectly the first time! - toma
Re: Finding a Path
by Ieronim (Friar) on Jan 24, 2007 at 15:19 UTC
    Some examples of very optimized pathfinding can be found in the node A Better Word Morph Builder. I think that the general idea for solving your problem is giving each machine an unique number (which is already done if the network map is implemented as you described), buiding a datastructure like
    %network_map = ( 12567 => # the machine id [335, 456, 338], # the id's of machines it is directly connected to 335 => [12657, 558, 667, 333] # etc )
    and browsing this datastructure with some tree search algorithm. I myself prefer bidirectional search, the working example is given e.q. in this node, but i think that your network is small enough for using the breadth-first search without any significant performance loss.

    Sorry for my English :)


         s;;Just-me-not-h-Ni-m-P-Ni-lm-I-ar-O-Ni;;tr?IerONim-?HAcker ?d;print
Re: Finding a Path
by kyle (Abbot) on Jan 24, 2007 at 14:36 UTC

    This is completely untested:

    # Call as path( $workstation, $server ) sub path { my ( $workstation, $server, @start ) = @_; # initial invocation; make the ws the whole of the path if ( !@start ) { return path( $workstation, $server, $workstation ); } my $last_hop = $start[ -1 ]; # found the server; we're done! if ( $last_hop eq $server ) { return @start; } # for every possible next hop, NEXT_HOP: foreach my $next_hop ( get_next_hops( $last_hop ) ) { # if it's already in our path somewhere, skip it. foreach my $previous_hop ( @start ) { next NEXT_HOP if ( $previous_hop eq $next_hop ); } # look for a path with this as the next hop my @out = path( $workstation, $server, @start, $next_hop ); # if a path was found, return it return @out if @out; } # dead end return (); }

    There's probably a module to do this better, but I don't know what it is. The above may not be as efficient as an iterative version could be. It makes no attempt to find the shortest path. get_next_hops is left to you (it has to return a list).

Re: Finding a Path
by logie17 (Friar) on Jan 24, 2007 at 16:01 UTC
    You might check out Net::Traceroute .
    s;;5776?12321=10609$d=9409:12100$xx;;s;(\d*);push @_,$1;eg;map{print chr(sqrt($_))."\n"} @_;
Re: Develop a Tree
by Ace128 (Hermit) on Jan 29, 2007 at 02:49 UTC
    Something like this may help?
    package Tree; sub new { my $class = shift; my $self = { 'name' => $name, 'root' => undef, }; return bless $self, $class; } sub addParent { my $self = shift; my $parent = shift; $self->{'parent'} = $parent; } sub getParent { my $self = shift; return $self->{'parent'}; } sub setInherits { my $self = shift; my $inherits = shift; $self->{'inherits'} = $inherits; } sub getInherits { my $self = shift; return $self->{'inherits'}; } sub getRoot { my $self = shift; return $self->{"root"} if (exists $self->{"root"}); if (defined $self->{"parent"}) { $self->{"root"} = $self->{"parent"}->getRoot(); } else { $self->{"root"} = $self; } return $self->{"root"}; } return "Tree";
    And you can create several "Tree"s as Nodes, doing a tree.