mailRe: [bug #6503] Uncaught nan in xh_vect


Others Months | Index by Date | Thread Index
>>   [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Header


Content

Posted by Chris MacRaild on August 03, 2006 - 17:57:
On Thu, 2006-08-03 at 23:50 +1000, Edward d'Auvergne wrote:

I'll look into it, but perhaps its sufficient to catch NaNs before
they
cause the problen in the first place (though this might be harder
than
it seems, see below...). Certainly it seems to me that the Grid
Search
should report failure if it cant find a function value less than
1e300.
This should ensure the starting point of the minimisation always
evaluates to a finite floating-point value, as long the user always
does
a grid search first.

Catching the NaN and maybe raising a 'RelaxError' might be best.  I
think 1e300 is the value I use as the initial value - it's used to
test the function tolerance.  NaN maybe a better starting value
though.  Then if NaN is returned an error can be thrown within the
code not in 'minimise/'.  Otherwise the point at which the NaN is
generated could be tracked down so the code causes the NaN can be
destroyed.

1e300 is the current starting value. Probably INF is the correct one to
use, but there are issues with Python's handling of all the special fp
values.

Raising an uncaught generic exception might be a bit heavy-handed. If it
is only one residue (eg.) causing the problem, it would be nice to catch
the problem, de-select the residue, and continue with the rest of the
calculation. This could be managed two ways: 1) raise a specific
exception from within the minimisation code, and catch that elsewhere
and de-select the offending residue. 2) have the minimiser return NaN or
INF, and have the higher-level code handle that.

Option 2 is the 'correct' way of doing things, in the sense that that is
what INF, NaN etc. exist for in the first place. On the other hand,
Python doesn't handle these values in a defined way, so it would take
some work to make this reliable. See below...


From what I can gather Python inherits its fp behaviour almost
entirely
from the underlying hardware/libc combination. This means NaN
behaviour
is platform dependent, and all the obvious ways of catching NaNs
(and
INFs and other special floats) tend to be non-portable (including
NaN !=
NaN). I'll look into other options.

Maybe the built in Python function 'cmp' could be used to catch the
NaN.  If two NaN values are supplied then the function should return
'0'.  If NaN is compared to Inf then the value should be 1.  Any other
number should return -1.  This is how Python 2.4 sees the world!
Unfortunately I also tried the 'cmp' function under Python 2.1 and all
comparisons returned zero.  According to the informative link
http://www.cs.ucla.edu/classes/winter04/cs131/hw/hw4.html version
2.3.3 and lower are likely to be affected.  If the NaN is to be caught
using 'cmp' it will most likely cause issues if older versions of
Python are used.  The relax manual says to use version 2.4 or higher
so it shouldn't be too important.  In addition if someone uses an old
Python version the likelihood of them encountering the issue is low.
Avoiding the NaN in the first place may be a better solution though.

on my machine (Python 2.4 on dual 64 bit AMD, GCC 4.0.2):

n
nan
cmp(n,n)
0
cmp(n,n*1)
1
a = 1e300*1e300
a
inf
a/a
nan
cmp(a/a,n)
-1
a2 = 1e1500**2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
OverflowError: (34, 'Numerical result out of range')

And it gets even more bizare that that if you go hunting - there is a
Python bug report somewhere for a simple test script that gives
different results depending on whether the .py file of the .pyc file is
run!

As I say, Python (of any version) has no defined behaviour when it comes
to special fp vaues - it inherits directly from the underlying c
environment, and c is no better at defining any of these things than
Python. The upshot is there is no simple and robust way of generating
NaN values (compare a and a2 above), nor is there a simple and robust
way of testing for a NaN value.

That said, there are ways around it which might be workable. I know of
two options:
1) Numpy has NaN and INF support, including isNaN() type functions. I
haven't tested them, and I don't know how they work, but they are there.
Of course this would involve transfering relax from Numeric to Numpy, or
adding an additional dependency. Neither of these are attractive
options, but nor is the bug...
2) there is an external module called fpconst which supplies similar
functionality. This relies on the python struct module to compare the
underlying bit sequence with the IEEE 754 standards. It seems to work
well on my machine, and I think most platforms should be compliant at
that level, but I'm not sure and I have limited opportunity to test
other platforms. On the up side the module is relatively small, and
could be incorporated into relax, so it need not be a dependency (its
under the Apache Licence).

Chris






Related Messages


Powered by MHonArc, Updated Fri Aug 04 16:20:21 2006