File Coverage

blib/lib/Math/Cartesian/Product.pm
Criterion Covered Total %
statement 44 44 100.0
branch 12 14 85.7
condition n/a
subroutine 6 6 100.0
pod 0 1 0.0
total 62 65 95.3


line stmt bran cond sub pod time code
1             =head1 Name
2              
3             Math::Cartesian::Product - Generate the Cartesian product of zero or more lists.
4              
5             =head1 Synopsis
6              
7             use Math::Cartesian::Product;
8              
9             cartesian {print "@_\n"} [qw(a b c)], [1..2];
10              
11             # a 1
12             # a 2
13             # b 1
14             # b 2
15             # c 1
16             # c 2
17              
18             cartesian {print "@_\n"} ([0..1]) x 8;
19              
20             # 0 0 0 0 0 0 0 0
21             # 0 0 0 0 0 0 0 1
22             # 0 0 0 0 0 0 1 0
23             # ...
24             # 1 1 1 1 1 1 1 0
25             # 1 1 1 1 1 1 1 1
26              
27             =cut
28              
29             package Math::Cartesian::Product;
30              
31 1     1   16651 use Carp;
  1         2  
  1         72  
32 1     1   4 use strict;
  1         1  
  1         402  
33              
34 40     40 0 12452 sub cartesian(&@) # Generate the Cartesian product of zero or more lists
35             {my $s = shift; # Subroutine to call to process each element of the product
36              
37 40         70 my @C = @_; # Lists to be multiplied
38 40         46 my @c = (); # Current element of Cartesian product
39 40         52 my @P = (); # Cartesian product
40 40         51 my $n = 0; # Number of elements in product
41              
42             # return 0 if @C == 0; # Empty product per Philipp Rumpf
43              
44 40 50       78 @C == grep {ref eq 'ARRAY'} @C or croak("Arrays of things required by cartesian");
  60         174  
45              
46             # Generate each Cartesian product when there are no prior Cartesian products.
47              
48 40         38 my $p; $p = sub
  65753         85224  
49 2625881 100   2625881   2881127 {if (@c < @C)
50 65753         51987 {for(@{$C[@c]})
  2625843         1847759  
  2560128         3215338  
51             {push @c, $_;
52 2625843         2447594 &$p();
53 2625843         7070773 pop @c;
54             }
55             }
56             else
57             {my $p = [@c];
58 2560128 100       2951010 push @P, bless $p if &$s(@$p);
59             }
60 40         2065 };
61              
62             # Generate each Cartesian product allowing for prior Cartesian products.
63              
64 40         48 my $q; $q = sub
  10         14  
65 42 100   42   54 {if (@c < @C)
66 10 50       8 {for(@{$C[@c]})
  40         35  
  64         126  
67             {push @c, $_;
68 40         39 &$q();
69 40         134 pop @c;
70             }
71             }
72             else
73 32         24 {my $p = [map {ref eq __PACKAGE__ ? @$_ : $_} @c];
74 32 100       44 push @P, bless $p if &$s(@$p);
75             }
76 40         128 };
77              
78             # Determine optimal method of forming Cartesian products for this call
79              
80 40 100       63 if (grep {grep {ref eq __PACKAGE__} @$_} @C)
  60         84  
  267         309  
  2         4  
81 38         52 {&$q
82             }
83             else
84             {&$p
85             }
86              
87 40         103 $p = $q = undef; # Break memory loops per Philipp Rumpf
88             @P # Product
89 40         419303 }
90              
91             # Export details
92            
93             require 5;
94             require Exporter;
95              
96 1     1   7 use vars qw(@ISA @EXPORT $VERSION);
  1         6  
  1         141  
97              
98             @ISA = qw(Exporter);
99             @EXPORT = qw(cartesian);
100             $VERSION = '1.008'; # Monday 26 Jan 2015
101              
102             =head1 Description
103              
104             Generate the Cartesian product of zero or more lists.
105              
106             Given two lists, say: [a,b] and [1,2,3], the Cartesian product is the
107             set of all ordered pairs:
108              
109             (a,1), (a,2), (a,3), (b,1), (b,2), (b,3)
110              
111             which select their first element from all the possibilities listed in
112             the first list, and select their second element from all the
113             possibilities in the second list.
114              
115             The idea can be generalized to n-tuples selected from n lists where all the
116             elements of the first list are combined with all the elements of the second
117             list, the results of which are then combined with all the member of the third
118             list and so on over all the input lists.
119              
120             It should be noted that Cartesian product of one or more lists where one or
121             more of the lists are empty (representing the empty set) is the empty set
122             and thus has zero members; and that the Cartesian product of zero lists is a
123             set with exactly one member, namely the empty set.
124              
125             C takes the following parameters:
126              
127             1. A block of code to process each n-tuple. this code should return true
128             if the current n-tuple should be included in the returned value of the
129             C function, otherwise false.
130              
131             2. Zero or more lists.
132              
133             C returns an array of references to all the n-tuples
134             selected by the code block supplied as parameter 1.
135              
136             C croaks if you try to form the Cartesian product of
137             something other than lists of things.
138              
139             The cartesian product of lists A,B,C is associative, that is:
140              
141             (A X B) X C = A X (B X C)
142              
143             C respects associativity by allowing you to include a
144             Cartesian product produced by an earlier call to C in the
145             set of lists whose Cartesian product is to be formed, at the cost of a
146             performance penalty if this option is chosen.
147              
148             use Math::Cartesian::Product;
149            
150             my $a = [qw(a b)];
151             my $b = [cartesian {1} $a, $a];
152             cartesian {print "@_\n"} $b, $b;
153              
154             # a a a a
155             # a a a b
156             # a a b a
157             # ...
158            
159              
160             C is easy to use and fast. It is written in 100% Pure Perl.
161              
162              
163             =head1 Export
164              
165             The C function is exported.
166              
167             =head1 Installation
168              
169             Standard Module::Build process for building and installing modules:
170              
171             perl Build.PL
172             ./Build
173             ./Build test
174             ./Build install
175              
176             Or, if you're on a platform (like DOS or Windows) that doesn't require
177             the "./" notation, you can do this:
178              
179             perl Build.PL
180             Build
181             Build test
182             Build install
183              
184             =head1 Author
185              
186             PhilipRBrenan@appaapps.com
187              
188             http://www.appaapps.com
189              
190             =head1 Acknowledgements
191              
192             With much help and good natured advice from Philipp Rumpf to whom I am greatly indebted.
193              
194             =head1 See Also
195              
196             =over
197              
198             =item L
199              
200             =item L
201              
202             =item L
203              
204             =item L
205              
206             =back
207              
208             =head1 Copyright
209              
210             Copyright (c) 2009 Philip R Brenan.
211              
212             This module is free software. It may be used, redistributed and/or
213             modified under the same terms as Perl itself.
214              
215             =cut