File Coverage

lib/BalanceOfPower/Relations/RelPack.pm
Criterion Covered Total %
statement 185 249 74.3
branch 41 72 56.9
condition 3 10 30.0
subroutine 24 31 77.4
pod 0 27 0.0
total 253 389 65.0


line stmt bran cond sub pod time code
1             package BalanceOfPower::Relations::RelPack;
2             $BalanceOfPower::Relations::RelPack::VERSION = '0.400115';
3 13     13   60 use strict;
  13         19  
  13         381  
4 13     13   124 use v5.10;
  13         32  
5              
6 13     13   54 use Moo;
  13         15  
  13         72  
7 13     13   10948 use Module::Load;
  13         14071  
  13         91  
8              
9             has links => (
10             is => 'rw',
11             default => sub { [] }
12             );
13             has links_grid => (
14             is => 'rw',
15             default => sub { {} }
16             );
17             has distance_cache => (
18             is => 'rw',
19             default => sub { {} }
20             );
21              
22              
23             sub all
24             {
25 322     322 0 369 my $self = shift;
26 322         276 return @{$self->links};
  322         1123  
27             }
28             sub reset
29             {
30 1     1 0 3 my $self = shift;
31 1         5 $self->links([]);
32 1         18 $self->links_grid({});
33 1         4 $self->distance_cache({});
34             }
35              
36             sub exists_link
37             {
38 3157     3157 0 120920 my $self = shift;
39 3157         2881 my $node1 = shift;
40 3157         2689 my $node2 = shift;
41 3157 100       6897 if(exists $self->links_grid->{$node1}->{$node2})
42             {
43 1630         5162 return $self->links_grid->{$node1}->{$node2}
44             }
45             else
46             {
47 1527         4549 return undef;
48             }
49             }
50              
51             sub add_link
52             {
53 244     244 0 43840 my $self = shift;
54 244         303 my $link = shift;
55 244         584 my $node1 = $link->node1;
56 244         409 my $node2 = $link->node2;
57 244 50       442 if(! $self->exists_link($node1, $node2))
58             {
59 244         263 push @{$self->links}, $link;
  244         613  
60 244         485 $self->links_grid->{$node1}->{$node2} = $link;
61 244         450 $self->links_grid->{$node2}->{$node1} = $link;
62 244         981 return 1;
63             }
64             else
65             {
66 0         0 return 0;
67             }
68             }
69             sub update_link
70             {
71 0     0 0 0 my $self = shift;
72 0         0 my $link = shift;
73 0         0 $self->delete_link($link->node1, $link->node2);
74 0         0 $self->add_link($link);
75             }
76             sub delete_references
77             {
78 8     8 0 11 my $self = shift;
79 8         14 my $node1 = shift;
80 8         13 my $node2 = shift;
81 8         29 $self->links_grid->{$node1}->{$node2} = undef;
82 8         42 $self->links_grid->{$node2}->{$node1} = undef;
83             }
84             sub delete_references_for_node
85             {
86 15     15 0 15 my $self = shift;
87 15         16 my $node1 = shift;
88 15         13 foreach my $k (%{$self->links_grid->{$node1}})
  15         72  
89             {
90 2 50       7 if($k)
91             {
92 2         7 $self->links_grid->{$k}->{$node1} = undef;
93             }
94             }
95 15         53 $self->links_grid->{$node1} = undef;
96             }
97             sub delete_link
98             {
99 8     8 0 3673 my $self = shift;
100 8         18 my $node1 = shift;
101 8         14 my $node2 = shift;
102 8         17 @{$self->links} = grep { ! $_->involve($node1, $node2) } @{$self->links};
  8         28  
  9         42  
  8         43  
103 8         35 $self->delete_references($node1, $node2);
104             }
105              
106             sub delete_link_for_node
107             {
108 15     15 0 5891 my $self = shift;
109 15         20 my $n1 = shift;
110 15         33 @{$self->links} = grep { ! $_->has_node($n1) } @{$self->links};
  15         28  
  3         10  
  15         51  
111 15         35 $self->delete_references_for_node($n1);
112             }
113             sub garbage_collector
114             {
115 69     69 0 110 my $self = shift;
116 69         98 my $query = shift;
117 69         141 my @new = ();
118 69         90 for(@{$self->links})
  69         208  
119             {
120 14 50       37 if(! $query->($_))
121             {
122 14         38 push @new, $_;
123             }
124             else
125             {
126 0         0 $self->delete_references($_->node1, $_->node2);
127             }
128             }
129 69         96 @{$self->links} = @new;
  69         200  
130             }
131             sub links_for_node
132             {
133 515     515 0 49477 my $self = shift;
134 515         606 my $node = shift;
135 515 50       1077 return $self->all() if(! $node);
136 515         749 my @out = ();
137 515         495 foreach my $k (keys %{$self->links_grid->{$node}})
  515         2186  
138             {
139 386 50       625 if($k)
140             {
141 386         527 my $r = $self->links_grid->{$node}->{$k};
142 386 100       899 push @out, $r if($r);
143             }
144             }
145 515         1446 return @out;
146             }
147             sub links_for_node1
148             {
149 370     370 0 23880 my $self = shift;
150 370         404 my $node = shift;
151 370 50       702 return $self->all() if(! $node);
152 370         472 my @out = ();
153 370         374 foreach my $r (@{$self->links})
  370         952  
154             {
155 80 50       217 if($r->bidirectional)
156             {
157 0         0 return $self->links_for_node($node);
158             }
159 80 100       259 if($r->node1 eq $node)
160             {
161 18         53 push @out, $r;
162             }
163             }
164 370         856 return @out;
165             }
166             sub links_for_node2
167             {
168 159     159 0 177 my $self = shift;
169 159         174 my $node = shift;
170 159 50       348 return $self->all() if(! $node);
171 159         231 my @out = ();
172 159         191 foreach my $r (@{$self->links})
  159         466  
173             {
174 43 50       120 if($r->bidirectional)
175             {
176 0         0 return $self->links_for_node($node);
177             }
178 43 100       139 if($r->node2 eq $node)
179             {
180 18         34 push @out, $r;
181             }
182             }
183 159         298 return @out;
184             }
185             sub first_link_for_node
186             {
187 681     681 0 40587 my $self = shift;
188 681         767 my $node = shift;
189 681         634 foreach my $r (@{$self->links})
  681         1724  
190             {
191 122 100       398 if($r->has_node($node))
192             {
193 42         222 return $r;
194             }
195             }
196 639         2680 return undef;
197             }
198             sub first_link_for_node1
199             {
200 0     0 0 0 my $self = shift;
201 0         0 my $node = shift;
202 0         0 my @links = $self->links_for_node1($node);
203 0 0       0 if(@links)
204             {
205 0         0 return $links[0]
206             }
207             else
208             {
209 0         0 return undef;
210             }
211             }
212             sub first_link_for_node2
213             {
214 159     159 0 15366 my $self = shift;
215 159         212 my $node = shift;
216 159         360 my @links = $self->links_for_node2($node);
217 159 100       319 if(@links)
218             {
219 18         66 return $links[0]
220             }
221             else
222             {
223 141         434 return undef;
224             }
225             }
226              
227             sub link_destinations_for_node
228             {
229 5     5 0 1017 my $self = shift;
230 5         14 my $node1 = shift;
231 5         17 my @out = ();
232 5         16 for(keys %{$self->links_grid->{$node1}})
  5         46  
233             {
234 10         29 my $r = $self->links_grid->{$node1}->{$_};
235 10 50       32 if($r)
236             {
237 10         47 push @out, $r->destination($node1);
238             }
239             }
240 5         31 return @out;
241             }
242              
243             sub query
244             {
245 847     847 0 820 my $self = shift;
246 847         701 my $query = shift;
247 847         710 my $node1 = shift;
248 847         897 my @out = ();
249 847         710 for(@{$self->links})
  847         1718  
250             {
251 409 100       636 if($query->($_))
252             {
253 125 100       201 if($node1)
254             {
255 13 50       29 if($_->has_node($node1))
256             {
257 13         27 push @out, $_;
258             }
259             }
260             else
261             {
262 112         203 push @out, $_;
263             }
264             }
265             }
266 847         1570 return @out;
267             }
268             sub output_links
269             {
270 0     0 0 0 my $self = shift;
271 0         0 my $n = shift;
272 0   0     0 my $mode = shift || 'print';
273 0 0       0 if($mode eq 'print')
    0          
274             {
275 0         0 return $self->print_links($n);
276             }
277             elsif($mode eq 'html')
278             {
279 0         0 return $self->html_links($n);
280             }
281             }
282              
283             sub print_links
284             {
285 0     0 0 0 my $self = shift;
286 0         0 my $n = shift;
287 0         0 my $out = "";
288 0         0 foreach my $b (@{$self->links})
  0         0  
289             {
290 0 0       0 if($n)
291             {
292 0 0       0 if($b->has_node($n))
293             {
294 0         0 $out .= $b->print($n) . "\n";
295             }
296             }
297             else
298             {
299 0         0 $out .= $b->print($n) . "\n";
300             }
301             }
302 0         0 return $out;
303             }
304             sub html_links
305             {
306 0     0 0 0 my $self = shift;
307 0         0 my $n = shift;
308 0         0 my $out = "";
309 0         0 foreach my $b (@{$self->links})
  0         0  
310             {
311 0 0       0 if($n)
312             {
313 0 0       0 if($b->has_node($n))
314             {
315 0         0 $out .= $b->html($n) . "<br />";
316             }
317             }
318             else
319             {
320 0         0 $out .= $b->html($n) . "<br />";
321             }
322             }
323 0         0 return "<p>$out</p>";
324             }
325              
326             #BFS implementation
327             sub distance
328             {
329 170     170 0 11729 my $self = shift;
330 170         241 my $node1 = shift;
331 170         189 my $node2 = shift;
332 170         183 my $nodes_list = shift;
333 170         348 my %nodes = $self->get_cached_nodes($node1, $nodes_list);
334 170         226 my $log;
335 170 100       492 if($nodes{$node2}->{distance} != -1)
336             {
337 75         291 return $nodes{$node2}->{distance};
338             }
339 95 50       207 if(my $cached_distance = $self->get_cached_distance($node2, $node1))
340             {
341 0         0 $nodes{$node2}->{distance} = $cached_distance;
342 0         0 $self->distance_cache->{$node1}->{nodes} = \%nodes;
343 0         0 return $cached_distance;
344             }
345              
346 95         208 my @queue = ( $node1 );
347 95 100       267 if(exists $self->distance_cache->{$node1}->{queue})
348             {
349 37         51 @queue = @{$self->distance_cache->{$node1}->{queue}};
  37         135  
350             }
351 95         212 while(@queue)
352             {
353            
354 165         195 my $n = shift @queue;
355 165         309 foreach my $near ($self->near($n, $nodes_list))
356             {
357 313 100       647 if($nodes{$near}->{distance} == -1)
358             {
359 136         179 my $d = $nodes{$n}->{distance} + 1;
360 136         148 $nodes{$near}->{distance} = $nodes{$n}->{distance} + 1;
361 136         206 push @queue, $near;
362             }
363             }
364 165 100       486 if($nodes{$node2}->{distance} != -1)
365             {
366 37         116 $self->distance_cache->{$node1}->{nodes} = \%nodes;
367 37         102 $self->distance_cache->{$node1}->{queue} = \@queue;
368 37         163 return $nodes{$node2}->{distance};
369             }
370             }
371 58         96 $nodes{$node2}->{distance} = 100;
372 58         142 $self->distance_cache->{$node1}->{nodes} = \%nodes;
373 58         153 $self->distance_cache->{$node1}->{queue} = \@queue;
374 58         202 return 100;
375             }
376             sub get_cached_distance
377             {
378 95     95 0 124 my $self = shift;
379 95         107 my $node1 = shift;
380 95         96 my $node2 = shift;
381 95 50 66     369 if(exists $self->distance_cache->{$node1} &&
      33        
382             exists $self->distance_cache->{$node1}->{$node2} &&
383             $self->distance_cache->{$node1}->{$node2} != -1)
384             {
385 0         0 return $self->distance_cache->{$node1}->{$node2};
386             }
387             else
388             {
389 95         246 return undef;
390             }
391             }
392             sub get_cached_nodes
393             {
394 170     170 0 182 my $self = shift;
395 170         168 my $node1 = shift;
396 170         269 my $nodes_list = shift;
397 170         300 my %nodes = ();
398 170 100       519 if(exists $self->distance_cache->{$node1})
399             {
400 112         130 %nodes = %{$self->distance_cache->{$node1}->{nodes}};
  112         642  
401             }
402             else
403             {
404 58         67 foreach(@{$nodes_list})
  58         127  
405             {
406 292         522 $nodes{$_}->{distance} = -1;
407             }
408 58         96 $nodes{$node1}->{distance} = 0;
409             }
410 170         872 return %nodes;
411             }
412             sub near
413             {
414 180     180 0 2789 my $self = shift;
415 180         176 my $node = shift;
416 180         193 my $nodes = shift;
417 180 100       164 return grep { $self->exists_link($node, $_) && $node ne $_ } @{$nodes};
  912         1218  
  180         289  
418             }
419             sub dump
420             {
421 0     0 0   my $self = shift;
422 0           my $io = shift;
423 0   0       my $indent = shift || "";
424 0           foreach my $l (@{$self->links})
  0            
425             {
426 0           $l->dump($io, $indent);
427             }
428             }
429             sub load_pack
430             {
431 0     0 0   my $self = shift;
432 0           my $class = shift;
433 0           my $data = shift;
434 0           $data .= "EOF\n";
435 0           my @lines = split "\n", $data;
436 0           load $class;
437 0           my $rel_data = "";
438 0           foreach my $l (@lines)
439             {
440 0 0         if($l !~ /^\s/)
441             {
442 0 0         if($rel_data)
443             {
444 0           my $rel = $class->load($rel_data);
445 0           $self->add_link($rel);
446             }
447 0           $rel_data = $l . "\n";
448             }
449             else
450             {
451 0           $rel_data .= $l . "\n";
452             }
453             }
454             }
455              
456             1;