Provided by: pdl_2.085-1ubuntu1_amd64 bug

NAME

       PDL::BadValues - Discussion of bad value support in PDL

DESCRIPTION

   What are bad values and why should I bother with them?
       Sometimes it's useful to be able to specify a certain value is 'bad' or 'missing'; for example CCDs used
       in astronomy produce 2D images which are not perfect since certain areas contain invalid data due to
       imperfections in the detector.  Whilst PDL's powerful index routines and all the complicated business
       with dataflow, slices, etc etc mean that these regions can be ignored in processing, it's awkward to do.
       It would be much easier to be able to say "$c = $x + $y" and leave all the hassle to the computer.

       If you're not interested in this, then you may (rightly) be concerned with how this affects the speed of
       PDL, since the overhead of checking for a bad value at each operation can be large.  Because of this, the
       code has been written to be as fast as possible - particularly when operating on ndarrays which do not
       contain bad values.  In fact, you should notice essentially no speed difference when working with
       ndarrays which do not contain bad values.

       You may also ask 'well, my computer supports IEEE NaN, so I already have this'.  They are different
       things; a bad value signifies "leave this out of processing", whereas NaN is the result of a
       mathematically-invalid operation.

       Many routines, such as "y=sin(x)", will propagate NaN's without the user having to code differently, but
       routines such as "qsort", or finding the median of an array, need to be re-coded to handle bad values.
       For floating-point datatypes, "NaN" and "Inf" can be used to flag bad values, but by default special
       values are used (Default bad values).

       There is one default bad value for each datatype, but as of PDL 2.040, you can have different bad values
       for separate ndarrays of the same type.

       You can use "NaN" as the bad value for any floating-point type, including complex.

   A quick overview
        pdl> $x = sequence(4,3);
        pdl> p $x
        [
         [ 0  1  2  3]
         [ 4  5  6  7]
         [ 8  9 10 11]
        ]
        pdl> $x = $x->setbadif( $x % 3 == 2 )
        pdl> p $x
        [
         [  0   1 BAD   3]
         [  4 BAD   6   7]
         [BAD   9  10 BAD]
        ]
        pdl> $x *= 3
        pdl> p $x
        [
         [  0   3 BAD   9]
         [ 12 BAD  18  21]
         [BAD  27  30 BAD]
        ]
        pdl> p $x->sum
        120

       "demo bad" within perldl or pdl2 gives a demonstration of some of the things possible with bad values.
       These are also available on PDL's web-site, at http://pdl.perl.org/demos/.  See PDL::Bad for useful
       routines for working with bad values and t/bad.t to see them in action.

       To find out if a routine supports bad values, use the "badinfo" command in perldl or pdl2 or the "-b"
       option to pdldoc.

       Each ndarray contains a flag - accessible via "$pdl->badflag" - to say whether there's any bad data
       present:

       •   If  false/0, which means there's no bad data here, the code supplied by the "Code" option to pp_def()
           is executed.

       •   If true/1, then this says there MAY be bad data in the ndarray, so use  the  code  in  the  "BadCode"
           option (assuming that the pp_def() for this routine has been updated to have a BadCode key).  You get
           all  the  advantages of broadcasting, as with the "Code" option, but it will run slower since you are
           going to have to handle the presence of bad values.

       If  you  create  an  ndarray,  it  will  have  its  bad-value  flag  set  to  0.  To  change  this,   use
       "$pdl->badflag($new_bad_status)",  where  $new_bad_status  can  be  0  or  1.   When a routine creates an
       ndarray,  its  bad-value  flag  will  depend  on  the  input  ndarrays:  unless  over-ridden   (see   the
       "CopyBadStatusCode" option to "pp_def"), the bad-value flag will be set true if any of the input ndarrays
       contain bad values.  To check that an ndarray really contains bad data, use the "check_badflag" method.

       NOTE: propagation of the badflag

       If you change the badflag of an ndarray, this change is propagated to all the children of an ndarray, so

          pdl> $x = zeroes(20,30);
          pdl> $y = $x->slice('0:10,0:10');
          pdl> $c = $y->slice(',(2)');
          pdl> print ">>c: ", $c->badflag, "\n";
          >>c: 0
          pdl> $x->badflag(1);
          pdl> print ">>c: ", $c->badflag, "\n";
          >>c: 1

       This is also propagated to the parents of an ndarray, so

          pdl> print ">>a: ", $x->badflag, "\n";
          >>a: 1
          pdl> $c->badflag(0);
          pdl> print ">>a: ", $x->badflag, "\n";
          >>a: 0

       There's  also the issue of what happens if you change the badvalue of an ndarray - should these propagate
       to children/parents (yes) or whether you should only be able to change the badvalue at the 'top' level  -
       i.e. those ndarrays which do not have parents.

       The  orig_badvalue()  method  returns  the compile-time value for a given datatype. It works on ndarrays,
       PDL::Type objects, and numbers - eg

         $pdl->orig_badvalue(), byte->orig_badvalue(), and orig_badvalue(4).

       To get the current bad value, use the badvalue() method - it has the same syntax as orig_badvalue().

       To change the current bad value, supply the new number to badvalue - eg

         $pdl->badvalue(2.3), byte->badvalue(2), badvalue(5,-3e34).

       Note: the value is silently converted to the correct C type, and returned  -  i.e.  "byte->badvalue(-26)"
       returns 230 on my Linux machine.

       Note  that  changes  to the bad value are NOT propagated to previously-created ndarrays - they will still
       have the bad flag set, but suddenly the elements that were bad will become 'good', but containing the old
       bad value.  See discussion below.

   Bad values and boolean operators
       For those boolean operators in PDL::Ops, evaluation on a bad value returns the bad value. This:

        $mask = $img > $thresh;

       correctly propagates bad values. This will omit any bad values, but return a bad value if  there  are  no
       good ones:

        $bool = any( $img > $thresh );

       As of 2.077, a bad value used as a boolean will throw an exception.

       When using one of the 'projection' functions in PDL::Ufunc - such as orover - bad values are skipped over
       (see  the  documentation  of  these  functions for the current handling of the case when all elements are
       bad).

