File Coverage

blib/lib/SNA/Network.pm
Criterion Covered Total %
statement 135 135 100.0
branch 3 4 75.0
condition 4 5 80.0
subroutine 35 35 100.0
pod 12 12 100.0
total 189 191 98.9


line stmt bran cond sub pod time code
1             package SNA::Network;
2              
3 14     14   250848 use warnings;
  14         24  
  14         464  
4 14     14   58 use strict;
  14         19  
  14         399  
5              
6 14     14   55 use Carp;
  14         27  
  14         1080  
7 14     14   7364 use English;
  14         46249  
  14         75  
8              
9 14     14   13280 use Object::Tiny::XS qw(community_levels);
  14         44722  
  14         82  
10              
11 14     14   4053 use Scalar::Util qw(weaken);
  14         26  
  14         1468  
12 14     14   72 use List::Util qw(sum);
  14         19  
  14         1145  
13              
14 14     14   5673 use SNA::Network::Node;
  14         35  
  14         165  
15 14     14   5646 use SNA::Network::Edge;
  14         36  
  14         143  
16 14     14   5667 use SNA::Network::Filter::Pajek;
  14         24  
  14         819  
17 14     14   5367 use SNA::Network::Filter::Guess;
  14         34  
  14         930  
18 14     14   5565 use SNA::Network::Algorithm::Betweenness;
  14         28  
  14         724  
19 14     14   4925 use SNA::Network::Algorithm::Connectivity;
  14         27  
  14         773  
20 14     14   5097 use SNA::Network::Algorithm::Cores;
  14         28  
  14         675  
21 14     14   4961 use SNA::Network::Algorithm::HITS;
  14         29  
  14         713  
22 14     14   5268 use SNA::Network::Algorithm::Louvain;
  14         58  
  14         785  
23 14     14   5450 use SNA::Network::Algorithm::PageRank;
  14         32  
  14         735  
24 14     14   5156 use SNA::Network::Generator::ByDensity;
  14         32  
  14         655  
25 14     14   5072 use SNA::Network::Generator::ConfigurationModel;
  14         50  
  14         676  
26 14     14   5233 use SNA::Network::Generator::MCMC;
  14         26  
  14         705  
27              
28 14     14   70 use Module::List::Pluggable qw(import_modules);
  14         15  
  14         12428  
