File Coverage

blib/lib/Graph/Maker/Johnson.pm
Criterion Covered Total %
statement 6 8 75.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 9 11 81.8


line stmt bran cond sub pod time code
1             # Copyright 2015, 2016, 2017 Kevin Ryde
2             #
3             # This file is part of Graph-Maker-Other.
4             #
5             # This file is free software; you can redistribute it and/or modify it
6             # under the terms of the GNU General Public License as published by the Free
7             # Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # This file is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Graph-Maker-Other. See the file COPYING. If not, see
17             # .
18              
19             package Graph::Maker::Johnson;
20 1     1   728 use 5.004;
  1         4  
21 1     1   5 use strict;
  1         1  
  1         18  
22 1     1   92 use Graph::Maker;
  0            
  0            
23              
24             use vars '$VERSION','@ISA';
25             $VERSION = 7;
26             @ISA = ('Graph::Maker');
27              
28             # uncomment this to run the ### lines
29             # use Smart::Comments;
30              
31              
32             sub _default_graph_maker {
33             require Graph;
34             return Graph->new(@_);
35             }
36             sub _make_graph {
37             my ($params) = @_;
38             my $graph_maker = delete($params->{'graph_maker'}) || \&_default_graph_maker;
39             return $graph_maker->(%$params);
40             }
41              
42             # $aref and $bref are arrayrefs of integers sorted in ascending order.
43             # Return the number of integers common to both arrays.
44             sub _sorted_arefs_count_same {
45             my ($aref, $bref) = @_;
46             my $i = 0;
47             my $j = 0;
48             my $count = 0;
49             while ($i <= $#$aref && $j <= $#$bref) {
50             if ($aref->[$i] == $bref->[$j]) {
51             $count++;
52             $i++;
53             $j++;
54             } elsif ($aref->[$i] < $bref->[$j]) {
55             $i++;
56             } else {
57             $j++;
58             }
59             }
60             return $count;
61             }
62              
63             # Return a list of arrayrefs which contain all the $K element subsets of
64             # integers 1 to $N. The integers in each subset are in ascending order.
65             # The order of the subsets themselves is unspecified.
66             #
67             sub _N_K_subsets {
68             my ($N, $K) = @_;
69              
70             # $pos is 0 to $K-1
71             # $upto[$pos] to maximum $N-($K-1)+$pos
72             # the top $upto[$K-1] runs to maximum $N-($K-1)+($K-1) = $N
73             # so $upto[$pos] <= $N-$K+1+$pos
74             my @ret;
75             my @upto = (0);
76             my $pos = 0;
77             my $limit = $N-$K+1;
78             for (;;) {
79             ### @upto
80             ### $pos
81             if (++$upto[$pos] > $limit+$pos) {
82             # backtrack
83             if (--$pos < 0) {
84             last;
85             }
86             } else {
87             if (++$pos >= $K) {
88             ### subset: "@upto"
89             push @ret, [@upto];
90             $pos--;
91             } else {
92             $upto[$pos] = $upto[$pos-1];
93             }
94             }
95             }
96             return @ret;
97             }
98              
99              
100             sub init {
101             my ($self, %params) = @_;
102              
103             my $N = delete($params{'N'}) || 0;
104             my $K = delete($params{'K'}) || 0;
105             ### $N
106             ### $K
107             my $graph = _make_graph(\%params);
108              
109             $graph->set_graph_attribute (name => "Johnson $N,$K");
110             my $directed = $graph->is_directed;
111              
112             my @vertices = _N_K_subsets($N,$K);
113             foreach my $v (@vertices) {
114             $graph->add_vertex(join(',',@$v));
115             }
116              
117             foreach my $i_from (0 .. $#vertices-1) {
118             my $from = $vertices[$i_from];
119             foreach my $i_to ($i_from+1 .. $#vertices) {
120             my $to = $vertices[$i_to];
121             ### consider: "from=".join(',',@$from)." to=".join(',',@$to)
122              
123             my $count = _sorted_arefs_count_same($from, $to);
124             ### $count
125             if ($count == $K - 1) {
126             my $v_from = join(',',@$from);
127             my $v_to = join(',',@$to);
128             ### edge: "$v_from to $v_to"
129             $graph->add_edge($v_from, $v_to);
130             if ($directed) { $graph->add_edge($v_to, $v_from); }
131             }
132             }
133             }
134             return $graph;
135             }
136              
137             Graph::Maker->add_factory_type('Johnson' => __PACKAGE__);
138             1;
139              
140             __END__