File Coverage

blib/lib/Math/NumSeq/AllPrimeFactors.pm
Criterion Covered Total %
statement 63 66 95.4
branch 10 12 83.3
condition 2 3 66.6
subroutine 17 17 100.0
pod 5 5 100.0
total 97 103 94.1


line stmt bran cond sub pod time code
1             # Copyright 2012, 2013, 2014 Kevin Ryde
2              
3             # This file is part of Math-NumSeq.
4             #
5             # Math-NumSeq is free software; you can redistribute it and/or modify
6             # it under the terms of the GNU General Public License as published by the
7             # Free Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # Math-NumSeq 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 Math-NumSeq. If not, see .
17              
18             package Math::NumSeq::AllPrimeFactors;
19 1     1   1052 use 5.004;
  1         3  
20 1     1   4 use strict;
  1         1  
  1         30  
21 1     1   3 use Math::Prime::XS 0.23 'is_prime'; # version 0.23 fix for 1928099
  1         14  
  1         52  
22 1     1   4 use Math::Factor::XS 0.39 'prime_factors'; # version 0.39 for prime_factors()
  1         23  
  1         35  
23              
24 1     1   3 use vars '$VERSION', '@ISA';
  1         1  
  1         53  
25             $VERSION = 72;
26 1     1   4 use Math::NumSeq;
  1         1  
  1         26  
27             @ISA = ('Math::NumSeq');
28              
29 1     1   3 use Math::NumSeq 7; # v.7 for _is_infinite()
  1         8  
  1         28  
30             *_is_infinite = \&Math::NumSeq::_is_infinite;
31              
32 1     1   4 use Math::NumSeq::Primes;
  1         1  
  1         24  
33              
34             # uncomment this to run the ### lines
35             #use Smart::Comments;
36              
37              
38             # use constant name => Math::NumSeq::__('All Prime Factors');
39 1     1   4 use constant description => Math::NumSeq::__('Prime factors of the integers.');
  1         1  
  1         3  
40 1     1   4 use constant default_i_start => 1;
  1         1  
  1         34  
41 1     1   3 use constant characteristic_smaller => 1;
  1         2  
  1         122  
42              
43 1         3 use constant parameter_info_array =>
44             [
45             {
46             name => 'order',
47             display => Math::NumSeq::__('Order'),
48             share_key => 'order_as',
49             type => 'enum',
50             default => 'ascending',
51             choices => ['ascending','descending'],
52             choices_display => [Math::NumSeq::__('Ascending'),
53             Math::NumSeq::__('Descending'),
54             ],
55             description => Math::NumSeq::__('Order for the digits within each integer.'),
56             },
57             { name => 'multiplicity',
58             display => Math::NumSeq::__('Multiplicity'),
59             type => 'enum',
60             choices => ['repeated','distinct'],
61             choices_display => [Math::NumSeq::__('Repeated'),
62             Math::NumSeq::__('Distinct'),
63             ],
64             default => 'repeated',
65             description => Math::NumSeq::__('Whether to include repeated prime factors, or only distinct prime factors.'),
66             },
67             {
68             name => 'on_values',
69             display => Math::NumSeq::__('On Values'),
70             type => 'enum',
71             default => 'all',
72             choices => ['all','composites','odd','even'],
73             choices_display => [Math::NumSeq::__('All'),
74             Math::NumSeq::__('Composites'),
75             Math::NumSeq::__('Odd'),
76             Math::NumSeq::__('Even')],
77             description => Math::NumSeq::__('The values to take prime factors from, either all integers or just composites or odds or evens.'),
78             },
79 1     1   3 ];
  1         2  
80              
81             my %values_min = (all => 2,
82             composites => 2,
83             odd => 3,
84             even => 2);
85             sub values_min {
86 6     6 1 30 my ($self) = @_;
87 6         14 return $values_min{$self->{'on_values'}};
88             }
89              
90             #------------------------------------------------------------------------------
91             # cf A033308 - concatenate primes digits
92             # A056538 - list of all divisors
93              
94             my %oeis_anum;
95             $oeis_anum{'all'} ->{'repeated'}->{'ascending'} = 'A027746';
96             $oeis_anum{'composites'}->{'repeated'}->{'ascending'} = 'A109709';
97             $oeis_anum{'all'} ->{'distinct'}->{'ascending'} = 'A027748';
98              
99             sub oeis_anum {
100 6     6 1 16 my ($self) = @_;
101             return $oeis_anum{$self->{'on_values'}}
102             ->{$self->{'multiplicity'}}
103 6         17 ->{$self->{'order'}};
104             }
105              
106             #------------------------------------------------------------------------------
107             # ENHANCE-ME: find prime factors by sieve
108              
109             my %rewind = (all => [ n => 2-1, n_step => 1 ],
110             composites => [ n => 2-1, n_step => 1 ],
111             odd => [ n => 2-1, n_step => 2 ],
112             even => [ n => 2-2, n_step => 2 ]);
113             sub rewind {
114 18     18 1 2335 my ($self) = @_;
115             %$self = (%$self,
116 18         40 @{$rewind{$self->{'on_values'}}});
  18         91  
117 18         35 $self->{'pending'} = [ ];
118 18         45 $self->{'i'} = $self->i_start;
119             }
120              
121             sub next {
122 198     198 1 2012 my ($self) = @_;
123             ### AllDigits next(): $self->{'i'}
124              
125 198         125 my $value;
126 198         114 my $pending = $self->{'pending'};
127 198 100       258 unless (defined ($value = shift @$pending)) {
128 120         87 my $n = ($self->{'n'} += $self->{'n_step'});
129              
130 120 50       136 if ($self->{'on_values'} eq 'composites') {
131 0         0 while (is_prime($n)) {
132 0         0 $n = ++$self->{'n'};
133             }
134             }
135              
136 120         204 @$pending = prime_factors($n);
137 120 100       158 if ($self->{'multiplicity'} eq 'distinct') {
138 42         25 my $prev = 0;
139 42 100       27 @$pending = grep { $_ == $prev ? () : ($prev=$_) } @$pending;
  86         125  
140             }
141 120         74 my $order = $self->{'order'};
142 120 100       137 if ($order eq 'descending') {
143 20         21 @$pending = reverse @$pending;
144             }
145 120         96 $value = shift @$pending;
146             }
147 198         210 return ($self->{'i'}++, $value);
148             }
149              
150             sub pred {
151 99     99 1 259 my ($self, $value) = @_;
152 99 50 66     165 if ($self->{'on_values'} eq 'odd' && $value < 3) {
153 0         0 return 0;
154             }
155 99         134 return Math::NumSeq::Primes->pred($value);
156             }
157              
158             1;
159             __END__