29             import_modules('SNA::Network::Plugin');
30              
31              
32             =head1 NAME
33              
34             SNA::Network - A toolkit for Social Network Analysis
35              
36             =head1 VERSION
37              
38             Version 0.20
39              
40             =cut
41              
42             our $VERSION = '0.20';
43              
44              
45             =head1 SYNOPSIS
46              
47             Quick summary of what the module does.
48              
49             use SNA::Network;
50              
51             my $net = SNA::Network->new();
52             $net->create_node_at_index(index => 0, name => 'A');
53             $net->create_node_at_index(index => 1, name => 'B');
54             $net->create_edge(source_index => 0, target_index => 1, weight => 1);
55             ...
56            
57             =head1 DESCRIPTION
58              
59             SNA::Network is a bundle of modules for network algorithms,
60             specifically designed for the needs of Social Network Analysis (SNA),
61             but can be used for any other graph algorithms of course.
62              
63             It represents a standard directed and weighted network,
64             which can also be used as an undirected and/or unweighted network of course.
65             It is freely extensible by using own hash entries.
66              
67             Data structures have been designed for SNA-typical sparse network operations,
68             and consist of Node and Edge objects, linked via references to each other.
69              
70             Functionality is implemented in sub-modules in the B namespace,
71             and all methods are imported into B.
72             So you can read the documentation in the sub-modules and call the methods
73             from your B instance.
74              
75             Methods are called with named parameter style, e.g.
76              
77             $net->method( param1 => value1, param2 => value2, ...);
78            
79             Only in cases, where methods have only one parameter,
80             this one is passed by value.
81              
82             This module was implemented mainly because I had massive problems
83             understanding the internal structures of Perl's L module.
84             Despite it uses lots of arrays instead of hashes for attributes
85             and bit setting for properties, it was terribly slow for my purposes,
86             especially in network manipulation (consistent node removal).
87             It currently has much more features and plugins though,
88             and is suitable for different network types.
89             This package is focussing on directed networks only,
90             with the possibility to model undirected ones as well.
91              
92              
93             =head1 METHODS
94              
95             =head2 new
96              
97             Creates a new empty network.
98             There are no parameters.
99             After creation, use methods to add nodes and edges,
100             or load a network from a file.
101              
102             =cut
103              
104             sub new {
105 25     25 1 748 my ($package) = @_;
106 25         139 return bless { nodes => [], edges => [] }, $package;
107             }
108              
109              
110             =head2 create_node_at_index
111              
112             Creates a node at the given index.
113             Pass node attributes as additional named parameters, index is mandatory.
114             Returns the created L object.
115              
116             =cut
117              
118             sub create_node_at_index {
119 660     660 1 1852 my ($self, %node_attributes) = @_;
120 660         1487 return $self->{nodes}->[$node_attributes{index}] = SNA::Network::Node->new(%node_attributes);
121             }
122              
123              
124             =head2 create_node
125              
126             Creates a node at the next index.
127             Pass node attributes as additional named parameters, index is forbidden.
128             Returns the created L object with the right index field.
129              
130             =cut
131              
132             sub create_node {
133 12     12 1 809 my ($self, %node_attributes) = @_;
134 12 50       33 croak "illegally passed index to create_node method" if defined $node_attributes{index};
135 12         19 my $index = int $self->nodes;
136 12         31 return $self->create_node_at_index( index => $index, %node_attributes );
137             }
138              
139              
140             =head2 create_edge
141              
142             Creates a new edge between nodes with the given B and B.
143             A B is optional, it defaults to 1.
144             Pass any additional attributes as key/value pairs.
145             Returns the created L object.
146              
147             =cut
148              
149             sub create_edge {
150 4001     4001 1 7171 my ($self, %params) = @_;
151 4001         5275 my $source_node = $self->node_at_index( $params{source_index} );
152 4001         5155 my $target_node = $self->node_at_index( $params{target_index} );
153 4001         3185 my $index = int @{ $self->{edges} };
  4001         4380  
154 4001         3771 my $weight = $params{weight};
155 4001         4017 delete $params{source_index};
156 4001         3168 delete $params{target_index};
157 4001         3081 delete $params{weight};
158 4001         8020 my $edge = SNA::Network::Edge->new(
159             source => $source_node,
160             target => $target_node,
161             weight => $weight,
162             index => $index,
163             %params,
164             );
165 4001         3665 push @{ $self->{edges} }, $edge;
  4001         4922  
166 4001         3003 push @{ $source_node->{outgoing_edges} }, $edge;
  4001         4494  
167 4001         6921 weaken $source_node->{outgoing_edges}->[-1];
168 4001         2733 push @{ $target_node->{incoming_edges} }, $edge;
  4001         5071  
169 4001         5877 weaken $target_node->{incoming_edges}->[-1];
170 4001         12937 return $edge;
171             }
172              
173              
174             =head2 nodes
175              
176             Returns the array of L objects belonging to this network.
177              
178             =cut
179              
180             sub nodes {
181 169     169 1 3066 my ($self) = @_;
182 169         148 return @{ $self->{nodes} };
  169         591  
183             }
184              
185              
186             =head2 node_at_index
187              
188             Returns the L object at the given index.
189              
190             =cut
191              
192             sub node_at_index {
193 8197     8197 1 8234 my ($self, $index) = @_;
194 8197         10111 return $self->{nodes}->[$index];
195             }
196              
197              
198             =head2 edges
199              
200             Returns the array of L objects belonging to this network.
201              
202             =cut
203              
204             sub edges {
205 21116     21116 1 17233 my ($self) = @_;
206 21116         14537 return @{ $self->{edges} };
  21116         40396  
207             }
208              
209              
210             =head2 total_weight
211              
212             Returns the sum of all weights of the L objects belonging to this network.
213              
214             =cut
215              
216             sub total_weight {
217 4     4 1 8 my ($self) = @_;
218 4         11 return sum map { $_->weight } $self->edges;
  1501         2279  
219             }
220              
221              
222             =head2 delete_nodes
223              
224             Delete the passed node objects.
225             These have to be sorted by index!
226             All related edges get deleted as well.
227             Indexes get restored after this operation.
228              
229             =cut
230              
231             sub delete_nodes {
232 1     1 1 2 my ($self, @nodes_to_delete) = @_;
233             # nodes have to be sorted by index!
234            
235 1         3 foreach (@nodes_to_delete) {
236 2         6 $self->delete_edges( $_->edges() );
237             }
238            
239 7 100 100     27 $self->{nodes} = [ grep {
      50        
240 1         4 ($nodes_to_delete[0] && $_ == $nodes_to_delete[0]) ? shift @nodes_to_delete && 0 : 1
241             } $self->nodes() ];
242 1         3 $self->_restore_node_indexes();
243             }
244              
245              
246             sub _restore_node_indexes {
247 1     1   1 my ($self) = @_;
248 1         2 my $i = 0;
249 1         84 foreach ($self->nodes()) {
250 5         6 $_->{index} = $i++;
251 5         7 undef $_->{weak_component_index};
252             }
253             }
254              
255              
256             =head2 delete_edges
257              
258             Delete the passed edge objects.
259              
260             =cut
261              
262             sub delete_edges {
263 3     3 1 5 my ($self, @edges_to_delete) = @_;
264            
265 3         5 foreach my $edge (@edges_to_delete) {
266            
267             # delete references in endpoint nodes
268              
269 13         28 $edge->source->{outgoing_edges} = [ grep {
270 8         16 $_ != $edge
271             } $edge->source->outgoing_edges ];
272            
273 8         18 for (0 .. int $edge->source->outgoing_edges - 1) {
274 5         19 weaken $edge->source->{outgoing_edges}->[$_];
275             }
276              
277 14         26 $edge->target->{incoming_edges} = [ grep {
278 8         19 $_ != $edge
279             } $edge->target->incoming_edges ];
280            
281 8         19 for (0 .. int $edge->target->incoming_edges - 1) {
282 6         15 weaken $edge->target->{incoming_edges}->[$_];
283             }
284            
285             # delete references in edge index
286 43         52 $self->{edges} = [ grep {
287 8         11 $_ != $edge
288             } $self->edges ];
289             }
290            
291            
292 3         6 $self->_restore_edge_indexes;
293             }
294              
295              
296             sub _restore_edge_indexes {
297 3     3   2 my ($self) = @_;
298 3         4 my $i = 0;
299 3         4 foreach ($self->edges) {
300 9         25 $_->{index} = $i++;
301             }
302             }
303              
304              
305             =head2 community_levels
306              
307             Returns an array reference containing L objects, which were identified by a previously executed community identification algorithm, usually the L algorithm.
308             With a hierarchical identification algorithm, the array containts the structures of the different levels from the finest-granular structure at index 0 to the most coarsely-granular structure at the last index.
309             If no such algorithm had been executed, it returns C.
310              
311              
312             =head2 communities
313              
314             Return a list of L objects, which were identified by a previously executed community identification algorithm, usually the L algorithm.
315             If no such algorithm was executed, returns C.
316              
317             =cut
318              
319             sub communities {
320 13     13 1 762 my ($self) = @_;
321 13         13 return @{ $self->{communities_ref} };
  13         46  
322             }
323              
324              
325             =head2 modularity
326              
327             Return the modularity value based on the current communities of the network,
328             which were identified by a previously executed community identification algorithm,
329             usually the L algorithm.
330             If no such algorithm was executed, returns C.
331              
332             =cut
333              
334             sub modularity {
335 1     1 1 205 my ($self) = @_;
336 1         3 return sum map { $_->module_value } $self->communities;
  4         8  
337             }
338              
339              
340              
341             =head1 PLUGIN SYSTEM
342              
343             This package can be extenden with plugins,
344             which gives you the possibility, to add your own algorithms, filters, and so on.
345             Each class found in the namespace B
346             will be imported into the namespace of B,
347             and each class found in the namespace B
348             will be imported into the namespace of B.
349             With this mechanism, you can add methods to these classes.
350              
351             For example:
352              
353             package SNA::Network::Plugin::Foo;
354              
355             use warnings;
356             use strict;
357              
358             require Exporter;
359             use base qw(Exporter);
360             our @EXPORT = qw(foo);
361              
362             sub foo {
363             my ($self) = @_;
364             # $self is a reference to our network object
365             # do something with it here
366             ...
367             }
368              
369             adds a new foo method to B.
370              
371              
372             =head1 SEE ALSO
373              
374             =over 4
375              
376             =item * L
377              
378             =item * L
379              
380             =item * L
381              
382             =item * L
383              
384             =item * L
385              
386             =item * L
387              
388             =item * L
389              
390             =item * L
391              
392             =item * L
393              
394             =item * L
395              
396             =item * L
397              
398             =item * L
399              
400             =item * L
401              
402             =item * L
403              
404             =back
405              
406              
407             =head1 AUTHOR
408              
409             Darko Obradovic, C<< >>
410              
411              
412             =head1 BUGS
413              
414             Please report any bugs or feature requests to C, or through
415             the web interface at L. I will be notified, and then you'll
416             automatically be notified of progress on your bug as I make changes.
417              
418              
419             =head1 SUPPORT
420              
421             You can find documentation for this module with the perldoc command.
422              
423             perldoc SNA::Network
424              
425              
426             You can also look for information at:
427              
428             =over 4
429              
430             =item * RT: CPAN's request tracker
431              
432             L
433              
434             =item * AnnoCPAN: Annotated CPAN documentation
435              
436             L
437              
438             =item * CPAN Ratings
439              
440             L
441              
442             =item * Search CPAN
443              
444             L
445              
446             =back
447              
448              
449             =head1 ACKNOWLEDGEMENTS
450              
451             This module has been developed as part of my work at the
452             German Research Center for Artificial Intelligence (DFKI) L.
453              
454              
455             =head1 COPYRIGHT & LICENSE
456              
457             Copyright 2009 Darko Obradovic, all rights reserved.
458              
459             This program is free software; you can redistribute it and/or modify it
460             under the same terms as Perl itself.
461              
462              
463             =cut
464              
465             1; # End of SNA::Network