#!/usr/bin/perl -w

# Copyright 2010, 2011, 2012 Kevin Ryde

# This file is part of Math-PlanePath.
#
# Math-PlanePath 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-PlanePath 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-PlanePath.  If not, see <http://www.gnu.org/licenses/>.

use 5.010;
use strict;
use warnings;
use Math::BigRat;
use Math::Polynomial 1;
use Math::Polynomial::Horner;

#use Devel::Comments;

my_interpolate ([0,1,2],[55, 239, 551,]);
exit 0;

  
my_interpolate ([ 0,2,4,6 ],
[ 0,5,25,61]);


# [1,2,3,4],[1+4,12+4+8,35+4+8+8,70+4+8+8+8]
# # step==0
# my_interpolate ([  0,   1,   2,   3,   4 ],
#                 [0.5, 0.5, 0.5, 0.5, 0.5 ]);
# # step==1
# #  7 8 9 10
# #  4 5 6
# #  2 3
# #  1
# my_interpolate ([  0,   1,   2,   3 ],
#                 [0.5, 1.5, 3.5, 6.5 ]);
# # step==2
# my_interpolate ([  0,   1,   2,   3 ],
#                 [0.5, 1.5, 4.5, 9.5 ]);
# # step==3
# my_interpolate ([  0,   1,   2,   3 ],
#                 [0.5, 1.5, 5.5, 12.5 ]);
# # step==4
# my_interpolate ([  0,   1,   2,   3 ],
#                 [0.5, 1.5, 6.5, 15.5 ]);


# my_interpolate ([ 2,   3,  4,  5,   6,   7,   8,   9, 10 ],
#                 [ 9, 25, 49, 81, 121, 169, 225, 289, 361 ]
#                );
exit 0;

# N = a*s^2 + b*s + c
#   = a * (s^2 + b/a s + c/a)
#
# N/a = (s + b/2a)^2 - b^2/4a^2 + c/a
# (s + b/2a)^2 = N/a + b^2/4a^2 - c/a
# s+ b/2a = sqrt(4aN/4a^2 + b^2/4a^2 - 4ac/4a^2)
#         = 1/2a * sqrt(4aN + b^2 - 4ac)
#
#      -b + sqrt(4aN + b2 - 4ac)
# s =  ------------------------
#               2a
#




my_interpolate (
                [ 1,  2,    3,       4, 5],
                [ map {3*$_} 1,1+4,1+4+9,1+4+9+16,1+4+9+16+25 ],
               );

sub bigrat_to_decimal {
  my ($rat) = @_;
  if (is_pow2($rat->denominator)) {
    return $rat->as_float;
  } else {
    return $rat;
  }
}
sub is_pow2 {
  my ($n) = @_;
  while ($n > 1) {
    if ($n & 1) {
      return 0;
    }
    $n >>= 1;
  }
  return ($n == 1);
}

use constant my_string_config => (variable     => '$d',
                                  times       => '*',
                                  power       => '**',
                                  fold_one    => 1,
                                  fold_sign   => 1,
                                  fold_sign_swap_end => 1,
                                  power_by_times     => 1,
                                 );

