Re: [Numpy-discussion] wrong casting of augmented assignment statements
I've written a self-contained example that shows that numpy indeed tries to call the __float__ method. What is buggy is what happens if calling the __float__ method raises an Exception. Then numpy assumes (in this case wrongly) that the object should be casted to the neutral element. I'd guess that the __float__ method is called somewhere in a try: statement and if an exception is raised it is casted to the neutral element. I've tried to locate the corresponding code in the numpy sources but I got lost. Could someone be so kind and point me to it? start code -- import numpy print 'numpy.__version__ = ',numpy.__version__ class ad1: def __init__(self,x): self.x = x def __mul__(self,other): if not isinstance(other, self.__class__): return self.__class__(self.x * other) return self.__class__(self.x * other.x) def __rmul__(self,other): return self * other def __float__(self): raise Exception('this is not possible') def __str__(self): return str(self.x) print '\nThis example yields buggy behavior:' x1 = numpy.array([ad1(1.), ad1(2.), ad1(3.)]) y1 = numpy.random.rand(3) print 'y1= ',y1 print 'x1= ',x1 z1 = x1 * y1 y1 *= x1# this should call the __float__ method of ad1 which would raise an Exception print 'z1=x1*y1',z1 print 'y1*=x1 ',y1 class ad2: def __init__(self,x): self.x = x def __mul__(self,other): if not isinstance(other, self.__class__): return self.__class__(self.x * other) return self.__class__(self.x * other.x) def __rmul__(self,other): return self * other def __float__(self): return float(self.x) def __str__(self): return str(self.x) print '\nThis example works fine:' x2 = numpy.array([ad2(1.), ad2(2.), ad2(3.)]) y2 = numpy.random.rand(3) print 'y2= ',y2 print 'x2= ',x2 z2 = x2 * y2 y2 *= x2# this should call the __float__ method of ad1 which would raise an Exception print 'z2=x2*y2',z2 print 'y2*=x2 ',y2 end code -- output - wal...@wronski$ python wrong_casting_object_to_float_of_augmented_assignment_statements.py numpy.__version__ = 1.3.0 This example yields buggy behavior: y1= [ 0.15322371 0.47915903 0.81153995] x1= [1.0 2.0 3.0] z1=x1*y1 [0.153223711127 0.958318053803 2.43461983729] y1*=x1 [ 0.15322371 0.47915903 0.81153995] This example works fine: y2= [ 0.49377037 0.60908423 0.79772095] x2= [1.0 2.0 3.0] z2=x2*y2 [0.493770370747 1.21816846399 2.39316283707] y2*=x2 [ 0.49377037 1.21816846 2.39316284] end output - On Tue, Jan 12, 2010 at 7:38 PM, Robert Kern wrote: > On Tue, Jan 12, 2010 at 12:31, Sebastian Walter > wrote: >> On Tue, Jan 12, 2010 at 7:09 PM, Robert Kern wrote: >>> On Tue, Jan 12, 2010 at 12:05, Sebastian Walter >>> wrote: Hello, I have a question about the augmented assignment statements *=, +=, etc. Apparently, the casting of types is not working correctly. Is this known resp. intended behavior of numpy? >>> >>> Augmented assignment modifies numpy arrays in-place, so the usual >>> casting rules for assignment into an array apply. Namely, the array >>> being assigned into keeps its dtype. >> >> what are the usual casting rules? > > For assignment into an array, the array keeps its dtype and the data > being assigned into it will be cast to that dtype. > >> How does numpy know how to cast an object to a float? > > For a general object, numpy will call its __float__ method. > >>> If you do not want in-place modification, do not use augmented assignment. >> >> Normally, I'd be perfectly fine with that. >> However, this particular problem occurs when you try to automatically >> differentiate an algorithm by using an Algorithmic Differentiation >> (AD) tool. >> E.g. given a function >> >> x = numpy.ones(2) >> def f(x): >> a = numpy.ones(2) >> a *= x >> return numpy.sum(a) >> >> one would use an AD tool as follows: >> x = numpy.array([adouble(1.), adouble(1.)]) >> y = f(x) >> >> but since the casting from object to float is not possible the >> computed gradient \nabla_x f(x) will be wrong. > > Sorry, but that's just a limitation of the AD approach. There are all > kinds of numpy constructions that AD can't handle. > > -- > Robert Kern > > "I have come to believe that the whole world is an enigma, a harmless > enigma that is made terrible by our own mad attempt to interpret it as > though it had an underlying truth." > -- Umberto Eco > ___ > NumPy-Discussion mailing list > NumPy-Discussion@scipy.org > http://mail.scipy.org/mailman/listinfo/numpy-discussion > ___ NumPy-Discussion mailing list NumPy-Discussion@scipy.org http://mail.scipy.org/mailman/listinfo/numpy-discussion
Re: [Numpy-discussion] wrong casting of augmented assignment statements
Sebastian Walter wrote: >>> However, this particular problem occurs when you try to automatically >>> differentiate an algorithm by using an Algorithmic Differentiation >>> (AD) tool. >>> E.g. given a function >>> >>> x = numpy.ones(2) >>> def f(x): >>> a = numpy.ones(2) >>> a *= x >>> return numpy.sum(a) I don't know anything about AD, but in general, when I write a function that requires a given numpy array type as input, I'll do something like: def f(x): x = np.asarray(a, dtype=np.float) a = np.ones(2) a *= x return np.sum(a) That makes the casting explicit, and forces it to happen at the top of the function, where the error will be more obvious. asarray will just pass through a conforming array, so little performance penalty when you do give it the right type. -Chris -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R(206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception chris.bar...@noaa.gov ___ NumPy-Discussion mailing list NumPy-Discussion@scipy.org http://mail.scipy.org/mailman/listinfo/numpy-discussion
Re: [Numpy-discussion] wrong casting of augmented assignment statements
On Tue, Jan 12, 2010 at 7:38 PM, Robert Kern wrote: > On Tue, Jan 12, 2010 at 12:31, Sebastian Walter > wrote: >> On Tue, Jan 12, 2010 at 7:09 PM, Robert Kern wrote: >>> On Tue, Jan 12, 2010 at 12:05, Sebastian Walter >>> wrote: Hello, I have a question about the augmented assignment statements *=, +=, etc. Apparently, the casting of types is not working correctly. Is this known resp. intended behavior of numpy? >>> >>> Augmented assignment modifies numpy arrays in-place, so the usual >>> casting rules for assignment into an array apply. Namely, the array >>> being assigned into keeps its dtype. >> >> what are the usual casting rules? > > For assignment into an array, the array keeps its dtype and the data > being assigned into it will be cast to that dtype. > >> How does numpy know how to cast an object to a float? > > For a general object, numpy will call its __float__ method. 1) the object does not have a __float__ method. 2) I've now implemented the __float__ method (to raise an error). However, it doesn't get called. All objects are casted to 1. > >>> If you do not want in-place modification, do not use augmented assignment. >> >> Normally, I'd be perfectly fine with that. >> However, this particular problem occurs when you try to automatically >> differentiate an algorithm by using an Algorithmic Differentiation >> (AD) tool. >> E.g. given a function >> >> x = numpy.ones(2) >> def f(x): >> a = numpy.ones(2) >> a *= x >> return numpy.sum(a) >> >> one would use an AD tool as follows: >> x = numpy.array([adouble(1.), adouble(1.)]) >> y = f(x) >> >> but since the casting from object to float is not possible the >> computed gradient \nabla_x f(x) will be wrong. > > Sorry, but that's just a limitation of the AD approach. There are all > kinds of numpy constructions that AD can't handle. > > -- > Robert Kern > > "I have come to believe that the whole world is an enigma, a harmless > enigma that is made terrible by our own mad attempt to interpret it as > though it had an underlying truth." > -- Umberto Eco > ___ > NumPy-Discussion mailing list > NumPy-Discussion@scipy.org > http://mail.scipy.org/mailman/listinfo/numpy-discussion > ___ NumPy-Discussion mailing list NumPy-Discussion@scipy.org http://mail.scipy.org/mailman/listinfo/numpy-discussion
Re: [Numpy-discussion] wrong casting of augmented assignment statements
On Tue, Jan 12, 2010 at 12:31, Sebastian Walter wrote: > On Tue, Jan 12, 2010 at 7:09 PM, Robert Kern wrote: >> On Tue, Jan 12, 2010 at 12:05, Sebastian Walter >> wrote: >>> Hello, >>> I have a question about the augmented assignment statements *=, +=, etc. >>> Apparently, the casting of types is not working correctly. Is this >>> known resp. intended behavior of numpy? >> >> Augmented assignment modifies numpy arrays in-place, so the usual >> casting rules for assignment into an array apply. Namely, the array >> being assigned into keeps its dtype. > > what are the usual casting rules? For assignment into an array, the array keeps its dtype and the data being assigned into it will be cast to that dtype. > How does numpy know how to cast an object to a float? For a general object, numpy will call its __float__ method. >> If you do not want in-place modification, do not use augmented assignment. > > Normally, I'd be perfectly fine with that. > However, this particular problem occurs when you try to automatically > differentiate an algorithm by using an Algorithmic Differentiation > (AD) tool. > E.g. given a function > > x = numpy.ones(2) > def f(x): > a = numpy.ones(2) > a *= x > return numpy.sum(a) > > one would use an AD tool as follows: > x = numpy.array([adouble(1.), adouble(1.)]) > y = f(x) > > but since the casting from object to float is not possible the > computed gradient \nabla_x f(x) will be wrong. Sorry, but that's just a limitation of the AD approach. There are all kinds of numpy constructions that AD can't handle. -- Robert Kern "I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco ___ NumPy-Discussion mailing list NumPy-Discussion@scipy.org http://mail.scipy.org/mailman/listinfo/numpy-discussion
Re: [Numpy-discussion] wrong casting of augmented assignment statements
On Tue, Jan 12, 2010 at 7:09 PM, Robert Kern wrote: > On Tue, Jan 12, 2010 at 12:05, Sebastian Walter > wrote: >> Hello, >> I have a question about the augmented assignment statements *=, +=, etc. >> Apparently, the casting of types is not working correctly. Is this >> known resp. intended behavior of numpy? > > Augmented assignment modifies numpy arrays in-place, so the usual > casting rules for assignment into an array apply. Namely, the array > being assigned into keeps its dtype. what are the usual casting rules? How does numpy know how to cast an object to a float? > > If you do not want in-place modification, do not use augmented assignment. Normally, I'd be perfectly fine with that. However, this particular problem occurs when you try to automatically differentiate an algorithm by using an Algorithmic Differentiation (AD) tool. E.g. given a function x = numpy.ones(2) def f(x): a = numpy.ones(2) a *= x return numpy.sum(a) one would use an AD tool as follows: x = numpy.array([adouble(1.), adouble(1.)]) y = f(x) but since the casting from object to float is not possible the computed gradient \nabla_x f(x) will be wrong. > > -- > Robert Kern > > "I have come to believe that the whole world is an enigma, a harmless > enigma that is made terrible by our own mad attempt to interpret it as > though it had an underlying truth." > -- Umberto Eco > ___ > NumPy-Discussion mailing list > NumPy-Discussion@scipy.org > http://mail.scipy.org/mailman/listinfo/numpy-discussion > ___ NumPy-Discussion mailing list NumPy-Discussion@scipy.org http://mail.scipy.org/mailman/listinfo/numpy-discussion
Re: [Numpy-discussion] wrong casting of augmented assignment statements
On Tue, Jan 12, 2010 at 1:05 PM, Sebastian Walter wrote: > Hello, > I have a question about the augmented assignment statements *=, +=, etc. > Apparently, the casting of types is not working correctly. Is this > known resp. intended behavior of numpy? > (I'm using numpy.__version__ = '1.4.0.dev7039' on this machine but I > remember a recent checkout of numpy yielded the same result). > > The problem is best explained at some examples: > > wrong casting from float to int:: > > In [1]: import numpy > > In [2]: x = numpy.ones(2,dtype=int) > > In [3]: y = 1.3 * numpy.ones(2,dtype=float) > > In [4]: z = x * y > > In [5]: z > Out[5]: array([ 1.3, 1.3]) > > In [6]: x *= y > > In [7]: x > Out[7]: array([1, 1]) > > In [8]: x.dtype > Out[8]: dtype('int32') > > wrong casting from float to object:: > > In [1]: import numpy > > In [2]: import adolc > > In [3]: x = adolc.adouble(numpy.array([1,2,3],dtype=float)) > > In [4]: y = numpy.array([4,5,6],dtype=float) > > In [5]: x > Out[5]: array([1(a), 2(a), 3(a)], dtype=object) > > In [6]: y > Out[6]: array([ 4., 5., 6.]) > > In [7]: x * y > Out[7]: array([4(a), 10(a), 18(a)], dtype=object) > > In [8]: y *= x > > In [9]: y > > Out[9]: array([ 4., 5., 6.]) > > > It is inconsistent to the Python behavior:: > > In [9]: a = 1 > > In [10]: b = 1.3 > > In [11]: c = a * b > > In [12]: c > Out[12]: 1.3 > > In [13]: a *= b > > In [14]: a > Out[14]: 1.3 > > > I would expect that numpy should at least raise an exception in the > case of casting object to float. > Any thoughts? You are assigning to an existing array, which implies casting to the dtype of that array. It's the behavior that I would expect. If you want upcasting then don't use inplace *= , ... Josef > > regards, > Sebastian > ___ > NumPy-Discussion mailing list > NumPy-Discussion@scipy.org > http://mail.scipy.org/mailman/listinfo/numpy-discussion > ___ NumPy-Discussion mailing list NumPy-Discussion@scipy.org http://mail.scipy.org/mailman/listinfo/numpy-discussion
Re: [Numpy-discussion] wrong casting of augmented assignment statements
On Tue, Jan 12, 2010 at 12:05, Sebastian Walter wrote: > Hello, > I have a question about the augmented assignment statements *=, +=, etc. > Apparently, the casting of types is not working correctly. Is this > known resp. intended behavior of numpy? Augmented assignment modifies numpy arrays in-place, so the usual casting rules for assignment into an array apply. Namely, the array being assigned into keeps its dtype. If you do not want in-place modification, do not use augmented assignment. -- Robert Kern "I have come to believe that the whole world is an enigma, a harmless enigma that is made terrible by our own mad attempt to interpret it as though it had an underlying truth." -- Umberto Eco ___ NumPy-Discussion mailing list NumPy-Discussion@scipy.org http://mail.scipy.org/mailman/listinfo/numpy-discussion