[pypy-commit] pypy default: merge numpy-refactor branch. This branch changes more or less everything
fijal
noreply at buildbot.pypy.org
Tue Sep 11 16:04:49 CEST 2012
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch:
Changeset: r57288:67d9a48f4362
Date: 2012-09-11 16:03 +0200
http://bitbucket.org/pypy/pypy/changeset/67d9a48f4362/
Log: merge numpy-refactor branch. This branch changes more or less
everything related to arrays in micronumpy. This means killing lazy
evaluation, but a lot of complexity as well. Right now the numpy is
just a thin wrapper around the underlaying implementation. For now
it's just scalar, concrete array or a view, but this can add virtual
arrays easily in the future.
diff --git a/lib_pypy/numpypy/core/_methods.py b/lib_pypy/numpypy/core/_methods.py
--- a/lib_pypy/numpypy/core/_methods.py
+++ b/lib_pypy/numpypy/core/_methods.py
@@ -1,62 +1,77 @@
# Array methods which are called by the both the C-code for the method
# and the Python code for the NumPy-namespace function
+#from numpy.core import multiarray as mu
+#from numpy.core import umath as um
import _numpypy as mu
um = mu
-#from numpypy.core import umath as um
-from numpypy.core.numeric import asanyarray
+from numpy.core.numeric import asanyarray
-def _amax(a, axis=None, out=None, skipna=False, keepdims=False):
+def _amax(a, axis=None, out=None, keepdims=False):
return um.maximum.reduce(a, axis=axis,
- out=out, skipna=skipna, keepdims=keepdims)
+ out=out, keepdims=keepdims)
-def _amin(a, axis=None, out=None, skipna=False, keepdims=False):
+def _amin(a, axis=None, out=None, keepdims=False):
return um.minimum.reduce(a, axis=axis,
- out=out, skipna=skipna, keepdims=keepdims)
+ out=out, keepdims=keepdims)
-def _sum(a, axis=None, dtype=None, out=None, skipna=False, keepdims=False):
+def _sum(a, axis=None, dtype=None, out=None, keepdims=False):
return um.add.reduce(a, axis=axis, dtype=dtype,
- out=out, skipna=skipna, keepdims=keepdims)
+ out=out, keepdims=keepdims)
-def _prod(a, axis=None, dtype=None, out=None, skipna=False, keepdims=False):
+def _prod(a, axis=None, dtype=None, out=None, keepdims=False):
return um.multiply.reduce(a, axis=axis, dtype=dtype,
- out=out, skipna=skipna, keepdims=keepdims)
+ out=out, keepdims=keepdims)
-def _mean(a, axis=None, dtype=None, out=None, skipna=False, keepdims=False):
+def _any(a, axis=None, dtype=None, out=None, keepdims=False):
+ return um.logical_or.reduce(a, axis=axis, dtype=dtype, out=out,
+ keepdims=keepdims)
+
+def _all(a, axis=None, dtype=None, out=None, keepdims=False):
+ return um.logical_and.reduce(a, axis=axis, dtype=dtype, out=out,
+ keepdims=keepdims)
+
+def _count_reduce_items(arr, axis):
+ if axis is None:
+ axis = tuple(xrange(arr.ndim))
+ if not isinstance(axis, tuple):
+ axis = (axis,)
+ items = 1
+ for ax in axis:
+ items *= arr.shape[ax]
+ return items
+
+def _mean(a, axis=None, dtype=None, out=None, keepdims=False):
arr = asanyarray(a)
# Upgrade bool, unsigned int, and int to float64
if dtype is None and arr.dtype.kind in ['b','u','i']:
ret = um.add.reduce(arr, axis=axis, dtype='f8',
- out=out, skipna=skipna, keepdims=keepdims)
+ out=out, keepdims=keepdims)
else:
ret = um.add.reduce(arr, axis=axis, dtype=dtype,
- out=out, skipna=skipna, keepdims=keepdims)
- rcount = mu.count_reduce_items(arr, axis=axis,
- skipna=skipna, keepdims=keepdims)
+ out=out, keepdims=keepdims)
+ rcount = _count_reduce_items(arr, axis)
if isinstance(ret, mu.ndarray):
ret = um.true_divide(ret, rcount,
- casting='unsafe', subok=False)
+ out=ret, casting='unsafe', subok=False)
else:
ret = ret / float(rcount)
return ret
def _var(a, axis=None, dtype=None, out=None, ddof=0,
- skipna=False, keepdims=False):
+ keepdims=False):
arr = asanyarray(a)
# First compute the mean, saving 'rcount' for reuse later
if dtype is None and arr.dtype.kind in ['b','u','i']:
- arrmean = um.add.reduce(arr, axis=axis, dtype='f8',
- skipna=skipna, keepdims=True)
+ arrmean = um.add.reduce(arr, axis=axis, dtype='f8', keepdims=True)
else:
- arrmean = um.add.reduce(arr, axis=axis, dtype=dtype,
- skipna=skipna, keepdims=True)
- rcount = mu.count_reduce_items(arr, axis=axis,
- skipna=skipna, keepdims=True)
+ arrmean = um.add.reduce(arr, axis=axis, dtype=dtype, keepdims=True)
+ rcount = _count_reduce_items(arr, axis)
if isinstance(arrmean, mu.ndarray):
arrmean = um.true_divide(arrmean, rcount,
- casting='unsafe', subok=False)
+ out=arrmean, casting='unsafe', subok=False)
else:
arrmean = arrmean / float(rcount)
@@ -65,13 +80,12 @@
# (arr - arrmean) ** 2
if arr.dtype.kind == 'c':
- x = um.multiply(x, um.conjugate(x)).real
+ x = um.multiply(x, um.conjugate(x), out=x).real
else:
- x = um.multiply(x, x)
+ x = um.multiply(x, x, out=x)
# add.reduce((arr - arrmean) ** 2, axis)
- ret = um.add.reduce(x, axis=axis, dtype=dtype, out=out,
- skipna=skipna, keepdims=keepdims)
+ ret = um.add.reduce(x, axis=axis, dtype=dtype, out=out, keepdims=keepdims)
# add.reduce((arr - arrmean) ** 2, axis) / (n - ddof)
if not keepdims and isinstance(rcount, mu.ndarray):
@@ -79,19 +93,18 @@
rcount -= ddof
if isinstance(ret, mu.ndarray):
ret = um.true_divide(ret, rcount,
- casting='unsafe', subok=False)
+ out=ret, casting='unsafe', subok=False)
else:
ret = ret / float(rcount)
return ret
-def _std(a, axis=None, dtype=None, out=None, ddof=0,
- skipna=False, keepdims=False):
+def _std(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False):
ret = _var(a, axis=axis, dtype=dtype, out=out, ddof=ddof,
- skipna=skipna, keepdims=keepdims)
+ keepdims=keepdims)
if isinstance(ret, mu.ndarray):
- ret = um.sqrt(ret)
+ ret = um.sqrt(ret, out=ret)
else:
ret = um.sqrt(ret)
diff --git a/lib_pypy/numpypy/core/arrayprint.py b/lib_pypy/numpypy/core/arrayprint.py
--- a/lib_pypy/numpypy/core/arrayprint.py
+++ b/lib_pypy/numpypy/core/arrayprint.py
@@ -14,9 +14,9 @@
import sys
import _numpypy as _nt
-from _numpypy import maximum, minimum, absolute, not_equal, isinf, isnan, isna
+from _numpypy import maximum, minimum, absolute, not_equal, isnan, isinf
#from _numpypy import format_longfloat, datetime_as_string, datetime_data
-from .fromnumeric import ravel
+from fromnumeric import ravel
def product(x, y): return x*y
@@ -29,7 +29,6 @@
_line_width = 75
_nan_str = 'nan'
_inf_str = 'inf'
-_na_str = 'NA'
_formatter = None # formatting function for array elements
if sys.version_info[0] >= 3:
@@ -37,7 +36,7 @@
def set_printoptions(precision=None, threshold=None, edgeitems=None,
linewidth=None, suppress=None,
- nanstr=None, infstr=None, nastr=None,
+ nanstr=None, infstr=None,
formatter=None):
"""
Set printing options.
@@ -65,8 +64,6 @@
String representation of floating point not-a-number (default nan).
infstr : str, optional
String representation of floating point infinity (default inf).
- nastr : str, optional
- String representation of NA missing value (default NA).
formatter : dict of callables, optional
If not None, the keys should indicate the type(s) that the respective
formatting function applies to. Callables should return a string.
@@ -144,7 +141,7 @@
global _summaryThreshold, _summaryEdgeItems, _float_output_precision, \
_line_width, _float_output_suppress_small, _nan_str, _inf_str, \
- _na_str, _formatter
+ _formatter
if linewidth is not None:
_line_width = linewidth
if threshold is not None:
@@ -159,8 +156,6 @@
_nan_str = nanstr
if infstr is not None:
_inf_str = infstr
- if nastr is not None:
- _na_str = nastr
_formatter = formatter
def get_printoptions():
@@ -195,7 +190,6 @@
suppress=_float_output_suppress_small,
nanstr=_nan_str,
infstr=_inf_str,
- nastr=_na_str,
formatter=_formatter)
return d
@@ -219,19 +213,14 @@
return b
def _boolFormatter(x):
- if isna(x):
- return str(x).replace('NA', _na_str, 1)
- elif x:
+ if x:
return ' True'
else:
return 'False'
def repr_format(x):
- if isna(x):
- return str(x).replace('NA', _na_str, 1)
- else:
- return repr(x)
+ return repr(x)
def _array2string(a, max_line_width, precision, suppress_small, separator=' ',
prefix="", formatter=None):
@@ -262,8 +251,8 @@
#'complexfloat' : ComplexFormat(data, precision,
# suppress_small),
#'longcomplexfloat' : LongComplexFormat(precision),
- #'datetime' : DatetimeFormat(data),
- #'timedelta' : TimedeltaFormat(data),
+ 'datetime' : DatetimeFormat(data),
+ 'timedelta' : TimedeltaFormat(data),
'numpystr' : repr_format,
'str' : str}
@@ -309,11 +298,11 @@
# format_function = formatdict['longfloat']
#else:
format_function = formatdict['float']
- elif issubclass(dtypeobj, _nt.complexfloating):
- if issubclass(dtypeobj, _nt.clongfloat):
- format_function = formatdict['longcomplexfloat']
- else:
- format_function = formatdict['complexfloat']
+ #elif issubclass(dtypeobj, _nt.complexfloating):
+ # if issubclass(dtypeobj, _nt.clongfloat):
+ # format_function = formatdict['longcomplexfloat']
+ # else:
+ # format_function = formatdict['complexfloat']
elif issubclass(dtypeobj, (_nt.unicode_, _nt.string_)):
format_function = formatdict['numpystr']
elif issubclass(dtypeobj, _nt.datetime64):
@@ -437,20 +426,17 @@
if a.shape == ():
x = a.item()
- if isna(x):
- lst = str(x).replace('NA', _na_str, 1)
- else:
- try:
- lst = a._format(x)
- msg = "The `_format` attribute is deprecated in Numpy " \
- "2.0 and will be removed in 2.1. Use the " \
- "`formatter` kw instead."
- import warnings
- warnings.warn(msg, DeprecationWarning)
- except AttributeError:
- if isinstance(x, tuple):
- x = _convert_arrays(x)
- lst = style(x)
+ try:
+ lst = a._format(x)
+ msg = "The `_format` attribute is deprecated in Numpy " \
+ "2.0 and will be removed in 2.1. Use the " \
+ "`formatter` kw instead."
+ import warnings
+ warnings.warn(msg, DeprecationWarning)
+ except AttributeError:
+ if isinstance(x, tuple):
+ x = _convert_arrays(x)
+ lst = style(x)
elif reduce(product, a.shape) == 0:
# treat as a null array if any of shape elements == 0
lst = "[]"
@@ -542,38 +528,33 @@
self.exp_format = False
self.large_exponent = False
self.max_str_len = 0
- #try:
- self.fillFormat(data)
- #except (TypeError, NotImplementedError):
+ try:
+ self.fillFormat(data)
+ except (TypeError, NotImplementedError):
# if reduce(data) fails, this instance will not be called, just
# instantiated in formatdict.
- #pass
+ pass
def fillFormat(self, data):
import numeric as _nc
- # XXX pypy unimplemented
- #errstate = _nc.seterr(all='ignore')
+ errstate = _nc.seterr(all='ignore')
try:
- special = isnan(data) | isinf(data) | isna(data)
- special[isna(data)] = False
+ special = isnan(data) | isinf(data)
valid = not_equal(data, 0) & ~special
- valid[isna(data)] = False
non_zero = absolute(data.compress(valid))
if len(non_zero) == 0:
max_val = 0.
min_val = 0.
else:
- max_val = maximum.reduce(non_zero, skipna=True)
- min_val = minimum.reduce(non_zero, skipna=True)
+ max_val = maximum.reduce(non_zero)
+ min_val = minimum.reduce(non_zero)
if max_val >= 1.e8:
self.exp_format = True
if not self.suppress_small and (min_val < 0.0001
or max_val/min_val > 1000.):
self.exp_format = True
finally:
- pass
- # XXX pypy unimplemented
- #_nc.seterr(**errstate)
+ _nc.seterr(**errstate)
if self.exp_format:
self.large_exponent = 0 < min_val < 1e-99 or max_val >= 1e100
@@ -594,11 +575,10 @@
precision = 0
precision = min(self.precision, precision)
self.max_str_len = len(str(int(max_val))) + precision + 2
- if special.any():
+ if _nc.any(special):
self.max_str_len = max(self.max_str_len,
len(_nan_str),
- len(_inf_str)+1,
- len(_na_str))
+ len(_inf_str)+1)
if self.sign:
format = '%#+'
else:
@@ -610,11 +590,9 @@
def __call__(self, x, strip_zeros=True):
import numeric as _nc
- #err = _nc.seterr(invalid='ignore')
+ err = _nc.seterr(invalid='ignore')
try:
- if isna(x):
- return self.special_fmt % (str(x).replace('NA', _na_str, 1),)
- elif isnan(x):
+ if isnan(x):
if self.sign:
return self.special_fmt % ('+' + _nan_str,)
else:
@@ -628,8 +606,7 @@
else:
return self.special_fmt % ('-' + _inf_str,)
finally:
- pass
- #_nc.seterr(**err)
+ _nc.seterr(**err)
s = self.format % x
if self.large_exponent:
@@ -658,10 +635,10 @@
class IntegerFormat(object):
def __init__(self, data):
try:
- max_str_len = max(len(str(maximum.reduce(data, skipna=True))),
- len(str(minimum.reduce(data, skipna=True))))
+ max_str_len = max(len(str(maximum.reduce(data))),
+ len(str(minimum.reduce(data))))
self.format = '%' + str(max_str_len) + 'd'
- except TypeError, NotImplementedError:
+ except (TypeError, NotImplementedError):
# if reduce(data) fails, this instance will not be called, just
# instantiated in formatdict.
pass
@@ -670,9 +647,7 @@
pass
def __call__(self, x):
- if isna(x):
- return str(x).replace('NA', _na_str, 1)
- elif _MININT < x < _MAXINT:
+ if _MININT < x < _MAXINT:
return self.format % x
else:
return "%s" % x
@@ -685,9 +660,7 @@
self.sign = sign
def __call__(self, x):
- if isna(x):
- return str(x).replace('NA', _na_str, 1)
- elif isnan(x):
+ if isnan(x):
if self.sign:
return '+' + _nan_str
else:
@@ -715,12 +688,9 @@
self.imag_format = LongFloatFormat(precision, sign=True)
def __call__(self, x):
- if isna(x):
- return str(x).replace('NA', _na_str, 1)
- else:
- r = self.real_format(x.real)
- i = self.imag_format(x.imag)
- return r + i + 'j'
+ r = self.real_format(x.real)
+ i = self.imag_format(x.imag)
+ return r + i + 'j'
class ComplexFormat(object):
@@ -730,17 +700,14 @@
sign=True)
def __call__(self, x):
- if isna(x):
- return str(x).replace('NA', _na_str, 1)
+ r = self.real_format(x.real, strip_zeros=False)
+ i = self.imag_format(x.imag, strip_zeros=False)
+ if not self.imag_format.exp_format:
+ z = i.rstrip('0')
+ i = z + 'j' + ' '*(len(i)-len(z))
else:
- r = self.real_format(x.real, strip_zeros=False)
- i = self.imag_format(x.imag, strip_zeros=False)
- if not self.imag_format.exp_format:
- z = i.rstrip('0')
- i = z + 'j' + ' '*(len(i)-len(z))
- else:
- i = i + 'j'
- return r + i
+ i = i + 'j'
+ return r + i
class DatetimeFormat(object):
def __init__(self, x, unit=None,
@@ -765,13 +732,10 @@
self.casting = casting
def __call__(self, x):
- if isna(x):
- return str(x).replace('NA', _na_str, 1)
- else:
- return "'%s'" % datetime_as_string(x,
- unit=self.unit,
- timezone=self.timezone,
- casting=self.casting)
+ return "'%s'" % datetime_as_string(x,
+ unit=self.unit,
+ timezone=self.timezone,
+ casting=self.casting)
class TimedeltaFormat(object):
def __init__(self, data):
@@ -782,8 +746,5 @@
self.format = '%' + str(max_str_len) + 'd'
def __call__(self, x):
- if isna(x):
- return str(x).replace('NA', _na_str, 1)
- else:
- return self.format % x.astype('i8')
+ return self.format % x.astype('i8')
diff --git a/lib_pypy/numpypy/core/numeric.py b/lib_pypy/numpypy/core/numeric.py
--- a/lib_pypy/numpypy/core/numeric.py
+++ b/lib_pypy/numpypy/core/numeric.py
@@ -1,6 +1,7 @@
from _numpypy import array, ndarray, int_, float_, bool_ #, complex_# , longlong
from _numpypy import concatenate
+from .fromnumeric import any
import math
import sys
import _numpypy as multiarray # ARGH
@@ -8,7 +9,11 @@
newaxis = None
-def asanyarray(a, dtype=None, order=None, maskna=None, ownmaskna=False):
+# XXX this file to be reviewed
+def seterr(**args):
+ return args
+
+def asanyarray(a, dtype=None, order=None):
"""
Convert the input to an ndarray, but pass ndarray subclasses through.
@@ -23,13 +28,6 @@
order : {'C', 'F'}, optional
Whether to use row-major ('C') or column-major ('F') memory
representation. Defaults to 'C'.
- maskna : bool or None, optional
- If this is set to True, it forces the array to have an NA mask.
- If this is set to False, it forces the array to not have an NA
- mask.
- ownmaskna : bool, optional
- If this is set to True, forces the array to have a mask which
- it owns.
Returns
-------
@@ -65,8 +63,7 @@
True
"""
- return array(a, dtype, copy=False, order=order, subok=True,
- maskna=maskna, ownmaskna=ownmaskna)
+ return array(a, dtype, copy=False, order=order, subok=True)
def base_repr(number, base=2, padding=0):
"""
@@ -347,7 +344,7 @@
return False
return bool((a1 == a2).all())
-def asarray(a, dtype=None, order=None, maskna=None, ownmaskna=False):
+def asarray(a, dtype=None, order=None):
"""
Convert the input to an array.
@@ -362,13 +359,6 @@
order : {'C', 'F'}, optional
Whether to use row-major ('C') or column-major ('F' for FORTRAN)
memory representation. Defaults to 'C'.
- maskna : bool or None, optional
- If this is set to True, it forces the array to have an NA mask.
- If this is set to False, it forces the array to not have an NA
- mask.
- ownmaskna : bool, optional
- If this is set to True, forces the array to have a mask which
- it owns.
Returns
-------
@@ -422,8 +412,7 @@
True
"""
- return array(a, dtype, copy=False, order=order,
- maskna=maskna, ownmaskna=ownmaskna)
+ return array(a, dtype, copy=False, order=order)
set_string_function(array_str, 0)
set_string_function(array_repr, 1)
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
@@ -25,18 +25,16 @@
'zeros': 'interp_numarray.zeros',
'empty': 'interp_numarray.zeros',
'ones': 'interp_numarray.ones',
- 'dot': 'interp_numarray.dot',
+ 'dot': 'interp_arrayops.dot',
'fromstring': 'interp_support.fromstring',
- 'flatiter': 'interp_numarray.W_FlatIterator',
- 'isna': 'interp_numarray.isna',
- 'concatenate': 'interp_numarray.concatenate',
- 'repeat': 'interp_numarray.repeat',
+ 'flatiter': 'interp_flatiter.W_FlatIterator',
+ 'concatenate': 'interp_arrayops.concatenate',
+ 'repeat': 'interp_arrayops.repeat',
'where': 'interp_arrayops.where',
+ 'count_nonzero': 'interp_arrayops.count_nonzero',
'set_string_function': 'appbridge.set_string_function',
- 'count_reduce_items': 'interp_numarray.count_reduce_items',
-
'True_': 'types.Bool.True',
'False_': 'types.Bool.False',
@@ -166,5 +164,4 @@
'eye': 'app_numpy.eye',
'max': 'app_numpy.max',
'arange': 'app_numpy.arange',
- 'count_nonzero': 'app_numpy.count_nonzero',
}
diff --git a/pypy/module/micronumpy/app_numpy.py b/pypy/module/micronumpy/app_numpy.py
--- a/pypy/module/micronumpy/app_numpy.py
+++ b/pypy/module/micronumpy/app_numpy.py
@@ -2,11 +2,6 @@
import _numpypy
-def count_nonzero(a):
- if not hasattr(a, 'count_nonzero'):
- a = _numpypy.array(a)
- return a.count_nonzero()
-
def average(a):
# This implements a weighted average, for now we don't implement the
# weighting, just the average part!
diff --git a/pypy/module/micronumpy/arrayimpl/__init__.py b/pypy/module/micronumpy/arrayimpl/__init__.py
new file mode 100644
diff --git a/pypy/module/micronumpy/arrayimpl/base.py b/pypy/module/micronumpy/arrayimpl/base.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/arrayimpl/base.py
@@ -0,0 +1,14 @@
+
+class BaseArrayImplementation(object):
+ def is_scalar(self):
+ return False
+
+class BaseArrayIterator(object):
+ def next(self):
+ raise NotImplementedError # purely abstract base class
+
+ def setitem(self, elem):
+ raise NotImplementedError
+
+ def set_scalar_object(self, value):
+ raise NotImplementedError # works only on scalars
diff --git a/pypy/module/micronumpy/arrayimpl/concrete.py b/pypy/module/micronumpy/arrayimpl/concrete.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/arrayimpl/concrete.py
@@ -0,0 +1,430 @@
+
+from pypy.module.micronumpy.arrayimpl import base
+from pypy.module.micronumpy import support, loop
+from pypy.module.micronumpy.base import convert_to_array, W_NDimArray
+from pypy.module.micronumpy.strides import calc_new_strides, shape_agreement,\
+ calculate_broadcast_strides, calculate_dot_strides
+from pypy.module.micronumpy.iter import Chunk, Chunks, NewAxisChunk, RecordChunk
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.rlib import jit
+from pypy.rlib.rawstorage import free_raw_storage
+
+class ConcreteArrayIterator(base.BaseArrayIterator):
+ def __init__(self, array):
+ self.array = array
+ self.offset = 0
+ self.dtype = array.dtype
+ self.skip = self.dtype.itemtype.get_element_size()
+ self.size = array.size
+
+ def setitem(self, elem):
+ self.array.setitem(self.offset, elem)
+
+ def getitem(self):
+ return self.array.getitem(self.offset)
+
+ def getitem_bool(self):
+ return self.dtype.getitem_bool(self.array, self.offset)
+
+ def next(self):
+ self.offset += self.skip
+
+ def next_skip_x(self, x):
+ self.offset += self.skip * x
+
+ def done(self):
+ return self.offset >= self.size
+
+ def reset(self):
+ self.offset %= self.size
+
+class OneDimViewIterator(ConcreteArrayIterator):
+ def __init__(self, array):
+ self.array = array
+ self.offset = array.start
+ self.skip = array.strides[0]
+ self.dtype = array.dtype
+ self.index = 0
+ self.size = array.shape[0]
+
+ def next(self):
+ self.offset += self.skip
+ self.index += 1
+
+ def next_skip_x(self, x):
+ self.offset += self.skip * x
+ self.index += x
+
+ def done(self):
+ return self.index >= self.size
+
+ def reset(self):
+ self.offset %= self.size
+
+class MultiDimViewIterator(ConcreteArrayIterator):
+ def __init__(self, array, start, strides, backstrides, shape):
+ self.indexes = [0] * len(shape)
+ self.array = array
+ self.shape = shape
+ self.offset = start
+ self.shapelen = len(shape)
+ self._done = False
+ self.strides = strides
+ self.backstrides = backstrides
+ self.size = array.size
+
+ @jit.unroll_safe
+ def next(self):
+ offset = self.offset
+ for i in range(self.shapelen - 1, -1, -1):
+ if self.indexes[i] < self.shape[i] - 1:
+ self.indexes[i] += 1
+ offset += self.strides[i]
+ break
+ else:
+ self.indexes[i] = 0
+ offset -= self.backstrides[i]
+ else:
+ self._done = True
+ self.offset = offset
+
+ @jit.unroll_safe
+ def next_skip_x(self, step):
+ for i in range(len(self.shape) - 1, -1, -1):
+ if self.indexes[i] < self.shape[i] - step:
+ self.indexes[i] += step
+ self.offset += self.strides[i] * step
+ break
+ else:
+ remaining_step = (self.indexes[i] + step) // self.shape[i]
+ this_i_step = step - remaining_step * self.shape[i]
+ self.offset += self.strides[i] * this_i_step
+ self.indexes[i] = self.indexes[i] + this_i_step
+ step = remaining_step
+ else:
+ self._done = True
+
+ def done(self):
+ return self._done
+
+ def reset(self):
+ self.offset %= self.size
+
+class AxisIterator(base.BaseArrayIterator):
+ def __init__(self, array, shape, dim):
+ self.shape = shape
+ strides = array.strides
+ backstrides = array.backstrides
+ if len(shape) == len(strides):
+ # keepdims = True
+ self.strides = strides[:dim] + [0] + strides[dim + 1:]
+ self.backstrides = backstrides[:dim] + [0] + backstrides[dim + 1:]
+ else:
+ self.strides = strides[:dim] + [0] + strides[dim:]
+ self.backstrides = backstrides[:dim] + [0] + backstrides[dim:]
+ self.first_line = True
+ self.indices = [0] * len(shape)
+ self._done = False
+ self.offset = array.start
+ self.dim = dim
+ self.array = array
+
+ def setitem(self, elem):
+ self.array.setitem(self.offset, elem)
+
+ def getitem(self):
+ return self.array.getitem(self.offset)
+
+ @jit.unroll_safe
+ def next(self):
+ for i in range(len(self.shape) - 1, -1, -1):
+ if self.indices[i] < self.shape[i] - 1:
+ if i == self.dim:
+ self.first_line = False
+ self.indices[i] += 1
+ self.offset += self.strides[i]
+ break
+ else:
+ if i == self.dim:
+ self.first_line = True
+ self.indices[i] = 0
+ self.offset -= self.backstrides[i]
+ else:
+ self._done = True
+
+ def done(self):
+ return self._done
+
+def int_w(space, w_obj):
+ try:
+ return space.int_w(space.index(w_obj))
+ except OperationError:
+ return space.int_w(space.int(w_obj))
+
+class BaseConcreteArray(base.BaseArrayImplementation):
+ start = 0
+ parent = None
+
+ def get_shape(self):
+ return self.shape
+
+ def getitem(self, index):
+ return self.dtype.getitem(self, index)
+
+ def setitem(self, index, value):
+ self.dtype.setitem(self, index, value)
+
+ def setslice(self, space, arr):
+ impl = arr.implementation
+ if impl.is_scalar():
+ self.fill(impl.get_scalar_value())
+ return
+ shape = shape_agreement(space, self.shape, arr)
+ if impl.storage == self.storage:
+ impl = impl.copy()
+ loop.setslice(shape, self, impl)
+
+ def get_size(self):
+ return self.size // self.dtype.itemtype.get_element_size()
+
+ def reshape(self, space, new_shape):
+ # Since we got to here, prod(new_shape) == self.size
+ new_strides = None
+ if self.size > 0:
+ new_strides = calc_new_strides(new_shape, self.shape,
+ self.strides, self.order)
+ if new_strides:
+ # We can create a view, strides somehow match up.
+ ndims = len(new_shape)
+ new_backstrides = [0] * ndims
+ for nd in range(ndims):
+ new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
+ return SliceArray(self.start, new_strides, new_backstrides,
+ new_shape, self)
+ else:
+ return None
+
+ # -------------------- applevel get/setitem -----------------------
+
+ @jit.unroll_safe
+ def _lookup_by_index(self, space, view_w):
+ item = self.start
+ for i, w_index in enumerate(view_w):
+ if space.isinstance_w(w_index, space.w_slice):
+ raise IndexError
+ idx = int_w(space, w_index)
+ if idx < 0:
+ idx = self.shape[i] + idx
+ if idx < 0 or idx >= self.shape[i]:
+ raise operationerrfmt(space.w_IndexError,
+ "index (%d) out of range (0<=index<%d", i, self.shape[i],
+ )
+ item += idx * self.strides[i]
+ return item
+
+ def _single_item_index(self, space, w_idx):
+ """ Return an index of single item if possible, otherwise raises
+ IndexError
+ """
+ if (space.isinstance_w(w_idx, space.w_str) or
+ space.isinstance_w(w_idx, space.w_slice) or
+ space.is_w(w_idx, space.w_None)):
+ raise IndexError
+ shape_len = len(self.shape)
+ if shape_len == 0:
+ raise OperationError(space.w_IndexError, space.wrap(
+ "0-d arrays can't be indexed"))
+ if space.isinstance_w(w_idx, space.w_tuple):
+ view_w = space.fixedview(w_idx)
+ if len(view_w) < shape_len:
+ raise IndexError
+ if len(view_w) > shape_len:
+ # we can allow for one extra None
+ count = len(view_w)
+ for w_item in view_w:
+ if space.is_w(w_item, space.w_None):
+ count -= 1
+ if count == shape_len:
+ raise IndexError # but it's still not a single item
+ raise OperationError(space.w_IndexError,
+ space.wrap("invalid index"))
+ return self._lookup_by_index(space, view_w)
+ if shape_len > 1:
+ raise IndexError
+ idx = int_w(space, w_idx)
+ return self._lookup_by_index(space, [space.wrap(idx)])
+
+ @jit.unroll_safe
+ def _prepare_slice_args(self, space, w_idx):
+ if space.isinstance_w(w_idx, space.w_str):
+ idx = space.str_w(w_idx)
+ dtype = self.dtype
+ if not dtype.is_record_type() or idx not in dtype.fields:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "field named %s not defined" % idx))
+ return RecordChunk(idx)
+ if (space.isinstance_w(w_idx, space.w_int) or
+ space.isinstance_w(w_idx, space.w_slice)):
+ return Chunks([Chunk(*space.decode_index4(w_idx, self.shape[0]))])
+ elif space.is_w(w_idx, space.w_None):
+ return Chunks([NewAxisChunk()])
+ result = []
+ i = 0
+ for w_item in space.fixedview(w_idx):
+ if space.is_w(w_item, space.w_None):
+ result.append(NewAxisChunk())
+ else:
+ result.append(Chunk(*space.decode_index4(w_item,
+ self.shape[i])))
+ i += 1
+ return Chunks(result)
+
+ def descr_getitem(self, space, w_index):
+ try:
+ item = self._single_item_index(space, w_index)
+ return self.getitem(item)
+ except IndexError:
+ # not a single result
+ chunks = self._prepare_slice_args(space, w_index)
+ return chunks.apply(self)
+
+ def descr_setitem(self, space, w_index, w_value):
+ try:
+ item = self._single_item_index(space, w_index)
+ self.setitem(item, self.dtype.coerce(space, w_value))
+ except IndexError:
+ w_value = convert_to_array(space, w_value)
+ chunks = self._prepare_slice_args(space, w_index)
+ view = chunks.apply(self)
+ view.implementation.setslice(space, w_value)
+
+ def transpose(self):
+ if len(self.shape) < 2:
+ return self
+ strides = []
+ backstrides = []
+ shape = []
+ for i in range(len(self.shape) - 1, -1, -1):
+ strides.append(self.strides[i])
+ backstrides.append(self.backstrides[i])
+ shape.append(self.shape[i])
+ return SliceArray(self.start, strides,
+ backstrides, shape, self)
+
+ def copy(self):
+ strides, backstrides = support.calc_strides(self.shape, self.dtype,
+ self.order)
+ impl = ConcreteArray(self.shape, self.dtype, self.order, strides,
+ backstrides)
+ return loop.setslice(self.shape, impl, self)
+
+ def create_axis_iter(self, shape, dim):
+ return AxisIterator(self, shape, dim)
+
+ def create_dot_iter(self, shape, skip):
+ r = calculate_dot_strides(self.strides, self.backstrides,
+ shape, skip)
+ return MultiDimViewIterator(self, self.start, r[0], r[1], shape)
+
+ def swapaxes(self, axis1, axis2):
+ shape = self.shape[:]
+ strides = self.strides[:]
+ backstrides = self.backstrides[:]
+ shape[axis1], shape[axis2] = shape[axis2], shape[axis1]
+ strides[axis1], strides[axis2] = strides[axis2], strides[axis1]
+ backstrides[axis1], backstrides[axis2] = backstrides[axis2], backstrides[axis1]
+ return W_NDimArray.new_slice(self.start, strides,
+ backstrides, shape, self)
+
+ def get_storage_as_int(self, space):
+ return rffi.cast(lltype.Signed, self.storage)
+
+class ConcreteArray(BaseConcreteArray):
+ def __init__(self, shape, dtype, order, strides, backstrides):
+ self.shape = shape
+ self.size = support.product(shape) * dtype.get_size()
+ self.storage = dtype.itemtype.malloc(self.size)
+ self.order = order
+ self.dtype = dtype
+ self.strides = strides
+ self.backstrides = backstrides
+
+ def create_iter(self, shape):
+ if shape == self.shape:
+ return ConcreteArrayIterator(self)
+ r = calculate_broadcast_strides(self.strides, self.backstrides,
+ self.shape, shape)
+ return MultiDimViewIterator(self, 0, r[0], r[1], shape)
+
+ def fill(self, box):
+ self.dtype.fill(self.storage, box, 0, self.size)
+
+ def __del__(self):
+ free_raw_storage(self.storage, track_allocation=False)
+
+ def set_shape(self, space, new_shape):
+ strides, backstrides = support.calc_strides(new_shape, self.dtype,
+ self.order)
+ return SliceArray(0, strides, backstrides, new_shape, self)
+
+class SliceArray(BaseConcreteArray):
+ def __init__(self, start, strides, backstrides, shape, parent, dtype=None):
+ self.strides = strides
+ self.backstrides = backstrides
+ self.shape = shape
+ if isinstance(parent, SliceArray):
+ parent = parent.parent # one level only
+ self.parent = parent
+ self.storage = parent.storage
+ self.order = parent.order
+ if dtype is None:
+ dtype = parent.dtype
+ self.dtype = dtype
+ self.size = support.product(shape) * self.dtype.itemtype.get_element_size()
+ self.start = start
+
+ def fill(self, box):
+ loop.fill(self, box.convert_to(self.dtype))
+
+ def create_iter(self, shape):
+ if shape != self.shape:
+ r = calculate_broadcast_strides(self.strides, self.backstrides,
+ self.shape, shape)
+ return MultiDimViewIterator(self.parent,
+ self.start, r[0], r[1], shape)
+ if len(self.shape) == 1:
+ return OneDimViewIterator(self)
+ return MultiDimViewIterator(self.parent, self.start, self.strides,
+ self.backstrides, self.shape)
+
+ def set_shape(self, space, new_shape):
+ if len(self.shape) < 2 or self.size == 0:
+ # TODO: this code could be refactored into calc_strides
+ # but then calc_strides would have to accept a stepping factor
+ strides = []
+ backstrides = []
+ dtype = self.dtype
+ s = self.strides[0] // dtype.get_size()
+ if self.order == 'C':
+ new_shape.reverse()
+ for sh in new_shape:
+ strides.append(s * dtype.get_size())
+ backstrides.append(s * (sh - 1) * dtype.get_size())
+ s *= max(1, sh)
+ if self.order == 'C':
+ strides.reverse()
+ backstrides.reverse()
+ new_shape.reverse()
+ return SliceArray(self.start, strides, backstrides, new_shape,
+ self)
+ new_strides = calc_new_strides(new_shape, self.shape, self.strides,
+ self.order)
+ if new_strides is None:
+ raise OperationError(space.w_AttributeError, space.wrap(
+ "incompatible shape for a non-contiguous array"))
+ new_backstrides = [0] * len(new_shape)
+ for nd in range(len(new_shape)):
+ new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
+ return SliceArray(self.start, new_strides, new_backstrides, new_shape,
+ self)
diff --git a/pypy/module/micronumpy/arrayimpl/scalar.py b/pypy/module/micronumpy/arrayimpl/scalar.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/arrayimpl/scalar.py
@@ -0,0 +1,90 @@
+
+from pypy.module.micronumpy.arrayimpl import base
+from pypy.module.micronumpy.base import W_NDimArray
+from pypy.module.micronumpy import support
+from pypy.interpreter.error import OperationError
+
+class ScalarIterator(base.BaseArrayIterator):
+ def __init__(self, v):
+ self.v = v
+
+ def next(self):
+ pass
+
+ def getitem(self):
+ return self.v
+
+ def setitem(self, v):
+ raise Exception("Don't call setitem on scalar iterators")
+
+ def done(self):
+ raise Exception("should not call done on scalar")
+
+ def reset(self):
+ pass
+
+class Scalar(base.BaseArrayImplementation):
+ def __init__(self, dtype, value=None):
+ self.dtype = dtype
+ self.value = value
+
+ def is_scalar(self):
+ return True
+
+ def get_shape(self):
+ return []
+
+ def create_iter(self, shape):
+ return ScalarIterator(self.value)
+
+ def get_scalar_value(self):
+ return self.value
+
+ def set_scalar_value(self, w_val):
+ self.value = w_val.convert_to(self.dtype)
+
+ def copy(self):
+ scalar = Scalar(self.dtype)
+ scalar.value = self.value
+ return scalar
+
+ def get_size(self):
+ return 1
+
+ def transpose(self):
+ return self
+
+ def descr_getitem(self, space, w_idx):
+ raise OperationError(space.w_IndexError,
+ space.wrap("scalars cannot be indexed"))
+
+ def descr_setitem(self, space, w_idx, w_val):
+ raise OperationError(space.w_IndexError,
+ space.wrap("scalars cannot be indexed"))
+
+ def set_shape(self, space, new_shape):
+ if not new_shape:
+ return self
+ if support.product(new_shape) == 1:
+ arr = W_NDimArray.from_shape(new_shape, self.dtype)
+ arr_iter = arr.create_iter(new_shape)
+ arr_iter.setitem(self.value)
+ return arr.implementation
+ raise OperationError(space.w_ValueError, space.wrap(
+ "total size of the array must be unchanged"))
+
+ def reshape(self, space, new_shape):
+ return self.set_shape(space, new_shape)
+
+ def create_axis_iter(self, shape, dim):
+ raise Exception("axis iter should not happen on scalar")
+
+ def swapaxes(self, axis1, axis2):
+ raise Exception("should not be called")
+
+ def fill(self, w_value):
+ self.value = w_value
+
+ def get_storage_as_int(self, space):
+ raise OperationError(space.w_ValueError,
+ space.wrap("scalars have no address"))
diff --git a/pypy/module/micronumpy/arrayimpl/voidbox.py b/pypy/module/micronumpy/arrayimpl/voidbox.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/arrayimpl/voidbox.py
@@ -0,0 +1,11 @@
+
+from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation
+from pypy.rlib.rawstorage import free_raw_storage, alloc_raw_storage
+
+class VoidBoxStorage(BaseArrayImplementation):
+ def __init__(self, size, dtype):
+ self.storage = alloc_raw_storage(size)
+ self.dtype = dtype
+
+ def __del__(self):
+ free_raw_storage(self.storage)
diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/base.py
@@ -0,0 +1,50 @@
+
+from pypy.interpreter.baseobjspace import Wrappable
+from pypy.tool.pairtype import extendabletype
+from pypy.module.micronumpy.support import calc_strides
+
+class W_NDimArray(Wrappable):
+ __metaclass__ = extendabletype
+
+ def __init__(self, implementation):
+ self.implementation = implementation
+
+ @staticmethod
+ def from_shape(shape, dtype, order='C'):
+ from pypy.module.micronumpy.arrayimpl import concrete
+
+ assert shape
+ strides, backstrides = calc_strides(shape, dtype, order)
+ impl = concrete.ConcreteArray(shape, dtype, order, strides,
+ backstrides)
+ return W_NDimArray(impl)
+
+ @staticmethod
+ def new_slice(offset, strides, backstrides, shape, parent, dtype=None):
+ from pypy.module.micronumpy.arrayimpl import concrete
+
+ impl = concrete.SliceArray(offset, strides, backstrides, shape, parent,
+ dtype)
+ return W_NDimArray(impl)
+
+ @staticmethod
+ def new_scalar(space, dtype, w_val=None):
+ from pypy.module.micronumpy.arrayimpl import scalar
+
+ if w_val is not None:
+ w_val = dtype.coerce(space, w_val)
+ return W_NDimArray(scalar.Scalar(dtype, w_val))
+
+def convert_to_array(space, w_obj):
+ from pypy.module.micronumpy.interp_numarray import array
+ from pypy.module.micronumpy import interp_ufuncs
+
+ if isinstance(w_obj, W_NDimArray):
+ return w_obj
+ elif space.issequence_w(w_obj):
+ # Convert to array.
+ return array(space, w_obj, w_order=None)
+ else:
+ # If it's a scalar
+ dtype = interp_ufuncs.find_dtype_for_scalar(space, w_obj)
+ return W_NDimArray.new_scalar(space, dtype, w_obj)
diff --git a/pypy/module/micronumpy/dot.py b/pypy/module/micronumpy/dot.py
--- a/pypy/module/micronumpy/dot.py
+++ b/pypy/module/micronumpy/dot.py
@@ -1,85 +1,23 @@
-from pypy.module.micronumpy.strides import calculate_dot_strides
from pypy.interpreter.error import OperationError
-from pypy.module.micronumpy.interp_iter import ViewIterator
-from pypy.rlib import jit
-
-def dot_printable_location(shapelen):
- return 'numpy dot [%d]' % shapelen
-
-dot_driver = jit.JitDriver(
- greens=['shapelen'],
- reds=['lefti', 'righti', 'outi', 'result', 'right', 'dtype',
- 'left'],
- get_printable_location=dot_printable_location,
- name='dot',
-)
def match_dot_shapes(space, left, right):
- my_critical_dim_size = left.shape[-1]
- right_critical_dim_size = right.shape[0]
+ left_shape = left.get_shape()
+ right_shape = right.get_shape()
+ my_critical_dim_size = left_shape[-1]
+ right_critical_dim_size = right_shape[0]
right_critical_dim = 0
out_shape = []
- if len(right.shape) > 1:
- right_critical_dim = len(right.shape) - 2
- right_critical_dim_size = right.shape[right_critical_dim]
+ if len(right_shape) > 1:
+ right_critical_dim = len(right_shape) - 2
+ right_critical_dim_size = right_shape[right_critical_dim]
assert right_critical_dim >= 0
- out_shape += left.shape[:-1] + \
- right.shape[0:right_critical_dim] + \
- right.shape[right_critical_dim + 1:]
- elif len(right.shape) > 0:
+ out_shape += left_shape[:-1] + \
+ right_shape[0:right_critical_dim] + \
+ right_shape[right_critical_dim + 1:]
+ elif len(right_shape) > 0:
#dot does not reduce for scalars
- out_shape += left.shape[:-1]
+ out_shape += left_shape[:-1]
if my_critical_dim_size != right_critical_dim_size:
raise OperationError(space.w_ValueError, space.wrap(
"objects are not aligned"))
return out_shape, right_critical_dim
-
-def multidim_dot(space, left, right, result, dtype, right_critical_dim):
- ''' assumes left, right are concrete arrays
- given left.shape == [3, 5, 7],
- right.shape == [2, 7, 4]
- then
- result.shape == [3, 5, 2, 4]
- broadcast shape should be [3, 5, 2, 7, 4]
- result should skip dims 3 which is len(result_shape) - 1
- (note that if right is 1d, result should
- skip len(result_shape))
- left should skip 2, 4 which is a.ndims-1 + range(right.ndims)
- except where it==(right.ndims-2)
- right should skip 0, 1
- '''
- broadcast_shape = left.shape[:-1] + right.shape
- shapelen = len(broadcast_shape)
- left_skip = [len(left.shape) - 1 + i for i in range(len(right.shape))
- if i != right_critical_dim]
- right_skip = range(len(left.shape) - 1)
- result_skip = [len(result.shape) - (len(right.shape) > 1)]
- _r = calculate_dot_strides(result.strides, result.backstrides,
- broadcast_shape, result_skip)
- outi = ViewIterator(result.start, _r[0], _r[1], broadcast_shape)
- _r = calculate_dot_strides(left.strides, left.backstrides,
- broadcast_shape, left_skip)
- lefti = ViewIterator(left.start, _r[0], _r[1], broadcast_shape)
- _r = calculate_dot_strides(right.strides, right.backstrides,
- broadcast_shape, right_skip)
- righti = ViewIterator(right.start, _r[0], _r[1], broadcast_shape)
- while not outi.done():
- dot_driver.jit_merge_point(left=left,
- right=right,
- shapelen=shapelen,
- lefti=lefti,
- righti=righti,
- outi=outi,
- result=result,
- dtype=dtype,
- )
- lval = left.getitem(lefti.offset).convert_to(dtype)
- rval = right.getitem(righti.offset).convert_to(dtype)
- outval = result.getitem(outi.offset).convert_to(dtype)
- v = dtype.itemtype.mul(lval, rval)
- value = dtype.itemtype.add(v, outval).convert_to(dtype)
- result.setitem(outi.offset, value)
- outi = outi.next(shapelen)
- righti = righti.next(shapelen)
- lefti = lefti.next(shapelen)
- return result
diff --git a/pypy/module/micronumpy/interp_arrayops.py b/pypy/module/micronumpy/interp_arrayops.py
--- a/pypy/module/micronumpy/interp_arrayops.py
+++ b/pypy/module/micronumpy/interp_arrayops.py
@@ -1,30 +1,12 @@
-from pypy.module.micronumpy.interp_numarray import convert_to_array,\
- VirtualArray
-from pypy.module.micronumpy import signature
+from pypy.module.micronumpy.base import convert_to_array, W_NDimArray
+from pypy.module.micronumpy import loop, interp_ufuncs
+from pypy.module.micronumpy.iter import Chunk, Chunks
+from pypy.module.micronumpy.strides import shape_agreement
+from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.gateway import unwrap_spec
-class WhereArray(VirtualArray):
- def __init__(self, space, arr, x, y):
- self.arr = arr
- self.x = x
- self.y = y
- VirtualArray.__init__(self, 'where', arr.shape[:],
- x.find_dtype())
-
- def create_sig(self):
- if self.forced_result is not None:
- return self.forced_result.create_sig()
- return signature.WhereSignature(self.res_dtype, self.arr.find_dtype(),
- self.arr.create_sig(),
- self.x.create_sig(),
- self.y.create_sig())
-
- def _del_sources(self):
- self.arr = None
- self.x = None
- self.y = None
-
-def where(space, w_arr, w_x, w_y):
+def where(space, w_arr, w_x=None, w_y=None):
"""where(condition, [x, y])
Return elements, either from `x` or `y`, depending on `condition`.
@@ -84,7 +66,87 @@
NOTE: support for not passing x and y is unsupported
"""
+ if space.is_w(w_y, space.w_None):
+ if space.is_w(w_x, space.w_None):
+ raise OperationError(space.w_NotImplementedError, space.wrap(
+ "1-arg where unsupported right now"))
+ raise OperationError(space.w_ValueError, space.wrap(
+ "Where should be called with either 1 or 3 arguments"))
arr = convert_to_array(space, w_arr)
x = convert_to_array(space, w_x)
y = convert_to_array(space, w_y)
- return WhereArray(space, arr, x, y)
+ if x.is_scalar() and y.is_scalar() and arr.is_scalar():
+ if arr.get_dtype().itemtype.bool(arr.get_scalar_value()):
+ return x
+ return y
+ dtype = interp_ufuncs.find_binop_result_dtype(space, x.get_dtype(),
+ y.get_dtype())
+ shape = shape_agreement(space, arr.get_shape(), x)
+ shape = shape_agreement(space, shape, y)
+ out = W_NDimArray.from_shape(shape, dtype)
+ return loop.where(out, shape, arr, x, y, dtype)
+
+def dot(space, w_obj1, w_obj2):
+ w_arr = convert_to_array(space, w_obj1)
+ if w_arr.is_scalar():
+ return convert_to_array(space, w_obj2).descr_dot(space, w_arr)
+ return w_arr.descr_dot(space, w_obj2)
+
+
+ at unwrap_spec(axis=int)
+def concatenate(space, w_args, axis=0):
+ args_w = space.listview(w_args)
+ if len(args_w) == 0:
+ raise OperationError(space.w_ValueError, space.wrap("need at least one array to concatenate"))
+ args_w = [convert_to_array(space, w_arg) for w_arg in args_w]
+ dtype = args_w[0].get_dtype()
+ shape = args_w[0].get_shape()[:]
+ if len(shape) <= axis:
+ raise operationerrfmt(space.w_IndexError, "axis %d out of bounds [0, %d)", axis, len(shape))
+ for arr in args_w[1:]:
+ dtype = interp_ufuncs.find_binop_result_dtype(space, dtype,
+ arr.get_dtype())
+ if len(arr.get_shape()) <= axis:
+ raise operationerrfmt(space.w_IndexError, "axis %d out of bounds [0, %d)", axis, len(shape))
+ for i, axis_size in enumerate(arr.get_shape()):
+ if len(arr.get_shape()) != len(shape) or (i != axis and axis_size != shape[i]):
+ raise OperationError(space.w_ValueError, space.wrap(
+ "all the input arrays must have same number of dimensions"))
+ elif i == axis:
+ shape[i] += axis_size
+ res = W_NDimArray.from_shape(shape, dtype, 'C')
+ chunks = [Chunk(0, i, 1, i) for i in shape]
+ axis_start = 0
+ for arr in args_w:
+ chunks[axis] = Chunk(axis_start, axis_start + arr.get_shape()[axis], 1,
+ arr.get_shape()[axis])
+ Chunks(chunks).apply(res.implementation).implementation.setslice(space, arr)
+ axis_start += arr.get_shape()[axis]
+ return res
+
+ at unwrap_spec(repeats=int)
+def repeat(space, w_arr, repeats, w_axis=None):
+ arr = convert_to_array(space, w_arr)
+ if space.is_w(w_axis, space.w_None):
+ arr = arr.descr_flatten(space)
+ orig_size = arr.get_shape()[0]
+ shape = [arr.get_shape()[0] * repeats]
+ res = W_NDimArray.from_shape(shape, arr.get_dtype())
+ for i in range(repeats):
+ Chunks([Chunk(i, shape[0] - repeats + i, repeats,
+ orig_size)]).apply(res.implementation).implementation.setslice(space, arr)
+ else:
+ axis = space.int_w(w_axis)
+ shape = arr.get_shape()[:]
+ chunks = [Chunk(0, i, 1, i) for i in shape]
+ orig_size = shape[axis]
+ shape[axis] *= repeats
+ res = W_NDimArray.from_shape(shape, arr.get_dtype())
+ for i in range(repeats):
+ chunks[axis] = Chunk(i, shape[axis] - repeats + i, repeats,
+ orig_size)
+ Chunks(chunks).apply(res.implementation).implementation.setslice(space, arr)
+ return res
+
+def count_nonzero(space, w_obj):
+ return space.wrap(loop.count_all_true(convert_to_array(space, w_obj)))
diff --git a/pypy/module/micronumpy/interp_boxes.py b/pypy/module/micronumpy/interp_boxes.py
--- a/pypy/module/micronumpy/interp_boxes.py
+++ b/pypy/module/micronumpy/interp_boxes.py
@@ -8,6 +8,7 @@
from pypy.objspace.std.inttype import int_typedef
from pypy.rlib.rarithmetic import LONG_BIT
from pypy.tool.sourcetools import func_with_new_name
+from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage
MIXIN_32 = (int_typedef,) if LONG_BIT == 32 else ()
MIXIN_64 = (int_typedef,) if LONG_BIT == 64 else ()
@@ -33,7 +34,6 @@
def convert_to(self, dtype):
return dtype.box(self.value)
-
class W_GenericBox(Wrappable):
_attrs_ = ()
@@ -142,7 +142,6 @@
def item(self, space):
return self.get_dtype(space).itemtype.to_builtin_type(space, self)
-
class W_BoolBox(W_GenericBox, PrimitiveBox):
descr__new__, _get_dtype = new_dtype_getter("bool")
@@ -246,11 +245,10 @@
class W_StringBox(W_CharacterBox):
def descr__new__string_box(space, w_subtype, w_arg):
- from pypy.module.micronumpy.interp_numarray import W_NDimArray
from pypy.module.micronumpy.interp_dtype import new_string_dtype
arg = space.str_w(space.str(w_arg))
- arr = W_NDimArray([1], new_string_dtype(space, len(arg)))
+ arr = VoidBoxStorage(len(arg), new_string_dtype(space, len(arg)))
for i in range(len(arg)):
arr.storage[i] = arg[i]
return W_StringBox(arr, 0, arr.dtype)
@@ -258,11 +256,11 @@
class W_UnicodeBox(W_CharacterBox):
def descr__new__unicode_box(space, w_subtype, w_arg):
- from pypy.module.micronumpy.interp_numarray import W_NDimArray
from pypy.module.micronumpy.interp_dtype import new_unicode_dtype
arg = space.unicode_w(unicode_from_object(space, w_arg))
- arr = W_NDimArray([1], new_unicode_dtype(space, len(arg)))
+ # XXX size computations, we need tests anyway
+ arr = VoidBoxStorage(len(arg), new_unicode_dtype(space, len(arg)))
# XXX not this way, we need store
#for i in range(len(arg)):
# arr.storage[i] = arg[i]
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
@@ -18,6 +18,12 @@
STRINGLTR = 'S'
UNICODELTR = 'U'
+def decode_w_dtype(space, w_dtype):
+ if w_dtype is None or space.is_w(w_dtype, space.w_None):
+ return None
+ return space.interp_w(W_Dtype,
+ space.call_function(space.gettypefor(W_Dtype), w_dtype))
+
class W_Dtype(Wrappable):
_immutable_fields_ = ["itemtype", "num", "kind"]
diff --git a/pypy/module/micronumpy/interp_flatiter.py b/pypy/module/micronumpy/interp_flatiter.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/interp_flatiter.py
@@ -0,0 +1,83 @@
+
+from pypy.module.micronumpy.base import W_NDimArray, convert_to_array
+from pypy.module.micronumpy import loop
+from pypy.module.micronumpy.arrayimpl.base import BaseArrayImplementation
+from pypy.interpreter.error import OperationError
+
+class FakeArrayImplementation(BaseArrayImplementation):
+ """ The sole purpose of this class is to W_FlatIterator can behave
+ like a real array for descr_eq and friends
+ """
+ def __init__(self, base):
+ self.base = base
+ self.dtype = base.get_dtype()
+ self.shape = [base.get_size()]
+
+ def get_shape(self):
+ return self.shape
+
+ def create_iter(self, shape=None):
+ return self.base.create_iter()
+
+class W_FlatIterator(W_NDimArray):
+ def __init__(self, arr):
+ self.base = arr
+ # this is needed to support W_NDimArray interface
+ self.implementation = FakeArrayImplementation(self.base)
+ self.reset()
+
+ def reset(self):
+ self.iter = self.base.create_iter()
+ self.index = 0
+
+ def descr_len(self, space):
+ return space.wrap(self.base.get_size())
+
+ def descr_next(self, space):
+ if self.iter.done():
+ raise OperationError(space.w_StopIteration, space.w_None)
+ w_res = self.iter.getitem()
+ self.iter.next()
+ self.index += 1
+ return w_res
+
+ def descr_index(self, space):
+ return space.wrap(self.index)
+
+ def descr_coords(self, space):
+ coords = self.base.to_coords(space, space.wrap(self.index))
+ return space.newtuple([space.wrap(c) for c in coords])
+
+ def descr_getitem(self, space, w_idx):
+ if not (space.isinstance_w(w_idx, space.w_int) or
+ space.isinstance_w(w_idx, space.w_slice)):
+ raise OperationError(space.w_IndexError,
+ space.wrap('unsupported iterator index'))
+ self.reset()
+ base = self.base
+ start, stop, step, length = space.decode_index4(w_idx, base.get_size())
+ base_iter = base.create_iter()
+ base_iter.next_skip_x(start)
+ if length == 1:
+ return base_iter.getitem()
+ res = W_NDimArray.from_shape([length], base.get_dtype(),
+ base.get_order())
+ return loop.flatiter_getitem(res, base_iter, step)
+
+ def descr_setitem(self, space, w_idx, w_value):
+ if not (space.isinstance_w(w_idx, space.w_int) or
+ space.isinstance_w(w_idx, space.w_slice)):
+ raise OperationError(space.w_IndexError,
+ space.wrap('unsupported iterator index'))
+ base = self.base
+ start, stop, step, length = space.decode_index4(w_idx, base.get_size())
+ arr = convert_to_array(space, w_value)
+ loop.flatiter_setitem(self.base, arr, start, step, length)
+
+ def descr_iter(self):
+ return self
+
+ def descr_base(self, space):
+ return space.wrap(self.base)
+
+# typedef is in interp_numarray, so we see the additional arguments
diff --git a/pypy/module/micronumpy/interp_iter.py b/pypy/module/micronumpy/interp_iter.py
deleted file mode 100644
--- a/pypy/module/micronumpy/interp_iter.py
+++ /dev/null
@@ -1,359 +0,0 @@
-
-from pypy.rlib import jit
-from pypy.rlib.objectmodel import instantiate
-from pypy.module.micronumpy.strides import calculate_broadcast_strides,\
- calculate_slice_strides, calculate_dot_strides, enumerate_chunks
-
-""" This is a mini-tutorial on iterators, strides, and
-memory layout. It assumes you are familiar with the terms, see
-http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html
-for a more gentle introduction.
-
-Given an array x: x.shape == [5,6],
-
-At which byte in x.data does the item x[3,4] begin?
-if x.strides==[1,5]:
- pData = x.pData + (x.start + 3*1 + 4*5)*sizeof(x.pData[0])
- pData = x.pData + (x.start + 24) * sizeof(x.pData[0])
-so the offset of the element is 24 elements after the first
-
-What is the next element in x after coordinates [3,4]?
-if x.order =='C':
- next == [3,5] => offset is 28
-if x.order =='F':
- next == [4,4] => offset is 24
-so for the strides [1,5] x is 'F' contiguous
-likewise, for the strides [6,1] x would be 'C' contiguous.
-
-Iterators have an internal representation of the current coordinates
-(indices), the array, strides, and backstrides. A short digression to
-explain backstrides: what is the coordinate and offset after [3,5] in
-the example above?
-if x.order == 'C':
- next == [4,0] => offset is 4
-if x.order == 'F':
- next == [4,5] => offset is 25
-Note that in 'C' order we stepped BACKWARDS 24 while 'overflowing' a
-shape dimension
- which is back 25 and forward 1,
- which is x.strides[1] * (x.shape[1] - 1) + x.strides[0]
-so if we precalculate the overflow backstride as
-[x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))]
-we can go faster.
-All the calculations happen in next()
-
-next_skip_x() tries to do the iteration for a number of steps at once,
-but then we cannot gaurentee that we only overflow one single shape
-dimension, perhaps we could overflow times in one big step.
-"""
-
-# structures to describe slicing
-
-class BaseChunk(object):
- pass
-
-class RecordChunk(BaseChunk):
- def __init__(self, name):
- self.name = name
-
- def apply(self, arr):
- from pypy.module.micronumpy.interp_numarray import W_NDimSlice
-
- arr = arr.get_concrete()
- ofs, subdtype = arr.dtype.fields[self.name]
- # strides backstrides are identical, ofs only changes start
- return W_NDimSlice(arr.start + ofs, arr.strides[:], arr.backstrides[:],
- arr.shape[:], arr, subdtype)
-
-class Chunks(BaseChunk):
- def __init__(self, l):
- self.l = l
-
- @jit.unroll_safe
- def extend_shape(self, old_shape):
- shape = []
- i = -1
- for i, c in enumerate_chunks(self.l):
- if c.step != 0:
- shape.append(c.lgt)
- s = i + 1
- assert s >= 0
- return shape[:] + old_shape[s:]
-
- def apply(self, arr):
- from pypy.module.micronumpy.interp_numarray import W_NDimSlice,\
- VirtualSlice, ConcreteArray
-
- shape = self.extend_shape(arr.shape)
- if not isinstance(arr, ConcreteArray):
- return VirtualSlice(arr, self, shape)
- r = calculate_slice_strides(arr.shape, arr.start, arr.strides,
- arr.backstrides, self.l)
- _, start, strides, backstrides = r
- return W_NDimSlice(start, strides[:], backstrides[:],
- shape[:], arr)
-
-
-class Chunk(BaseChunk):
- axis_step = 1
-
- def __init__(self, start, stop, step, lgt):
- self.start = start
- self.stop = stop
- self.step = step
- self.lgt = lgt
-
- def __repr__(self):
- return 'Chunk(%d, %d, %d, %d)' % (self.start, self.stop, self.step,
- self.lgt)
-
-class NewAxisChunk(Chunk):
- start = 0
- stop = 1
- step = 1
- lgt = 1
- axis_step = 0
-
- def __init__(self):
- pass
-
-class BaseTransform(object):
- pass
-
-class ViewTransform(BaseTransform):
- def __init__(self, chunks):
- # 4-tuple specifying slicing
- self.chunks = chunks
-
-class BroadcastTransform(BaseTransform):
- def __init__(self, res_shape):
- self.res_shape = res_shape
-
-
-class BaseIterator(object):
- def next(self, shapelen):
- raise NotImplementedError
-
- def done(self):
- raise NotImplementedError
-
- def apply_transformations(self, arr, transformations):
- v = self
- if transformations is not None:
- for transform in transformations:
- v = v.transform(arr, transform)
- return v
-
- def transform(self, arr, t):
- raise NotImplementedError
-
-class ArrayIterator(BaseIterator):
- def __init__(self, size, element_size):
- self.offset = 0
- self.size = size
- self.element_size = element_size
-
- def next(self, shapelen):
- return self.next_skip_x(1)
-
- def next_skip_x(self, x):
- arr = instantiate(ArrayIterator)
- arr.size = self.size
- arr.offset = self.offset + x * self.element_size
- arr.element_size = self.element_size
- return arr
-
- def next_no_increase(self, shapelen):
- # a hack to make JIT believe this is always virtual
- return self.next_skip_x(0)
-
- def done(self):
- return self.offset >= self.size
-
- def transform(self, arr, t):
- return ViewIterator(arr.start, arr.strides, arr.backstrides,
- arr.shape).transform(arr, t)
-
-class OneDimIterator(BaseIterator):
- def __init__(self, start, step, stop):
- self.offset = start
- self.step = step
- self.size = stop * step + start
-
- def next(self, shapelen):
- arr = instantiate(OneDimIterator)
- arr.size = self.size
- arr.step = self.step
- arr.offset = self.offset + self.step
- return arr
-
- def done(self):
- return self.offset == self.size
-
-class ViewIterator(BaseIterator):
- def __init__(self, start, strides, backstrides, shape):
- self.offset = start
- self._done = False
- self.strides = strides
- self.backstrides = backstrides
- self.res_shape = shape
- self.indices = [0] * len(self.res_shape)
-
- def transform(self, arr, t):
- if isinstance(t, BroadcastTransform):
- r = calculate_broadcast_strides(self.strides, self.backstrides,
- self.res_shape, t.res_shape)
- return ViewIterator(self.offset, r[0], r[1], t.res_shape)
- elif isinstance(t, ViewTransform):
- r = calculate_slice_strides(self.res_shape, self.offset,
- self.strides,
- self.backstrides, t.chunks.l)
- return ViewIterator(r[1], r[2], r[3], r[0])
-
- @jit.unroll_safe
- def next(self, shapelen):
- shapelen = jit.promote(len(self.res_shape))
- offset = self.offset
- indices = [0] * shapelen
- for i in range(shapelen):
- indices[i] = self.indices[i]
- done = False
- for i in range(shapelen - 1, -1, -1):
- if indices[i] < self.res_shape[i] - 1:
- indices[i] += 1
- offset += self.strides[i]
- break
- else:
- indices[i] = 0
- offset -= self.backstrides[i]
- else:
- done = True
- res = instantiate(ViewIterator)
- res.offset = offset
- res.indices = indices
- res.strides = self.strides
- res.backstrides = self.backstrides
- res.res_shape = self.res_shape
- res._done = done
- return res
-
- @jit.unroll_safe
- def next_skip_x(self, shapelen, step):
- shapelen = jit.promote(len(self.res_shape))
- offset = self.offset
- indices = [0] * shapelen
- for i in range(shapelen):
- indices[i] = self.indices[i]
- done = False
- for i in range(shapelen - 1, -1, -1):
- if indices[i] < self.res_shape[i] - step:
- indices[i] += step
- offset += self.strides[i] * step
- break
- else:
- remaining_step = (indices[i] + step) // self.res_shape[i]
- this_i_step = step - remaining_step * self.res_shape[i]
- offset += self.strides[i] * this_i_step
- indices[i] = indices[i] + this_i_step
- step = remaining_step
- else:
- done = True
- res = instantiate(ViewIterator)
- res.offset = offset
- res.indices = indices
- res.strides = self.strides
- res.backstrides = self.backstrides
- res.res_shape = self.res_shape
- res._done = done
- return res
-
- def apply_transformations(self, arr, transformations):
- v = BaseIterator.apply_transformations(self, arr, transformations)
- if len(arr.shape) == 1 and len(v.res_shape) == 1:
- return OneDimIterator(self.offset, self.strides[0],
- self.res_shape[0])
- return v
-
- def done(self):
- return self._done
-
-class ConstantIterator(BaseIterator):
- def next(self, shapelen):
- return self
-
- def transform(self, arr, t):
- pass
-
-
-class AxisIterator(BaseIterator):
- def __init__(self, start, dim, shape, strides, backstrides):
- self.res_shape = shape[:]
- if len(shape) == len(strides):
- # keepdims = True
- self.strides = strides[:dim] + [0] + strides[dim + 1:]
- self.backstrides = backstrides[:dim] + [0] + backstrides[dim + 1:]
- else:
- self.strides = strides[:dim] + [0] + strides[dim:]
- self.backstrides = backstrides[:dim] + [0] + backstrides[dim:]
- self.first_line = True
- self.indices = [0] * len(shape)
- self._done = False
- self.offset = start
- self.dim = dim
-
- @jit.unroll_safe
- def next(self, shapelen):
- offset = self.offset
- first_line = self.first_line
- indices = [0] * shapelen
- for i in range(shapelen):
- indices[i] = self.indices[i]
- done = False
- for i in range(shapelen - 1, -1, -1):
- if indices[i] < self.res_shape[i] - 1:
- if i == self.dim:
- first_line = False
- indices[i] += 1
- offset += self.strides[i]
- break
- else:
- if i == self.dim:
- first_line = True
- indices[i] = 0
- offset -= self.backstrides[i]
- else:
- done = True
- res = instantiate(AxisIterator)
- res.offset = offset
- res.indices = indices
- res.strides = self.strides
- res.backstrides = self.backstrides
- res.res_shape = self.res_shape
- res._done = done
- res.first_line = first_line
- res.dim = self.dim
- return res
-
- def done(self):
- return self._done
-
-# ------ other iterators that are not part of the computation frame ----------
-
-class SkipLastAxisIterator(object):
- def __init__(self, arr):
- self.arr = arr
- self.indices = [0] * (len(arr.shape) - 1)
- self.done = False
- self.offset = arr.start
-
- def next(self):
- for i in range(len(self.arr.shape) - 2, -1, -1):
- if self.indices[i] < self.arr.shape[i] - 1:
- self.indices[i] += 1
- self.offset += self.arr.strides[i]
- break
- else:
- self.indices[i] = 0
- self.offset -= self.arr.backstrides[i]
- else:
- self.done = True
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
@@ -1,88 +1,299 @@
-from pypy.interpreter.baseobjspace import Wrappable
-from pypy.interpreter.error import OperationError, operationerrfmt
+
+from pypy.interpreter.error import operationerrfmt, OperationError
+from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.interpreter.gateway import interp2app, unwrap_spec
-from pypy.interpreter.typedef import TypeDef, GetSetProperty
-from pypy.module.micronumpy import (interp_ufuncs, interp_dtype, interp_boxes,
- signature, support, loop)
+from pypy.module.micronumpy.base import W_NDimArray, convert_to_array
+from pypy.module.micronumpy import interp_dtype, interp_ufuncs, interp_boxes
+from pypy.module.micronumpy.strides import find_shape_and_elems,\
+ get_shape_from_iterable, to_coords
+from pypy.module.micronumpy.interp_flatiter import W_FlatIterator
+from pypy.module.micronumpy.interp_support import unwrap_axis_arg
from pypy.module.micronumpy.appbridge import get_appbridge_cache
-from pypy.module.micronumpy.dot import multidim_dot, match_dot_shapes
-from pypy.module.micronumpy.interp_iter import (ArrayIterator,
- SkipLastAxisIterator, Chunk, ViewIterator, Chunks, RecordChunk,
- NewAxisChunk)
-from pypy.module.micronumpy.strides import (shape_agreement,
- find_shape_and_elems, get_shape_from_iterable, calc_new_strides, to_coords)
+from pypy.module.micronumpy import loop
+from pypy.module.micronumpy.dot import match_dot_shapes
+from pypy.module.micronumpy.interp_arrayops import repeat
+from pypy.tool.sourcetools import func_with_new_name
from pypy.rlib import jit
from pypy.rlib.rstring import StringBuilder
-from pypy.rlib.rawstorage import free_raw_storage
-from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.tool.sourcetools import func_with_new_name
-from pypy.module.micronumpy.interp_support import unwrap_axis_arg
-count_driver = jit.JitDriver(
- greens=['shapelen'],
- virtualizables=['frame'],
- reds=['s', 'frame', 'iter', 'arr'],
- name='numpy_count'
-)
-filter_driver = jit.JitDriver(
- greens=['shapelen', 'sig'],
- virtualizables=['frame'],
- reds=['concr', 'argi', 'ri', 'frame', 'v', 'res', 'self'],
- name='numpy_filter',
-)
-filter_set_driver = jit.JitDriver(
- greens=['shapelen', 'sig'],
- virtualizables=['frame'],
- reds=['idx', 'idxi', 'frame', 'arr'],
- name='numpy_filterset',
-)
-take_driver = jit.JitDriver(
- greens=['shapelen', 'sig'],
- reds=['index_i', 'res_i', 'concr', 'index', 'res'],
- name='numpy_take',
-)
-flat_get_driver = jit.JitDriver(
- greens=['shapelen', 'base'],
- reds=['step', 'ri', 'basei', 'res'],
- name='numpy_flatget',
-)
-flat_set_driver = jit.JitDriver(
- greens=['shapelen', 'base'],
- reds=['step', 'lngth', 'ri', 'arr', 'basei'],
- name='numpy_flatset',
-)
+def _find_shape(space, w_size):
+ if space.isinstance_w(w_size, space.w_int):
+ return [space.int_w(w_size)]
+ shape = []
+ for w_item in space.fixedview(w_size):
+ shape.append(space.int_w(w_item))
+ return shape
-class BaseArray(Wrappable):
- _attrs_ = ["invalidates", "shape", 'size']
+class __extend__(W_NDimArray):
+ @jit.unroll_safe
+ def descr_get_shape(self, space):
+ shape = self.get_shape()
+ return space.newtuple([space.wrap(i) for i in shape])
- _immutable_fields_ = []
+ def get_shape(self):
+ return self.implementation.get_shape()
- strides = None
- start = 0
+ def descr_set_shape(self, space, w_new_shape):
+ self.implementation = self.implementation.set_shape(space,
+ get_shape_from_iterable(space, self.get_size(), w_new_shape))
- def __init__(self, shape):
- self.invalidates = []
- self.shape = shape
+ def get_dtype(self):
+ return self.implementation.dtype
- def invalidated(self):
- if self.invalidates:
- self._invalidated()
+ def get_order(self):
+ return self.implementation.order
- def _invalidated(self):
- for arr in self.invalidates:
- arr.force_if_needed()
- del self.invalidates[:]
+ def descr_get_dtype(self, space):
+ return self.implementation.dtype
- def add_invalidates(self, space, other):
- if get_numarray_cache(space).enable_invalidation:
- self.invalidates.append(other)
-
- def descr__new__(space, w_subtype, w_size, w_dtype=None):
- dtype = space.interp_w(interp_dtype.W_Dtype,
- space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
- )
- shape = _find_shape(space, w_size)
- return space.wrap(W_NDimArray(shape[:], dtype=dtype))
+ def descr_get_ndim(self, space):
+ return space.wrap(len(self.get_shape()))
+
+ def descr_get_itemsize(self, space):
+ return space.wrap(self.get_dtype().itemtype.get_element_size())
+
+ def descr_get_nbytes(self, space):
+ return space.wrap(self.get_size() * self.get_dtype().itemtype.get_element_size())
+
+ def descr_fill(self, space, w_value):
+ self.fill(self.get_dtype().coerce(space, w_value))
+
+ def descr_tostring(self, space):
+ return space.wrap(loop.tostring(space, self))
+
+ def getitem_filter(self, space, arr):
+ if arr.get_size() > self.get_size():
+ raise OperationError(space.w_IndexError,
+ space.wrap("index out of range for array"))
+ size = loop.count_all_true(arr)
+ res = W_NDimArray.from_shape([size], self.get_dtype())
+ return loop.getitem_filter(res, self, arr)
+
+ def setitem_filter(self, space, idx, val):
+ loop.setitem_filter(self, idx, val)
+
+ def descr_getitem(self, space, w_idx):
+ if (isinstance(w_idx, W_NDimArray) and w_idx.get_shape() == self.get_shape() and
+ w_idx.get_dtype().is_bool_type()):
+ return self.getitem_filter(space, w_idx)
+ try:
+ return self.implementation.descr_getitem(space, w_idx)
+ except OperationError:
+ raise OperationError(space.w_IndexError, space.wrap("wrong index"))
+
+ def descr_setitem(self, space, w_idx, w_value):
+ if (isinstance(w_idx, W_NDimArray) and w_idx.get_shape() == self.get_shape() and
+ w_idx.get_dtype().is_bool_type()):
+ return self.setitem_filter(space, w_idx,
+ convert_to_array(space, w_value))
+ self.implementation.descr_setitem(space, w_idx, w_value)
+
+ def descr_len(self, space):
+ shape = self.get_shape()
+ if len(shape):
+ return space.wrap(shape[0])
+ raise OperationError(space.w_TypeError, space.wrap(
+ "len() of unsized object"))
+
+ def descr_repr(self, space):
+ cache = get_appbridge_cache(space)
+ if cache.w_array_repr is None:
+ return space.wrap(self.dump_data())
+ return space.call_function(cache.w_array_repr, self)
+
+ def descr_str(self, space):
+ cache = get_appbridge_cache(space)
+ if cache.w_array_str is None:
+ return space.wrap(self.dump_data())
+ return space.call_function(cache.w_array_str, self)
+
+ def dump_data(self):
+ i = self.create_iter(self.get_shape())
+ first = True
+ dtype = self.get_dtype()
+ s = StringBuilder()
+ s.append('array([')
+ while not i.done():
+ if first:
+ first = False
+ else:
+ s.append(', ')
+ s.append(dtype.itemtype.str_format(i.getitem()))
+ i.next()
+ s.append('])')
+ return s.build()
+
+ def create_iter(self, shape=None):
+ if shape is None:
+ shape = self.get_shape()
+ return self.implementation.create_iter(shape)
+
+ def create_axis_iter(self, shape, dim):
+ return self.implementation.create_axis_iter(shape, dim)
+
+ def create_dot_iter(self, shape, skip):
+ return self.implementation.create_dot_iter(shape, skip)
+
+ def is_scalar(self):
+ return self.implementation.is_scalar()
+
+ def set_scalar_value(self, w_val):
+ self.implementation.set_scalar_value(w_val)
+
+ def fill(self, box):
+ self.implementation.fill(box)
+
+ def descr_get_size(self, space):
+ return space.wrap(self.get_size())
+
+ def get_size(self):
+ return self.implementation.get_size()
+
+ def get_scalar_value(self):
+ return self.implementation.get_scalar_value()
+
+ def descr_copy(self, space):
+ return W_NDimArray(self.implementation.copy())
+
+ def descr_reshape(self, space, args_w):
+ """reshape(...)
+ a.reshape(shape)
+
+ Returns an array containing the same data with a new shape.
+
+ Refer to `numpypy.reshape` for full documentation.
+
+ See Also
+ --------
+ numpypy.reshape : equivalent function
+ """
+ if len(args_w) == 1:
+ w_shape = args_w[0]
+ else:
+ w_shape = space.newtuple(args_w)
+ new_shape = get_shape_from_iterable(space, self.get_size(), w_shape)
+ new_impl = self.implementation.reshape(space, new_shape)
+ if new_impl is not None:
+ return W_NDimArray(new_impl)
+ # Create copy with contiguous data
+ arr = self.descr_copy(space)
+ if arr.get_size() > 0:
+ arr.implementation = arr.implementation.reshape(space, new_shape)
+ assert arr.implementation
+ else:
+ arr.implementation.shape = new_shape
+ return arr
+
+ def descr_get_transpose(self, space):
+ return W_NDimArray(self.implementation.transpose())
+
+ @unwrap_spec(axis1=int, axis2=int)
+ def descr_swapaxes(self, space, axis1, axis2):
+ """a.swapaxes(axis1, axis2)
+
+ Return a view of the array with `axis1` and `axis2` interchanged.
+
+ Refer to `numpy.swapaxes` for full documentation.
+
+ See Also
+ --------
+ numpy.swapaxes : equivalent function
+ """
+ if self.is_scalar():
+ return self
+ return self.implementation.swapaxes(axis1, axis2)
+
+ def descr_tolist(self, space):
+ if len(self.get_shape()) == 0:
+ return self.get_scalar_value().item(space)
+ l_w = []
+ for i in range(self.get_shape()[0]):
+ l_w.append(space.call_method(self.descr_getitem(space,
+ space.wrap(i)), "tolist"))
+ return space.newlist(l_w)
+
+ def descr_ravel(self, space, w_order=None):
+ if w_order is None or space.is_w(w_order, space.w_None):
+ order = 'C'
+ else:
+ order = space.str_w(w_order)
+ if order != 'C':
+ raise OperationError(space.w_NotImplementedError, space.wrap(
+ "order not implemented"))
+ return self.descr_reshape(space, [space.wrap(-1)])
+
+ def descr_take(self, space, w_obj, w_axis=None, w_out=None):
+ # if w_axis is None and w_out is Nont this is an equivalent to
+ # fancy indexing
+ raise Exception("unsupported for now")
+ if not space.is_w(w_axis, space.w_None):
+ raise OperationError(space.w_NotImplementedError,
+ space.wrap("axis unsupported for take"))
+ if not space.is_w(w_out, space.w_None):
+ raise OperationError(space.w_NotImplementedError,
+ space.wrap("out unsupported for take"))
+ return self.getitem_int(space, convert_to_array(space, w_obj))
+
+ def descr_compress(self, space, w_obj, w_axis=None):
+ index = convert_to_array(space, w_obj)
+ return self.getitem_filter(space, index)
+
+ def descr_flatten(self, space, w_order=None):
+ if self.is_scalar():
+ # scalars have no storage
+ return self.descr_reshape(space, [space.wrap(1)])
+ w_res = self.descr_ravel(space, w_order)
+ if w_res.implementation.storage == self.implementation.storage:
+ return w_res.descr_copy(space)
+ return w_res
+
+ @unwrap_spec(repeats=int)
+ def descr_repeat(self, space, repeats, w_axis=None):
+ return repeat(space, self, repeats, w_axis)
+
+ def descr_get_flatiter(self, space):
+ return space.wrap(W_FlatIterator(self))
+
+ def to_coords(self, space, w_index):
+ coords, _, _ = to_coords(space, self.get_shape(),
+ self.get_size(), self.get_order(),
+ w_index)
+ return coords
+
+ def descr_item(self, space, w_arg=None):
+ if space.is_w(w_arg, space.w_None):
+ if self.is_scalar():
+ return self.get_scalar_value().item(space)
+ if self.get_size() == 1:
+ w_obj = self.descr_getitem(space,
+ space.newtuple([space.wrap(0) for i
+ in range(len(self.get_shape()))]))
+ assert isinstance(w_obj, interp_boxes.W_GenericBox)
+ return w_obj.item(space)
+ raise OperationError(space.w_IndexError,
+ space.wrap("index out of bounds"))
+ if space.isinstance_w(w_arg, space.w_int):
+ if self.is_scalar():
+ raise OperationError(space.w_IndexError,
+ space.wrap("index out of bounds"))
+ i = self.to_coords(space, w_arg)
+ item = self.descr_getitem(space, space.newtuple([space.wrap(x)
+ for x in i]))
+ assert isinstance(item, interp_boxes.W_GenericBox)
+ return item.item(space)
+ raise OperationError(space.w_NotImplementedError, space.wrap(
+ "non-int arg not supported"))
+
+ def descr_array_iface(self, space):
+ addr = self.implementation.get_storage_as_int(space)
+ # will explode if it can't
+ w_d = space.newdict()
+ space.setitem_str(w_d, 'data', space.newtuple([space.wrap(addr),
+ space.w_False]))
+ return w_d
+
+
+ # --------------------- operations ----------------------------
def _unaryop_impl(ufunc_name):
def impl(self, space, w_out=None):
@@ -95,6 +306,13 @@
descr_abs = _unaryop_impl("absolute")
descr_invert = _unaryop_impl("invert")
+ def descr_nonzero(self, space):
+ if self.get_size() > 1:
+ raise OperationError(space.w_ValueError, space.wrap(
+ "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()"))
+ iter = self.create_iter(self.get_shape())
+ return space.wrap(space.is_true(iter.getitem()))
+
def _binop_impl(ufunc_name):
def impl(self, space, w_other, w_out=None):
return getattr(interp_ufuncs.get(space), ufunc_name).call(space,
@@ -115,6 +333,11 @@
descr_or = _binop_impl("bitwise_or")
descr_xor = _binop_impl("bitwise_xor")
+ def descr_divmod(self, space, w_other):
+ w_quotient = self.descr_div(space, w_other)
+ w_remainder = self.descr_mod(space, w_other)
+ return space.newtuple([w_quotient, w_remainder])
+
descr_eq = _binop_impl("equal")
descr_ne = _binop_impl("not_equal")
descr_lt = _binop_impl("less")
@@ -122,17 +345,11 @@
descr_gt = _binop_impl("greater")
descr_ge = _binop_impl("greater_equal")
- def descr_divmod(self, space, w_other):
- w_quotient = self.descr_div(space, w_other)
- w_remainder = self.descr_mod(space, w_other)
- return space.newtuple([w_quotient, w_remainder])
-
def _binop_right_impl(ufunc_name):
def impl(self, space, w_other, w_out=None):
- w_other = scalar_w(space,
- interp_ufuncs.find_dtype_for_scalar(space, w_other, self.find_dtype()),
- w_other
- )
+ dtype = interp_ufuncs.find_dtype_for_scalar(space, w_other,
+ self.get_dtype())
+ w_other = W_NDimArray.new_scalar(space, dtype, w_other)
return getattr(interp_ufuncs.get(space), ufunc_name).call(space, [w_other, self, w_out])
return func_with_new_name(impl, "binop_right_%s_impl" % ufunc_name)
@@ -155,18 +372,49 @@
w_remainder = self.descr_rmod(space, w_other)
return space.newtuple([w_quotient, w_remainder])
+ def descr_dot(self, space, w_other):
+ other = convert_to_array(space, w_other)
+ if other.is_scalar():
+ #Note: w_out is not modified, this is numpy compliant.
+ return self.descr_mul(space, other)
+ elif len(self.get_shape()) < 2 and len(other.get_shape()) < 2:
+ w_res = self.descr_mul(space, other)
+ assert isinstance(w_res, W_NDimArray)
+ return w_res.descr_sum(space, space.wrap(-1))
+ dtype = interp_ufuncs.find_binop_result_dtype(space,
+ self.get_dtype(), other.get_dtype())
+ if self.get_size() < 1 and other.get_size() < 1:
+ # numpy compatability
+ return W_NDimArray.new_scalar(space, dtype, space.wrap(0))
+ # Do the dims match?
+ out_shape, other_critical_dim = match_dot_shapes(space, self, other)
+ result = W_NDimArray.from_shape(out_shape, dtype)
+ # This is the place to add fpypy and blas
+ return loop.multidim_dot(space, self, other, result, dtype,
+ other_critical_dim)
+
+ def descr_var(self, space, w_axis=None):
+ return get_appbridge_cache(space).call_method(space, '_var', self,
+ w_axis)
+
+ def descr_std(self, space, w_axis=None):
+ return get_appbridge_cache(space).call_method(space, '_std', self,
+ w_axis)
+
+ # ----------------------- reduce -------------------------------
+
def _reduce_ufunc_impl(ufunc_name, promote_to_largest=False):
- def impl(self, space, w_axis=None, w_out=None):
+ def impl(self, space, w_axis=None, w_out=None, w_dtype=None):
if space.is_w(w_out, space.w_None) or not w_out:
out = None
- elif not isinstance(w_out, BaseArray):
+ elif not isinstance(w_out, W_NDimArray):
raise OperationError(space.w_TypeError, space.wrap(
'output must be an array'))
else:
out = w_out
return getattr(interp_ufuncs.get(space), ufunc_name).reduce(space,
self, True, promote_to_largest, w_axis,
- False, out)
+ False, out, w_dtype)
return func_with_new_name(impl, "reduce_%s_impl" % ufunc_name)
descr_sum = _reduce_ufunc_impl("add")
@@ -177,1088 +425,162 @@
descr_all = _reduce_ufunc_impl('logical_and')
descr_any = _reduce_ufunc_impl('logical_or')
+ def descr_mean(self, space, w_axis=None, w_out=None):
+ if space.is_w(w_axis, space.w_None):
+ w_denom = space.wrap(self.get_size())
+ else:
+ axis = unwrap_axis_arg(space, len(self.get_shape()), w_axis)
+ w_denom = space.wrap(self.get_shape()[axis])
+ return space.div(self.descr_sum_promote(space, w_axis, w_out), w_denom)
+
def _reduce_argmax_argmin_impl(op_name):
- reduce_driver = jit.JitDriver(
- greens=['shapelen', 'sig'],
- reds=['result', 'idx', 'frame', 'self', 'cur_best', 'dtype'],
- get_printable_location=signature.new_printable_location(op_name),
- name='numpy_' + op_name,
- )
- def loop(self):
- sig = self.find_sig()
- frame = sig.create_frame(self)
- cur_best = sig.eval(frame, self)
- shapelen = len(self.shape)
- frame.next(shapelen)
- dtype = self.find_dtype()
- result = 0
- idx = 1
- while not frame.done():
- reduce_driver.jit_merge_point(sig=sig,
- shapelen=shapelen,
- self=self, dtype=dtype,
- frame=frame, result=result,
- idx=idx,
- cur_best=cur_best)
- new_best = getattr(dtype.itemtype, op_name)(cur_best, sig.eval(frame, self))
- if dtype.itemtype.ne(new_best, cur_best):
- result = idx
- cur_best = new_best
- frame.next(shapelen)
- idx += 1
- return result
-
def impl(self, space):
- if self.size == 0:
+ if self.get_size() == 0:
raise OperationError(space.w_ValueError,
space.wrap("Can't call %s on zero-size arrays" % op_name))
- return space.wrap(loop(self))
+ return space.wrap(loop.argmin_argmax(op_name, self))
return func_with_new_name(impl, "reduce_arg%s_impl" % op_name)
descr_argmax = _reduce_argmax_argmin_impl("max")
descr_argmin = _reduce_argmax_argmin_impl("min")
- def descr_dot(self, space, w_other):
- other = convert_to_array(space, w_other)
- if isinstance(other, Scalar):
- #Note: w_out is not modified, this is numpy compliant.
- return self.descr_mul(space, other)
- elif len(self.shape) < 2 and len(other.shape) < 2:
- w_res = self.descr_mul(space, other)
- assert isinstance(w_res, BaseArray)
- return w_res.descr_sum(space, space.wrap(-1))
- dtype = interp_ufuncs.find_binop_result_dtype(space,
- self.find_dtype(), other.find_dtype())
- if self.size < 1 and other.size < 1:
- # numpy compatability
- return scalar_w(space, dtype, space.wrap(0))
- # Do the dims match?
- out_shape, other_critical_dim = match_dot_shapes(space, self, other)
- result = W_NDimArray(out_shape, dtype)
- # This is the place to add fpypy and blas
- return multidim_dot(space, self.get_concrete(),
- other.get_concrete(), result, dtype,
- other_critical_dim)
- def get_concrete(self):
- raise NotImplementedError
+ at unwrap_spec(offset=int)
+def descr_new_array(space, w_subtype, w_shape, w_dtype=None, w_buffer=None,
+ offset=0, w_strides=None, w_order=None):
+ if (offset != 0 or not space.is_w(w_strides, space.w_None) or
+ not space.is_w(w_order, space.w_None) or
+ not space.is_w(w_buffer, space.w_None)):
+ raise OperationError(space.w_NotImplementedError,
+ space.wrap("unsupported param"))
+ dtype = space.interp_w(interp_dtype.W_Dtype,
+ space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype))
+ shape = _find_shape(space, w_shape)
+ if not shape:
+ return W_NDimArray.new_scalar(space, dtype)
+ return W_NDimArray.from_shape(shape, dtype)
- def descr_get_dtype(self, space):
- return space.wrap(self.find_dtype())
+W_NDimArray.typedef = TypeDef(
+ "ndarray",
+ __new__ = interp2app(descr_new_array),
- def descr_get_ndim(self, space):
- return space.wrap(len(self.shape))
+ __len__ = interp2app(W_NDimArray.descr_len),
+ __getitem__ = interp2app(W_NDimArray.descr_getitem),
+ __setitem__ = interp2app(W_NDimArray.descr_setitem),
- def descr_get_itemsize(self, space):
- return space.wrap(self.find_dtype().itemtype.get_element_size())
+ __repr__ = interp2app(W_NDimArray.descr_repr),
+ __str__ = interp2app(W_NDimArray.descr_str),
- def descr_get_nbytes(self, space):
- return space.wrap(self.size)
+ __pos__ = interp2app(W_NDimArray.descr_pos),
+ __neg__ = interp2app(W_NDimArray.descr_neg),
+ __abs__ = interp2app(W_NDimArray.descr_abs),
+ __invert__ = interp2app(W_NDimArray.descr_invert),
+ __nonzero__ = interp2app(W_NDimArray.descr_nonzero),
- @jit.unroll_safe
- def descr_get_shape(self, space):
- return space.newtuple([space.wrap(i) for i in self.shape])
+ __add__ = interp2app(W_NDimArray.descr_add),
+ __sub__ = interp2app(W_NDimArray.descr_sub),
+ __mul__ = interp2app(W_NDimArray.descr_mul),
+ __div__ = interp2app(W_NDimArray.descr_div),
+ __truediv__ = interp2app(W_NDimArray.descr_truediv),
+ __floordiv__ = interp2app(W_NDimArray.descr_floordiv),
+ __mod__ = interp2app(W_NDimArray.descr_mod),
+ __divmod__ = interp2app(W_NDimArray.descr_divmod),
+ __pow__ = interp2app(W_NDimArray.descr_pow),
+ __lshift__ = interp2app(W_NDimArray.descr_lshift),
+ __rshift__ = interp2app(W_NDimArray.descr_rshift),
+ __and__ = interp2app(W_NDimArray.descr_and),
+ __or__ = interp2app(W_NDimArray.descr_or),
+ __xor__ = interp2app(W_NDimArray.descr_xor),
- def descr_set_shape(self, space, w_iterable):
- new_shape = get_shape_from_iterable(space,
- support.product(self.shape), w_iterable)
- if isinstance(self, Scalar):
- return
- self.get_concrete().setshape(space, new_shape)
+ __radd__ = interp2app(W_NDimArray.descr_radd),
+ __rsub__ = interp2app(W_NDimArray.descr_rsub),
+ __rmul__ = interp2app(W_NDimArray.descr_rmul),
+ __rdiv__ = interp2app(W_NDimArray.descr_rdiv),
+ __rtruediv__ = interp2app(W_NDimArray.descr_rtruediv),
+ __rfloordiv__ = interp2app(W_NDimArray.descr_rfloordiv),
+ __rmod__ = interp2app(W_NDimArray.descr_rmod),
+ __rdivmod__ = interp2app(W_NDimArray.descr_rdivmod),
+ __rpow__ = interp2app(W_NDimArray.descr_rpow),
+ __rlshift__ = interp2app(W_NDimArray.descr_rlshift),
+ __rrshift__ = interp2app(W_NDimArray.descr_rrshift),
+ __rand__ = interp2app(W_NDimArray.descr_rand),
+ __ror__ = interp2app(W_NDimArray.descr_ror),
+ __rxor__ = interp2app(W_NDimArray.descr_rxor),
- def descr_get_size(self, space):
- return space.wrap(self.get_size())
+ __eq__ = interp2app(W_NDimArray.descr_eq),
+ __ne__ = interp2app(W_NDimArray.descr_ne),
+ __lt__ = interp2app(W_NDimArray.descr_lt),
+ __le__ = interp2app(W_NDimArray.descr_le),
+ __gt__ = interp2app(W_NDimArray.descr_gt),
+ __ge__ = interp2app(W_NDimArray.descr_ge),
- def get_size(self):
- return self.size // self.find_dtype().get_size()
+ dtype = GetSetProperty(W_NDimArray.descr_get_dtype),
+ shape = GetSetProperty(W_NDimArray.descr_get_shape,
+ W_NDimArray.descr_set_shape),
+ ndim = GetSetProperty(W_NDimArray.descr_get_ndim),
+ size = GetSetProperty(W_NDimArray.descr_get_size),
+ itemsize = GetSetProperty(W_NDimArray.descr_get_itemsize),
+ nbytes = GetSetProperty(W_NDimArray.descr_get_nbytes),
- def descr_copy(self, space):
- return self.copy(space)
+ fill = interp2app(W_NDimArray.descr_fill),
+ tostring = interp2app(W_NDimArray.descr_tostring),
- def descr_flatten(self, space, w_order=None):
- if isinstance(self, Scalar):
- # scalars have no storage
- return self.descr_reshape(space, [space.wrap(1)])
- concr = self.get_concrete()
- w_res = concr.descr_ravel(space, w_order)
- if w_res.storage == concr.storage:
- return w_res.copy(space)
- return w_res
+ mean = interp2app(W_NDimArray.descr_mean),
+ sum = interp2app(W_NDimArray.descr_sum),
+ prod = interp2app(W_NDimArray.descr_prod),
+ max = interp2app(W_NDimArray.descr_max),
+ min = interp2app(W_NDimArray.descr_min),
+ argmax = interp2app(W_NDimArray.descr_argmax),
+ argmin = interp2app(W_NDimArray.descr_argmin),
+ all = interp2app(W_NDimArray.descr_all),
+ any = interp2app(W_NDimArray.descr_any),
+ dot = interp2app(W_NDimArray.descr_dot),
+ var = interp2app(W_NDimArray.descr_var),
+ std = interp2app(W_NDimArray.descr_std),
- def copy(self, space):
- return self.get_concrete().copy(space)
+ copy = interp2app(W_NDimArray.descr_copy),
+ reshape = interp2app(W_NDimArray.descr_reshape),
+ T = GetSetProperty(W_NDimArray.descr_get_transpose),
+ transpose = interp2app(W_NDimArray.descr_get_transpose),
+ tolist = interp2app(W_NDimArray.descr_tolist),
+ flatten = interp2app(W_NDimArray.descr_flatten),
+ ravel = interp2app(W_NDimArray.descr_ravel),
+ take = interp2app(W_NDimArray.descr_take),
+ compress = interp2app(W_NDimArray.descr_compress),
+ repeat = interp2app(W_NDimArray.descr_repeat),
+ swapaxes = interp2app(W_NDimArray.descr_swapaxes),
+ flat = GetSetProperty(W_NDimArray.descr_get_flatiter),
+ item = interp2app(W_NDimArray.descr_item),
- def empty_copy(self, space, dtype):
- shape = self.shape
- return W_NDimArray(shape[:], dtype, 'C')
+ __array_interface__ = GetSetProperty(W_NDimArray.descr_array_iface),
+)
- def descr_len(self, space):
- if len(self.shape):
- return space.wrap(self.shape[0])
- raise OperationError(space.w_TypeError, space.wrap(
- "len() of unsized object"))
-
- def descr_repr(self, space):
- cache = get_appbridge_cache(space)
- if cache.w_array_repr is None:
- return space.wrap(self.dump_data())
- return space.call_function(cache.w_array_repr, self)
-
- def dump_data(self):
- concr = self.get_concrete()
- i = concr.create_iter()
- first = True
- s = StringBuilder()
- s.append('array([')
- while not i.done():
- if first:
- first = False
- else:
- s.append(', ')
- s.append(concr.dtype.itemtype.str_format(concr.getitem(i.offset)))
- i = i.next(len(concr.shape))
- s.append('])')
- return s.build()
-
- def descr_str(self, space):
- cache = get_appbridge_cache(space)
- if cache.w_array_str is None:
- return space.wrap(self.dump_data())
- return space.call_function(cache.w_array_str, self)
-
- @jit.unroll_safe
- def _single_item_result(self, space, w_idx):
- """ The result of getitem/setitem is a single item if w_idx
- is a list of scalars that match the size of shape
- """
- if space.isinstance_w(w_idx, space.w_str):
- return False
- shape_len = len(self.shape)
- if space.isinstance_w(w_idx, space.w_tuple):
- for w_item in space.fixedview(w_idx):
- if (space.isinstance_w(w_item, space.w_slice) or
- space.is_w(w_item, space.w_None)):
- return False
- elif space.is_w(w_idx, space.w_None):
- return False
- if shape_len == 0:
- raise OperationError(space.w_IndexError, space.wrap(
- "0-d arrays can't be indexed"))
- if shape_len == 1:
- if space.isinstance_w(w_idx, space.w_int):
- return True
-
- try:
- value = space.int_w(space.index(w_idx))
- return True
- except OperationError:
- pass
-
- try:
- value = space.int_w(w_idx)
- return True
- except OperationError:
- pass
-
- if space.isinstance_w(w_idx, space.w_slice):
- return False
- elif (space.isinstance_w(w_idx, space.w_slice) or
- space.isinstance_w(w_idx, space.w_int)):
- return False
-
- try:
- lgt = space.len_w(w_idx)
- except OperationError:
- raise OperationError(space.w_IndexError,
- space.wrap("index must be either an int or a sequence."))
-
- if lgt > shape_len:
- raise OperationError(space.w_IndexError,
- space.wrap("invalid index"))
- return lgt == shape_len
-
- @jit.unroll_safe
- def _prepare_slice_args(self, space, w_idx):
- if space.isinstance_w(w_idx, space.w_str):
- idx = space.str_w(w_idx)
- dtype = self.find_dtype()
- if not dtype.is_record_type() or idx not in dtype.fields:
- raise OperationError(space.w_ValueError, space.wrap(
- "field named %s not defined" % idx))
- return RecordChunk(idx)
- if (space.isinstance_w(w_idx, space.w_int) or
- space.isinstance_w(w_idx, space.w_slice)):
- return Chunks([Chunk(*space.decode_index4(w_idx, self.shape[0]))])
- elif space.is_w(w_idx, space.w_None):
- return Chunks([NewAxisChunk()])
- result = []
- i = 0
- for w_item in space.fixedview(w_idx):
- if space.is_w(w_item, space.w_None):
- result.append(NewAxisChunk())
- else:
- result.append(Chunk(*space.decode_index4(w_item,
- self.shape[i])))
- i += 1
- return Chunks(result)
-
- def descr_count_nonzero(self, space):
- concr = self.get_concrete()
- res = concr.count_all_true()
- return space.wrap(res)
-
- def count_all_true(self):
- sig = self.find_sig()
- frame = sig.create_frame(self)
- shapelen = len(self.shape)
- s = 0
- iter = None
- while not frame.done():
- count_driver.jit_merge_point(arr=self, frame=frame, iter=iter, s=s,
- shapelen=shapelen)
- iter = frame.get_final_iter()
- s += self.dtype.getitem_bool(self, iter.offset)
- frame.next(shapelen)
- return s
-
- def getitem_filter(self, space, arr):
- concr = arr.get_concrete()
- if concr.get_size() > self.get_size():
- raise OperationError(space.w_IndexError,
- space.wrap("index out of range for array"))
- size = concr.count_all_true()
- res = W_NDimArray([size], self.find_dtype())
- ri = res.create_iter()
- shapelen = len(self.shape)
- argi = concr.create_iter()
- sig = self.find_sig()
- frame = sig.create_frame(self)
- v = None
- while not ri.done():
- filter_driver.jit_merge_point(concr=concr, argi=argi, ri=ri,
- frame=frame, v=v, res=res, sig=sig,
- shapelen=shapelen, self=self)
- if concr.dtype.getitem_bool(concr, argi.offset):
- v = sig.eval(frame, self)
- res.setitem(ri.offset, v)
- ri = ri.next(1)
- else:
- ri = ri.next_no_increase(1)
- argi = argi.next(shapelen)
- frame.next(shapelen)
- return res
-
- def descr_getitem(self, space, w_idx):
- if (isinstance(w_idx, BaseArray) and w_idx.shape == self.shape and
- w_idx.find_dtype().is_bool_type()):
- return self.getitem_filter(space, w_idx)
- if self._single_item_result(space, w_idx):
- concrete = self.get_concrete()
- item = concrete._index_of_single_item(space, w_idx)
- return concrete.getitem(item)
- chunks = self._prepare_slice_args(space, w_idx)
- return chunks.apply(self)
-
- def setitem_filter(self, space, idx, val):
- size = idx.count_all_true()
- arr = SliceArray([size], self.dtype, self, val)
- sig = arr.find_sig()
- shapelen = len(self.shape)
- frame = sig.create_frame(arr)
- idxi = idx.create_iter()
- while not frame.done():
- filter_set_driver.jit_merge_point(idx=idx, idxi=idxi, sig=sig,
- frame=frame, arr=arr,
- shapelen=shapelen)
- if idx.dtype.getitem_bool(idx, idxi.offset):
- sig.eval(frame, arr)
- frame.next_from_second(1)
- frame.next_first(shapelen)
- idxi = idxi.next(shapelen)
-
- def descr_setitem(self, space, w_idx, w_value):
- self.invalidated()
- if (isinstance(w_idx, BaseArray) and w_idx.shape == self.shape and
- w_idx.find_dtype().is_bool_type()):
- return self.get_concrete().setitem_filter(space,
- w_idx.get_concrete(),
- convert_to_array(space, w_value))
- if self._single_item_result(space, w_idx):
- concrete = self.get_concrete()
- item = concrete._index_of_single_item(space, w_idx)
- dtype = concrete.find_dtype()
- concrete.setitem(item, dtype.coerce(space, w_value))
- return
- if not isinstance(w_value, BaseArray):
- w_value = convert_to_array(space, w_value)
- chunks = self._prepare_slice_args(space, w_idx)
- view = chunks.apply(self).get_concrete()
- view.setslice(space, w_value)
-
- def descr_reshape(self, space, args_w):
- """reshape(...)
- a.reshape(shape)
-
- Returns an array containing the same data with a new shape.
-
- Refer to `numpypy.reshape` for full documentation.
-
- See Also
- --------
- numpypy.reshape : equivalent function
- """
- if len(args_w) == 1:
- w_shape = args_w[0]
- else:
- w_shape = space.newtuple(args_w)
- new_shape = get_shape_from_iterable(space, support.product(self.shape),
- w_shape)
- return self.reshape(space, new_shape)
-
- def reshape(self, space, new_shape):
- concrete = self.get_concrete()
- # Since we got to here, prod(new_shape) == self.size
- new_strides = None
- if self.size > 0:
- new_strides = calc_new_strides(new_shape, concrete.shape,
- concrete.strides, concrete.order)
- if new_strides:
- # We can create a view, strides somehow match up.
- ndims = len(new_shape)
- new_backstrides = [0] * ndims
- for nd in range(ndims):
- new_backstrides[nd] = (new_shape[nd] - 1) * new_strides[nd]
- arr = W_NDimSlice(concrete.start, new_strides, new_backstrides,
- new_shape, concrete)
- else:
- # Create copy with contiguous data
- arr = concrete.copy(space)
- arr.setshape(space, new_shape)
- return arr
-
- @unwrap_spec(axis1=int, axis2=int)
- def descr_swapaxes(self, space, axis1, axis2):
- """a.swapaxes(axis1, axis2)
-
- Return a view of the array with `axis1` and `axis2` interchanged.
-
- Refer to `numpy.swapaxes` for full documentation.
-
- See Also
- --------
- numpy.swapaxes : equivalent function
- """
- concrete = self.get_concrete()
- shape = concrete.shape[:]
- strides = concrete.strides[:]
- backstrides = concrete.backstrides[:]
- shape[axis1], shape[axis2] = shape[axis2], shape[axis1]
- strides[axis1], strides[axis2] = strides[axis2], strides[axis1]
- backstrides[axis1], backstrides[axis2] = backstrides[axis2], backstrides[axis1]
- arr = W_NDimSlice(concrete.start, strides,
- backstrides, shape, concrete)
- return space.wrap(arr)
-
- def descr_tolist(self, space):
- if len(self.shape) == 0:
- assert isinstance(self, Scalar)
- return self.value.item(space)
- w_result = space.newlist([])
- for i in range(self.shape[0]):
- space.call_method(w_result, "append",
- space.call_method(self.descr_getitem(space, space.wrap(i)), "tolist")
- )
- return w_result
-
- def descr_mean(self, space, w_axis=None, w_out=None):
- if space.is_w(w_axis, space.w_None):
- w_denom = space.wrap(support.product(self.shape))
- else:
- axis = unwrap_axis_arg(space, len(self.shape), w_axis)
- w_denom = space.wrap(self.shape[axis])
- return space.div(self.descr_sum_promote(space, w_axis, w_out), w_denom)
-
- def descr_var(self, space, w_axis=None):
- return get_appbridge_cache(space).call_method(space, '_var', self,
- w_axis)
-
- def descr_std(self, space, w_axis=None):
- return get_appbridge_cache(space).call_method(space, '_std', self,
- w_axis)
-
- def descr_fill(self, space, w_value):
- concr = self.get_concrete_or_scalar()
- concr.fill(space, w_value)
-
- def descr_nonzero(self, space):
- if self.get_size() > 1:
- raise OperationError(space.w_ValueError, space.wrap(
- "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()"))
- concr = self.get_concrete_or_scalar()
- sig = concr.find_sig()
- frame = sig.create_frame(self)
- return space.wrap(space.is_true(
- sig.eval(frame, concr)))
-
- def get_concrete_or_scalar(self):
- return self.get_concrete()
-
- def descr_get_transpose(self, space):
- concrete = self.get_concrete()
- if len(concrete.shape) < 2:
- return space.wrap(self)
- strides = []
- backstrides = []
- shape = []
- for i in range(len(concrete.shape) - 1, -1, -1):
- strides.append(concrete.strides[i])
- backstrides.append(concrete.backstrides[i])
- shape.append(concrete.shape[i])
- return space.wrap(W_NDimSlice(concrete.start, strides,
- backstrides, shape, concrete))
-
- def descr_ravel(self, space, w_order=None):
- if w_order is None or space.is_w(w_order, space.w_None):
- order = 'C'
- else:
- order = space.str_w(w_order)
- if order != 'C':
- raise OperationError(space.w_NotImplementedError, space.wrap(
- "order not implemented"))
- return self.descr_reshape(space, [space.wrap(-1)])
-
- def descr_get_flatiter(self, space):
- return space.wrap(W_FlatIterator(self))
-
- def getitem(self, item):
- raise NotImplementedError
-
- def find_sig(self, res_shape=None, arr=None):
- """ find a correct signature for the array
- """
- res_shape = res_shape or self.shape
- arr = arr or self
- return signature.find_sig(self.create_sig(), arr)
-
- def descr_array_iface(self, space):
- if not self.shape:
- raise OperationError(space.w_TypeError,
- space.wrap("can't get the array data of a 0-d array for now")
- )
- concrete = self.get_concrete()
- storage = concrete.storage
- addr = rffi.cast(lltype.Signed, storage)
- w_d = space.newdict()
- space.setitem_str(w_d, 'data', space.newtuple([space.wrap(addr),
- space.w_False]))
- return w_d
-
- def supports_fast_slicing(self):
- return False
-
- def descr_compress(self, space, w_obj, w_axis=None):
- index = convert_to_array(space, w_obj)
- return self.getitem_filter(space, index)
-
- def descr_take(self, space, w_obj, w_axis=None):
- index = convert_to_array(space, w_obj).get_concrete()
- concr = self.get_concrete()
- if space.is_w(w_axis, space.w_None):
- concr = concr.descr_ravel(space)
- else:
- raise OperationError(space.w_NotImplementedError,
- space.wrap("axis unsupported for take"))
- index_i = index.create_iter()
- res_shape = index.shape
- res = W_NDimArray(res_shape[:], concr.dtype, concr.order)
- res_i = res.create_iter()
- shapelen = len(index.shape)
- sig = concr.find_sig()
- while not index_i.done():
- take_driver.jit_merge_point(index_i=index_i, index=index,
- res_i=res_i, concr=concr,
- res=res,
- shapelen=shapelen, sig=sig)
- w_item = index._getitem_long(space, index_i.offset)
- res.setitem(res_i.offset, concr.descr_getitem(space, w_item))
- index_i = index_i.next(shapelen)
- res_i = res_i.next(shapelen)
- return res
-
- def _getitem_long(self, space, offset):
- # an obscure hack to not have longdtype inside a jitted loop
- longdtype = interp_dtype.get_dtype_cache(space).w_longdtype
- return self.getitem(offset).convert_to(longdtype).item(
- space)
-
- @jit.unroll_safe
- def descr_item(self, space, w_arg=None):
- if space.is_w(w_arg, space.w_None):
- if isinstance(self, Scalar):
- return self.value.item(space)
- if support.product(self.shape) == 1:
- return self.descr_getitem(space,
- space.newtuple([space.wrap(0) for i
- in range(len(self.shape))]))
- raise OperationError(space.w_ValueError,
- space.wrap("index out of bounds"))
- if space.isinstance_w(w_arg, space.w_int):
- if isinstance(self, Scalar):
- raise OperationError(space.w_ValueError, space.wrap("index out of bounds"))
- concr = self.get_concrete()
- i = to_coords(space, self.shape, concr.size, concr.order, w_arg)[0]
- # XXX a bit around
- item = self.descr_getitem(space, space.newtuple([space.wrap(x)
- for x in i]))
- assert isinstance(item, interp_boxes.W_GenericBox)
- return item.item(space)
- raise OperationError(space.w_NotImplementedError, space.wrap(
- "non-int arg not supported"))
-
- def descr_tostring(self, space):
- ra = ToStringArray(self)
- loop.compute(ra)
- return space.wrap(ra.s.build())
-
- def compute_first_step(self, sig, frame):
- pass
-
- @unwrap_spec(repeats=int)
- def descr_repeat(self, space, repeats, w_axis=None):
- return repeat(space, self, repeats, w_axis)
-
-def convert_to_array(space, w_obj):
- if isinstance(w_obj, BaseArray):
- return w_obj
- elif space.issequence_w(w_obj):
- # Convert to array.
- return array(space, w_obj, w_order=None)
- else:
- # If it's a scalar
- dtype = interp_ufuncs.find_dtype_for_scalar(space, w_obj)
- return scalar_w(space, dtype, w_obj)
-
-def scalar_w(space, dtype, w_obj):
- return Scalar(dtype, dtype.coerce(space, w_obj))
-
-class Scalar(BaseArray):
- """
- Intermediate class representing a literal.
- """
- _attrs_ = ["dtype", "value", "shape", "size"]
-
- def __init__(self, dtype, value):
- self.shape = []
- BaseArray.__init__(self, [])
- self.dtype = dtype
- assert isinstance(value, interp_boxes.W_GenericBox)
- self.value = value
- self.size = dtype.get_size()
-
- def find_dtype(self):
- return self.dtype
-
- def copy(self, space):
- return Scalar(self.dtype, self.value)
-
- def fill(self, space, w_value):
- self.value = self.dtype.coerce(space, w_value)
-
- def create_sig(self):
- return signature.ScalarSignature(self.dtype)
-
- def get_concrete_or_scalar(self):
- return self
-
- def reshape(self, space, new_shape):
- res = W_NDimArray(new_shape, self.dtype, 'C')
- res.setitem(0, self.value)
- return res
-
-class VirtualArray(BaseArray):
- """
- Class for representing virtual arrays, such as binary ops or ufuncs
- """
- def __init__(self, name, shape, res_dtype, out_arg=None):
- BaseArray.__init__(self, shape)
- self.forced_result = None
- self.res_dtype = res_dtype
- self.name = name
- self.res = out_arg
- self.size = support.product(self.shape) * res_dtype.get_size()
-
- def _del_sources(self):
- # Function for deleting references to source arrays,
- # to allow garbage-collecting them
- raise NotImplementedError
-
- def compute(self):
- ra = ResultArray(self, self.shape, self.res_dtype, self.res)
- loop.compute(ra)
- if self.res:
- broadcast_dims = len(self.res.shape) - len(self.shape)
- chunks = [Chunk(0,0,0,0)] * broadcast_dims + \
- [Chunk(0, i, 1, i) for i in self.shape]
- return Chunks(chunks).apply(self.res)
- return ra.left
-
- def force_if_needed(self):
- if self.forced_result is None:
- self.forced_result = self.compute().get_concrete()
- self._del_sources()
-
- def get_concrete(self):
- self.force_if_needed()
- res = self.forced_result
- assert isinstance(res, ConcreteArray)
- return res
-
- def getitem(self, item):
- return self.get_concrete().getitem(item)
-
- def setitem(self, item, value):
- return self.get_concrete().setitem(item, value)
-
- def find_dtype(self):
- return self.res_dtype
-
-class VirtualSlice(VirtualArray):
- def __init__(self, child, chunks, shape):
- self.child = child
- self.chunks = chunks
- VirtualArray.__init__(self, 'slice', shape, child.find_dtype())
-
- def create_sig(self):
- if self.forced_result is not None:
- return self.forced_result.create_sig()
- return signature.VirtualSliceSignature(
- self.child.create_sig())
-
- def force_if_needed(self):
- if self.forced_result is None:
- concr = self.child.get_concrete()
- self.forced_result = self.chunks.apply(concr)
-
- def _del_sources(self):
- self.child = None
-
-
-class Call1(VirtualArray):
- def __init__(self, ufunc, name, shape, calc_dtype, res_dtype, values,
- out_arg=None):
- VirtualArray.__init__(self, name, shape, res_dtype, out_arg)
- self.values = values
- self.ufunc = ufunc
- self.calc_dtype = calc_dtype
-
- def _del_sources(self):
- self.values = None
-
- def create_sig(self):
- if self.forced_result is not None:
- return self.forced_result.create_sig()
- if self.shape != self.values.shape:
- #This happens if out arg is used
- return signature.BroadcastUfunc(self.ufunc, self.name,
- self.calc_dtype,
- self.values.create_sig(),
- self.res.create_sig())
- return signature.Call1(self.ufunc, self.name, self.calc_dtype,
- self.values.create_sig())
-
-class Call2(VirtualArray):
- """
- Intermediate class for performing binary operations.
- """
- def __init__(self, ufunc, name, shape, calc_dtype, res_dtype, left, right,
- out_arg=None):
- VirtualArray.__init__(self, name, shape, res_dtype, out_arg)
- self.ufunc = ufunc
- self.left = left
- self.right = right
- self.calc_dtype = calc_dtype
-
- def _del_sources(self):
- self.left = None
- self.right = None
-
- def create_sig(self):
- if self.forced_result is not None:
- return self.forced_result.create_sig()
- if self.shape != self.left.shape and self.shape != self.right.shape:
- return signature.BroadcastBoth(self.ufunc, self.name,
- self.calc_dtype,
- self.left.create_sig(),
- self.right.create_sig())
- elif self.shape != self.left.shape:
- return signature.BroadcastLeft(self.ufunc, self.name,
- self.calc_dtype,
- self.left.create_sig(),
- self.right.create_sig())
- elif self.shape != self.right.shape:
- return signature.BroadcastRight(self.ufunc, self.name,
- self.calc_dtype,
- self.left.create_sig(),
- self.right.create_sig())
- return signature.Call2(self.ufunc, self.name, self.calc_dtype,
- self.left.create_sig(), self.right.create_sig())
-
-class ResultArray(Call2):
- def __init__(self, child, shape, dtype, res=None, order='C'):
- if res is None:
- res = W_NDimArray(shape, dtype, order)
- Call2.__init__(self, None, 'assign', shape, dtype, dtype, res, child)
-
- def create_sig(self):
- if self.left.shape != self.right.shape:
- sig = signature.BroadcastResultSignature(self.res_dtype,
- self.left.create_sig(), self.right.create_sig())
- else:
- sig = signature.ResultSignature(self.res_dtype,
- self.left.create_sig(), self.right.create_sig())
- return sig
-
-class ToStringArray(Call1):
- def __init__(self, child):
- dtype = child.find_dtype()
- self.item_size = dtype.itemtype.get_element_size()
- self.s = StringBuilder(child.size * self.item_size)
- Call1.__init__(self, None, 'tostring', child.shape, dtype, dtype,
- child)
- self.res_str = W_NDimArray([1], dtype, order='C')
- self.res_str_casted = rffi.cast(rffi.CArrayPtr(lltype.Char),
- self.res_str.storage)
-
- def create_sig(self):
- return signature.ToStringSignature(self.calc_dtype,
- self.values.create_sig())
-
-def done_if_true(dtype, val):
- return dtype.itemtype.bool(val)
-
-def done_if_false(dtype, val):
- return not dtype.itemtype.bool(val)
-
-class ReduceArray(Call2):
- def __init__(self, func, name, identity, child, dtype):
- self.identity = identity
- Call2.__init__(self, func, name, [1], dtype, dtype, None, child)
-
- def compute_first_step(self, sig, frame):
- assert isinstance(sig, signature.ReduceSignature)
- if self.identity is None:
- frame.cur_value = sig.right.eval(frame, self.right).convert_to(
- self.calc_dtype)
- frame.next(len(self.right.shape))
- else:
- frame.cur_value = self.identity.convert_to(self.calc_dtype)
-
- def create_sig(self):
- if self.name == 'logical_and':
- done_func = done_if_false
- elif self.name == 'logical_or':
- done_func = done_if_true
- else:
- done_func = None
- return signature.ReduceSignature(self.ufunc, self.name, self.res_dtype,
- signature.ScalarSignature(self.res_dtype),
- self.right.create_sig(), done_func)
-
-class AxisReduce(Call2):
- def __init__(self, ufunc, name, identity, shape, dtype, left, right, dim):
- Call2.__init__(self, ufunc, name, shape, dtype, dtype,
- left, right)
- self.dim = dim
- self.identity = identity
-
- def compute_first_step(self, sig, frame):
- if self.identity is not None:
- frame.identity = self.identity.convert_to(self.calc_dtype)
-
- def create_sig(self):
- return signature.AxisReduceSignature(self.ufunc, self.name,
- self.res_dtype,
- signature.ScalarSignature(self.res_dtype),
- self.right.create_sig())
-
-class SliceArray(Call2):
- def __init__(self, shape, dtype, left, right, no_broadcast=False):
- self.no_broadcast = no_broadcast
- Call2.__init__(self, None, 'sliceloop', shape, dtype, dtype, left,
- right)
-
- def create_sig(self):
- lsig = self.left.create_sig()
- rsig = self.right.create_sig()
- if not self.no_broadcast and self.shape != self.right.shape:
- return signature.SliceloopBroadcastSignature(self.ufunc,
- self.name,
- self.calc_dtype,
- lsig, rsig)
- return signature.SliceloopSignature(self.ufunc, self.name,
- self.calc_dtype,
- lsig, rsig)
-
-class ConcreteArray(BaseArray):
- """ An array that have actual storage, whether owned or not
- """
- _immutable_fields_ = ['storage']
-
- def __init__(self, shape, dtype, order='C', parent=None):
- self.parent = parent
- self.size = support.product(shape) * dtype.get_size()
- if parent is not None:
- self.storage = parent.storage
- else:
- self.storage = dtype.itemtype.malloc(self.size)
- self.order = order
- self.dtype = dtype
- if self.strides is None:
- self.calc_strides(shape)
- BaseArray.__init__(self, shape)
- if parent is not None:
- self.invalidates = parent.invalidates
-
- def get_concrete(self):
- return self
-
- def supports_fast_slicing(self):
- return self.order == 'C' and self.strides[-1] == 1
-
- def find_dtype(self):
- return self.dtype
-
- def getitem(self, item):
- return self.dtype.getitem(self, item)
-
- def setitem(self, item, value):
- self.invalidated()
- self.dtype.setitem(self, item, value.convert_to(self.dtype))
-
- def calc_strides(self, shape):
- dtype = self.find_dtype()
- strides = []
- backstrides = []
- s = 1
- shape_rev = shape[:]
- if self.order == 'C':
- shape_rev.reverse()
- for sh in shape_rev:
- strides.append(s * dtype.get_size())
- backstrides.append(s * (sh - 1) * dtype.get_size())
- s *= sh
- if self.order == 'C':
- strides.reverse()
- backstrides.reverse()
- self.strides = strides
- self.backstrides = backstrides
-
- @jit.unroll_safe
- def _index_of_single_item(self, space, w_idx):
- is_valid = False
- try:
- idx = space.int_w(space.index(w_idx))
- is_valid = True
- except OperationError:
- pass
-
- if not is_valid:
- try:
- idx = space.int_w(w_idx)
- is_valid = True
- except OperationError:
- pass
-
- if is_valid:
- if idx < 0:
- idx = self.shape[0] + idx
- if idx < 0 or idx >= self.shape[0]:
- raise OperationError(space.w_IndexError,
- space.wrap("index out of range"))
- return self.start + idx * self.strides[0]
- index = [space.int_w(w_item)
- for w_item in space.fixedview(w_idx)]
- item = self.start
- for i in range(len(index)):
- v = index[i]
- if v < 0:
- v += self.shape[i]
- if v < 0 or v >= self.shape[i]:
- raise operationerrfmt(space.w_IndexError,
- "index (%d) out of range (0<=index<%d", i, self.shape[i],
- )
- item += v * self.strides[i]
- return item
-
- def setslice(self, space, w_value):
- res_shape = shape_agreement(space, self.shape, w_value.shape)
- if (res_shape == w_value.shape and self.supports_fast_slicing() and
- w_value.supports_fast_slicing() and
- self.dtype is w_value.find_dtype()):
- self._fast_setslice(space, w_value)
- else:
- arr = SliceArray(self.shape, self.dtype, self, w_value)
- loop.compute(arr)
-
- def _fast_setslice(self, space, w_value):
- assert isinstance(w_value, ConcreteArray)
- itemsize = self.dtype.itemtype.get_element_size()
- shapelen = len(self.shape)
- if shapelen == 1:
- rffi.c_memcpy(
- rffi.ptradd(self.storage, self.start),
- rffi.ptradd(w_value.storage, w_value.start),
- self.size
- )
- else:
- dest = SkipLastAxisIterator(self)
- source = SkipLastAxisIterator(w_value)
- while not dest.done:
- rffi.c_memcpy(
- rffi.ptradd(self.storage, dest.offset * itemsize),
- rffi.ptradd(w_value.storage, source.offset * itemsize),
- self.shape[-1] * itemsize
- )
- source.next()
- dest.next()
-
- def copy(self, space):
- array = W_NDimArray(self.shape[:], self.dtype, self.order)
- array.setslice(space, self)
- return array
-
- def fill(self, space, w_value):
- self.setslice(space, scalar_w(space, self.dtype, w_value))
-
-
-class ViewArray(ConcreteArray):
- def create_sig(self):
- return signature.ViewSignature(self.dtype)
-
-
-class W_NDimSlice(ViewArray):
- def __init__(self, start, strides, backstrides, shape, parent, dtype=None):
- assert isinstance(parent, ConcreteArray)
- if isinstance(parent, W_NDimSlice):
- parent = parent.parent
- self.strides = strides
- self.backstrides = backstrides
- if dtype is None:
- dtype = parent.dtype
- ViewArray.__init__(self, shape, dtype, parent.order, parent)
- self.start = start
-
- def create_iter(self, transforms=None):
- return ViewIterator(self.start, self.strides, self.backstrides,
- self.shape).apply_transformations(self, transforms)
-
- def setshape(self, space, new_shape):
- if len(self.shape) < 1:
- return
- elif len(self.shape) < 2 or self.size < 1:
- # TODO: this code could be refactored into calc_strides
- # but then calc_strides would have to accept a stepping factor
- strides = []
- backstrides = []
- dtype = self.find_dtype()
- s = self.strides[0] // dtype.get_size()
- if self.order == 'C':
- new_shape.reverse()
- for sh in new_shape:
- strides.append(s * dtype.get_size())
- backstrides.append(s * (sh - 1) * dtype.get_size())
- s *= max(1, sh)
- if self.order == 'C':
- strides.reverse()
- backstrides.reverse()
- new_shape.reverse()
- self.strides = strides
- self.backstrides = backstrides
- self.shape = new_shape
- return
- new_strides = calc_new_strides(new_shape, self.shape, self.strides,
- self.order)
- if new_strides is None:
- raise OperationError(space.w_AttributeError, space.wrap(
- "incompatible shape for a non-contiguous array"))
- 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 W_NDimArray(ConcreteArray):
- """ A class representing contiguous array. We know that each iteration
- by say ufunc will increase the data index by one
- """
- def setitem(self, item, value):
- self.invalidated()
- self.dtype.setitem(self, item, value)
-
- def setshape(self, space, new_shape):
- self.shape = new_shape
- self.calc_strides(new_shape)
-
- def create_iter(self, transforms=None):
- esize = self.find_dtype().get_size()
- return ArrayIterator(self.size, esize).apply_transformations(self,
- transforms)
-
- def create_sig(self):
- return signature.ArraySignature(self.dtype)
-
- def __del__(self):
- free_raw_storage(self.storage, track_allocation=False)
-
-def _find_shape(space, w_size):
- if space.isinstance_w(w_size, space.w_int):
- return [space.int_w(w_size)]
- shape = []
- for w_item in space.fixedview(w_size):
- shape.append(space.int_w(w_item))
- return shape
-
- at unwrap_spec(subok=bool, copy=bool, ownmaskna=bool)
-def array(space, w_item_or_iterable, w_dtype=None, w_order=None,
- subok=True, copy=True, w_maskna=None, ownmaskna=False,
- w_ndmin=None):
- # find scalar
- if w_maskna is None:
- w_maskna = space.w_None
- if (not subok or not space.is_w(w_maskna, space.w_None) or
- ownmaskna):
- raise OperationError(space.w_NotImplementedError, space.wrap("Unsupported args"))
- if not space.issequence_w(w_item_or_iterable):
+ at unwrap_spec(ndmin=int, copy=bool, subok=bool)
+def array(space, w_object, w_dtype=None, copy=True, w_order=None, subok=False,
+ ndmin=0):
+ if not space.issequence_w(w_object):
if w_dtype is None or space.is_w(w_dtype, space.w_None):
- w_dtype = interp_ufuncs.find_dtype_for_scalar(space,
- w_item_or_iterable)
+ w_dtype = interp_ufuncs.find_dtype_for_scalar(space, w_object)
dtype = space.interp_w(interp_dtype.W_Dtype,
- space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
- )
- return scalar_w(space, dtype, w_item_or_iterable)
- if space.is_w(w_order, space.w_None) or w_order is None:
+ space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype))
+ return W_NDimArray.new_scalar(space, dtype, w_object)
+ if w_order is None or space.is_w(w_order, space.w_None):
order = 'C'
else:
order = space.str_w(w_order)
if order != 'C': # or order != 'F':
raise operationerrfmt(space.w_ValueError, "Unknown order: %s",
order)
- if isinstance(w_item_or_iterable, BaseArray):
+ if isinstance(w_object, W_NDimArray):
if (not space.is_w(w_dtype, space.w_None) and
- w_item_or_iterable.find_dtype() is not w_dtype):
+ w_object.get_dtype() is not w_dtype):
raise OperationError(space.w_NotImplementedError, space.wrap(
- "copying over different dtypes unsupported"))
+ "copying over different dtypes unsupported"))
if copy:
- return w_item_or_iterable.copy(space)
- return w_item_or_iterable
- if w_dtype is None or space.is_w(w_dtype, space.w_None):
- dtype = None
- else:
- dtype = space.interp_w(interp_dtype.W_Dtype,
- space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype))
- shape, elems_w = find_shape_and_elems(space, w_item_or_iterable, dtype)
- # they come back in C order
+ return w_object.descr_copy(space)
+ return w_object
+ dtype = interp_dtype.decode_w_dtype(space, w_dtype)
+ shape, elems_w = find_shape_and_elems(space, w_object, dtype)
if dtype is None:
for w_elem in elems_w:
dtype = interp_ufuncs.find_dtype_for_scalar(space, w_elem,
@@ -1267,378 +589,54 @@
break
if dtype is None:
dtype = interp_dtype.get_dtype_cache(space).w_float64dtype
- shapelen = len(shape)
- if w_ndmin is not None and not space.is_w(w_ndmin, space.w_None):
- ndmin = space.int_w(w_ndmin)
- if ndmin > shapelen:
- shape = [1] * (ndmin - shapelen) + shape
- shapelen = ndmin
- arr = W_NDimArray(shape[:], dtype=dtype, order=order)
- arr_iter = arr.create_iter()
- # XXX we might want to have a jitdriver here
- for i in range(len(elems_w)):
- w_elem = elems_w[i]
- dtype.setitem(arr, arr_iter.offset,
- dtype.coerce(space, w_elem))
- arr_iter = arr_iter.next(shapelen)
+ if ndmin > len(shape):
+ shape = [1] * (ndmin - len(shape)) + shape
+ arr = W_NDimArray.from_shape(shape, dtype, order=order)
+ arr_iter = arr.create_iter(arr.get_shape())
+ for w_elem in elems_w:
+ arr_iter.setitem(dtype.coerce(space, w_elem))
+ arr_iter.next()
return arr
-def zeros(space, w_size, w_dtype=None):
+ at unwrap_spec(order=str)
+def zeros(space, w_shape, w_dtype=None, order='C'):
dtype = space.interp_w(interp_dtype.W_Dtype,
space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
)
- shape = _find_shape(space, w_size)
+ shape = _find_shape(space, w_shape)
if not shape:
- return scalar_w(space, dtype, space.wrap(0))
- return space.wrap(W_NDimArray(shape[:], dtype=dtype))
+ return W_NDimArray.new_scalar(space, dtype, space.wrap(0))
+ return space.wrap(W_NDimArray.from_shape(shape, dtype=dtype, order=order))
-def ones(space, w_size, w_dtype=None):
+ at unwrap_spec(order=str)
+def ones(space, w_shape, w_dtype=None, order='C'):
dtype = space.interp_w(interp_dtype.W_Dtype,
space.call_function(space.gettypefor(interp_dtype.W_Dtype), w_dtype)
)
-
- shape = _find_shape(space, w_size)
+ shape = _find_shape(space, w_shape)
if not shape:
- return scalar_w(space, dtype, space.wrap(1))
- arr = W_NDimArray(shape[:], dtype=dtype)
+ return W_NDimArray.new_scalar(space, dtype, space.wrap(0))
+ arr = W_NDimArray.from_shape(shape, dtype=dtype, order=order)
one = dtype.box(1)
- arr.dtype.fill(arr.storage, one, 0, arr.size)
+ arr.fill(one)
return space.wrap(arr)
- at unwrap_spec(arr=BaseArray, skipna=bool, keepdims=bool)
-def count_reduce_items(space, arr, w_axis=None, skipna=False, keepdims=True):
- if not keepdims:
- raise OperationError(space.w_NotImplementedError, space.wrap("unsupported"))
- if space.is_w(w_axis, space.w_None):
- return space.wrap(support.product(arr.shape))
- shapelen = len(arr.shape)
- if space.isinstance_w(w_axis, space.w_int):
- axis = space.int_w(w_axis)
- if axis < -shapelen or axis>= shapelen:
- raise operationerrfmt(space.w_ValueError,
- "axis entry %d is out of bounds [%d, %d)", axis,
- -shapelen, shapelen)
- return space.wrap(arr.shape[axis])
- # numpy as of June 2012 does not implement this
- s = 1
- elems = space.fixedview(w_axis)
- for w_elem in elems:
- axis = space.int_w(w_elem)
- if axis < -shapelen or axis>= shapelen:
- raise operationerrfmt(space.w_ValueError,
- "axis entry %d is out of bounds [%d, %d)", axis,
- -shapelen, shapelen)
- s *= arr.shape[axis]
- return space.wrap(s)
-
-def dot(space, w_obj, w_obj2):
- '''see numpypy.dot. Does not exist as an ndarray method in numpy.
- '''
- w_arr = convert_to_array(space, w_obj)
- if isinstance(w_arr, Scalar):
- return convert_to_array(space, w_obj2).descr_dot(space, w_arr)
- return w_arr.descr_dot(space, w_obj2)
-
- at unwrap_spec(repeats=int)
-def repeat(space, w_arr, repeats, w_axis=None):
- arr = convert_to_array(space, w_arr)
- if space.is_w(w_axis, space.w_None):
- arr = arr.descr_flatten(space).get_concrete()
- orig_size = arr.shape[0]
- shape = [arr.shape[0] * repeats]
- res = W_NDimArray(shape, arr.find_dtype())
- for i in range(repeats):
- Chunks([Chunk(i, shape[0] - repeats + i, repeats,
- orig_size)]).apply(res).setslice(space, arr)
- else:
- arr = arr.get_concrete()
- axis = space.int_w(w_axis)
- shape = arr.shape[:]
- chunks = [Chunk(0, i, 1, i) for i in shape]
- orig_size = shape[axis]
- shape[axis] *= repeats
- res = W_NDimArray(shape, arr.find_dtype())
- for i in range(repeats):
- chunks[axis] = Chunk(i, shape[axis] - repeats + i, repeats,
- orig_size)
- Chunks(chunks).apply(res).setslice(space, arr)
- return res
-
- at unwrap_spec(axis=int)
-def concatenate(space, w_args, axis=0):
- args_w = space.listview(w_args)
- if len(args_w) == 0:
- raise OperationError(space.w_ValueError, space.wrap("concatenation of zero-length sequences is impossible"))
- args_w = [convert_to_array(space, w_arg) for w_arg in args_w]
- dtype = args_w[0].find_dtype()
- shape = args_w[0].shape[:]
- if len(shape) <= axis:
- raise OperationError(space.w_ValueError,
- space.wrap("bad axis argument"))
- for arr in args_w[1:]:
- dtype = interp_ufuncs.find_binop_result_dtype(space, dtype,
- arr.find_dtype())
- if len(arr.shape) <= axis:
- raise OperationError(space.w_ValueError,
- space.wrap("bad axis argument"))
- for i, axis_size in enumerate(arr.shape):
- if len(arr.shape) != len(shape) or (i != axis and axis_size != shape[i]):
- raise OperationError(space.w_ValueError, space.wrap(
- "array dimensions must agree except for axis being concatenated"))
- elif i == axis:
- shape[i] += axis_size
- res = W_NDimArray(shape, dtype, 'C')
- chunks = [Chunk(0, i, 1, i) for i in shape]
- axis_start = 0
- for arr in args_w:
- chunks[axis] = Chunk(axis_start, axis_start + arr.shape[axis], 1,
- arr.shape[axis])
- Chunks(chunks).apply(res).setslice(space, arr)
- axis_start += arr.shape[axis]
- return res
-
-BaseArray.typedef = TypeDef(
- 'ndarray',
- __module__ = "numpypy",
- __new__ = interp2app(BaseArray.descr__new__.im_func),
-
- __len__ = interp2app(BaseArray.descr_len),
- __getitem__ = interp2app(BaseArray.descr_getitem),
- __setitem__ = interp2app(BaseArray.descr_setitem),
-
- __pos__ = interp2app(BaseArray.descr_pos),
- __neg__ = interp2app(BaseArray.descr_neg),
- __abs__ = interp2app(BaseArray.descr_abs),
- __invert__ = interp2app(BaseArray.descr_invert),
- __nonzero__ = interp2app(BaseArray.descr_nonzero),
-
- __add__ = interp2app(BaseArray.descr_add),
- __sub__ = interp2app(BaseArray.descr_sub),
- __mul__ = interp2app(BaseArray.descr_mul),
- __div__ = interp2app(BaseArray.descr_div),
- __truediv__ = interp2app(BaseArray.descr_truediv),
- __floordiv__ = interp2app(BaseArray.descr_floordiv),
- __mod__ = interp2app(BaseArray.descr_mod),
- __divmod__ = interp2app(BaseArray.descr_divmod),
- __pow__ = interp2app(BaseArray.descr_pow),
- __lshift__ = interp2app(BaseArray.descr_lshift),
- __rshift__ = interp2app(BaseArray.descr_rshift),
- __and__ = interp2app(BaseArray.descr_and),
- __or__ = interp2app(BaseArray.descr_or),
- __xor__ = interp2app(BaseArray.descr_xor),
-
- __radd__ = interp2app(BaseArray.descr_radd),
- __rsub__ = interp2app(BaseArray.descr_rsub),
- __rmul__ = interp2app(BaseArray.descr_rmul),
- __rdiv__ = interp2app(BaseArray.descr_rdiv),
- __rtruediv__ = interp2app(BaseArray.descr_rtruediv),
- __rfloordiv__ = interp2app(BaseArray.descr_rfloordiv),
- __rmod__ = interp2app(BaseArray.descr_rmod),
- __rdivmod__ = interp2app(BaseArray.descr_rdivmod),
- __rpow__ = interp2app(BaseArray.descr_rpow),
- __rlshift__ = interp2app(BaseArray.descr_rlshift),
- __rrshift__ = interp2app(BaseArray.descr_rrshift),
- __rand__ = interp2app(BaseArray.descr_rand),
- __ror__ = interp2app(BaseArray.descr_ror),
- __rxor__ = interp2app(BaseArray.descr_rxor),
-
- __eq__ = interp2app(BaseArray.descr_eq),
- __ne__ = interp2app(BaseArray.descr_ne),
- __lt__ = interp2app(BaseArray.descr_lt),
- __le__ = interp2app(BaseArray.descr_le),
- __gt__ = interp2app(BaseArray.descr_gt),
- __ge__ = interp2app(BaseArray.descr_ge),
-
- __repr__ = interp2app(BaseArray.descr_repr),
- __str__ = interp2app(BaseArray.descr_str),
- __array_interface__ = GetSetProperty(BaseArray.descr_array_iface),
-
- dtype = GetSetProperty(BaseArray.descr_get_dtype),
- shape = GetSetProperty(BaseArray.descr_get_shape,
- BaseArray.descr_set_shape),
- size = GetSetProperty(BaseArray.descr_get_size),
- ndim = GetSetProperty(BaseArray.descr_get_ndim),
- itemsize = GetSetProperty(BaseArray.descr_get_itemsize),
- nbytes = GetSetProperty(BaseArray.descr_get_nbytes),
-
- T = GetSetProperty(BaseArray.descr_get_transpose),
- transpose = interp2app(BaseArray.descr_get_transpose),
- flat = GetSetProperty(BaseArray.descr_get_flatiter),
- ravel = interp2app(BaseArray.descr_ravel),
- item = interp2app(BaseArray.descr_item),
-
- mean = interp2app(BaseArray.descr_mean),
- sum = interp2app(BaseArray.descr_sum),
- prod = interp2app(BaseArray.descr_prod),
- max = interp2app(BaseArray.descr_max),
- min = interp2app(BaseArray.descr_min),
- argmax = interp2app(BaseArray.descr_argmax),
- argmin = interp2app(BaseArray.descr_argmin),
- all = interp2app(BaseArray.descr_all),
- any = interp2app(BaseArray.descr_any),
- dot = interp2app(BaseArray.descr_dot),
- var = interp2app(BaseArray.descr_var),
- std = interp2app(BaseArray.descr_std),
-
- fill = interp2app(BaseArray.descr_fill),
- tostring = interp2app(BaseArray.descr_tostring),
-
- copy = interp2app(BaseArray.descr_copy),
- flatten = interp2app(BaseArray.descr_flatten),
- reshape = interp2app(BaseArray.descr_reshape),
- swapaxes = interp2app(BaseArray.descr_swapaxes),
- tolist = interp2app(BaseArray.descr_tolist),
- take = interp2app(BaseArray.descr_take),
- compress = interp2app(BaseArray.descr_compress),
- repeat = interp2app(BaseArray.descr_repeat),
- count_nonzero = interp2app(BaseArray.descr_count_nonzero),
-)
-
-
-class W_FlatIterator(ViewArray):
-
- @jit.unroll_safe
- def __init__(self, arr):
- arr = arr.get_concrete()
- self.strides = [arr.strides[-1]]
- self.backstrides = [arr.backstrides[-1]]
- self.shapelen = len(arr.shape)
- sig = arr.find_sig()
- self.iter = sig.create_frame(arr).get_final_iter()
- self.base = arr
- self.index = 0
- ViewArray.__init__(self, [arr.get_size()], arr.dtype, arr.order,
- arr)
-
- def descr_next(self, space):
- if self.iter.done():
- raise OperationError(space.w_StopIteration, space.w_None)
- result = self.base.getitem(self.iter.offset)
- self.iter = self.iter.next(self.shapelen)
- self.index += 1
- return result
-
- def descr_iter(self):
- return self
-
- def descr_len(self, space):
- return space.wrap(self.get_size())
-
- def descr_index(self, space):
- return space.wrap(self.index)
-
- def descr_coords(self, space):
- coords, step, lngth = to_coords(space, self.base.shape,
- self.base.size, self.base.order,
- space.wrap(self.index))
- return space.newtuple([space.wrap(c) for c in coords])
-
- @jit.unroll_safe
- def descr_getitem(self, space, w_idx):
- if not (space.isinstance_w(w_idx, space.w_int) or
- space.isinstance_w(w_idx, space.w_slice)):
- raise OperationError(space.w_IndexError,
- space.wrap('unsupported iterator index'))
- base = self.base
- start, stop, step, lngth = space.decode_index4(w_idx, base.get_size())
- # setslice would have been better, but flat[u:v] for arbitrary
- # shapes of array a cannot be represented as a[x1:x2, y1:y2]
- basei = ViewIterator(base.start, base.strides,
- base.backstrides, base.shape)
- shapelen = len(base.shape)
- basei = basei.next_skip_x(shapelen, start)
- if lngth <2:
- return base.getitem(basei.offset)
- res = W_NDimArray([lngth], base.dtype, base.order)
- ri = res.create_iter()
- while not ri.done():
- flat_get_driver.jit_merge_point(shapelen=shapelen,
- base=base,
- basei=basei,
- step=step,
- res=res,
- ri=ri)
- w_val = base.getitem(basei.offset)
- res.setitem(ri.offset, w_val)
- basei = basei.next_skip_x(shapelen, step)
- ri = ri.next(shapelen)
- return res
-
- def descr_setitem(self, space, w_idx, w_value):
- if not (space.isinstance_w(w_idx, space.w_int) or
- space.isinstance_w(w_idx, space.w_slice)):
- raise OperationError(space.w_IndexError,
- space.wrap('unsupported iterator index'))
- base = self.base
- start, stop, step, lngth = space.decode_index4(w_idx, base.get_size())
- arr = convert_to_array(space, w_value)
- ri = arr.create_iter()
- basei = ViewIterator(base.start, base.strides,
- base.backstrides, base.shape)
- shapelen = len(base.shape)
- basei = basei.next_skip_x(shapelen, start)
- while lngth > 0:
- flat_set_driver.jit_merge_point(shapelen=shapelen,
- basei=basei,
- base=base,
- step=step,
- arr=arr,
- lngth=lngth,
- ri=ri)
- v = arr.getitem(ri.offset).convert_to(base.dtype)
- base.setitem(basei.offset, v)
- # need to repeat input values until all assignments are done
- basei = basei.next_skip_x(shapelen, step)
- ri = ri.next(shapelen)
- # WTF is numpy thinking?
- ri.offset %= arr.size
- lngth -= 1
-
- def create_sig(self):
- return signature.FlatSignature(self.base.dtype)
-
- def create_iter(self, transforms=None):
- return ViewIterator(self.base.start, self.base.strides,
- self.base.backstrides,
- self.base.shape).apply_transformations(self.base,
- transforms)
-
- def descr_base(self, space):
- return space.wrap(self.base)
-
W_FlatIterator.typedef = TypeDef(
'flatiter',
__iter__ = interp2app(W_FlatIterator.descr_iter),
- __len__ = interp2app(W_FlatIterator.descr_len),
__getitem__ = interp2app(W_FlatIterator.descr_getitem),
__setitem__ = interp2app(W_FlatIterator.descr_setitem),
+ __len__ = interp2app(W_FlatIterator.descr_len),
- __eq__ = interp2app(BaseArray.descr_eq),
- __ne__ = interp2app(BaseArray.descr_ne),
- __lt__ = interp2app(BaseArray.descr_lt),
- __le__ = interp2app(BaseArray.descr_le),
- __gt__ = interp2app(BaseArray.descr_gt),
- __ge__ = interp2app(BaseArray.descr_ge),
+ __eq__ = interp2app(W_FlatIterator.descr_eq),
+ __ne__ = interp2app(W_FlatIterator.descr_ne),
+ __lt__ = interp2app(W_FlatIterator.descr_lt),
+ __le__ = interp2app(W_FlatIterator.descr_le),
+ __gt__ = interp2app(W_FlatIterator.descr_gt),
+ __ge__ = interp2app(W_FlatIterator.descr_ge),
+ next = interp2app(W_FlatIterator.descr_next),
base = GetSetProperty(W_FlatIterator.descr_base),
index = GetSetProperty(W_FlatIterator.descr_index),
coords = GetSetProperty(W_FlatIterator.descr_coords),
- next = interp2app(W_FlatIterator.descr_next),
-
)
-W_FlatIterator.acceptable_as_base_class = False
-
-def isna(space, w_obj):
- if isinstance(w_obj, BaseArray):
- arr = w_obj.empty_copy(space,
- interp_dtype.get_dtype_cache(space).w_booldtype)
- arr.fill(space, space.wrap(False))
- return arr
- return space.wrap(False)
-
-class NumArrayCache(object):
- def __init__(self, space):
- self.enable_invalidation = True
-
-def get_numarray_cache(space):
- return space.fromcache(NumArrayCache)
diff --git a/pypy/module/micronumpy/interp_support.py b/pypy/module/micronumpy/interp_support.py
--- a/pypy/module/micronumpy/interp_support.py
+++ b/pypy/module/micronumpy/interp_support.py
@@ -1,16 +1,14 @@
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.gateway import unwrap_spec
from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.module.micronumpy import interp_dtype
+from pypy.module.micronumpy import interp_dtype, loop
from pypy.objspace.std.strutil import strip_spaces
-from pypy.rlib import jit
from pypy.rlib.rarithmetic import maxint
+from pypy.module.micronumpy.base import W_NDimArray
FLOAT_SIZE = rffi.sizeof(lltype.Float)
def _fromstring_text(space, s, count, sep, length, dtype):
- from pypy.module.micronumpy.interp_numarray import W_NDimArray
-
sep_stripped = strip_spaces(sep)
skip_bad_vals = len(sep_stripped) == 0
@@ -52,17 +50,15 @@
raise OperationError(space.w_ValueError, space.wrap(
"string is smaller than requested size"))
- a = W_NDimArray([num_items], dtype=dtype)
+ a = W_NDimArray.from_shape([num_items], dtype=dtype)
ai = a.create_iter()
for val in items:
- a.dtype.setitem(a, ai.offset, val)
- ai = ai.next(1)
-
+ ai.setitem(val)
+ ai.next()
+
return space.wrap(a)
def _fromstring_bin(space, s, count, length, dtype):
- from pypy.module.micronumpy.interp_numarray import W_NDimArray
-
itemsize = dtype.itemtype.get_element_size()
assert itemsize >= 0
if count == -1:
@@ -75,25 +71,10 @@
raise OperationError(space.w_ValueError, space.wrap(
"string is smaller than requested size"))
- a = W_NDimArray([count], dtype=dtype)
- fromstring_loop(a, dtype, itemsize, s)
+ a = W_NDimArray.from_shape([count], dtype=dtype)
+ loop.fromstring_loop(a, dtype, itemsize, s)
return space.wrap(a)
-fromstring_driver = jit.JitDriver(greens=[], reds=['i', 'itemsize',
- 'dtype', 'ai', 's', 'a'])
-
-def fromstring_loop(a, dtype, itemsize, s):
- i = 0
- ai = a.create_iter()
- while not ai.done():
- fromstring_driver.jit_merge_point(a=a, dtype=dtype,
- itemsize=itemsize, s=s, i=i,
- ai=ai)
- val = dtype.itemtype.runpack_str(s[i*itemsize:i*itemsize + itemsize])
- a.dtype.setitem(a, ai.offset, val)
- ai = ai.next(1)
- i += 1
-
@unwrap_spec(s=str, count=int, sep=str)
def fromstring(space, s, w_dtype=None, count=-1, sep=''):
dtype = space.interp_w(interp_dtype.W_Dtype,
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
@@ -7,6 +7,14 @@
from pypy.rlib.rarithmetic import LONG_BIT
from pypy.tool.sourcetools import func_with_new_name
from pypy.module.micronumpy.interp_support import unwrap_axis_arg
+from pypy.module.micronumpy.strides import shape_agreement
+from pypy.module.micronumpy.base import convert_to_array, W_NDimArray
+
+def done_if_true(dtype, val):
+ return dtype.itemtype.bool(val)
+
+def done_if_false(dtype, val):
+ return not dtype.itemtype.bool(val)
class W_Ufunc(Wrappable):
_attrs_ = ["name", "promote_to_float", "promote_bools", "identity"]
@@ -30,7 +38,6 @@
return self.identity
def descr_call(self, space, __args__):
- from interp_numarray import BaseArray
args_w, kwds_w = __args__.unpack()
# it occurs to me that we don't support any datatypes that
# require casting, change it later when we do
@@ -58,8 +65,8 @@
if len(args_w) > self.argcount:
out = args_w[-1]
else:
- args_w = args_w[:] + [out]
- if out is not None and not isinstance(out, BaseArray):
+ args_w = args_w + [out]
+ if out is not None and not isinstance(out, W_NDimArray):
raise OperationError(space.w_TypeError, space.wrap(
'output must be an array'))
return self.call(space, args_w)
@@ -119,97 +126,88 @@
array([[ 1, 5],
[ 9, 13]])
"""
- from pypy.module.micronumpy.interp_numarray import BaseArray
+ from pypy.module.micronumpy.interp_numarray import W_NDimArray
if w_axis is None:
w_axis = space.wrap(0)
if space.is_w(w_out, space.w_None):
out = None
- elif not isinstance(w_out, BaseArray):
+ elif not isinstance(w_out, W_NDimArray):
raise OperationError(space.w_TypeError, space.wrap(
'output must be an array'))
else:
out = w_out
- return self.reduce(space, w_obj, False, False, w_axis, keepdims, out)
+ return self.reduce(space, w_obj, False, False, w_axis, keepdims, out,
+ w_dtype)
def reduce(self, space, w_obj, multidim, promote_to_largest, w_axis,
- keepdims=False, out=None):
- from pypy.module.micronumpy.interp_numarray import convert_to_array, \
- Scalar, ReduceArray, W_NDimArray
+ keepdims=False, out=None, dtype=None):
if self.argcount != 2:
raise OperationError(space.w_ValueError, space.wrap("reduce only "
"supported for binary functions"))
assert isinstance(self, W_Ufunc2)
obj = convert_to_array(space, w_obj)
- if isinstance(obj, Scalar):
- raise OperationError(space.w_TypeError, space.wrap("cannot reduce "
- "on a scalar"))
- axis = unwrap_axis_arg(space, len(obj.shape), w_axis)
+ obj_shape = obj.get_shape()
+ if obj.is_scalar():
+ return obj.get_scalar_value()
+ shapelen = len(obj_shape)
+ axis = unwrap_axis_arg(space, shapelen, w_axis)
assert axis>=0
- size = obj.size
- if self.comparison_func:
- dtype = interp_dtype.get_dtype_cache(space).w_booldtype
- else:
- dtype = find_unaryop_result_dtype(
- space, obj.find_dtype(),
- promote_to_float=self.promote_to_float,
- promote_to_largest=promote_to_largest,
- promote_bools=True
- )
- shapelen = len(obj.shape)
+ size = obj.get_size()
+ dtype = interp_dtype.decode_w_dtype(space, dtype)
+ if dtype is None:
+ if self.comparison_func:
+ dtype = interp_dtype.get_dtype_cache(space).w_booldtype
+ else:
+ dtype = find_unaryop_result_dtype(
+ space, obj.get_dtype(),
+ promote_to_float=self.promote_to_float,
+ promote_to_largest=promote_to_largest,
+ promote_bools=True
+ )
if self.identity is None and size == 0:
raise operationerrfmt(space.w_ValueError, "zero-size array to "
"%s.reduce without identity", self.name)
if shapelen > 1 and axis < shapelen:
if keepdims:
- shape = obj.shape[:axis] + [1] + obj.shape[axis + 1:]
+ shape = obj_shape[:axis] + [1] + obj_shape[axis + 1:]
else:
- shape = obj.shape[:axis] + obj.shape[axis + 1:]
+ shape = obj_shape[:axis] + obj_shape[axis + 1:]
if out:
- #Test for shape agreement
- if len(out.shape) > len(shape):
+ # Test for shape agreement
+ # XXX maybe we need to do broadcasting here, although I must
+ # say I don't understand the details for axis reduce
+ if len(out.get_shape()) > len(shape):
raise operationerrfmt(space.w_ValueError,
'output parameter for reduction operation %s' +
' has too many dimensions', self.name)
- elif len(out.shape) < len(shape):
+ elif len(out.get_shape()) < len(shape):
raise operationerrfmt(space.w_ValueError,
'output parameter for reduction operation %s' +
' does not have enough dimensions', self.name)
- elif out.shape != shape:
+ elif out.get_shape() != shape:
raise operationerrfmt(space.w_ValueError,
'output parameter shape mismatch, expecting [%s]' +
' , got [%s]',
",".join([str(x) for x in shape]),
- ",".join([str(x) for x in out.shape]),
+ ",".join([str(x) for x in out.get_shape()]),
)
- #Test for dtype agreement, perhaps create an itermediate
- #if out.dtype != dtype:
- # raise OperationError(space.w_TypeError, space.wrap(
- # "mismatched dtypes"))
- return self.do_axis_reduce(obj, out.find_dtype(), axis, out)
+ dtype = out.get_dtype()
else:
- result = W_NDimArray(shape, dtype)
- return self.do_axis_reduce(obj, dtype, axis, result)
+ out = W_NDimArray.from_shape(shape, dtype)
+ return loop.do_axis_reduce(shape, self.func, obj, dtype, axis, out,
+ self.identity)
if out:
- if len(out.shape)>0:
+ if len(out.get_shape())>0:
raise operationerrfmt(space.w_ValueError, "output parameter "
"for reduction operation %s has too many"
" dimensions",self.name)
- arr = ReduceArray(self.func, self.name, self.identity, obj,
- out.find_dtype())
- val = loop.compute(arr)
- assert isinstance(out, Scalar)
- out.value = val
- else:
- arr = ReduceArray(self.func, self.name, self.identity, obj, dtype)
- val = loop.compute(arr)
- return val
-
- def do_axis_reduce(self, obj, dtype, axis, result):
- from pypy.module.micronumpy.interp_numarray import AxisReduce
- arr = AxisReduce(self.func, self.name, self.identity, obj.shape, dtype,
- result, obj, axis)
- loop.compute(arr)
- return arr.left
+ dtype = out.get_dtype()
+ res = loop.compute_reduce(obj, dtype, self.func, self.done_func,
+ self.identity)
+ if out:
+ out.set_scalar_value(res)
+ return out
+ return res
class W_Ufunc1(W_Ufunc):
argcount = 1
@@ -225,57 +223,43 @@
self.bool_result = bool_result
def call(self, space, args_w):
- from pypy.module.micronumpy.interp_numarray import (Call1, BaseArray,
- convert_to_array, Scalar, shape_agreement)
- if len(args_w)<2:
- [w_obj] = args_w
- out = None
- else:
- [w_obj, out] = args_w
+ w_obj = args_w[0]
+ out = None
+ if len(args_w) > 1:
+ out = args_w[1]
if space.is_w(out, space.w_None):
out = None
w_obj = convert_to_array(space, w_obj)
calc_dtype = find_unaryop_result_dtype(space,
- w_obj.find_dtype(),
+ w_obj.get_dtype(),
promote_to_float=self.promote_to_float,
promote_bools=self.promote_bools)
- if out:
- if not isinstance(out, BaseArray):
+ if out is not None:
+ if not isinstance(out, W_NDimArray):
raise OperationError(space.w_TypeError, space.wrap(
'output must be an array'))
- res_dtype = out.find_dtype()
+ res_dtype = out.get_dtype()
+ #if not w_obj.get_dtype().can_cast_to(res_dtype):
+ # raise operationerrfmt(space.w_TypeError,
+ # "Cannot cast ufunc %s output from dtype('%s') to dtype('%s') with casting rule 'same_kind'", self.name, w_obj.get_dtype().name, res_dtype.name)
elif self.bool_result:
res_dtype = interp_dtype.get_dtype_cache(space).w_booldtype
else:
res_dtype = calc_dtype
- if isinstance(w_obj, Scalar):
- arr = self.func(calc_dtype, w_obj.value.convert_to(calc_dtype))
- if isinstance(out,Scalar):
- out.value = arr
- elif isinstance(out, BaseArray):
- out.fill(space, arr)
+ if w_obj.is_scalar():
+ w_val = self.func(calc_dtype,
+ w_obj.get_scalar_value().convert_to(calc_dtype))
+ if out is None:
+ return w_val
+ if out.is_scalar():
+ out.set_scalar_value(w_val)
else:
- out = arr
- return space.wrap(out)
- if out:
- assert isinstance(out, BaseArray) # For translation
- broadcast_shape = shape_agreement(space, w_obj.shape, out.shape)
- if not broadcast_shape or broadcast_shape != out.shape:
- raise operationerrfmt(space.w_ValueError,
- 'output parameter shape mismatch, could not broadcast [%s]' +
- ' to [%s]',
- ",".join([str(x) for x in w_obj.shape]),
- ",".join([str(x) for x in out.shape]),
- )
- w_res = Call1(self.func, self.name, out.shape, calc_dtype,
- res_dtype, w_obj, out)
- #Force it immediately
- w_res.get_concrete()
- else:
- w_res = Call1(self.func, self.name, w_obj.shape, calc_dtype,
- res_dtype, w_obj)
- w_obj.add_invalidates(space, w_res)
- return w_res
+ out.fill(res_dtype.coerce(space, w_val))
+ return out
+ shape = shape_agreement(space, w_obj.get_shape(), out,
+ broadcast_down=False)
+ return loop.call1(shape, self.func, self.name, calc_dtype, res_dtype,
+ w_obj, out)
class W_Ufunc2(W_Ufunc):
@@ -289,11 +273,15 @@
int_only)
self.func = func
self.comparison_func = comparison_func
+ if name == 'logical_and':
+ self.done_func = done_if_false
+ elif name == 'logical_or':
+ self.done_func = done_if_true
+ else:
+ self.done_func = None
@jit.unroll_safe
def call(self, space, args_w):
- from pypy.module.micronumpy.interp_numarray import (Call2,
- convert_to_array, Scalar, shape_agreement, BaseArray)
if len(args_w) > 2:
[w_lhs, w_rhs, w_out] = args_w
else:
@@ -304,50 +292,38 @@
if space.is_w(w_out, space.w_None) or w_out is None:
out = None
calc_dtype = find_binop_result_dtype(space,
- w_lhs.find_dtype(), w_rhs.find_dtype(),
+ w_lhs.get_dtype(), w_rhs.get_dtype(),
int_only=self.int_only,
promote_to_float=self.promote_to_float,
promote_bools=self.promote_bools,
)
- elif not isinstance(w_out, BaseArray):
+ elif not isinstance(w_out, W_NDimArray):
raise OperationError(space.w_TypeError, space.wrap(
'output must be an array'))
else:
out = w_out
- calc_dtype = out.find_dtype()
+ calc_dtype = out.get_dtype()
if self.comparison_func:
res_dtype = interp_dtype.get_dtype_cache(space).w_booldtype
else:
res_dtype = calc_dtype
- if isinstance(w_lhs, Scalar) and isinstance(w_rhs, Scalar):
+ if w_lhs.is_scalar() and w_rhs.is_scalar():
arr = self.func(calc_dtype,
- w_lhs.value.convert_to(calc_dtype),
- w_rhs.value.convert_to(calc_dtype)
+ w_lhs.get_scalar_value().convert_to(calc_dtype),
+ w_rhs.get_scalar_value().convert_to(calc_dtype)
)
- if isinstance(out,Scalar):
- out.value = arr
- elif isinstance(out, BaseArray):
- out.fill(space, arr)
+ if isinstance(out, W_NDimArray):
+ if out.is_scalar():
+ out.set_scalar_value(arr)
+ else:
+ out.fill(arr)
else:
out = arr
- return space.wrap(out)
- new_shape = shape_agreement(space, w_lhs.shape, w_rhs.shape)
- # Test correctness of out.shape
- if out and out.shape != shape_agreement(space, new_shape, out.shape):
- raise operationerrfmt(space.w_ValueError,
- 'output parameter shape mismatch, could not broadcast [%s]' +
- ' to [%s]',
- ",".join([str(x) for x in new_shape]),
- ",".join([str(x) for x in out.shape]),
- )
- w_res = Call2(self.func, self.name,
- new_shape, calc_dtype,
- res_dtype, w_lhs, w_rhs, out)
- w_lhs.add_invalidates(space, w_res)
- w_rhs.add_invalidates(space, w_res)
- if out:
- w_res.get_concrete()
- return w_res
+ return out
+ new_shape = shape_agreement(space, w_lhs.get_shape(), w_rhs)
+ new_shape = shape_agreement(space, new_shape, out, broadcast_down=False)
+ return loop.call2(new_shape, self.func, self.name, calc_dtype,
+ res_dtype, w_lhs, w_rhs, out)
W_Ufunc.typedef = TypeDef("ufunc",
diff --git a/pypy/module/micronumpy/iter.py b/pypy/module/micronumpy/iter.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/micronumpy/iter.py
@@ -0,0 +1,123 @@
+
+""" This is a mini-tutorial on iterators, strides, and
+memory layout. It assumes you are familiar with the terms, see
+http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html
+for a more gentle introduction.
+
+Given an array x: x.shape == [5,6],
+
+At which byte in x.data does the item x[3,4] begin?
+if x.strides==[1,5]:
+ pData = x.pData + (x.start + 3*1 + 4*5)*sizeof(x.pData[0])
+ pData = x.pData + (x.start + 24) * sizeof(x.pData[0])
+so the offset of the element is 24 elements after the first
+
+What is the next element in x after coordinates [3,4]?
+if x.order =='C':
+ next == [3,5] => offset is 28
+if x.order =='F':
+ next == [4,4] => offset is 24
+so for the strides [1,5] x is 'F' contiguous
+likewise, for the strides [6,1] x would be 'C' contiguous.
+
+Iterators have an internal representation of the current coordinates
+(indices), the array, strides, and backstrides. A short digression to
+explain backstrides: what is the coordinate and offset after [3,5] in
+the example above?
+if x.order == 'C':
+ next == [4,0] => offset is 4
+if x.order == 'F':
+ next == [4,5] => offset is 25
+Note that in 'C' order we stepped BACKWARDS 24 while 'overflowing' a
+shape dimension
+ which is back 25 and forward 1,
+ which is x.strides[1] * (x.shape[1] - 1) + x.strides[0]
+so if we precalculate the overflow backstride as
+[x.strides[i] * (x.shape[i] - 1) for i in range(len(x.shape))]
+we can go faster.
+All the calculations happen in next()
+
+next_skip_x() tries to do the iteration for a number of steps at once,
+but then we cannot gaurentee that we only overflow one single shape
+dimension, perhaps we could overflow times in one big step.
+"""
+
+from pypy.module.micronumpy.strides import enumerate_chunks,\
+ calculate_slice_strides
+from pypy.module.micronumpy.base import W_NDimArray
+from pypy.rlib import jit
+
+# structures to describe slicing
+
+class BaseChunk(object):
+ pass
+
+class RecordChunk(BaseChunk):
+ def __init__(self, name):
+ self.name = name
+
+ def apply(self, arr):
+ ofs, subdtype = arr.dtype.fields[self.name]
+ # strides backstrides are identical, ofs only changes start
+ return W_NDimArray.new_slice(arr.start + ofs, arr.strides,
+ arr.backstrides,
+ arr.shape, arr, subdtype)
+
+class Chunks(BaseChunk):
+ def __init__(self, l):
+ self.l = l
+
+ @jit.unroll_safe
+ def extend_shape(self, old_shape):
+ shape = []
+ i = -1
+ for i, c in enumerate_chunks(self.l):
+ if c.step != 0:
+ shape.append(c.lgt)
+ s = i + 1
+ assert s >= 0
+ return shape[:] + old_shape[s:]
+
+ def apply(self, arr):
+ shape = self.extend_shape(arr.shape)
+ r = calculate_slice_strides(arr.shape, arr.start, arr.strides,
+ arr.backstrides, self.l)
+ _, start, strides, backstrides = r
+ return W_NDimArray.new_slice(start, strides[:], backstrides[:],
+ shape[:], arr)
+
+
+class Chunk(BaseChunk):
+ axis_step = 1
+
+ def __init__(self, start, stop, step, lgt):
+ self.start = start
+ self.stop = stop
+ self.step = step
+ self.lgt = lgt
+
+ def __repr__(self):
+ return 'Chunk(%d, %d, %d, %d)' % (self.start, self.stop, self.step,
+ self.lgt)
+
+class NewAxisChunk(Chunk):
+ start = 0
+ stop = 1
+ step = 1
+ lgt = 1
+ axis_step = 0
+
+ def __init__(self):
+ pass
+
+class BaseTransform(object):
+ pass
+
+class ViewTransform(BaseTransform):
+ def __init__(self, chunks):
+ # 4-tuple specifying slicing
+ self.chunks = chunks
+
+class BroadcastTransform(BaseTransform):
+ def __init__(self, res_shape):
+ self.res_shape = res_shape
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
--- a/pypy/module/micronumpy/loop.py
+++ b/pypy/module/micronumpy/loop.py
@@ -3,81 +3,244 @@
signatures
"""
-from pypy.rlib.jit import JitDriver, hint, unroll_safe, promote
-from pypy.module.micronumpy.interp_iter import ConstantIterator
+from pypy.rlib.objectmodel import specialize
+from pypy.module.micronumpy.base import W_NDimArray
+from pypy.rlib.rstring import StringBuilder
+from pypy.rpython.lltypesystem import lltype, rffi
-class NumpyEvalFrame(object):
- _virtualizable2_ = ['iterators[*]', 'final_iter', 'arraylist[*]',
- 'value', 'identity', 'cur_value']
+def call2(shape, func, name, calc_dtype, res_dtype, w_lhs, w_rhs, out):
+ if out is None:
+ out = W_NDimArray.from_shape(shape, res_dtype)
+ left_iter = w_lhs.create_iter(shape)
+ right_iter = w_rhs.create_iter(shape)
+ out_iter = out.create_iter(shape)
+ while not out_iter.done():
+ w_left = left_iter.getitem().convert_to(calc_dtype)
+ w_right = right_iter.getitem().convert_to(calc_dtype)
+ out_iter.setitem(func(calc_dtype, w_left, w_right).convert_to(
+ res_dtype))
+ left_iter.next()
+ right_iter.next()
+ out_iter.next()
+ return out
- @unroll_safe
- def __init__(self, iterators, arrays):
- self = hint(self, access_directly=True, fresh_virtualizable=True)
- self.iterators = iterators[:]
- self.arrays = arrays[:]
- for i in range(len(self.iterators)):
- iter = self.iterators[i]
- if not isinstance(iter, ConstantIterator):
- self.final_iter = i
- break
+def call1(shape, func, name, calc_dtype, res_dtype, w_obj, out):
+ if out is None:
+ out = W_NDimArray.from_shape(shape, res_dtype)
+ obj_iter = w_obj.create_iter(shape)
+ out_iter = out.create_iter(shape)
+ while not out_iter.done():
+ elem = obj_iter.getitem().convert_to(calc_dtype)
+ out_iter.setitem(func(calc_dtype, elem).convert_to(res_dtype))
+ out_iter.next()
+ obj_iter.next()
+ return out
+
+def setslice(shape, target, source):
+ # note that unlike everything else, target and source here are
+ # array implementations, not arrays
+ target_iter = target.create_iter(shape)
+ source_iter = source.create_iter(shape)
+ dtype = target.dtype
+ while not target_iter.done():
+ target_iter.setitem(source_iter.getitem().convert_to(dtype))
+ target_iter.next()
+ source_iter.next()
+ return target
+
+def compute_reduce(obj, calc_dtype, func, done_func, identity):
+ obj_iter = obj.create_iter(obj.get_shape())
+ if identity is None:
+ cur_value = obj_iter.getitem().convert_to(calc_dtype)
+ obj_iter.next()
+ else:
+ cur_value = identity.convert_to(calc_dtype)
+ while not obj_iter.done():
+ rval = obj_iter.getitem().convert_to(calc_dtype)
+ if done_func is not None and done_func(calc_dtype, rval):
+ return rval
+ cur_value = func(calc_dtype, cur_value, rval)
+ obj_iter.next()
+ return cur_value
+
+def fill(arr, box):
+ arr_iter = arr.create_iter(arr.get_shape())
+ while not arr_iter.done():
+ arr_iter.setitem(box)
+ arr_iter.next()
+
+def where(out, shape, arr, x, y, dtype):
+ out_iter = out.create_iter(shape)
+ arr_iter = arr.create_iter(shape)
+ arr_dtype = arr.get_dtype()
+ x_iter = x.create_iter(shape)
+ y_iter = y.create_iter(shape)
+ if x.is_scalar():
+ if y.is_scalar():
+ iter = arr_iter
else:
- self.final_iter = -1
- self.cur_value = None
- self.identity = None
+ iter = y_iter
+ else:
+ iter = x_iter
+ while not iter.done():
+ w_cond = arr_iter.getitem()
+ if arr_dtype.itemtype.bool(w_cond):
+ w_val = x_iter.getitem().convert_to(dtype)
+ else:
+ w_val = y_iter.getitem().convert_to(dtype)
+ out_iter.setitem(w_val)
+ out_iter.next()
+ arr_iter.next()
+ x_iter.next()
+ y_iter.next()
+ return out
- def done(self):
- final_iter = promote(self.final_iter)
- if final_iter < 0:
- assert False
- return self.iterators[final_iter].done()
+def do_axis_reduce(shape, func, arr, dtype, axis, out, identity):
+ out_iter = out.create_axis_iter(arr.get_shape(), axis)
+ arr_iter = arr.create_iter(arr.get_shape())
+ if identity is not None:
+ identity = identity.convert_to(dtype)
+ while not out_iter.done():
+ w_val = arr_iter.getitem().convert_to(dtype)
+ if out_iter.first_line:
+ if identity is not None:
+ w_val = func(dtype, identity, w_val)
+ else:
+ cur = out_iter.getitem()
+ w_val = func(dtype, cur, w_val)
+ out_iter.setitem(w_val)
+ arr_iter.next()
+ out_iter.next()
+ return out
- @unroll_safe
- def next(self, shapelen):
- for i in range(len(self.iterators)):
- self.iterators[i] = self.iterators[i].next(shapelen)
+ at specialize.arg(0)
+def argmin_argmax(op_name, arr):
+ result = 0
+ idx = 1
+ dtype = arr.get_dtype()
+ iter = arr.create_iter(arr.get_shape())
+ cur_best = iter.getitem()
+ iter.next()
+ while not iter.done():
+ w_val = iter.getitem()
+ new_best = getattr(dtype.itemtype, op_name)(cur_best, w_val)
+ if dtype.itemtype.ne(new_best, cur_best):
+ result = idx
+ cur_best = new_best
+ iter.next()
+ idx += 1
+ return result
- @unroll_safe
- def next_from_second(self, shapelen):
- """ Don't increase the first iterator
- """
- for i in range(1, len(self.iterators)):
- self.iterators[i] = self.iterators[i].next(shapelen)
+def multidim_dot(space, left, right, result, dtype, right_critical_dim):
+ ''' assumes left, right are concrete arrays
+ given left.shape == [3, 5, 7],
+ right.shape == [2, 7, 4]
+ then
+ result.shape == [3, 5, 2, 4]
+ broadcast shape should be [3, 5, 2, 7, 4]
+ result should skip dims 3 which is len(result_shape) - 1
+ (note that if right is 1d, result should
+ skip len(result_shape))
+ left should skip 2, 4 which is a.ndims-1 + range(right.ndims)
+ except where it==(right.ndims-2)
+ right should skip 0, 1
+ '''
+ left_shape = left.get_shape()
+ right_shape = right.get_shape()
+ broadcast_shape = left_shape[:-1] + right_shape
+ left_skip = [len(left_shape) - 1 + i for i in range(len(right_shape))
+ if i != right_critical_dim]
+ right_skip = range(len(left_shape) - 1)
+ result_skip = [len(result.get_shape()) - (len(right_shape) > 1)]
+ outi = result.create_dot_iter(broadcast_shape, result_skip)
+ lefti = left.create_dot_iter(broadcast_shape, left_skip)
+ righti = right.create_dot_iter(broadcast_shape, right_skip)
+ while not outi.done():
+ lval = lefti.getitem().convert_to(dtype)
+ rval = righti.getitem().convert_to(dtype)
+ outval = outi.getitem().convert_to(dtype)
+ v = dtype.itemtype.mul(lval, rval)
+ value = dtype.itemtype.add(v, outval).convert_to(dtype)
+ outi.setitem(value)
+ outi.next()
+ righti.next()
+ lefti.next()
+ return result
- def next_first(self, shapelen):
- self.iterators[0] = self.iterators[0].next(shapelen)
+def count_all_true(arr):
+ s = 0
+ if arr.is_scalar():
+ return arr.get_dtype().itemtype.bool(arr.get_scalar_value())
+ iter = arr.create_iter()
+ while not iter.done():
+ s += iter.getitem_bool()
+ iter.next()
+ return s
- def get_final_iter(self):
- final_iter = promote(self.final_iter)
- if final_iter < 0:
- assert False
- return self.iterators[final_iter]
+def getitem_filter(res, arr, index):
+ res_iter = res.create_iter()
+ index_iter = index.create_iter()
+ arr_iter = arr.create_iter()
+ while not index_iter.done():
+ if index_iter.getitem_bool():
+ res_iter.setitem(arr_iter.getitem())
+ res_iter.next()
+ index_iter.next()
+ arr_iter.next()
+ return res
-def get_printable_location(shapelen, sig):
- return 'numpy ' + sig.debug_repr() + ' [%d dims]' % (shapelen,)
+def setitem_filter(arr, index, value):
+ arr_iter = arr.create_iter()
+ index_iter = index.create_iter()
+ value_iter = value.create_iter()
+ while not arr_iter.done():
+ if index_iter.getitem_bool():
+ arr_iter.setitem(value_iter.getitem())
+ value_iter.next()
+ arr_iter.next()
+ index_iter.next()
-numpy_driver = JitDriver(
- greens=['shapelen', 'sig'],
- virtualizables=['frame'],
- reds=['frame', 'arr'],
- get_printable_location=get_printable_location,
- name='numpy',
-)
+def flatiter_getitem(res, base_iter, step):
+ ri = res.create_iter()
+ while not ri.done():
+ ri.setitem(base_iter.getitem())
+ base_iter.next_skip_x(step)
+ ri.next()
+ return res
-class ComputationDone(Exception):
- def __init__(self, value):
- self.value = value
+def flatiter_setitem(arr, val, start, step, length):
+ dtype = arr.get_dtype()
+ arr_iter = arr.create_iter()
+ val_iter = val.create_iter()
+ arr_iter.next_skip_x(start)
+ while length > 0:
+ arr_iter.setitem(val_iter.getitem().convert_to(dtype))
+ # need to repeat i_nput values until all assignments are done
+ arr_iter.next_skip_x(step)
+ length -= 1
+ val_iter.next()
+ # WTF numpy?
+ val_iter.reset()
-def compute(arr):
- sig = arr.find_sig()
- shapelen = len(arr.shape)
- frame = sig.create_frame(arr)
- try:
- while not frame.done():
- numpy_driver.jit_merge_point(sig=sig,
- shapelen=shapelen,
- frame=frame, arr=arr)
- sig.eval(frame, arr)
- frame.next(shapelen)
- return frame.cur_value
- except ComputationDone, e:
- return e.value
+def fromstring_loop(a, dtype, itemsize, s):
+ i = 0
+ ai = a.create_iter()
+ while not ai.done():
+ val = dtype.itemtype.runpack_str(s[i*itemsize:i*itemsize + itemsize])
+ ai.setitem(val)
+ ai.next()
+ i += 1
+
+def tostring(space, arr):
+ builder = StringBuilder()
+ iter = arr.create_iter()
+ res_str = W_NDimArray.from_shape([1], arr.get_dtype(), order='C')
+ itemsize = arr.get_dtype().itemtype.get_element_size()
+ res_str_casted = rffi.cast(rffi.CArrayPtr(lltype.Char),
+ res_str.implementation.get_storage_as_int(space))
+ while not iter.done():
+ res_str.implementation.setitem(0, iter.getitem())
+ for i in range(itemsize):
+ builder.append(res_str_casted[i])
+ iter.next()
+ return builder.build()
diff --git a/pypy/module/micronumpy/signature.py b/pypy/module/micronumpy/signature.py
deleted file mode 100644
--- a/pypy/module/micronumpy/signature.py
+++ /dev/null
@@ -1,564 +0,0 @@
-from pypy.rlib.objectmodel import r_dict, compute_identity_hash, compute_hash
-from pypy.rlib.rarithmetic import intmask
-from pypy.module.micronumpy.interp_iter import ConstantIterator, AxisIterator,\
- ViewTransform, BroadcastTransform
-from pypy.tool.pairtype import extendabletype
-from pypy.module.micronumpy.loop import ComputationDone
-from pypy.rlib import jit
-
-""" Signature specifies both the numpy expression that has been constructed
-and the assembler to be compiled. This is a very important observation -
-Two expressions will be using the same assembler if and only if they are
-compiled to the same signature.
-
-This is also a very convinient tool for specializations. For example
-a + a and a + b (where a != b) will compile to different assembler because
-we specialize on the same array access.
-
-When evaluating, signatures will create iterators per signature node,
-potentially sharing some of them. Iterators depend also on the actual
-expression, they're not only dependant on the array itself. For example
-a + b where a is dim 2 and b is dim 1 would create a broadcasted iterator for
-the array b.
-
-Such iterator changes are called Transformations. An actual iterator would
-be a combination of array and various transformation, like view, broadcast,
-dimension swapping etc.
-
-See interp_iter for transformations
-"""
-
-def new_printable_location(driver_name):
- def get_printable_location(shapelen, sig):
- return 'numpy ' + sig.debug_repr() + ' [%d dims,%s]' % (shapelen, driver_name)
- return get_printable_location
-
-def sigeq(one, two):
- return one.eq(two)
-
-def sigeq_no_numbering(one, two):
- """ Cache for iterator numbering should not compare array numbers
- """
- return one.eq(two, compare_array_no=False)
-
-def sighash(sig):
- return sig.hash()
-
-known_sigs = r_dict(sigeq, sighash)
-
-def find_sig(sig, arr):
- sig.invent_array_numbering(arr)
- try:
- return known_sigs[sig]
- except KeyError:
- sig.invent_numbering()
- known_sigs[sig] = sig
- return sig
-
-def _add_ptr_to_cache(ptr, cache):
- i = 0
- for p in cache:
- if ptr == p:
- return i
- i += 1
- else:
- res = len(cache)
- cache.append(ptr)
- return res
-
-def new_cache():
- return r_dict(sigeq_no_numbering, sighash)
-
-class Signature(object):
- __metaclass_ = extendabletype
-
- _attrs_ = ['iter_no', 'array_no']
- _immutable_fields_ = ['iter_no', 'array_no']
-
- array_no = 0
- iter_no = 0
-
- def invent_numbering(self):
- cache = new_cache()
- allnumbers = []
- self._invent_numbering(cache, allnumbers)
-
- def invent_array_numbering(self, arr):
- cache = []
- self._invent_array_numbering(arr, cache)
-
- def _invent_numbering(self, cache, allnumbers):
- try:
- no = cache[self]
- except KeyError:
- no = len(allnumbers)
- cache[self] = no
- allnumbers.append(no)
- self.iter_no = no
-
- def create_frame(self, arr):
- from pypy.module.micronumpy.loop import NumpyEvalFrame
-
- iterlist = []
- arraylist = []
- self._create_iter(iterlist, arraylist, arr, [])
- f = NumpyEvalFrame(iterlist, arraylist)
- # hook for cur_value being used by reduce
- arr.compute_first_step(self, f)
- return f
-
- def debug_repr(self):
- # should be overridden, but in case it isn't, provide a default
- return str(self)
-
-class ConcreteSignature(Signature):
- _immutable_fields_ = ['dtype']
-
- def __init__(self, dtype):
- self.dtype = dtype
-
- def eq(self, other, compare_array_no=True):
- if type(self) is not type(other):
- return False
- assert isinstance(other, ConcreteSignature)
- if compare_array_no:
- if self.array_no != other.array_no:
- return False
- return self.dtype is other.dtype
-
- def hash(self):
- return compute_identity_hash(self.dtype)
-
-class ArraySignature(ConcreteSignature):
- def debug_repr(self):
- return 'Array'
-
- def _invent_array_numbering(self, arr, cache):
- from pypy.module.micronumpy.interp_numarray import ConcreteArray
- concr = arr.get_concrete()
- # this get_concrete never forces assembler. If we're here and array
- # is not of a concrete class it means that we have a _forced_result,
- # otherwise the signature would not match
- assert isinstance(concr, ConcreteArray)
- assert concr.dtype is self.dtype
- self.array_no = _add_ptr_to_cache(concr.storage, cache)
-
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import ConcreteArray
- concr = arr.get_concrete()
- assert isinstance(concr, ConcreteArray)
- if self.iter_no >= len(iterlist):
- iterlist.append(concr.create_iter(transforms))
- if self.array_no >= len(arraylist):
- arraylist.append(concr)
-
- def eval(self, frame, arr):
- iter = frame.iterators[self.iter_no]
- return self.dtype.getitem(frame.arrays[self.array_no], iter.offset)
-
-class ScalarSignature(ConcreteSignature):
- def debug_repr(self):
- return 'Scalar'
-
- def _invent_array_numbering(self, arr, cache):
- pass
-
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- if self.iter_no >= len(iterlist):
- iter = ConstantIterator()
- iterlist.append(iter)
-
- def eval(self, frame, arr):
- from pypy.module.micronumpy.interp_numarray import Scalar
- assert isinstance(arr, Scalar)
- return arr.value
-
-class ViewSignature(ArraySignature):
- def debug_repr(self):
- return 'Slice'
-
- def _invent_numbering(self, cache, allnumbers):
- # always invent a new number for view
- no = len(allnumbers)
- allnumbers.append(no)
- self.iter_no = no
-
-class FlatSignature(ViewSignature):
- def debug_repr(self):
- return 'Flat'
-
-class VirtualSliceSignature(Signature):
- def __init__(self, child):
- self.child = child
-
- def _invent_array_numbering(self, arr, cache):
- from pypy.module.micronumpy.interp_numarray import VirtualSlice
- assert isinstance(arr, VirtualSlice)
- self.child._invent_array_numbering(arr.child, cache)
-
- def _invent_numbering(self, cache, allnumbers):
- self.child._invent_numbering(new_cache(), allnumbers)
-
- def hash(self):
- return intmask(self.child.hash() ^ 1234)
-
- def eq(self, other, compare_array_no=True):
- if type(self) is not type(other):
- return False
- assert isinstance(other, VirtualSliceSignature)
- return self.child.eq(other.child, compare_array_no)
-
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import VirtualSlice
- assert isinstance(arr, VirtualSlice)
- transforms = [ViewTransform(arr.chunks)] + transforms
- self.child._create_iter(iterlist, arraylist, arr.child, transforms)
-
- def eval(self, frame, arr):
- from pypy.module.micronumpy.interp_numarray import VirtualSlice
- assert isinstance(arr, VirtualSlice)
- return self.child.eval(frame, arr.child)
-
- def debug_repr(self):
- return 'VirtualSlice(%s)' % self.child.debug_repr()
-
-class Call1(Signature):
- _immutable_fields_ = ['unfunc', 'name', 'child', 'res', 'dtype']
-
- def __init__(self, func, name, dtype, child, res=None):
- self.unfunc = func
- self.child = child
- self.name = name
- self.dtype = dtype
- self.res = res
-
- def hash(self):
- return compute_hash(self.name) ^ intmask(self.child.hash() << 1)
-
- def eq(self, other, compare_array_no=True):
- if type(self) is not type(other):
- return False
- assert isinstance(other, Call1)
- return (self.unfunc is other.unfunc and
- self.child.eq(other.child, compare_array_no))
-
- def debug_repr(self):
- return 'Call1(%s, %s)' % (self.name, self.child.debug_repr())
-
- def _invent_numbering(self, cache, allnumbers):
- self.child._invent_numbering(cache, allnumbers)
-
- def _invent_array_numbering(self, arr, cache):
- from pypy.module.micronumpy.interp_numarray import Call1
- assert isinstance(arr, Call1)
- self.child._invent_array_numbering(arr.values, cache)
-
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import Call1
- assert isinstance(arr, Call1)
- self.child._create_iter(iterlist, arraylist, arr.values, transforms)
-
- def eval(self, frame, arr):
- from pypy.module.micronumpy.interp_numarray import Call1
- assert isinstance(arr, Call1)
- v = self.child.eval(frame, arr.values).convert_to(arr.calc_dtype)
- return self.unfunc(arr.calc_dtype, v)
-
-
-class BroadcastUfunc(Call1):
- def _invent_numbering(self, cache, allnumbers):
- self.res._invent_numbering(cache, allnumbers)
- self.child._invent_numbering(new_cache(), allnumbers)
-
- def debug_repr(self):
- return 'BroadcastUfunc(%s, %s)' % (self.name, self.child.debug_repr())
-
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import Call1
-
- assert isinstance(arr, Call1)
- vtransforms = [BroadcastTransform(arr.values.shape)] + transforms
- self.child._create_iter(iterlist, arraylist, arr.values, vtransforms)
- self.res._create_iter(iterlist, arraylist, arr.res, transforms)
-
- def eval(self, frame, arr):
- from pypy.module.micronumpy.interp_numarray import Call1
- assert isinstance(arr, Call1)
- v = self.child.eval(frame, arr.values).convert_to(arr.calc_dtype)
- return self.unfunc(arr.calc_dtype, v)
-
-class Call2(Signature):
- _immutable_fields_ = ['binfunc', 'name', 'calc_dtype', 'left', 'right']
-
- def __init__(self, func, name, calc_dtype, left, right):
- self.binfunc = func
- self.left = left
- self.right = right
- self.name = name
- self.calc_dtype = calc_dtype
-
- def hash(self):
- return (compute_hash(self.name) ^ intmask(self.left.hash() << 1) ^
- intmask(self.right.hash() << 2))
-
- def eq(self, other, compare_array_no=True):
- if type(self) is not type(other):
- return False
- assert isinstance(other, Call2)
- return (self.binfunc is other.binfunc and
- self.calc_dtype is other.calc_dtype and
- self.left.eq(other.left, compare_array_no) and
- self.right.eq(other.right, compare_array_no))
-
- def _invent_array_numbering(self, arr, cache):
- from pypy.module.micronumpy.interp_numarray import Call2
- assert isinstance(arr, Call2)
- self.left._invent_array_numbering(arr.left, cache)
- self.right._invent_array_numbering(arr.right, cache)
-
- def _invent_numbering(self, cache, allnumbers):
- self.left._invent_numbering(cache, allnumbers)
- self.right._invent_numbering(cache, allnumbers)
-
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import Call2
-
- assert isinstance(arr, Call2)
- self.left._create_iter(iterlist, arraylist, arr.left, transforms)
- self.right._create_iter(iterlist, arraylist, arr.right, transforms)
-
- def eval(self, frame, arr):
- from pypy.module.micronumpy.interp_numarray import Call2
- assert isinstance(arr, Call2)
- lhs = self.left.eval(frame, arr.left).convert_to(self.calc_dtype)
- rhs = self.right.eval(frame, arr.right).convert_to(self.calc_dtype)
- return self.binfunc(self.calc_dtype, lhs, rhs)
-
- def debug_repr(self):
- return 'Call2(%s, %s, %s)' % (self.name, self.left.debug_repr(),
- self.right.debug_repr())
-
-class ResultSignature(Call2):
- def __init__(self, dtype, left, right):
- Call2.__init__(self, None, 'assign', dtype, left, right)
-
- def eval(self, frame, arr):
- from pypy.module.micronumpy.interp_numarray import ResultArray
-
- assert isinstance(arr, ResultArray)
- offset = frame.get_final_iter().offset
- val = self.right.eval(frame, arr.right)
- arr.left.setitem(offset, val)
-
-class BroadcastResultSignature(ResultSignature):
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import ResultArray
-
- assert isinstance(arr, ResultArray)
- rtransforms = [BroadcastTransform(arr.left.shape)] + transforms
- self.left._create_iter(iterlist, arraylist, arr.left, transforms)
- self.right._create_iter(iterlist, arraylist, arr.right, rtransforms)
-
-class ToStringSignature(Call1):
- def __init__(self, dtype, child):
- Call1.__init__(self, None, 'tostring', dtype, child)
-
- @jit.unroll_safe
- def eval(self, frame, arr):
- from pypy.module.micronumpy.interp_numarray import ToStringArray
-
- assert isinstance(arr, ToStringArray)
- arr.res_str.setitem(0, self.child.eval(frame, arr.values).convert_to(
- self.dtype))
- for i in range(arr.item_size):
- arr.s.append(arr.res_str_casted[i])
-
-class BroadcastLeft(Call2):
- def _invent_numbering(self, cache, allnumbers):
- self.left._invent_numbering(new_cache(), allnumbers)
- self.right._invent_numbering(cache, allnumbers)
-
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import Call2
-
- assert isinstance(arr, Call2)
- ltransforms = [BroadcastTransform(arr.shape)] + transforms
- self.left._create_iter(iterlist, arraylist, arr.left, ltransforms)
- self.right._create_iter(iterlist, arraylist, arr.right, transforms)
-
-class BroadcastRight(Call2):
- def _invent_numbering(self, cache, allnumbers):
- self.left._invent_numbering(cache, allnumbers)
- self.right._invent_numbering(new_cache(), allnumbers)
-
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import Call2
-
- assert isinstance(arr, Call2)
- rtransforms = [BroadcastTransform(arr.shape)] + transforms
- self.left._create_iter(iterlist, arraylist, arr.left, transforms)
- self.right._create_iter(iterlist, arraylist, arr.right, rtransforms)
-
-class BroadcastBoth(Call2):
- def _invent_numbering(self, cache, allnumbers):
- self.left._invent_numbering(new_cache(), allnumbers)
- self.right._invent_numbering(new_cache(), allnumbers)
-
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import Call2
-
- assert isinstance(arr, Call2)
- rtransforms = [BroadcastTransform(arr.shape)] + transforms
- ltransforms = [BroadcastTransform(arr.shape)] + transforms
- self.left._create_iter(iterlist, arraylist, arr.left, ltransforms)
- self.right._create_iter(iterlist, arraylist, arr.right, rtransforms)
-
-class ReduceSignature(Call2):
- _immutable_fields_ = ['binfunc', 'name', 'calc_dtype',
- 'left', 'right', 'done_func']
-
- def __init__(self, func, name, calc_dtype, left, right,
- done_func):
- Call2.__init__(self, func, name, calc_dtype, left, right)
- self.done_func = done_func
-
- def eval(self, frame, arr):
- from pypy.module.micronumpy.interp_numarray import ReduceArray
- assert isinstance(arr, ReduceArray)
- rval = self.right.eval(frame, arr.right).convert_to(self.calc_dtype)
- if self.done_func is not None and self.done_func(self.calc_dtype, rval):
- raise ComputationDone(rval)
- frame.cur_value = self.binfunc(self.calc_dtype, frame.cur_value, rval)
-
- def debug_repr(self):
- return 'ReduceSig(%s, %s)' % (self.name, self.right.debug_repr())
-
-class SliceloopSignature(Call2):
- def eval(self, frame, arr):
- from pypy.module.micronumpy.interp_numarray import Call2
-
- assert isinstance(arr, Call2)
- ofs = frame.iterators[0].offset
- arr.left.setitem(ofs, self.right.eval(frame, arr.right).convert_to(
- self.calc_dtype))
-
- def _invent_numbering(self, cache, allnumbers):
- self.left._invent_numbering(new_cache(), allnumbers)
- self.right._invent_numbering(cache, allnumbers)
-
- def debug_repr(self):
- return 'SliceLoop(%s, %s, %s)' % (self.name, self.left.debug_repr(),
- self.right.debug_repr())
-
-class SliceloopBroadcastSignature(SliceloopSignature):
- def _invent_numbering(self, cache, allnumbers):
- self.left._invent_numbering(new_cache(), allnumbers)
- self.right._invent_numbering(cache, allnumbers)
-
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import SliceArray
-
- assert isinstance(arr, SliceArray)
- rtransforms = [BroadcastTransform(arr.shape)] + transforms
- self.left._create_iter(iterlist, arraylist, arr.left, transforms)
- self.right._create_iter(iterlist, arraylist, arr.right, rtransforms)
-
-class AxisReduceSignature(Call2):
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_numarray import AxisReduce,\
- ConcreteArray
-
- assert isinstance(arr, AxisReduce)
- left = arr.left
- assert isinstance(left, ConcreteArray)
- iterlist.append(AxisIterator(left.start, arr.dim, arr.shape,
- left.strides, left.backstrides))
- self.right._create_iter(iterlist, arraylist, arr.right, transforms)
-
- def _invent_numbering(self, cache, allnumbers):
- allnumbers.append(0)
- self.right._invent_numbering(cache, allnumbers)
-
- def _invent_array_numbering(self, arr, cache):
- from pypy.module.micronumpy.interp_numarray import AxisReduce
-
- assert isinstance(arr, AxisReduce)
- self.right._invent_array_numbering(arr.right, cache)
-
- def eval(self, frame, arr):
- from pypy.module.micronumpy.interp_numarray import AxisReduce
-
- assert isinstance(arr, AxisReduce)
- iterator = frame.get_final_iter()
- v = self.right.eval(frame, arr.right).convert_to(self.calc_dtype)
- if iterator.first_line:
- if frame.identity is not None:
- value = self.binfunc(self.calc_dtype, frame.identity, v)
- else:
- value = v
- else:
- cur = arr.left.getitem(iterator.offset)
- value = self.binfunc(self.calc_dtype, cur, v)
- arr.left.setitem(iterator.offset, value)
- def debug_repr(self):
- return 'AxisReduceSig(%s, %s)' % (self.name, self.right.debug_repr())
-
-class WhereSignature(Signature):
- _immutable_fields_ = ['dtype', 'arrdtype', 'arrsig', 'xsig', 'ysig']
-
- def __init__(self, dtype, arrdtype, arrsig, xsig, ysig):
- self.dtype = dtype
- self.arrdtype = arrdtype
- self.arrsig = arrsig
- self.xsig = xsig
- self.ysig = ysig
-
- def hash(self):
- return (intmask(self.arrsig.hash() << 1) ^
- intmask(self.xsig.hash() << 2) ^
- intmask(self.ysig.hash() << 3))
-
- def eq(self, other, compare_array_no=True):
- if type(self) is not type(other):
- return False
- assert isinstance(other, WhereSignature)
- return (self.arrsig.eq(other.arrsig, compare_array_no) and
- self.xsig.eq(other.xsig, compare_array_no) and
- self.ysig.eq(other.ysig, compare_array_no))
-
- def _invent_array_numbering(self, arr, cache):
- from pypy.module.micronumpy.interp_arrayops import WhereArray
- assert isinstance(arr, WhereArray)
- self.arrsig._invent_array_numbering(arr.arr, cache)
- self.xsig._invent_array_numbering(arr.x, cache)
- self.ysig._invent_array_numbering(arr.y, cache)
-
- def _invent_numbering(self, cache, allnumbers):
- self.arrsig._invent_numbering(cache, allnumbers)
- self.xsig._invent_numbering(cache, allnumbers)
- self.ysig._invent_numbering(cache, allnumbers)
-
- def _create_iter(self, iterlist, arraylist, arr, transforms):
- from pypy.module.micronumpy.interp_arrayops import WhereArray
-
- assert isinstance(arr, WhereArray)
- # XXX this does not support broadcasting correctly
- self.arrsig._create_iter(iterlist, arraylist, arr.arr, transforms)
- self.xsig._create_iter(iterlist, arraylist, arr.x, transforms)
- self.ysig._create_iter(iterlist, arraylist, arr.y, transforms)
-
- def eval(self, frame, arr):
- from pypy.module.micronumpy.interp_arrayops import WhereArray
- assert isinstance(arr, WhereArray)
- lhs = self.xsig.eval(frame, arr.x).convert_to(self.dtype)
- rhs = self.ysig.eval(frame, arr.y).convert_to(self.dtype)
- w_val = self.arrsig.eval(frame, arr.arr)
- if self.arrdtype.itemtype.bool(w_val):
- return lhs
- else:
- return rhs
-
- def debug_repr(self):
- return 'Where(%s, %s, %s)' % (self.arrsig.debug_repr(),
- self.xsig.debug_repr(),
- self.ysig.debug_repr())
diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py
--- a/pypy/module/micronumpy/strides.py
+++ b/pypy/module/micronumpy/strides.py
@@ -1,5 +1,6 @@
from pypy.rlib import jit
from pypy.interpreter.error import OperationError
+from pypy.module.micronumpy.base import W_NDimArray
@jit.look_inside_iff(lambda chunks: jit.isconstant(len(chunks)))
def enumerate_chunks(chunks):
@@ -48,11 +49,10 @@
return rstrides, rbackstrides
def is_single_elem(space, w_elem, is_rec_type):
- from pypy.module.micronumpy.interp_numarray import BaseArray
if (is_rec_type and space.isinstance_w(w_elem, space.w_tuple)):
return True
if (space.isinstance_w(w_elem, space.w_tuple) or
- isinstance(w_elem, BaseArray) or
+ isinstance(w_elem, W_NDimArray) or
space.isinstance_w(w_elem, space.w_list)):
return False
return True
@@ -104,7 +104,11 @@
i //= shape[s]
return coords, step, lngth
-def shape_agreement(space, shape1, shape2):
+def shape_agreement(space, shape1, w_arr2, broadcast_down=True):
+ if w_arr2 is None:
+ return shape1
+ assert isinstance(w_arr2, W_NDimArray)
+ shape2 = w_arr2.get_shape()
ret = _shape_agreement(shape1, shape2)
if len(ret) < max(len(shape1), len(shape2)):
raise OperationError(space.w_ValueError,
@@ -113,6 +117,13 @@
",".join([str(x) for x in shape2]),
))
)
+ if not broadcast_down and len([x for x in ret if x != 1]) > len([x for x in shape2 if x != 1]):
+ raise OperationError(space.w_ValueError,
+ space.wrap("unbroadcastable shape (%s) cannot be broadcasted to (%s)" % (
+ ",".join([str(x) for x in shape1]),
+ ",".join([str(x) for x in shape2]),
+ ))
+ )
return ret
def _shape_agreement(shape1, shape2):
@@ -165,12 +176,6 @@
neg_dim = -1
batch = space.listview(w_iterable)
new_size = 1
- if len(batch) < 1:
- if old_size == 1:
- # Scalars can have an empty size.
- new_size = 1
- else:
- new_size = 0
new_shape = []
i = 0
for elem in batch:
diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py
--- a/pypy/module/micronumpy/support.py
+++ b/pypy/module/micronumpy/support.py
@@ -7,3 +7,19 @@
for x in s:
i *= x
return i
+
+def calc_strides(shape, dtype, order):
+ strides = []
+ backstrides = []
+ s = 1
+ shape_rev = shape[:]
+ if order == 'C':
+ shape_rev.reverse()
+ for sh in shape_rev:
+ strides.append(s * dtype.get_size())
+ backstrides.append(s * (sh - 1) * dtype.get_size())
+ s *= sh
+ if order == 'C':
+ strides.reverse()
+ backstrides.reverse()
+ return strides, backstrides
diff --git a/pypy/module/micronumpy/test/test_arrayops.py b/pypy/module/micronumpy/test/test_arrayops.py
--- a/pypy/module/micronumpy/test/test_arrayops.py
+++ b/pypy/module/micronumpy/test/test_arrayops.py
@@ -8,9 +8,78 @@
a = where(array(a) > 0, ones(5), zeros(5))
assert (a == [1, 1, 1, 0, 0]).all()
+ def test_where_differing_dtypes(self):
+ from _numpypy import array, ones, zeros, where
+ a = [1, 2, 3, 0, -3]
+ a = where(array(a) > 0, ones(5, dtype=int), zeros(5, dtype=float))
+ assert (a == [1, 1, 1, 0, 0]).all()
+
+ def test_where_broadcast(self):
+ from _numpypy import array, where
+ a = where(array([[1, 2, 3], [4, 5, 6]]) > 3, [1, 1, 1], 2)
+ assert (a == [[2, 2, 2], [1, 1, 1]]).all()
+ a = where(True, [1, 1, 1], 2)
+ assert (a == [1, 1, 1]).all()
+
+ def test_where_errors(self):
+ from _numpypy import where, array
+ raises(ValueError, "where([1, 2, 3], [3, 4, 5])")
+ raises(ValueError, "where([1, 2, 3], [3, 4, 5], [6, 7])")
+ assert where(True, 1, 2) == array(1)
+ assert where(False, 1, 2) == array(2)
+ assert (where(True, [1, 2, 3], 2) == [1, 2, 3]).all()
+ assert (where(False, 1, [1, 2, 3]) == [1, 2, 3]).all()
+ assert (where([1, 2, 3], True, False) == [True, True, True]).all()
+
+ #def test_where_1_arg(self):
+ # xxx
+
def test_where_invalidates(self):
from _numpypy import where, ones, zeros, array
a = array([1, 2, 3, 0, -3])
b = where(a > 0, ones(5), zeros(5))
a[0] = 0
assert (b == [1, 1, 1, 0, 0]).all()
+
+
+ def test_dot(self):
+ from _numpypy import array, dot, arange
+ a = array(range(5))
+ assert dot(a, a) == 30.0
+
+ a = array(range(5))
+ assert a.dot(range(5)) == 30
+ assert dot(range(5), range(5)) == 30
+ assert (dot(5, [1, 2, 3]) == [5, 10, 15]).all()
+
+ a = arange(12).reshape(3, 4)
+ b = arange(12).reshape(4, 3)
+ c = a.dot(b)
+ assert (c == [[ 42, 48, 54], [114, 136, 158], [186, 224, 262]]).all()
+
+ a = arange(24).reshape(2, 3, 4)
+ raises(ValueError, "a.dot(a)")
+ b = a[0, :, :].T
+ #Superfluous shape test makes the intention of the test clearer
+ assert a.shape == (2, 3, 4)
+ assert b.shape == (4, 3)
+ c = dot(a, b)
+ assert (c == [[[14, 38, 62], [38, 126, 214], [62, 214, 366]],
+ [[86, 302, 518], [110, 390, 670], [134, 478, 822]]]).all()
+ c = dot(a, b[:, 2])
+ assert (c == [[62, 214, 366], [518, 670, 822]]).all()
+ a = arange(3*2*6).reshape((3,2,6))
+ b = arange(3*2*6)[::-1].reshape((2,6,3))
+ assert dot(a, b)[2,0,1,2] == 1140
+ assert (dot([[1,2],[3,4]],[5,6]) == [17, 39]).all()
+
+ def test_dot_constant(self):
+ from _numpypy import array, dot
+ a = array(range(5))
+ b = a.dot(2.5)
+ for i in xrange(5):
+ assert b[i] == 2.5 * a[i]
+ c = dot(4, 3.0)
+ assert c == 12.0
+ c = array(3.0).dot(array(4))
+ assert c == 12.0
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
--- a/pypy/module/micronumpy/test/test_base.py
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -1,9 +1,7 @@
from pypy.conftest import gettestobjspace
from pypy.module.micronumpy.interp_dtype import get_dtype_cache
-from pypy.module.micronumpy.interp_numarray import W_NDimArray, Scalar
from pypy.module.micronumpy.interp_ufuncs import (find_binop_result_dtype,
find_unaryop_result_dtype)
-from pypy.module.micronumpy.interp_boxes import W_Float64Box
from pypy.module.micronumpy.interp_dtype import nonnative_byteorder_prefix,\
byteorder_prefix
from pypy.conftest import option
@@ -21,59 +19,6 @@
cls.w_non_native_prefix = cls.space.wrap(nonnative_byteorder_prefix)
cls.w_native_prefix = cls.space.wrap(byteorder_prefix)
-class TestSignature(object):
- def test_binop_signature(self, space):
- float64_dtype = get_dtype_cache(space).w_float64dtype
- bool_dtype = get_dtype_cache(space).w_booldtype
-
- ar = W_NDimArray([10], dtype=float64_dtype)
- ar2 = W_NDimArray([10], dtype=float64_dtype)
- v1 = ar.descr_add(space, ar)
- v2 = ar.descr_add(space, Scalar(float64_dtype, W_Float64Box(2.0)))
- sig1 = v1.find_sig()
- sig2 = v2.find_sig()
- assert v1 is not v2
- assert sig1.left.iter_no == sig1.right.iter_no
- assert sig2.left.iter_no != sig2.right.iter_no
- assert sig1.left.array_no == sig1.right.array_no
- sig1b = ar2.descr_add(space, ar).find_sig()
- assert sig1b.left.array_no != sig1b.right.array_no
- assert sig1b is not sig1
- v3 = ar.descr_add(space, Scalar(float64_dtype, W_Float64Box(1.0)))
- sig3 = v3.find_sig()
- assert sig2 is sig3
- v4 = ar.descr_add(space, ar)
- assert v1.find_sig() is v4.find_sig()
-
- bool_ar = W_NDimArray([10], dtype=bool_dtype)
- v5 = ar.descr_add(space, bool_ar)
- assert v5.find_sig() is not v1.find_sig()
- assert v5.find_sig() is not v2.find_sig()
- v6 = ar.descr_add(space, bool_ar)
- assert v5.find_sig() is v6.find_sig()
- v7 = v6.descr_add(space, v6)
- sig7 = v7.find_sig()
- assert sig7.left.left.iter_no == sig7.right.left.iter_no
- assert sig7.left.left.iter_no != sig7.right.right.iter_no
- assert sig7.left.right.iter_no == sig7.right.right.iter_no
- v1.forced_result = ar
- assert v1.find_sig() is not sig1
-
- def test_slice_signature(self, space):
- float64_dtype = get_dtype_cache(space).w_float64dtype
-
- ar = W_NDimArray([10], dtype=float64_dtype)
- v1 = ar.descr_getitem(space, space.wrap(slice(1, 3, 1)))
- v2 = ar.descr_getitem(space, space.wrap(slice(4, 6, 1)))
- assert v1.find_sig() is v2.find_sig()
-
- v3 = v2.descr_add(space, v1)
- v4 = v1.descr_add(space, v2)
- assert v3.find_sig() is v4.find_sig()
- v5 = ar.descr_add(space, ar).descr_getitem(space, space.wrap(slice(1, 3, 1)))
- v6 = ar.descr_add(space, ar).descr_getitem(space, space.wrap(slice(1, 4, 1)))
- assert v5.find_sig() is v6.find_sig()
-
class TestUfuncCoerscion(object):
def test_binops(self, space):
bool_dtype = get_dtype_cache(space).w_booldtype
diff --git a/pypy/module/micronumpy/test/test_compile.py b/pypy/module/micronumpy/test/test_compile.py
--- a/pypy/module/micronumpy/test/test_compile.py
+++ b/pypy/module/micronumpy/test/test_compile.py
@@ -1,4 +1,5 @@
import py
+py.test.skip("this is going away")
from pypy.module.micronumpy.compile import (numpy_compile, Assignment,
ArrayConstant, FloatConstant, Operator, Variable, RangeConstant, Execute,
diff --git a/pypy/module/micronumpy/test/test_dtypes.py b/pypy/module/micronumpy/test/test_dtypes.py
--- a/pypy/module/micronumpy/test/test_dtypes.py
+++ b/pypy/module/micronumpy/test/test_dtypes.py
@@ -1,4 +1,4 @@
-import py
+import py, sys
from pypy.conftest import option
from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
from pypy.interpreter.gateway import interp2app
@@ -508,13 +508,6 @@
from _numpypy import dtype
assert dtype('i4').alignment == 4
- def test_typeinfo(self):
- from _numpypy import typeinfo, void, number, int64, bool_
- assert typeinfo['Number'] == number
- assert typeinfo['LONGLONG'] == ('q', 9, 64, 8, 9223372036854775807L, -9223372036854775808L, int64)
- assert typeinfo['VOID'] == ('V', 20, 0, 1, void)
- assert typeinfo['BOOL'] == ('?', 0, 8, 1, 1, 0, bool_)
-
class AppTestStrUnicodeDtypes(BaseNumpyAppTest):
def test_str_unicode(self):
from _numpypy import str_, unicode_, character, flexible, generic
@@ -583,14 +576,16 @@
def setup_class(cls):
BaseNumpyAppTest.setup_class.im_func(cls)
def check_non_native(w_obj, w_obj2):
- assert w_obj.storage[0] == w_obj2.storage[1]
- assert w_obj.storage[1] == w_obj2.storage[0]
- if w_obj.storage[0] == '\x00':
- assert w_obj2.storage[1] == '\x00'
- assert w_obj2.storage[0] == '\x01'
+ stor1 = w_obj.implementation.storage
+ stor2 = w_obj2.implementation.storage
+ assert stor1[0] == stor2[1]
+ assert stor1[1] == stor2[0]
+ if stor1[0] == '\x00':
+ assert stor2[1] == '\x00'
+ assert stor2[0] == '\x01'
else:
- assert w_obj2.storage[1] == '\x01'
- assert w_obj2.storage[0] == '\x00'
+ assert stor2[1] == '\x01'
+ assert stor2[0] == '\x00'
cls.w_check_non_native = cls.space.wrap(interp2app(check_non_native))
if option.runappdirect:
py.test.skip("not a direct test")
@@ -602,3 +597,15 @@
assert (a + a)[1] == 4
self.check_non_native(a, array([1, 2, 3], 'i2'))
+class AppTestPyPyOnly(BaseNumpyAppTest):
+ def setup_class(cls):
+ if option.runappdirect and '__pypy__' not in sys.builtin_module_names:
+ py.test.skip("pypy only test")
+ BaseNumpyAppTest.setup_class.im_func(cls)
+
+ def test_typeinfo(self):
+ from _numpypy import typeinfo, void, number, int64, bool_
+ assert typeinfo['Number'] == number
+ assert typeinfo['LONGLONG'] == ('q', 9, 64, 8, 9223372036854775807L, -9223372036854775808L, int64)
+ assert typeinfo['VOID'] == ('V', 20, 0, 1, void)
+ assert typeinfo['BOOL'] == ('?', 0, 8, 1, 1, 0, bool_)
diff --git a/pypy/module/micronumpy/test/test_iter.py b/pypy/module/micronumpy/test/test_iter.py
--- a/pypy/module/micronumpy/test/test_iter.py
+++ b/pypy/module/micronumpy/test/test_iter.py
@@ -1,4 +1,7 @@
-from pypy.module.micronumpy.interp_iter import ViewIterator
+from pypy.module.micronumpy.arrayimpl.concrete import MultiDimViewIterator
+
+class MockArray(object):
+ size = 1
class TestIterDirect(object):
def test_C_viewiterator(self):
@@ -9,36 +12,36 @@
strides = [5, 1]
backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
assert backstrides == [10, 4]
- i = ViewIterator(start, strides, backstrides, shape)
- i = i.next(2)
- i = i.next(2)
- i = i.next(2)
+ i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
+ i.next()
+ i.next()
+ i.next()
assert i.offset == 3
assert not i.done()
- assert i.indices == [0,3]
+ assert i.indexes == [0,3]
#cause a dimension overflow
- i = i.next(2)
- i = i.next(2)
+ i.next()
+ i.next()
assert i.offset == 5
- assert i.indices == [1,0]
+ assert i.indexes == [1,0]
#Now what happens if the array is transposed? strides[-1] != 1
# therefore layout is non-contiguous
strides = [1, 3]
backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
assert backstrides == [2, 12]
- i = ViewIterator(start, strides, backstrides, shape)
- i = i.next(2)
- i = i.next(2)
- i = i.next(2)
+ i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
+ i.next()
+ i.next()
+ i.next()
assert i.offset == 9
assert not i.done()
- assert i.indices == [0,3]
+ assert i.indexes == [0,3]
#cause a dimension overflow
- i = i.next(2)
- i = i.next(2)
+ i.next()
+ i.next()
assert i.offset == 1
- assert i.indices == [1,0]
+ assert i.indexes == [1,0]
def test_C_viewiterator_step(self):
#iteration in C order with #contiguous layout => strides[-1] is 1
@@ -48,22 +51,22 @@
strides = [5, 1]
backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
assert backstrides == [10, 4]
- i = ViewIterator(start, strides, backstrides, shape)
- i = i.next_skip_x(2,2)
- i = i.next_skip_x(2,2)
- i = i.next_skip_x(2,2)
+ i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
+ i.next_skip_x(2)
+ i.next_skip_x(2)
+ i.next_skip_x(2)
assert i.offset == 6
assert not i.done()
- assert i.indices == [1,1]
+ assert i.indexes == [1,1]
#And for some big skips
- i = i.next_skip_x(2,5)
+ i.next_skip_x(5)
assert i.offset == 11
- assert i.indices == [2,1]
- i = i.next_skip_x(2,5)
+ assert i.indexes == [2,1]
+ i.next_skip_x(5)
# Note: the offset does not overflow but recycles,
# this is good for broadcast
assert i.offset == 1
- assert i.indices == [0,1]
+ assert i.indexes == [0,1]
assert i.done()
#Now what happens if the array is transposed? strides[-1] != 1
@@ -71,18 +74,18 @@
strides = [1, 3]
backstrides = [x * (y - 1) for x,y in zip(strides, shape)]
assert backstrides == [2, 12]
- i = ViewIterator(start, strides, backstrides, shape)
- i = i.next_skip_x(2,2)
- i = i.next_skip_x(2,2)
- i = i.next_skip_x(2,2)
+ i = MultiDimViewIterator(MockArray, start, strides, backstrides, shape)
+ i.next_skip_x(2)
+ i.next_skip_x(2)
+ i.next_skip_x(2)
assert i.offset == 4
- assert i.indices == [1,1]
+ assert i.indexes == [1,1]
assert not i.done()
- i = i.next_skip_x(2,5)
+ i.next_skip_x(5)
assert i.offset == 5
- assert i.indices == [2,1]
+ assert i.indexes == [2,1]
assert not i.done()
- i = i.next_skip_x(2,5)
- assert i.indices == [0,1]
+ i.next_skip_x(5)
+ assert i.indexes == [0,1]
assert i.offset == 3
assert i.done()
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
@@ -1,11 +1,10 @@
-import py
+import py, sys
from pypy.conftest import option
-from pypy.interpreter.error import OperationError
from pypy.module.micronumpy.appbridge import get_appbridge_cache
-from pypy.module.micronumpy.interp_iter import Chunk, Chunks
-from pypy.module.micronumpy.interp_numarray import W_NDimArray, shape_agreement
+from pypy.module.micronumpy.iter import Chunk, Chunks
+from pypy.module.micronumpy.interp_numarray import W_NDimArray
from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
class MockDtype(object):
@@ -14,12 +13,19 @@
def malloc(size):
return None
+ @staticmethod
+ def get_element_size():
+ return 1
+
def get_size(self):
return 1
def create_slice(a, chunks):
- return Chunks(chunks).apply(a)
+ return Chunks(chunks).apply(a).implementation
+
+def create_array(*args, **kwargs):
+ return W_NDimArray.from_shape(*args, **kwargs).implementation
class TestNumArrayDirect(object):
def newslice(self, *args):
@@ -35,17 +41,17 @@
return self.space.newtuple(args_w)
def test_strides_f(self):
- a = W_NDimArray([10, 5, 3], MockDtype(), 'F')
+ a = create_array([10, 5, 3], MockDtype(), order='F')
assert a.strides == [1, 10, 50]
assert a.backstrides == [9, 40, 100]
def test_strides_c(self):
- a = W_NDimArray([10, 5, 3], MockDtype(), 'C')
+ a = create_array([10, 5, 3], MockDtype(), order='C')
assert a.strides == [15, 3, 1]
assert a.backstrides == [135, 12, 2]
def test_create_slice_f(self):
- a = W_NDimArray([10, 5, 3], MockDtype(), 'F')
+ a = create_array([10, 5, 3], MockDtype(), order='F')
s = create_slice(a, [Chunk(3, 0, 0, 1)])
assert s.start == 3
assert s.strides == [10, 50]
@@ -63,7 +69,7 @@
assert s.shape == [10, 3]
def test_create_slice_c(self):
- a = W_NDimArray([10, 5, 3], MockDtype(), 'C')
+ a = create_array([10, 5, 3], MockDtype(), order='C')
s = create_slice(a, [Chunk(3, 0, 0, 1)])
assert s.start == 45
assert s.strides == [3, 1]
@@ -83,7 +89,7 @@
assert s.shape == [10, 3]
def test_slice_of_slice_f(self):
- a = W_NDimArray([10, 5, 3], MockDtype(), 'F')
+ a = create_array([10, 5, 3], MockDtype(), order='F')
s = create_slice(a, [Chunk(5, 0, 0, 1)])
assert s.start == 5
s2 = create_slice(s, [Chunk(3, 0, 0, 1)])
@@ -100,7 +106,7 @@
assert s2.start == 1 * 15 + 2 * 3
def test_slice_of_slice_c(self):
- a = W_NDimArray([10, 5, 3], MockDtype(), order='C')
+ a = create_array([10, 5, 3], MockDtype(), order='C')
s = create_slice(a, [Chunk(5, 0, 0, 1)])
assert s.start == 15 * 5
s2 = create_slice(s, [Chunk(3, 0, 0, 1)])
@@ -117,51 +123,30 @@
assert s2.start == 1 * 15 + 2 * 3
def test_negative_step_f(self):
- a = W_NDimArray([10, 5, 3], MockDtype(), 'F')
+ a = create_array([10, 5, 3], MockDtype(), order='F')
s = create_slice(a, [Chunk(9, -1, -2, 5)])
assert s.start == 9
assert s.strides == [-2, 10, 50]
assert s.backstrides == [-8, 40, 100]
def test_negative_step_c(self):
- a = W_NDimArray([10, 5, 3], MockDtype(), order='C')
+ a = create_array([10, 5, 3], MockDtype(), order='C')
s = create_slice(a, [Chunk(9, -1, -2, 5)])
assert s.start == 135
assert s.strides == [-30, 3, 1]
assert s.backstrides == [-120, 12, 2]
- def test_index_of_single_item_f(self):
- a = W_NDimArray([10, 5, 3], MockDtype(), 'F')
- r = a._index_of_single_item(self.space, self.newtuple(1, 2, 2))
- assert r == 1 + 2 * 10 + 2 * 50
- s = create_slice(a, [Chunk(0, 10, 1, 10), Chunk(2, 0, 0, 1)])
- r = s._index_of_single_item(self.space, self.newtuple(1, 0))
- assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 0))
- r = s._index_of_single_item(self.space, self.newtuple(1, 1))
- assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 1))
-
- def test_index_of_single_item_c(self):
- a = W_NDimArray([10, 5, 3], MockDtype(), 'C')
- r = a._index_of_single_item(self.space, self.newtuple(1, 2, 2))
- assert r == 1 * 3 * 5 + 2 * 3 + 2
- s = create_slice(a, [Chunk(0, 10, 1, 10), Chunk(2, 0, 0, 1)])
- r = s._index_of_single_item(self.space, self.newtuple(1, 0))
- assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 0))
- r = s._index_of_single_item(self.space, self.newtuple(1, 1))
- assert r == a._index_of_single_item(self.space, self.newtuple(1, 2, 1))
-
def test_shape_agreement(self):
- assert shape_agreement(self.space, [3], [3]) == [3]
- assert shape_agreement(self.space, [1, 2, 3], [1, 2, 3]) == [1, 2, 3]
- py.test.raises(OperationError, shape_agreement, self.space, [2], [3])
- assert shape_agreement(self.space, [4, 4], []) == [4, 4]
- assert shape_agreement(self.space,
- [8, 1, 6, 1], [7, 1, 5]) == [8, 7, 6, 5]
- assert shape_agreement(self.space,
- [5, 2], [4, 3, 5, 2]) == [4, 3, 5, 2]
+ from pypy.module.micronumpy.strides import _shape_agreement
+ assert _shape_agreement([3], [3]) == [3]
+ assert _shape_agreement([1, 2, 3], [1, 2, 3]) == [1, 2, 3]
+ _shape_agreement([2], [3]) == 0
+ assert _shape_agreement([4, 4], []) == [4, 4]
+ assert _shape_agreement([8, 1, 6, 1], [7, 1, 5]) == [8, 7, 6, 5]
+ assert _shape_agreement([5, 2], [4, 3, 5, 2]) == [4, 3, 5, 2]
def test_calc_new_strides(self):
- from pypy.module.micronumpy.interp_numarray import calc_new_strides
+ from pypy.module.micronumpy.strides import calc_new_strides
assert calc_new_strides([2, 4], [4, 2], [4, 2], "C") == [8, 2]
assert calc_new_strides([2, 4, 3], [8, 3], [1, 16], 'F') == [1, 2, 16]
assert calc_new_strides([2, 3, 4], [8, 3], [1, 16], 'F') is None
@@ -251,6 +236,8 @@
a = ndarray(3, dtype=int)
assert a.shape == (3,)
assert a.dtype is dtype(int)
+ a = ndarray([], dtype=float)
+ assert a.shape == ()
def test_ndmin(self):
from _numpypy import array
@@ -281,7 +268,7 @@
assert x.ndim == 3
# numpy actually raises an AttributeError, but _numpypy raises an
# TypeError
- raises(TypeError, 'x.ndim = 3')
+ raises((TypeError, AttributeError), 'x.ndim = 3')
def test_init(self):
from _numpypy import zeros
@@ -464,7 +451,7 @@
assert a[1] == 0.
assert a[3] == 1.
b[::-1] = b
- assert b[0] == 0.
+ assert b[0] == 1.
assert b[1] == 0.
def test_setslice_of_slice_array(self):
@@ -589,7 +576,7 @@
def test_set_shape(self):
from _numpypy import array, zeros
a = array([])
- a.shape = []
+ raises(ValueError, "a.shape = []")
a = array(range(12))
a.shape = (3, 4)
assert (a == [range(4), range(4, 8), range(8, 12)]).all()
@@ -605,6 +592,7 @@
a.shape = ()
#numpy allows this
a.shape = (1,)
+ assert a[0] == 3
a = array(range(6)).reshape(2,3).T
raises(AttributeError, 'a.shape = 6')
@@ -1094,7 +1082,7 @@
assert a[:4].mean() == 1.5
a = array(range(105)).reshape(3, 5, 7)
b = a.mean(axis=0)
- b[0, 0]==35.
+ assert b[0, 0] == 35.
assert a.mean(axis=0)[0, 0] == 35
assert (b == array(range(35, 70), dtype=float).reshape(5, 7)).all()
assert (a.mean(2) == array(range(0, 15), dtype=float).reshape(3, 5) * 7 + 3).all()
@@ -1102,6 +1090,8 @@
assert (a.mean(axis=-1) == a.mean(axis=2)).all()
raises(ValueError, a.mean, -4)
raises(ValueError, a.mean, 3)
+ a = arange(10).reshape(5, 2)
+ assert (a.mean(1) == [0.5, 2.5, 4.5, 6.5, 8.5]).all()
def test_sum(self):
from _numpypy import array
@@ -1117,7 +1107,7 @@
d = array(0.)
b = a.sum(out=d)
assert b == d
- assert isinstance(b, float)
+ assert b is d
def test_reduce_nd(self):
from numpypy import arange, array, multiply
@@ -1272,48 +1262,6 @@
c = array([])
assert c.any() == False
- def test_dot(self):
- from _numpypy import array, dot, arange
- a = array(range(5))
- assert dot(a, a) == 30.0
-
- a = array(range(5))
- assert a.dot(range(5)) == 30
- assert dot(range(5), range(5)) == 30
- assert (dot(5, [1, 2, 3]) == [5, 10, 15]).all()
-
- a = arange(12).reshape(3, 4)
- b = arange(12).reshape(4, 3)
- c = a.dot(b)
- assert (c == [[ 42, 48, 54], [114, 136, 158], [186, 224, 262]]).all()
-
- a = arange(24).reshape(2, 3, 4)
- raises(ValueError, "a.dot(a)")
- b = a[0, :, :].T
- #Superfluous shape test makes the intention of the test clearer
- assert a.shape == (2, 3, 4)
- assert b.shape == (4, 3)
- c = dot(a, b)
- assert (c == [[[14, 38, 62], [38, 126, 214], [62, 214, 366]],
- [[86, 302, 518], [110, 390, 670], [134, 478, 822]]]).all()
- c = dot(a, b[:, 2])
- assert (c == [[62, 214, 366], [518, 670, 822]]).all()
- a = arange(3*2*6).reshape((3,2,6))
- b = arange(3*2*6)[::-1].reshape((2,6,3))
- assert dot(a, b)[2,0,1,2] == 1140
- assert (dot([[1,2],[3,4]],[5,6]) == [17, 39]).all()
-
- def test_dot_constant(self):
- from _numpypy import array, dot
- a = array(range(5))
- b = a.dot(2.5)
- for i in xrange(5):
- assert b[i] == 2.5 * a[i]
- c = dot(4, 3.0)
- assert c == 12.0
- c = array(3.0).dot(array(4))
- assert c == 12.0
-
def test_dtype_guessing(self):
from _numpypy import array, dtype, float64, int8, bool_
@@ -1364,36 +1312,12 @@
from _numpypy import array
a = array(range(5))
a[::-1] = a
- assert (a == [0, 1, 2, 1, 0]).all()
+ assert (a == [4, 3, 2, 1, 0]).all()
# but we force intermediates
a = array(range(5))
a[::-1] = a + a
assert (a == [8, 6, 4, 2, 0]).all()
- def test_debug_repr(self):
- from _numpypy import zeros, sin
- from _numpypy.pypy import debug_repr
- a = zeros(1)
- assert debug_repr(a) == 'Array'
- assert debug_repr(a + a) == 'Call2(add, Array, Array)'
- assert debug_repr(a[::2]) == 'Slice'
- assert debug_repr(a + 2) == 'Call2(add, Array, Scalar)'
- assert debug_repr(a + a.flat) == 'Call2(add, Array, Flat)'
- assert debug_repr(sin(a)) == 'Call1(sin, Array)'
-
- b = a + a
- b[0] = 3
- assert debug_repr(b) == 'Array'
-
- def test_remove_invalidates(self):
- from _numpypy import array
- from _numpypy.pypy import remove_invalidates
- a = array([1, 2, 3])
- b = a + a
- remove_invalidates(a)
- a[0] = 14
- assert b[0] == 28
-
def test_virtual_views(self):
from _numpypy import arange
a = arange(15)
@@ -1484,16 +1408,16 @@
f = concatenate((f1, [2], f1, [7]))
assert (f == [0,1,2,0,1,7]).all()
- bad_axis = raises(ValueError, concatenate, (a1,a2), axis=1)
- assert str(bad_axis.value) == "bad axis argument"
+ bad_axis = raises(IndexError, concatenate, (a1,a2), axis=1)
+ assert str(bad_axis.value) == "axis 1 out of bounds [0, 1)"
concat_zero = raises(ValueError, concatenate, ())
assert str(concat_zero.value) == \
- "concatenation of zero-length sequences is impossible"
+ "need at least one array to concatenate"
dims_disagree = raises(ValueError, concatenate, (a1, b1), axis=0)
assert str(dims_disagree.value) == \
- "array dimensions must agree except for axis being concatenated"
+ "all the input arrays must have same number of dimensions"
a = array([1, 2, 3, 4, 5, 6])
a = (a + a)[::2]
b = concatenate((a[:3], a[-3:]))
@@ -1586,6 +1510,7 @@
# test virtual
assert ((x + x).swapaxes(0,1) == array([[[ 2, 4, 6], [14, 16, 18]],
[[ 8, 10, 12], [20, 22, 24]]])).all()
+ assert array(1).swapaxes(10, 12) == 1
def test_filter_bug(self):
from numpypy import array
@@ -1655,18 +1580,6 @@
assert a[0][1][1] == 13
assert a[1][2][1] == 15
- def test_init_2(self):
- import _numpypy
- raises(ValueError, _numpypy.array, [[1], 2])
- raises(ValueError, _numpypy.array, [[1, 2], [3]])
- raises(ValueError, _numpypy.array, [[[1, 2], [3, 4], 5]])
- raises(ValueError, _numpypy.array, [[[1, 2], [3, 4], [5]]])
- a = _numpypy.array([[1, 2], [4, 5]])
- assert a[0, 1] == 2
- assert a[0][1] == 2
- a = _numpypy.array(([[[1, 2], [3, 4], [5, 6]]]))
- assert (a[0, 1] == [3, 4]).all()
-
def test_setitem_slice(self):
import _numpypy
a = _numpypy.zeros((3, 4))
@@ -1789,8 +1702,7 @@
a = zeros((4, 3, 2))
b = zeros((4, 2))
exc = raises(ValueError, lambda: a + b)
- assert str(exc.value) == "operands could not be broadcast" \
- " together with shapes (4,3,2) (4,2)"
+ assert str(exc.value).startswith("operands could not be broadcast")
def test_reduce(self):
from _numpypy import array
@@ -1799,6 +1711,7 @@
b = a[1:, 1::2]
c = b + b
assert c.sum() == (6 + 8 + 10 + 12) * 2
+ assert isinstance(c.sum(dtype='f8'), float)
def test_transpose(self):
from _numpypy import array
@@ -1860,6 +1773,8 @@
b.next()
b.next()
b.next()
+ assert b.index == 3
+ assert b.coords == (0, 3)
assert b[3] == 3
assert (b[::3] == [0, 3, 6, 9]).all()
assert (b[2::5] == [2, 7]).all()
@@ -1867,20 +1782,18 @@
raises(IndexError, "b[11]")
raises(IndexError, "b[-11]")
raises(IndexError, 'b[0, 1]')
- assert b.index == 3
- assert b.coords == (0,3)
+ assert b.index == 0
+ assert b.coords == (0, 0)
def test_flatiter_setitem(self):
from _numpypy import arange, array
a = arange(12).reshape(3,4)
b = a.T.flat
b[6::2] = [-1, -2]
- print a == [[0, 1, -1, 3], [4, 5, 6, -1], [8, 9, -2, 11]]
assert (a == [[0, 1, -1, 3], [4, 5, 6, -1], [8, 9, -2, 11]]).all()
b[0:2] = [[[100]]]
assert(a[0,0] == 100)
assert(a[1,0] == 100)
- raises(IndexError, 'b[array([10, 11])] == [-20, -40]')
def test_flatiter_ops(self):
from _numpypy import arange, array
@@ -1934,7 +1847,6 @@
a = a[::2]
i = a.__array_interface__
assert isinstance(i['data'][0], int)
- raises(TypeError, getattr, array(3), '__array_interface__')
def test_array_indexing_one_elem(self):
skip("not yet")
@@ -2006,12 +1918,6 @@
assert array(x, copy=False) is x
assert array(x, copy=True) is not x
- def test_isna(self):
- from _numpypy import isna, array
- # XXX for now
- assert not isna(3)
- assert (isna(array([1, 2, 3, 4])) == [False, False, False, False]).all()
-
def test_ravel(self):
from _numpypy import arange
assert (arange(3).ravel() == arange(3)).all()
@@ -2019,6 +1925,7 @@
assert (arange(6).reshape(2, 3).T.ravel() == [0, 3, 1, 4, 2, 5]).all()
def test_take(self):
+ skip("we wait for int-based indexing")
from _numpypy import arange
assert (arange(10).take([1, 2, 1, 1]) == [1, 2, 1, 1]).all()
raises(IndexError, "arange(3).take([15])")
@@ -2044,21 +1951,16 @@
assert type(array(3).item()) is int
assert type(array(True).item()) is bool
assert type(array(3.5).item()) is float
- raises((ValueError, IndexError), "array(3).item(15)")
- raises(ValueError, "array([1, 2, 3]).item()")
+ raises(IndexError, "array(3).item(15)")
+ raises(IndexError, "array([1, 2, 3]).item()")
assert array([3]).item(0) == 3
assert type(array([3]).item(0)) is int
assert array([1, 2, 3]).item(-1) == 3
a = array([1, 2, 3])
assert a[::2].item(1) == 3
assert (a + a).item(1) == 4
- raises(ValueError, "array(5).item(1)")
+ raises(IndexError, "array(5).item(1)")
assert array([1]).item() == 1
-
- def test_count_nonzero(self):
- from _numpypy import array
- a = array([1,0,5,0,10])
- assert a.count_nonzero() == 3
class AppTestSupport(BaseNumpyAppTest):
@@ -2127,7 +2029,7 @@
r = fromstring("\x01\x00\x02", dtype='bool')
assert (r == [True, False, True]).all()
s = fromstring("1,2,3,,5", dtype=bool, sep=",")
- assert (s == [True, True, True, False, True]).all()
+ assert (s == [True, True, True, True, True]).all()
t = fromstring("", bool)
assert (t == []).all()
u = fromstring("\x01\x00\x00\x00\x00\x00\x00\x00", dtype=int)
@@ -2241,8 +2143,8 @@
def test_views(self):
from _numpypy import array
a = array([(1, 2), (3, 4)], dtype=[('x', int), ('y', float)])
- raises(ValueError, 'array([1])["x"]')
- raises(ValueError, 'a["z"]')
+ raises((IndexError, ValueError), 'array([1])["x"]')
+ raises((IndexError, ValueError), 'a["z"]')
assert a['x'][1] == 3
assert a['y'][1] == 4
a['x'][0] = 15
@@ -2275,3 +2177,21 @@
assert arr[1]['y']['x'] == 0.0
assert arr[1]['x'] == 15
+class AppTestPyPy(BaseNumpyAppTest):
+ def setup_class(cls):
+ if option.runappdirect and '__pypy__' not in sys.builtin_module_names:
+ py.test.skip("pypy only test")
+ BaseNumpyAppTest.setup_class.im_func(cls)
+
+ def test_init_2(self):
+ # this test is pypy only since in numpy it becomes an object dtype
+ import _numpypy
+ raises(ValueError, _numpypy.array, [[1], 2])
+ raises(ValueError, _numpypy.array, [[1, 2], [3]])
+ raises(ValueError, _numpypy.array, [[[1, 2], [3, 4], 5]])
+ raises(ValueError, _numpypy.array, [[[1, 2], [3, 4], [5]]])
+ a = _numpypy.array([[1, 2], [4, 5]])
+ assert a[0, 1] == 2
+ assert a[0][1] == 2
+ a = _numpypy.array(([[[1, 2], [3, 4], [5, 6]]]))
+ assert (a[0, 1] == [3, 4]).all()
diff --git a/pypy/module/micronumpy/test/test_outarg.py b/pypy/module/micronumpy/test/test_outarg.py
--- a/pypy/module/micronumpy/test/test_outarg.py
+++ b/pypy/module/micronumpy/test/test_outarg.py
@@ -108,19 +108,6 @@
d = array([16, 16], dtype=int)
b = sum(d, out=c)
assert b == c
- try:
- from _numpypy import version
- v = version.version.split('.')
- except:
- v = ['1', '6', '0'] # numpypy is api compatable to what version?
- if v[0]<'2':
- b = negative(c, out=a)
- assert b == a
- b = add(c, c, out=a)
- assert b == a
- b = sum(array([16, 16], dtype=float), out=a)
- assert b == a
- else:
- cast_error = raises(TypeError, negative, c, a)
- assert str(cast_error.value) == \
- "Cannot cast ufunc negative output from dtype('float64') to dtype('int64') with casting rule 'same_kind'"
+ #cast_error = raises(TypeError, negative, c, a)
+ #assert str(cast_error.value) == \
+ # "Cannot cast ufunc negative output from dtype('float64') to dtype('int64') with casting rule 'same_kind'"
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
@@ -7,7 +7,7 @@
assert isinstance(add, ufunc)
assert repr(add) == "<ufunc 'add'>"
- assert repr(ufunc) == "<type 'numpypy.ufunc'>"
+ assert repr(ufunc) == "<type 'numpypy.ufunc'>" or repr(ufunc) == "<type 'numpy.ufunc'>"
def test_ufunc_attrs(self):
from _numpypy import add, multiply, sin
@@ -113,6 +113,7 @@
assert (divide(array([-10]), array([2])) == array([-5])).all()
def test_true_divide(self):
+ import math
from _numpypy import array, true_divide
a = array([0, 1, 2, 3, 4, 1, -1])
@@ -144,8 +145,8 @@
assert (fmax(a, [ninf]*5) == a).all()
assert (fmax(a, [inf]*5) == [inf]*5).all()
assert (fmax(a, [1]*5) == [1, 1, 1, 5, inf]).all()
- assert math.isnan(fmax(nan, 0))
- assert math.isnan(fmax(0, nan))
+ assert fmax(nan, 0) == 0
+ assert fmax(0, nan) == 0
assert math.isnan(fmax(nan, nan))
# The numpy docs specify that the FIRST NaN should be used if both are NaN
# Since comparisons with nnan and nan all return false,
@@ -164,8 +165,8 @@
assert (fmin(a, [ninf]*5) == [ninf]*5).all()
assert (fmin(a, [inf]*5) == a).all()
assert (fmin(a, [1]*5) == [ninf, -5, 0, 1, 1]).all()
- assert math.isnan(fmin(nan, 0))
- assert math.isnan(fmin(0, nan))
+ assert fmin(nan, 0) == 0
+ assert fmin(0, nan) == 0
assert math.isnan(fmin(nan, nan))
# The numpy docs specify that the FIRST NaN should be used if both are NaN
# use copysign on both sides to sidestep bug in nan representaion
@@ -227,11 +228,6 @@
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_signbit(self):
from _numpypy import signbit
@@ -345,7 +341,7 @@
assert b[i] == math.sin(a[i])
a = sin(array([True, False], dtype=bool))
- assert abs(a[0] - sin(1)) < 1e-7 # a[0] will be less precise
+ assert abs(a[0] - sin(1)) < 1e-3 # a[0] will be very imprecise
assert a[1] == 0.0
def test_cos(self):
@@ -557,7 +553,7 @@
from _numpypy import sin, add
raises(ValueError, sin.reduce, [1, 2, 3])
- raises((ValueError, TypeError), add.reduce, 1)
+ assert add.reduce(1) == 1
def test_reduce_1d(self):
from _numpypy import add, maximum, less
@@ -631,23 +627,16 @@
]:
assert ufunc(a, b) == func(a, b)
- def test_count_reduce_items(self):
- from _numpypy import count_reduce_items, arange
- a = arange(24).reshape(2, 3, 4)
- assert count_reduce_items(a) == 24
- assert count_reduce_items(a, 1) == 3
- assert count_reduce_items(a, (1, 2)) == 3 * 4
- raises(ValueError, count_reduce_items, a, -4)
- raises(ValueError, count_reduce_items, a, (0, 2, -4))
def test_count_nonzero(self):
- from _numpypy import where, count_nonzero, arange
- a = arange(10)
- assert count_nonzero(a) == 9
- a[9] = 0
- assert count_nonzero(a) == 8
+ from _numpypy import count_nonzero
+ assert count_nonzero(0) == 0
+ assert count_nonzero(1) == 1
+ assert count_nonzero([]) == 0
+ assert count_nonzero([1, 2, 0]) == 2
+ assert count_nonzero([[1, 2, 0], [1, 0, 2]]) == 4
- def test_true_divide(self):
+ def test_true_divide_2(self):
from _numpypy import arange, array, true_divide
assert (true_divide(arange(3), array([2, 2, 2])) == array([0, 0.5, 1])).all()
diff --git a/pypy/module/micronumpy/test/test_zjit.py b/pypy/module/micronumpy/test/test_zjit.py
--- a/pypy/module/micronumpy/test/test_zjit.py
+++ b/pypy/module/micronumpy/test/test_zjit.py
@@ -4,6 +4,7 @@
"""
import py
+py.test.skip("this is going away")
from pypy.jit.metainterp import pyjitpl
from pypy.jit.metainterp.test.support import LLJitMixin
diff --git a/pypy/module/micronumpy/test/test_ztranslation.py b/pypy/module/micronumpy/test/test_ztranslation.py
--- a/pypy/module/micronumpy/test/test_ztranslation.py
+++ b/pypy/module/micronumpy/test/test_ztranslation.py
@@ -1,8 +1,4 @@
-from pypy.module.micronumpy import signature
from pypy.objspace.fake.checkmodule import checkmodule
def test_numpy_translates():
- # XXX: If there are signatures floating around this might explode. This fix
- # is ugly.
- signature.known_sigs.clear()
checkmodule('micronumpy')
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
@@ -4,11 +4,12 @@
from pypy.interpreter.error import OperationError
from pypy.module.micronumpy import interp_boxes
+from pypy.module.micronumpy.arrayimpl.voidbox import VoidBoxStorage
from pypy.objspace.std.floatobject import float2string
from pypy.rlib import rfloat, clibffi
from pypy.rlib.rawstorage import (alloc_raw_storage, raw_storage_setitem,
raw_storage_getitem)
-from pypy.rlib.objectmodel import specialize, we_are_translated
+from pypy.rlib.objectmodel import specialize
from pypy.rlib.rarithmetic import widen, byteswap
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rlib.rstruct.runpack import runpack
@@ -279,7 +280,7 @@
return int(v)
def default_fromstring(self, space):
- return self.box(False)
+ return self.box(True)
@simple_binary_op
def bitwise_and(self, v1, v2):
@@ -616,17 +617,21 @@
@simple_binary_op
def fmax(self, v1, v2):
if math.isnan(v1):
+ if math.isnan(v2):
+ return v1
+ return v2
+ elif math.isnan(v2):
return v1
- elif math.isnan(v2):
- return v2
return max(v1, v2)
@simple_binary_op
def fmin(self, v1, v2):
if math.isnan(v1):
+ if math.isnan(v2):
+ return v1
+ return v2
+ elif math.isnan(v2):
return v1
- elif math.isnan(v2):
- return v2
return min(v1, v2)
@simple_binary_op
@@ -931,8 +936,6 @@
@jit.unroll_safe
def coerce(self, space, dtype, w_item):
- from pypy.module.micronumpy.interp_numarray import W_NDimArray
-
if isinstance(w_item, interp_boxes.W_VoidBox):
return w_item
# we treat every sequence as sequence, no special support
@@ -944,16 +947,14 @@
raise OperationError(space.w_ValueError, space.wrap(
"wrong length"))
items_w = space.fixedview(w_item)
- # XXX optimize it out one day, but for now we just allocate an
- # array
- arr = W_NDimArray([1], dtype)
+ arr = VoidBoxStorage(self.size, dtype)
for i in range(len(items_w)):
subdtype = dtype.fields[dtype.fieldnames[i]][1]
ofs, itemtype = self.offsets_and_fields[i]
w_item = items_w[i]
w_box = itemtype.coerce(space, subdtype, w_item)
itemtype.store(arr, 0, ofs, w_box)
- return interp_boxes.W_VoidBox(arr, 0, arr.dtype)
+ return interp_boxes.W_VoidBox(arr, 0, dtype)
@jit.unroll_safe
def store(self, arr, i, ofs, box):
diff --git a/pypy/rlib/rawstorage.py b/pypy/rlib/rawstorage.py
--- a/pypy/rlib/rawstorage.py
+++ b/pypy/rlib/rawstorage.py
@@ -3,10 +3,12 @@
from pypy.rpython.lltypesystem import lltype, rffi, llmemory
from pypy.annotation import model as annmodel
from pypy.rlib.rgc import lltype_is_gc
+from pypy.rlib.objectmodel import specialize
RAW_STORAGE = rffi.CCHARP.TO
RAW_STORAGE_PTR = rffi.CCHARP
+ at specialize.arg(1, 2)
def alloc_raw_storage(size, track_allocation=True, zero=False):
return lltype.malloc(RAW_STORAGE, size, flavor='raw',
add_memory_pressure=True,
@@ -22,6 +24,7 @@
TP = rffi.CArrayPtr(lltype.typeOf(item))
rffi.cast(TP, rffi.ptradd(storage, index))[0] = item
+ at specialize.arg(1)
def free_raw_storage(storage, track_allocation=True):
lltype.free(storage, flavor='raw', track_allocation=track_allocation)
More information about the pypy-commit
mailing list