The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/perl -w

# Copyright 2009, 2010 Kevin Ryde

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

use 5.010;
use strict;
use warnings;
use Carp;
use List::Util;
use Math::Polynomial;
use Math::BigRat;
use Math::Matrix;
use Data::Dumper;

# Math::Polynomial->verbose(1);

# Bandini
{
  sub compose_weights {
    my ($w1, $w2) = @_;
    my @ret;
    foreach my $i (0 .. $#$w1) {
      foreach my $j (0 .. $#$w2) {
        $ret[$i+$j] += $w1->[$i] * $w2->[$j];
      }
    }
    return \@ret;
  }
  my $sma2 = [0.5, 0.5];
  my @bandini = ($sma2);
  while (@bandini < 10) {
    push @bandini, compose_weights($sma2, $bandini[-1]);
  }
  foreach my $aref (@bandini) {
    require Data::Dumper;
    say Data::Dumper->new([$aref],['B'])->Indent(0)->Dump;
  }
  say scalar @{$bandini[-1]};
  foreach my $aref (@bandini) {
    require Data::Dumper;
    $aref = [ map {$_*1024} @$aref ];
    say Data::Dumper->new([$aref],['B'])->Indent(0)->Dump;
  }
  exit 0;
}


sub wma {
  my ($N, $P) = @_;
  my @coeffs = (1 .. $N);
  my $total = List::Util::sum (@coeffs);
  @coeffs = map {Math::BigRat->new("$_/$total")} @coeffs;

  while (@coeffs < 30) { push @coeffs, Math::BigRat->new(0); }

  my $f = Math::Matrix->new ([@coeffs]);
  #   my $f = Math::Polynomial->new (@coeffs);
  #   if (defined $P) {
  #     $f *= $P;
  #   }
  # print Data::Dumper->Dump([$f],['matrix']);
  return $f;
}

sub weights {
  my %opt = @_;
  my $description = $opt{'description'}
    || die "weights: missing 'description'";
  my $basename = $opt{'basename'}
    || die "weights: missing 'basename'";
  my $method = $opt{'method'};
  my $N = $opt{'N'};
  my $show_count = $opt{'show_count'};
  # (proc (calc_proc count))

  my $warmup = 30 * $show_count;
  my @input = ((0) x $warmup,
               100,
               (0) x ($show_count - 1));

  my $in_series = ConstantSeries->new (array => \@input);
  my $ma_series = $in_series->$method ($N);
  my $hi = $ma_series->hi;
  $ma_series->fill (0, $hi);

  my $output = $ma_series->values_array;
  my @weights = @{$output}[$warmup .. $hi];

  print "$basename: ",Data::Dumper->Dump([\@weights],['weights']);
}

my $N = 15;
my $N2 = int($N/2);
my $NS = int(sqrt($N));

my $p = wma($N2);
print "N2  ",$p,"\n\n";

my $q = wma($N);
print "N   ",$q,"\n\n";

$p = $p->multiply_scalar(2); # - $q;
print "2*N ",$p,"\n\n";

$p -= $q;
print "2*N-N  ",$p,"\n\n";


exit 0;

$p = wma($NS, $p);
print $p,"\n\n";

foreach my $i (0 .. $p->degree) {
  print "$i  ",$p->coeff($i)->numify*100,"\n";
}

weights (description => "Hull moving average weights",
         basename    => "chart-hull-weights",
         method      => 'HullMA',
         N           => 15,
         show_count  => 20);
exit 0;


package ConstantSeries;
use strict;
use warnings;
use base 'App::Chart::Series';

sub new {
  my ($class, %option) = @_;
  my $array = delete $option{'array'} || die;
  $option{'hi'} = $#$array;
  $option{'name'} //= 'Const';
  $option{'timebase'} ||= do {
    require App::Chart::Timebase::Days;
    App::Chart::Timebase::Days->new_from_iso ('2008-07-23')
    };
  return $class->SUPER::new (arrays => { values => $array },
                             %option);
}
sub fill_part {}