1import functools
2import warnings
3import operator
4import types
5
6import numpy as np
7from . import numeric as _nx
8from .numeric import result_type, NaN, asanyarray, ndim
9from numpy.core.multiarray import add_docstring
10from numpy.core import overrides
11
12__all__ = ['logspace', 'linspace', 'geomspace']
13
14
15array_function_dispatch = functools.partial(
16 overrides.array_function_dispatch, module='numpy')
17
18
19def _linspace_dispatcher(start, stop, num=None, endpoint=None, retstep=None,
20 dtype=None, axis=None):
21 return (start, stop)
22
23
24@array_function_dispatch(_linspace_dispatcher)
25def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None,
26 axis=0):
27 """
28 Return evenly spaced numbers over a specified interval.
29
30 Returns `num` evenly spaced samples, calculated over the
31 interval [`start`, `stop`].
32
33 The endpoint of the interval can optionally be excluded.
34
35 .. versionchanged:: 1.16.0
36 Non-scalar `start` and `stop` are now supported.
37
38 .. versionchanged:: 1.20.0
39 Values are rounded towards ``-inf`` instead of ``0`` when an
40 integer ``dtype`` is specified. The old behavior can
41 still be obtained with ``np.linspace(start, stop, num).astype(int)``
42
43 Parameters
44 ----------
45 start : array_like
46 The starting value of the sequence.
47 stop : array_like
48 The end value of the sequence, unless `endpoint` is set to False.
49 In that case, the sequence consists of all but the last of ``num + 1``
50 evenly spaced samples, so that `stop` is excluded. Note that the step
51 size changes when `endpoint` is False.
52 num : int, optional
53 Number of samples to generate. Default is 50. Must be non-negative.
54 endpoint : bool, optional
55 If True, `stop` is the last sample. Otherwise, it is not included.
56 Default is True.
57 retstep : bool, optional
58 If True, return (`samples`, `step`), where `step` is the spacing
59 between samples.
60 dtype : dtype, optional
61 The type of the output array. If `dtype` is not given, the data type
62 is inferred from `start` and `stop`. The inferred dtype will never be
63 an integer; `float` is chosen even if the arguments would produce an
64 array of integers.
65
66 .. versionadded:: 1.9.0
67
68 axis : int, optional
69 The axis in the result to store the samples. Relevant only if start
70 or stop are array-like. By default (0), the samples will be along a
71 new axis inserted at the beginning. Use -1 to get an axis at the end.
72
73 .. versionadded:: 1.16.0
74
75 Returns
76 -------
77 samples : ndarray
78 There are `num` equally spaced samples in the closed interval
79 ``[start, stop]`` or the half-open interval ``[start, stop)``
80 (depending on whether `endpoint` is True or False).
81 step : float, optional
82 Only returned if `retstep` is True
83
84 Size of spacing between samples.
85
86
87 See Also
88 --------
89 arange : Similar to `linspace`, but uses a step size (instead of the
90 number of samples).
91 geomspace : Similar to `linspace`, but with numbers spaced evenly on a log
92 scale (a geometric progression).
93 logspace : Similar to `geomspace`, but with the end points specified as
94 logarithms.
95 :ref:`how-to-partition`
96
97 Examples
98 --------
99 >>> np.linspace(2.0, 3.0, num=5)
100 array([2. , 2.25, 2.5 , 2.75, 3. ])
101 >>> np.linspace(2.0, 3.0, num=5, endpoint=False)
102 array([2. , 2.2, 2.4, 2.6, 2.8])
103 >>> np.linspace(2.0, 3.0, num=5, retstep=True)
104 (array([2. , 2.25, 2.5 , 2.75, 3. ]), 0.25)
105
106 Graphical illustration:
107
108 >>> import matplotlib.pyplot as plt
109 >>> N = 8
110 >>> y = np.zeros(N)
111 >>> x1 = np.linspace(0, 10, N, endpoint=True)
112 >>> x2 = np.linspace(0, 10, N, endpoint=False)
113 >>> plt.plot(x1, y, 'o')
114 [<matplotlib.lines.Line2D object at 0x...>]
115 >>> plt.plot(x2, y + 0.5, 'o')
116 [<matplotlib.lines.Line2D object at 0x...>]
117 >>> plt.ylim([-0.5, 1])
118 (-0.5, 1)
119 >>> plt.show()
120
121 """
122 num = operator.index(num)
123 if num < 0:
124 raise ValueError("Number of samples, %s, must be non-negative." % num)
125 div = (num - 1) if endpoint else num
126
127 # Convert float/complex array scalars to float, gh-3504
128 # and make sure one can use variables that have an __array_interface__, gh-6634
129 start = asanyarray(start) * 1.0
130 stop = asanyarray(stop) * 1.0
131
132 dt = result_type(start, stop, float(num))
133 if dtype is None:
134 dtype = dt
135 integer_dtype = False
136 else:
137 integer_dtype = _nx.issubdtype(dtype, _nx.integer)
138
139 delta = stop - start
140 y = _nx.arange(0, num, dtype=dt).reshape((-1,) + (1,) * ndim(delta))
141 # In-place multiplication y *= delta/div is faster, but prevents the multiplicant
142 # from overriding what class is produced, and thus prevents, e.g. use of Quantities,
143 # see gh-7142. Hence, we multiply in place only for standard scalar types.
144 if div > 0:
145 _mult_inplace = _nx.isscalar(delta)
146 step = delta / div
147 any_step_zero = (
148 step == 0 if _mult_inplace else _nx.asanyarray(step == 0).any())
149 if any_step_zero:
150 # Special handling for denormal numbers, gh-5437
151 y /= div
152 if _mult_inplace:
153 y *= delta
154 else:
155 y = y * delta
156 else:
157 if _mult_inplace:
158 y *= step
159 else:
160 y = y * step
161 else:
162 # sequences with 0 items or 1 item with endpoint=True (i.e. div <= 0)
163 # have an undefined step
164 step = NaN
165 # Multiply with delta to allow possible override of output class.
166 y = y * delta
167
168 y += start
169
170 if endpoint and num > 1:
171 y[-1, ...] = stop
172
173 if axis != 0:
174 y = _nx.moveaxis(y, 0, axis)
175
176 if integer_dtype:
177 _nx.floor(y, out=y)
178
179 if retstep:
180 return y.astype(dtype, copy=False), step
181 else:
182 return y.astype(dtype, copy=False)
183
184
185def _logspace_dispatcher(start, stop, num=None, endpoint=None, base=None,
186 dtype=None, axis=None):
187 return (start, stop, base)
188
189
190@array_function_dispatch(_logspace_dispatcher)
191def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None,
192 axis=0):
193 """
194 Return numbers spaced evenly on a log scale.
195
196 In linear space, the sequence starts at ``base ** start``
197 (`base` to the power of `start`) and ends with ``base ** stop``
198 (see `endpoint` below).
199
200 .. versionchanged:: 1.16.0
201 Non-scalar `start` and `stop` are now supported.
202
203 .. versionchanged:: 1.25.0
204 Non-scalar 'base` is now supported
205
206 Parameters
207 ----------
208 start : array_like
209 ``base ** start`` is the starting value of the sequence.
210 stop : array_like
211 ``base ** stop`` is the final value of the sequence, unless `endpoint`
212 is False. In that case, ``num + 1`` values are spaced over the
213 interval in log-space, of which all but the last (a sequence of
214 length `num`) are returned.
215 num : integer, optional
216 Number of samples to generate. Default is 50.
217 endpoint : boolean, optional
218 If true, `stop` is the last sample. Otherwise, it is not included.
219 Default is True.
220 base : array_like, optional
221 The base of the log space. The step size between the elements in
222 ``ln(samples) / ln(base)`` (or ``log_base(samples)``) is uniform.
223 Default is 10.0.
224 dtype : dtype
225 The type of the output array. If `dtype` is not given, the data type
226 is inferred from `start` and `stop`. The inferred type will never be
227 an integer; `float` is chosen even if the arguments would produce an
228 array of integers.
229 axis : int, optional
230 The axis in the result to store the samples. Relevant only if start,
231 stop, or base are array-like. By default (0), the samples will be
232 along a new axis inserted at the beginning. Use -1 to get an axis at
233 the end.
234
235 .. versionadded:: 1.16.0
236
237
238 Returns
239 -------
240 samples : ndarray
241 `num` samples, equally spaced on a log scale.
242
243 See Also
244 --------
245 arange : Similar to linspace, with the step size specified instead of the
246 number of samples. Note that, when used with a float endpoint, the
247 endpoint may or may not be included.
248 linspace : Similar to logspace, but with the samples uniformly distributed
249 in linear space, instead of log space.
250 geomspace : Similar to logspace, but with endpoints specified directly.
251 :ref:`how-to-partition`
252
253 Notes
254 -----
255 If base is a scalar, logspace is equivalent to the code
256
257 >>> y = np.linspace(start, stop, num=num, endpoint=endpoint)
258 ... # doctest: +SKIP
259 >>> power(base, y).astype(dtype)
260 ... # doctest: +SKIP
261
262 Examples
263 --------
264 >>> np.logspace(2.0, 3.0, num=4)
265 array([ 100. , 215.443469 , 464.15888336, 1000. ])
266 >>> np.logspace(2.0, 3.0, num=4, endpoint=False)
267 array([100. , 177.827941 , 316.22776602, 562.34132519])
268 >>> np.logspace(2.0, 3.0, num=4, base=2.0)
269 array([4. , 5.0396842 , 6.34960421, 8. ])
270 >>> np.logspace(2.0, 3.0, num=4, base=[2.0, 3.0], axis=-1)
271 array([[ 4. , 5.0396842 , 6.34960421, 8. ],
272 [ 9. , 12.98024613, 18.72075441, 27. ]])
273
274 Graphical illustration:
275
276 >>> import matplotlib.pyplot as plt
277 >>> N = 10
278 >>> x1 = np.logspace(0.1, 1, N, endpoint=True)
279 >>> x2 = np.logspace(0.1, 1, N, endpoint=False)
280 >>> y = np.zeros(N)
281 >>> plt.plot(x1, y, 'o')
282 [<matplotlib.lines.Line2D object at 0x...>]
283 >>> plt.plot(x2, y + 0.5, 'o')
284 [<matplotlib.lines.Line2D object at 0x...>]
285 >>> plt.ylim([-0.5, 1])
286 (-0.5, 1)
287 >>> plt.show()
288
289 """
290 ndmax = np.broadcast(start, stop, base).ndim
291 start, stop, base = (
292 np.array(a, copy=False, subok=True, ndmin=ndmax)
293 for a in (start, stop, base)
294 )
295 y = linspace(start, stop, num=num, endpoint=endpoint, axis=axis)
296 base = np.expand_dims(base, axis=axis)
297 if dtype is None:
298 return _nx.power(base, y)
299 return _nx.power(base, y).astype(dtype, copy=False)
300
301
302def _geomspace_dispatcher(start, stop, num=None, endpoint=None, dtype=None,
303 axis=None):
304 return (start, stop)
305
306
307@array_function_dispatch(_geomspace_dispatcher)
308def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0):
309 """
310 Return numbers spaced evenly on a log scale (a geometric progression).
311
312 This is similar to `logspace`, but with endpoints specified directly.
313 Each output sample is a constant multiple of the previous.
314
315 .. versionchanged:: 1.16.0
316 Non-scalar `start` and `stop` are now supported.
317
318 Parameters
319 ----------
320 start : array_like
321 The starting value of the sequence.
322 stop : array_like
323 The final value of the sequence, unless `endpoint` is False.
324 In that case, ``num + 1`` values are spaced over the
325 interval in log-space, of which all but the last (a sequence of
326 length `num`) are returned.
327 num : integer, optional
328 Number of samples to generate. Default is 50.
329 endpoint : boolean, optional
330 If true, `stop` is the last sample. Otherwise, it is not included.
331 Default is True.
332 dtype : dtype
333 The type of the output array. If `dtype` is not given, the data type
334 is inferred from `start` and `stop`. The inferred dtype will never be
335 an integer; `float` is chosen even if the arguments would produce an
336 array of integers.
337 axis : int, optional
338 The axis in the result to store the samples. Relevant only if start
339 or stop are array-like. By default (0), the samples will be along a
340 new axis inserted at the beginning. Use -1 to get an axis at the end.
341
342 .. versionadded:: 1.16.0
343
344 Returns
345 -------
346 samples : ndarray
347 `num` samples, equally spaced on a log scale.
348
349 See Also
350 --------
351 logspace : Similar to geomspace, but with endpoints specified using log
352 and base.
353 linspace : Similar to geomspace, but with arithmetic instead of geometric
354 progression.
355 arange : Similar to linspace, with the step size specified instead of the
356 number of samples.
357 :ref:`how-to-partition`
358
359 Notes
360 -----
361 If the inputs or dtype are complex, the output will follow a logarithmic
362 spiral in the complex plane. (There are an infinite number of spirals
363 passing through two points; the output will follow the shortest such path.)
364
365 Examples
366 --------
367 >>> np.geomspace(1, 1000, num=4)
368 array([ 1., 10., 100., 1000.])
369 >>> np.geomspace(1, 1000, num=3, endpoint=False)
370 array([ 1., 10., 100.])
371 >>> np.geomspace(1, 1000, num=4, endpoint=False)
372 array([ 1. , 5.62341325, 31.6227766 , 177.827941 ])
373 >>> np.geomspace(1, 256, num=9)
374 array([ 1., 2., 4., 8., 16., 32., 64., 128., 256.])
375
376 Note that the above may not produce exact integers:
377
378 >>> np.geomspace(1, 256, num=9, dtype=int)
379 array([ 1, 2, 4, 7, 16, 32, 63, 127, 256])
380 >>> np.around(np.geomspace(1, 256, num=9)).astype(int)
381 array([ 1, 2, 4, 8, 16, 32, 64, 128, 256])
382
383 Negative, decreasing, and complex inputs are allowed:
384
385 >>> np.geomspace(1000, 1, num=4)
386 array([1000., 100., 10., 1.])
387 >>> np.geomspace(-1000, -1, num=4)
388 array([-1000., -100., -10., -1.])
389 >>> np.geomspace(1j, 1000j, num=4) # Straight line
390 array([0. +1.j, 0. +10.j, 0. +100.j, 0.+1000.j])
391 >>> np.geomspace(-1+0j, 1+0j, num=5) # Circle
392 array([-1.00000000e+00+1.22464680e-16j, -7.07106781e-01+7.07106781e-01j,
393 6.12323400e-17+1.00000000e+00j, 7.07106781e-01+7.07106781e-01j,
394 1.00000000e+00+0.00000000e+00j])
395
396 Graphical illustration of `endpoint` parameter:
397
398 >>> import matplotlib.pyplot as plt
399 >>> N = 10
400 >>> y = np.zeros(N)
401 >>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=True), y + 1, 'o')
402 [<matplotlib.lines.Line2D object at 0x...>]
403 >>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=False), y + 2, 'o')
404 [<matplotlib.lines.Line2D object at 0x...>]
405 >>> plt.axis([0.5, 2000, 0, 3])
406 [0.5, 2000, 0, 3]
407 >>> plt.grid(True, color='0.7', linestyle='-', which='both', axis='both')
408 >>> plt.show()
409
410 """
411 start = asanyarray(start)
412 stop = asanyarray(stop)
413 if _nx.any(start == 0) or _nx.any(stop == 0):
414 raise ValueError('Geometric sequence cannot include zero')
415
416 dt = result_type(start, stop, float(num), _nx.zeros((), dtype))
417 if dtype is None:
418 dtype = dt
419 else:
420 # complex to dtype('complex128'), for instance
421 dtype = _nx.dtype(dtype)
422
423 # Promote both arguments to the same dtype in case, for instance, one is
424 # complex and another is negative and log would produce NaN otherwise.
425 # Copy since we may change things in-place further down.
426 start = start.astype(dt, copy=True)
427 stop = stop.astype(dt, copy=True)
428
429 out_sign = _nx.ones(_nx.broadcast(start, stop).shape, dt)
430 # Avoid negligible real or imaginary parts in output by rotating to
431 # positive real, calculating, then undoing rotation
432 if _nx.issubdtype(dt, _nx.complexfloating):
433 all_imag = (start.real == 0.) & (stop.real == 0.)
434 if _nx.any(all_imag):
435 start[all_imag] = start[all_imag].imag
436 stop[all_imag] = stop[all_imag].imag
437 out_sign[all_imag] = 1j
438
439 both_negative = (_nx.sign(start) == -1) & (_nx.sign(stop) == -1)
440 if _nx.any(both_negative):
441 _nx.negative(start, out=start, where=both_negative)
442 _nx.negative(stop, out=stop, where=both_negative)
443 _nx.negative(out_sign, out=out_sign, where=both_negative)
444
445 log_start = _nx.log10(start)
446 log_stop = _nx.log10(stop)
447 result = logspace(log_start, log_stop, num=num,
448 endpoint=endpoint, base=10.0, dtype=dtype)
449
450 # Make sure the endpoints match the start and stop arguments. This is
451 # necessary because np.exp(np.log(x)) is not necessarily equal to x.
452 if num > 0:
453 result[0] = start
454 if num > 1 and endpoint:
455 result[-1] = stop
456
457 result = out_sign * result
458
459 if axis != 0:
460 result = _nx.moveaxis(result, 0, axis)
461
462 return result.astype(dtype, copy=False)
463
464
465def _needs_add_docstring(obj):
466 """
467 Returns true if the only way to set the docstring of `obj` from python is
468 via add_docstring.
469
470 This function errs on the side of being overly conservative.
471 """
472 Py_TPFLAGS_HEAPTYPE = 1 << 9
473
474 if isinstance(obj, (types.FunctionType, types.MethodType, property)):
475 return False
476
477 if isinstance(obj, type) and obj.__flags__ & Py_TPFLAGS_HEAPTYPE:
478 return False
479
480 return True
481
482
483def _add_docstring(obj, doc, warn_on_python):
484 if warn_on_python and not _needs_add_docstring(obj):
485 warnings.warn(
486 "add_newdoc was used on a pure-python object {}. "
487 "Prefer to attach it directly to the source."
488 .format(obj),
489 UserWarning,
490 stacklevel=3)
491 try:
492 add_docstring(obj, doc)
493 except Exception:
494 pass
495
496
497def add_newdoc(place, obj, doc, warn_on_python=True):
498 """
499 Add documentation to an existing object, typically one defined in C
500
501 The purpose is to allow easier editing of the docstrings without requiring
502 a re-compile. This exists primarily for internal use within numpy itself.
503
504 Parameters
505 ----------
506 place : str
507 The absolute name of the module to import from
508 obj : str
509 The name of the object to add documentation to, typically a class or
510 function name
511 doc : {str, Tuple[str, str], List[Tuple[str, str]]}
512 If a string, the documentation to apply to `obj`
513
514 If a tuple, then the first element is interpreted as an attribute of
515 `obj` and the second as the docstring to apply - ``(method, docstring)``
516
517 If a list, then each element of the list should be a tuple of length
518 two - ``[(method1, docstring1), (method2, docstring2), ...]``
519 warn_on_python : bool
520 If True, the default, emit `UserWarning` if this is used to attach
521 documentation to a pure-python object.
522
523 Notes
524 -----
525 This routine never raises an error if the docstring can't be written, but
526 will raise an error if the object being documented does not exist.
527
528 This routine cannot modify read-only docstrings, as appear
529 in new-style classes or built-in functions. Because this
530 routine never raises an error the caller must check manually
531 that the docstrings were changed.
532
533 Since this function grabs the ``char *`` from a c-level str object and puts
534 it into the ``tp_doc`` slot of the type of `obj`, it violates a number of
535 C-API best-practices, by:
536
537 - modifying a `PyTypeObject` after calling `PyType_Ready`
538 - calling `Py_INCREF` on the str and losing the reference, so the str
539 will never be released
540
541 If possible it should be avoided.
542 """
543 new = getattr(__import__(place, globals(), {}, [obj]), obj)
544 if isinstance(doc, str):
545 _add_docstring(new, doc.strip(), warn_on_python)
546 elif isinstance(doc, tuple):
547 attr, docstring = doc
548 _add_docstring(getattr(new, attr), docstring.strip(), warn_on_python)
549 elif isinstance(doc, list):
550 for attr, docstring in doc:
551 _add_docstring(getattr(new, attr), docstring.strip(), warn_on_python)