[pypy-commit] pypy numpy-dtype-alt: Fix for various arithmatic operations on bool arrays, including their promotion to int8s in some circumstances. Also fixed ll2ctypes turning lltype.Bool into a c_long, rather than a c_bool.

alex_gaynor noreply at buildbot.pypy.org
Sun Aug 28 20:42:01 CEST 2011


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: numpy-dtype-alt
Changeset: r46866:c322561494f1
Date: 2011-08-28 14:41 -0400
http://bitbucket.org/pypy/pypy/changeset/c322561494f1/

Log:	Fix for various arithmatic operations on bool arrays, including
	their promotion to int8s in some circumstances. Also fixed
	ll2ctypes turning lltype.Bool into a c_long, rather than a c_bool.

diff --git a/pypy/module/micronumpy/interp_dtype.py b/pypy/module/micronumpy/interp_dtype.py
--- a/pypy/module/micronumpy/interp_dtype.py
+++ b/pypy/module/micronumpy/interp_dtype.py
@@ -235,6 +235,9 @@
 class IntegerArithmeticDtype(ArithmaticTypeMixin):
     _mixin_ = True
 
+    def unwrap(self, space, w_item):
+        return self.adapt_val(space.int_w(space.int(w_item)))
+
     def for_computation(self, v):
         return widen(v)
 
@@ -262,7 +265,7 @@
     T = lltype.Bool,
     valtype = bool,
 )
-class W_BoolDtype(W_BoolDtype):
+class W_BoolDtype(IntegerArithmeticDtype, W_BoolDtype):
     def unwrap(self, space, w_item):
         return self.adapt_val(space.is_true(w_item))
 
@@ -273,10 +276,6 @@
     def for_computation(self, v):
         return int(v)
 
-    @binop
-    def add(self, v1, v2):
-        return bool(v1 + v2)
-
 W_Int8Dtype = create_low_level_dtype(
     num = 1, kind = SIGNEDLTR, name = "int8",
     aliases = ["int8"],
@@ -296,8 +295,7 @@
     valtype = rffi.INT._type,
 )
 class W_Int32Dtype(IntegerArithmeticDtype, W_Int32Dtype):
-    def unwrap(self, space, w_item):
-        return self.adapt_val(space.int_w(space.int(w_item)))
+    pass
 
 W_Int64Dtype = create_low_level_dtype(
     num = 9, kind = SIGNEDLTR, name = "int64",
@@ -307,8 +305,7 @@
     valtype = rffi.LONGLONG._type,
 )
 class W_Int64Dtype(IntegerArithmeticDtype, W_Int64Dtype):
