Tour of the bad value support in PDL

Each piddle contains a flag - accessible via the badflag() method - which indicates whether:

If the flag is set, then the routines (well, those that have been converted) will process these bad values correctly, otherwise they are ignored.

The code has been written so as to provide as little overhead as possible; therefore there should be almost no difference in the time it takes to process piddles which do not have their bad flag set.

# There are 2 ways to see whether bad-value support has been
# compiled into your PDL shell:

pdl> print("You can use bad values.\n") if $PDL::Bad::Status;
# or

pdl> use PDL::Config;
pdl> print("You can stil use bad values.\n") if $PDL::Config{WITH_BADVAL};
# note that PDL::Bad is included by default when you use
# 'use PDL', 'use PDL::Lite', or 'use PDL::LiteF'

You can use bad values.
You can stil use bad values.
# create a piddle

pdl> $a = byte(1,2,3);
pdl> print( "Bad flag (a) == ", $a->badflag(), "\n" );
# set bad flag, even though all the data is good

pdl> $a->badflag(1);
pdl> print( "Bad flag (a) == ", $a->badflag(), "\n" );
# note the bad flag is infectious

pdl> $b = 2 * $a;
pdl> print( "Bad flag (b) == ", $b->badflag(), "\n\n" );

Bad flag (a) == 0
Bad flag (a) == 1
Bad flag (b) == 1
# the badflag is also included in the state info of
# piddle

pdl> $c = pdl(2,3); # just a piddle without the badflag set
pdl> print "   Type   Dimension        State          Mem\n";
pdl> print "-------------------------------------------------\n";
pdl> print "a ", $a->info("%-6T %-15D   %-5S  %12M"), "\n";
pdl> print "b ", $b->info("%-6T %-15D   %-5S  %12M"), "\n";
pdl> print "c ", $c->info("%-6T %-15D   %-5S  %12M"), "\n\n";

   Type   Dimension        State          Mem
a Byte   D [3]             PB           0.00Kb
b Byte   D [3]             PB           0.00Kb
c Double D [2]             P            0.02Kb
pdl> print "No bad values:   $a\n";
# set the middle value bad

pdl> $a->setbadat(1);
# now print out

pdl> print "Some bad values: $a\n";
pdl> print "b contains:      $b\n";
pdl> $c = $a + $b;
pdl> print "so a + b =       $c\n\n";

No bad values:   [1 2 3]
Some bad values: [1 BAD 3]
b contains:      [2 4 6]
so a + b =       [3 BAD 9]
# The module PDL::Bad contains a number of routines designed
# to make using bad values easy.

pdl> print "a contains ", $a->nbad, " bad elements.\n";
pdl> print "The bad value for type #",$a->get_datatype," is ",$a->badvalue,"\n";
pdl> print "It is easy to find whether a value is good: ", isgood($a), "\n\n";
pdl> print "or to remove the bad values\n";
pdl> $a->inplace->setbadtoval(23);
pdl> print "a = $a and \$a->badflag == ", $a->badflag, "\n\n";

a contains 1 bad elements.
The bad value for type #0 is 255
It is easy to find whether a value is good: [1 0 1]

or to remove the bad values
a = [1 23 3] and $a->badflag == 0
pdl> print "We can even label certain values as bad!\n";
pdl> $a = sequence(3,3);
pdl> $a = $a->setbadif( $a % 2 );
pdl> print $a;

We can even label certain values as bad!

 [  0 BAD   2]
 [BAD   4 BAD]
 [  6 BAD   8]
# the issue of how to cope with dataflow is not fully resolved. At
# present, if you change the badflag of a piddle, all its children
# are also changed:

pdl> $a = sequence( byte, 2, 3 );
pdl> $a = $a->setbadif( $a == 3 );
pdl> $b = $a->slice("(1),:");
pdl> print "b = $b\tbadflag = ", $b->badflag, "\n";
pdl> $a->inplace->setbadtoval(3);
pdl> print "b = $b\tbadflag = ", $b->badflag, "\n\n";

b = [1 BAD 5]	badflag = 1
b = [1 3 5]	badflag = 0

# One area that is likely to cause confusion is the return value from
# comparison operators (e.g. all and any) when ALL elements are bad.
# Currently, the bad value is returned; however most code will not
# be aware of this and just see it as a true or false value (depending
# on the numerical value used to store bad values).
# There is also the fact that the bad value need not relate to the
# type of the input piddle (due to internal conversion to an 'int +').

pdl> $a = ones(3); $a = $a->setbadif( $a == 1 );
pdl> print "Any returns: ", any( $a> 2 ), "\n";
pdl> print "which is the bad value of 'long' (", long->badvalue, ").\n";
pdl> print "Whereas the bad value for \$a is: ", $a->badvalue, "\n";

Any returns: -2147483648
which is the bad value of 'long' (-2147483648).
Whereas the bad value for $a is: -1.79769313486232e+308

Many of the 'core' routines have been converted to handle bad values. However, some (including most of the additional modules) have not, either because it does not make sense or its too much work to do!

To find out the status of a particular routine, use the 'badinfo' command in the PDL shell (this information is also included when you do 'help'), or the '-b' switch of pdldoc.