#!/usr/bin/env perl
use strict;
use warnings;
use File::Spec::Functions;
use FindBin;
use Time::HiRes qw(gettimeofday tv_interval);
use bigint try => 'GMP';
use Data::BitStream::XS;
$|++; #flush the output buffer after every write() or print() function
# Maps between oeis name and number, filled in as we read sequences.
my %oeis_number; # short-name -> no
my %oeis_data; # no -> ref to info+data
# returned array contains elements of:
# [$oeis_no, $name, $script_arg, $num_entries, \@ref_data];
my $test_data = read_script_data('script-test-data.bs');
# Verify additional filters
my @additional_filters;
foreach my $name (@ARGV) {
$name =~ s/^--//;
my $oeis_no = $oeis_number{$name};
die "Unknown filter: $name\n" unless defined $oeis_no;
push @additional_filters, $oeis_no;
}
if (@additional_filters > 0) {
print "Additional Filters: ",
join(" ", map { $oeis_data{$_}->[2] } @additional_filters), "\n";
}
foreach my $test (@$test_data) {
test_oeis(@$test);
}
sub read_script_data {
my ($filename) = @_;
die "Can't find test file: $filename\nRun make-script-test-data.pl\n"
unless -r $filename;
my $stream = Data::BitStream::XS->new( file => $filename, mode => 'ro' );
my @data;
while (!$stream->exhausted) {
my $script_arg = get_text_string($stream);
my $name = get_text_string($stream);
my ($oeis_no, $is_bigint, $num_entries, @ref) = $stream->get_gamma(5);
printf "%12s primes (OEIS A%06d): reading %7d entries..", $name, $oeis_no, $num_entries;
if ($is_bigint) {
print ",";
my $k = 2;
my @deltas = $stream->get_arice($k, $num_entries-2);
print ".";
# Check to see if we have any giant deltas
foreach my $d (@deltas) {
if ( $d >= '18446744073709551614' ) {
my $len = $stream->get_gamma;
my $binstr = $stream->read_string($len);
$d = Math::BigInt->new('0b' . $binstr);
}
}
print ".";
my $prev = $ref[1];
push @ref, map { $prev = $_*2+$prev+2; } @deltas;
print ".\n";
} else {
no bigint;
print ".";
my $k = 2;
my @deltas = $stream->get_arice($k, $num_entries-2);
print ".";
my $prev = $ref[1];
push @ref, map { $prev = $_*2+$prev+2; } @deltas;
print ".\n";
}
my $row = [$oeis_no, $name, $script_arg, $num_entries, \@ref];
push @data, $row;
$oeis_data{$oeis_no} = $row;
$oeis_number{$script_arg} = $oeis_no;
}
\@data;
}
sub test_oeis {
my($oeis_no, $name, $script_arg, $num_entries, $ref_data) = @_;
my @ref = @$ref_data;
my $end = $ref[-1];
$script_arg = '--' . $script_arg;
foreach my $filter_no (@additional_filters) {
#my $row = [$oeis_no, $name, $script_arg, $num_entries, \@ref];
my $filter_name = $oeis_data{$filter_no}->[2];
my $filter_data_ref = $oeis_data{$filter_no}->[4];
my %filter_data_hash;
undef @filter_data_hash{ @$filter_data_ref };
my $filter_end = $filter_data_ref->[-1];
@ref = grep { exists $filter_data_hash{$_} } @ref;
$script_arg .= " --$filter_name";
$end = $filter_end if $end > $filter_end; # bring endpoint down
}
printf "%12s primes (OEIS A%06d): generating..", $name, $oeis_no;
my $start = [gettimeofday];
my @scr = split /\s+/, qx+$FindBin::Bin/../bin/primes.pl $script_arg 1 $end+;
{
no bigint;
my $num_generated = scalar @scr || 0.1;
my $seconds = tv_interval($start);
my $msperprime = ($seconds * 1000.0) / $num_generated;
printf " %7d. %7.2f ms/prime\n", $num_generated, $msperprime;
}
if (scalar @ref != scalar @scr) {
warn " $FindBin::Bin/../bin/primes.pl $script_arg 1 $end\n";
die "Not equal numbers: ", scalar @ref, " - ", scalar @scr, "\n";
}
foreach my $i (0 .. $#ref) {
die "$name prime $i not equal: $ref[$i] - $scr[$i]\n"
if $ref[$i] != $scr[$i];
}
}
sub put_text_string {
my ($stream, $str) = @_;
$stream->put_gamma(ord($_)) for (split "", $str);
$stream->put_gamma(0);
1;
}
sub get_text_string {
my ($stream) = @_;
my $str = '';
while (my $c = $stream->get_gamma) {
$str .= chr($c);
}
$str;
}