function_base.py 19 KB

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