-    def unwrap(self, space, w_item):
-        return self.adapt_val(space.int_w(space.int(w_item)))
+    pass
 
 W_Float64Dtype = create_low_level_dtype(
     num = 12, kind = FLOATINGLTR, name = "float64",
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
@@ -2,9 +2,9 @@
 from pypy.tool.sourcetools import func_with_new_name
 
 
-def ufunc(func=None, promote_to_float=False):
+def ufunc(func=None, promote_to_float=False, promote_bools=False):
     if func is None:
-        return lambda func: ufunc(func, promote_to_float)
+        return lambda func: ufunc(func, promote_to_float, promote_bools)
     call_sig = signature.Call1(func)
     def impl(space, w_obj):
         from pypy.module.micronumpy.interp_numarray import (Call1,
@@ -14,6 +14,7 @@
         res_dtype = find_unaryop_result_dtype(space,
             w_obj.find_dtype(),
             promote_to_float=promote_to_float,
+            promote_bools=promote_bools,
         )
         if isinstance(w_obj, Scalar):
             return func(res_dtype, w_obj.value.convert_to(res_dtype)).wrap(space)
@@ -24,9 +25,9 @@
         return w_res
     return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
 
-def ufunc2(func=None, promote_to_float=False):
+def ufunc2(func=None, promote_to_float=False, promote_bools=False):
     if func is None:
-        return lambda func: ufunc2(func, promote_to_float)
+        return lambda func: ufunc2(func, promote_to_float, promote_bools)
 
     call_sig = signature.Call2(func)
     def impl(space, w_lhs, w_rhs):
@@ -38,6 +39,7 @@
         res_dtype = find_binop_result_dtype(space,
             w_lhs.find_dtype(), w_rhs.find_dtype(),
             promote_to_float=promote_to_float,
+            promote_bools=promote_bools,
         )
         if isinstance(w_lhs, Scalar) and isinstance(w_rhs, Scalar):
             return func(res_dtype, w_lhs.value, w_rhs.value).wrap(space)
@@ -51,7 +53,8 @@
         return w_res
     return func_with_new_name(impl, "%s_dispatcher" % func.__name__)
 
-def find_binop_result_dtype(space, dt1, dt2, promote_bools=False, promote_to_float=False):
+def find_binop_result_dtype(space, dt1, dt2, promote_to_float=False,
+    promote_bools=False):
     # dt1.num should be <= dt2.num
     if dt1.num > dt2.num:
         dt1, dt2 = dt2, dt1
@@ -71,7 +74,9 @@
     assert False
 
 def find_unaryop_result_dtype(space, dt, promote_to_float=False,
-    promote_to_largest=False):
+    promote_to_largest=False, promote_bools=False):
+    if promote_bools and (dt.kind == interp_dtype.BOOLLTR):
+        return space.fromcache(interp_dtype.W_Int8Dtype)
     if promote_to_float:
         for bytes, dtype in interp_dtype.dtypes_by_num_bytes:
             if dtype.kind == interp_dtype.FLOATINGLTR and dtype.num_bytes >= dt.num_bytes:
@@ -116,9 +121,9 @@
     ("add", "add", 2),
     ("subtract", "sub", 2),
     ("multiply", "mul", 2),
-    ("divide", "div", 2),
-    ("mod", "mod", 2),
-    ("power", "pow", 2),
+    ("divide", "div", 2, {"promote_bools": True}),
+    ("mod", "mod", 2, {"promote_bools": True}),
+    ("power", "pow", 2, {"promote_bools": True}),
 
     ("maximum", "max", 2),
     ("minimum", "min", 2),
@@ -128,7 +133,7 @@
     ("positive", "pos", 1),
     ("negative", "neg", 1),
     ("absolute", "abs", 1),
-    ("sign", "sign", 1),
+    ("sign", "sign", 1, {"promote_bools": True}),
     ("reciprocal", "reciprocal", 1),
 
     ("fabs", "fabs", 1, {"promote_to_float": True}),
diff --git a/pypy/module/micronumpy/test/test_numarray.py b/pypy/module/micronumpy/test/test_numarray.py
--- a/pypy/module/micronumpy/test/test_numarray.py
+++ b/pypy/module/micronumpy/test/test_numarray.py
@@ -236,12 +236,19 @@
             assert b[i] == i - 5
 
     def test_mul(self):
-        from numpy import array
+        from numpy import array, dtype
         a = array(range(5))
         b = a * a
         for i in range(5):
             assert b[i] == i * i
 
+        a = array(range(5), dtype=bool)
+        b = a * a
+        assert b.dtype is dtype(bool)
+        assert b[0] is False
+        for i in range(1, 5):
+            assert b[i] is True
+
     def test_mul_constant(self):
         from numpy import array
         a = array(range(5))
@@ -250,12 +257,18 @@
             assert b[i] == i * 5
 
     def test_div(self):
-        from numpy import array
+        from numpy import array, dtype
         a = array(range(1, 6))
         b = a / a
         for i in range(5):
             assert b[i] == 1
 
+        a = array(range(1, 6), dtype=bool)
+        b = a / a
+        assert b.dtype is dtype("int8")
+        for i in range(5):
+            assert b[i] == 1
+
     def test_div_other(self):
         from numpy import array
         a = array(range(5))
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
@@ -124,7 +124,7 @@
             assert c[i] == a[i] * b[i]
 
     def test_sign(self):
-        from numpy import array, sign
+        from numpy import array, sign, dtype
 
         reference = [-1.0, 0.0, 0.0, 1.0]
         a = array([-5.0, -0.0, 0.0, 6.0])
@@ -137,6 +137,11 @@
         for i in range(10):
             assert a[i] == ref[i]
 
+        a = sign(array([True, False], dtype=bool))
+        assert a.dtype == dtype("int8")
+        assert a[0] == 1
+        assert a[1] == 0
+
     def test_reciporocal(self):
         from numpy import array, reciprocal
 
diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -113,7 +113,7 @@
         rffi.LONGLONG:   ctypes.c_longlong,
         rffi.ULONGLONG:  ctypes.c_ulonglong,
         rffi.SIZE_T:     ctypes.c_size_t,
-        lltype.Bool:     ctypes.c_long, # XXX
+        lltype.Bool:     ctypes.c_bool,
         llmemory.Address:  ctypes.c_void_p,
         llmemory.GCREF:    ctypes.c_void_p,
         llmemory.WeakRef:  ctypes.c_void_p, # XXX


More information about the pypy-commit mailing list