File Coverage

blib/lib/Graph/TransitiveClosure.pm
Criterion Covered Total %
statement 36 36 100.0
branch 13 14 92.8
condition 4 6 66.6
subroutine 8 8 100.0
pod 3 3 100.0
total 64 67 95.5


line stmt bran cond sub pod time code
1             package Graph::TransitiveClosure;
2              
3 6     6   562 use strict;
  6         13  
  6         185  
4 6     6   31 use warnings;
  6         13  
  6         191  
5              
6             # COMMENT THESE OUT FOR TESTING AND PRODUCTION.
7             # $SIG{__DIE__ } = \&Graph::__carp_confess;
8             # $SIG{__WARN__} = \&Graph::__carp_confess;
9              
10 6     6   28 use base 'Graph';
  6         11  
  6         565  
11 6     6   3254 use Graph::TransitiveClosure::Matrix;
  6         15  
  6         2536  
12              
13             sub _G () { Graph::_G() }
14              
15             sub new {
16 75     75 1 359 my ($class, $g, %opt) = @_;
17 75 50 33     570 Graph::__carp_confess(__PACKAGE__."->new given non-Graph '$g'")
18             if !(ref $g and $g->isa('Graph'));
19 75 100       225 %opt = (path_vertices => 1) unless %opt;
20             # No delete $opt{ attribute_name } since we need to pass it on.
21 75 100       287 my $attr = exists $opt{ attribute_name } ? $opt{ attribute_name } : Graph::_defattr();
22 75 100       273 $opt{ reflexive } = 1 unless exists $opt{ reflexive };
23             my $tcg = $g->new(
24             multiedged => 0,
25 75 100       394 ($opt{ reflexive } ? (vertices => [$g->vertices]) : ()),
26             );
27 75         550 my $tcm = $g->_check_cache('transitive_closure_matrix', [],
28             \&_transitive_closure_matrix_compute, %opt);
29 75         205 my $tcm00 = $tcm->[0][0]; # 0=am, 0=bitmatrix
30 75         132 my $tcm01 = $tcm->[0][1]; # , 1=hash mapping v-name to the offset into dm data structures (in retval of $g->vertices)
31 75         115 my @edges;
32 75         227 for my $u ($tcm->vertices) {
33 524         987 my $tcm00i = $tcm00->[ $tcm01->{ $u } ];
34 524         1251 for my $v ($tcm->vertices) {
35 17438 100 100     30459 next if $u eq $v && ! $opt{ reflexive };
36 17426         22741 my $j = $tcm01->{ $v };
37 17426 100       40429 push @edges, [$u, $v] if vec($tcm00i, $j, 1);
38             # $tcm->is_transitive($u, $v)
39             # $tcm->[0]->get($u, $v)
40             }
41             }
42 75         538 $tcg->add_edges(@edges);
43 75         359 $tcg->set_graph_attribute('_tcm', [ $g->[ _G ], $tcm ]);
44 75         1612 bless $tcg, $class;
45             }
46              
47             sub _transitive_closure_matrix_compute {
48 60     60   298 Graph::TransitiveClosure::Matrix->new(@_);
49             }
50              
51             sub is_transitive {
52 10     10 1 471 my $g = shift;
53 10         53 $g->expect_no_args(@_);
54 10         28 Graph::TransitiveClosure::Matrix::is_transitive($g);
55             }
56              
57             sub transitive_closure_matrix {
58 12797     12797 1 25613 $_[0]->get_graph_attribute('_tcm')->[1];
59             }
60              
61             1;
62             __END__