IMPLEMENTATION DETAILS

       A new flag has been added to the state of an ndarray - "PDL_BADVAL". If unset, then the ndarray does  not
       contain  bad  values,  and so all the support code can be ignored. If set, it does not guarantee that bad
       values are present, just that they should be checked for.

       The "pdl_trans" structure has been extended to include an integer value,  "bvalflag",  which  acts  as  a
       switch  to  tell  the  code  whether  to  handle bad values or not. This value is set if any of the input
       ndarrays  have  their  "PDL_BADVAL"  flag  set  (although  this  code  can   be   replaced   by   setting
       "FindBadStateCode" in pp_def).

   Default bad values
       The  default  bad  values  are  now stored in a structure within the Core PDL structure - "PDL.bvals" (eg
       Basic/Core/pdlcore.h.PL); see also  "typedef  badvals"  in  Basic/Core/pdl.h.PL  and  the  BOOT  code  of
       Basic/Core/Core.xs.PL where the values are initialised to (hopefully) sensible values.  See "badvalue" in
       PDL::Bad and "orig_badvalue" in PDL::Bad for read/write routines to the values.

       The  default/original  bad  values  are  set  to  the C type's maximum (unsigned integers) or the minimum
       (floating-point and signed integers).

   How do I change a routine to handle bad values?
       See "BadCode" in PDL::PP and "HandleBad" in PDL::PP.

       If you have a routine that you want to be able to use as in-place, look at the  routines  in  bad.pd  (or
       ops.pd)  which  use  the  "in-place"  option  to see how the bad flag is propagated to children using the
       "xxxBadStatusCode" options.  I decided not to automate this as rules would be a little complex, since not
       every in-place op will need to propagate the badflag (eg unary functions).

       This all means that you can change

          Code => '$a() = $b() + $c();'

       to

          BadCode => 'if ( $ISBAD(b()) || $ISBAD(c()) ) {
                        $SETBAD(a());
                      } else {
                        $a() = $b() + $c();
                      }'

       leaving Code as it is. PP::PDLCode will then create code something like

          if ( __trans->bvalflag ) {
               broadcastloop over BadCode
          } else {
               broadcastloop over Code
          }

WHAT ABOUT DOCUMENTATION?

       One of the strengths of PDL is its on-line documentation. The aim  is  to  use  this  system  to  provide
       information  on how/if a routine supports bad values: in many cases pp_def() contains all the information
       anyway, so the function-writer doesn't need to do anything at  all!  For  the  cases  when  this  is  not
       sufficient,  there's  the  "BadDoc" option. For code written at the Perl level - i.e. in a .pm file - use
       the "=for bad" pod directive.

       This information will be available via man/pod2man/html documentation.  It's  also  accessible  from  the
       "perldl" or "pdl2" shells - using the "badinfo" command - and the "pdldoc" shell command - using the "-b"
       option.

AUTHOR

       Copyright (C) Doug Burke (djburke@cpan.org), 2000, 2006.

       The per-ndarray bad value support is by Heiko Klein (2006).

perl v5.38.2                                       2024-04-10                                      BADVALUES(1p)