summaryrefslogtreecommitdiff
path: root/numpy/lib
diff options
context:
space:
mode:
Diffstat (limited to 'numpy/lib')
-rw-r--r--numpy/lib/_iotools.py10
-rw-r--r--numpy/lib/arraypad.py10
-rw-r--r--numpy/lib/arraysetops.py19
-rw-r--r--numpy/lib/financial.py2
-rw-r--r--numpy/lib/format.py9
-rw-r--r--numpy/lib/function_base.py149
-rw-r--r--numpy/lib/index_tricks.py7
-rw-r--r--numpy/lib/nanfunctions.py6
-rw-r--r--numpy/lib/npyio.py45
-rw-r--r--numpy/lib/polynomial.py24
-rw-r--r--numpy/lib/setup.py1
-rw-r--r--numpy/lib/src/_compiled_base.c542
-rw-r--r--numpy/lib/stride_tricks.py28
-rw-r--r--numpy/lib/tests/test__iotools.py18
-rw-r--r--numpy/lib/tests/test_arraysetops.py6
-rw-r--r--numpy/lib/tests/test_format.py32
-rw-r--r--numpy/lib/tests/test_function_base.py72
-rw-r--r--numpy/lib/tests/test_io.py52
-rw-r--r--numpy/lib/tests/test_nanfunctions.py16
-rw-r--r--numpy/lib/tests/test_packbits.py26
-rw-r--r--numpy/lib/tests/test_polynomial.py11
-rw-r--r--numpy/lib/tests/test_stride_tricks.py46
-rw-r--r--numpy/lib/tests/test_twodim_base.py34
-rw-r--r--numpy/lib/twodim_base.py13
-rw-r--r--numpy/lib/utils.py158
25 files changed, 800 insertions, 536 deletions
diff --git a/numpy/lib/_iotools.py b/numpy/lib/_iotools.py
index 1b1180893..f2adcda10 100644
--- a/numpy/lib/_iotools.py
+++ b/numpy/lib/_iotools.py
@@ -27,6 +27,7 @@ else:
_bytes_to_complex = complex
_bytes_to_name = str
+
def _is_string_like(obj):
"""
Check whether obj behaves like a string.
@@ -37,6 +38,7 @@ def _is_string_like(obj):
return False
return True
+
def _is_bytes_like(obj):
"""
Check whether obj behaves like a bytes object.
@@ -445,6 +447,7 @@ class ConverterError(Exception):
"""
pass
+
class ConverterLockError(ConverterError):
"""
Exception raised when an attempt is made to upgrade a locked converter.
@@ -452,6 +455,7 @@ class ConverterLockError(ConverterError):
"""
pass
+
class ConversionWarning(UserWarning):
"""
Warning issued when a string converter has a problem.
@@ -687,7 +691,7 @@ class StringConverter(object):
def upgrade(self, value):
"""
- Rind the best converter for a given string, and return the result.
+ Find the best converter for a given string, and return the result.
The supplied string `value` is converted by testing different
converters in order. First the `func` method of the
@@ -708,7 +712,7 @@ class StringConverter(object):
"""
self._checked = True
try:
- self._strict_call(value)
+ return self._strict_call(value)
except ValueError:
# Raise an exception if we locked the converter...
if self._locked:
@@ -728,7 +732,7 @@ class StringConverter(object):
self.default = self._initial_default
else:
self.default = default
- self.upgrade(value)
+ return self.upgrade(value)
def iterupgrade(self, value):
self._checked = True
diff --git a/numpy/lib/arraypad.py b/numpy/lib/arraypad.py
index bbfdce794..a48199a82 100644
--- a/numpy/lib/arraypad.py
+++ b/numpy/lib/arraypad.py
@@ -1105,7 +1105,7 @@ def pad(array, pad_width, mode=None, **kwargs):
((before, after),) yields same before and after pad for each axis.
(pad,) or int is a shortcut for before = after = pad width for all
axes.
- mode : {str, function}
+ mode : str or function
One of the following string values or a user supplied function.
'constant'
@@ -1140,7 +1140,7 @@ def pad(array, pad_width, mode=None, **kwargs):
end values are used to pad the beginning.
<function>
Padding function, see Notes.
- stat_length : {sequence, int}, optional
+ stat_length : sequence or int, optional
Used in 'maximum', 'mean', 'median', and 'minimum'. Number of
values at edge of each axis used to calculate the statistic value.
@@ -1154,7 +1154,7 @@ def pad(array, pad_width, mode=None, **kwargs):
length for all axes.
Default is ``None``, to use the entire axis.
- constant_values : {sequence, int}, optional
+ constant_values : sequence or int, optional
Used in 'constant'. The values to set the padded values for each
axis.
@@ -1168,7 +1168,7 @@ def pad(array, pad_width, mode=None, **kwargs):
all axes.
Default is 0.
- end_values : {sequence, int}, optional
+ end_values : sequence or int, optional
Used in 'linear_ramp'. The values used for the ending value of the
linear_ramp and that will form the edge of the padded array.
@@ -1182,7 +1182,7 @@ def pad(array, pad_width, mode=None, **kwargs):
all axes.
Default is 0.
- reflect_type : str {'even', 'odd'}, optional
+ reflect_type : {'even', 'odd'}, optional
Used in 'reflect', and 'symmetric'. The 'even' style is the
default with an unaltered reflection around the edge value. For
the 'odd' style, the extented part of the array is created by
diff --git a/numpy/lib/arraysetops.py b/numpy/lib/arraysetops.py
index 2d98c35d2..d3b6119f4 100644
--- a/numpy/lib/arraysetops.py
+++ b/numpy/lib/arraysetops.py
@@ -204,8 +204,9 @@ def unique(ar, return_index=False, return_inverse=False, return_counts=False):
ret += (perm[flag],)
if return_inverse:
iflag = np.cumsum(flag) - 1
- iperm = perm.argsort()
- ret += (np.take(iflag, iperm),)
+ inv_idx = np.empty(ar.shape, dtype=np.intp)
+ inv_idx[perm] = iflag
+ ret += (inv_idx,)
if return_counts:
idx = np.concatenate(np.nonzero(flag) + ([ar.size],))
ret += (np.diff(idx),)
@@ -240,6 +241,11 @@ def intersect1d(ar1, ar2, assume_unique=False):
>>> np.intersect1d([1, 3, 4, 3], [3, 1, 2, 1])
array([1, 3])
+ To intersect more than two arrays, use functools.reduce:
+
+ >>> from functools import reduce
+ >>> reduce(np.intersect1d, ([1, 3, 4, 3], [3, 1, 2, 1], [6, 3, 4, 2]))
+ array([3])
"""
if not assume_unique:
# Might be faster than unique( intersect1d( ar1, ar2 ) )?
@@ -332,6 +338,10 @@ def in1d(ar1, ar2, assume_unique=False, invert=False):
`in1d` can be considered as an element-wise function version of the
python keyword `in`, for 1-D sequences. ``in1d(a, b)`` is roughly
equivalent to ``np.array([item in b for item in a])``.
+ However, this idea fails if `ar2` is a set, or similar (non-sequence)
+ container: As ``ar2`` is converted to an array, in those cases
+ ``asarray(ar2)`` is an object array rather than the expected array of
+ contained values.
.. versionadded:: 1.4.0
@@ -416,6 +426,11 @@ def union1d(ar1, ar2):
>>> np.union1d([-1, 0, 1], [-2, 0, 2])
array([-2, -1, 0, 1, 2])
+ To find the union of more than two arrays, use functools.reduce:
+
+ >>> from functools import reduce
+ >>> reduce(np.union1d, ([1, 3, 4, 3], [3, 1, 2, 1], [6, 3, 4, 2]))
+ array([1, 2, 3, 4, 6])
"""
return unique(np.concatenate((ar1, ar2)))
diff --git a/numpy/lib/financial.py b/numpy/lib/financial.py
index 5b96e5b8e..baff8b0b6 100644
--- a/numpy/lib/financial.py
+++ b/numpy/lib/financial.py
@@ -148,7 +148,7 @@ def pmt(rate, nper, pv, fv=0, when='end'):
Number of compounding periods
pv : array_like
Present value
- fv : array_like (optional)
+ fv : array_like, optional
Future value (default = 0)
when : {{'begin', 1}, {'end', 0}}, {string, int}
When payments are due ('begin' (1) or 'end' (0))
diff --git a/numpy/lib/format.py b/numpy/lib/format.py
index 7c8dfbafa..67da0d6d1 100644
--- a/numpy/lib/format.py
+++ b/numpy/lib/format.py
@@ -35,7 +35,7 @@ Capabilities
- Is straightforward to reverse engineer. Datasets often live longer than
the programs that created them. A competent developer should be
- able to create a solution in his preferred programming language to
+ able to create a solution in their preferred programming language to
read most ``.npy`` files that he has been given without much
documentation.
@@ -298,7 +298,8 @@ def _write_array_header(fp, d, version=None):
# can take advantage of our premature optimization.
current_header_len = MAGIC_LEN + 2 + len(header) + 1 # 1 for the newline
topad = 16 - (current_header_len % 16)
- header = asbytes(header + ' '*topad + '\n')
+ header = header + ' '*topad + '\n'
+ header = asbytes(_filter_header(header))
if len(header) >= (256*256) and version == (1, 0):
raise ValueError("header does not fit inside %s bytes required by the"
@@ -433,7 +434,7 @@ def _filter_header(s):
from io import StringIO
else:
from StringIO import StringIO
-
+
tokens = []
last_token_was_number = False
for token in tokenize.generate_tokens(StringIO(asstr(s)).read):
@@ -448,7 +449,7 @@ def _filter_header(s):
last_token_was_number = (token_type == tokenize.NUMBER)
return tokenize.untokenize(tokens)
-
+
def _read_array_header(fp, version):
"""
see read_array_header_1_0
diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py
index 0a1d05f77..135053e43 100644
--- a/numpy/lib/function_base.py
+++ b/numpy/lib/function_base.py
@@ -263,7 +263,7 @@ def histogramdd(sample, bins=10, range=None, normed=False, weights=None):
normed : bool, optional
If False, returns the number of samples in each bin. If True,
returns the bin density ``bin_count / sample_count / bin_volume``.
- weights : array_like (N,), optional
+ weights : (N,) array_like, optional
An array of values `w_i` weighing each sample `(x_i, y_i, z_i, ...)`.
Weights are normalized to 1 if normed is True. If normed is False,
the values of the returned histogram are equal to the sum of the
@@ -337,6 +337,11 @@ def histogramdd(sample, bins=10, range=None, normed=False, weights=None):
smin[i] = smin[i] - .5
smax[i] = smax[i] + .5
+ # avoid rounding issues for comparisons when dealing with inexact types
+ if np.issubdtype(sample.dtype, np.inexact):
+ edge_dt = sample.dtype
+ else:
+ edge_dt = float
# Create edge arrays
for i in arange(D):
if isscalar(bins[i]):
@@ -345,9 +350,9 @@ def histogramdd(sample, bins=10, range=None, normed=False, weights=None):
"Element at index %s in `bins` should be a positive "
"integer." % i)
nbin[i] = bins[i] + 2 # +2 for outlier bins
- edges[i] = linspace(smin[i], smax[i], nbin[i]-1)
+ edges[i] = linspace(smin[i], smax[i], nbin[i]-1, dtype=edge_dt)
else:
- edges[i] = asarray(bins[i], float)
+ edges[i] = asarray(bins[i], edge_dt)
nbin[i] = len(edges[i]) + 1 # +1 for outlier bins
dedges[i] = diff(edges[i])
if np.any(np.asarray(dedges[i]) <= 0):
@@ -456,7 +461,7 @@ def average(a, axis=None, weights=None, returned=False):
Returns
-------
- average, [sum_of_weights] : {array_type, double}
+ average, [sum_of_weights] : array_type or double
Return the average along the specified axis. When returned is `True`,
return a tuple with the average as the first element and the sum
of the weights as the second element. The return type is `Float`
@@ -510,8 +515,7 @@ def average(a, axis=None, weights=None, returned=False):
scl = avg.dtype.type(a.size/avg.size)
else:
a = a + 0.0
- wgt = np.array(weights, dtype=a.dtype, copy=0)
-
+ wgt = np.asarray(weights)
# Sanity checks
if a.shape != wgt.shape:
if axis is None:
@@ -528,7 +532,7 @@ def average(a, axis=None, weights=None, returned=False):
# setup wgt to broadcast along axis
wgt = np.array(wgt, copy=0, ndmin=a.ndim).swapaxes(-1, axis)
- scl = wgt.sum(axis=axis)
+ scl = wgt.sum(axis=axis, dtype=np.result_type(a.dtype, wgt.dtype))
if (scl == 0.0).any():
raise ZeroDivisionError(
"Weights sum to zero, can't be normalized")
@@ -878,28 +882,33 @@ def copy(a, order='K'):
# Basic operations
-def gradient(f, *varargs):
+def gradient(f, *varargs, **kwargs):
"""
Return the gradient of an N-dimensional array.
The gradient is computed using second order accurate central differences
- in the interior and second order accurate one-sides (forward or backwards)
- differences at the boundaries. The returned gradient hence has the same
- shape as the input array.
+ in the interior and either first differences or second order accurate
+ one-sides (forward or backwards) differences at the boundaries. The
+ returned gradient hence has the same shape as the input array.
Parameters
----------
f : array_like
- An N-dimensional array containing samples of a scalar function.
- `*varargs` : scalars
- 0, 1, or N scalars specifying the sample distances in each direction,
- that is: `dx`, `dy`, `dz`, ... The default distance is 1.
+ An N-dimensional array containing samples of a scalar function.
+ varargs : list of scalar, optional
+ N scalars specifying the sample distances for each dimension,
+ i.e. `dx`, `dy`, `dz`, ... Default distance: 1.
+ edge_order : {1, 2}, optional
+ Gradient is calculated using N\ :sup:`th` order accurate differences
+ at the boundaries. Default: 1.
+
+ .. versionadded:: 1.9.1
Returns
-------
gradient : ndarray
- N arrays of the same shape as `f` giving the derivative of `f` with
- respect to each dimension.
+ N arrays of the same shape as `f` giving the derivative of `f` with
+ respect to each dimension.
Examples
--------
@@ -911,15 +920,14 @@ def gradient(f, *varargs):
>>> np.gradient(np.array([[1, 2, 6], [3, 4, 5]], dtype=np.float))
[array([[ 2., 2., -1.],
- [ 2., 2., -1.]]),
- array([[ 1. , 2.5, 4. ],
- [ 1. , 1. , 1. ]])]
+ [ 2., 2., -1.]]), array([[ 1. , 2.5, 4. ],
+ [ 1. , 1. , 1. ]])]
- >>> x = np.array([0,1,2,3,4])
- >>> dx = gradient(x)
+ >>> x = np.array([0, 1, 2, 3, 4])
+ >>> dx = np.gradient(x)
>>> y = x**2
- >>> gradient(y,dx)
- array([0., 2., 4., 6., 8.])
+ >>> np.gradient(y, dx, edge_order=2)
+ array([-0., 2., 4., 6., 8.])
"""
f = np.asanyarray(f)
N = len(f.shape) # number of dimensions
@@ -934,6 +942,13 @@ def gradient(f, *varargs):
raise SyntaxError(
"invalid number of arguments")
+ edge_order = kwargs.pop('edge_order', 1)
+ if kwargs:
+ raise TypeError('"{}" are not valid keyword arguments.'.format(
+ '", "'.join(kwargs.keys())))
+ if edge_order > 2:
+ raise ValueError("'edge_order' greater than 2 not supported")
+
# use central differences on interior and one-sided differences on the
# endpoints. This preserves second order-accuracy over the full domain.
@@ -973,7 +988,7 @@ def gradient(f, *varargs):
"at least two elements are required.")
# Numerical differentiation: 1st order edges, 2nd order interior
- if y.shape[axis] == 2:
+ if y.shape[axis] == 2 or edge_order == 1:
# Use first order differences for time data
out = np.empty_like(y, dtype=otype)
@@ -1021,7 +1036,8 @@ def gradient(f, *varargs):
out[slice1] = (3.0*y[slice2] - 4.0*y[slice3] + y[slice4])/2.0
# divide by step size
- outvals.append(out / dx[axis])
+ out /= dx[axis]
+ outvals.append(out)
# reset the slice object in this dimension to ":"
slice1[axis] = slice(None)
@@ -1097,7 +1113,7 @@ def diff(a, n=1, axis=-1):
return a[slice1]-a[slice2]
-def interp(x, xp, fp, left=None, right=None):
+def interp(x, xp, fp, left=None, right=None, period=None):
"""
One-dimensional linear interpolation.
@@ -1110,7 +1126,9 @@ def interp(x, xp, fp, left=None, right=None):
The x-coordinates of the interpolated values.
xp : 1-D sequence of floats
- The x-coordinates of the data points, must be increasing.
+ The x-coordinates of the data points, must be increasing if argument
+ `period` is not specified. Otherwise, `xp` is internally sorted after
+ normalizing the periodic boundaries with ``xp = xp % period``.
fp : 1-D sequence of floats
The y-coordinates of the data points, same length as `xp`.
@@ -1121,15 +1139,23 @@ def interp(x, xp, fp, left=None, right=None):
right : float, optional
Value to return for `x > xp[-1]`, default is `fp[-1]`.
+ period : None or float, optional
+ .. versionadded:: 1.10.0
+ A period for the x-coordinates. This parameter allows the proper
+ interpolation of angular x-coordinates. Parameters `left` and `right`
+ are ignored if `period` is specified.
+
Returns
-------
- y : {float, ndarray}
+ y : float or ndarray
The interpolated values, same shape as `x`.
Raises
------
ValueError
If `xp` and `fp` have different length
+ If `xp` or `fp` are not 1-D sequences
+ If `period == 0`
Notes
-----
@@ -1139,7 +1165,6 @@ def interp(x, xp, fp, left=None, right=None):
np.all(np.diff(xp) > 0)
-
Examples
--------
>>> xp = [1, 2, 3]
@@ -1165,13 +1190,51 @@ def interp(x, xp, fp, left=None, right=None):
[<matplotlib.lines.Line2D object at 0x...>]
>>> plt.show()
+ Interpolation with periodic x-coordinates:
+
+ >>> x = [-180, -170, -185, 185, -10, -5, 0, 365]
+ >>> xp = [190, -190, 350, -350]
+ >>> fp = [5, 10, 3, 4]
+ >>> np.interp(x, xp, fp, period=360)
+ array([7.5, 5., 8.75, 6.25, 3., 3.25, 3.5, 3.75])
+
"""
- if isinstance(x, (float, int, number)):
- return compiled_interp([x], xp, fp, left, right).item()
- elif isinstance(x, np.ndarray) and x.ndim == 0:
- return compiled_interp([x], xp, fp, left, right).item()
+ if period is None:
+ if isinstance(x, (float, int, number)):
+ return compiled_interp([x], xp, fp, left, right).item()
+ elif isinstance(x, np.ndarray) and x.ndim == 0:
+ return compiled_interp([x], xp, fp, left, right).item()
+ else:
+ return compiled_interp(x, xp, fp, left, right)
else:
- return compiled_interp(x, xp, fp, left, right)
+ if period == 0:
+ raise ValueError("period must be a non-zero value")
+ period = abs(period)
+ left = None
+ right = None
+ return_array = True
+ if isinstance(x, (float, int, number)):
+ return_array = False
+ x = [x]
+ x = np.asarray(x, dtype=np.float64)
+ xp = np.asarray(xp, dtype=np.float64)
+ fp = np.asarray(fp, dtype=np.float64)
+ if xp.ndim != 1 or fp.ndim != 1:
+ raise ValueError("Data points must be 1-D sequences")
+ if xp.shape[0] != fp.shape[0]:
+ raise ValueError("fp and xp are not of the same length")
+ # normalizing periodic boundaries
+ x = x % period
+ xp = xp % period
+ asort_xp = np.argsort(xp)
+ xp = xp[asort_xp]
+ fp = fp[asort_xp]
+ xp = np.concatenate((xp[-1:]-period, xp, xp[0:1]+period))
+ fp = np.concatenate((fp[-1:], fp, fp[0:1]))
+ if return_array:
+ return compiled_interp(x, xp, fp, left, right)
+ else:
+ return compiled_interp(x, xp, fp, left, right).item()
def angle(z, deg=0):
@@ -1187,7 +1250,7 @@ def angle(z, deg=0):
Returns
-------
- angle : {ndarray, scalar}
+ angle : ndarray or scalar
The counterclockwise angle from the positive real axis on
the complex plane, with dtype as numpy.float64.
@@ -1387,6 +1450,8 @@ def extract(condition, arr):
This is equivalent to ``np.compress(ravel(condition), ravel(arr))``. If
`condition` is boolean ``np.extract`` is equivalent to ``arr[condition]``.
+ Note that `place` does the exact opposite of `extract`.
+
Parameters
----------
condition : array_like
@@ -1402,7 +1467,7 @@ def extract(condition, arr):
See Also
--------
- take, put, copyto, compress
+ take, put, copyto, compress, place
Examples
--------
@@ -1915,7 +1980,7 @@ def corrcoef(x, y=None, rowvar=1, bias=0, ddof=None):
observations (unbiased estimate). If `bias` is 1, then
normalization is by ``N``. These values can be overridden by using
the keyword ``ddof`` in numpy versions >= 1.5.
- ddof : {None, int}, optional
+ ddof : int, optional
.. versionadded:: 1.5
If not ``None`` normalization is by ``(N - ddof)``, where ``N`` is
the number of observations; this overrides the value implied by
@@ -2998,7 +3063,7 @@ def percentile(a, q, axis=None, out=None,
nearest neighbors as well as the `interpolation` parameter will
determine the percentile if the normalized ranking does not match q
exactly. This function is the same as the median if ``q=50``, the same
- as the minimum if ``q=0``and the same as the maximum if ``q=100``.
+ as the minimum if ``q=0`` and the same as the maximum if ``q=100``.
Examples
--------
@@ -3031,7 +3096,7 @@ def percentile(a, q, axis=None, out=None,
array([ 3.5])
"""
- q = asarray(q, dtype=np.float64)
+ q = array(q, dtype=np.float64, copy=True)
r, k = _ureduce(a, func=_percentile, q=q, axis=axis, out=out,
overwrite_input=overwrite_input,
interpolation=interpolation)
@@ -3758,7 +3823,9 @@ def insert(arr, obj, values, axis=None):
if (index < 0):
index += N
- values = array(values, copy=False, ndmin=arr.ndim)
+ # There are some object array corner cases here, but we cannot avoid
+ # that:
+ values = array(values, copy=False, ndmin=arr.ndim, dtype=arr.dtype)
if indices.ndim == 0:
# broadcasting is very different here, since a[:,0,:] = ... behaves
# very different from a[:,[0],:] = ...! This changes values so that
diff --git a/numpy/lib/index_tricks.py b/numpy/lib/index_tricks.py
index 98c6b291b..f83024961 100644
--- a/numpy/lib/index_tricks.py
+++ b/numpy/lib/index_tricks.py
@@ -727,6 +727,7 @@ def fill_diagonal(a, val, wrap=False):
# tall matrices no wrap
>>> a = np.zeros((5, 3),int)
>>> fill_diagonal(a, 4)
+ >>> a
array([[4, 0, 0],
[0, 4, 0],
[0, 0, 4],
@@ -735,7 +736,8 @@ def fill_diagonal(a, val, wrap=False):
# tall matrices wrap
>>> a = np.zeros((5, 3),int)
- >>> fill_diagonal(a, 4)
+ >>> fill_diagonal(a, 4, wrap=True)
+ >>> a
array([[4, 0, 0],
[0, 4, 0],
[0, 0, 4],
@@ -744,7 +746,8 @@ def fill_diagonal(a, val, wrap=False):
# wide matrices
>>> a = np.zeros((3, 5),int)
- >>> fill_diagonal(a, 4)
+ >>> fill_diagonal(a, 4, wrap=True)
+ >>> a
array([[4, 0, 0, 0, 0],
[0, 4, 0, 0, 0],
[0, 0, 4, 0, 0]])
diff --git a/numpy/lib/nanfunctions.py b/numpy/lib/nanfunctions.py
index f5ac35e54..7260a35b8 100644
--- a/numpy/lib/nanfunctions.py
+++ b/numpy/lib/nanfunctions.py
@@ -33,6 +33,10 @@ def _replace_nan(a, val):
marking the locations where NaNs were present. If `a` is not of
inexact type, do nothing and return `a` together with a mask of None.
+ Note that scalars will end up as array scalars, which is important
+ for using the result as the value of the out argument in some
+ operations.
+
Parameters
----------
a : array-like
@@ -1037,7 +1041,7 @@ def nanvar(a, axis=None, dtype=None, out=None, ddof=0, keepdims=False):
avg = _divide_by_count(avg, cnt)
# Compute squared deviation from mean.
- arr -= avg
+ np.subtract(arr, avg, out=arr, casting='unsafe')
arr = _copyto(arr, 0, mask)
if issubclass(arr.dtype.type, np.complexfloating):
sqr = np.multiply(arr, arr.conj(), out=arr).real
diff --git a/numpy/lib/npyio.py b/numpy/lib/npyio.py
index fe855a71a..5f274f27c 100644
--- a/numpy/lib/npyio.py
+++ b/numpy/lib/npyio.py
@@ -123,6 +123,14 @@ class BagObj(object):
except KeyError:
raise AttributeError(key)
+ def __dir__(self):
+ """
+ Enables dir(bagobj) to list the files in an NpzFile.
+
+ This also enables tab-completion in an interpreter or IPython.
+ """
+ return object.__getattribute__(self, '_obj').keys()
+
def zipfile_factory(*args, **kwargs):
import zipfile
@@ -288,8 +296,7 @@ def load(file, mmap_mode=None):
Parameters
----------
file : file-like object or string
- The file to read. Compressed files with the filename extension
- ``.gz`` are acceptable. File-like objects must support the
+ The file to read. File-like objects must support the
``seek()`` and ``read()`` methods. Pickled files require that the
file-like object support the ``readline()`` method as well.
mmap_mode : {None, 'r+', 'r', 'w+', 'c'}, optional
@@ -425,7 +432,9 @@ def save(file, arr):
Notes
-----
- For a description of the ``.npy`` format, see `format`.
+ For a description of the ``.npy`` format, see the module docstring
+ of `numpy.lib.format` or the Numpy Enhancement Proposal
+ http://docs.scipy.org/doc/numpy/neps/npy-format.html
Examples
--------
@@ -496,7 +505,9 @@ def savez(file, *args, **kwds):
The ``.npz`` file format is a zipped archive of files named after the
variables they contain. The archive is not compressed and each file
in the archive contains one variable in ``.npy`` format. For a
- description of the ``.npy`` format, see `format`.
+ description of the ``.npy`` format, see `numpy.lib.format` or the
+ Numpy Enhancement Proposal
+ http://docs.scipy.org/doc/numpy/neps/npy-format.html
When opening the saved ``.npz`` file with `load` a `NpzFile` object is
returned. This is a dictionary-like object which can be queried for
@@ -1081,7 +1092,12 @@ def savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='\n', header='',
fh.write(asbytes(format % tuple(row2) + newline))
else:
for row in X:
- fh.write(asbytes(format % tuple(row) + newline))
+ try:
+ fh.write(asbytes(format % tuple(row) + newline))
+ except TypeError:
+ raise TypeError("Mismatch between array dtype ('%s') and "
+ "format specifier ('%s')"
+ % (str(X.dtype), format))
if len(footer) > 0:
footer = footer.replace('\n', '\n' + comments)
fh.write(asbytes(comments + footer + newline))
@@ -1519,7 +1535,9 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None,
# Process the filling_values ...............................
# Rename the input for convenience
- user_filling_values = filling_values or []
+ user_filling_values = filling_values
+ if user_filling_values is None:
+ user_filling_values = []
# Define the default
filling_values = [None] * nbcols
# We have a dictionary : update each entry individually
@@ -1574,22 +1592,25 @@ def genfromtxt(fname, dtype=float, comments='#', delimiter=None,
for (miss, fill) in zipit]
# Update the converters to use the user-defined ones
uc_update = []
- for (i, conv) in user_converters.items():
+ for (j, conv) in user_converters.items():
# If the converter is specified by column names, use the index instead
- if _is_string_like(i):
+ if _is_string_like(j):
try:
- i = names.index(i)
+ j = names.index(j)
+ i = j
except ValueError:
continue
elif usecols:
try:
- i = usecols.index(i)
+ i = usecols.index(j)
except ValueError:
# Unused converter specified
continue
- # Find the value to test:
+ else:
+ i = j
+ # Find the value to test - first_line is not filtered by usecols:
if len(first_line):
- testing_value = first_values[i]
+ testing_value = first_values[j]
else:
testing_value = None
converters[i].update(conv, locked=True,
diff --git a/numpy/lib/polynomial.py b/numpy/lib/polynomial.py
index 6a1adc773..de9376300 100644
--- a/numpy/lib/polynomial.py
+++ b/numpy/lib/polynomial.py
@@ -12,10 +12,11 @@ import re
import warnings
import numpy.core.numeric as NX
-from numpy.core import isscalar, abs, finfo, atleast_1d, hstack, dot
+from numpy.core import (isscalar, abs, finfo, atleast_1d, hstack, dot, array,
+ ones)
from numpy.lib.twodim_base import diag, vander
from numpy.lib.function_base import trim_zeros, sort_complex
-from numpy.lib.type_check import iscomplex, real, imag
+from numpy.lib.type_check import iscomplex, real, imag, mintypecode
from numpy.linalg import eigvals, lstsq, inv
class RankWarning(UserWarning):
@@ -122,19 +123,24 @@ def poly(seq_of_zeros):
"""
seq_of_zeros = atleast_1d(seq_of_zeros)
sh = seq_of_zeros.shape
+
if len(sh) == 2 and sh[0] == sh[1] and sh[0] != 0:
seq_of_zeros = eigvals(seq_of_zeros)
elif len(sh) == 1:
- pass
+ dt = seq_of_zeros.dtype
+ # Let object arrays slip through, e.g. for arbitrary precision
+ if dt != object:
+ seq_of_zeros = seq_of_zeros.astype(mintypecode(dt.char))
else:
raise ValueError("input must be 1d or non-empty square 2d array.")
if len(seq_of_zeros) == 0:
return 1.0
-
- a = [1]
+ dt = seq_of_zeros.dtype
+ a = ones((1,), dtype=dt)
for k in range(len(seq_of_zeros)):
- a = NX.convolve(a, [1, -seq_of_zeros[k]], mode='full')
+ a = NX.convolve(a, array([1, -seq_of_zeros[k]], dtype=dt),
+ mode='full')
if issubclass(a.dtype.type, NX.complexfloating):
# if complex roots are all complex conjugates, the roots are real.
@@ -247,12 +253,12 @@ def polyint(p, m=1, k=None):
Parameters
----------
- p : {array_like, poly1d}
+ p : array_like or poly1d
Polynomial to differentiate.
A sequence is interpreted as polynomial coefficients, see `poly1d`.
m : int, optional
Order of the antiderivative. (Default: 1)
- k : {None, list of `m` scalars, scalar}, optional
+ k : list of `m` scalars or scalar, optional
Integration constants. They are given in the order of integration:
those corresponding to highest-order terms come first.
@@ -671,7 +677,7 @@ def polyval(p, x):
x = NX.asarray(x)
y = NX.zeros_like(x)
for i in range(len(p)):
- y = x * y + p[i]
+ y = y * x + p[i]
return y
def polyadd(a1, a2):
diff --git a/numpy/lib/setup.py b/numpy/lib/setup.py
index 68d99c33a..62d1dfbb8 100644
--- a/numpy/lib/setup.py
+++ b/numpy/lib/setup.py
@@ -13,7 +13,6 @@ def configuration(parent_package='',top_path=None):
sources=[join('src', '_compiled_base.c')]
)
- config.add_data_dir('benchmarks')
config.add_data_dir('tests')
return config
diff --git a/numpy/lib/src/_compiled_base.c b/numpy/lib/src/_compiled_base.c
index a461613e3..9d9344526 100644
--- a/numpy/lib/src/_compiled_base.c
+++ b/numpy/lib/src/_compiled_base.c
@@ -1,64 +1,13 @@
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
-#include "Python.h"
-#include "structmember.h"
+#include <Python.h>
+#include <structmember.h>
+#include <string.h>
+
#include "numpy/arrayobject.h"
#include "numpy/npy_3kcompat.h"
#include "npy_config.h"
#include "numpy/ufuncobject.h"
-#include "string.h"
-
-
-static npy_intp
-incr_slot_(double x, double *bins, npy_intp lbins)
-{
- npy_intp i;
-
- for ( i = 0; i < lbins; i ++ ) {
- if ( x < bins [i] ) {
- return i;
- }
- }
- return lbins;
-}
-
-static npy_intp
-decr_slot_(double x, double * bins, npy_intp lbins)
-{
- npy_intp i;
-
- for ( i = lbins - 1; i >= 0; i -- ) {
- if (x < bins [i]) {
- return i + 1;
- }
- }
- return 0;
-}
-
-static npy_intp
-incr_slot_right_(double x, double *bins, npy_intp lbins)
-{
- npy_intp i;
-
- for ( i = 0; i < lbins; i ++ ) {
- if ( x <= bins [i] ) {
- return i;
- }
- }
- return lbins;
-}
-static npy_intp
-decr_slot_right_(double x, double * bins, npy_intp lbins)
-{
- npy_intp i;
-
- for ( i = lbins - 1; i >= 0; i -- ) {
- if (x <= bins [i]) {
- return i + 1;
- }
- }
- return 0;
-}
/*
* Returns -1 if the array is monotonic decreasing,
@@ -125,6 +74,7 @@ minmax(const npy_intp *data, npy_intp data_len, npy_intp *mn, npy_intp *mx)
*mn = min;
*mx = max;
}
+
/*
* arr_bincount is registered as bincount.
*
@@ -244,143 +194,111 @@ fail:
return NULL;
}
-
/*
- * digitize (x, bins, right=False) returns an array of python integers the same
- * length of x. The values i returned are such that bins [i - 1] <= x <
- * bins [i] if bins is monotonically increasing, or bins [i - 1] > x >=
- * bins [i] if bins is monotonically decreasing. Beyond the bounds of
- * bins, returns either i = 0 or i = len (bins) as appropriate.
- * if right == True the comparison is bins [i - 1] < x <= bins[i]
- * or bins [i - 1] >= x > bins[i]
+ * digitize(x, bins, right=False) returns an array of integers the same length
+ * as x. The values i returned are such that bins[i - 1] <= x < bins[i] if
+ * bins is monotonically increasing, or bins[i - 1] > x >= bins[i] if bins
+ * is monotonically decreasing. Beyond the bounds of bins, returns either
+ * i = 0 or i = len(bins) as appropriate. If right == True the comparison
+ * is bins [i - 1] < x <= bins[i] or bins [i - 1] >= x > bins[i]
*/
static PyObject *
arr_digitize(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)
{
- /* self is not used */
- PyObject *ox, *obins;
- PyArrayObject *ax = NULL, *abins = NULL, *aret = NULL;
- double *dx, *dbins;
- npy_intp lbins, lx; /* lengths */
- npy_intp right = 0; /* whether right or left is inclusive */
- npy_intp *iret;
- int m, i;
+ PyObject *obj_x = NULL;
+ PyObject *obj_bins = NULL;
+ PyArrayObject *arr_x = NULL;
+ PyArrayObject *arr_bins = NULL;
+ PyObject *ret = NULL;
+ npy_intp len_bins;
+ int monotonic, right = 0;
+ NPY_BEGIN_THREADS_DEF
+
static char *kwlist[] = {"x", "bins", "right", NULL};
- PyArray_Descr *type;
- char bins_non_monotonic = 0;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|i", kwlist, &ox, &obins,
- &right)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|i", kwlist,
+ &obj_x, &obj_bins, &right)) {
goto fail;
}
- type = PyArray_DescrFromType(NPY_DOUBLE);
- ax = (PyArrayObject *)PyArray_FromAny(ox, type,
- 1, 1, NPY_ARRAY_CARRAY, NULL);
- if (ax == NULL) {
+
+ /* PyArray_SearchSorted will make `x` contiguous even if we don't */
+ arr_x = (PyArrayObject *)PyArray_FROMANY(obj_x, NPY_DOUBLE, 0, 0,
+ NPY_ARRAY_CARRAY_RO);
+ if (arr_x == NULL) {
goto fail;
}
- Py_INCREF(type);
- abins = (PyArrayObject *)PyArray_FromAny(obins, type,
- 1, 1, NPY_ARRAY_CARRAY, NULL);
- if (abins == NULL) {
+
+ /* TODO: `bins` could be strided, needs change to check_array_monotonic */
+ arr_bins = (PyArrayObject *)PyArray_FROMANY(obj_bins, NPY_DOUBLE, 1, 1,
+ NPY_ARRAY_CARRAY_RO);
+ if (arr_bins == NULL) {
goto fail;
}
- lx = PyArray_SIZE(ax);
- dx = (double *)PyArray_DATA(ax);
- lbins = PyArray_SIZE(abins);
- dbins = (double *)PyArray_DATA(abins);
- aret = (PyArrayObject *)PyArray_SimpleNew(1, &lx, NPY_INTP);
- if (aret == NULL) {
+ len_bins = PyArray_SIZE(arr_bins);
+ if (len_bins == 0) {
+ PyErr_SetString(PyExc_ValueError, "bins must have non-zero length");
goto fail;
}
- iret = (npy_intp *)PyArray_DATA(aret);
- if (lx <= 0 || lbins < 0) {
+ NPY_BEGIN_THREADS_THRESHOLDED(len_bins)
+ monotonic = check_array_monotonic((const double *)PyArray_DATA(arr_bins),
+ len_bins);
+ NPY_END_THREADS
+
+ if (monotonic == 0) {
PyErr_SetString(PyExc_ValueError,
- "Both x and bins must have non-zero length");
- goto fail;
+ "bins must be monotonically increasing or decreasing");
+ goto fail;
}
- NPY_BEGIN_ALLOW_THREADS;
- if (lbins == 1) {
- if (right == 0) {
- for (i = 0; i < lx; i++) {
- if (dx [i] >= dbins[0]) {
- iret[i] = 1;
- }
- else {
- iret[i] = 0;
- }
- }
- }
- else {
- for (i = 0; i < lx; i++) {
- if (dx [i] > dbins[0]) {
- iret[i] = 1;
- }
- else {
- iret[i] = 0;
- }
- }
+ /* PyArray_SearchSorted needs an increasing array */
+ if (monotonic == - 1) {
+ PyArrayObject *arr_tmp = NULL;
+ npy_intp shape = PyArray_DIM(arr_bins, 0);
+ npy_intp stride = -PyArray_STRIDE(arr_bins, 0);
+ void *data = (void *)(PyArray_BYTES(arr_bins) - stride * (shape - 1));
+
+ arr_tmp = (PyArrayObject *)PyArray_New(&PyArray_Type, 1, &shape,
+ NPY_DOUBLE, &stride, data, 0,
+ PyArray_FLAGS(arr_bins), NULL);
+ if (!arr_tmp) {
+ goto fail;
}
- }
- else {
- m = check_array_monotonic(dbins, lbins);
- if (right == 0) {
- if ( m == -1 ) {
- for ( i = 0; i < lx; i ++ ) {
- iret [i] = decr_slot_ ((double)dx[i], dbins, lbins);
- }
- }
- else if ( m == 1 ) {
- for ( i = 0; i < lx; i ++ ) {
- iret [i] = incr_slot_ ((double)dx[i], dbins, lbins);
- }
- }
- else {
- /* defer PyErr_SetString until after NPY_END_ALLOW_THREADS */
- bins_non_monotonic = 1;
- }
- }
- else {
- if ( m == -1 ) {
- for ( i = 0; i < lx; i ++ ) {
- iret [i] = decr_slot_right_ ((double)dx[i], dbins,
- lbins);
- }
- }
- else if ( m == 1 ) {
- for ( i = 0; i < lx; i ++ ) {
- iret [i] = incr_slot_right_ ((double)dx[i], dbins,
- lbins);
- }
- }
- else {
- /* defer PyErr_SetString until after NPY_END_ALLOW_THREADS */
- bins_non_monotonic = 1;
- }
+ if (PyArray_SetBaseObject(arr_tmp, (PyObject *)arr_bins) < 0) {
+
+ Py_DECREF(arr_tmp);
+ goto fail;
}
+ arr_bins = arr_tmp;
}
- NPY_END_ALLOW_THREADS;
- if (bins_non_monotonic) {
- PyErr_SetString(PyExc_ValueError,
- "The bins must be monotonically increasing or decreasing");
+
+ ret = PyArray_SearchSorted(arr_bins, (PyObject *)arr_x,
+ right ? NPY_SEARCHLEFT : NPY_SEARCHRIGHT, NULL);
+ if (!ret) {
goto fail;
}
- Py_DECREF(ax);
- Py_DECREF(abins);
- return (PyObject *)aret;
-fail:
- Py_XDECREF(ax);
- Py_XDECREF(abins);
- Py_XDECREF(aret);
- return NULL;
-}
+ /* If bins is decreasing, ret has bins from end, not start */
+ if (monotonic == -1) {
+ npy_intp *ret_data =
+ (npy_intp *)PyArray_DATA((PyArrayObject *)ret);
+ npy_intp len_ret = PyArray_SIZE((PyArrayObject *)ret);
+ NPY_BEGIN_THREADS_THRESHOLDED(len_ret)
+ while (len_ret--) {
+ *ret_data = len_bins - *ret_data;
+ ret_data++;
+ }
+ NPY_END_THREADS
+ }
+ fail:
+ Py_XDECREF(arr_x);
+ Py_XDECREF(arr_bins);
+ return ret;
+}
static char arr_insert__doc__[] = "Insert vals sequentially into equivalent 1-d positions indicated by mask.";
@@ -1394,131 +1312,179 @@ add_newdoc_ufunc(PyObject *NPY_UNUSED(dummy), PyObject *args)
return Py_None;
}
-/* PACKBITS
- *
- * This function packs binary (0 or 1) 1-bit per pixel arrays
- * into contiguous bytes.
- *
+/*
+ * This function packs boolean values in the input array into the bits of a
+ * byte array. Truth values are determined as usual: 0 is false, everything
+ * else is true.
*/
-
-static void
-_packbits( void *In,
- int element_size, /* in bytes */
- npy_intp in_N,
+static NPY_INLINE void
+pack_inner(const char *inptr,
+ npy_intp element_size, /* in bytes */
+ npy_intp n_in,
npy_intp in_stride,
- void *Out,
- npy_intp out_N,
- npy_intp out_stride
-)
+ char *outptr,
+ npy_intp n_out,
+ npy_intp out_stride)
{
- char build;
- int i, index;
- npy_intp out_Nm1;
- int maxi, remain, nonzero, j;
- char *outptr,*inptr;
- NPY_BEGIN_THREADS_DEF;
-
- NPY_BEGIN_THREADS_THRESHOLDED(out_N);
-
- outptr = Out; /* pointer to output buffer */
- inptr = In; /* pointer to input buffer */
-
/*
- * Loop through the elements of In
+ * Loop through the elements of inptr.
* Determine whether or not it is nonzero.
- * Yes: set correspdoning bit (and adjust build value)
+ * Yes: set corresponding bit (and adjust build value)
* No: move on
* Every 8th value, set the value of build and increment the outptr
*/
+ npy_intp index;
+ int remain = n_in % 8; /* uneven bits */
- remain = in_N % 8; /* uneven bits */
- if (remain == 0) {
+ if (remain == 0) { /* assumes n_in > 0 */
remain = 8;
}
- out_Nm1 = out_N - 1;
- for (index = 0; index < out_N; index++) {
- build = 0;
- maxi = (index != out_Nm1 ? 8 : remain);
+ for (index = 0; index < n_out; index++) {
+ char build = 0;
+ int i, maxi;
+ npy_intp j;
+
+ maxi = (index == n_out - 1) ? remain : 8;
for (i = 0; i < maxi; i++) {
build <<= 1;
- nonzero = 0;
for (j = 0; j < element_size; j++) {
- nonzero += (*(inptr++) != 0);
+ build |= (inptr[j] != 0);
}
- inptr += (in_stride - element_size);
- build += (nonzero != 0);
+ inptr += in_stride;
+ }
+ if (index == n_out - 1) {
+ build <<= 8 - remain;
}
- if (index == out_Nm1) build <<= (8-remain);
- /* printf("Here: %d %d %d %d\n",build,slice,index,maxi); */
*outptr = build;
outptr += out_stride;
}
-
- NPY_END_THREADS;
- return;
}
-
-static void
-_unpackbits(void *In,
- int NPY_UNUSED(el_size), /* unused */
- npy_intp in_N,
- npy_intp in_stride,
- void *Out,
- npy_intp NPY_UNUSED(out_N),
- npy_intp out_stride
- )
+static PyObject *
+pack_bits(PyObject *input, int axis)
{
- unsigned char mask;
- int i, index;
- char *inptr, *outptr;
+ PyArrayObject *inp;
+ PyArrayObject *new = NULL;
+ PyArrayObject *out = NULL;
+ npy_intp outdims[NPY_MAXDIMS];
+ int i;
+ PyArrayIterObject *it, *ot;
NPY_BEGIN_THREADS_DEF;
- NPY_BEGIN_THREADS_THRESHOLDED(in_N);
+ inp = (PyArrayObject *)PyArray_FROM_O(input);
+
+ if (inp == NULL) {
+ return NULL;
+ }
+ if (!PyArray_ISBOOL(inp) && !PyArray_ISINTEGER(inp)) {
+ PyErr_SetString(PyExc_TypeError,
+ "Expected an input array of integer or boolean data type");
+ goto fail;
+ }
+
+ new = (PyArrayObject *)PyArray_CheckAxis(inp, &axis, 0);
+ Py_DECREF(inp);
+ if (new == NULL) {
+ return NULL;
+ }
+ /* Handle empty array separately */
+ if (PyArray_SIZE(new) == 0) {
+ return PyArray_Copy(new);
+ }
+
+ if (PyArray_NDIM(new) == 0) {
+ char *optr, *iptr;
- outptr = Out;
- inptr = In;
- for (index = 0; index < in_N; index++) {
- mask = 128;
- for (i = 0; i < 8; i++) {
- *outptr = ((mask & (unsigned char)(*inptr)) != 0);
- outptr += out_stride;
- mask >>= 1;
+ out = (PyArrayObject *)PyArray_New(Py_TYPE(new), 0, NULL, NPY_UBYTE,
+ NULL, NULL, 0, 0, NULL);
+ if (out == NULL) {
+ goto fail;
}
- inptr += in_stride;
+ optr = PyArray_DATA(out);
+ iptr = PyArray_DATA(new);
+ *optr = 0;
+ for (i = 0; i < PyArray_ITEMSIZE(new); i++) {
+ if (*iptr != 0) {
+ *optr = 1;
+ break;
+ }
+ iptr++;
+ }
+ goto finish;
}
+
+ /* Setup output shape */
+ for (i = 0; i < PyArray_NDIM(new); i++) {
+ outdims[i] = PyArray_DIM(new, i);
+ }
+
+ /*
+ * Divide axis dimension by 8
+ * 8 -> 1, 9 -> 2, 16 -> 2, 17 -> 3 etc..
+ */
+ outdims[axis] = ((outdims[axis] - 1) >> 3) + 1;
+
+ /* Create output array */
+ out = (PyArrayObject *)PyArray_New(Py_TYPE(new),
+ PyArray_NDIM(new), outdims, NPY_UBYTE,
+ NULL, NULL, 0, PyArray_ISFORTRAN(new), NULL);
+ if (out == NULL) {
+ goto fail;
+ }
+ /* Setup iterators to iterate over all but given axis */
+ it = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)new, &axis);
+ ot = (PyArrayIterObject *)PyArray_IterAllButAxis((PyObject *)out, &axis);
+ if (it == NULL || ot == NULL) {
+ Py_XDECREF(it);
+ Py_XDECREF(ot);
+ goto fail;
+ }
+
+ NPY_BEGIN_THREADS_THRESHOLDED(PyArray_DIM(out, axis));
+ while (PyArray_ITER_NOTDONE(it)) {
+ pack_inner(PyArray_ITER_DATA(it), PyArray_ITEMSIZE(new),
+ PyArray_DIM(new, axis), PyArray_STRIDE(new, axis),
+ PyArray_ITER_DATA(ot), PyArray_DIM(out, axis),
+ PyArray_STRIDE(out, axis));
+ PyArray_ITER_NEXT(it);
+ PyArray_ITER_NEXT(ot);
+ }
NPY_END_THREADS;
- return;
+
+ Py_DECREF(it);
+ Py_DECREF(ot);
+
+finish:
+ Py_DECREF(new);
+ return (PyObject *)out;
+
+fail:
+ Py_XDECREF(new);
+ Py_XDECREF(out);
+ return NULL;
}
-/* Fixme -- pack and unpack should be separate routines */
static PyObject *
-pack_or_unpack_bits(PyObject *input, int axis, int unpack)
+unpack_bits(PyObject *input, int axis)
{
PyArrayObject *inp;
PyArrayObject *new = NULL;
PyArrayObject *out = NULL;
npy_intp outdims[NPY_MAXDIMS];
int i;
- void (*thefunc)(void *, int, npy_intp, npy_intp, void *, npy_intp, npy_intp);
PyArrayIterObject *it, *ot;
+ npy_intp n_in, in_stride, out_stride;
+ NPY_BEGIN_THREADS_DEF;
inp = (PyArrayObject *)PyArray_FROM_O(input);
if (inp == NULL) {
return NULL;
}
- if (unpack) {
- if (PyArray_TYPE(inp) != NPY_UBYTE) {
- PyErr_SetString(PyExc_TypeError,
- "Expected an input array of unsigned byte data type");
- goto fail;
- }
- }
- else if (!PyArray_ISINTEGER(inp)) {
+ if (PyArray_TYPE(inp) != NPY_UBYTE) {
PyErr_SetString(PyExc_TypeError,
- "Expected an input array of integer data type");
+ "Expected an input array of unsigned byte data type");
goto fail;
}
@@ -1533,60 +1499,27 @@ pack_or_unpack_bits(PyObject *input, int axis, int unpack)
}
if (PyArray_NDIM(new) == 0) {
- if (unpack) {
- /* Handle 0-d array by converting it to a 1-d array */
- PyArrayObject *temp;
- PyArray_Dims newdim = {NULL, 1};
- npy_intp shape = 1;
-
- newdim.ptr = &shape;
- temp = (PyArrayObject *)PyArray_Newshape(new, &newdim, NPY_CORDER);
- if (temp == NULL) {
- goto fail;
- }
- Py_DECREF(new);
- new = temp;
- }
- else {
- char *optr, *iptr;
- out = (PyArrayObject *)PyArray_New(Py_TYPE(new), 0, NULL, NPY_UBYTE,
- NULL, NULL, 0, 0, NULL);
- if (out == NULL) {
- goto fail;
- }
- optr = PyArray_DATA(out);
- iptr = PyArray_DATA(new);
- *optr = 0;
- for (i = 0; i<PyArray_ITEMSIZE(new); i++) {
- if (*iptr != 0) {
- *optr = 1;
- break;
- }
- iptr++;
- }
- goto finish;
+ /* Handle 0-d array by converting it to a 1-d array */
+ PyArrayObject *temp;
+ PyArray_Dims newdim = {NULL, 1};
+ npy_intp shape = 1;
+
+ newdim.ptr = &shape;
+ temp = (PyArrayObject *)PyArray_Newshape(new, &newdim, NPY_CORDER);
+ if (temp == NULL) {
+ goto fail;
}
+ Py_DECREF(new);
+ new = temp;
}
-
/* Setup output shape */
for (i=0; i<PyArray_NDIM(new); i++) {
outdims[i] = PyArray_DIM(new, i);
}
- if (unpack) {
- /* Multiply axis dimension by 8 */
- outdims[axis] <<= 3;
- thefunc = _unpackbits;
- }
- else {
- /*
- * Divide axis dimension by 8
- * 8 -> 1, 9 -> 2, 16 -> 2, 17 -> 3 etc..
- */
- outdims[axis] = ((outdims[axis] - 1) >> 3) + 1;
- thefunc = _packbits;
- }
+ /* Multiply axis dimension by 8 */
+ outdims[axis] <<= 3;
/* Create output array */
out = (PyArrayObject *)PyArray_New(Py_TYPE(new),
@@ -1604,18 +1537,35 @@ pack_or_unpack_bits(PyObject *input, int axis, int unpack)
goto fail;
}
- while(PyArray_ITER_NOTDONE(it)) {
- thefunc(PyArray_ITER_DATA(it), PyArray_ITEMSIZE(new),
- PyArray_DIM(new, axis), PyArray_STRIDE(new, axis),
- PyArray_ITER_DATA(ot), PyArray_DIM(out, axis),
- PyArray_STRIDE(out, axis));
+ NPY_BEGIN_THREADS_THRESHOLDED(PyArray_DIM(new, axis));
+
+ n_in = PyArray_DIM(new, axis);
+ in_stride = PyArray_STRIDE(new, axis);
+ out_stride = PyArray_STRIDE(out, axis);
+
+ while (PyArray_ITER_NOTDONE(it)) {
+ npy_intp index;
+ unsigned const char *inptr = PyArray_ITER_DATA(it);
+ char *outptr = PyArray_ITER_DATA(ot);
+
+ for (index = 0; index < n_in; index++) {
+ unsigned char mask = 128;
+
+ for (i = 0; i < 8; i++) {
+ *outptr = ((mask & (*inptr)) != 0);
+ outptr += out_stride;
+ mask >>= 1;
+ }
+ inptr += in_stride;
+ }
PyArray_ITER_NEXT(it);
PyArray_ITER_NEXT(ot);
}
+ NPY_END_THREADS;
+
Py_DECREF(it);
Py_DECREF(ot);
-finish:
Py_DECREF(new);
return (PyObject *)out;
@@ -1637,7 +1587,7 @@ io_pack(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)
&obj, PyArray_AxisConverter, &axis)) {
return NULL;
}
- return pack_or_unpack_bits(obj, axis, 0);
+ return pack_bits(obj, axis);
}
static PyObject *
@@ -1651,7 +1601,7 @@ io_unpack(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwds)
&obj, PyArray_AxisConverter, &axis)) {
return NULL;
}
- return pack_or_unpack_bits(obj, axis, 1);
+ return unpack_bits(obj, axis);
}
/* The docstrings for many of these methods are in add_newdocs.py. */
diff --git a/numpy/lib/stride_tricks.py b/numpy/lib/stride_tricks.py
index 12f8bbf13..b81307a65 100644
--- a/numpy/lib/stride_tricks.py
+++ b/numpy/lib/stride_tricks.py
@@ -20,9 +20,11 @@ class DummyArray(object):
self.__array_interface__ = interface
self.base = base
-def as_strided(x, shape=None, strides=None):
+def as_strided(x, shape=None, strides=None, subok=False):
""" Make an ndarray from the given array with the given shape and strides.
"""
+ # first convert input to array, possibly keeping subclass
+ x = np.array(x, copy=False, subok=subok)
interface = dict(x.__array_interface__)
if shape is not None:
interface['shape'] = tuple(shape)
@@ -32,9 +34,17 @@ def as_strided(x, shape=None, strides=None):
# Make sure dtype is correct in case of custom dtype
if array.dtype.kind == 'V':
array.dtype = x.dtype
+ if type(x) is not type(array):
+ # if input was an ndarray subclass and subclasses were OK,
+ # then view the result as that subclass.
+ array = array.view(type=type(x))
+ # Since we have done something akin to a view from x, we should let
+ # the subclass finalize (if it has it implemented, i.e., is not None).
+ if array.__array_finalize__:
+ array.__array_finalize__(x)
return array
-def broadcast_arrays(*args):
+def broadcast_arrays(*args, **kwargs):
"""
Broadcast any number of arrays against each other.
@@ -43,6 +53,10 @@ def broadcast_arrays(*args):
`*args` : array_likes
The arrays to broadcast.
+ subok : bool, optional
+ If True, then sub-classes will be passed-through, otherwise
+ the returned arrays will be forced to be a base-class array (default).
+
Returns
-------
broadcasted : list of arrays
@@ -73,7 +87,11 @@ def broadcast_arrays(*args):
[3, 3, 3]])]
"""
- args = [np.asarray(_m) for _m in args]
+ subok = kwargs.pop('subok', False)
+ if kwargs:
+ raise TypeError('broadcast_arrays() got an unexpected keyword '
+ 'argument {}'.format(kwargs.pop()))
+ args = [np.array(_m, copy=False, subok=subok) for _m in args]
shapes = [x.shape for x in args]
if len(set(shapes)) == 1:
# Common case where nothing needs to be broadcasted.
@@ -118,6 +136,6 @@ def broadcast_arrays(*args):
common_shape.append(1)
# Construct the new arrays.
- broadcasted = [as_strided(x, shape=sh, strides=st) for (x, sh, st) in
- zip(args, shapes, strides)]
+ broadcasted = [as_strided(x, shape=sh, strides=st, subok=subok)
+ for (x, sh, st) in zip(args, shapes, strides)]
return broadcasted
diff --git a/numpy/lib/tests/test__iotools.py b/numpy/lib/tests/test__iotools.py
index 4db19382a..92ca1c973 100644
--- a/numpy/lib/tests/test__iotools.py
+++ b/numpy/lib/tests/test__iotools.py
@@ -7,7 +7,7 @@ from datetime import date
import numpy as np
from numpy.compat import asbytes, asbytes_nested
from numpy.testing import (
- run_module_suite, TestCase, assert_, assert_equal
+ run_module_suite, TestCase, assert_, assert_equal, assert_allclose
)
from numpy.lib._iotools import (
LineSplitter, NameValidator, StringConverter,
@@ -76,7 +76,7 @@ class TestLineSplitter(TestCase):
test = LineSplitter((6, 6, 9))(strg)
assert_equal(test, asbytes_nested(['1', '3 4', '5 6']))
-#-------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
class TestNameValidator(TestCase):
@@ -127,7 +127,7 @@ class TestNameValidator(TestCase):
assert_(validator(namelist) is None)
assert_equal(validator(namelist, nbfields=3), ['f0', 'f1', 'f2'])
-#-------------------------------------------------------------------------------
+# -----------------------------------------------------------------------------
def _bytes_to_date(s):
@@ -150,13 +150,17 @@ class TestStringConverter(TestCase):
"Tests the upgrade method."
converter = StringConverter()
assert_equal(converter._status, 0)
- converter.upgrade(asbytes('0'))
+ # test int
+ assert_equal(converter.upgrade(asbytes('0')), 0)
assert_equal(converter._status, 1)
- converter.upgrade(asbytes('0.'))
+ # test float
+ assert_allclose(converter.upgrade(asbytes('0.')), 0.0)
assert_equal(converter._status, 2)
- converter.upgrade(asbytes('0j'))
+ # test complex
+ assert_equal(converter.upgrade(asbytes('0j')), complex('0j'))
assert_equal(converter._status, 3)
- converter.upgrade(asbytes('a'))
+ # test str
+ assert_equal(converter.upgrade(asbytes('a')), asbytes('a'))
assert_equal(converter._status, len(converter._mapper) - 1)
def test_missing(self):
diff --git a/numpy/lib/tests/test_arraysetops.py b/numpy/lib/tests/test_arraysetops.py
index e83f8552e..39196f4bc 100644
--- a/numpy/lib/tests/test_arraysetops.py
+++ b/numpy/lib/tests/test_arraysetops.py
@@ -109,6 +109,12 @@ class TestSetOps(TestCase):
assert_array_equal(a2, unq)
assert_array_equal(a2_inv, inv)
+ # test for chararrays with return_inverse (gh-5099)
+ a = np.chararray(5)
+ a[...] = ''
+ a2, a2_inv = np.unique(a, return_inverse=True)
+ assert_array_equal(a2_inv, np.zeros(5))
+
def test_intersect1d(self):
# unique inputs
a = np.array([5, 7, 1, 2])
diff --git a/numpy/lib/tests/test_format.py b/numpy/lib/tests/test_format.py
index b266f1c15..ee77386bc 100644
--- a/numpy/lib/tests/test_format.py
+++ b/numpy/lib/tests/test_format.py
@@ -688,28 +688,28 @@ def test_bad_header():
def test_large_file_support():
from nose import SkipTest
+ if (sys.platform == 'win32' or sys.platform == 'cygwin'):
+ raise SkipTest("Unknown if Windows has sparse filesystems")
# try creating a large sparse file
- with tempfile.NamedTemporaryFile() as tf:
- try:
- # seek past end would work too, but linux truncate somewhat
- # increases the chances that we have a sparse filesystem and can
- # avoid actually writing 5GB
- import subprocess as sp
- sp.check_call(["truncate", "-s", "5368709120", tf.name])
- except:
- raise SkipTest("Could not create 5GB large file")
- # write a small array to the end
- f = open(tf.name, "wb")
+ tf_name = os.path.join(tempdir, 'sparse_file')
+ try:
+ # seek past end would work too, but linux truncate somewhat
+ # increases the chances that we have a sparse filesystem and can
+ # avoid actually writing 5GB
+ import subprocess as sp
+ sp.check_call(["truncate", "-s", "5368709120", tf_name])
+ except:
+ raise SkipTest("Could not create 5GB large file")
+ # write a small array to the end
+ with open(tf_name, "wb") as f:
f.seek(5368709120)
d = np.arange(5)
np.save(f, d)
- f.close()
- # read it back
- f = open(tf.name, "rb")
+ # read it back
+ with open(tf_name, "rb") as f:
f.seek(5368709120)
r = np.load(f)
- f.close()
- assert_array_equal(r, d)
+ assert_array_equal(r, d)
if __name__ == "__main__":
diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py
index a3f805691..03521ca4c 100644
--- a/numpy/lib/tests/test_function_base.py
+++ b/numpy/lib/tests/test_function_base.py
@@ -124,6 +124,11 @@ class TestAverage(TestCase):
assert_array_equal(average(y1, weights=w2, axis=1), desired)
assert_equal(average(y1, weights=w2), 5.)
+ y3 = rand(5).astype(np.float32)
+ w3 = rand(5).astype(np.float64)
+
+ assert_(np.average(y3, weights=w3).dtype == np.result_type(y3, w3))
+
def test_returned(self):
y = np.array([[1, 2, 3], [4, 5, 6]])
@@ -312,6 +317,16 @@ class TestInsert(TestCase):
np.insert([0, 1, 2], x, [3, 4, 5])
assert_equal(x, np.array([1, 1, 1]))
+ def test_structured_array(self):
+ a = np.array([(1, 'a'), (2, 'b'), (3, 'c')],
+ dtype=[('foo', 'i'), ('bar', 'a1')])
+ val = (4, 'd')
+ b = np.insert(a, 0, val)
+ assert_array_equal(b[0], np.array(val, dtype=b.dtype))
+ val = [(4, 'd')] * 2
+ b = np.insert(a, [0, 2], val)
+ assert_array_equal(b[[0, 3]], np.array(val, dtype=b.dtype))
+
class TestAmax(TestCase):
def test_basic(self):
@@ -516,8 +531,18 @@ class TestGradient(TestCase):
def test_masked(self):
# Make sure that gradient supports subclasses like masked arrays
- x = np.ma.array([[1, 1], [3, 4]])
- assert_equal(type(gradient(x)[0]), type(x))
+ x = np.ma.array([[1, 1], [3, 4]],
+ mask=[[False, False], [False, False]])
+ out = gradient(x)[0]
+ assert_equal(type(out), type(x))
+ # And make sure that the output and input don't have aliased mask
+ # arrays
+ assert_(x.mask is not out.mask)
+ # Also check that edge_order=2 doesn't alter the original mask
+ x2 = np.ma.arange(5)
+ x2[2] = np.ma.masked
+ np.gradient(x2, edge_order=2)
+ assert_array_equal(x2.mask, [False, False, True, False, False])
def test_datetime64(self):
# Make sure gradient() can handle special types like datetime64
@@ -526,7 +551,7 @@ class TestGradient(TestCase):
'1910-10-12', '1910-12-12', '1912-12-12'],
dtype='datetime64[D]')
dx = np.array(
- [-7, -3, 0, 31, 61, 396, 1066],
+ [-5, -3, 0, 31, 61, 396, 731],
dtype='timedelta64[D]')
assert_array_equal(gradient(x), dx)
assert_(dx.dtype == np.dtype('timedelta64[D]'))
@@ -537,7 +562,7 @@ class TestGradient(TestCase):
[-5, -3, 10, 12, 61, 321, 300],
dtype='timedelta64[D]')
dx = np.array(
- [-3, 7, 7, 25, 154, 119, -161],
+ [2, 7, 7, 25, 154, 119, -21],
dtype='timedelta64[D]')
assert_array_equal(gradient(x), dx)
assert_(dx.dtype == np.dtype('timedelta64[D]'))
@@ -551,7 +576,7 @@ class TestGradient(TestCase):
dx = x[1] - x[0]
y = 2 * x ** 3 + 4 * x ** 2 + 2 * x
analytical = 6 * x ** 2 + 8 * x + 2
- num_error = np.abs((np.gradient(y, dx) / analytical) - 1)
+ num_error = np.abs((np.gradient(y, dx, edge_order=2) / analytical) - 1)
assert_(np.all(num_error < 0.03) == True)
@@ -836,6 +861,13 @@ class TestDigitize(TestCase):
bins = [1, 1, 0, 1]
assert_raises(ValueError, digitize, x, bins)
+ def test_casting_error(self):
+ x = [1, 2, 3+1.j]
+ bins = [1, 2, 3]
+ assert_raises(TypeError, digitize, x, bins)
+ x, bins = bins, x
+ assert_raises(TypeError, digitize, x, bins)
+
class TestUnwrap(TestCase):
def test_simple(self):
@@ -1072,6 +1104,13 @@ class TestHistogram(TestCase):
h, b = histogram(a, weights=np.ones(10, float))
assert_(issubdtype(h.dtype, float))
+ def test_f32_rounding(self):
+ # gh-4799, check that the rounding of the edges works with float32
+ x = np.array([276.318359 , -69.593948 , 21.329449], dtype=np.float32)
+ y = np.array([5005.689453, 4481.327637, 6010.369629], dtype=np.float32)
+ counts_hist, xedges, yedges = np.histogram2d(x, y, bins=100)
+ assert_equal(counts_hist.sum(), 3.)
+
def test_weights(self):
v = rand(100)
w = np.ones(100) * 5
@@ -1460,7 +1499,7 @@ class TestMeshgrid(TestCase):
# Test that meshgrid complains about invalid arguments
# Regression test for issue #4755:
# https://github.com/numpy/numpy/issues/4755
- assert_raises(TypeError, meshgrid,
+ assert_raises(TypeError, meshgrid,
[1, 2, 3], [4, 5, 6, 7], indices='ij')
@@ -1587,6 +1626,9 @@ class TestInterp(TestCase):
def test_exceptions(self):
assert_raises(ValueError, interp, 0, [], [])
assert_raises(ValueError, interp, 0, [0], [1, 2])
+ assert_raises(ValueError, interp, 0, [0, 1], [1, 2], period=0)
+ assert_raises(ValueError, interp, 0, [], [], period=360)
+ assert_raises(ValueError, interp, 0, [0], [1, 2], period=360)
def test_basic(self):
x = np.linspace(0, 1, 5)
@@ -1627,6 +1669,16 @@ class TestInterp(TestCase):
fp = np.sin(xp)
assert_almost_equal(np.interp(np.pi, xp, fp), 0.0)
+ def test_period(self):
+ x = [-180, -170, -185, 185, -10, -5, 0, 365]
+ xp = [190, -190, 350, -350]
+ fp = [5, 10, 3, 4]
+ y = [7.5, 5., 8.75, 6.25, 3., 3.25, 3.5, 3.75]
+ assert_almost_equal(np.interp(x, xp, fp, period=360), y)
+ x = np.array(x, order='F').reshape(2, -1)
+ y = np.array(y, order='C').reshape(2, -1)
+ assert_almost_equal(np.interp(x, xp, fp, period=360), y)
+
def compare_results(res, desired):
for i in range(len(desired)):
@@ -1860,6 +1912,14 @@ class TestScoreatpercentile(TestCase):
np.percentile(a, [50])
assert_equal(a, np.array([2, 3, 4, 1]))
+ def test_no_p_overwrite(self):
+ p = np.linspace(0., 100., num=5)
+ np.percentile(np.arange(100.), p, interpolation="midpoint")
+ assert_array_equal(p, np.linspace(0., 100., num=5))
+ p = np.linspace(0., 100., num=5).tolist()
+ np.percentile(np.arange(100.), p, interpolation="midpoint")
+ assert_array_equal(p, np.linspace(0., 100., num=5).tolist())
+
def test_percentile_overwrite(self):
a = np.array([2, 3, 4, 1])
b = np.percentile(a, [50], overwrite_input=True)
diff --git a/numpy/lib/tests/test_io.py b/numpy/lib/tests/test_io.py
index 49ad1ba5b..68b2018cd 100644
--- a/numpy/lib/tests/test_io.py
+++ b/numpy/lib/tests/test_io.py
@@ -4,9 +4,7 @@ import sys
import gzip
import os
import threading
-import shutil
-import contextlib
-from tempfile import mkstemp, mkdtemp, NamedTemporaryFile
+from tempfile import mkstemp, NamedTemporaryFile
import time
import warnings
import gc
@@ -24,13 +22,7 @@ from numpy.ma.testutils import (
assert_raises, assert_raises_regex, run_module_suite
)
from numpy.testing import assert_warns, assert_, build_err_msg
-
-
-@contextlib.contextmanager
-def tempdir(change_dir=False):
- tmpdir = mkdtemp()
- yield tmpdir
- shutil.rmtree(tmpdir)
+from numpy.testing.utils import tempdir
class TextIO(BytesIO):
@@ -202,7 +194,7 @@ class TestSavezLoad(RoundtripTest, TestCase):
def test_big_arrays(self):
L = (1 << 31) + 100000
a = np.empty(L, dtype=np.uint8)
- with tempdir() as tmpdir:
+ with tempdir(prefix="numpy_test_big_arrays_") as tmpdir:
tmp = os.path.join(tmpdir, "file.npz")
np.savez(tmp, a=a)
del a
@@ -224,6 +216,17 @@ class TestSavezLoad(RoundtripTest, TestCase):
l = np.load(c)
assert_equal(a, l['file_a'])
assert_equal(b, l['file_b'])
+
+ def test_BagObj(self):
+ a = np.array([[1, 2], [3, 4]], float)
+ b = np.array([[1 + 2j, 2 + 7j], [3 - 6j, 4 + 12j]], complex)
+ c = BytesIO()
+ np.savez(c, file_a=a, file_b=b)
+ c.seek(0)
+ l = np.load(c)
+ assert_equal(sorted(dir(l.f)), ['file_a','file_b'])
+ assert_equal(a, l.f.file_a)
+ assert_equal(b, l.f.file_b)
def test_savez_filename_clashes(self):
# Test that issue #852 is fixed
@@ -311,7 +314,7 @@ class TestSavezLoad(RoundtripTest, TestCase):
# Check that zipfile owns file and can close it.
# This needs to pass a file name to load for the
# test.
- with tempdir() as tmpdir:
+ with tempdir(prefix="numpy_test_closing_zipfile_after_load_") as tmpdir:
fd, tmp = mkstemp(suffix='.npz', dir=tmpdir)
os.close(fd)
np.savez(tmp, lab='place holder')
@@ -1093,6 +1096,21 @@ M 33 21.99
control = np.array([2009., 23., 46],)
assert_equal(test, control)
+ def test_dtype_with_converters_and_usecols(self):
+ dstr = "1,5,-1,1:1\n2,8,-1,1:n\n3,3,-2,m:n\n"
+ dmap = {'1:1':0, '1:n':1, 'm:1':2, 'm:n':3}
+ dtyp = [('E1','i4'),('E2','i4'),('E3','i2'),('N', 'i1')]
+ conv = {0: int, 1: int, 2: int, 3: lambda r: dmap[r.decode()]}
+ test = np.recfromcsv(TextIO(dstr,), dtype=dtyp, delimiter=',',
+ names=None, converters=conv)
+ control = np.rec.array([[1,5,-1,0], [2,8,-1,1], [3,3,-2,3]], dtype=dtyp)
+ assert_equal(test, control)
+ dtyp = [('E1','i4'),('E2','i4'),('N', 'i1')]
+ test = np.recfromcsv(TextIO(dstr,), dtype=dtyp, delimiter=',',
+ usecols=(0,1,3), names=None, converters=conv)
+ control = np.rec.array([[1,5,0], [2,8,1], [3,3,3]], dtype=dtyp)
+ assert_equal(test, control)
+
def test_dtype_with_object(self):
"Test using an explicit dtype with an object"
from datetime import date
@@ -1308,6 +1326,16 @@ M 33 21.99
ctrl = np.array([(0, 3), (4, -999)], dtype=[(_, int) for _ in "ac"])
assert_equal(test, ctrl)
+ data2 = "1,2,*,4\n5,*,7,8\n"
+ test = np.genfromtxt(TextIO(data2), delimiter=',', dtype=int,
+ missing_values="*", filling_values=0)
+ ctrl = np.array([[1, 2, 0, 4], [5, 0, 7, 8]])
+ assert_equal(test, ctrl)
+ test = np.genfromtxt(TextIO(data2), delimiter=',', dtype=int,
+ missing_values="*", filling_values=-1)
+ ctrl = np.array([[1, 2, -1, 4], [5, -1, 7, 8]])
+ assert_equal(test, ctrl)
+
def test_withmissing_float(self):
data = TextIO('A,B\n0,1.5\n2,-999.00')
test = np.mafromtxt(data, dtype=None, delimiter=',',
diff --git a/numpy/lib/tests/test_nanfunctions.py b/numpy/lib/tests/test_nanfunctions.py
index 3da6b5149..35ae86c20 100644
--- a/numpy/lib/tests/test_nanfunctions.py
+++ b/numpy/lib/tests/test_nanfunctions.py
@@ -645,6 +645,22 @@ class TestNanFunctions_Median(TestCase):
assert_raises(IndexError, np.nanmedian, d, axis=(0, 4))
assert_raises(ValueError, np.nanmedian, d, axis=(1, 1))
+ def test_float_special(self):
+ with warnings.catch_warnings(record=True):
+ warnings.simplefilter('ignore', RuntimeWarning)
+ a = np.array([[np.inf, np.nan], [np.nan, np.nan]])
+ assert_equal(np.nanmedian(a, axis=0), [np.inf, np.nan])
+ assert_equal(np.nanmedian(a, axis=1), [np.inf, np.nan])
+ assert_equal(np.nanmedian(a), np.inf)
+
+ # minimum fill value check
+ a = np.array([[np.nan, np.nan, np.inf], [np.nan, np.nan, np.inf]])
+ assert_equal(np.nanmedian(a, axis=1), np.inf)
+
+ # no mask path
+ a = np.array([[np.inf, np.inf], [np.inf, np.inf]])
+ assert_equal(np.nanmedian(a, axis=1), np.inf)
+
class TestNanFunctions_Percentile(TestCase):
diff --git a/numpy/lib/tests/test_packbits.py b/numpy/lib/tests/test_packbits.py
new file mode 100644
index 000000000..186e8960d
--- /dev/null
+++ b/numpy/lib/tests/test_packbits.py
@@ -0,0 +1,26 @@
+import numpy as np
+
+from numpy.testing import assert_array_equal, assert_equal, assert_raises
+
+
+def test_packbits():
+ # Copied from the docstring.
+ a = [[[1, 0, 1], [0, 1, 0]],
+ [[1, 1, 0], [0, 0, 1]]]
+ for dtype in [np.bool, np.uint8, np.int]:
+ arr = np.array(a, dtype=dtype)
+ b = np.packbits(arr, axis=-1)
+ assert_equal(b.dtype, np.uint8)
+ assert_array_equal(b, np.array([[[160], [64]], [[192], [32]]]))
+
+ assert_raises(TypeError, np.packbits, np.array(a, dtype=float))
+
+
+def test_unpackbits():
+ # Copied from the docstring.
+ a = np.array([[2], [7], [23]], dtype=np.uint8)
+ b = np.unpackbits(a, axis=1)
+ assert_equal(b.dtype, np.uint8)
+ assert_array_equal(b, np.array([[0, 0, 0, 0, 0, 0, 1, 0],
+ [0, 0, 0, 0, 0, 1, 1, 1],
+ [0, 0, 0, 1, 0, 1, 1, 1]]))
diff --git a/numpy/lib/tests/test_polynomial.py b/numpy/lib/tests/test_polynomial.py
index 02faa0283..5c15941e6 100644
--- a/numpy/lib/tests/test_polynomial.py
+++ b/numpy/lib/tests/test_polynomial.py
@@ -153,6 +153,9 @@ class TestDocs(TestCase):
assert_(p2[3] == Decimal("1.333333333333333333333333333"))
assert_(p2[2] == Decimal('1.5'))
assert_(np.issubdtype(p2.coeffs.dtype, np.object_))
+ p = np.poly([Decimal(1), Decimal(2)])
+ assert_equal(np.poly([Decimal(1), Decimal(2)]),
+ [1, Decimal(-3), Decimal(2)])
def test_complex(self):
p = np.poly1d([3j, 2j, 1j])
@@ -173,5 +176,13 @@ class TestDocs(TestCase):
except ValueError:
pass
+ def test_poly_int_overflow(self):
+ """
+ Regression test for gh-5096.
+ """
+ v = np.arange(1, 21)
+ assert_almost_equal(np.poly(v), np.poly(np.diag(v)))
+
+
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/lib/tests/test_stride_tricks.py b/numpy/lib/tests/test_stride_tricks.py
index cd0973300..bc7e30ca4 100644
--- a/numpy/lib/tests/test_stride_tricks.py
+++ b/numpy/lib/tests/test_stride_tricks.py
@@ -3,7 +3,7 @@ from __future__ import division, absolute_import, print_function
import numpy as np
from numpy.testing import (
run_module_suite, assert_equal, assert_array_equal,
- assert_raises
+ assert_raises, assert_
)
from numpy.lib.stride_tricks import as_strided, broadcast_arrays
@@ -234,5 +234,49 @@ def test_as_strided():
assert_array_equal(a_view, expected)
+class VerySimpleSubClass(np.ndarray):
+ def __new__(cls, *args, **kwargs):
+ kwargs['subok'] = True
+ return np.array(*args, **kwargs).view(cls)
+
+
+class SimpleSubClass(VerySimpleSubClass):
+ def __new__(cls, *args, **kwargs):
+ kwargs['subok'] = True
+ self = np.array(*args, **kwargs).view(cls)
+ self.info = 'simple'
+ return self
+
+ def __array_finalize__(self, obj):
+ self.info = getattr(obj, 'info', '') + ' finalized'
+
+
+def test_subclasses():
+ # test that subclass is preserved only if subok=True
+ a = VerySimpleSubClass([1, 2, 3, 4])
+ assert_(type(a) is VerySimpleSubClass)
+ a_view = as_strided(a, shape=(2,), strides=(2 * a.itemsize,))
+ assert_(type(a_view) is np.ndarray)
+ a_view = as_strided(a, shape=(2,), strides=(2 * a.itemsize,), subok=True)
+ assert_(type(a_view) is VerySimpleSubClass)
+ # test that if a subclass has __array_finalize__, it is used
+ a = SimpleSubClass([1, 2, 3, 4])
+ a_view = as_strided(a, shape=(2,), strides=(2 * a.itemsize,), subok=True)
+ assert_(type(a_view) is SimpleSubClass)
+ assert_(a_view.info == 'simple finalized')
+
+ # similar tests for broadcast_arrays
+ b = np.arange(len(a)).reshape(-1, 1)
+ a_view, b_view = broadcast_arrays(a, b)
+ assert_(type(a_view) is np.ndarray)
+ assert_(type(b_view) is np.ndarray)
+ assert_(a_view.shape == b_view.shape)
+ a_view, b_view = broadcast_arrays(a, b, subok=True)
+ assert_(type(a_view) is SimpleSubClass)
+ assert_(a_view.info == 'simple finalized')
+ assert_(type(b_view) is np.ndarray)
+ assert_(a_view.shape == b_view.shape)
+
+
if __name__ == "__main__":
run_module_suite()
diff --git a/numpy/lib/tests/test_twodim_base.py b/numpy/lib/tests/test_twodim_base.py
index e9dbef70f..739061a5d 100644
--- a/numpy/lib/tests/test_twodim_base.py
+++ b/numpy/lib/tests/test_twodim_base.py
@@ -311,6 +311,40 @@ def test_tril_triu_ndim3():
yield assert_equal, a_triu_observed.dtype, a.dtype
yield assert_equal, a_tril_observed.dtype, a.dtype
+def test_tril_triu_with_inf():
+ # Issue 4859
+ arr = np.array([[1, 1, np.inf],
+ [1, 1, 1],
+ [np.inf, 1, 1]])
+ out_tril = np.array([[1, 0, 0],
+ [1, 1, 0],
+ [np.inf, 1, 1]])
+ out_triu = out_tril.T
+ assert_array_equal(np.triu(arr), out_triu)
+ assert_array_equal(np.tril(arr), out_tril)
+
+
+def test_tril_triu_dtype():
+ # Issue 4916
+ # tril and triu should return the same dtype as input
+ for c in np.typecodes['All']:
+ if c == 'V':
+ continue
+ arr = np.zeros((3, 3), dtype=c)
+ assert_equal(np.triu(arr).dtype, arr.dtype)
+ assert_equal(np.tril(arr).dtype, arr.dtype)
+
+ # check special cases
+ arr = np.array([['2001-01-01T12:00', '2002-02-03T13:56'],
+ ['2004-01-01T12:00', '2003-01-03T13:45']],
+ dtype='datetime64')
+ assert_equal(np.triu(arr).dtype, arr.dtype)
+ assert_equal(np.tril(arr).dtype, arr.dtype)
+
+ arr = np.zeros((3,3), dtype='f4,f4')
+ assert_equal(np.triu(arr).dtype, arr.dtype)
+ assert_equal(np.tril(arr).dtype, arr.dtype)
+
def test_mask_indices():
# simple test without offset
diff --git a/numpy/lib/twodim_base.py b/numpy/lib/twodim_base.py
index 2861e1c4a..25504e434 100644
--- a/numpy/lib/twodim_base.py
+++ b/numpy/lib/twodim_base.py
@@ -19,6 +19,8 @@ __all__ = [
i1 = iinfo(int8)
i2 = iinfo(int16)
i4 = iinfo(int32)
+
+
def _min_int(low, high):
""" get small int that fits the range """
if high <= i1.max and low >= i1.min:
@@ -293,7 +295,7 @@ def diag(v, k=0):
[0, 0, 8]])
"""
- v = asarray(v)
+ v = asanyarray(v)
s = v.shape
if len(s) == 1:
n = s[0]+abs(k)
@@ -387,7 +389,6 @@ def tri(N, M=None, k=0, dtype=float):
dtype : dtype, optional
Data type of the returned array. The default is float.
-
Returns
-------
tri : ndarray of shape (N, M)
@@ -452,7 +453,9 @@ def tril(m, k=0):
"""
m = asanyarray(m)
- return multiply(tri(*m.shape[-2:], k=k, dtype=bool), m, dtype=m.dtype)
+ mask = tri(*m.shape[-2:], k=k, dtype=bool)
+
+ return where(mask, m, zeros(1, m.dtype))
def triu(m, k=0):
@@ -478,7 +481,9 @@ def triu(m, k=0):
"""
m = asanyarray(m)
- return multiply(~tri(*m.shape[-2:], k=k-1, dtype=bool), m, dtype=m.dtype)
+ mask = tri(*m.shape[-2:], k=k-1, dtype=bool)
+
+ return where(mask, zeros(1, m.dtype), m)
# Originally borrowed from John Hunter and matplotlib
diff --git a/numpy/lib/utils.py b/numpy/lib/utils.py
index df0052493..519d0e9b9 100644
--- a/numpy/lib/utils.py
+++ b/numpy/lib/utils.py
@@ -4,6 +4,7 @@ import os
import sys
import types
import re
+import warnings
from numpy.core.numerictypes import issubclass_, issubsctype, issubdtype
from numpy.core import ndarray, ufunc, asarray
@@ -1002,111 +1003,70 @@ class SafeEval(object):
This includes strings with lists, dicts and tuples using the abstract
syntax tree created by ``compiler.parse``.
- For an example of usage, see `safe_eval`.
+ .. deprecated:: 1.10.0
See Also
--------
safe_eval
"""
+ def __init__(self):
+ warnings.warn("SafeEval is deprecated in 1.10 and will be removed.",
+ DeprecationWarning)
- if sys.version_info[0] < 3:
- def visit(self, node, **kw):
- cls = node.__class__
- meth = getattr(self, 'visit'+cls.__name__, self.default)
- return meth(node, **kw)
+ def visit(self, node):
+ cls = node.__class__
+ meth = getattr(self, 'visit' + cls.__name__, self.default)
+ return meth(node)
- def default(self, node, **kw):
- raise SyntaxError("Unsupported source construct: %s"
- % node.__class__)
+ def default(self, node):
+ raise SyntaxError("Unsupported source construct: %s"
+ % node.__class__)
- def visitExpression(self, node, **kw):
- for child in node.getChildNodes():
- return self.visit(child, **kw)
+ def visitExpression(self, node):
+ return self.visit(node.body)
- def visitConst(self, node, **kw):
- return node.value
+ def visitNum(self, node):
+ return node.n
- def visitDict(self, node,**kw):
- return dict(
- [(self.visit(k), self.visit(v)) for k, v in node.items]
- )
-
- def visitTuple(self, node, **kw):
- return tuple([self.visit(i) for i in node.nodes])
-
- def visitList(self, node, **kw):
- return [self.visit(i) for i in node.nodes]
-
- def visitUnaryAdd(self, node, **kw):
- return +self.visit(node.getChildNodes()[0])
-
- def visitUnarySub(self, node, **kw):
- return -self.visit(node.getChildNodes()[0])
-
- def visitName(self, node, **kw):
- if node.name == 'False':
- return False
- elif node.name == 'True':
- return True
- elif node.name == 'None':
- return None
- else:
- raise SyntaxError("Unknown name: %s" % node.name)
- else:
-
- def visit(self, node):
- cls = node.__class__
- meth = getattr(self, 'visit' + cls.__name__, self.default)
- return meth(node)
-
- def default(self, node):
- raise SyntaxError("Unsupported source construct: %s"
- % node.__class__)
-
- def visitExpression(self, node):
- return self.visit(node.body)
-
- def visitNum(self, node):
- return node.n
+ def visitStr(self, node):
+ return node.s
- def visitStr(self, node):
- return node.s
+ def visitBytes(self, node):
+ return node.s
- def visitBytes(self, node):
- return node.s
+ def visitDict(self, node,**kw):
+ return dict([(self.visit(k), self.visit(v))
+ for k, v in zip(node.keys, node.values)])
- def visitDict(self, node,**kw):
- return dict([(self.visit(k), self.visit(v))
- for k, v in zip(node.keys, node.values)])
+ def visitTuple(self, node):
+ return tuple([self.visit(i) for i in node.elts])
- def visitTuple(self, node):
- return tuple([self.visit(i) for i in node.elts])
+ def visitList(self, node):
+ return [self.visit(i) for i in node.elts]
- def visitList(self, node):
- return [self.visit(i) for i in node.elts]
+ def visitUnaryOp(self, node):
+ import ast
+ if isinstance(node.op, ast.UAdd):
+ return +self.visit(node.operand)
+ elif isinstance(node.op, ast.USub):
+ return -self.visit(node.operand)
+ else:
+ raise SyntaxError("Unknown unary op: %r" % node.op)
+
+ def visitName(self, node):
+ if node.id == 'False':
+ return False
+ elif node.id == 'True':
+ return True
+ elif node.id == 'None':
+ return None
+ else:
+ raise SyntaxError("Unknown name: %s" % node.id)
- def visitUnaryOp(self, node):
- import ast
- if isinstance(node.op, ast.UAdd):
- return +self.visit(node.operand)
- elif isinstance(node.op, ast.USub):
- return -self.visit(node.operand)
- else:
- raise SyntaxError("Unknown unary op: %r" % node.op)
-
- def visitName(self, node):
- if node.id == 'False':
- return False
- elif node.id == 'True':
- return True
- elif node.id == 'None':
- return None
- else:
- raise SyntaxError("Unknown name: %s" % node.id)
+ def visitNameConstant(self, node):
+ return node.value
- def visitNameConstant(self, node):
- return node.value
def safe_eval(source):
"""
@@ -1151,26 +1111,8 @@ def safe_eval(source):
SyntaxError: Unsupported source construct: compiler.ast.CallFunc
"""
- # Local imports to speed up numpy's import time.
- import warnings
-
- with warnings.catch_warnings():
- # compiler package is deprecated for 3.x, which is already solved
- # here
- warnings.simplefilter('ignore', DeprecationWarning)
- try:
- import compiler
- except ImportError:
- import ast as compiler
-
- walker = SafeEval()
- try:
- ast = compiler.parse(source, mode="eval")
- except SyntaxError:
- raise
- try:
- return walker.visit(ast)
- except SyntaxError:
- raise
+ # Local import to speed up numpy's import time.
+ import ast
+ return ast.literal_eval(source)
#-----------------------------------------------------------------------------