File Coverage

blib/lib/Math/NumSeq/PrimeIndexPrimes.pm
Criterion Covered Total %
statement 65 65 100.0
branch 8 10 80.0
condition n/a
subroutine 13 13 100.0
pod 5 5 100.0
total 91 93 97.8


line stmt bran cond sub pod time code
1             # Copyright 2011, 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              
19             # http://www.cs.uwaterloo.ca/journals/JIS/VOL12/Broughan/broughan16.pdf
20             # http://www.borve.org/primeness/FOP.html
21              
22              
23             package Math::NumSeq::PrimeIndexPrimes;
24 1     1   1060 use 5.004;
  1         2  
25 1     1   4 use strict;
  1         2  
  1         24  
26              
27 1     1   3 use vars '$VERSION', '@ISA';
  1         1  
  1         59  
28             $VERSION = 72;
29 1     1   6 use Math::NumSeq;
  1         3  
  1         41  
30             @ISA = ('Math::NumSeq');
31              
32 1     1   5 use Math::NumSeq::Primes;
  1         2  
  1         28  
33              
34             # uncomment this to run the ### lines
35             #use Smart::Comments;
36              
37 1     1   4 use constant description => Math::NumSeq::__('The primes whose index in the list of primes is also a prime.');
  1         1  
  1         3  
38 1     1   3 use constant characteristic_increasing => 1;
  1         2  
  1         73  
39              
40 1         3 use constant parameter_info_array =>
41             [ { name => 'level',
42             share_key => 'prime_index_primes_level',
43             display => Math::NumSeq::__('Level'),
44             type => 'integer',
45             default => 2,
46             minimum => 0,
47             width => 2,
48             description => Math::NumSeq::__('The level of prime-index repetition.'),
49             },
50             { name => 'level_type',
51             display => Math::NumSeq::__('Level Type'),
52             type => 'enum',
53             default => 'minimum',
54             choices => ['minimum','exact',
55             # 'maximum'
56             ],
57             },
58 1     1   3 ];
  1         1  
59              
60             #------------------------------------------------------------------------------
61             # cf A175247 primes at non-composite, including 1 as non-composite
62             # A007097 a(n+1) = a(n)'th prime, growing recurrence
63             # A058010 order of primeness diagonal
64              
65             my %oeis_anum
66             = (minimum => [
67             'A000027', # level=0 # integers 1 up
68             # OEIS-Other: A000027 level=0
69              
70             'A000040', # level=1 # all primes, F(p) >= 1
71             # OEIS-Other: A000040 level=1
72              
73             # OEIS-Catalogue array begin
74             'A006450', # # prime index primes F(p) >= 2
75             'A038580', # level=3 # F(p) >= 3
76             'A049090', # level=4 # F(p) > 3 is F(p) >= 4
77             'A049203', # level=5
78             'A049202', # level=6
79             'A057849', # level=7
80             'A057850', # level=8
81             'A057851', # level=9
82             'A057847', # level=10
83             'A058332', # level=11
84             'A093047', # level=12 # F(p)>11 is F(p)>=12
85             'A093046', # level=13
86             # OEIS-Catalogue array end
87             ],
88             exact => [
89             # OEIS-Catalogue array begin
90             'A018252', # level_type=exact level=0 # composites 1 up
91             'A007821', # level_type=exact level=1 # primes at compos ind
92             'A049078', # level_type=exact # F(p)=2
93             'A049079', # level_type=exact level=3
94             'A049080', # level_type=exact level=4
95             'A049081', # level_type=exact level=5
96             # OEIS-Catalogue array end
97             ],
98             );
99             sub oeis_anum {
100 6     6 1 19 my ($self) = @_;
101 6         15 return $oeis_anum{$self->{'level_type'}}->[$self->{'level'}];
102             }
103              
104             #------------------------------------------------------------------------------
105              
106             # First value of desired order is exactly that order, so same values_min()
107             # for level_type "minimum" or "exact".
108             #
109             sub values_min {
110 6     6 1 21 my ($self) = @_;
111              
112 6 50       14 if (! defined $self->{'values_min'}) {
113 6         14 my $seq = Math::NumSeq::Primes->new;
114 6         7 my $target = 1;
115 6         10 foreach (1 .. $self->{'level'}) {
116 6         6 my ($i, $prime);
117 6         6 do {
118 6         16 ($i, $prime) = $seq->next;
119             } until ($i >= $target);
120 6         12 $target = $prime;
121             }
122 6         20 $self->{'values_min'} = $target;
123             }
124 6         12 return $self->{'values_min'};
125             }
126              
127             # primes, level=0
128             # 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
129             # 1 2 3 4 5 6 7 8 9 10 11 12 13
130             # ^ ^ ^ ^ ^ ^
131             # prime-index-primes, level=1
132             # 3, 5, 11, 17, 31, 41, 59, 67,
133             #
134             # prime-index-primes, level=2
135             # 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67,
136             # 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
137             # ^ ^ ^ ^
138             # 5, 11, 31, 59,
139              
140             #
141             # exact level=1 A007821 2,7,13,19,23,29,37,43,47,53,61,71,73,79,
142             # exact level=2 A049078 3,17,41,67,83,109,157,191,211,241,283,353,
143             #
144              
145             sub rewind {
146 18     18 1 2285 my ($self) = @_;
147 18         40 $self->{'i'} = $self->i_start;
148 18         20 $self->{'target'} = 1;
149 18         34 $self->{'seqs'} = [ map { Math::NumSeq::Primes->new } 1 .. $self->{'level'} ];
  18         56  
150 18 100       76 if ($self->{'level_type'} ne 'minimum') {
151 9         18 $self->{'initial_seq'} = Math::NumSeq::Primes->new; # pop @$seqs;
152 9         19 $self->{'initial_prime'} = 0;
153 9         20 $self->{'target'} = 0;
154             }
155             }
156              
157             sub next {
158 124     124 1 2020 my ($self) = @_;
159             ### PrimeIndexPrimes next(): $self->{'i'}
160              
161 124         96 my $seqs = $self->{'seqs'};
162 124         77 my $target = $self->{'target'}++;
163              
164 124 50       161 if ($self->{'level_type'} eq 'maximum') {
165              
166             } else {
167 124 100       160 if ($self->{'level_type'} eq 'exact') {
168 68         88 while ($target >= $self->{'initial_prime'}) {
169 50         69 (undef, $self->{'initial_prime'}) = $self->{'initial_seq'}->next;
170 50         75 $target = $self->{'target'}++;
171             }
172             }
173 124         111 foreach my $seq (@$seqs) {
174             ### $target
175 148         77 my ($i, $prime);
176 148         93 do {
177 356         407 ($i, $prime) = $seq->next;
178             } until ($i >= $target);
179 148         125 $target = $prime;
180             }
181             }
182 124         157 return ($self->{'i'}++, $target);
183             }
184              
185             sub value_to_i_estimate {
186 116     116 1 1561 my ($self, $value) = @_;
187              
188 116         139 foreach (1 .. $self->{'level'}) {
189 128         645 $value = Math::NumSeq::Primes->value_to_i_estimate($value);
190             }
191 116 100       861 if ($self->{'level_type'} eq 'exact') {
192 61         82 $value = $value - Math::NumSeq::Primes->value_to_i_estimate($value);
193             }
194 116         772 return int($value);
195             }
196              
197             1;
198             __END__