[pypy-commit] pypy numpypy-complex2: add ndarray.real, ndarray.imag; properly promote to complex; move rAlmostEqual out of space
mattip
noreply at buildbot.pypy.org
Thu Sep 13 00:14:17 CEST 2012
Author: mattip <matti.picus at gmail.com>
Branch: numpypy-complex2
Changeset: r57306:207ac3dd1b78
Date: 2012-09-13 01:13 +0300
http://bitbucket.org/pypy/pypy/changeset/207ac3dd1b78/
Log: add ndarray.real, ndarray.imag; properly promote to complex; move
rAlmostEqual out of space
diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py
--- a/pypy/module/micronumpy/interp_boxes.py
+++ b/pypy/module/micronumpy/interp_boxes.py
@@ -295,27 +295,6 @@
class W_ComplexFloatingBox(W_InexactBox):
_attrs_ = ()
-
-class W_Complex64Box(ComplexBox, W_ComplexFloatingBox):
- descr__new__, _get_dtype = new_dtype_getter("complex64")
- _COMPONENTS_BOX = W_Float32Box
-
- def descr_get_real(self, space):
- dtype = W_Float32Box._get_dtype(space)
- box = self.convert_real_to(dtype)
- assert isinstance(box, W_Float32Box)
- return space.wrap(box)
-
- def descr_get_imag(self, space):
- dtype = W_Float32Box._get_dtype(space)
- box = self.convert_imag_to(dtype)
- assert isinstance(box, W_Float32Box)
- return space.wrap(box)
-
-class W_Complex128Box(ComplexBox, W_ComplexFloatingBox):
- descr__new__, _get_dtype = new_dtype_getter("complex128")
- _COMPONENTS_BOX = W_Float64Box
-
def descr_get_real(self, space):
dtype = self._COMPONENTS_BOX._get_dtype(space)
box = self.convert_real_to(dtype)
@@ -328,8 +307,17 @@
assert isinstance(box, self._COMPONENTS_BOX)
return space.wrap(box)
+
+class W_Complex64Box(ComplexBox, W_ComplexFloatingBox):
+ descr__new__, _get_dtype = new_dtype_getter("complex64")
+ _COMPONENTS_BOX = W_Float32Box
+
+
+class W_Complex128Box(ComplexBox, W_ComplexFloatingBox):
+ descr__new__, _get_dtype = new_dtype_getter("complex128")
+ _COMPONENTS_BOX = W_Float64Box
+
-
W_GenericBox.typedef = TypeDef("generic",
__module__ = "numpypy",
@@ -520,13 +508,13 @@
W_Complex128Box.typedef = TypeDef("complex128", (W_ComplexFloatingBox.typedef, complex_typedef),
__module__ = "numpypy",
__new__ = interp2app(W_Complex128Box.descr__new__.im_func),
- real = GetSetProperty(W_Complex128Box.descr_get_real),
- imag = GetSetProperty(W_Complex128Box.descr_get_imag),
+ real = GetSetProperty(W_ComplexFloatingBox.descr_get_real),
+ imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag),
)
W_Complex64Box.typedef = TypeDef("complex64", (W_ComplexFloatingBox.typedef),
__module__ = "numpypy",
__new__ = interp2app(W_Complex64Box.descr__new__.im_func),
- real = GetSetProperty(W_Complex64Box.descr_get_real),
- imag = GetSetProperty(W_Complex64Box.descr_get_imag),
+ real = GetSetProperty(W_ComplexFloatingBox .descr_get_real),
+ imag = GetSetProperty(W_ComplexFloatingBox.descr_get_imag),
)
diff --git a/pypy/module/micronumpy/interp_numarray.py b/pypy/module/micronumpy/interp_numarray.py
--- a/pypy/module/micronumpy/interp_numarray.py
+++ b/pypy/module/micronumpy/interp_numarray.py
@@ -305,6 +305,8 @@
descr_neg = _unaryop_impl("negative")
descr_abs = _unaryop_impl("absolute")
descr_invert = _unaryop_impl("invert")
+ descr_get_real = _unaryop_impl("real")
+ descr_get_imag = _unaryop_impl("imag")
def descr_nonzero(self, space):
if self.get_size() > 1:
@@ -551,6 +553,8 @@
swapaxes = interp2app(W_NDimArray.descr_swapaxes),
flat = GetSetProperty(W_NDimArray.descr_get_flatiter),
item = interp2app(W_NDimArray.descr_item),
+ real = GetSetProperty(W_NDimArray.descr_get_real),
+ imag = GetSetProperty(W_NDimArray.descr_get_imag),
__array_interface__ = GetSetProperty(W_NDimArray.descr_array_iface),
)
@@ -585,8 +589,9 @@
for w_elem in elems_w:
dtype = interp_ufuncs.find_dtype_for_scalar(space, w_elem,
dtype)
- if dtype is interp_dtype.get_dtype_cache(space).w_float64dtype:
- break
+ #if dtype is interp_dtype.get_dtype_cache(space).w_float64dtype:
+ # break
+
if dtype is None:
dtype = interp_dtype.get_dtype_cache(space).w_float64dtype
if ndmin > len(shape):
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -354,6 +354,14 @@
# Some operations promote op(bool, bool) to return int8, rather than bool
if promote_bools and (dt1.kind == dt2.kind == interp_dtype.BOOLLTR):
return interp_dtype.get_dtype_cache(space).w_int8dtype
+
+ # Everything promotes to complex
+ if dt2.num == 14 or dt2.num == 15 or dt1.num == 14 or dt2.num == 15:
+ if dt2.num == 15 or dt1.num == 15:
+ return interp_dtype.get_dtype_cache(space).w_complex128dtype
+ else:
+ return interp_dtype.get_dtype_cache(space).w_complex64dtype
+
if promote_to_float:
return find_unaryop_result_dtype(space, dt2, promote_to_float=True)
# If they're the same kind, choose the greater one.
@@ -428,7 +436,6 @@
int64_dtype = interp_dtype.get_dtype_cache(space).w_int64dtype
complex_type = interp_dtype.get_dtype_cache(space).w_complex128dtype
float_type = interp_dtype.get_dtype_cache(space).w_float64dtype
-
if isinstance(w_obj, interp_boxes.W_GenericBox):
dtype = w_obj.get_dtype(space)
if current_guess is None:
@@ -455,7 +462,8 @@
current_guess is complex_type or current_guess is float_type):
return complex_type
return current_guess
-
+ if current_guess is complex_type:
+ return complex_type
return interp_dtype.get_dtype_cache(space).w_float64dtype
@@ -529,6 +537,8 @@
("signbit", "signbit", 1, {"bool_result": True}),
("reciprocal", "reciprocal", 1),
("conjugate", "conj", 1),
+ ("real", "real", 1),
+ ("imag", "imag", 1),
("fabs", "fabs", 1, {"promote_to_float": True,
"allow_complex": False}),
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -2,58 +2,8 @@
from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
from math import isnan, isinf, copysign
-from sys import version_info
from pypy.conftest import option
-def rAlmostEqual(a, b, rel_err = 2e-15, abs_err = 5e-323, msg=''):
- """Fail if the two floating-point numbers are not almost equal.
-
- Determine whether floating-point values a and b are equal to within
- a (small) rounding error. The default values for rel_err and
- abs_err are chosen to be suitable for platforms where a float is
- represented by an IEEE 754 double. They allow an error of between
- 9 and 19 ulps.
- """
-
- # special values testing
- if isnan(a):
- if isnan(b):
- return True,''
- raise AssertionError(msg + '%r should be nan' % (b,))
-
- if isinf(a):
- if a == b:
- return True,''
- raise AssertionError(msg + 'finite result where infinity expected: '+ \
- 'expected %r, got %r' % (a, b))
-
- # if both a and b are zero, check whether they have the same sign
- # (in theory there are examples where it would be legitimate for a
- # and b to have opposite signs; in practice these hardly ever
- # occur).
- if not a and not b:
- # only check it if we are running on top of CPython >= 2.6
- if version_info >= (2, 6) and copysign(1., a) != copysign(1., b):
- raise AssertionError( msg + \
- 'zero has wrong sign: expected %r, got %r' % (a, b))
-
- # if a-b overflows, or b is infinite, return False. Again, in
- # theory there are examples where a is within a few ulps of the
- # max representable float, and then b could legitimately be
- # infinite. In practice these examples are rare.
- try:
- absolute_error = abs(b-a)
- except OverflowError:
- pass
- else:
- # test passes if either the absolute error or the relative
- # error is sufficiently small. The defaults amount to an
- # error of between 9 ulps and 19 ulps on an IEEE-754 compliant
- # machine.
- if absolute_error <= max(abs_err, rel_err * abs(a)):
- return True,''
- raise AssertionError(msg + '%r and %r are not sufficiently close' % (a, b))
-
class AppTestUfuncs(BaseNumpyAppTest):
def setup_class(cls):
import os
@@ -62,9 +12,6 @@
fname64 = os.path.join(os.path.dirname(__file__), 'complex64_testcases.txt')
cls.w_testcases128 = cls.space.wrap(fname128)
cls.w_testcases64 = cls.space.wrap(fname64)
- def cls_rAlmostEqual(self, *args, **kwargs):
- return rAlmostEqual(*args, **kwargs)
- cls.w_rAlmostEqual = cls.space.wrap(cls_rAlmostEqual)
cls.w_runAppDirect = cls.space.wrap(option.runappdirect)
cls.w_isWindows = cls.space.wrap(os.name == 'nt')
@@ -235,6 +182,8 @@
a[4 ], a[5 ], a[6 ], a[7 ],
a[8 ], a[9 ], a[10], a[11],
b[12], b[13]]
+ r2 = fmax(a,b)
+ r3 = (r2 == res)
assert (fmax(a, b) == res).all()
b = [inf]*a.size
res = [b[0 ], b[1 ], a[2 ], b[3 ],
@@ -388,20 +337,10 @@
-0j, 0j, cnan,
cnan, cnan, cnan]
for c, rel_err in ((complex64, 2e-7), (complex128, 2e-15), ):
- actual = reciprocal(array(orig, dtype=c))
+ actual = reciprocal(array([orig], dtype=c))
for b, a, e in zip(orig, actual, expected):
- error_message = (
- 'reciprocal(%r(%r, %r))\n'
- 'Expected: complex(%r, %r)\n'
- 'Received: complex(%r, %r)\n'
- ) % (c, b.real, b.imag,
- e.real, e.imag,
- a.real, a.imag)
-
- self.rAlmostEqual(e.real, a.real,
- rel_err=rel_err, msg=error_message)
- self.rAlmostEqual(e.imag, a.imag,
- rel_err=rel_err, msg=error_message)
+ assert (a[0].real - e.real) < rel_err
+ assert (a[0].imag - e.imag) < rel_err
def test_subtract(self):
from _numpypy import array, subtract
@@ -1089,6 +1028,58 @@
if self.isWindows:
skip('windows does not support c99 complex')
import _numpypy as np
+ from math import isnan, isinf, copysign
+ from sys import version_info
+
+ def rAlmostEqual(a, b, rel_err = 2e-15, abs_err = 5e-323, msg=''):
+ """Fail if the two floating-point numbers are not almost equal.
+
+ Determine whether floating-point values a and b are equal to within
+ a (small) rounding error. The default values for rel_err and
+ abs_err are chosen to be suitable for platforms where a float is
+ represented by an IEEE 754 double. They allow an error of between
+ 9 and 19 ulps.
+ """
+
+ # special values testing
+ if isnan(a):
+ if isnan(b):
+ return True,''
+ raise AssertionError(msg + '%r should be nan' % (b,))
+
+ if isinf(a):
+ if a == b:
+ return True,''
+ raise AssertionError(msg + 'finite result where infinity expected: '+ \
+ 'expected %r, got %r' % (a, b))
+
+ # if both a and b are zero, check whether they have the same sign
+ # (in theory there are examples where it would be legitimate for a
+ # and b to have opposite signs; in practice these hardly ever
+ # occur).
+ if not a and not b:
+ # only check it if we are running on top of CPython >= 2.6
+ if version_info >= (2, 6) and copysign(1., a) != copysign(1., b):
+ raise AssertionError( msg + \
+ 'zero has wrong sign: expected %r, got %r' % (a, b))
+
+ # if a-b overflows, or b is infinite, return False. Again, in
+ # theory there are examples where a is within a few ulps of the
+ # max representable float, and then b could legitimately be
+ # infinite. In practice these examples are rare.
+ try:
+ absolute_error = abs(b-a)
+ except OverflowError:
+ pass
+ else:
+ # test passes if either the absolute error or the relative
+ # error is sufficiently small. The defaults amount to an
+ # error of between 9 ulps and 19 ulps on an IEEE-754 compliant
+ # machine.
+ if absolute_error <= max(abs_err, rel_err * abs(a)):
+ return True,''
+ raise AssertionError(msg + '%r and %r are not sufficiently close' % (a, b))
+
def parse_testfile(fname):
"""Parse a file with test values
@@ -1153,7 +1144,7 @@
expected[0], expected[1],
actual[0], actual[1])
- self.rAlmostEqual(expected[0], actual[0],
+ rAlmostEqual(expected[0], actual[0],
abs_err=real_abs_err, msg=error_message)
- self.rAlmostEqual(expected[1], actual[1],
+ rAlmostEqual(expected[1], actual[1],
msg=error_message)
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -49,6 +49,19 @@
)
return dispatcher
+def complex_to_real_unary_op(func):
+ specialize.argtype(1)(func)
+ @functools.wraps(func)
+ def dispatcher(self, v):
+ return self.RealBoxType(
+ func(
+ self,
+ self.for_computation(self.unbox(v))
+ )
+ )
+ return dispatcher
+
+
def raw_unary_op(func):
specialize.argtype(1)(func)
@functools.wraps(func)
@@ -193,6 +206,14 @@
return v
@simple_unary_op
+ def real(self, v):
+ return v
+
+ @simple_unary_op
+ def imag(self, v):
+ return 0
+
+ @simple_unary_op
def abs(self, v):
return abs(v)
@@ -1017,8 +1038,6 @@
return rfloat.NAN, rfloat.NAN
return rfloat.INFINITY, rfloat.INFINITY
-
-
@complex_unary_op
def pos(self, v):
return v
@@ -1031,9 +1050,17 @@
def conj(self, v):
return v[0], -v[1]
- @raw_unary_op
+ @complex_to_real_unary_op
+ def real(self, v):
+ return self.RealBoxType(v.real)
+
+ @complex_to_real_unary_op
+ def imag(self, v):
+ return self.RealBoxType(v.imag)
+
+ @complex_to_real_unary_op
def abs(self, v):
- return rcomplex.c_abs(v[0], v[1])
+ return self.RealBoxType(rcomplex.c_abs(v[0], v[1]))
@raw_unary_op
def isnan(self, v):
@@ -1154,16 +1181,16 @@
return v1
elif self.isnan(v1):
return v2
- if v1 >= v2:
+ if self.ge(v1, v2):
return v1
return v2
def fmin(self, v1, v2):
- if math.isnan(v2):
+ if self.isnan(v2):
return v1
- elif math.isnan(v1):
+ elif self.isnan(v1):
return v2
- if v1 <= v2:
+ if self.le(v1, v2):
return v1
return v2
@@ -1334,7 +1361,7 @@
@raw_unary_op
def isnan(self, v):
- return rfloat.isnan(v)
+ return rfloat.isnan(v[0]) or rfloat.isnan(v[1])
@raw_unary_op
def isinf(self, v):
@@ -1415,6 +1442,7 @@
T = rffi.CHAR
_COMPONENTS_T = rffi.FLOAT
BoxType = interp_boxes.W_Complex64Box
+ RealBoxType = interp_boxes.W_Float32Box
@@ -1426,6 +1454,7 @@
T = rffi.CHAR
_COMPONENTS_T = rffi.DOUBLE
BoxType = interp_boxes.W_Complex128Box
+ RealBoxType = interp_boxes.W_Float64Box
NonNativeComplex128 = Complex128
More information about the pypy-commit
mailing list