| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Graph::Fast; |
|
2
|
|
|
|
|
|
|
|
|
3
|
6
|
|
|
6
|
|
133992
|
use strict; |
|
|
6
|
|
|
|
|
16
|
|
|
|
6
|
|
|
|
|
224
|
|
|
4
|
6
|
|
|
6
|
|
31
|
use warnings; |
|
|
6
|
|
|
|
|
13
|
|
|
|
6
|
|
|
|
|
163
|
|
|
5
|
6
|
|
|
6
|
|
155
|
use 5.010; |
|
|
6
|
|
|
|
|
20
|
|
|
|
6
|
|
|
|
|
353
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = "0.02"; |
|
8
|
|
|
|
|
|
|
|
|
9
|
6
|
|
|
6
|
|
7533
|
use Data::Dumper; |
|
|
6
|
|
|
|
|
69029
|
|
|
|
6
|
|
|
|
|
473
|
|
|
10
|
6
|
|
|
6
|
|
8852
|
use Storable qw(dclone); |
|
|
6
|
|
|
|
|
25379
|
|
|
|
6
|
|
|
|
|
495
|
|
|
11
|
6
|
|
|
6
|
|
55
|
use List::Util qw(min); |
|
|
6
|
|
|
|
|
13
|
|
|
|
6
|
|
|
|
|
700
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
6
|
|
|
6
|
|
5178
|
use Hash::PriorityQueue; |
|
|
6
|
|
|
|
|
3823
|
|
|
|
6
|
|
|
|
|
9984
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub new { |
|
16
|
5
|
|
|
5
|
1
|
89
|
my ($class, %args) = @_; |
|
17
|
5
|
50
|
|
7
|
|
46
|
my $queue_maker = exists($args{queue_maker}) ? $args{queue_maker} : sub { Hash::PriorityQueue->new() }; |
|
|
7
|
|
|
|
|
30
|
|
|
18
|
5
|
|
|
|
|
44
|
return bless({ |
|
19
|
|
|
|
|
|
|
vertices => {}, |
|
20
|
|
|
|
|
|
|
edges => [], |
|
21
|
|
|
|
|
|
|
_queue_maker => $queue_maker, |
|
22
|
|
|
|
|
|
|
}, $class); |
|
23
|
|
|
|
|
|
|
} |
|
24
|
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub count_edges { |
|
26
|
21
|
|
|
21
|
1
|
55
|
my ($self) = @_; |
|
27
|
21
|
|
|
|
|
30
|
return scalar(@{$self->{edges}}); |
|
|
21
|
|
|
|
|
128
|
|
|
28
|
|
|
|
|
|
|
} |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub count_vertices { |
|
31
|
21
|
|
|
21
|
1
|
43
|
my ($self) = @_; |
|
32
|
21
|
|
|
|
|
31
|
return scalar(keys(%{$self->{vertices}})); |
|
|
21
|
|
|
|
|
105
|
|
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub add_vertex { |
|
36
|
15
|
|
|
15
|
1
|
27
|
my ($self, $name) = @_; |
|
37
|
|
|
|
|
|
|
|
|
38
|
15
|
50
|
|
|
|
47
|
if (!exists($self->{vertices}->{$name})) { |
|
39
|
15
|
|
|
|
|
83
|
$self->{vertices}->{$name} = { name => $name, edges_in => {}, edges_out => {} }; |
|
40
|
|
|
|
|
|
|
} |
|
41
|
15
|
|
|
|
|
98
|
return $self->{vertices}->{$name}; |
|
42
|
|
|
|
|
|
|
} |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
sub del_vertex { |
|
45
|
6
|
|
|
6
|
1
|
14
|
my ($self, $name) = @_; |
|
46
|
|
|
|
|
|
|
|
|
47
|
6
|
50
|
|
|
|
28
|
if (exists($self->{vertices}->{$name})) { |
|
48
|
6
|
100
|
|
|
|
10
|
@{$self->{edges}} = grep { $_->{from} ne $name and $_->{to} ne $name } @{$self->{edges}}; |
|
|
6
|
|
|
|
|
20
|
|
|
|
23
|
|
|
|
|
140
|
|
|
|
6
|
|
|
|
|
18
|
|
|
49
|
6
|
|
|
|
|
9
|
foreach my $in_edge (keys %{$self->{vertices}->{$name}->{edges_in}}) { |
|
|
6
|
|
|
|
|
27
|
|
|
50
|
8
|
|
|
|
|
27
|
delete($self->{vertices}->{$in_edge}->{edges_out}->{$name}); |
|
51
|
|
|
|
|
|
|
} |
|
52
|
6
|
|
|
|
|
12
|
foreach my $out_edge (keys %{$self->{vertices}->{$name}->{edges_out}}) { |
|
|
6
|
|
|
|
|
38
|
|
|
53
|
4
|
|
|
|
|
11
|
delete($self->{vertices}->{$out_edge}->{edges_in}->{$name}); |
|
54
|
|
|
|
|
|
|
} |
|
55
|
6
|
|
|
|
|
38
|
delete($self->{vertices}->{$name}); |
|
56
|
|
|
|
|
|
|
} |
|
57
|
|
|
|
|
|
|
} |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
sub dijkstra_worker { |
|
60
|
9
|
|
|
9
|
0
|
15
|
my ($self, $from, $to) = @_; |
|
61
|
|
|
|
|
|
|
|
|
62
|
9
|
|
|
|
|
15
|
my $vert = $self->{vertices}; |
|
63
|
9
|
|
|
|
|
21
|
my $suboptimal = $self->{_queue_maker}->(); |
|
64
|
9
|
|
|
|
|
60
|
$suboptimal->insert($_, $self->{d_suboptimal}->{$_}) foreach (keys(%{$self->{d_suboptimal}})); |
|
|
9
|
|
|
|
|
49
|
|
|
65
|
9
|
|
|
|
|
124
|
$self->{d_dist}->{$_} = -1 foreach (@{$self->{d_unvisited}}); |
|
|
9
|
|
|
|
|
69
|
|
|
66
|
9
|
|
|
|
|
20
|
$self->{d_dist}->{$from} = 0; |
|
67
|
|
|
|
|
|
|
|
|
68
|
9
|
|
|
|
|
10
|
while (1) { |
|
69
|
|
|
|
|
|
|
# find the smallest unvisited node |
|
70
|
31
|
|
100
|
|
|
218
|
my $current = $suboptimal->pop() // last; |
|
71
|
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
# update all neighbors |
|
73
|
22
|
|
|
|
|
455
|
foreach my $edge (values %{$vert->{$current}->{edges_out}}) { |
|
|
22
|
|
|
|
|
67
|
|
|
74
|
19
|
100
|
100
|
|
|
186
|
if (($self->{d_dist}->{$edge->{to}} == -1) || |
|
75
|
|
|
|
|
|
|
($self->{d_dist}->{$edge->{to}} > ($self->{d_dist}->{$current} + $edge->{weight}) )) { |
|
76
|
16
|
|
|
|
|
65
|
$suboptimal->update( |
|
77
|
|
|
|
|
|
|
$edge->{to}, |
|
78
|
|
|
|
|
|
|
$self->{d_dist}->{$edge->{to}} = $self->{d_dist}->{$current} + $edge->{weight} |
|
79
|
|
|
|
|
|
|
); |
|
80
|
|
|
|
|
|
|
} |
|
81
|
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# trace the path from the destination to the start |
|
85
|
9
|
|
|
|
|
54
|
my @path = (); |
|
86
|
9
|
|
|
|
|
12
|
my $current = $to; |
|
87
|
9
|
|
|
|
|
20
|
NODE: while ($current ne $from) { |
|
88
|
11
|
|
|
|
|
12
|
foreach my $edge (values %{$vert->{$current}->{edges_in}}) { |
|
|
11
|
|
|
|
|
32
|
|
|
89
|
14
|
100
|
|
|
|
49
|
if ($self->{d_dist}->{$current} == $self->{d_dist}->{$edge->{from}} + $edge->{weight}) { |
|
90
|
7
|
|
|
|
|
10
|
$current = $edge->{from}; |
|
91
|
7
|
|
|
|
|
9
|
unshift(@path, $edge); |
|
92
|
7
|
|
|
|
|
39
|
next NODE; |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
# getting here means we found no predecessor - there is none. |
|
96
|
|
|
|
|
|
|
# so there's no path. |
|
97
|
4
|
|
|
|
|
36
|
return (); |
|
98
|
|
|
|
|
|
|
} |
|
99
|
|
|
|
|
|
|
|
|
100
|
5
|
|
|
|
|
71
|
return @path; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub dijkstra_first { |
|
104
|
9
|
|
|
9
|
0
|
15
|
my ($self, $from, $to) = @_; |
|
105
|
9
|
|
|
|
|
13
|
$self->{d_from} = $from; |
|
106
|
9
|
|
|
|
|
19
|
$self->{d_dist} = {}; |
|
107
|
9
|
|
|
|
|
35
|
$self->{d_unvisited} = [ grep { $_ ne $from } keys(%{$self->{vertices}}) ]; |
|
|
42
|
|
|
|
|
92
|
|
|
|
9
|
|
|
|
|
29
|
|
|
108
|
9
|
|
|
|
|
30
|
$self->{d_suboptimal} = { $from => 0 }; |
|
109
|
|
|
|
|
|
|
|
|
110
|
9
|
|
|
|
|
52
|
dijkstra_worker($self, $from, $to); |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub dijkstra_continue { |
|
114
|
5
|
|
|
5
|
0
|
10
|
my ($self, $from, $to, $del_to) = @_; |
|
115
|
|
|
|
|
|
|
# instead of reinitializing, it should invoke the worker after initializing |
|
116
|
|
|
|
|
|
|
# to a state that assumes that an edge to $del_to has just been deleted. |
|
117
|
5
|
|
|
|
|
12
|
goto &dijkstra_first; |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
sub dijkstra { |
|
121
|
9
|
|
|
9
|
1
|
1012
|
my ($self, $from, $to, $del_to) = @_; |
|
122
|
9
|
100
|
100
|
|
|
49
|
if (!defined($self->{d_from}) or $self->{d_from} ne $from) { |
|
123
|
4
|
|
|
|
|
15
|
goto &dijkstra_first; |
|
124
|
|
|
|
|
|
|
} else { |
|
125
|
5
|
|
|
|
|
16
|
goto &dijkstra_continue; |
|
126
|
|
|
|
|
|
|
} |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
sub recursive_dijkstra { |
|
130
|
0
|
|
|
0
|
0
|
0
|
my ($self, $from, $to, $level, $del_to) = @_; |
|
131
|
0
|
|
|
|
|
0
|
my @d = ([ $self->dijkstra($from, $to, $del_to) ]); |
|
132
|
|
|
|
|
|
|
|
|
133
|
0
|
0
|
|
|
|
0
|
if (!defined($d[0]->[0])) { |
|
134
|
0
|
|
|
|
|
0
|
return (); |
|
135
|
|
|
|
|
|
|
} |
|
136
|
|
|
|
|
|
|
|
|
137
|
0
|
0
|
|
|
|
0
|
if ($level > 0) { |
|
138
|
0
|
|
|
|
|
0
|
foreach (0..(@{$d[0]}-1)) { |
|
|
0
|
|
|
|
|
0
|
|
|
139
|
|
|
|
|
|
|
# from copies of the graph, remove one edge from the result path, |
|
140
|
|
|
|
|
|
|
# and continue finding paths on that tree. |
|
141
|
0
|
|
|
|
|
0
|
my $ffffuuuu = $self->{_queue_maker}; |
|
142
|
0
|
|
|
|
|
0
|
$self->{_queue_maker} = "omg"; |
|
143
|
0
|
|
|
|
|
0
|
my $g2 = dclone($self); |
|
144
|
0
|
|
|
|
|
0
|
$g2->{_queue_maker} = $self->{_queue_maker} = $ffffuuuu; |
|
145
|
|
|
|
|
|
|
|
|
146
|
0
|
|
|
|
|
0
|
$g2->del_edge($d[0]->[$_]->{from}, $d[0]->[$_]->{to}); |
|
147
|
0
|
|
|
|
|
0
|
my @new = $g2->recursive_dijkstra($from, $to, $level - 1, $d[0]->[$_]->{to}); |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
# add all new paths, unless they are already present in the result set |
|
150
|
0
|
|
|
|
|
0
|
foreach my $n (@new) { |
|
151
|
0
|
0
|
|
|
|
0
|
push(@d, $n) unless (grep { $n ~~ $_ } @d); |
|
|
0
|
|
|
|
|
0
|
|
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
} |
|
155
|
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
0
|
@d; |
|
157
|
|
|
|
|
|
|
} |
|
158
|
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
sub add_edge { |
|
160
|
31
|
|
|
31
|
1
|
93
|
my ($self, $from, $to, $weight, $user_data) = @_; |
|
161
|
31
|
|
|
|
|
76
|
$self->del_edge($from => $to); |
|
162
|
|
|
|
|
|
|
|
|
163
|
31
|
50
|
|
|
|
211
|
my $edge = { from => $from, to => $to, weight => $weight, (defined($user_data) ? (user_data => $user_data) : ()) }; |
|
164
|
|
|
|
|
|
|
|
|
165
|
31
|
|
|
|
|
43
|
push(@{$self->{edges}}, $edge); |
|
|
31
|
|
|
|
|
59
|
|
|
166
|
31
|
|
33
|
|
|
124
|
($self->{vertices}->{$from} // $self->add_vertex($from))->{edges_out}->{$to} = $edge; |
|
167
|
31
|
|
66
|
|
|
149
|
($self->{vertices}->{$to } // $self->add_vertex($to ))->{edges_in }->{$from} = $edge; |
|
168
|
|
|
|
|
|
|
} |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub del_edge { |
|
171
|
33
|
|
|
33
|
1
|
53
|
my ($self, $from, $to) = @_; |
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
# find the edge. assume it only exists once -> only delete the first. |
|
174
|
|
|
|
|
|
|
# while we're at it, delete the edge from the source vertex... |
|
175
|
33
|
|
|
|
|
102
|
my $e = $self->{vertices}->{$from}->{edges_out}->{$to}; |
|
176
|
33
|
100
|
|
|
|
97
|
return undef if (!defined($e)); |
|
177
|
2
|
|
|
|
|
6
|
delete($self->{vertices}->{$from}->{edges_out}->{$to}); |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
# now search it in the destination vertex' list, delete it there |
|
180
|
|
|
|
|
|
|
# also only delete the first matching one here (though now there |
|
181
|
|
|
|
|
|
|
# shouldn't be any duplicates at all because now we're matching the |
|
182
|
|
|
|
|
|
|
# actual edge, not just its endpoints like above. |
|
183
|
2
|
|
|
|
|
4
|
delete($self->{vertices}->{$to}->{edges_in}->{$from}); |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# and remove it from the graph's vertex list |
|
186
|
2
|
|
|
|
|
5
|
@{$self->{edges}} = grep { $_ != $e } @{$self->{edges}} |
|
|
2
|
|
|
|
|
8
|
|
|
|
3
|
|
|
|
|
8
|
|
|
|
2
|
|
|
|
|
5
|
|
|
187
|
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
1; |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
__END__ |