[pypy-commit] pypy default: clean up ufuncs, fix some behaviors
bdkearns
noreply at buildbot.pypy.org
Thu Oct 17 09:13:57 CEST 2013
Author: Brian Kearns <bdkearns at 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))
More information about the pypy-commit
mailing list