diff options
author | François Bissey <francois.bissey@canterbury.ac.nz> | 2016-08-23 21:14:54 +1200 |
---|---|---|
committer | François Bissey <francois.bissey@canterbury.ac.nz> | 2016-08-23 21:14:54 +1200 |
commit | 9266c2dfb97248dd20719c12ff9a009a71d941aa (patch) | |
tree | 891484d157a4c69c4af15fe46b957fe9f2705472 /numpy/core/function_base.py | |
parent | 072e8a5572f0104c4b28828cb1404bed8682e951 (diff) | |
parent | 276423aa7f4f7d39189ee5ccf7b167ad2c9c25a7 (diff) | |
download | numpy-9266c2dfb97248dd20719c12ff9a009a71d941aa.tar.gz |
Merge branch 'master' into asarray
Diffstat (limited to 'numpy/core/function_base.py')
-rw-r--r-- | numpy/core/function_base.py | 190 |
1 files changed, 147 insertions, 43 deletions
diff --git a/numpy/core/function_base.py b/numpy/core/function_base.py index 0e2bdc693..d6757bb74 100644 --- a/numpy/core/function_base.py +++ b/numpy/core/function_base.py @@ -1,9 +1,25 @@ from __future__ import division, absolute_import, print_function -__all__ = ['logspace', 'linspace', 'may_share_memory'] +import warnings +import operator from . import numeric as _nx -from .numeric import result_type, NaN, shares_memory, MAY_SHARE_BOUNDS, TooHardError, asanyarray +from .numeric import (result_type, NaN, shares_memory, MAY_SHARE_BOUNDS, + TooHardError,asanyarray) + +__all__ = ['logspace', 'linspace', 'geomspace'] + + +def _index_deprecate(i, stacklevel=2): + try: + i = operator.index(i) + except TypeError: + msg = ("object of type {} cannot be safely interpreted as " + "an integer.".format(type(i))) + i = int(i) + stacklevel += 1 + warnings.warn(msg, DeprecationWarning, stacklevel=stacklevel) + return i def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None): @@ -44,7 +60,7 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None): There are `num` equally spaced samples in the closed interval ``[start, stop]`` or the half-open interval ``[start, stop)`` (depending on whether `endpoint` is True or False). - step : float + step : float, optional Only returned if `retstep` is True Size of spacing between samples. @@ -59,11 +75,11 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None): Examples -------- >>> np.linspace(2.0, 3.0, num=5) - array([ 2. , 2.25, 2.5 , 2.75, 3. ]) + array([ 2. , 2.25, 2.5 , 2.75, 3. ]) >>> np.linspace(2.0, 3.0, num=5, endpoint=False) - array([ 2. , 2.2, 2.4, 2.6, 2.8]) + array([ 2. , 2.2, 2.4, 2.6, 2.8]) >>> np.linspace(2.0, 3.0, num=5, retstep=True) - (array([ 2. , 2.25, 2.5 , 2.75, 3. ]), 0.25) + (array([ 2. , 2.25, 2.5 , 2.75, 3. ]), 0.25) Graphical illustration: @@ -81,15 +97,16 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None): >>> plt.show() """ - num = int(num) + # 2016-02-25, 1.12 + num = _index_deprecate(num) if num < 0: raise ValueError("Number of samples, %s, must be non-negative." % num) div = (num - 1) if endpoint else num # Convert float/complex array scalars to float, gh-3504 - # Make sure one can use variables that have an __array_interface__, gh-6634 - start = asanyarray(start) * 1. - stop = asanyarray(stop) * 1. + # and make sure one can use variables that have an __array_interface__, gh-6634 + start = asanyarray(start) * 1.0 + stop = asanyarray(stop) * 1.0 dt = result_type(start, stop, float(num)) if dtype is None: @@ -97,18 +114,23 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None): y = _nx.arange(0, num, dtype=dt) + delta = stop - start if num > 1: - delta = stop - start step = delta / div if step == 0: # Special handling for denormal numbers, gh-5437 y /= div - y *= delta + y = y * delta else: - y *= step + # One might be tempted to use faster, in-place multiplication here, + # but this prevents step from overriding what class is produced, + # and thus prevents, e.g., use of Quantities; see gh-7142. + y = y * step else: # 0 and 1 item long sequences have an undefined step step = NaN + # Multiply with delta to allow possible override of output class. + y = y * delta y += start @@ -137,7 +159,7 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None): ``base ** stop`` is the final value of the sequence, unless `endpoint` is False. In that case, ``num + 1`` values are spaced over the interval in log-space, of which all but the last (a sequence of - length ``num``) are returned. + length `num`) are returned. num : integer, optional Number of samples to generate. Default is 50. endpoint : boolean, optional @@ -163,6 +185,7 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None): endpoint may or may not be included. linspace : Similar to logspace, but with the samples uniformly distributed in linear space, instead of log space. + geomspace : Similar to logspace, but with endpoints specified directly. Notes ----- @@ -176,11 +199,11 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None): Examples -------- >>> np.logspace(2.0, 3.0, num=4) - array([ 100. , 215.443469 , 464.15888336, 1000. ]) + array([ 100. , 215.443469 , 464.15888336, 1000. ]) >>> np.logspace(2.0, 3.0, num=4, endpoint=False) - array([ 100. , 177.827941 , 316.22776602, 562.34132519]) + array([ 100. , 177.827941 , 316.22776602, 562.34132519]) >>> np.logspace(2.0, 3.0, num=4, base=2.0) - array([ 4. , 5.0396842 , 6.34960421, 8. ]) + array([ 4. , 5.0396842 , 6.34960421, 8. ]) Graphical illustration: @@ -204,44 +227,125 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None): return _nx.power(base, y).astype(dtype) -def may_share_memory(a, b, max_work=None): - """Determine if two arrays can share memory - - A return of True does not necessarily mean that the two arrays - share any element. It just means that they *might*. +def geomspace(start, stop, num=50, endpoint=True, dtype=None): + """ + Return numbers spaced evenly on a log scale (a geometric progression). - Only the memory bounds of a and b are checked by default. + This is similar to `logspace`, but with endpoints specified directly. + Each output sample is a constant multiple of the previous. Parameters ---------- - a, b : ndarray - Input arrays - max_work : int, optional - Effort to spend on solving the overlap problem. See - `shares_memory` for details. Default for ``may_share_memory`` - is to do a bounds check. + start : scalar + The starting value of the sequence. + stop : scalar + The final value of the sequence, unless `endpoint` is False. + In that case, ``num + 1`` values are spaced over the + interval in log-space, of which all but the last (a sequence of + length `num`) are returned. + num : integer, optional + Number of samples to generate. Default is 50. + endpoint : boolean, optional + If true, `stop` is the last sample. Otherwise, it is not included. + Default is True. + dtype : dtype + The type of the output array. If `dtype` is not given, infer the data + type from the other input arguments. Returns ------- - out : bool + samples : ndarray + `num` samples, equally spaced on a log scale. See Also -------- - shares_memory + logspace : Similar to geomspace, but with endpoints specified using log + and base. + linspace : Similar to geomspace, but with arithmetic instead of geometric + progression. + arange : Similar to linspace, with the step size specified instead of the + number of samples. + + Notes + ----- + If the inputs or dtype are complex, the output will follow a logarithmic + spiral in the complex plane. (There are an infinite number of spirals + passing through two points; the output will follow the shortest such path.) Examples -------- - >>> np.may_share_memory(np.array([1,2]), np.array([5,8,9])) - False - >>> x = np.zeros([3, 4]) - >>> np.may_share_memory(x[:,0], x[:,1]) - True + >>> np.geomspace(1, 1000, num=4) + array([ 1., 10., 100., 1000.]) + >>> np.geomspace(1, 1000, num=3, endpoint=False) + array([ 1., 10., 100.]) + >>> np.geomspace(1, 1000, num=4, endpoint=False) + array([ 1. , 5.62341325, 31.6227766 , 177.827941 ]) + >>> np.geomspace(1, 256, num=9) + array([ 1., 2., 4., 8., 16., 32., 64., 128., 256.]) + + Note that the above may not produce exact integers: + + >>> np.geomspace(1, 256, num=9, dtype=int) + array([ 1, 2, 4, 7, 16, 32, 63, 127, 256]) + >>> np.around(np.geomspace(1, 256, num=9)).astype(int) + array([ 1, 2, 4, 8, 16, 32, 64, 128, 256]) + + Negative, decreasing, and complex inputs are allowed: + + >>> geomspace(1000, 1, num=4) + array([ 1000., 100., 10., 1.]) + >>> geomspace(-1000, -1, num=4) + array([-1000., -100., -10., -1.]) + >>> geomspace(1j, 1000j, num=4) # Straight line + array([ 0. +1.j, 0. +10.j, 0. +100.j, 0.+1000.j]) + >>> geomspace(-1+0j, 1+0j, num=5) # Circle + array([-1.00000000+0.j , -0.70710678+0.70710678j, + 0.00000000+1.j , 0.70710678+0.70710678j, + 1.00000000+0.j ]) + + Graphical illustration of ``endpoint`` parameter: + + >>> import matplotlib.pyplot as plt + >>> N = 10 + >>> y = np.zeros(N) + >>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=True), y + 1, 'o') + >>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=False), y + 2, 'o') + >>> plt.axis([0.5, 2000, 0, 3]) + >>> plt.grid(True, color='0.7', linestyle='-', which='both', axis='both') + >>> plt.show() """ - if max_work is None: - max_work = MAY_SHARE_BOUNDS - try: - return shares_memory(a, b, max_work=max_work) - except (TooHardError, OverflowError): - # Unable to determine, assume yes - return True + if start == 0 or stop == 0: + raise ValueError('Geometric sequence cannot include zero') + + dt = result_type(start, stop, float(num)) + if dtype is None: + dtype = dt + else: + # complex to dtype('complex128'), for instance + dtype = _nx.dtype(dtype) + + # Avoid negligible real or imaginary parts in output by rotating to + # positive real, calculating, then undoing rotation + out_sign = 1 + if start.real == stop.real == 0: + start, stop = start.imag, stop.imag + out_sign = 1j * out_sign + if _nx.sign(start) == _nx.sign(stop) == -1: + start, stop = -start, -stop + out_sign = -out_sign + + # Promote both arguments to the same dtype in case, for instance, one is + # complex and another is negative and log would produce NaN otherwise + start = start + (stop - stop) + stop = stop + (start - start) + if _nx.issubdtype(dtype, complex): + start = start + 0j + stop = stop + 0j + + log_start = _nx.log10(start) + log_stop = _nx.log10(stop) + result = out_sign * logspace(log_start, log_stop, num=num, + endpoint=endpoint, base=10.0, dtype=dtype) + + return result.astype(dtype) |