#  @string_config = (
# #                      power       => '**',
# #                      fold_one    => 1,
# #                      fold_sign   => 1,
# #                      fold_sign_swap_end => 1,
# #                      power_by_times     => 1,
#                     );
sub my_interpolate {
  my ($xarray, $valarray) = @_;

  my $zero = 0;

  $zero = Math::BigRat->new(0);
  $xarray   = [ map {Math::BigRat->new($_)} @$xarray ];
  $valarray = [ map {Math::BigRat->new($_)} @$valarray ];

  my $p = Math::Polynomial->new($zero);
  $p = $p->interpolate($xarray, $valarray);

  $p->string_config({ fold_sign => 1,
                      variable  => 'd' });
  print "N = $p\n";

  $p->string_config({ my_string_config() });
  print "  = $p\n";

  $p->string_config({ my_string_config(),
                      #  convert_coeff  => \&bigrat_to_decimal,
                    });
  print "  = ",Math::Polynomial::Horner::as_string($p),"\n";

  my $a = $p->coeff(2);
  return if $a == 0;
  my $b = $p->coeff(1);
  my $c = $p->coeff(0);

  my $x = -$b/(2*$a);
  my $y = 4*$a / ((2*$a) ** 2);
  my $z = ($b*$b-4*$a*$c) / ((2*$a) ** 2);
  print "d = $x + sqrt($y * \$n + $z)\n";

  #   return;

  my $s_to_n = sub {
    my ($s) = @_;
    return $p->evaluate($s);
  };

  if (ref $x) {
    $x = $x->numify;
    $y = $y->numify;
    $z = $z->numify;
  }
  my $n_to_d = sub {
    my ($n) = @_;
    my $root = $y * $n + $z;
    if ($root < 0) {
      return 'neg sqrt';
    }
    return ($x + sqrt($root));
  };
  # for (my $i = 0; $i < 100; $i += 0.5) {
  #   printf "%4s  d=%s\n", $i, $n_to_d->($i);
  # }
  exit 0;
}
# {
#   package Math::Polynomial;
#   sub interpolate {
#     my ($this, $xvalues, $yvalues) = @_;
#     if (
#         !ref($xvalues) || !ref($yvalues) || @{$xvalues} != @{$yvalues}
#        ) {
#       croak 'usage: $q = $p->interpolate([$x1, $x2, ...], [$y1, $y2, ...])';
#     }
#     return $this->new if !@{$xvalues};
#     my @alpha  = @{$yvalues};
#     my $result = $this->new($alpha[0]);
#     my $aux    = $result->monomial(0);
#     my $zero   = $result->coeff_zero;
#     for (my $k=1; $k<=$#alpha; ++$k) {
#       for (my $j=$#alpha; $j>=$k; --$j) {
#         my $dx = $xvalues->[$j] - $xvalues->[$j-$k];
#         croak 'x values not disjoint' if $zero == $dx;
#         ### dx: "$dx",ref $dx
#         $alpha[$j] = ($alpha[$j] - $alpha[$j-1]) / $dx;
#       }
#       $aux = $aux->mul_root($xvalues->[$k-1]);
#       $result += $aux->mul_const($alpha[$k]);
#     ### alpha: join(' ',map{"$_"}@alpha)
#     }
#     return $result;
#   }
# }



{
  my $f1 = 1.5;
  my $f2 = 4.5;
  my $f3 = 9.5;
  my $f4 = 16.5;

  foreach ($f1, $f2, $f3, $f4) {
    $_ = Math::BigRat->new($_);
  }

  my $a = $f4/2 - $f3 + $f2/2;
  my $b = $f4*-5/2 + $f3*6 - $f2*7/2;
  my $c = $f4*3 - $f3*8 + $f2*6;

  print "$a\n";
  print "$b\n";
  print "$c\n";

  print "$a*\$s*\$s + $b*\$s + $c\n";
  exit 0;
}

{
  my $subr = sub {
    my ($s) = @_;
     return 3*$s*$s - 4*$s + 2;
    # return 2*$s*$s - 2*$s + 2;
    # return $s*$s + .5;
    # return $s*$s - $s + 1;
    # return $s*($s+1)*.5 + 0.5;
  };
  my $back = sub {
    my ($n) = @_;
    return (2 + sqrt(3*$n - 2)) / 3;
    # return .5 + sqrt(.5*$n-.75);
    # return sqrt ($n - .5);
    # return -.5 + sqrt(2*$n - .75);
    #    return int((sqrt(4*$n-1) - 1) / 2);
  };

  my $prev = 0;
  foreach (1..15) {
    my $this = $subr->($_);
    printf("%2d  %.2f  %.2f  %.2f\n", $_, $this, $this-$prev,$back->($this));
    $prev = $this;
  }
  for (my $n = 1; $n < 23; $n++) {
    printf "%.2f  %.2f\n", $n,$back->($n);
  }
  exit 0;
}
