# Copyright 2010, 2011, 2012, 2013, 2014, 2016, 2019, 2020 Kevin Ryde

# This file is part of Math-NumSeq.
#
# Math-NumSeq is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 3, or (at your option) any later
# version.
#
# Math-NumSeq is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with Math-NumSeq.  If not, see <http://www.gnu.org/licenses/>.


# cf
# http://mathworld.wolfram.com/dePolignacsConjecture.html
#   consecutive primes difference is every even number infinitely many times

# 1,
# 127, 149, 251, 331,
# 337, 373, 509, 599,
# 701, 757, 809, 877,
# 905, 907, 959, 977,
# 997, 

package Math::NumSeq::PolignacObstinate;
use 5.004;
use strict;

use vars '$VERSION', '@ISA';
$VERSION = 75;
use Math::NumSeq;
@ISA = ('Math::NumSeq');
*_is_infinite = \&Math::NumSeq::_is_infinite;

use Math::NumSeq::Primes; # for primes_list()
use Math::Prime::XS 'is_prime';

# uncomment this to run the ### lines
#use Smart::Comments;


# use constant name => Math::NumSeq::__('Polignac Obstinate');
use constant description => Math::NumSeq::__('Odd integers N not representable as prime+2^k.');
use constant values_min => 1;
use constant characteristic_increasing => 1;
use constant characteristic_integer => 1;
use constant i_start => 1;

# cf A133122 - demanding k>0, so 1,3,127,... as 3 no longer representable
#    A065381 - primes not p+2^k k>=0, filtering from odds to primes
#    
use constant oeis_anum => 'A006285'; # with k>=0 so 1,127,...


sub rewind {
  my ($self) = @_;
  $self->{'i'} = $self->i_start;
  $self->{'string'} = '';
  vec($self->{'string'},3/2,1) = 1;  # 2+2^0=3
  $self->{'done'} = -1;
  _resieve ($self, 20);
}

sub _resieve {
  my ($self, $hi) = @_;
  ### _resieve() ...

  $self->{'hi'} = $hi;
  my $sref = \$self->{'string'};
  vec($$sref,$hi,1) = 0;  # pre-extend
  my @primes = Math::NumSeq::Primes::_primes_list (3, $hi-1);
  for (my $power = 2; $power < $hi; $power *= 2) {
    foreach my $p (@primes) {
      if ((my $v = $p + $power) > $hi) {
        last;
      } else {
        vec($$sref,$v/2,1) = 1;
      }
    }
  }
}

sub next {
  my ($self) = @_;
  ### Obstinate next(): $self->{'i'}

  my $v = $self->{'done'};
  my $sref = \$self->{'string'};
  my $hi = $self->{'hi'};

  for (;;) {
    ### consider: "v=".($v+1)."  cf done=$self->{'done'}"
    if (($v+=2) > $hi) {
      _resieve ($self,
                $hi = ($self->{'hi'} *= 2));
    }
    unless (vec($$sref,$v/2,1)) {
      return ($self->{'i'}++,
              $self->{'done'} = $v);
    }
  }
}

sub pred {
  my ($self, $value) = @_;
  ### Obstinate pred(): $value

  unless ($value >= 0 && $value <= 0xFFFF_FFFF) {
    return undef;
  }
  if ($value != int($value)
      || $value < 127
      || ($value % 2) == 0) {
    return ($value == 1);
  }
  $value = "$value"; # numize Math::BigInt for speed

  # Maybe an is_any_prime(...)
  for (my $power = 2; $power < $value; $power *= 2) {
    if (is_prime($value - $power)) {
      return 0;
    }
  }
  return 1;
}

1;
__END__

=for stopwords Ryde Math-NumSeq de Polignac Erdos Pickover ie

=head1 NAME

Math::NumSeq::PolignacObstinate -- odd integers not prime+2^k

=head1 SYNOPSIS

 use Math::NumSeq::PolignacObstinate;
 my $seq = Math::NumSeq::PolignacObstinate->new;
 my ($i, $value) = $seq->next;

=head1 DESCRIPTION

This sequence is integers which cannot be represented as prime+2^k for an
integer k.  These are counter-examples to a conjecture by Prince de Polignac
that every odd integer occurs as prime+2^k (and are called "obstinate"
numbers by Andy Edwards).

    1, 127, 149, 251, 331, 337, ...

For example 149 is obstinate because it cannot be written as prime+2^k.
Working backwards, it can be seen that none of 149-1, 149-2, 149-4, 149-8,
... 149-128 are primes.

A theorem by Erdos gives infinitely many such obstinate integers (in an
arithmetic progression).

The value 3 is not in the sequence because it can be written prime+2^k, for
prime=2 and k=0.

=head1 FUNCTIONS

See L<Math::NumSeq/FUNCTIONS> for behaviour common to all sequence classes.

=over 4

=item C<$seq = Math::NumSeq::PolignacObstinate-E<gt>new ()>

Create and return a new sequence object.

=item C<$bool = $seq-E<gt>pred($value)>

Return true if C<$value> is obstinate, ie. that there's no C<$k E<gt>= 0>
for which C<$value - 2**$k> is a prime.

This check requires prime testing up to C<$value> and in the current code a
hard limit of 2**32 is placed on the C<$value> to be checked, in the
interests of not going into a near-infinite loop.

=back

=head1 SEE ALSO

L<Math::NumSeq>,
L<Math::NumSeq::Primes>

Clifford Pickover, "The Grand Internet Obstinate Number Search"

=over

L<http://sprott.physics.wisc.edu/pickover/obstinate.html>

=back

=head1 LICENSE

Copyright 2010, 2011, 2012, 2013, 2014, 2016, 2019, 2020 Kevin Ryde

Math-NumSeq is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

Math-NumSeq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
more details.

You should have received a copy of the GNU General Public License along with
Math-NumSeq.  If not, see <http://www.gnu.org/licenses/>.

=cut