Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
function_base.py548 linesDownload Raw Back to _core
1import functools
2import inspect
3import operator
4import types
5import warnings
6
7import numpy as np
8from numpy._core import overrides
9from numpy._core._multiarray_umath import _array_converter
10from numpy._core.multiarray import add_docstring
11
12from . import numeric as _nx
13from .numeric import asanyarray, nan, ndim, result_type
14
15__all__ = ['logspace', 'linspace', 'geomspace']
16
17
18array_function_dispatch = functools.partial(
19    overrides.array_function_dispatch, module='numpy')
20
21
22def _linspace_dispatcher(start, stop, num=None, endpoint=None, retstep=None,
23                         dtype=None, axis=None, *, device=None):
24    return (start, stop)
25
26
27@array_function_dispatch(_linspace_dispatcher)
28def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None,
29             axis=0, *, device=None):
30    """
31    Return evenly spaced numbers over a specified interval.
32
33    Returns `num` evenly spaced samples, calculated over the
34    interval [`start`, `stop`].
35
36    The endpoint of the interval can optionally be excluded.
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    axis : int, optional
66        The axis in the result to store the samples.  Relevant only if start
67        or stop are array-like.  By default (0), the samples will be along a
68        new axis inserted at the beginning. Use -1 to get an axis at the end.
69    device : str, optional
70        The device on which to place the created array. Default: None.
71        For Array-API interoperability only, so must be ``"cpu"`` if passed.
72
73        .. versionadded:: 2.0.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    >>> import numpy as np
100    >>> np.linspace(2.0, 3.0, num=5)
101    array([2.  , 2.25, 2.5 , 2.75, 3.  ])
102    >>> np.linspace(2.0, 3.0, num=5, endpoint=False)
103    array([2. ,  2.2,  2.4,  2.6,  2.8])
104    >>> np.linspace(2.0, 3.0, num=5, retstep=True)
105    (array([2.  ,  2.25,  2.5 ,  2.75,  3.  ]), 0.25)
106
107    Graphical illustration:
108
109    >>> import matplotlib.pyplot as plt
110    >>> N = 8
111    >>> y = np.zeros(N)
112    >>> x1 = np.linspace(0, 10, N, endpoint=True)
113    >>> x2 = np.linspace(0, 10, N, endpoint=False)
114    >>> plt.plot(x1, y, 'o')
115    [<matplotlib.lines.Line2D object at 0x...>]
116    >>> plt.plot(x2, y + 0.5, 'o')
117    [<matplotlib.lines.Line2D object at 0x...>]
118    >>> plt.ylim([-0.5, 1])
119    (-0.5, 1)
120    >>> plt.show()
121
122    """
123    num = operator.index(num)
124    if num < 0:
125        raise ValueError(
126            f"Number of samples, {num}, must be non-negative."
127        )
128    div = (num - 1) if endpoint else num
129
130    conv = _array_converter(start, stop)
131    start, stop = conv.as_arrays()
132    dt = conv.result_type(ensure_inexact=True)
133
134    if dtype is None:
135        dtype = dt
136        integer_dtype = False
137    else:
138        integer_dtype = _nx.issubdtype(dtype, _nx.integer)
139
140    # Use `dtype=type(dt)` to enforce a floating point evaluation:
141    delta = np.subtract(stop, start, dtype=type(dt))
142    y = _nx.arange(
143        0, num, dtype=dt, device=device
144    ).reshape((-1,) + (1,) * ndim(delta))
145
146    # In-place multiplication y *= delta/div is faster, but prevents
147    # the multiplicant from overriding what class is produced, and thus
148    # prevents, e.g. use of Quantities, see gh-7142. Hence, we multiply
149    # in place only for standard scalar types.
150    if div > 0:
151        _mult_inplace = _nx.isscalar(delta)
152        step = delta / div
153        any_step_zero = (
154            step == 0 if _mult_inplace else _nx.asanyarray(step == 0).any())
155        if any_step_zero:
156            # Special handling for denormal numbers, gh-5437
157            y /= div
158            if _mult_inplace:
159                y *= delta
160            else:
161                y = y * delta
162        elif _mult_inplace:
163            y *= step
164        else:
165            y = y * step
166    else:
167        # sequences with 0 items or 1 item with endpoint=True (i.e. div <= 0)
168        # have an undefined step
169        step = nan
170        # Multiply with delta to allow possible override of output class.
171        y = y * delta
172
173    y += start
174
175    if endpoint and num > 1:
176        y[-1, ...] = stop
177
178    if axis != 0:
179        y = _nx.moveaxis(y, 0, axis)
180
181    if integer_dtype:
182        _nx.floor(y, out=y)
183
184    y = conv.wrap(y.astype(dtype, copy=False))
185    if retstep:
186        return y, step
187    else:
188        return y
189
190
191def _logspace_dispatcher(start, stop, num=None, endpoint=None, base=None,
192                         dtype=None, axis=None):
193    return (start, stop, base)
194
195
196@array_function_dispatch(_logspace_dispatcher)
197def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None,
198             axis=0):
199    """
200    Return numbers spaced evenly on a log scale.
201
202    In linear space, the sequence starts at ``base ** start``
203    (`base` to the power of `start`) and ends with ``base ** stop``
204    (see `endpoint` below).
205
206    .. versionchanged:: 1.25.0
207        Non-scalar 'base` is now supported
208
209    Parameters
210    ----------
211    start : array_like
212        ``base ** start`` is the starting value of the sequence.
213    stop : array_like
214        ``base ** stop`` is the final value of the sequence, unless `endpoint`
215        is False.  In that case, ``num + 1`` values are spaced over the
216        interval in log-space, of which all but the last (a sequence of
217        length `num`) are returned.
218    num : integer, optional
219        Number of samples to generate.  Default is 50.
220    endpoint : boolean, optional
221        If true, `stop` is the last sample. Otherwise, it is not included.
222        Default is True.
223    base : array_like, optional
224        The base of the log space. The step size between the elements in
225        ``ln(samples) / ln(base)`` (or ``log_base(samples)``) is uniform.
226        Default is 10.0.
227    dtype : dtype
228        The type of the output array.  If `dtype` is not given, the data type
229        is inferred from `start` and `stop`. The inferred type will never be
230        an integer; `float` is chosen even if the arguments would produce an
231        array of integers.
232    axis : int, optional
233        The axis in the result to store the samples.  Relevant only if start,
234        stop, or base are array-like.  By default (0), the samples will be
235        along a new axis inserted at the beginning. Use -1 to get an axis at
236        the end.
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    >>> import numpy as np
265    >>> np.logspace(2.0, 3.0, num=4)
266    array([ 100.        ,  215.443469  ,  464.15888336, 1000.        ])
267    >>> np.logspace(2.0, 3.0, num=4, endpoint=False)
268    array([100.        ,  177.827941  ,  316.22776602,  562.34132519])
269    >>> np.logspace(2.0, 3.0, num=4, base=2.0)
270    array([4.        ,  5.0396842 ,  6.34960421,  8.        ])
271    >>> np.logspace(2.0, 3.0, num=4, base=[2.0, 3.0], axis=-1)
272    array([[ 4.        ,  5.0396842 ,  6.34960421,  8.        ],
273           [ 9.        , 12.98024613, 18.72075441, 27.        ]])
274
275    Graphical illustration:
276
277    >>> import matplotlib.pyplot as plt
278    >>> N = 10
279    >>> x1 = np.logspace(0.1, 1, N, endpoint=True)
280    >>> x2 = np.logspace(0.1, 1, N, endpoint=False)
281    >>> y = np.zeros(N)
282    >>> plt.plot(x1, y, 'o')
283    [<matplotlib.lines.Line2D object at 0x...>]
284    >>> plt.plot(x2, y + 0.5, 'o')
285    [<matplotlib.lines.Line2D object at 0x...>]
286    >>> plt.ylim([-0.5, 1])
287    (-0.5, 1)
288    >>> plt.show()
289
290    """
291    if not isinstance(base, (float, int)) and np.ndim(base):
292        # If base is non-scalar, broadcast it with the others, since it
293        # may influence how axis is interpreted.
294        ndmax = np.broadcast(start, stop, base).ndim
295        start, stop, base = (
296            np.array(a, copy=None, subok=True, ndmin=ndmax)
297            for a in (start, stop, base)
298        )
299        base = np.expand_dims(base, axis=axis)
300    y = linspace(start, stop, num=num, endpoint=endpoint, axis=axis)
301    if dtype is None:
302        return _nx.power(base, y)
303    return _nx.power(base, y).astype(dtype, copy=False)
304
305
306def _geomspace_dispatcher(start, stop, num=None, endpoint=None, dtype=None,
307                          axis=None):
308    return (start, stop)
309
310
311@array_function_dispatch(_geomspace_dispatcher)
312def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0):
313    """
314    Return numbers spaced evenly on a log scale (a geometric progression).
315
316    This is similar to `logspace`, but with endpoints specified directly.
317    Each output sample is a constant multiple of the previous.
318
319    Parameters
320    ----------
321    start : array_like
322        The starting value of the sequence.
323    stop : array_like
324        The final value of the sequence, unless `endpoint` is False.
325        In that case, ``num + 1`` values are spaced over the
326        interval in log-space, of which all but the last (a sequence of
327        length `num`) are returned.
328    num : integer, optional
329        Number of samples to generate.  Default is 50.
330    endpoint : boolean, optional
331        If true, `stop` is the last sample. Otherwise, it is not included.
332        Default is True.
333    dtype : dtype
334        The type of the output array.  If `dtype` is not given, the data type
335        is inferred from `start` and `stop`. The inferred dtype will never be
336        an integer; `float` is chosen even if the arguments would produce an
337        array of integers.
338    axis : int, optional
339        The axis in the result to store the samples.  Relevant only if start
340        or stop are array-like.  By default (0), the samples will be along a
341        new axis inserted at the beginning. Use -1 to get an axis at the end.
342
343    Returns
344    -------
345    samples : ndarray
346        `num` samples, equally spaced on a log scale.
347
348    See Also
349    --------
350    logspace : Similar to geomspace, but with endpoints specified using log
351               and base.
352    linspace : Similar to geomspace, but with arithmetic instead of geometric
353               progression.
354    arange : Similar to linspace, with the step size specified instead of the
355             number of samples.
356    :ref:`how-to-partition`
357
358    Notes
359    -----
360    If the inputs or dtype are complex, the output will follow a logarithmic
361    spiral in the complex plane.  (There are an infinite number of spirals
362    passing through two points; the output will follow the shortest such path.)
363
364    Examples
365    --------
366    >>> import numpy as np
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    # Allow negative real values and ensure a consistent result for complex
430    # (including avoiding negligible real or imaginary parts in output) by
431    # rotating start to positive real, calculating, then undoing rotation.
432    out_sign = _nx.sign(start)
433    start /= out_sign
434    stop = stop / out_sign
435
436    log_start = _nx.log10(start)
437    log_stop = _nx.log10(stop)
438    result = logspace(log_start, log_stop, num=num,
439                      endpoint=endpoint, base=10.0, dtype=dt)
440
441    # Make sure the endpoints match the start and stop arguments. This is
442    # necessary because np.exp(np.log(x)) is not necessarily equal to x.
443    if num > 0:
444        result[0] = start
445        if num > 1 and endpoint:
446            result[-1] = stop
447
448    result *= out_sign
449
450    if axis != 0:
451        result = _nx.moveaxis(result, 0, axis)
452
453    return result.astype(dtype, copy=False)
454
455
456def _needs_add_docstring(obj):
457    """
458    Returns true if the only way to set the docstring of `obj` from python is
459    via add_docstring.
460
461    This function errs on the side of being overly conservative.
462    """
463    Py_TPFLAGS_HEAPTYPE = 1 << 9
464
465    if isinstance(obj, (types.FunctionType, types.MethodType, property)):
466        return False
467
468    if isinstance(obj, type) and obj.__flags__ & Py_TPFLAGS_HEAPTYPE:
469        return False
470
471    return True
472
473
474def _add_docstring(obj, doc, warn_on_python):
475    if warn_on_python and not _needs_add_docstring(obj):
476        warnings.warn(
477            f"add_newdoc was used on a pure-python object {obj}. "
478            "Prefer to attach it directly to the source.",
479            UserWarning,
480            stacklevel=3)
481
482    doc = inspect.cleandoc(doc)
483
484    try:
485        add_docstring(obj, doc)
486    except Exception:
487        pass
488
489
490def add_newdoc(place, obj, doc, warn_on_python=True):
491    """
492    Add documentation to an existing object, typically one defined in C
493
494    The purpose is to allow easier editing of the docstrings without requiring
495    a re-compile. This exists primarily for internal use within numpy itself.
496
497    Parameters
498    ----------
499    place : str
500        The absolute name of the module to import from
501    obj : str | None
502        The name of the object to add documentation to, typically a class or
503        function name.
504    doc : str | tuple[str, str] | list[tuple[str, str]]
505        If a string, the documentation to apply to `obj`
506
507        If a tuple, then the first element is interpreted as an attribute
508        of `obj` and the second as the docstring to apply -
509        ``(method, docstring)``
510
511        If a list, then each element of the list should be a tuple of length
512        two - ``[(method1, docstring1), (method2, docstring2), ...]``
513    warn_on_python : bool
514        If True, the default, emit `UserWarning` if this is used to attach
515        documentation to a pure-python object.
516
517    Notes
518    -----
519    This routine never raises an error if the docstring can't be written, but
520    will raise an error if the object being documented does not exist.
521
522    This routine cannot modify read-only docstrings, as appear
523    in new-style classes or built-in functions. Because this
524    routine never raises an error the caller must check manually
525    that the docstrings were changed.
526
527    Since this function grabs the ``char *`` from a c-level str object and puts
528    it into the ``tp_doc`` slot of the type of `obj`, it violates a number of
529    C-API best-practices, by:
530
531    - modifying a `PyTypeObject` after calling `PyType_Ready`
532    - calling `Py_INCREF` on the str and losing the reference, so the str
533      will never be released
534
535    If possible it should be avoided.
536    """
537    new = getattr(__import__(place, globals(), {}, [obj]), obj)
538    if isinstance(doc, str):
539        if "${ARRAY_FUNCTION_LIKE}" in doc:
540            doc = overrides.get_array_function_like_doc(new, doc)
541        _add_docstring(new, doc, warn_on_python)
542    elif isinstance(doc, tuple):
543        attr, docstring = doc
544        _add_docstring(getattr(new, attr), docstring, warn_on_python)
545    elif isinstance(doc, list):
546        for attr, docstring in doc:
547            _add_docstring(getattr(new, attr), docstring, warn_on_python)
548 
codekingpro/portable-devtools · Team Ai