aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xchallenge-246/jo-37/perl/ch-2.pl101
1 files changed, 101 insertions, 0 deletions
diff --git a/challenge-246/jo-37/perl/ch-2.pl b/challenge-246/jo-37/perl/ch-2.pl
new file mode 100755
index 0000000000..bdb35e6014
--- /dev/null
+++ b/challenge-246/jo-37/perl/ch-2.pl
@@ -0,0 +1,101 @@
+#!/usr/bin/perl -s
+
+use v5.10;
+use Test2::V0 '!float';
+use PDL;
+use PDL::NiceSlice;
+
+our ($tests, $examples, $verbose);
+
+run_tests() if $tests || $examples; # does not return
+
+die <<EOS unless @ARGV > 4;
+usage: $0 [-examples] [-tests] [-verbose] [--] [N...]
+
+-examples
+ run the examples from the challenge
+
+-tests
+ run some tests
+
+-verbose
+ print intermediate results and the detected recurrence from the
+ first elements
+
+N...
+ five or more integers
+
+EOS
+
+
+### Input and Output
+
+say is_lin_recur_2(@ARGV) ? 'true' : 'false';
+
+
+### Implementation
+
+sub logv {
+ printf @_ if $verbose;
+}
+
+sub is_lin_recur_2 {
+ my $a = pdl @_;
+ logv "a: %s\n", $a;
+ my $m = cat $a(0:1), $a(1:2);
+ logv "M: %s\n", $m;
+ if ($m->determinant) {
+ my $p = $m->inv x $a(2:3)->transpose;
+ logv "p: %s\n", $p;
+ logv "recur: a[n] = %g * a[n-2] + (%g * a[n-1])\n", $p->list;
+ return all(approx $p, $p->rint) &&
+ all approx $a(4:), $p->transpose x cat $a(2:-3), $a(3:-2);
+ }
+ if ($a(1)) {
+ my $p1 = $a(2) / $a(1);
+ logv "recur: a[n] = %g * a[n-1]\n", $p1->sclr;
+ return approx($p1, $p1->rint) && all approx $a(3:), $p1 * $a(2:-2);
+ }
+
+ logv "recur: a[n] = 0\n";
+ return all $a(2:) == 0;
+}
+
+
+### Examples and tests
+
+sub run_tests {
+ SKIP: {
+ skip "examples" unless $examples;
+
+ ok is_lin_recur_2(1, 1, 2, 3, 5), 'example 1';
+ ok !is_lin_recur_2(4, 2, 4, 5, 7), 'example 2';
+ ok is_lin_recur_2(4, 1, 2, -3, 8), 'example 3';
+ }
+
+ SKIP: {
+ skip "tests" unless $tests;
+
+ ok is_lin_recur_2(1, 0, 0, 0, 0), 'order 0';
+ ok !is_lin_recur_2(1, 0, 0, 1, 0), 'failed order 0, @ 3';
+ ok !is_lin_recur_2(1, 0, 0, 0, 1), 'failed order 0, @ 4';
+ ok !is_lin_recur_2(0, 0, 1, 0, 0), 'failed order 0, @ 2';
+ ok is_lin_recur_2(1, 2, 4, 8, 16), 'order 1';
+ ok !is_lin_recur_2(1, 2, 4, 9, 16), 'failed order 1, @ 3';
+ ok !is_lin_recur_2(1, 2, 4, 8, 15), 'failed order 1, @ 4';
+ ok !is_lin_recur_2(81, 27, 9, 3, 1), 'failed order 1, non-integer';
+ ok is_lin_recur_2(1, 0, 2, 0, 4), 'order 2: a[n] = 2 * a[n-2]';
+ ok is_lin_recur_2(1, 1, 0, 0, 0), 'order 2: zeroes';
+ ok !is_lin_recur_2(1, 1, 0, 0, 1), 'failed order 2, @ 4';
+ ok is_lin_recur_2(1, 0, 0, 0, 0, 0), 'order 0: six numbers';
+ ok !is_lin_recur_2(1, 0, 0, 0, 0, 1), 'failed order 0: six numbers';
+ ok is_lin_recur_2(1, 1, 1, 1, 1, 1), 'order 1: six numbers';
+ ok !is_lin_recur_2(1, 1, 1, 1, 1, 2), 'failed order 1: six numbers';
+ ok is_lin_recur_2(1, 1, 2, 3, 5, 8), 'order 2: six numbers';
+ ok !is_lin_recur_2(1, 1, 2, 3, 5, 7), 'failed order 2: six numbers';
+ ok is_lin_recur_2(1, 1, 11, 21, 131), 'approximation required';
+ }
+
+ done_testing;
+ exit;
+}