Math-Cartesian-Product-1.009000755001751001751 012564671672 15036 5ustar00philphil000000000000Math-Cartesian-Product-1.009/META.json000444001751001751 146612564671672 16623 0ustar00philphil000000000000{ "abstract" : "Generate the cartesian product of zero or more lists.", "author" : [ "PhilipRBrenan@appaapps.com" ], "dynamic_config" : 1, "generated_by" : "Module::Build version 0.4211", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : "2" }, "name" : "Math-Cartesian-Product", "prereqs" : { "configure" : { "requires" : { "Module::Build" : "0.42" } } }, "provides" : { "Math::Cartesian::Product" : { "file" : "lib/Math/Cartesian/Product.pm", "version" : "1.009" } }, "release_status" : "stable", "resources" : { "license" : [ "http://dev.perl.org/licenses/" ] }, "version" : "1.009" } Math-Cartesian-Product-1.009/MANIFEST000444001751001751 14212564671672 16301 0ustar00philphil000000000000lib/Math/Cartesian/Product.pm CHANGES Build.PL MANIFEST META.yml README t/test.t META.json Math-Cartesian-Product-1.009/Build.PL000444001751001751 47012564671672 16450 0ustar00philphil000000000000use Module::Build; my $b = Module::Build->new (module_name => 'Math::Cartesian::Product', dist_author => 'PhilipRBrenan@appaapps.com', dist_abstract => 'Generate the cartesian product of zero or more lists.', license => 'perl', create_readme => 1, ); $b->create_build_script(); Math-Cartesian-Product-1.009/README000444001751001751 773312564671672 16065 0ustar00philphil000000000000Name Math::Cartesian::Product - Generate the Cartesian product of zero or more lists. Synopsis use Math::Cartesian::Product; cartesian {print "@_\n"} [qw(a b c)], [1..2]; # a 1 # a 2 # b 1 # b 2 # c 1 # c 2 cartesian {print "@_\n"} ([0..1]) x 8; # 0 0 0 0 0 0 0 0 # 0 0 0 0 0 0 0 1 # 0 0 0 0 0 0 1 0 # ... # 1 1 1 1 1 1 1 0 # 1 1 1 1 1 1 1 1 print "@$_\n" for cartesian {"@{[reverse @_]}" eq "@_"} ([' ', '*']) x 8; # * * # * * # * * * * # * * # * * * * # * * * * # * * * * * * # * * # * * * * # * * * * # * * * * * * # * * * * # * * * * * * # * * * * * * # * * * * * * * * Description Generate the Cartesian product of zero or more lists. Given two lists, say: [a,b] and [1,2,3], the Cartesian product is the set of all ordered pairs: (a,1), (a,2), (a,3), (b,1), (b,2), (b,3) which select their first element from all the possibilities listed in the first list, and select their second element from all the possibilities in the second list. The idea can be generalized to n-tuples selected from n lists where all the elements of the first list are combined with all the elements of the second list, the results of which are then combined with all the member of the third list and so on over all the input lists. It should be noted that Cartesian product of one or more lists where one or more of the lists are empty (representing the empty set) is the empty set and thus has zero members; and that the Cartesian product of zero lists is a set with exactly one member, namely the empty set. "cartesian()" takes the following parameters: 1. A block of code to process each n-tuple. this code should return true if the current n-tuple should be included in the returned value of the "cartesian()" function, otherwise false. 2. Zero or more lists. "cartesian()" returns an array of references to all the n-tuples selected by the code block supplied as parameter 1 if called in list context, else it returns a count of the selected n-tuples. "cartesian()" croaks if you try to form the Cartesian product of something other than lists of things or prior Cartesian products. The cartesian product of lists A,B,C is associative, that is: (A X B) X C = A X (B X C) "cartesian()" respects associativity by allowing you to include a Cartesian product produced by an earlier call to "cartesian()" in the set of lists whose Cartesian product is to be formed, at the cost of a performance penalty if this option is chosen. use Math::Cartesian::Product; my $a = [qw(a b)]; my $b = [cartesian {1} $a, $a]; cartesian {print "@_\n"} $b, $b; # a a a a # a a a b # a a b a # ... "cartesian()" is easy to use and fast. It is written in 100% Pure Perl. Export The "cartesian()" function is exported. Installation Standard Module::Build process for building and installing modules: perl Build.PL ./Build ./Build test ./Build install Or, if you're on a platform (like DOS or Windows) that doesn't require the "./" notation, you can do this: perl Build.PL Build Build test Build install Author Philip R Brenan at gmail dot com http://www.appaapps.com Acknowledgements With much help and good natured advice from Philipp Rumpf and Justin Case to whom I am indebted. See Also Math::Disarrange::List Math::Permute::List Math::Permute::Lists Math::Permute::Partitions Math::Subsets::List Math::Transform::List Copyright Copyright (c) 2009-2015 Philip R Brenan. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself. Math-Cartesian-Product-1.009/CHANGES000444001751001751 50012564671672 16141 0ustar00philphil000000000000Change Log 1.006 18 Apr 2009 Initial release 1.007 26 Jan 2015 Break memory loop, empty cartesian products and additional tests per Philipp Rumpf 1.008 28 Jan 2015 Improved documentation and tests on the empty product per Philipp Rumpf 1.009 18 Aug 2015 Results array not built in void or scalar context per Justin Case Math-Cartesian-Product-1.009/META.yml000444001751001751 110112564671672 16435 0ustar00philphil000000000000--- abstract: 'Generate the cartesian product of zero or more lists.' author: - PhilipRBrenan@appaapps.com build_requires: {} configure_requires: Module::Build: '0.42' dynamic_config: 1 generated_by: 'Module::Build version 0.4211, CPAN::Meta::Converter version 2.143240' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Math-Cartesian-Product provides: Math::Cartesian::Product: file: lib/Math/Cartesian/Product.pm version: '1.009' resources: license: http://dev.perl.org/licenses/ version: '1.009' Math-Cartesian-Product-1.009/t000755001751001751 012564671672 15301 5ustar00philphil000000000000Math-Cartesian-Product-1.009/t/test.t000444001751001751 1471612564671672 16633 0ustar00philphil000000000000use Test::More tests=>88; use Math::Cartesian::Product; use warnings FATAL => qw(all); use strict; # 0 {ok 0 == cartesian {}; ok 1 == cartesian {1}; {my $r = cartesian {1}; ok 1 == $r;} # Called in scalar context {my @r = cartesian {1}; ok 0 == length(join ",", map {join '', @$_} @r)} # Called in array context } # 3 {my $a = ''; ok 0 == cartesian {0} [qw(a b c)]; ok 1 == cartesian {shift() eq 'b'} [qw(a b c)]; ok 2 == cartesian {shift() ne 'b'} [qw(a b c)]; ok 3 == cartesian {$a .= "@_\n"; 1} [qw(a b c)]; ok $a eq << "end"; a b c end {my $r = cartesian {1} [qw(a b c)]; ok 3 == $r} # Called in scalar context {my @r = cartesian {1} [qw(a b c)]; ok "a,b,c" eq join ",", map {join '', @$_} @r} # Called in array context } # 3*2 {my $a = ''; ok 6 == cartesian {$a .= "@_\n"; 1} [qw(a b c)], [1,2]; ok $a eq << "end"; a 1 a 2 b 1 b 2 c 1 c 2 end {my $r = cartesian {1} [qw(a b c)], [1,2]; ok 6 == $r} # Called in scalar context {my @r = cartesian {1} [qw(a b c)], [1,2]; ok "a1,a2,b1,b2,c1,c2" eq join ",", map {join '', @$_} @r} # Called in array context } # 3*2*0 {my $a = ''; ok 0 == cartesian {$a .= "@_\n"; 1} [qw(a b c)], [1,2], []; ok $a eq << "end"; end {my $r = cartesian {1} [qw(a b c)], [1,2], []; ok 0 == $r} # Called in scalar context {my @r = cartesian {1} [qw(a b c)], [1,2], []; ok 0 == length(join ",", map {join '', @$_} @r)} # Called in array context } # 2*2*2*2 {my $a = ''; my $b = [qw(a b)]; ok 16 == cartesian {$a .= "@_\n"; 1} $b,$b,$b,$b; ok $a eq << "end"; a a a a a a a b a a b a a a b b a b a a a b a b a b b a a b b b b a a a b a a b b a b a b a b b b b a a b b a b b b b a b b b b end } # (2*2)*(2*2) {my $a = ''; my $b = [qw(a b)]; my $c = [cartesian {$a .= "@_\n"; 1} $b,$b]; ok 4 == @$c; ok $a eq << "end"; a a a b b a b b end my $d = ''; ok 16 == cartesian {$d .= "@_\n"; 1} $c, $c; ok $d eq << "end"; a a a a a a a b a a b a a a b b a b a a a b a b a b b a a b b b b a a a b a a b b a b a b a b b b b a a b b a b b b b a b b b b end ok 8 == cartesian {$_[1] eq 'a'} $c, $c; {my $r = cartesian {my @a = reverse @_; "@a" eq "@_"} $c, $c; ok 4 == $r} {my @r = cartesian {my @a = reverse @_; "@a" eq "@_"} $c, $c; ok "aaaa,abba,baab,bbbb" eq join ",", map {join '', @$_} @r} {my @r = cartesian {my @a = sort @_; "@a" eq "@_"} $c, $c; ok "aaaa,aaab,aabb,abbb,bbbb" eq join ",", map {join '', @$_} @r} {my @r = cartesian {my @a = reverse sort @_; "@a" eq "@_"} $c, $c; ok "aaaa,baaa,bbaa,bbba,bbbb" eq join ",", map {join '', @$_} @r} } # (3*3)*3*(3*3) {my $a = ''; my $b = [qw(a b c)]; my $c = [cartesian {$a .= "@_\n"; 1} $b,$b]; ok 9 == @$c; ok $a eq << "end"; a a a b a c b a b b b c c a c b c c end ok 81 == cartesian {$_[1] eq 'a'} $c, $b, $c; {my $r = cartesian {my @a = reverse @_; "@a" eq "@_"} $c, $b, $c; ok 27 == $r} {my @r = cartesian {my @a = reverse @_; "@a" eq "@_"} $c, $b, $c; ok "aaaaa,aabaa,aacaa,ababa,abbba,abcba,acaca,acbca,accca,baaab,babab,bacab,bbabb,bbbbb,bbcbb,bcacb,bcbcb,bcccb,caaac,cabac,cacac,cbabc,cbbbc,cbcbc,ccacc,ccbcc,ccccc" eq join ",", map {join '', @$_} @r} {my @r = cartesian {my @a = sort @_; "@a" eq "@_"} $c, $b, $c; ok "aaaaa,aaaab,aaaac,aaabb,aaabc,aaacc,aabbb,aabbc,aabcc,aaccc,abbbb,abbbc,abbcc,abccc,acccc,bbbbb,bbbbc,bbbcc,bbccc,bcccc,ccccc" eq join ",", map {join '', @$_} @r} {my @r = cartesian {my @a = reverse sort @_; "@a" eq "@_"} $c, $b, $c; ok "aaaaa,baaaa,bbaaa,bbbaa,bbbba,bbbbb,caaaa,cbaaa,cbbaa,cbbba,cbbbb,ccaaa,ccbaa,ccbba,ccbbb,cccaa,cccba,cccbb,cccca,ccccb,ccccc" eq join ",", map {join '', @$_} @r} } # 2**8 {my $b = ['0', '1']; my @c = cartesian {my @r = reverse @_; "@r" eq "@_"} map {$b} 1..8; ok 16 == @c; my $c = join "\n", map {join '', @$_} @c; my $r = << "end"; chomp($r); 00000000 00011000 00100100 00111100 01000010 01011010 01100110 01111110 10000001 10011001 10100101 10111101 11000011 11011011 11100111 11111111 end ok $c eq $r; } # 40*40*40*40 {my $a = [1..40]; ok 2_560_000 == cartesian {1} $a,$a,$a,$a; } # Tests from Philipp Rumpf # The empty product contains one element, the empty list {my $a = ''; ok 1 == cartesian { $a .= "@_\n" }; ok $a eq "\n"; } {ok 0 == @{[cartesian {1}]->[0]}; ok defined [cartesian {1}]->[0]; ok ref([cartesian {1}]->[0]) =~ /Math::Cartesian::Product/; ok defined([cartesian {1}]->[0]); } # Including the empty set in the product list produces the empty set {my $a = ''; ok 0 == cartesian { $a .= "@_\n" } []; ok $a eq ''; } {my $a = ''; ok 0 == cartesian { $a .= "@_\n" } [], []; ok $a eq ''; } {my $a = ''; ok 0 == cartesian { $a .= "@_\n" } [], [], []; ok $a eq ''; } {my $a = ''; ok 0 == cartesian { $a .= "@_\n" } [1,2,3], []; ok $a eq ''; } {my $a = ''; ok 0 == cartesian { $a .= "@_\n" } [], [1,2,3]; ok $a eq ''; } {my $a = ''; ok 0 == cartesian { $a .= "@_\n" } [], [1,2,3], []; ok $a eq ''; } # Cartesian products split, so the cartesian product of (@a,@b) can be # achieved by taking the cartesian product of @a inside the cartesian # product of @b. {my @a = ([1,2]); my @b = ([3,4]); my $a = ''; ok 2 == cartesian { my @c = @_; cartesian { my @d = (@c, @_); $a .= "@d\n"} @b } @a; my $b = ''; ok 4 == cartesian { $b .= "@_\n"} @a, @b; ok $a eq $b; } # Cartesian products split even when the first list is empty {my @a = (); my @b = ([2,3]); my $a = ''; ok 1 == cartesian { my @c = @_; cartesian { my @d = (@c, @_); $a .= "@d\n"} @b } @a; my $b = ''; ok 2 == cartesian { $b .= "@_\n"} @a, @b; ok $a eq $b; } # Cartesian products split even when the second list is empty {my @a = ([1,2]); my @b = (); my $a = ''; ok 2 == cartesian { my @c = @_; cartesian { my @d = (@c, @_); $a .= "@d\n"} @b } @a; my $b = ''; ok 2 == cartesian { $b .= "@_\n"} @a, @b; ok $a eq $b; } # Exponentiation can be performed using the cartesian product {my @a = ([1,2]); ok 2**$_ == cartesian {1} ((@a) x $_) for 0..20 } Math-Cartesian-Product-1.009/lib000755001751001751 012564671672 15604 5ustar00philphil000000000000Math-Cartesian-Product-1.009/lib/Math000755001751001751 012564671672 16475 5ustar00philphil000000000000Math-Cartesian-Product-1.009/lib/Math/Cartesian000755001751001751 012564671672 20406 5ustar00philphil000000000000Math-Cartesian-Product-1.009/lib/Math/Cartesian/Product.pm000444001751001751 1361112564671672 22543 0ustar00philphil000000000000=head1 Name Math::Cartesian::Product - Generate the Cartesian product of zero or more lists. =head1 Synopsis use Math::Cartesian::Product; cartesian {print "@_\n"} [qw(a b c)], [1..2]; # a 1 # a 2 # b 1 # b 2 # c 1 # c 2 cartesian {print "@_\n"} ([0..1]) x 8; # 0 0 0 0 0 0 0 0 # 0 0 0 0 0 0 0 1 # 0 0 0 0 0 0 1 0 # ... # 1 1 1 1 1 1 1 0 # 1 1 1 1 1 1 1 1 print "@$_\n" for cartesian {"@{[reverse @_]}" eq "@_"} ([' ', '*']) x 8; # * * # * * # * * * * # * * # * * * * # * * * * # * * * * * * # * * # * * * * # * * * * # * * * * * * # * * * * # * * * * * * # * * * * * * # * * * * * * * * =cut package Math::Cartesian::Product; use Carp; use strict; sub cartesian(&@) # Generate the Cartesian product of zero or more lists {my $s = shift; # Subroutine to call to process each element of the product my @C = @_; # Lists to be multiplied my @c = (); # Current element of Cartesian product my @P = (); # Cartesian product my $n = 0; # Number of elements in product # return 0 if @C == 0; # Empty product per Philipp Rumpf @C == grep {ref eq 'ARRAY'} @C or croak("Arrays of things required by cartesian"); # Generate each Cartesian product when there are no prior Cartesian products. # The first variant builds the results array, the second does not per Justin Case my $p; $p = wantarray() ? sub {if (@c < @C) {for(@{$C[@c]}) {push @c, $_; &$p(); pop @c; } } else {my $p = [@c]; push @P, bless $p if &$s(@$p); } } : sub # List not required per Justin Case {if (@c < @C) {for(@{$C[@c]}) {push @c, $_; &$p(); pop @c; } } else {++$n if &$s(@c); } }; # Generate each Cartesian product allowing for prior Cartesian products. my $q; $q = wantarray() ? sub {if (@c < @C) {for(@{$C[@c]}) {push @c, $_; &$q(); pop @c; } } else {my $p = [map {ref eq __PACKAGE__ ? @$_ : $_} @c]; push @P, bless $p if &$s(@$p); } } : sub # List not required per Justin Case {if (@c < @C) {for(@{$C[@c]}) {push @c, $_; &$q(); pop @c; } } else {++$n if &$s(map {ref eq __PACKAGE__ ? @$_ : $_} @c); } }; # Determine optimal method of forming Cartesian products for this call if (grep {grep {ref eq __PACKAGE__} @$_} @C) {&$q } else {&$p } $p = $q = undef; # Break memory loops per Philipp Rumpf wantarray() ? @P : $n # Product or count per Justin Case } # Export details require 5; require Exporter; use vars qw(@ISA @EXPORT $VERSION); @ISA = qw(Exporter); @EXPORT = qw(cartesian); $VERSION = '1.009'; # Tuesday 18 Aug 2015 =head1 Description Generate the Cartesian product of zero or more lists. Given two lists, say: [a,b] and [1,2,3], the Cartesian product is the set of all ordered pairs: (a,1), (a,2), (a,3), (b,1), (b,2), (b,3) which select their first element from all the possibilities listed in the first list, and select their second element from all the possibilities in the second list. The idea can be generalized to n-tuples selected from n lists where all the elements of the first list are combined with all the elements of the second list, the results of which are then combined with all the member of the third list and so on over all the input lists. It should be noted that Cartesian product of one or more lists where one or more of the lists are empty (representing the empty set) is the empty set and thus has zero members; and that the Cartesian product of zero lists is a set with exactly one member, namely the empty set. C takes the following parameters: 1. A block of code to process each n-tuple. this code should return true if the current n-tuple should be included in the returned value of the C function, otherwise false. 2. Zero or more lists. C returns an array of references to all the n-tuples selected by the code block supplied as parameter 1 if called in list context, else it returns a count of the selected n-tuples. C croaks if you try to form the Cartesian product of something other than lists of things or prior Cartesian products. The cartesian product of lists A,B,C is associative, that is: (A X B) X C = A X (B X C) C respects associativity by allowing you to include a Cartesian product produced by an earlier call to C in the set of lists whose Cartesian product is to be formed, at the cost of a performance penalty if this option is chosen. use Math::Cartesian::Product; my $a = [qw(a b)]; my $b = [cartesian {1} $a, $a]; cartesian {print "@_\n"} $b, $b; # a a a a # a a a b # a a b a # ... C is easy to use and fast. It is written in 100% Pure Perl. =head1 Export The C function is exported. =head1 Installation Standard Module::Build process for building and installing modules: perl Build.PL ./Build ./Build test ./Build install Or, if you're on a platform (like DOS or Windows) that doesn't require the "./" notation, you can do this: perl Build.PL Build Build test Build install =head1 Author Philip R Brenan at gmail dot com http://www.appaapps.com =head1 Acknowledgements With much help and good natured advice from Philipp Rumpf and Justin Case to whom I am indebted. =head1 See Also =over =item L =item L =item L =item L =item L =item L =back =head1 Copyright Copyright (c) 2009-2015 Philip R Brenan. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself. =cut