8000 Merge pull request #7268 from endolith/geomspace · numpy/numpy@70f50b8 · GitHub
[go: up one dir, main page]

Skip to content

Commit 70f50b8

Browse files
authored
Merge pull request #7268 from endolith/geomspace
ENH: add geomspace function
2 parents f902cfd + e53570d commit 70f50b8

File tree

4 files changed

+313
-47
lines changed

4 files changed

+313
-47
lines changed

doc/release/1.12.0-notes.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,13 @@ from the roots of the polynomial. This is useful for higher order polynomials,
162162
where expansion into polynomial coefficients is inaccurate at machine
163163
precision.
164164

165+
New array creation function ``geomspace`` added
166+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
167+
The new function ``geomspace`` generates a geometric sequence. It is similar
168+
to ``logspace``, but with start and stop specified directly:
169+
``geomspace(start, stop)`` behaves the same as
170+
``logspace(log10(start), log10(stop))``.
171+
165172
Improvements
166173
============
167174

doc/source/reference/routines.array-creation.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ Numerical ranges
8080
arange
8181
linspace
8282
logspace
83+
geomspace
8384
meshgrid
8485
mgrid
8586
ogrid

numpy/core/function_base.py

Lines changed: 138 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import warnings
44
import operator
55

6-
__all__ = ['logspace', 'linspace']
7-
86
from . import numeric as _nx
9-
from .numeric import result_type, NaN, shares_memory, MAY_SHARE_BOUNDS, TooHardError
7+
from .numeric import (result_type, NaN, shares_memory, MAY_SHARE_BOUNDS,
8+
TooHardError)
9+
10+
__all__ = ['logspace', 'linspace', 'geomspace']
11+
1012

1113
def _index_deprecate(i, stacklevel=2):
1214
try:
@@ -73,11 +75,11 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None):
7375
Examples
7476
--------
7577
>>> np.linspace(2.0, 3.0, num=5)
76-
array([ 2. , 2.25, 2.5 , 2.75, 3. ])
78+
array([ 2. , 2.25, 2.5 , 2.75, 3. ])
7779
>>> np.linspace(2.0, 3.0, num=5, endpoint=False)
78-
array([ 2. , 2.2, 2.4, 2.6, 2.8])
80+
array([ 2. , 2.2, 2.4, 2.6, 2.8])
7981
>>> np.linspace(2.0, 3.0, num=5, retstep=True)
80-
(array([ 2. , 2.25, 2.5 , 2.75, 3. ]), 0.25)
82+
(array([ 2. , 2.25, 2.5 , 2.75, 3. ]), 0.25)
8183
8284
Graphical illustration:
8385
@@ -102,8 +104,8 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None):
102104
div = (num - 1) if endpoint else num
103105

104106
# Convert float/complex array scalars to float, gh-3504
105-
start = start * 1.
106-
stop = stop * 1.
107+
start = start * 1.0
108+
stop = stop * 1.0
107109

