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.400105';
3 13     13   42 use strict;
  13         17  
  13         269  
4 13     13   93 use v5.10;
  13         33  
5              
6 13     13   47 use Moo;
  13         15  
  13         52  
7 13     13   7801 use Module::Load;
  13         10225  
  13         63  
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 242 my $self = shift;
26 322         239 return @{$self->links};
  322         831  
27             }
28             sub reset
29             {
30 1     1 0 1 my $self = shift;
31 1         4 $self->links([]);
32 1         20 $self->links_grid({});
33 1         4 $self->distance_cache({});
34             }
35              
36             sub exists_link
37             {
38 3124     3124 0 91852 my $self = shift;
39 3124         2299 my $node1 = shift;
40 3124         1953 my $node2 = shift;
41 3124 100       5331 if(exists $self->links_grid->{$node1}->{$node2})
42             {
43 1614         3917 return $self->links_grid->{$node1}->{$node2}
44             }
45             else
46             {
47 1510         3337 return undef;
48             }
49             }
50              
51             sub add_link
52             {
53 251     251 0 37346 my $self = shift;
54 251         244 my $link = shift;
55 251         454 my $node1 = $link->node1;
56 251         346 my $node2 = $link->node2;
57 251 50       377 if(! $self->exists_link($node1, $node2))
58             {
59 251         215 push @{$self->links}, $link;
  251         562  
60 251         403 $self->links_grid->{$node1}->{$node2} = $link;
61 251         370 $self->links_grid->{$node2}->{$node1} = $link;
62 251         805 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 13 my $self = shift;
79 8         10 my $node1 = shift;
80 8         12 my $node2 = shift;
81 8         31 $self->links_grid->{$node1}->{$node2} = undef;
82 8         36 $self->links_grid->{$node2}->{$node1} = undef;
83             }
84             sub delete_references_for_node
85             {
86 15     15 0 14 my $self = shift;
87 15         14 my $node1 = shift;
88 15         15 foreach my $k (%{$self->links_grid->{$node1}})
  15         53  
89             {
90 2 50       4 if($k)
91             {
92 2         8 $self->links_grid->{$k}->{$node1} = undef;
93             }
94             }
95 15         44 $self->links_grid->{$node1} = undef;
96             }
97             sub delete_link
98             {
99 8     8 0 2671 my $self = shift;
100 8         13 my $node1 = shift;
101 8         11 my $node2 = shift;
102 8         10 @{$self->links} = grep { ! $_->involve($node1, $node2) } @{$self->links};
  8         26  
  9         36  
  8         29  
103 8         25 $self->delete_references($node1, $node2);
104             }
105              
106             sub delete_link_for_node
107             {
108 15     15 0 4735 my $self = shift;
109 15         17 my $n1 = shift;
110 15         15 @{$self->links} = grep { ! $_->has_node($n1) } @{$self->links};
  15         25  
  3         10  
  15         35  
111 15         29 $self->delete_references_for_node($n1);
112             }
113             sub garbage_collector
114             {
115 69     69 0 80 my $self = shift;
116 69         72 my $query = shift;
117 69         94 my @new = ();
118 69         69 for(@{$self->links})
  69         158  
119             {
120 14 50       30 if(! $query->($_))
121             {
122 14         42 push @new, $_;
123             }
124             else
125             {
126 0         0 $self->delete_references($_->node1, $_->node2);
127             }
128             }
129 69         82 @{$self->links} = @new;
  69         170  
130             }
131             sub links_for_node
132             {
133 529     529 0 38375 my $self = shift;
134 529         452 my $node = shift;
135 529 50       829 return $self->all() if(! $node);
136 529         608 my @out = ();
137 529         657 foreach my $k (keys %{$self->links_grid->{$node}})
  529         1637  
138             {
139 457 50       622 if($k)
140             {
141 457         475 my $r = $self->links_grid->{$node}->{$k};
142 457 100       831 push @out, $r if($r);
143             }
144             }
145 529         1149 return @out;
146             }
147             sub links_for_node1
148             {
149 317     317 0 16748 my $self = shift;
150 317         329 my $node = shift;
151 317 50       467 return $self->all() if(! $node);
152 317         340 my @out = ();
153 317         219 foreach my $r (@{$self->links})
  317         664  
154             {
155 69 50       167 if($r->bidirectional)
156             {
157 0         0 return $self->links_for_node($node);
158             }
159 69 100       185 if($r->node1 eq $node)
160             {
161 18         28 push @out, $r;
162             }
163             }
164 317         559 return @out;
165             }
166             sub links_for_node2
167             {
168 164     164 0 149 my $self = shift;
169 164         126 my $node = shift;
170 164 50       359 return $self->all() if(! $node);
171 164         178 my @out = ();
172 164         127 foreach my $r (@{$self->links})
  164         354  
173             {
174 43 50       108 if($r->bidirectional)
175             {
176 0         0 return $self->links_for_node($node);
177             }
178 43 100       134 if($r->node2 eq $node)
179             {
180 18         39 push @out, $r;
181             }
182             }
183 164         233 return @out;
184             }
185             sub first_link_for_node
186             {
187 611     611 0 29876 my $self = shift;
188 611         512 my $node = shift;
189 611         478 foreach my $r (@{$self->links})
  611         1265  
190             {
191 114 100       279 if($r->has_node($node))
192             {
193 43         148 return $r;
194             }
195             }
196 568         1796 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 164     164 0 11437 my $self = shift;
215 164         180 my $node = shift;
216 164         264 my @links = $self->links_for_node2($node);
217 164 100       256 if(@links)
218             {
219 18         50 return $links[0]
220             }
221             else
222             {
223 146         339 return undef;
224             }
225             }
226              
227             sub link_destinations_for_node
228             {
229 5     5 0 487 my $self = shift;
230 5         5 my $node1 = shift;
231 5         5 my @out = ();
232 5         7 for(keys %{$self->links_grid->{$node1}})
  5         21  
233             {
234 10         16 my $r = $self->links_grid->{$node1}->{$_};
235 10 50       17 if($r)
236             {
237 10         23 push @out, $r->destination($node1);
238             }
239             }
240 5         14 return @out;
241             }
242              
243             sub query
244             {
245 676     676 0 495 my $self = shift;
246 676         445 my $query = shift;
247 676         477 my $node1 = shift;
248 676         565 my @out = ();
249 676         421 for(@{$self->links})
  676         1071  
250             {
251 399 100       482 if($query->($_))
252             {
253 89 100       113 if($node1)
254             {
255 13 50       30 if($_->has_node($node1))
256             {
257 13         19 push @out, $_;
258             }
259             }
260             else
261             {
262 76         99 push @out, $_;
263             }
264             }
265             }
266 676         964 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 173     173 0 8987 my $self = shift;
330 173         168 my $node1 = shift;
331 173         139 my $node2 = shift;
332 173         127 my $nodes_list = shift;
333 173         319 my %nodes = $self->get_cached_nodes($node1, $nodes_list);
334 173         178 my $log;
335 173 100       357 if($nodes{$node2}->{distance} != -1)
336             {
337 76         231 return $nodes{$node2}->{distance};
338             }
339 97 50       154 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 97         173 my @queue = ( $node1 );
347 97 100       206 if(exists $self->distance_cache->{$node1}->{queue})
348             {
349 37         40 @queue = @{$self->distance_cache->{$node1}->{queue}};
  37         94  
350             }
351 97         193 while(@queue)
352             {
353            
354 176         157 my $n = shift @queue;
355 176         253 foreach my $near ($self->near($n, $nodes_list))
356             {
357 336 100       519 if($nodes{$near}->{distance} == -1)
358             {
359 146         132 my $d = $nodes{$n}->{distance} + 1;
360 146         132 $nodes{$near}->{distance} = $nodes{$n}->{distance} + 1;
361 146         166 push @queue, $near;
362             }
363             }
364 176 100       403 if($nodes{$node2}->{distance} != -1)
365             {
366 40         93 $self->distance_cache->{$node1}->{nodes} = \%nodes;
367 40         88 $self->distance_cache->{$node1}->{queue} = \@queue;
368 40         118 return $nodes{$node2}->{distance};
369             }
370             }
371 57         73 $nodes{$node2}->{distance} = 100;
372 57         108 $self->distance_cache->{$node1}->{nodes} = \%nodes;
373 57         120 $self->distance_cache->{$node1}->{queue} = \@queue;
374 57         150 return 100;
375             }
376             sub get_cached_distance
377             {
378 97     97 0 1428 my $self = shift;
379 97         85 my $node1 = shift;
380 97         74 my $node2 = shift;
381 97 50 66     284 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 97         220 return undef;
390             }
391             }
392             sub get_cached_nodes
393             {
394 173     173 0 133 my $self = shift;
395 173         146 my $node1 = shift;
396 173         1759 my $nodes_list = shift;
397 173         232 my %nodes = ();
398 173 100       374 if(exists $self->distance_cache->{$node1})
399             {
400 113         94 %nodes = %{$self->distance_cache->{$node1}->{nodes}};
  113         477  
401             }
402             else
403             {
404 60         53 foreach(@{$nodes_list})
  60         113  
405             {
406 302         390 $nodes{$_}->{distance} = -1;
407             }
408 60         78 $nodes{$node1}->{distance} = 0;
409             }
410 173         591 return %nodes;
411             }
412             sub near
413             {
414 193     193 0 1828 my $self = shift;
415 193         157 my $node = shift;
416 193         143 my $nodes = shift;
417 193 100       177 return grep { $self->exists_link($node, $_) && $node ne $_ } @{$nodes};
  984         938  
  193         214  
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;