File Coverage

blib/lib/Math/NumSeq/GoldbachCount.pm
Criterion Covered Total %
statement 88 90 97.7
branch 24 26 92.3
condition 4 8 50.0
subroutine 16 16 100.0
pod 5 5 100.0
total 137 145 94.4


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              
19             # http://mathworld.wolfram.com/GoldbachConjecture.html
20              
21              
22             package Math::NumSeq::GoldbachCount;
23 1     1   1079 use 5.004;
  1         3  
24 1     1   4 use strict;
  1         2  
  1         31  
25 1     1   3 use Math::Prime::XS 0.23 'is_prime'; # version 0.23 fix for 1928099
  1         12  
  1         46  
26              
27 1     1   3 use vars '$VERSION', '@ISA';
  1         2  
  1         71  
28             $VERSION = 72;
29             @ISA = ('Math::NumSeq');
30             *_is_infinite = \&Math::NumSeq::_is_infinite;
31              
32 1     1   4 use Math::NumSeq::Primes;
  1         2  
  1         24  
33              
34             # uncomment this to run the ### lines
35             #use Smart::Comments;
36              
37              
38             # use constant name => Math::NumSeq::__('Goldbach Count');
39 1     1   4 use constant description => Math::NumSeq::__('The number of ways i can be represented as P+Q for primes P and Q. The Goldbach conjecture is that all even i>=4 can be represented in at least one such way.');
  1         1  
  1         4  
40 1     1   4 use constant default_i_start => 1;
  1         2  
  1         38  
41 1     1   4 use constant values_min => 0;
  1         4  
  1         34  
42 1     1   3 use constant characteristic_count => 1;
  1         2  
  1         34  
43 1     1   3 use constant characteristic_smaller => 1;
  1         2  
  1         60  
44              
45             # not documented yet
46 1         3 use constant parameter_info_array =>
47             [
48             {
49             name => 'on_values',
50             share_key => 'on_values_even',
51             type => 'enum',
52             default => 'all',
53             choices => ['all','even'],
54             choices_display => [Math::NumSeq::__('All'),
55             Math::NumSeq::__('Even')],
56             # description => Math::NumSeq::__('...'),
57             },
58 1     1   4 ];
  1         2  