108110
dt = result_type(start, stop, float(num))
109111
if dtype is None:
@@ -156,7 +158,7 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None):
156158
``base ** stop`` is the final value of the sequence, unless `endpoint`
157159
is False. In that case, ``num + 1`` values are spaced over the
158160
interval in log-space, of which all but the last (a sequence of
159-
length ``num``) are returned.
161+
length `num`) are returned.
160162
num : integer, optional
161163
Number of samples to generate. Default is 50.
162164
endpoint : boolean, optional
@@ -195,11 +197,11 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None):
195197
Examples
196198
--------
197199
>>> np.logspace(2.0, 3.0, num=4)
198-
array([ 100. , 215.443469 , 464.15888336, 1000. ])
200+
array([ 100. , 215.443469 , 464.15888336, 1000. ])
199201
>>> np.logspace(2.0, 3.0, num=4, endpoint=False)
200-
array([ 100. , 177.827941 , 316.22776602, 562.34132519])
202+
array([ 100. , 177.827941 , 316.22776602, 562.34132519])
201203
>>> np.logspace(2.0, 3.0, num=4, base=2.0)
202-
array([ 4. , 5.0396842 , 6.34960421, 8. ])
204+
array([ 4. , 5.0396842 , 6.34960421, 8. ])
203205
204206
Graphical illustration:
205207
@@ -221,3 +223,127 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None):
221223
if dtype is None:
222224
return _nx.power(base, y)
223225
return _nx.power(base, y).astype(dtype)
226+
227+
228+
def geomspace(start, stop, num=50, endpoint=True, dtype=None):
229+
"""
230+
Return numbers spaced evenly on a log scale (a geometric progression).
231+
232+
This is similar to `logspace`, but with endpoints specified directly.
233+
Each output sample is a constant multiple of the previous.
234+
235+
Parameters
236+
----------
237+
start : scalar
238+
The starting value of the sequence.
239+
stop : scalar
240+
The final value of the sequence, unless `endpoint` is False.
241+
In that case, ``num + 1`` values are spaced over the
242+
interval in log-space, of which all but the last (a sequence of
243+
length `num`) are returned.
244+
num : integer, optional
245+
Number of samples to generate. Default is 50.
246+
endpoint : boolean, optional
247+
If true, `stop` is the last sample. Otherwise, it is not included.
248+
Default is True.
249+
dtype : dtype
250+
The type of the output array. If `dtype` is not given, infer the data
251+
type from the other input arguments.
252+
253+
Returns
254+
-------
255+
samples : ndarray
256+
`num` samples, equally spaced on a log scale.
257+
258+
See Also
259+
--------
260+
logspace : Similar to geomspace, but with endpoints specified using log
261+
and base.
262+
linspace : Similar to geomspace, but with arithmetic instead of geometric
263+
progression.
264+
arange : Similar to linspace, with the step size specified instead of the
265+
number of samples.
266+
267+
Notes
268+
-----
269+
If the inputs or dtype are complex, the output will follow a logarithmic
270+
spiral in the complex plane. (There are an infinite number of spirals
271+
passing through two points; the output will follow the shortest such path.)
272+
273+
Examples
274+
--------
275+
>>> np.geomspace(1, 1000, num=4)
276+
array([ 1., 10., 100., 1000.])
277+
>>> np.geomspace(1, 1000, num=3, endpoint=False)
278+
array([ 1., 10., 100.])
279+
>>> np.geomspace(1, 1000, num=4, endpoint=False)
280+
array([ 1. , 5.62341325, 31.6227766 , 177.827941 ])
281+
>>> np.geomspace(1, 256, num=9)
282+
array([ 1., 2., 4., 8., 16., 32., 64., 128., 256.])
283+
284+
Note that the above may not produce exact integers:
285+
286+
>>> np.geomspace(1, 256, num=9, dtype=int)
287+
array([ 1, 2, 4, 7, 16, 32, 63, 127, 256])
288+
>>> np.around(np.geomspace(1, 256, num=9)).astype(int)
289+
array([ 1, 2, 4, 8, 16, 32, 64, 128, 256])
290+
291+
Negative, decreasing, and complex inputs are allowed:
292+
293+
>>> geomspace(1000, 1, num=4)
294+
array([ 1000., 100., 10., 1.])
295+
>>> geomspace(-1000, -1, num=4)
296+
array([-1000., -100., -10., -1.])
297+
>>> geomspace(1j, 1000j, num=4) # Straight line
298+
array([ 0. +1.j, 0. +10.j, 0. +100.j, 0.+1000.j])
299+
>>> geomspace(-1+0j, 1+0j, num=5) # Circle
300+
array([-1.00000000+0.j , -0.70710678+0.70710678j,
301+
0.00000000+1.j , 0.70710678+0.70710678j,
302+
1.00000000+0.j ])
303+
304+
Graphical illustration of ``endpoint`` parameter:
305+
306+
>>> import matplotlib.pyplot as plt
307+
>>> N = 10
308+
>>> y = np.zeros(N)
309+
>>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=True), y + 1, 'o')
310+
>>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=False), y + 2, 'o')
311+
>>> plt.axis([0.5, 2000, 0, 3])
312+
>>> plt.grid(True, color='0.7', linestyle='-', which='both', axis='both')
313+
>>> plt.show()
314+
315+
"""
316+
if start == 0 or stop == 0:
317+
raise ValueError('Geometric sequence cannot include zero')
318+
319+
dt = result_type(start, stop, float(num))
320+
if dtype is None:
321+
dtype = dt
322+
else:
323+
# complex to dtype('complex128'), for instance
324+
dtype = _nx.dtype(dtype)
325+
326+
# Avoid negligible real or imaginary parts in output by rotating to
327+
# positive real, calculating, then undoing rotation
328+
out_sign = 1
329+
if start.real == stop.real == 0:
330+
start, stop = start.imag, stop.imag
331+
out_sign = 1j * out_sign
332+
if _nx.sign(start) == _nx.sign(stop) == -1:
333+
start, stop = -start, -stop
334+
out_sign = -out_sign
335+
336+
# Promote both arguments to the same dtype in case, for instance, one is
337+
# complex and another is negative and log would produce NaN otherwise
338+
start = start + (stop - stop)
339+
stop = stop + (start - start)
340+
if _nx.issubdtype(dtype, complex):
341+
start = start + 0j
342+
stop = stop + 0j
343+
344+
log_start = _nx.log10(start)
345+
log_stop = _nx.log10(stop)
346+
result = out_sign * logspace(log_start, log_stop, num=num,
347+
endpoint=endpoint, base=10.0, dtype=dtype)
348+
349+
return result.astype(dtype)

0 commit comments

Comments
 (0)
0