#!/usr/bin/perl # # This tests the new PDL constructor with a string argument. # There are two goals from the new functionality: (1) allow # MATLAB to use familiar syntax to create arrays, and # (2) to allow cut-n-paste of PDL print output as input # for scripts and programs # use Test::More tests => 111; use strict; use warnings; ############################# # Loading and ISA tests - 2 # ############################# BEGIN { # if we've got this far in the tests then # we can probably assume PDL::LiteF works! # use_ok( "PDL::LiteF" ); } isa_ok( pdl("[1,2]"), "PDL", qq{pdl("[1,2]") returns a piddle} ); ################### # Basic Tests - 8 # ################### ok( all(pdl([1,2])==pdl("[1,2]")), qq{pdl(ARRAY REF) equals pdl("ARRAY REF")}); my $compare = pdl([ [1, 0, 8], [6, 3, 5], [3, 0, 5], [2, 4, 2] ]); my $test_string = <ndims == 1, "Implicit bracketing gets proper number of dimensions - no brackets, no commas"); ok($t14->ndims == 1, "Implicit bracketing gets proper number of dimensions - no brackets, commas"); ok($t15->ndims == 1, "Implicit bracketing gets proper number of dimensions - brackets, no commas"); ok($t16->ndims == 1, "Implicit bracketing gets proper number of dimensions - brackets and commas"); $expected = pdl []; $got = pdl q[]; ok(all($got == $expected), 'Blank strings are interpreted as empty arrays'); # This generates an annoying warning, and the piddle should be Empty anyway #$expected = pdl []; $got = pdl q[[]]; ok(all($got == $expected), 'Empty bracket is correctly interpreted'); ############################# # Bad, inf, nan checks - 13 # ############################# # First term should be -inf my $bad_values = pdl q[nan inf -inf bad]; my $skip = 0; # nan test: nan is never considered equal to itself ... unless perl itself is buggy. if($bad_values->at(0) == $bad_values->at(0) && pdl($bad_values->at(0)) != pdl($bad_values->at(0))) { warn "Looks like your perl asserts (incorrectly) that NaN == NaN\n"; $skip = 1; } SKIP: { skip "because perl's handling of NaN seems buggy", 1 if $skip; ok($bad_values->at(0) != $bad_values->at(0), 'properly handles nan') or diag("Zeroeth bad value should be nan but it describes itself as " . $bad_values->at(0)); } # inf test: inf == inf but inf * 0 != 0 ok(($bad_values->at(1) == $bad_values->at(1) and $bad_values->at(1) * 0.0 != 0.0), 'properly handles inf') or diag("First bad value should be inf but it describes itself as " . $bad_values->at(1)); # inf test: -inf == -1 * inf ok(($bad_values->at(2) == $bad_values->at(2) and $bad_values->at(2) * 0.0 != 0.0), 'properly handles -inf') or diag("Second bad value should be -inf but it describes itself as " . $bad_values->at(2)); ok($bad_values->at(2) == -$bad_values->at(1), "negative inf is numerically equal to -inf"); # bad test ok($bad_values->isbad->at(3), 'properly handles bad values') or diag("Third bad value should be BAD but it describes itself as " . $bad_values->slice(3)); my $infty = pdl 'inf'; my $min_inf = pdl '-inf'; my $nan = pdl 'nan'; my $nan2 = pdl '-nan'; my $bad = pdl 'bad'; ok(($infty == $infty and $infty * 0.0 != 0.0), "pdl 'inf' works by itself") or diag("pdl 'inf' gave me $infty"); ok(($min_inf == $min_inf and $min_inf * 0.0 != 0.0), "pdl '-inf' works by itself") or diag("pdl '-inf' gave me $min_inf"); ok($min_inf == -$infty, "pdl '-inf' == -pdl 'inf'"); ok($nan != $nan, "pdl 'nan' works by itself") or diag("pdl 'nan' gave me $nan"); ok($nan2 != $nan2, "pdl '-nan' works by itself") or diag("pdl '-nan' gave me $nan2"); ok($bad->isbad, "pdl 'bad' works by itself") or diag("pdl 'bad' gave me $bad"); # Checks for windows strings: $infty = pdl q[1.#INF]; $nan = pdl q[-1.#IND]; ok(($infty == $infty and $infty * 0 != 0), "pdl '1.#INF' works"); ok($nan != $nan, "pdl '-1.#IND' works"); ######################## # Pi and e checks - 10 # ######################## $expected = pdl(1)->exp; $got = pdl q[e]; is($got, $expected, 'q[e] returns exp(1)') or diag("Got $got"); $got = pdl q[E]; is($got, $expected, 'q[E] returns exp(1)') or diag("Got $got"); $expected = pdl(1, exp(1)); $got = pdl q[1 e]; ok(all($got == $expected), 'q[1 e] returns [1 exp(1)]') or diag("Got $got"); $got = pdl q[1 E]; ok(all($got == $expected), 'q[1 E] returns [1 exp(1)]') or diag("Got $got"); $expected = pdl(exp(1), 1); $got = pdl q[e 1]; ok(all($got == $expected), 'q[e 1] returns [exp(1) 1]') or diag("Got $got"); $got = pdl q[E 1]; ok(all($got == $expected), 'q[E 1] returns [exp(1) 1]') or diag("Got $got"); $expected = pdl(1, exp(1), 2); $got = pdl q[1 e 2]; ok(all($got == $expected), 'q[1 e 2] returns [1 exp(1) 2]') or diag("Got $got"); $got = pdl q[1 E 2]; ok(all($got == $expected), 'q[1 E 2] returns [1 exp(1) 2]') or diag("Got $got"); # Already checked all the permutations of e, so just make sure that it # properly substitutes pi $expected = pdl(1, 4 * atan2(1,1)); $got = pdl q[1 pi]; ok(all($got == $expected), 'q[1 pi] returns [1 4*atan2(1,1)]') or diag("Got $got"); $got = pdl q[1 PI]; ok(all($got == $expected), 'q[1 PI] returns [1 4*atan2(1,1)]') or diag("Got $got"); ######################## # Security checks - 10 # ######################## # Check croaking on arbitrary bare-words: eval {pdl q[1 foobar 2]}; isnt($@, '', 'croaks on arbitrary string input'); eval {pdl q[$a $b $c]}; isnt($@, '', 'croaks with non-interpolated strings'); # Install a function that knows if it's been executed. { no warnings 'redefine'; my $e_was_run = 0; sub PDL::Core::e { $e_was_run++ } my $to_check = q[1 e 2]; sub PDL::Core::e { $e_was_run++ } eval {pdl $to_check}; is($e_was_run, 0, "Does not execute local function e in [$to_check]"); $e_was_run = 0; $to_check = q[1 +e 2]; sub PDL::Core::e { $e_was_run++ } eval {pdl $to_check}; is($e_was_run, 0, "Does not execute local function e in [$to_check]"); $e_was_run = 0; $to_check = q[1 e+ 2]; sub PDL::Core::e { $e_was_run++ } eval {pdl $to_check}; is($e_was_run, 0, "Does not execute local function e in [$to_check]"); $e_was_run = 0; $to_check = q[1e 2]; sub PDL::Core::e { $e_was_run++ } eval {pdl $to_check}; is($e_was_run, 0, "Does not execute local function e in [$to_check]"); $e_was_run = 0; $to_check = q[1e+ 2]; sub PDL::Core::e { $e_was_run++ } eval {pdl $to_check}; is($e_was_run, 0, "Does not execute local function e in [$to_check]"); $e_was_run = 0; $to_check = q[1+e 2]; sub PDL::Core::e { $e_was_run++ } eval {pdl $to_check}; is($e_was_run, 0, "Does not execute local function e in [$to_check]"); $e_was_run = 0; $to_check = q[1+e+ 2]; sub PDL::Core::e { $e_was_run++ } eval {pdl $to_check}; is($e_was_run, 0, "Does not execute local function e in [$to_check]"); $e_was_run = 0; $to_check = q[1 e123 2]; sub PDL::Core::e123 { $e_was_run++ } eval {pdl $to_check}; is($e_was_run, 0, "Does not execute local function e123 in [$to_check]"); $e_was_run = 0; } ############################### # Useful croaking output - 36 # ############################### eval{ pdl q[1 l 3] }; isnt($@, '', 'Croaks when invalid character is specified'); like($@, qr/found disallowed character\(s\) 'l'/, 'Gives meaningful explanation of problem'); eval{ pdl q[1 po 3] }; isnt($@, '', 'Croaks when invalid characters are specified'); like($@, qr/found disallowed character\(s\) 'po'/, 'Gives meaningful explanation of problem'); # checks for croaking behavior for consecutive signs like +-2: eval{ pdl q[1 +-2 3] }; isnt($@, '', 'Croaks when it finds consecutive signs'); like($@, qr/found a \w+ sign/, 'Gives meaningful explanation of problem'); eval{ pdl q[1 -+2 3] }; isnt($@, '', 'Croaks when it finds consecutive signs'); like($@, qr/found a \w+ sign/, 'Gives meaningful explanation of problem'); # 'larger word' croak checks (36) foreach my $special (qw(bad inf pi)) { foreach my $append (qw(2 e l)) { eval "pdl q[1 $special$append 2]"; isnt($@, '', "Croaks when it finds $special$append"); like($@, qr/larger word/, 'Gives meaningful explanation of problem'); eval "pdl q[1 $append$special 2]"; isnt($@, '', "Croaks when it finds $append$special"); like($@, qr/larger word/, 'Gives meaningful explanation of problem'); } } # e croaks (6) my $special = 'e'; foreach my $append (qw(2 e l)) { eval "pdl q[1 $special$append 2]"; isnt($@, '', "Croaks when it finds $special$append"); eval "pdl q[1 $append$special 2]"; isnt($@, '', "Croaks when it finds $append$special"); } # Basic 2D array # pdl> p $a = pdl q[ [ 1, 2, 3 ], [ 4, 5, 6 ] ]; # pdl> p $a = pdl q[ 1 2 3 ; 4 5 6 ] # pdl> p $a = pdl '[ [ 1, 2, 3 ], [ 4, 5, 6 ] ]'; # # [ # [1 2 3] # [4 5 6] # ] # Basic 1D array # pdl> p $b = pdl [ 1, 2, 3, 4, 5, 6 ] # pdl> p $b = pdl q[ 1 2 3 4 5 6 ] # pdl> p $b = pdl q[1,2,3,4,5,6] # [1 2 3 4 5 6] # 1D array with signs # pdl> p $c = pdl [ 7, -2, +5 ] # pdl> p $c = pdl q[ 7 -2 +5 ] # pdl> p $c = pdl q[ 7, -2, +5 ] # [7 -2 5] # 1D array with mixed ops and signs # pdl> p $d = pdl [ 7 - 2, +5 ] # pdl> p $d = pdl q[ 7 - 2 +5 ] # [5 5] # ...another # pdl> p $d = pdl [ 7, -2 + 5 ] # pdl> p $d = pdl q[ 7 -2 + 5 ] # [7 3] # 1D array with ops, not signs # pdl> p $d = pdl [ 7 - 2 + 5 ] # pdl> p $d = pdl q[ 7 - 2 + 5 ] # 10 # A [2,3,4] shape piddle # pdl> p $d = pdl [ [ [0, 1], [4, 0], [0, 3] ], # [ [2, 0], [4, 0], [4, 1] ], # [ [0, 1], [3, 2], [1, 4] ], # [ [1, 2], [2, 2], [2, 1] ] ]; # # [ # [ # [0 1] # [4 0] # [0 3] # ] # [ # [2 0] # [4 0] # [4 1] # ] # [ # [0 1] # [3 2] # [1 4] # ] # [ # [1 2] # [2 2] # [2 1] # ] # ] # # ...the same, just different formatting... # # [ # [ [0 1] [4 0] [0 3] ] # [ [2 0] [4 0] [4 1] ] # [ [0 1] [3 2] [1 4] ] # [ [1 2] [2 2] [2 1] ] # ] # A 3x3 2D array # pdl> p pdl [ [1, 2, 3], [2, 1, 0], [2, 2, 1] ]; # pdl> p $e = pdl q[ [ 1 2 3 ] ; [ 2 1 0 ] ; [ 2 2 1 ] ]; # pdl> p pdl q[ 1 2 3 ; 2 1 0 ; 2 2 1 ] # this should be the same # # [ # [1 2 3] # [2 1 0] # [2 2 1] # ]