59              
60             #------------------------------------------------------------------------------
61             # cf A014092 - n not P+Q, ie. count=0, starting from value=1
62             # A014091 - n some P+Q, ie. count!=0
63             # A067187 - n one way P+Q, ie. count=1
64             # A067188 - n two ways, count=2
65             # A067189 - n three ways
66             # A067190 - n four ways
67             # A067191 - n five ways
68             # A073610 - num primes n-p where p prime, so counting two ways
69             # A045917 - 2n, ordered sum
70             # A185297 - sum of the p's p+q=2n
71             # A185298 - sum of the q's p+q=2n
72             # A002372 - count for two odd primes
73             #
74             # A045917 - unordered 2n, start n=1 is 2
75             # odd or even primes, so n=2 is 4 count 1 for 2+2=4
76             # A002375 - unordered 2n, start n=1 is 2
77             # odd primes, so n=2 is 4 count 1 for 2+2=4
78             #
79             my %oeis_anum = ('all' => 'A061358', # ordered p>=q, start n=0
80             'even' => 'A045917', # unordered sum, start n=1 is 2
81             # OEIS-Catalogue: A061358 i_start=0
82             # OEIS-Catalogue: A045917 on_values=even
83             );
84             sub oeis_anum {
85 2     2 1 6 my ($self) = @_;
86 2         4 return $oeis_anum{$self->{'on_values'}};
87             }
88              
89             #------------------------------------------------------------------------------
90              
91             sub rewind {
92 6     6 1 997 my ($self) = @_;
93             ### GoldbachCount rewind() ...
94 6         20 $self->{'i'} = $self->i_start;
95              
96             # special case initial array for even so can then exclude prime p=2 from loop
97 6 100       17 $self->{'array'} = ($self->{'on_values'} eq 'even'
98             ? [ 0, 0, 1, 1 ]
99             : []);
100 6         34 $self->{'size'} = 499; # must be odd for 2i case
101             }
102              
103             sub next {
104 50     50 1 720 my ($self) = @_;
105             ### next(): "i=$self->{'i'}, arraylen=".scalar(@{$self->{'array'}})
106              
107 50 100       30 unless (@{$self->{'array'}}) {
  50         72  
108 4         11 $self->{'size'} = int(1.1 * $self->{'size'}) | 1; # must be odd
109              
110 4         3 my $lo = $self->{'i'};
111 4         7 my $even_only = ($self->{'on_values'} eq 'even');
112 4 100       9 if ($even_only) {
113 2         4 $lo *= 2;
114             }
115 4         4 my $hi = $lo + $self->{'size'};
116             ### range: "lo=$lo to hi=$hi"
117 4         6 my @array;
118 4         12 $array[$hi-$lo] = 0; # array size
119              
120 4         13 my @primes = Math::NumSeq::Primes::_primes_list (0, $hi);
121 4 100       237 if ($even_only) {
122 2         3 shift @primes; # skip P=2
123             }
124              
125             {
126 4         5 my $qamax = $#primes;
  4         5  
127 4         10 foreach my $pa (0 .. $#primes-1) {
128 398         400 foreach my $qa (reverse $pa .. $qamax) {
129 12608         8011 my $sum = $primes[$pa] + $primes[$qa];
130             ### at: "p=$primes[$pa] q=$primes[$qa] sum=$sum incr ".($sum-$lo)
131 12608 100       14055 if ($sum > $hi) {
    50          
132 170         135 $qamax = $qa-1;
133             } elsif ($sum < $lo) {
134 0         0 last;
135             } else {
136 12438         9310 $array[$sum-$lo]++;
137             }
138             }
139             }
140             }
141             ### @array
142 4         16 $self->{'array'} = \@array;
143             }
144              
145 50   100     39 my $value = shift @{$self->{'array'}} || 0;
146             ### $value
147 50 100       67 if ($self->{'on_values'} eq 'even') {
148 16         14 shift @{$self->{'array'}}; # skip odd
  16         13  
149             }
150 50         55 return ($self->{'i'}++, $value);
151             }
152              
153             sub ith {
154 81     81 1 134 my ($self, $i) = @_;
155             ### ith(): $i
156              
157 81 100       111 if ($self->{'on_values'} eq 'even') {
158 27         19 $i *= 2;
159             }
160 81 100       99 if ($i <= 3) {
161 18         25 return 0;
162             }
163 63 50 33     170 unless ($i >= 0 && $i <= 0xFF_FFFF) {
164 0         0 return undef;
165             }
166 63         61 $i = "$i"; # numize any Math::BigInt for speed
167              
168 63 100       91 if ($i & 1) {
169             ### odd, check prime: $i-2
170 21 100       62 return (is_prime($i-2) ? 1 : 0); # odd only i=2+Q for prime Q
171             }
172              
173 42         35 my $count = 0;
174 42         65 my @primes = Math::NumSeq::Primes::_primes_list (0, $i-1);
175             ### @primes
176              
177 42         1173 my $pa = 0;
178 42         34 my $qa = $#primes;
179 42         58 while ($pa <= $qa) {
180 199         129 my $sum = $primes[$pa] + $primes[$qa];
181 199 100       188 if ($sum <= $i) {
182             ### at: "p=$primes[$pa] q=$primes[$qa] incr=".($sum == $i)
183 125         71 $count += ($sum == $i);
184 125         156 $pa++;
185             } else {
186 74         87 $qa--;
187             }
188             }
189              
190             ### $count
191 42         80 return $count;
192             }
193              
194             sub pred {
195 25     25 1 80 my ($self, $value) = @_;
196             ### HypotCount pred(): $value
197 25   33     73 return ($value >= 0 && $value == int($value));
198             }
199              
200             1;
201             __END__