#!/usr/bin/perl -w

# Copyright 2010, 2011, 2012 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/>.

use 5.010;
use strict;
use warnings;
use POSIX;
use Math::Prime::XS 0.23 'is_prime'; # version 0.23 fix for 1928099
use Math::Factor::XS 0.39 'prime_factors'; # version 0.39 for prime_factors()
use List::Util 'max','min';
use Math::Trig 'pi';

use Smart::Comments;

# use blib "$ENV{HOME}/perl/bit-vector/Bit-Vector-7.1/blib";



{
  # value_to_i_estimate()
  # require Math::NumSeq::Primes;
  # my $seq = Math::NumSeq::Primes->new;

   require Math::NumSeq::TwinPrimes;
  # my $seq = Math::NumSeq::TwinPrimes->new;

  require Math::NumSeq::SophieGermainPrimes;
  my $seq = Math::NumSeq::SophieGermainPrimes->new;

  my $target = 2;
  for (;;) {
    my ($i, $value) = $seq->next;
    if ($i >= $target) {
      $target *= 1.1;

      require Math::BigInt;
      $value = Math::BigInt->new($value);

      # require Math::BigRat;
      # $value = Math::BigRat->new($value);

      # require Math::BigFloat;
      # $value = Math::BigFloat->new($value);

      my $est_i = $seq->value_to_i_estimate($value);
      my $factor = (ref $est_i ? $est_i->numify : $est_i) / $i;
      printf "%d %d   %.10s  factor=%.3f\n",
        $i, $est_i, $value, $factor;
    }
  }
  exit 0;
}

{
  # SG density
  require Math::NumSeq::Primes;
  my $seq = Math::NumSeq::Primes->new;
  my $count_total = 0;
  my $count_primes = 0;
  my $target = 10;
  foreach (1 .. 1000) {
    my ($i, $prime) = $seq->next;
    $count_total++;
    $count_primes += is_prime(2*$prime+1);
    if ($count_total > $target) {
      my $frac = $count_primes/$count_total;
      my $log = log($count_total)/$count_total;
      print "$count_primes/$count_total = $frac  cf log=$log\n";
      $target *= 1.5;
    }
  }
  exit 0;
}

{
  # SG factorizations
  require Math::NumSeq::Primes;
  my $seq = Math::NumSeq::Primes->new;
  $, = ', ';
  foreach (1 .. 1000) {
    my ($i, $prime) = $seq->next;
    my @prime_factors = prime_factors(2*$prime+1);
    if (@prime_factors > 1) {
      print "$prime  ";
      print $prime_factors[0],"\n";
    }
  }
  exit 0;
}
{
  use Math::Prime::Util;
  {
    my $ret = Math::Prime::Util::is_prime(2**256);
    ### $ret
  }
  {
    my $approx = Math::Prime::Util::prime_count_approx(2**1024);
    ### $approx
  }
  exit 0;
}

{
  # SG speed

  require Math::NumSeq::Primes;
  require Math::NumSeq::SophieGermainPrimes;
  my $seq = Math::NumSeq::SophieGermainPrimes->new;

  require Devel::TimeThis;
  {
    my $t = Devel::TimeThis->new('seq');
    foreach (1 .. 1000) {
      $seq->next;
    }
  }
  my ($i, $prime) = $seq->next;
  {
    my $t = Devel::TimeThis->new('pred');
    foreach (1 .. $prime) {
      $seq->pred($_);
    }
  }
  my $p = Math::NumSeq::Primes->new;
  {
    my $t = Devel::TimeThis->new('p-pred');
    foreach (;;) {
      my ($i, $p) = $p->next;
      last if $p > $prime;
      $p->pred(2*$_+1);
    }
  }
  exit 0;
}




{
  # twin primes count
  use Math::NumSeq::TwinPrimes;
  my $seq = Math::NumSeq::TwinPrimes->new;

  # n	pi_2(n)
  # 10^3	35
  # 10^4	205
  # 10^5	1224
  # 10^6	8169
  # 10^7	58980
  # 10^8	440312
  # 10^9	3424506
  # 10^(10)	27412679
  # 10^(11)	224376048
  # 10^(12)	1870585220
  # 10^(13)	15834664872
  # 10^(14)	135780321665
  # 10^(15)	1177209242304
  # 10^(16)	10304195697298


  {
    my $value = 5.4e15;
    my $est_i = $seq->value_to_i_estimate($value);
    print "$value  $est_i\n";
  }


  my $target = 2;
  for (;;) {
    my ($i, $value) = $seq->next;
    if ($i >= $target) {
      $target *= 2;
      my $est_i = $seq->value_to_i_estimate($value);
      my $factor = $est_i / $i;
      printf "%d %d   %d  %.3f\n", $i, $est_i, $value, $factor;
    }
  }
  exit 0;
}



