Commits

Maciej Fijalkowski committed 32137bb Merge

(mattip) merge numpypy-real-as-view, which makes .real and .imag attributes
views instead of ufuncs, for compatibility

  • Participants
  • Parent commits cad5c05, 7f34d83

Comments (0)

Files changed (5)

File pypy/module/micronumpy/arrayimpl/concrete.py

 from pypy.rlib.debug import make_sure_not_resized
 
 class ConcreteArrayIterator(base.BaseArrayIterator):
+    _immutable_fields_ = ['dtype', 'skip', 'size']
     def __init__(self, array):
         self.array = array
         self.offset = 0
         self.size = array.size
 
     def setitem(self, elem):
-        self.array.setitem(self.offset, elem)
+        self.dtype.setitem(self.array, self.offset, elem)
 
     def getitem(self):
-        return self.array.getitem(self.offset)
+        return self.dtype.getitem(self.array, self.offset)
 
     def getitem_bool(self):
         return self.dtype.getitem_bool(self.array, self.offset)
         self.offset %= self.size
 
 class OneDimViewIterator(ConcreteArrayIterator):
-    def __init__(self, array):
+    ''' The view iterator dtype can be different from the
+    array.dtype, this is what makes it a View
+    '''
+    def __init__(self, array, dtype, start, strides, shape):
         self.array = array
-        self.offset = array.start
-        self.skip = array.get_strides()[0]
-        self.dtype = array.dtype
+        self.dtype = dtype
+        self.offset = start
+        self.skip = strides[0]
         self.index = 0
-        self.size = array.get_shape()[0]
+        self.size = shape[0]
 
     def next(self):
         self.offset += self.skip
         self.offset %= self.size
 
 class MultiDimViewIterator(ConcreteArrayIterator):
-    def __init__(self, array, start, strides, backstrides, shape):
+    ''' The view iterator dtype can be different from the
+    array.dtype, this is what makes it a View
+    '''
+    def __init__(self, array, dtype, start, strides, backstrides, shape):
         self.indexes = [0] * len(shape)
         self.array = array
+        self.dtype = dtype
         self.shape = shape
         self.offset = start
         self.shapelen = len(shape)
         self.offset = array.start
         self.dim = dim
         self.array = array
+        self.dtype = array.dtype
         
     def setitem(self, elem):
-        self.array.setitem(self.offset, elem)
+        self.dtype.setitem(self.array, self.offset, elem)
 
     def getitem(self):
-        return self.array.getitem(self.offset)
+        return self.dtype.getitem(self.array, self.offset)
 
     @jit.unroll_safe
     def next(self):
                               new_shape, self)
         else:
             return None
+    
+    def get_real(self):
+        strides = self.get_strides()
+        backstrides = self.get_backstrides()
+        if self.dtype.is_complex_type():
+            dtype =  self.dtype.float_type
+            return SliceArray(self.start, strides, backstrides,
+                          self.get_shape(), self, dtype=dtype)
+        return SliceArray(self.start, strides, backstrides, 
+                          self.get_shape(), self)
+
+    def get_imag(self):
+        strides = self.get_strides()
+        backstrides = self.get_backstrides()
+        if self.dtype.is_complex_type():
+            dtype =  self.dtype.float_type
+            return SliceArray(self.start + dtype.get_size(), strides, 
+                    backstrides, self.get_shape(), self, dtype=dtype)
+        if self.dtype.is_flexible_type():
+            # numpy returns self for self.imag
+            return SliceArray(self.start, strides, backstrides,
+                    self.get_shape(), self)
+        impl = NonWritableArray(self.get_shape(), self.dtype, self.order, strides,
+                             backstrides)
+        impl.fill(self.dtype.box(0))
+        return impl
 
     # -------------------- applevel get/setitem -----------------------
 
     def create_dot_iter(self, shape, skip):
         r = calculate_dot_strides(self.get_strides(), self.get_backstrides(),
                                   shape, skip)
-        return MultiDimViewIterator(self, self.start, r[0], r[1], shape)
+        return MultiDimViewIterator(self, self.dtype, self.start, r[0], r[1], shape)
 
     def swapaxes(self, axis1, axis2):
         shape = self.get_shape()[:]
         r = calculate_broadcast_strides(self.get_strides(),
                                         self.get_backstrides(),
                                         self.get_shape(), shape)
-        return MultiDimViewIterator(self, 0, r[0], r[1], shape)
+        return MultiDimViewIterator(self, self.dtype, 0, r[0], r[1], shape)
 
     def fill(self, box):
         self.dtype.fill(self.storage, box, 0, self.size)
                                                     self.order)
         return SliceArray(0, strides, backstrides, new_shape, self)
 
