File Coverage

blib/lib/Paths/Graph.pm
Criterion Covered Total %
statement 55 94 58.5
branch 11 36 30.5
condition 7 21 33.3
subroutine 6 8 75.0
pod 4 7 57.1
total 83 166 50.0


line stmt bran cond sub pod time code
1             package Paths::Graph;
2              
3             @ISA = qw(Exporter);
4             @EXPORT_OK = qw/shortest_path() free_path_event() debug()/;
5              
6             require 5.005_62;
7             our $VERSION = '0.03';
8              
9 1     1   63569 use strict;
  1         2  
  1         2095  
10              
11             # New Object
12             sub new {
13 2     2 0 714 my ($class , %vals) = @_;
14 2         3 my $self;
15 2         17 bless $self = {
16             graph => $vals{-graph},
17             origin => $vals{-origin},
18             destiny => $vals{-destiny},
19             sub => $vals{-sub},
20             } , $class;
21 2         8 return $self;
22             }
23              
24             # Push array of array to analisys the graph's shortest cost.
25             sub push_paths {
26 1     1 0 3 my ($self,@nodes) = @_;
27 1         3 push @{$self->{paths}} , \@nodes;
  1         4  
28             }
29              
30             # Return the result of nodes in recursive path
31             sub get_path_cost {
32 4     4 1 17 my ($self,@nodes) = @_;
33 4 50       17 return unless @nodes;
34 4         7 my $ant_node = shift @nodes;
35 4         5 my $cur_node = shift @nodes;
36 4 50 66     434 return 0 if (!$cur_node) ||
      66        
37             ($ant_node eq $cur_node) ||
38             (!$self->{graph}{$ant_node}{$cur_node});
39 2         11 return $self->{graph}{$ant_node}{$cur_node} + $self->get_path_cost($cur_node,@nodes);
40             }
41              
42             # Famous algorithm to get all possibles paths into the graph.
43             sub shortest_path {
44 1     1 1 6 my ($self,$father) = @_;
45 1 50       5 $father = 'zero' if $father eq '0';
46 1 50       11 my $tmp = $self->{sub} if $self->{sub};
47 1         4 $self->{sub} = \&push_paths;
48 1         5 $self->free_path_event($father);
49 1         2 $self->{sub} = $tmp;
50 1         4 my ($minor_cost,$pass,%paths_minor_cost) = (0,0,());
51 1         2 for my $path (@{$self->{paths}}) {
  1         4  
52 1         2 my $cost = $self->get_path_cost(@{$path});
  1         5  
53 1 50 33     9 if ( ($cost <= $minor_cost) || ($minor_cost == 0) ) {
54 1         2 push @{$paths_minor_cost{$cost}} , $path;
  1         5  
55 1         2 $minor_cost = $cost;
56             }
57 1         4 $pass=1;
58             }
59 1 50       3 return @{$paths_minor_cost{$minor_cost}} if $pass;
  1         5  
60 0 0       0 return [0] unless $pass;
61             }
62              
63             #Execution time for feedback of the graph's paths.
64             sub free_path_event {
65 2     2 1 7 my ($self , $father ) = @_;
66 2 50       8 $father = 'zero' if $father eq '0';
67 2 50       6 $father = $self->{origin} unless $father;
68 2         7 $self->{fathers}{$father}=1;
69 2         3 push @{$self->{path}} , $father;
  2         8  
70 2         2 foreach my $node (keys %{$self->{graph}{$father}}) {
  2         9  
71 2         4 my $pass=0;
72 2 50 33     17 $pass=1 if $node eq $self->{origin} || $node eq $self->{destiny};
73 2 50       6 if ($node eq $self->{destiny}) {
74 2         3 push @{$self->{path}} , $self->{destiny};
  2         5  
75 2         4 $self->{sub}->($self,@{$self->{path}});
  2         9  
76 2         210 pop @{$self->{path}};
  2         5  
77             }
78 2 50 33     23 $self->free_path_event($node) if (!$self->{fathers}{$node}) && (!$pass);
79             }
80 2         7 $self->{fathers}{$father}=0;
81 2         3 pop @{$self->{path}};
  2         13  
82             }
83              
84             #Educational method to undertand the steps to trace the graph.
85             sub debug {
86 0     0 1   my ($self , $father ,$level) = @_;
87 0 0         $father = 'zero' if $father eq '0';
88 0 0         $level = 1 unless $level;
89 0 0         $father = $self->{origin} unless $father;
90 0           $self->debug_msg($level,"Node:[$father] Save node into path hash\n");
91 0           $self->{fathers}{$father}=1;
92 0           push @{$self->{path}} , $father;
  0            
93 0           $self->debug_msg($level,"Node:[$father] Finding path into graph hash\n");
94 0           foreach my $node (keys %{$self->{graph}{$father}}) {
  0            
95 0           my $pass=0;
96 0           $self->debug_msg($level,"_Node:[$node] Checking if is not origin or detiny Node\n");
97 0 0 0       if ($node eq $self->{origin} || $node eq $self->{destiny}) {
98 0           $self->debug_msg($level,"__Node:[$node] Is equal\n");
99 0           $pass=1
100             } else {
101 0           $self->debug_msg($level,"__Node:[$node] Is not equal\n");
102             }
103 0           $self->debug_msg($level,"_Node:[$node] Checking is Node equal destiny Node\n");
104 0 0         if ($node eq $self->{destiny}) {
105 0           $self->debug_msg($level,"__Node:[$node] Is equal\n");
106 0           $self->debug_msg($level,"__Got Current Path :" . join("->",@{$self->{path}}) . "\n") ;
  0            
107 0           push @{$self->{path}} , $self->{destiny};
  0            
108             #$self->{sub}->($self, @{$self->{path}});
109 0           pop @{$self->{path}};
  0            
110             } else {
111 0           $self->debug_msg($level,"__Node:[$node] Is not equal\n");
112             }
113 0           $self->debug_msg($level,"_Node:[$node] Calling method self recurcive\n");
114 0 0 0       $self->debug($node,$level + 1) if (!$self->{fathers}{$node}) && (!$pass);
115             }
116 0           $level--;
117 0           $self->{fathers}{$father}=0;
118 0           my $tmp = pop @{$self->{path}};
  0            
119 0           $self->debug_msg($level,"Node[$father] Exiting Node\n");
120             }
121              
122             # Show messages sended from education method debug
123             sub debug_msg {
124 0     0 0   my ($self, $level , $msg ) = @_;
125 0           print "|_" for 1 .. $level;
126 0           print $msg;
127 0           sleep 1;
128             }
129              
130              
131             1;
132             __END__