{
  # dedekind psi cumulative estimate
  require Math::NumSeq::DedekindPsiCumulative;
  my $seq = Math::NumSeq::DedekindPsiCumulative->new;

  my $target = 2;
  for (;;) {
    my ($i, $value) = $seq->next;
    if ($i >= $target) {
      $target *= 2;
      my $est_i = $seq->value_to_i_estimate($value);
      my $factor = $est_i / $i;
      my $O = ($value - (15*$i**2)/(2*pi()*pi())) / ($i*log($i));
      my $est_value = ($i**2) * 15/(2*pi()*pi()); #  + 0 * ($i*log($i));
      printf "%d %d   %d %.0f  factor=%.3f  O=%.3f\n",
        $i, $est_i, $value, $est_value, $factor, $O;
    }
  }
  exit 0;
}

{
  # deletable primes high zeros
  use Math::NumSeq::DeletablePrimes;
  my $seq = Math::NumSeq::DeletablePrimes->new;

  for my $value (0 .. 100000) {
    (my $low = $value) =~ s/.0+//
      or next;
    is_prime($value) or next;
    if ($seq->pred($value)) { next; }
    $seq->pred($low) or next;

    print "$value $low\n";
  }
  exit 0;
}


{
  # pierpont offsets

  my $offset = -7;
  foreach my $x (1 .. 20) {
    foreach my $y (1 .. 20) {
      my $v = 2**$x * 3**$y + $offset;
      last if $v > 0xFFF_FFFF;
      if ($v > 0 && is_prime($v)) {
        print "$x,$y $offset\n";
      }
    }
  }
  exit 0;
}

{
  # pierpont
  use Math::NumSeq::PierpontPrimes;
  my $seq = Math::NumSeq::PierpontPrimes->new;

  foreach (1 .. 50) {
    my ($i, $value) = $seq->next;
    my ($x, $y) = pierpont_xy ($value);
    my $cmp = ($x <=> $y);
    print "$value    $x $y      $cmp\n";
  }

  sub pierpont_xy {
    my ($value) = @_;

    my $v = $value - 1;
    my $x = 0;
    until ($v % 2) {
      $v = int($v/2);
      $x++;
    }
    my $y = 0;
    until ($v % 3) {
      $v = int($v/3);
      $y++;
    }
    return ($x, $y);
  }

  exit 0;
}


{
  use Math::Prime::FastSieve;
  my @ret = Math::Prime::FastSieve::primes(20);
  ### @ret;

  require Test::Weaken;
  my $leaks = Test::Weaken::leaks (sub { Math::Prime::FastSieve::primes(20) });
  ### $leaks

  my $sieve = Math::Prime::FastSieve::Sieve->new( 2_000_000 );
  ### isprime: $sieve->isprime(1928099)

  exit 0;
}
{
  require Math::Prime::TiedArray;
  tie my @primes, 'Math::Prime::TiedArray';
  foreach my $i (0 .. 200) {
    print int(sqrt($primes[$i])),"\n";
  }
  exit 0;
}
{
  require Math::Prime::TiedArray;
  tie my @primes, 'Math::Prime::TiedArray';
  local $, = "\n";
  print @primes[0..5000];
  exit 0;
}

{
  require Bit::Vector;
  my $size = 0xFF; # F00000;
  my $vector = Bit::Vector->new($size);
  $vector->Primes();
  print $vector->bit_test(0),"\n";
  print $vector->bit_test(1),"\n";
  print $vector->bit_test(2),"\n";
  print $vector->bit_test(3),"\n";
  print $vector->bit_test(4),"\n";
  print $vector->bit_test(5),"\n";
  print $vector->bit_test(1928099),"\n";
  foreach my $i (0 .. 100) {
    if ($vector->bit_test($i)) {
      print ",$i";
    }
  }
  print "\n";


  # require Math::Prime::XS;
  # foreach my $i (65536 .. $size-1) {
  #   my $v = 0 + $vector->bit_test($i);
  #   my $x = 0 + Math::Prime::XS::is_prime($i);
  #   if ($v != $x) {
  #     print "$i $v $x\n";
  #   }
  # }
  exit 0;
}

{
  require Math::Prime::XS;
  local $, = "\n";
  print Math::Prime::XS::sieve_primes(2,3);
  exit 0;
}