+class NonWritableArray(ConcreteArray):
+    def descr_setitem(self, space, w_index, w_value):
+        raise OperationError(space.w_RuntimeError, space.wrap(
+            "array is not writable"))
+        
+
 class SliceArray(BaseConcreteArray):
     def __init__(self, start, strides, backstrides, shape, parent, dtype=None):
         self.strides = strides
             r = calculate_broadcast_strides(self.get_strides(),
                                             self.get_backstrides(),
                                             self.get_shape(), shape)
-            return MultiDimViewIterator(self.parent,
+            return MultiDimViewIterator(self.parent, self.dtype,
                                         self.start, r[0], r[1], shape)
         if len(self.get_shape()) == 1:
-            return OneDimViewIterator(self)
-        return MultiDimViewIterator(self.parent, self.start,
+            return OneDimViewIterator(self.parent, self.dtype, self.start, 
+                    self.get_strides(), self.get_shape())
+        return MultiDimViewIterator(self.parent, self.dtype, self.start,
                                     self.get_strides(),
                                     self.get_backstrides(), self.get_shape())
 

File pypy/module/micronumpy/interp_dtype.py

         return self.kind == SIGNEDLTR
 
     def is_complex_type(self):
-        return (self.num == 14 or self.num == 15 or self.num == 16)
+        return False
 
     def is_bool_type(self):
         return self.kind == BOOLLTR
     def get_size(self):
         return self.itemtype.get_element_size()
 
+class W_ComplexDtype(W_Dtype):
+
+    def __init__(self, itemtype, num, kind, name, char, w_box_type,
+                 alternate_constructors=[], aliases=[],
+                 fields=None, fieldnames=None, native=True, float_type=None):
+        W_Dtype.__init__(self, itemtype, num, kind, name, char, w_box_type,
+                 alternate_constructors=alternate_constructors, aliases=aliases,
+                 fields=fields, fieldnames=fieldnames, native=native)
+        self.float_type = float_type
+
+    def is_complex_type(self):
+        return True
+
 def dtype_from_list(space, w_lst):
     lst_w = space.listview(w_lst)
     fields = {}
             alternate_constructors=[space.w_float],
             aliases=["float"],
         )
-        self.w_complex64dtype = W_Dtype(
+        self.w_complex64dtype = W_ComplexDtype(
             types.Complex64(),
             num=14,
             kind=COMPLEXLTR,
             name="complex64",
             char="F",
             w_box_type = space.gettypefor(interp_boxes.W_Complex64Box),
+            float_type = self.w_float32dtype,
         )
-        self.w_complex128dtype = W_Dtype(
+        self.w_complex128dtype = W_ComplexDtype(
             types.Complex128(),
             num=15,
             kind=COMPLEXLTR,
             w_box_type = space.gettypefor(interp_boxes.W_Complex128Box),
             alternate_constructors=[space.w_complex],
             aliases=["complex"],
+            float_type = self.w_float64dtype,
         )
         if interp_boxes.long_double_size == 12:
             self.w_float96dtype = W_Dtype(
             )
             self.w_longdouble = self.w_float96dtype
 
-            self.w_complex192dtype = W_Dtype(
+            self.w_complex192dtype = W_ComplexDtype(
                 types.Complex192(),
                 num=16,
                 kind=COMPLEXLTR,
                 w_box_type = space.gettypefor(interp_boxes.W_Complex192Box),
                 alternate_constructors=[space.w_complex],
                 aliases=["clongdouble", "clongfloat"],
+                float_type = self.w_float96dtype,
             )
             self.w_clongdouble = self.w_complex192dtype
 
             )
             self.w_longdouble = self.w_float128dtype
 
-            self.w_complex256dtype = W_Dtype(
+            self.w_complex256dtype = W_ComplexDtype(
                 types.Complex256(),
                 num=16,
                 kind=COMPLEXLTR,
                 w_box_type = space.gettypefor(interp_boxes.W_Complex256Box),
                 alternate_constructors=[space.w_complex],
                 aliases=["clongdouble", "clongfloat"],
+                float_type = self.w_float128dtype,
             )
             self.w_clongdouble = self.w_complex256dtype
         else:

File pypy/module/micronumpy/interp_numarray.py

     def descr_copy(self, space):
         return W_NDimArray(self.implementation.copy())
 
+    def descr_get_real(self, space):
+        return W_NDimArray(self.implementation.get_real())
+
+    def descr_get_imag(self, space):
+        ret = self.implementation.get_imag()
+        if ret:
+            return W_NDimArray(ret)
+        raise OperationError(space.w_NotImplementedError, 
+                    space.wrap('imag not implemented for this dtype'))
+
+    def descr_set_real(self, space, w_value):
+        # copy (broadcast) values into self
+        tmp = self.implementation.get_real()
+        tmp.setslice(space, convert_to_array(space, w_value))
+
+    def descr_set_imag(self, space, w_value):
+        # if possible, copy (broadcast) values into self
+        if not self.get_dtype().is_complex_type():
+            raise OperationError(space.w_TypeError, 
+                    space.wrap('array does not have imaginary part to set'))
+        tmp = self.implementation.get_imag()
+        tmp.setslice(space, convert_to_array(space, w_value))
+
     def descr_reshape(self, space, args_w):
         """reshape(...)
         a.reshape(shape)
     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:
     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),
-
+    real = GetSetProperty(W_NDimArray.descr_get_real, 
+                          W_NDimArray.descr_set_real),
+    imag = GetSetProperty(W_NDimArray.descr_get_imag,
+                          W_NDimArray.descr_set_imag),
     __array_interface__ = GetSetProperty(W_NDimArray.descr_array_iface),
 )
 

File pypy/module/micronumpy/test/test_iter.py

         strides = [5, 1]
         backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
         assert backstrides == [10, 4]
-        i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
+        i = MultiDimViewIterator(MockArray, None, start, strides, backstrides, shape)
         i.next()
         i.next()
         i.next()
         strides = [1, 3]
         backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
         assert backstrides == [2, 12]
-        i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
+        i = MultiDimViewIterator(MockArray, None, start, strides, backstrides, shape)
         i.next()
         i.next()
         i.next()
         strides = [5, 1]
         backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
         assert backstrides == [10, 4]
-        i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
+        i = MultiDimViewIterator(MockArray, None, start, strides, backstrides, shape)
         i.next_skip_x(2)
         i.next_skip_x(2)
         i.next_skip_x(2)
         strides = [1, 3]
         backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
         assert backstrides == [2, 12]
-        i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
+        i = MultiDimViewIterator(MockArray, None, start, strides, backstrides, shape)
         i.next_skip_x(2)
         i.next_skip_x(2)
         i.next_skip_x(2)

File pypy/module/micronumpy/test/test_numarray.py

         assert (d == [[1, 0, 0], [0, 1, 0], [0, 0, 1]]).all()
    
     def test_eye(self):
-        from _numpypy import eye, array
-        from _numpypy import int32, float64, dtype
+        from _numpypy import eye
+        from _numpypy import int32, dtype
         a = eye(0)
         assert len(a) == 0
         assert a.dtype == dtype('float64')
         assert b[0] == 3
         assert b[1] == 2
 
+    def test_realimag_views(self):
+        from _numpypy import arange, array
+        a = arange(15)
+        b = a.real
+        b[5]=50
+        assert a[5] == 50
+        b = a.imag
+        assert b[7] == 0
+        raises(RuntimeError, 'b[7] = -2')
+        raises(TypeError, 'a.imag = -2')
+        a = array(['abc','def'],dtype='S3')
+        b = a.real
+        assert a[0] == b[0]
+        assert a[1] == b[1]
+        b[1] = 'xyz'
+        assert a[1] == 'xyz'
+        assert a.imag[0] == 'abc'
+        raises(TypeError, 'a.imag = "qop"')
+        a=array([[1+1j, 2-3j, 4+5j],[-6+7j, 8-9j, -2-1j]]) 
+        assert a.real[0,1] == 2
+        a.real[0,1] = -20
+        assert a[0,1].real == -20
+        b = a.imag
+        assert b[1,2] == -1
+        b[1,2] = 30
+        assert a[1,2].imag == 30
+        a.real = 13
+        assert a[1,1].real == 13
+        a=array([1+1j, 2-3j, 4+5j, -6+7j, 8-9j, -2-1j]) 
+        a.real = 13
+        assert a[3].real == 13
+        a.imag = -5
+        a.imag[3] = -10
+        assert a[3].imag == -10
+        assert a[2].imag == -5
+
     def test_tolist_scalar(self):
         from _numpypy import int32, bool_
         x = int32(23)
         assert a[0]['x'] == 'a'
 
     def test_stringarray(self):
-        from _numpypy import array, flexible
+        from _numpypy import array
         a = array(['abc'],'S3')
         assert str(a.dtype) == '|S3'
         a = array(['abc'])
 
     def test_flexible_repr(self):
         # import overrides str(), repr() for array
-        from numpypy.core import arrayprint
         from _numpypy import array
         a = array(['abc'],'S3')
         s = repr(a)