The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# Copyright 2010, 2011, 2012, 2013, 2014 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/>.


# FIXME: These are values with at least one prime factor 3k+1 or some such.


package Math::NumSeq::SumXsq3Ysq;
use 5.004;
use strict;
use POSIX 'floor','ceil';
use List::Util 'max';
use List::MoreUtils;

use vars '$VERSION', '@ISA';
$VERSION = 71;
use Math::NumSeq;
@ISA = ('Math::NumSeq');


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

# use constant name => Math::NumSeq::__('...');
use constant description => Math::NumSeq::__('Loeschian numbers x^2+3*y^2 for all x>=0 and y>=0.');
use constant characteristic_increasing => 2;
use constant i_start => 1;

#------------------------------------------------------------------------------
# cf A003136 - Loeschian x^2+3*y^2 with x>=0,y>=0 and opposite odd/even
#    A158937 - all x^2+3*y^2 with repetitions x>=0,y>=0
#    A092573 - number of solutions to x^2+3*y^2==n
#    A092575 - number of solutions to x^2+3*y^2==n with gcd(x,y)=1
#
#    A034017 loeschian primatives x^2+xy+y^2, primes 3k+1 and a factor of 3
#    A088534 - count x^2+xy+y^2 with 0<=x<=y
#         0 <= (Y-X)/2
#         0 <= Y-X
#         X <= Y
#         (Y-X)/2 <= (X+Y)/2
#         Y-X <= X+Y
#         -X <= X
#         0 <= 2X
#         X >= 0
#         so 0 <= X <= Y octant
#
#    A092572 values x^2+3*y^2 for all integer x,y
#    A092573 count occurrances of x^2+3*y^2
#    A158937 values x^2+3*y^2 with repetitions
#
#    A092574 values x^2+3*y^2 with gcd(x,y)=1
#    A092575 count occurrances of x^2+3*y^2 with gcd(x,y)=1
#
#    A020669 values x^2+5*y^2 for all integer x,y
#    A091727 norms of ideals in sqrt(-5)
#    A091728 num prime ideals of norm n in sqrt(-5)
#
use constant oeis_anum => 'A092572'; # all x^2+3*y^2 x>=1,y>=1

#          4, 7,    12, 13, 16, 19, 21, 28,         31, 36, 37, 39, 43, 48, 49, 52, 57, 61,     
# 0, 1, 3, 4, 7, 9, 12, 13, 16, 19, 21, 25, 27, 28, 31, 36, 37, 39, 43,     


#------------------------------------------------------------------------------
sub rewind {
  my ($self) = @_;
  ### SumXsq3Ysq rewind()
  $self->{'i'} = $self->i_start;
  $self->{'y_next_x'}     = [ undef, 1         ];
  $self->{'y_next_hypot'} = [ undef, 1*1+3*1*1 ];
  $self->{'prev_hypot'} = 1;
  ### assert: $self->{'y_next_hypot'}->[1] == 3*1**2 + $self->{'y_next_x'}->[1]**2
  ### $self
}
sub next {
  my ($self) = @_;
  my $prev_hypot = $self->{'prev_hypot'};
  my $y_next_x = $self->{'y_next_x'};
  my $y_next_hypot = $self->{'y_next_hypot'};
  my $found_hypot = 12 * $prev_hypot + 4;
  ### $prev_hypot
  for (my $y = 1; $y < @$y_next_x; $y++) {
    my $h = $y_next_hypot->[$y];
    ### consider y: $y
    ### $h
    if ($h <= $prev_hypot) {
      if ($y == $#$y_next_x) {
        my $next_y = $y + 1;
        ### extend to: $next_y
        push @$y_next_x, 1;  # x=1
        push @$y_next_hypot, 1 + 3*$next_y*$next_y;
        ### $y_next_x
        ### $y_next_hypot
        ### assert: $y_next_hypot->[$next_y] == 3*$next_y**2 + $y_next_x->[$next_y]**2
      }
      do {
        $h = ($y_next_hypot->[$y] += 2*($y_next_x->[$y]++)+1);
        ### step y: $y
        ### next x: $y_next_x->[$y]
        ### next hypot: $y_next_hypot->[$y]
        ### assert: $y_next_hypot->[$y] == 3*$y**2 + $y_next_x->[$y]**2
      } while ($h <= $prev_hypot);
    }
    ### $h
    if ($h < $found_hypot) {
      ### lower hypot: $y
      $found_hypot = $h;
    }
  }
  $self->{'prev_hypot'} = $found_hypot;
  ### return: $self->{'i'}, $found_hypot
  return ($self->{'i'}++, $found_hypot);
}

# ENHANCE-ME: check the factorization
sub pred {
  my ($self, $n) = @_;
  if ($n == $n-1) {
    return 0;
  }
  my $limit = int(sqrt(($n-($n>0))/3));
  ### $limit
  for (my $y = 1; $y <= $limit; $y++) {
    my $ysq = 3*$y*$y;
    my $x = int(sqrt($n - $ysq));
    if ($x*$x + $ysq == $n) {
      return 1;
    }
  }
  return 0;
}

1;
__END__