1# -*-perl-*- 2# 3# test some PDL core routines 4# 5 6use strict; 7use Test::More; 8 9BEGIN { 10 # if we've got this far in the tests then 11 # we can probably assume PDL::LiteF works! 12 # 13 eval { 14 require PDL::LiteF; 15 } or BAIL_OUT("PDL::LiteF failed: $@"); 16 plan tests => 75; 17 PDL::LiteF->import; 18} 19$| = 1; 20 21sub tapprox ($$) { 22 my ( $a, $b ) = @_; 23 my $d = abs( $a - $b ); 24 print "diff = [$d]\n"; 25 return $d <= 0.0001; 26} 27 28my $a_long = sequence long, 10; 29my $a_dbl = sequence 10; 30 31my $b_long = $a_long->slice('5'); 32my $b_dbl = $a_dbl->slice('5'); 33 34my $c_long = $a_long->slice('4:7'); 35my $c_dbl = $a_dbl->slice('4:7'); 36 37# test 'sclr' method 38# 39is $b_long->sclr, 5, "sclr test of 1-elem pdl (long)"; 40is $c_long->sclr, 4, "sclr test of 3-elem pdl (long)"; 41 42ok tapprox( $b_dbl->sclr, 5 ), "sclr test of 1-elem pdl (dbl)"; 43ok tapprox( $c_dbl->sclr, 4 ), "sclr test of 3-elem pdl (dbl)"; 44 45# switch multielement check on 46is( PDL->sclr({Check=>'barf'}), 2, "changed error mode of sclr" ); 47 48eval '$c_long->sclr'; 49like $@, qr/multielement piddle in 'sclr' call/, "sclr failed on multi-element piddle (long)"; 50 51eval '$c_dbl->sclr'; 52like $@, qr/multielement piddle in 'sclr' call/, "sclr failed on multi-element piddle (dbl)"; 53 54# test reshape barfing with negative args 55# 56eval 'my $d_long = $a_long->reshape(0,-3);'; 57like $@, qr/invalid dim size/, "reshape() failed with negative args (long)"; 58 59eval 'my $d_dbl = $a_dbl->reshape(0,-3);'; 60like $@, qr/invalid dim size/, "reshape() failed with negative args (dbl)"; 61 62# test reshape with no args 63my ( $a, $b, $c ); 64 65$a = ones 3,1,4; 66$b = $a->reshape; 67ok eq_array( [ $b->dims ], [3,4] ), "reshape()"; 68 69# test reshape(-1) and squeeze 70$a = ones 3,1,4; 71$b = $a->reshape(-1); 72$c = $a->squeeze; 73ok eq_array( [ $b->dims ], [3,4] ), "reshape(-1)"; 74ok all( $b == $c ), "squeeze"; 75 76$c++; # check dataflow in reshaped PDL 77ok all( $b == $c ), "dataflow"; # should flow back to b 78ok all( $a == 2 ), "dataflow"; 79 80our $d = pdl(5); # zero dim piddle and reshape/squeeze 81ok $d->reshape(-1)->ndims==0, "reshape(-1) on 0-dim PDL gives 0-dim PDL"; 82ok $d->reshape(1)->ndims==1, "reshape(1) on 0-dim PDL gives 1-dim PDL"; 83ok $d->reshape(1)->reshape(-1)->ndims==0, "reshape(-1) on 1-dim, 1-element PDL gives 0-dim PDL"; 84 85# reshape test related to bug SF#398 "$pdl->hdr items are lost after $pdl->reshape" 86$c = ones(25); 87$c->hdr->{demo} = "yes"; 88is($c->hdr->{demo}, "yes", "hdr before reshape"); 89$c->reshape(5,5); 90is($c->hdr->{demo}, "yes", "hdr after reshape"); 91 92 93 94# test topdl 95 96isa_ok( PDL->topdl(1), "PDL", "topdl(1) returns a piddle" ); 97isa_ok( PDL->topdl([1,2,3]), "PDL", "topdl([1,2,3]) returns a piddle" ); 98isa_ok( PDL->topdl(1,2,3), "PDL", "topdl(1,2,3) returns a piddle" ); 99$a=PDL->topdl(1,2,3); 100ok (($a->nelem == 3 and all($a == pdl(1,2,3))), "topdl(1,2,3) returns a 3-piddle containing (1,2,3)"); 101 102 103# test $PDL::undefval support in pdl (bug #886263) 104# 105is $PDL::undefval, 0, "default value of $PDL::undefval is 0"; 106 107$a = [ [ 2, undef ], [3, 4 ] ]; 108$b = pdl( $a ); 109$c = pdl( [ 2, 0, 3, 4 ] )->reshape(2,2); 110ok all( $b == $c ), "undef converted to 0 (dbl)"; 111ok eq_array( $a, [[2,undef],[3,4]] ), "pdl() has not changed input array"; 112 113$b = pdl( long, $a ); 114$c = pdl( long, [ 2, 0, 3, 4 ] )->reshape(2,2); 115ok all( $b == $c ), "undef converted to 0 (long)"; 116 117do { 118 local($PDL::undefval) = -999; 119 $a = [ [ 2, undef ], [3, 4 ] ]; 120 $b = pdl( $a ); 121 $c = pdl( [ 2, -999, 3, 4 ] )->reshape(2,2); 122 ok all( $b == $c ), "undef converted to -999 (dbl)"; 123 124 $b = pdl( long, $a ); 125 $c = pdl( long, [ 2, -999, 3, 4 ] )->reshape(2,2); 126 ok all( $b == $c ), "undef converted to -999 (long)"; 127} while(0); 128 129############## 130# Funky constructor cases 131 132# pdl of a pdl 133$a = pdl(pdl(5)); 134ok all( $a== pdl(5)), "pdl() can piddlify a piddle"; 135 136TODO: { 137 local $TODO = 'Known_problems bug sf.net #3011879' if ($PDL::Config{SKIP_KNOWN_PROBLEMS} or exists $ENV{SKIP_KNOWN_PROBLEMS}); 138 139 # pdl of mixed-dim pdls: pad within a dimension 140 $a = pdl( zeroes(5), ones(3) ); 141 ok all($a == pdl([0,0,0,0,0],[1,1,1,0,0])),"Piddlifying two piddles concatenates them and pads to length" or diag("a=$a\n"); 142} 143 144# pdl of mixed-dim pdls: pad a whole dimension 145$a = pdl( [[9,9],[8,8]], xvals(3)+1 ); 146ok all($a == pdl([[[9,9],[8,8],[0,0]] , [[1,0],[2,0],[3,0]] ])),"can concatenate mixed-dim piddles" or diag("a=$a\n"); 147 148# pdl of mixed-dim pdls: a hairier case 149$c = pdl [1], pdl[2,3,4], pdl[5]; 150ok all($c == pdl([[[1,0,0],[0,0,0]],[[2,3,4],[5,0,0]]])),"Can concatenate mixed-dim piddles: hairy case" or diag("c=$c\n"); 151 152# same thing, with undefval set differently 153do { 154 local($PDL::undefval) = 99; 155 $c = pdl [1], pdl[2,3,4], pdl[5]; 156 ok all($c == pdl([[[1,99,99],[99,99,99]],[[2,3,4],[5,99,99]]])), "undefval works for padding" or diag("c=$c\n");; 157} while(0); 158 159# empty pdl cases 160eval {$a = zeroes(2,0,1);}; 161ok(!$@,"zeroes accepts empty PDL specification"); 162 163eval { $b = pdl($a,sequence(2,0,1)); }; 164ok((!$@ and all(pdl($b->dims) == pdl(2,0,1,2))), "concatenating two empties gives an empty"); 165 166eval { $b = pdl($a,sequence(2,1,1)); }; 167ok((!$@ and all(pdl($b->dims) == pdl(2,1,1,2))), "concatenating an empty and a nonempty treats the empty as a filler"); 168 169eval { $b = pdl($a,5) }; 170ok((!$@ and all(pdl($b->dims)==pdl(2,1,1,2))), "concatenating an empty and a scalar on the right works"); 171ok( all($b==pdl([[[0,0]]],[[[5,0]]])), "concatenating an empty and a scalar on the right gives the right answer"); 172 173eval { $b = pdl(5,$a) }; 174ok((!$@ and all(pdl($b->dims)==pdl(2,1,1,2))), "concatenating an empty and a scalar on the left works"); 175ok( all($b==pdl([[[5,0]]],[[[0,0]]])), "concatenating an empty and a scalar on the left gives the right answer"); 176 177# end 178 179# cat problems 180eval {cat(1, pdl(1,2,3), {}, 6)}; 181ok ($@ ne '', 'cat barfs on non-piddle arguments'); 182like ($@, qr/Arguments 0, 2 and 3 are not piddles/, 'cat correctly identifies non-piddle arguments'); 183$@ = ''; 184eval {cat(1, pdl(1,2,3))}; 185like($@, qr/Argument 0 is not a piddle/, 'cat uses good grammar when discussing non-piddles'); 186$@ = ''; 187 188my $two_dim_array = cat(pdl(1,2), pdl(1,2)); 189eval {cat(pdl(1,2,3,4,5), $two_dim_array, pdl(1,2,3,4,5), pdl(1,2,3))}; 190ok ($@ ne '', 'cat barfs on mismatched piddles'); 191like($@, qr/The dimensions of arguments 1 and 3 do not match/ 192 , 'cat identifies all piddles with differing dimensions'); 193like ($@, qr/\(argument 0\)/, 'cat identifies the first actual piddle in the arg list'); 194$@ = ''; 195eval {cat(pdl(1,2,3), pdl(1,2))}; 196like($@, qr/The dimensions of argument 1 do not match/ 197 , 'cat uses good grammar when discussing piddle dimension mismatches'); 198$@ = ''; 199eval {cat(1, pdl(1,2,3), $two_dim_array, 4, {}, pdl(4,5,6), pdl(7))}; 200ok ($@ ne '', 'cat barfs combined screw-ups'); 201like($@, qr/Arguments 0, 3 and 4 are not piddles/ 202 , 'cat properly identifies non-piddles in combined screw-ups'); 203like($@, qr/arguments 2 and 6 do not match/ 204 , 'cat properly identifies piddles with mismatched dimensions in combined screw-ups'); 205like($@, qr/\(argument 1\)/, 206 'cat properly identifies the first actual piddle in combined screw-ups'); 207$@ = ''; 208 209eval {$a = cat(pdl(1),pdl(2,3));}; 210ok(!$@, 'cat(pdl(1),pdl(2,3)) succeeds'); 211ok( ($a->ndims==2 and $a->dim(0)==2 and $a->dim(1)==2), 'weird cat case has the right shape'); 212ok( all( $a == pdl([1,1],[2,3]) ), "cat does the right thing with catting a 0-pdl and 2-pdl together"); 213$@=''; 214 215my $by=xvals(byte,5)+253; 216my $so=xvals(short,5)+32766; 217my $lo=xvals(long,5)+32766; 218my $fl=float(xvals(5)+0.2); 219my @list = ($lo,$so,$fl,$by); 220my $c2 = cat(@list); 221is($c2->type,'float','concatentating different datatypes returns the highest type'); 222my $i=0; 223map{ ok(all($_==$list[$i]),"cat/dog symmetry for values ($i)"); $i++; }$c2->dog; 224 225# new_or_inplace 226$a = sequence(byte,5); 227 228 229$b = $a->new_or_inplace; 230ok( all($b==$a) && ($b->get_datatype == $a->get_datatype), "new_or_inplace with no pref returns something like the orig."); 231 232$b++; 233ok(all($b!=$a),"new_or_inplace with no inplace flag returns something disconnected from the orig."); 234 235$b = $a->new_or_inplace("float,long"); 236ok($b->type eq 'float',"new_or_inplace returns the first type in case of no match"); 237 238$b = $a->inplace->new_or_inplace; 239$b++; 240ok(all($b==$a),"new_or_inplace returns the original thing if inplace is set"); 241ok(!($b->is_inplace),"new_or_inplace clears the inplace flag"); 242 243# check reshape and dims. While we're at it, check null & empty creation too. 244my $null = null; 245my $empty = zeroes(0); 246ok($empty->nelem==0,"you can make an empty PDL with zeroes(0)"); 247ok("$empty" =~ m/Empty/, "an empty PDL prints 'Empty'"); 248 249ok($null->info =~ /^PDL->null$/, "null piddle's info is 'PDL->null'"); 250my $mt_info = $empty->info; 251$mt_info =~m/\[([\d,]+)\]/; 252my $mt_info_dims = pdl("$1"); 253ok(any($mt_info_dims==0), "empty piddle's info contains a 0 dimension"); 254ok($null->isnull && $null->isempty, "a null piddle is both null and empty"); 255ok(!$empty->isnull && $empty->isempty, "an empty piddle is empty but not null"); 256 257$a = short pdl(3,4,5,6); 258eval { $a->reshape(2,2);}; 259ok(!$@,"reshape succeeded in the normal case"); 260ok( ( $a->ndims==2 and $a->dim(0)==2 and $a->dim(1)==2 ), "reshape did the right thing"); 261ok(all($a == short pdl([[3,4],[5,6]])), "reshape moved the elements to the right place"); 262 263$b = $a->slice(":,:"); 264eval { $b->reshape(4); }; 265ok( $@ !~ m/Can\'t/, "reshape doesn't fail on a PDL with a parent" ); 266 267