Author: Brian Kearns <bdkea...@gmail.com> Branch: Changeset: r67454:022ea29b5d2e Date: 2013-10-17 03:10 -0400 http://bitbucket.org/pypy/pypy/changeset/022ea29b5d2e/
Log: clean up ufuncs, fix some behaviors diff --git a/lib_pypy/numpypy/lib/__init__.py b/lib_pypy/numpypy/lib/__init__.py --- a/lib_pypy/numpypy/lib/__init__.py +++ b/lib_pypy/numpypy/lib/__init__.py @@ -5,10 +5,12 @@ from .function_base import * from .shape_base import * from .twodim_base import * +from .ufunclike import * from .utils import * __all__ = ['math'] __all__ += function_base.__all__ __all__ += shape_base.__all__ __all__ += twodim_base.__all__ +__all__ += ufunclike.__all__ __all__ += utils.__all__ diff --git a/lib_pypy/numpypy/lib/ufunclike.py b/lib_pypy/numpypy/lib/ufunclike.py new file mode 100644 --- /dev/null +++ b/lib_pypy/numpypy/lib/ufunclike.py @@ -0,0 +1,177 @@ +""" +Module of functions that are like ufuncs in acting on arrays and optionally +storing results in an output array. + +""" +from __future__ import division, absolute_import, print_function + +__all__ = ['fix', 'isneginf', 'isposinf'] + +from ..core import numeric as nx + +def fix(x, y=None): + """ + Round to nearest integer towards zero. + + Round an array of floats element-wise to nearest integer towards zero. + The rounded values are returned as floats. + + Parameters + ---------- + x : array_like + An array of floats to be rounded + y : ndarray, optional + Output array + + Returns + ------- + out : ndarray of floats + The array of rounded numbers + + See Also + -------- + trunc, floor, ceil + around : Round to given number of decimals + + Examples + -------- + >>> np.fix(3.14) + 3.0 + >>> np.fix(3) + 3.0 + >>> np.fix([2.1, 2.9, -2.1, -2.9]) + array([ 2., 2., -2., -2.]) + + """ + x = nx.asanyarray(x) + y1 = nx.floor(x) + y2 = nx.ceil(x) + if y is None: + y = nx.asanyarray(y1) + y[...] = nx.where(x >= 0, y1, y2) + return y + +def isposinf(x, y=None): + """ + Test element-wise for positive infinity, return result as bool array. + + Parameters + ---------- + x : array_like + The input array. + y : array_like, optional + A boolean array with the same shape as `x` to store the result. + + Returns + ------- + y : ndarray + A boolean array with the same dimensions as the input. + If second argument is not supplied then a boolean array is returned + with values True where the corresponding element of the input is + positive infinity and values False where the element of the input is + not positive infinity. + + If a second argument is supplied the result is stored there. If the + type of that array is a numeric type the result is represented as zeros + and ones, if the type is boolean then as False and True. + The return value `y` is then a reference to that array. + + See Also + -------- + isinf, isneginf, isfinite, isnan + + Notes + ----- + Numpy uses the IEEE Standard for Binary Floating-Point for Arithmetic + (IEEE 754). + + Errors result if the second argument is also supplied when `x` is a + scalar input, or if first and second arguments have different shapes. + + Examples + -------- + >>> np.isposinf(np.PINF) + array(True, dtype=bool) + >>> np.isposinf(np.inf) + array(True, dtype=bool) + >>> np.isposinf(np.NINF) + array(False, dtype=bool) + >>> np.isposinf([-np.inf, 0., np.inf]) + array([False, False, True], dtype=bool) + + >>> x = np.array([-np.inf, 0., np.inf]) + >>> y = np.array([2, 2, 2]) + >>> np.isposinf(x, y) + array([0, 0, 1]) + >>> y + array([0, 0, 1]) + + """ + if y is None: + x = nx.asarray(x) + y = nx.empty(x.shape, dtype=nx.bool_) + nx.logical_and(nx.isinf(x), ~nx.signbit(x), y) + return y + +def isneginf(x, y=None): + """ + Test element-wise for negative infinity, return result as bool array. + + Parameters + ---------- + x : array_like + The input array. + y : array_like, optional + A boolean array with the same shape and type as `x` to store the + result. + + Returns + ------- + y : ndarray + A boolean array with the same dimensions as the input. + If second argument is not supplied then a numpy boolean array is + returned with values True where the corresponding element of the + input is negative infinity and values False where the element of + the input is not negative infinity. + + If a second argument is supplied the result is stored there. If the + type of that array is a numeric type the result is represented as + zeros and ones, if the type is boolean then as False and True. The + return value `y` is then a reference to that array. + + See Also + -------- + isinf, isposinf, isnan, isfinite + + Notes + ----- + Numpy uses the IEEE Standard for Binary Floating-Point for Arithmetic + (IEEE 754). + + Errors result if the second argument is also supplied when x is a scalar + input, or if first and second arguments have different shapes. + + Examples + -------- + >>> np.isneginf(np.NINF) + array(True, dtype=bool) + >>> np.isneginf(np.inf) + array(False, dtype=bool) + >>> np.isneginf(np.PINF) + array(False, dtype=bool) + >>> np.isneginf([-np.inf, 0., np.inf]) + array([ True, False, False], dtype=bool) + + >>> x = np.array([-np.inf, 0., np.inf]) + >>> y = np.array([2, 2, 2]) + >>> np.isneginf(x, y) + array([1, 0, 0]) + >>> y + array([1, 0, 0]) + + """ + if y is None: + x = nx.asarray(x) + y = nx.empty(x.shape, dtype=nx.bool_) + nx.logical_and(nx.isinf(x), nx.signbit(x), y) + return y diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py --- a/pypy/module/micronumpy/__init__.py +++ b/pypy/module/micronumpy/__init__.py @@ -63,6 +63,7 @@ ("less_equal", "less_equal"), ("maximum", "maximum"), ("minimum", "minimum"), + ("mod", "mod"), ("multiply", "multiply"), ("negative", "negative"), ("not_equal", "not_equal"), @@ -90,8 +91,6 @@ ('invert', 'invert'), ('isnan', 'isnan'), ('isinf', 'isinf'), - ('isneginf', 'isneginf'), - ('isposinf', 'isposinf'), ('isfinite', 'isfinite'), ('logical_and', 'logical_and'), ('logical_xor', 'logical_xor'), @@ -105,6 +104,7 @@ ('floor_divide', 'floor_divide'), ('logaddexp', 'logaddexp'), ('logaddexp2', 'logaddexp2'), + ('ldexp', 'ldexp'), ('real', 'real'), ('imag', 'imag'), ('ones_like', 'ones_like'), 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 @@ -16,23 +16,24 @@ def done_if_false(dtype, val): return not dtype.itemtype.bool(val) + class W_Ufunc(W_Root): _attrs_ = ["name", "promote_to_float", "promote_bools", "identity", - "allow_complex", "complex_to_float"] + "allow_bool", "allow_complex", "complex_to_float"] _immutable_fields_ = ["promote_to_float", "promote_bools", "name", - "allow_complex", "complex_to_float"] + "allow_bool", "allow_complex", "complex_to_float"] def __init__(self, name, promote_to_float, promote_bools, identity, - int_only, allow_complex, complex_to_float): + int_only, allow_bool, allow_complex, complex_to_float): self.name = name self.promote_to_float = promote_to_float self.promote_bools = promote_bools + self.identity = identity + self.int_only = int_only + self.allow_bool = allow_bool self.allow_complex = allow_complex self.complex_to_float = complex_to_float - self.identity = identity - self.int_only = int_only - def descr_repr(self, space): return space.wrap("<ufunc '%s'>" % self.name) @@ -259,10 +260,10 @@ def __init__(self, func, name, promote_to_float=False, promote_bools=False, identity=None, bool_result=False, int_only=False, - allow_complex=True, complex_to_float=False): + allow_bool=True, allow_complex=True, complex_to_float=False): W_Ufunc.__init__(self, name, promote_to_float, promote_bools, identity, - int_only, allow_complex, complex_to_float) + int_only, allow_bool, allow_complex, complex_to_float) self.func = func self.bool_result = bool_result @@ -274,17 +275,19 @@ if space.is_w(out, space.w_None): out = None w_obj = convert_to_array(space, w_obj) - if w_obj.get_dtype().is_flexible_type(): + dtype = w_obj.get_dtype() + if dtype.is_flexible_type(): raise OperationError(space.w_TypeError, space.wrap('Not implemented for this type')) - if self.int_only and not w_obj.get_dtype().is_int_type(): + if (self.int_only and not dtype.is_int_type() or + not self.allow_bool and dtype.is_bool_type() or + not self.allow_complex and dtype.is_complex_type()): raise OperationError(space.w_TypeError, space.wrap( "ufunc %s not supported for the input type" % self.name)) calc_dtype = find_unaryop_result_dtype(space, w_obj.get_dtype(), promote_to_float=self.promote_to_float, - promote_bools=self.promote_bools, - allow_complex=self.allow_complex) + promote_bools=self.promote_bools) if out is not None: if not isinstance(out, W_NDimArray): raise OperationError(space.w_TypeError, space.wrap( @@ -324,10 +327,10 @@ def __init__(self, func, name, promote_to_float=False, promote_bools=False, identity=None, comparison_func=False, int_only=False, - allow_complex=True, complex_to_float=False): + allow_bool=True, allow_complex=True, complex_to_float=False): W_Ufunc.__init__(self, name, promote_to_float, promote_bools, identity, - int_only, allow_complex, complex_to_float) + int_only, allow_bool, allow_complex, complex_to_float) self.func = func self.comparison_func = comparison_func if name == 'logical_and': @@ -375,16 +378,14 @@ w_rdtype = w_ldtype elif w_lhs.is_scalar() and not w_rhs.is_scalar(): w_ldtype = w_rdtype + if (self.int_only and (not w_ldtype.is_int_type() or not w_rdtype.is_int_type()) or + not self.allow_bool and (w_ldtype.is_bool_type() or w_rdtype.is_bool_type()) or + not self.allow_complex and (w_ldtype.is_complex_type() or w_rdtype.is_complex_type())): + raise OperationError(space.w_TypeError, space.wrap("Unsupported types")) calc_dtype = find_binop_result_dtype(space, w_ldtype, w_rdtype, - int_only=self.int_only, promote_to_float=self.promote_to_float, - promote_bools=self.promote_bools, - allow_complex=self.allow_complex, - ) - if self.int_only and not calc_dtype.is_int_type(): - raise OperationError(space.w_TypeError, space.wrap( - "ufunc '%s' not supported for the input types" % self.name)) + promote_bools=self.promote_bools) if space.is_none(w_out): out = None elif not isinstance(w_out, W_NDimArray): @@ -431,14 +432,10 @@ def find_binop_result_dtype(space, dt1, dt2, promote_to_float=False, - promote_bools=False, int_only=False, allow_complex=True): + promote_bools=False): # dt1.num should be <= dt2.num if dt1.num > dt2.num: dt1, dt2 = dt2, dt1 - if int_only and (not dt1.is_int_type() or not dt2.is_int_type()): - raise OperationError(space.w_TypeError, space.wrap("Unsupported types")) - if not allow_complex and (dt1.is_complex_type() or dt2.is_complex_type()): - raise OperationError(space.w_TypeError, space.wrap("Unsupported types")) # 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 @@ -507,14 +504,11 @@ dtypenum += 2 return interp_dtype.get_dtype_cache(space).dtypes_by_num[dtypenum] - @jit.unroll_safe def find_unaryop_result_dtype(space, dt, promote_to_float=False, - promote_bools=False, promote_to_largest=False, allow_complex=True): + promote_bools=False, promote_to_largest=False): if promote_bools and (dt.kind == interp_dtype.BOOLLTR): return interp_dtype.get_dtype_cache(space).w_int8dtype - if not allow_complex and (dt.is_complex_type()): - raise OperationError(space.w_TypeError, space.wrap("Unsupported types")) if promote_to_float: if dt.kind == interp_dtype.FLOATINGLTR or dt.kind==interp_dtype.COMPLEXLTR: return dt @@ -535,7 +529,6 @@ assert False return dt - def find_dtype_for_scalar(space, w_obj, current_guess=None): bool_dtype = interp_dtype.get_dtype_cache(space).w_booldtype long_dtype = interp_dtype.get_dtype_cache(space).w_longdtype @@ -588,7 +581,6 @@ 'unable to create dtype from objects, ' '"%T" instance not supported', w_obj) - def ufunc_dtype_caller(space, ufunc_name, op_name, argcount, comparison_func, bool_result): dtype_cache = interp_dtype.get_dtype_cache(space) @@ -606,6 +598,7 @@ return res return func_with_new_name(impl, ufunc_name) + class UfuncState(object): def __init__(self, space): "NOT_RPYTHON" @@ -635,10 +628,6 @@ ("greater_equal", "ge", 2, {"comparison_func": True}), ("isnan", "isnan", 1, {"bool_result": True}), ("isinf", "isinf", 1, {"bool_result": True}), - ("isneginf", "isneginf", 1, {"bool_result": True, - "allow_complex": False}), - ("isposinf", "isposinf", 1, {"bool_result": True, - "allow_complex": False}), ("isfinite", "isfinite", 1, {"bool_result": True}), ('logical_and', 'logical_and', 2, {'comparison_func': True, @@ -658,7 +647,7 @@ ("negative", "neg", 1), ("absolute", "abs", 1, {"complex_to_float": True}), ("rint", "rint", 1), - ("sign", "sign", 1, {"promote_bools": True}), + ("sign", "sign", 1, {"allow_bool": False}), ("signbit", "signbit", 1, {"bool_result": True, "allow_complex": False}), ("reciprocal", "reciprocal", 1), @@ -713,6 +702,8 @@ "allow_complex": False}), ("logaddexp2", "logaddexp2", 2, {"promote_to_float": True, "allow_complex": False}), + ("ldexp", "ldexp", 2, {"int_only": True}), + ("ones_like", "ones_like", 1), ("zeros_like", "zeros_like", 1), ]: 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 @@ -91,14 +91,14 @@ uncallable.add(s) return uncallable assert find_uncallable_ufuncs('int') == set() - assert find_uncallable_ufuncs('bool') == set() + assert find_uncallable_ufuncs('bool') == set(['sign']) assert find_uncallable_ufuncs('float') == set( ['bitwise_and', 'bitwise_not', 'bitwise_or', 'bitwise_xor', - 'left_shift', 'right_shift', 'invert']) + 'left_shift', 'right_shift', 'invert', 'ldexp']) assert find_uncallable_ufuncs('complex') == set( ['bitwise_and', 'bitwise_not', 'bitwise_or', 'bitwise_xor', 'arctan2', 'deg2rad', 'degrees', 'rad2deg', 'radians', - 'fabs', 'fmod', 'invert', 'isneginf', 'isposinf', + 'fabs', 'fmod', 'invert', 'ldexp', 'mod', 'logaddexp', 'logaddexp2', 'left_shift', 'right_shift', 'copysign', 'signbit', 'ceil', 'floor', 'trunc']) @@ -174,7 +174,6 @@ assert fabs(float('-inf')) == float('inf') assert isnan(fabs(float('nan'))) - def test_fmax(self): from numpypy import fmax, array import math @@ -194,7 +193,6 @@ # on Microsoft win32 assert math.copysign(1., fmax(nnan, nan)) == math.copysign(1., nnan) - def test_fmin(self): from numpypy import fmin, array import math @@ -213,7 +211,6 @@ # on Microsoft win32 assert math.copysign(1., fmin(nnan, nan)) == math.copysign(1., nnan) - def test_fmod(self): from numpypy import fmod import math @@ -368,7 +365,6 @@ c = array([10.5+11.5j, -15.2-100.3456j, 0.2343+11.123456j]) assert (c.round(0) == [10.+12.j, -15-100j, 0+11j]).all() - def test_copysign(self): from numpypy import array, copysign @@ -436,7 +432,6 @@ assert expm1(1e-50) == 1e-50 - def test_sin(self): import math from numpypy import array, sin @@ -704,6 +699,8 @@ assert (~a == [-2, -3, -4, -5]).all() assert (bitwise_not(a) == ~a).all() assert (invert(a) == ~a).all() + assert invert(True) == False + assert invert(False) == True def test_shift(self): from numpypy import left_shift, right_shift, bool @@ -964,6 +961,11 @@ assert logaddexp2(float('inf'), float('-inf')) == float('inf') assert logaddexp2(float('inf'), float('inf')) == float('inf') + def test_ldexp(self): + import numpypy as np + a = np.ldexp(2, 3) + assert type(a) is np.float64 and a == 16.0 + def test_ones_like(self): from numpypy import array, ones_like 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 @@ -248,14 +248,6 @@ def isinf(self, v): return False - @raw_unary_op - def isneginf(self, v): - return False - - @raw_unary_op - def isposinf(self, v): - return False - @raw_binary_op def eq(self, v1, v2): return v1 == v2 @@ -320,6 +312,10 @@ float64 = Float64() return float64.rint(float64.box(v)) + @raw_binary_op + def ldexp(self, v1, v2): + return Float64().box(v1 * 2**v2) + class NonNativePrimitive(Primitive): _mixin_ = True @@ -401,7 +397,7 @@ @simple_unary_op def invert(self, v): - return ~v + return not v @raw_unary_op def isfinite(self, v): @@ -497,14 +493,6 @@ def isinf(self, v): return False - @raw_unary_op - def isposinf(self, v): - return False - - @raw_unary_op - def isneginf(self, v): - return False - @simple_binary_op def bitwise_and(self, v1, v2): return v1 & v2 @@ -947,14 +935,6 @@ return rfloat.isinf(v) @raw_unary_op - def isneginf(self, v): - return rfloat.isinf(v) and v < 0 - - @raw_unary_op - def isposinf(self, v): - return rfloat.isinf(v) and v > 0 - - @raw_unary_op def isfinite(self, v): return not (rfloat.isinf(v) or rfloat.isnan(v)) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit