[pypy-commit] pypy matrixmath: Merge to avoid creating new head, not ready for review
mattip
noreply at buildbot.pypy.org
Fri Nov 25 08:35:11 CET 2011
Author: mattip
Branch: matrixmath
Changeset: r49781:5276f48f44f7
Date: 2011-11-25 09:33 +0200
http://bitbucket.org/pypy/pypy/changeset/5276f48f44f7/
Log: Merge to avoid creating new head, not ready for review
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
@@ -316,8 +316,7 @@
_attrs_ = ["invalidates", "signature", "shape", "strides", "backstrides",
"start", 'order']
- _immutable_fields_ = ['shape[*]', "strides[*]", "backstrides[*]", 'start',
- "order"]
+ _immutable_fields_ = ['start', "order"]
strides = None
start = 0
@@ -327,21 +326,24 @@
self.shape = shape
self.order = order
if self.strides is None:
- strides = []
- backstrides = []
- s = 1
- shape_rev = shape[:]
- if order == 'C':
- shape_rev.reverse()
- for sh in shape_rev:
- strides.append(s)
- backstrides.append(s * (sh - 1))
- s *= sh
- if order == 'C':
- strides.reverse()
- backstrides.reverse()
- self.strides = strides[:]
- self.backstrides = backstrides[:]
+ self.calc_strides(shape)
+
+ def calc_strides(self, shape):
+ strides = []
+ backstrides = []
+ s = 1
+ shape_rev = shape[:]
+ if self.order == 'C':
+ shape_rev.reverse()
+ for sh in shape_rev:
+ strides.append(s)
+ backstrides.append(s * (sh - 1))
+ s *= sh
+ if self.order == 'C':
+ strides.reverse()
+ backstrides.reverse()
+ self.strides = strides[:]
+ self.backstrides = backstrides[:]
def invalidated(self):
if self.invalidates:
@@ -494,7 +496,43 @@
def descr_get_shape(self, space):
return space.newtuple([space.wrap(i) for i in self.shape])
-
+
+ def descr_set_shape(self, space, w_iterable):
+ concrete = self.get_concrete()
+ new_size = 0
+ new_shape = []
+ if not space.issequence_w(w_iterable):
+ new_size = space.int_w(w_iterable)
+ if new_size < 0:
+ new_size = self.find_size()
+ new_shape = [new_size, ]
+ else:
+ neg_dim = -1
+ batch = space.listview(w_iterable)
+ new_size = 1
+ if len(batch) < 1:
+ new_size = 0
+ new_shape = []
+ i = 0
+ for elem in batch:
+ s = space.int_w(elem)
+ if s < 0:
+ if neg_dim >= 0:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "can only specify one unknown dimension"))
+ s = 1
+ neg_dim = i
+ new_size *= s
+ new_shape.append(s)
+ i += 1
+ if neg_dim >= 0:
+ new_shape[neg_dim] = self.find_size() / new_size
+ new_size *= new_shape[neg_dim]
+ if new_size != self.find_size():
+ raise OperationError(space.w_ValueError,
+ space.wrap("total size of new array must be unchanged"))
+ concrete.setshape(space, new_shape)
+
def descr_get_size(self, space):
return space.wrap(self.find_size())
@@ -744,6 +782,18 @@
return NDimSlice(self, new_sig, start, strides[:], backstrides[:],
shape[:])
+ def descr_reshape(self, space, w_iterable):
+ new_sig = signature.Signature.find_sig([
+ NDimSlice.signature, self.signature,
+ ])
+ #Does the [:] actually create a copy?
+ #I should do it explicitly
+ arr = NDimSlice(self, new_sig, self.start, self.strides[:],
+ self.backstrides[:], self.shape[:])
+
+ arr.descr_set_shape(space, w_iterable)
+ return arr
+
def descr_mean(self, space):
return space.wrap(space.float_w(self.descr_sum(space)) / self.find_size())
@@ -828,6 +878,9 @@
def to_str(self, space, comma, builder, indent=' ', use_ellipsis=False):
builder.append(self.dtype.str_format(self.value))
+ def setshape(self, space, new_shape):
+ pass
+
class VirtualArray(BaseArray):
"""
Class for representing virtual arrays, such as binary ops or ufuncs
@@ -997,6 +1050,82 @@
return space.wrap(self.shape[0])
return space.wrap(1)
+ def setshape(self, space, new_shape):
+ if len(self.shape) < 1:
+ return
+ elif len(self.shape) < 2:
+ #REVIEWER: this code could be refactored into calc_strides
+ #but then calc_strides would have to accept a factor of the
+ #current stride
+ strides = []
+ backstrides = []
+ self.shape = new_shape[:]
+ s = self.strides[0]
+ if self.order == 'C':
+ new_shape.reverse()
+ for sh in new_shape:
+ strides.append(s)
+ backstrides.append(s * (sh - 1))
+ s *= sh
+ if self.order == 'C':
+ strides.reverse()
+ backstrides.reverse()
+ self.strides = strides[:]
+ self.backstrides = backstrides[:]
+ return
+ #REVIEWER: wordy comment to explain what the intention was. Please
+ #edit or remove.
+ #We know that the product of new_shape is correct.
+ #Now we must check that the new shape does not create stepping conflicts
+ # for the strides It works like this:
+ # - Determine the right-to-lef tor left-to-right fastest iterating
+ # dimension. Note it is not enough just to check self.order, since a
+ # transpose reverses everything.
+ # - Start recalculating the strides, by each dimension. Keep a running
+ # cumprod of the old shape up to this dimension vs. the new shape up
+ # to this dimension. Every time the products match, update the stride
+ # currently in use.
+ # - The strides for each of the matching pieces must also match,
+ # - The stride will always be based on the old stride of the lowest
+ # dimension in the chunk, since
+ new_dims = range(len(new_shape))
+ old_dims = range(len(self.shape))
+ if self.strides[0]> self.strides[-1]:
+ #This is the normal thing to do
+ new_dims.reverse()
+ old_dims.reverse()
+ nd = 0
+ od = 0
+ prod_old = 1
+ prod_new = self.strides[old_dims[od]]
+ cur_old_stride = self.strides[old_dims[od]]
+ new_strides = [0]*len(new_shape)
+ while nd < len(new_dims):
+ new_strides[new_dims[nd]] = cur_old_stride
+ prod_new *= new_shape[nd]
+ while prod_new >= prod_old:
+ if prod_new == prod_old:
+ #Finished an old dim on a match. All is good
+ od += 1
+ prod_old *= self.shape[old_dims[od]]
+ cur_old_stride = self.strides[old_dims[od]]
+ elif prod_new > prod_old:
+ #Crossed over onto a different old_dim.
+ #Strides must be "equal" as per steps
+ od += 1
+ if self.strides[old_dims[od]] / self.shape[old_dims[od - 1]] \
+ <> self.strides[old_dims[od-1]]:
+ raise OperationError(space.w_AttributeError, space.wrap(
+ "incompatible shape for a non-contiguous array"))
+ prod_old *= self.shape[old_dims[od]]
+ nd += 1
+ new_backstrides = [0]*len(new_shape)
+ for nd in range(len(new_shape)):
+ new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
+ self.strides = new_strides
+ self.backstrides = new_backstrides
+ self.shape = new_shape
+
class VirtualView(VirtualArray):
pass
@@ -1094,6 +1223,10 @@
self.invalidated()
self.dtype.setitem(self.storage, item, value)
+ def setshape(self, space, new_shape):
+ self.shape = new_shape
+ self.calc_strides(new_shape)
+
def start_iter(self, res_shape=None):
if self.order == 'C':
if res_shape is not None and res_shape != self.shape:
@@ -1173,7 +1306,7 @@
__str__ = interp2app(BaseArray.descr_str),
dtype = GetSetProperty(BaseArray.descr_get_dtype),
- shape = GetSetProperty(BaseArray.descr_get_shape),
+ shape = GetSetProperty(BaseArray.descr_get_shape, BaseArray.descr_set_shape),
size = GetSetProperty(BaseArray.descr_get_size),
T = GetSetProperty(BaseArray.descr_get_transpose),
@@ -1190,4 +1323,5 @@
dot = interp2app(BaseArray.descr_dot),
copy = interp2app(BaseArray.descr_copy),
+ reshape = interp2app(BaseArray.descr_reshape),
)
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
@@ -321,6 +321,37 @@
c = a[:3]
assert c.shape == (3,)
+ def test_set_shape(self):
+ from numpypy import array, zeros
+ a = array([])
+ a.shape = []
+ a = array(range(12))
+ a.shape = (3, 4)
+ assert (a == [range(4), range(4, 8), range(8, 12)]).all()
+ a.shape = (3, 2, 2)
+ assert a[1, 1, 1] == 7
+ a.shape = (3, -1, 2)
+ assert a.shape == (3, 2, 2)
+ a.shape = 12
+ assert a.shape == (12, )
+ exc = raises(ValueError, "b = a.reshape((3, 10))")
+ assert str(exc.value) == "total size of new array must be unchanged"
+ exc = raises(ValueError, "a.shape = 10")
+ assert str(exc.value) == "total size of new array must be unchanged"
+ a = zeros((4, 2, 3))
+ b = a[::2, :, :]
+ b.shape = (2,6)
+ exc = raises(AttributeError, "b.shape = 12")
+ assert str(exc.value) == \
+ "incompatible shape for a non-contiguous array"
+ b.shape = (2, 6)
+ a.shape = (12, 2)
+ a = array(range(12))
+ b = a.reshape((3, 4))
+ assert (b == [range(4), range(4, 8), range(8, 12)]).all()
+ b[:, 0] = 1000
+ assert (a == [1000, 1, 2, 3, 1000, 5, 6, 7, 1000, 9, 10, 11]).all()
+
def test_add(self):
from numpypy import array
a = array(range(5))
More information about the pypy-commit
mailing list