File Coverage

blib/lib/Integer/Partition.pm
Criterion Covered Total %
statement 73 79 92.4
branch 39 42 92.8
condition 7 9 77.7
subroutine 6 6 100.0
pod 3 3 100.0
total 128 139 92.0


line stmt bran cond sub pod time code
1             # Integer::Partition.pm
2             #
3             # Copyright (c) 2007-2013 David Landgren
4             # All rights reserved
5              
6             package Integer::Partition;
7 3     3   67509 use strict;
  3         7  
  3         116  
8 3     3   17 use warnings;
  3         5  
  3         96  
9              
10 3     3   18 use vars qw/$VERSION/;
  3         8  
  3         3220  
11             $VERSION = '0.05';
12              
13             =head1 NAME
14              
15             Integer::Partition - Generate all integer partitions of an integer
16              
17             =head1 VERSION
18              
19             This document describes version 0.05 of Integer::Partition, released
20             2013-06-23.
21              
22             =head1 SYNOPSIS
23              
24             use Integer::Partition;
25              
26             my $i = Integer::Partition->new(4);
27             while (my $p = $i->next) {
28             print join( ' ', @$p ), $/;
29             }
30             # produces
31             4
32             3 1
33             2 2
34             2 1 1
35             1 1 1 1
36              
37             my $j = Integer::Partition->new(5, {lexicographic => 1});
38             while (my $p = $j->next) {
39             print join( ' ', @$p ), $/;
40             }
41             # produces
42             1 1 1 1 1
43             2 1 1 1
44             2 2 1
45             3 1 1
46             3 2
47             4 1
48             5
49              
50             =head1 DESCRIPTION
51              
52             C takes an integer number and produces an object
53             that can be used to generate all possible integer partitions of the
54             original number in either forward or reverse lexicographic order.
55              
56             =head1 METHODS
57              
58             =over 8
59              
60             =item new
61              
62             Creates a new C object. Takes an integer as a
63             parameter. By default, the partitions appear in reverse order, as
64             the algorithm is slightly faster. Forward ordering uses a different,
65             slightly slower algorithm (which is nonetheless much faster than
66             any existing algorithm).
67              
68             =cut
69              
70             sub new {
71 24     24 1 25492 my $class = shift;
72 24         37 my $n = shift;
73 24 50 33     257 if (!defined $n) {
    50          
    50          
74 0         0 require Carp;
75 0         0 Carp::croak("missing or undefined input");
76             }
77             elsif ($n =~ /\D/ or $n < 1) {
78 0         0 require Carp;
79 0         0 Carp::croak("$n is not a positive integer");
80             }
81             elsif ($n != int($n)) {
82 0         0 require Carp;
83 0         0 Carp::croak("$n is not an integer");
84             }
85 24         31 my $arg = shift;
86              
87 24         27 my $forward = 0;
88 24 100 100     132 if (defined $arg and ref($arg) eq 'HASH' and exists $arg->{lexicographic}) {
      100        
89 10         20 $forward = $arg->{lexicographic};
90             }
91              
92 24         29 my @x;
93 24 100       38 if ($forward) {
94 10         30 @x = (1) x ($n+1);
95 10         12 $x[0] = -1;
96             }
97             else {
98 14         36 @x = (1) x $n;
99 14         31 $x[0] = $n;
100             }
101              
102 24 100       150 my $self = {
    100          
103             n => $n,
104             x => \@x,
105             h => $forward ? 1 : 0,
106             m => $forward ? $n - 1 : 0,
107             count => 0,
108             forward => $forward,
109             };
110 24         87 return bless $self, $class;
111             }
112              
113             =item next
114              
115             Returns the partition, or C when all partitions have been
116             generated.
117              
118             =cut
119              
120             sub next {
121 316     316 1 315136 my $self = shift;
122 316 100       968 if ($self->{forward}) {
123 157 100       854 if (++$self->{count} == 1) {
    100          
    100          
124 19         56 return [@{$self->{x}}[1..$self->{n}]];
  19         80  
125             }
126             elsif ($self->{x}[1] == $self->{n}) {
127 10         24 return;
128             }
129             elsif ($self->{count} == 2) {
130 9         17 $self->{x}[1] = 2;
131 9         26 return [@{$self->{x}}[1..$self->{n}-1]];
  9         39  
132             }
133             else {
134 119 100       321 if ($self->{m} - $self->{h} > 1) {
135 58         120 $self->{x}[++$self->{h}] = 2;
136 58         194 --$self->{m};
137             }
138             else {
139 61         140 my $j = $self->{m} - 2;
140 61         207 while ($self->{x}[$j] == $self->{x}[$self->{m}-1]) {
141 26         96 $self->{x}[$j--] = 1;
142             }
143 61         110 $self->{h} = $j + 1;
144 61         410 $self->{x}[$self->{h}] = $self->{x}[$self->{m}-1] + 1;
145 61         327 my $r = $self->{x}[$self->{m}]
146             + $self->{x}[$self->{m} - 1] * ($self->{m} - $self->{h} - 1);
147 61         102 $self->{x}[$self->{m}] = 1;
148 61 100       179 $self->{x}[$self->{m}-1] = 1 if $self->{m} - $self->{h} > 1;
149 61         119 $self->{m} = $self->{h} + $r - 1;
150             }
151 119         353 return [@{$self->{x}}[1..$self->{m}]];
  119         517  
152             }
153             }
154              
155 159 100       748 return [$self->{n}] unless $self->{count}++;
156 138 100       405 return if $self->{x}[0] == 1;
157              
158 128 100       376 if ($self->{x}[$self->{h}] == 2) {
159 67         95 ++$self->{m};
160 67         147 $self->{x}[$self->{h}--] = 1;
161             }
162             else {
163 61         137 my $r = $self->{x}[$self->{h}] - 1;
164 61         154 $self->{x}[$self->{h}] = $r;
165              
166 61         263 my $t = $self->{m} - $self->{h} + 1;
167 61         190 while ($t >= $r) {
168 42         92 $self->{x}[++$self->{h}] = $r;
169 42         100 $t -= $r;
170             }
171 61 100       169 $self->{m} = $self->{h} + ($t ? 1 : 0);
172 61 100       173 $t > 1 and $self->{x}[++$self->{h}] = $t;
173             }
174 128         276 return [@{$self->{x}}[0..$self->{m}]];
  128         508  
175             }
176              
177             =item reset
178              
179             Resets the object, which causes it to enumerate the arrangements from the
180             beginning.
181              
182             $p->reset; # begin again
183              
184             =cut
185              
186             sub reset {
187 19     19 1 5795 my $self = shift;
188 19         191 my $n = $self->{n};
189 19         24 my @x;
190 19 100       50 if ($self->{forward}) {
191 9         33 @x = (1) x ($n+1);
192 9         16 $x[0] = -1;
193             }
194             else {
195 10         38 @x = (1) x $n;
196 10         58 $x[0] = $n;
197             }
198 19         37 $self->{x} = \@x;
199 19 100       98 $self->{m} = $self->{forward} ? $n - 1 : 0,
    100          
200             $self->{h} = $self->{forward} ? 1 : 0,
201             $self->{count} = 0;
202 19         43 return $self;
203             }
204              
205             =back
206              
207             =head1 DIAGNOSTICS
208              
209             =head2 missing or undefined input
210              
211             The C method was called without an input parameter, which
212             should be a positive integer.
213              
214             =head2 C is not a positive integer
215              
216             The C method was called with zero or a negative integer.
217              
218             =head2 C is not an integer
219              
220             The C method was called with a number containing a decimal
221             component. Use C or C on the input if necessary.
222              
223             =head1 NOTES
224              
225             This module implements the Zoghbi and Stojmenovic ZS1 and ZS2
226             algorithms for generating integer partitions. See
227             L for more
228             information. These algorithms have been proven to have constant
229             average delay, that is, the amount of effort it takes to produce
230             the next result in the series.
231              
232             They are the fastest known algorithms known for generating integer
233             partitions (with the ZS1 reverse lexicographic order algorithm being
234             slightly faster than the ZS2 lexicographic order algorithm).
235              
236             =head1 SEE ALSO
237              
238             =over 8
239              
240             =item *
241              
242             L
243              
244             The Wikipedia entry on integer partitions
245              
246             =item *
247              
248             L
249              
250             The original 1998 paper written by Zoghbi and Stojmenovic.
251              
252             =back
253              
254             =head1 BUGS
255              
256             None known.
257              
258             Please report all bugs at
259             L
260              
261             Make sure you include the output from the following two commands:
262              
263             perl -MInteger::Partition -le 'print $Integer::Partition::VERSION'
264             perl -V
265              
266             Pull requests on Github may be issued at
267             L.
268              
269             =head1 ACKNOWLEDGEMENTS
270              
271             Thanks to Antoine Zoghbi and Ivan Stojmenovic, for sharing their
272             discovery with the world on the internet, and not hiding it in
273             behind some sort of pay-wall.
274              
275             =head1 AUTHOR
276              
277             David Landgren, copyright (C) 2007-2013. All rights reserved.
278              
279             http://www.landgren.net/perl/
280              
281             If you (find a) use this module, I'd love to hear about it. If you
282             want to be informed of updates, send me a note. You know my first
283             name, you know my domain. Can you guess my e-mail address?
284              
285             =head1 LICENSE
286              
287             This library is free software; you can redistribute it and/or modify
288             it under the same terms as Perl itself.
289              
290             =cut
291              
292             'The Lusty Decadent Delights of Imperial Pompeii';
293             __END__