summaryrefslogtreecommitdiff
path: root/numpy/core/function_base.py
diff options
context:
space:
mode:
authorFrançois Bissey <francois.bissey@canterbury.ac.nz>2016-08-23 21:14:54 +1200
committerFrançois Bissey <francois.bissey@canterbury.ac.nz>2016-08-23 21:14:54 +1200
commit9266c2dfb97248dd20719c12ff9a009a71d941aa (patch)
tree891484d157a4c69c4af15fe46b957fe9f2705472 /numpy/core/function_base.py
parent072e8a5572f0104c4b28828cb1404bed8682e951 (diff)
parent276423aa7f4f7d39189ee5ccf7b167ad2c9c25a7 (diff)
downloadnumpy-9266c2dfb97248dd20719c12ff9a009a71d941aa.tar.gz
Merge branch 'master' into asarray
Diffstat (limited to 'numpy/core/function_base.py')
-rw-r--r--numpy/core/function_base.py190
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)