File Coverage

blib/lib/Graph/Weighted.pm
Criterion Covered Total %
statement 92 115 80.0
branch 30 36 83.3
condition 20 25 80.0
subroutine 12 14 85.7
pod 7 7 100.0
total 161 197 81.7


line stmt bran cond sub pod time code
1             package Graph::Weighted;
2             our $AUTHORITY = 'cpan:GENE';
3              
4             # ABSTRACT: A weighted graph implementation
5              
6             our $VERSION = '0.9101';
7              
8 2     2   1471 use warnings;
  2         6  
  2         65  
9 2     2   11 use strict;
  2         4  
  2         51  
10              
11 2     2   888 use parent qw( Graph );
  2         615  
  2         12  
12              
13 2     2   229876 use Carp qw( croak );
  2         7  
  2         121  
14              
15 2     2   15 use constant WEIGHT => 'weight';
  2         3  
  2         2634  
16              
17              
18             sub populate {
19 8     8 1 9249 my ($self, $data, $attr) = @_;
20              
21             # Set the default attribute.
22 8   50     50 $attr ||= WEIGHT;
23              
24             # What type of data are we given?
25 8         17 my $data_ref = ref $data;
26              
27 8 100 66     39 if ($data_ref eq 'ARRAY' || $data_ref eq 'Math::Matrix') {
    50          
    50          
28 6         11 my $vertex = 0; # Initial vertex id.
29 6         12 for my $neighbors (@$data) {
30 14         36 $self->_from_array($vertex, $neighbors, $attr);
31 14         2037 $vertex++; # Move on to the next vertex...
32             }
33             }
34             elsif ($data_ref eq 'Math::MatrixReal') {
35 0         0 my $vertex = 0;
36 0         0 for my $neighbors (@{ $data->[0] }) {
  0         0  
37 0         0 $self->_from_array($vertex, $neighbors, $attr);
38 0         0 $vertex++;
39             }
40             }
41             elsif ($data_ref eq 'HASH') {
42 2         14 for my $vertex (keys %$data) {
43 5         455 for my $entry ( keys %{ $data->{$vertex} } ) {
  5         18  
44 11 100       205 if ( $entry eq 'label' ) {
45 1         3 my $label = delete $data->{$vertex}{$entry};
46 1         4 $self->set_vertex_attribute($vertex, $entry, $label);
47             }
48             }
49 5         19 $self->_from_hash( $vertex, $data->{$vertex}, $attr );
50             }
51             }
52             else {
53 0         0 croak "Unknown data type: $data\n";
54             }
55             }
56              
57             sub _from_array {
58 14     14   28 my ($self, $vertex, $neighbors, $attr) = @_;
59              
60             # Initial vertex weight
61 14         21 my $vertex_weight = 0;
62              
63             # Make nodes and edges.
64 14         37 for my $n (0 .. @$neighbors - 1) {
65 55         76 my $w = $neighbors->[$n]; # Weight of the edge to the neighbor.
66 55 100       106 next unless $w; # Skip zero weight nodes
67              
68             # Add a node-node edge to the graph.
69 16         62 $self->add_edge($vertex, $n);
70              
71 16         3307 $self->set_edge_attribute($vertex, $n, $attr, $w);
72              
73             # Tally the weight of the vertex.
74 16         5274 $vertex_weight += $w;
75             }
76              
77             # Set the weight of the graph node.
78 14         42 $self->set_vertex_attribute($vertex, $attr, $vertex_weight);
79             }
80              
81             sub _from_hash {
82 5     5   13 my ($self, $vertex, $neighbors, $attr) = @_;
83              
84             # Initial vertex weight
85 5         10 my $vertex_weight = 0;
86              
87             # Handle terminal nodes.
88 5 50       13 if (ref $neighbors) {
89             # Make nodes and edges.
90 5         13 for my $n (keys %$neighbors) {
91 10         17 my $w = $neighbors->{$n}; # Weight of the edge to the neighbor.
92              
93             # Add a node-node edge to the graph.
94 10         35 $self->add_edge($vertex, $n);
95              
96 10         2319 $self->set_edge_attribute($vertex, $n, $attr, $w);
97              
98             # Tally the weight of the vertex.
99 10         3814 $vertex_weight += $w;
100             }
101             }
102             else {
103 0         0 $vertex_weight = $neighbors;
104             }
105              
106             # Set the weight of the graph node.
107 5         31 $self->set_vertex_attribute($vertex, $attr, $vertex_weight);
108             }
109              
110              
111             sub get_cost {
112 36     36 1 7035 my ($self, $v, $attr) = @_;
113 36 50       74 croak 'ERROR: No vertex given to get_cost()' unless defined $v;
114              
115             # Default to weight.
116 36   100     113 $attr ||= WEIGHT;
117              
118             # Return the edge attribute if given a list.
119 36 100 50     104 return $self->get_edge_attribute(@$v, $attr) || 0 if ref $v eq 'ARRAY';
120              
121             # Return the vertex attribute if given a scalar.
122 14   100     49 return $self->get_vertex_attribute($v, $attr) || 0;
123             }
124              
125              
126             sub vertex_span {
127 1     1 1 7 my ($self, $attr) = @_;
128              
129             # Get the cost of each vertex
130 1         2 my $mass = {};
131 1         5 for my $vertex ( $self->vertices ) {
132 5         427 $mass->{$vertex} = $self->get_cost($vertex, $attr);
133             }
134              
135             # Find the smallest & biggest costs
136 1         98 my ($smallest, $biggest);
137 1         9 for my $vertex ( keys %$mass ) {
138 5         10 my $current = $mass->{$vertex};
139 5 100 100     18 if ( !defined $smallest || $smallest > $current ) {
140 2         4 $smallest = $current;
141             }
142 5 100 100     16 if ( !defined $biggest || $biggest < $current ) {
143 3         5 $biggest = $current;
144             }
145             }
146              
147             # Collect the lightest & heaviest vertices
148 1         4 my ($lightest, $heaviest) = ([], []);
149 1         3 for my $vertex ( keys %$mass ) {
150 5 100       10 push @$lightest, $vertex if $mass->{$vertex} == $smallest;
151 5 100       12 push @$heaviest, $vertex if $mass->{$vertex} == $biggest;
152             }
153              
154 1         5 return $lightest, $heaviest;
155             }
156              
157              
158             sub edge_span {
159 1     1 1 1045 my ($self, $attr) = @_;
160              
161             # Get the cost of each edge
162 1         3 my $mass = {};
163 1         4 for my $edge ( $self->edges ) {
164 7         2322 $mass->{ $edge->[0] . '_' . $edge->[1] } = $self->get_cost($edge, $attr);
165             }
166              
167             # Find the smallest & biggest costs
168 1         349 my ($smallest, $biggest);
169 1         5 for my $edge ( keys %$mass ) {
170 7         11 my $current = $mass->{$edge};
171 7 100 100     24 if ( !defined $smallest || $smallest > $current ) {
172 2         3 $smallest = $current;
173             }
174 7 100 100     21 if ( !defined $biggest || $biggest < $current ) {
175 2         4 $biggest = $current;
176             }
177             }
178              
179             # Collect the lightest & heaviest edges
180 1         6 my ($lightest, $heaviest) = ([], []);
181 1         7 for my $edge ( sort keys %$mass ) {
182 7         17 my $arrayref = [ split /_/, $edge ];
183 7 100       19 push @$lightest, $arrayref if $mass->{$edge} == $smallest;
184 7 100       16 push @$heaviest, $arrayref if $mass->{$edge} == $biggest;
185             }
186              
187 1         7 return $lightest, $heaviest;
188             }
189              
190              
191              
192             sub path_cost {
193 4     4 1 3761 my ($self, $path, $attr) = @_;
194              
195 4 100       24 return undef unless $self->has_path( @$path );
196              
197 3         1017 my $path_cost = 0;
198              
199 3         12 for my $i ( 0 .. @$path - 2 ) {
200 6         1068 $path_cost += $self->get_cost( [ $path->[$i], $path->[ $i + 1 ] ], $attr );
201             }
202              
203 3         1145 return $path_cost;
204             }
205              
206              
207             sub MST_edge_sum {
208 0     0 1   my ($self, $tree) = @_;
209              
210 0           my $sum = 0;
211              
212 0           my @edges = split /,/, $tree;
213              
214 0           for my $edge (@edges) {
215 0           my @edge = split /=/, $edge;
216 0           $sum += $self->get_cost(\@edge);
217             }
218              
219 0           return $sum;
220             }
221              
222              
223             sub dump {
224 0     0 1   my $self = shift;
225 0   0       my $attr = shift || WEIGHT;
226              
227 0           for my $vertex ( sort { $a <=> $b } $self->vertices ) {
  0            
228 0           my $label = $self->get_vertex_attribute($vertex, 'label');
229 0 0         printf "%svertex: %s %s=%.2f\n",
230             ( $label ? "$label " : '' ),
231             $vertex,
232             $attr,
233             $self->get_cost( $vertex, $attr );
234 0           for my $successor ( sort { $a <=> $b } $self->successors($vertex) ) {
  0            
235 0           printf "\tedge to: %s %s=%.2f\n",
236             $successor,
237             $attr,
238             $self->get_cost( [ $vertex, $successor ], $attr );
239             }
240             }
241             }
242              
243             1;
244              
245             __END__