Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/numpy/lib/_scimath_impl.py: 46%
70 statements
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-09 06:12 +0000
« prev ^ index » next coverage.py v7.4.4, created at 2024-04-09 06:12 +0000
1"""
2Wrapper functions to more user-friendly calling of certain math functions
3whose output data-type is different than the input data-type in certain
4domains of the input.
6For example, for functions like `log` with branch cuts, the versions in this
7module provide the mathematically valid answers in the complex plane::
9 >>> import math
10 >>> np.emath.log(-math.exp(1)) == (1+1j*math.pi)
11 True
13Similarly, `sqrt`, other base logarithms, `power` and trig functions are
14correctly handled. See their respective docstrings for specific examples.
16Functions
17---------
19.. autosummary::
20 :toctree: generated/
22 sqrt
23 log
24 log2
25 logn
26 log10
27 power
28 arccos
29 arcsin
30 arctanh
32"""
33import numpy._core.numeric as nx
34import numpy._core.numerictypes as nt
35from numpy._core.numeric import asarray, any
36from numpy._core.overrides import array_function_dispatch
37from numpy.lib._type_check_impl import isreal
40__all__ = [
41 'sqrt', 'log', 'log2', 'logn', 'log10', 'power', 'arccos', 'arcsin',
42 'arctanh'
43 ]
46_ln2 = nx.log(2.0)
49def _tocomplex(arr):
50 """Convert its input `arr` to a complex array.
52 The input is returned as a complex array of the smallest type that will fit
53 the original data: types like single, byte, short, etc. become csingle,
54 while others become cdouble.
56 A copy of the input is always made.
58 Parameters
59 ----------
60 arr : array
62 Returns
63 -------
64 array
65 An array with the same input data as the input but in complex form.
67 Examples
68 --------
70 First, consider an input of type short:
72 >>> a = np.array([1,2,3],np.short)
74 >>> ac = np.lib.scimath._tocomplex(a); ac
75 array([1.+0.j, 2.+0.j, 3.+0.j], dtype=complex64)
77 >>> ac.dtype
78 dtype('complex64')
80 If the input is of type double, the output is correspondingly of the
81 complex double type as well:
83 >>> b = np.array([1,2,3],np.double)
85 >>> bc = np.lib.scimath._tocomplex(b); bc
86 array([1.+0.j, 2.+0.j, 3.+0.j])
88 >>> bc.dtype
89 dtype('complex128')
91 Note that even if the input was complex to begin with, a copy is still
92 made, since the astype() method always copies:
94 >>> c = np.array([1,2,3],np.csingle)
96 >>> cc = np.lib.scimath._tocomplex(c); cc
97 array([1.+0.j, 2.+0.j, 3.+0.j], dtype=complex64)
99 >>> c *= 2; c
100 array([2.+0.j, 4.+0.j, 6.+0.j], dtype=complex64)
102 >>> cc
103 array([1.+0.j, 2.+0.j, 3.+0.j], dtype=complex64)
104 """
105 if issubclass(arr.dtype.type, (nt.single, nt.byte, nt.short, nt.ubyte,
106 nt.ushort, nt.csingle)):
107 return arr.astype(nt.csingle)
108 else:
109 return arr.astype(nt.cdouble)
112def _fix_real_lt_zero(x):
113 """Convert `x` to complex if it has real, negative components.
115 Otherwise, output is just the array version of the input (via asarray).
117 Parameters
118 ----------
119 x : array_like
121 Returns
122 -------
123 array
125 Examples
126 --------
127 >>> np.lib.scimath._fix_real_lt_zero([1,2])
128 array([1, 2])
130 >>> np.lib.scimath._fix_real_lt_zero([-1,2])
131 array([-1.+0.j, 2.+0.j])
133 """
134 x = asarray(x)
135 if any(isreal(x) & (x < 0)):
136 x = _tocomplex(x)
137 return x
140def _fix_int_lt_zero(x):
141 """Convert `x` to double if it has real, negative components.
143 Otherwise, output is just the array version of the input (via asarray).
145 Parameters
146 ----------
147 x : array_like
149 Returns
150 -------
151 array
153 Examples
154 --------
155 >>> np.lib.scimath._fix_int_lt_zero([1,2])
156 array([1, 2])
158 >>> np.lib.scimath._fix_int_lt_zero([-1,2])
159 array([-1., 2.])
160 """
161 x = asarray(x)
162 if any(isreal(x) & (x < 0)):
163 x = x * 1.0
164 return x
167def _fix_real_abs_gt_1(x):
168 """Convert `x` to complex if it has real components x_i with abs(x_i)>1.
170 Otherwise, output is just the array version of the input (via asarray).
172 Parameters
173 ----------
174 x : array_like
176 Returns
177 -------
178 array
180 Examples
181 --------
182 >>> np.lib.scimath._fix_real_abs_gt_1([0,1])
183 array([0, 1])
185 >>> np.lib.scimath._fix_real_abs_gt_1([0,2])
186 array([0.+0.j, 2.+0.j])
187 """
188 x = asarray(x)
189 if any(isreal(x) & (abs(x) > 1)):
190 x = _tocomplex(x)
191 return x
194def _unary_dispatcher(x):
195 return (x,)
198@array_function_dispatch(_unary_dispatcher)
199def sqrt(x):
200 """
201 Compute the square root of x.
203 For negative input elements, a complex value is returned
204 (unlike `numpy.sqrt` which returns NaN).
206 Parameters
207 ----------
208 x : array_like
209 The input value(s).
211 Returns
212 -------
213 out : ndarray or scalar
214 The square root of `x`. If `x` was a scalar, so is `out`,
215 otherwise an array is returned.
217 See Also
218 --------
219 numpy.sqrt
221 Examples
222 --------
223 For real, non-negative inputs this works just like `numpy.sqrt`:
225 >>> np.emath.sqrt(1)
226 1.0
227 >>> np.emath.sqrt([1, 4])
228 array([1., 2.])
230 But it automatically handles negative inputs:
232 >>> np.emath.sqrt(-1)
233 1j
234 >>> np.emath.sqrt([-1,4])
235 array([0.+1.j, 2.+0.j])
237 Different results are expected because:
238 floating point 0.0 and -0.0 are distinct.
240 For more control, explicitly use complex() as follows:
242 >>> np.emath.sqrt(complex(-4.0, 0.0))
243 2j
244 >>> np.emath.sqrt(complex(-4.0, -0.0))
245 -2j
246 """
247 x = _fix_real_lt_zero(x)
248 return nx.sqrt(x)
251@array_function_dispatch(_unary_dispatcher)
252def log(x):
253 """
254 Compute the natural logarithm of `x`.
256 Return the "principal value" (for a description of this, see `numpy.log`)
257 of :math:`log_e(x)`. For real `x > 0`, this is a real number (``log(0)``
258 returns ``-inf`` and ``log(np.inf)`` returns ``inf``). Otherwise, the
259 complex principle value is returned.
261 Parameters
262 ----------
263 x : array_like
264 The value(s) whose log is (are) required.
266 Returns
267 -------
268 out : ndarray or scalar
269 The log of the `x` value(s). If `x` was a scalar, so is `out`,
270 otherwise an array is returned.
272 See Also
273 --------
274 numpy.log
276 Notes
277 -----
278 For a log() that returns ``NAN`` when real `x < 0`, use `numpy.log`
279 (note, however, that otherwise `numpy.log` and this `log` are identical,
280 i.e., both return ``-inf`` for `x = 0`, ``inf`` for `x = inf`, and,
281 notably, the complex principle value if ``x.imag != 0``).
283 Examples
284 --------
285 >>> np.emath.log(np.exp(1))
286 1.0
288 Negative arguments are handled "correctly" (recall that
289 ``exp(log(x)) == x`` does *not* hold for real ``x < 0``):
291 >>> np.emath.log(-np.exp(1)) == (1 + np.pi * 1j)
292 True
294 """
295 x = _fix_real_lt_zero(x)
296 return nx.log(x)
299@array_function_dispatch(_unary_dispatcher)
300def log10(x):
301 """
302 Compute the logarithm base 10 of `x`.
304 Return the "principal value" (for a description of this, see
305 `numpy.log10`) of :math:`log_{10}(x)`. For real `x > 0`, this
306 is a real number (``log10(0)`` returns ``-inf`` and ``log10(np.inf)``
307 returns ``inf``). Otherwise, the complex principle value is returned.
309 Parameters
310 ----------
311 x : array_like or scalar
312 The value(s) whose log base 10 is (are) required.
314 Returns
315 -------
316 out : ndarray or scalar
317 The log base 10 of the `x` value(s). If `x` was a scalar, so is `out`,
318 otherwise an array object is returned.
320 See Also
321 --------
322 numpy.log10
324 Notes
325 -----
326 For a log10() that returns ``NAN`` when real `x < 0`, use `numpy.log10`
327 (note, however, that otherwise `numpy.log10` and this `log10` are
328 identical, i.e., both return ``-inf`` for `x = 0`, ``inf`` for `x = inf`,
329 and, notably, the complex principle value if ``x.imag != 0``).
331 Examples
332 --------
334 (We set the printing precision so the example can be auto-tested)
336 >>> np.set_printoptions(precision=4)
338 >>> np.emath.log10(10**1)
339 1.0
341 >>> np.emath.log10([-10**1, -10**2, 10**2])
342 array([1.+1.3644j, 2.+1.3644j, 2.+0.j ])
344 """
345 x = _fix_real_lt_zero(x)
346 return nx.log10(x)
349def _logn_dispatcher(n, x):
350 return (n, x,)
353@array_function_dispatch(_logn_dispatcher)
354def logn(n, x):
355 """
356 Take log base n of x.
358 If `x` contains negative inputs, the answer is computed and returned in the
359 complex domain.
361 Parameters
362 ----------
363 n : array_like
364 The integer base(s) in which the log is taken.
365 x : array_like
366 The value(s) whose log base `n` is (are) required.
368 Returns
369 -------
370 out : ndarray or scalar
371 The log base `n` of the `x` value(s). If `x` was a scalar, so is
372 `out`, otherwise an array is returned.
374 Examples
375 --------
376 >>> np.set_printoptions(precision=4)
378 >>> np.emath.logn(2, [4, 8])
379 array([2., 3.])
380 >>> np.emath.logn(2, [-4, -8, 8])
381 array([2.+4.5324j, 3.+4.5324j, 3.+0.j ])
383 """
384 x = _fix_real_lt_zero(x)
385 n = _fix_real_lt_zero(n)
386 return nx.log(x)/nx.log(n)
389@array_function_dispatch(_unary_dispatcher)
390def log2(x):
391 """
392 Compute the logarithm base 2 of `x`.
394 Return the "principal value" (for a description of this, see
395 `numpy.log2`) of :math:`log_2(x)`. For real `x > 0`, this is
396 a real number (``log2(0)`` returns ``-inf`` and ``log2(np.inf)`` returns
397 ``inf``). Otherwise, the complex principle value is returned.
399 Parameters
400 ----------
401 x : array_like
402 The value(s) whose log base 2 is (are) required.
404 Returns
405 -------
406 out : ndarray or scalar
407 The log base 2 of the `x` value(s). If `x` was a scalar, so is `out`,
408 otherwise an array is returned.
410 See Also
411 --------
412 numpy.log2
414 Notes
415 -----
416 For a log2() that returns ``NAN`` when real `x < 0`, use `numpy.log2`
417 (note, however, that otherwise `numpy.log2` and this `log2` are
418 identical, i.e., both return ``-inf`` for `x = 0`, ``inf`` for `x = inf`,
419 and, notably, the complex principle value if ``x.imag != 0``).
421 Examples
422 --------
423 We set the printing precision so the example can be auto-tested:
425 >>> np.set_printoptions(precision=4)
427 >>> np.emath.log2(8)
428 3.0
429 >>> np.emath.log2([-4, -8, 8])
430 array([2.+4.5324j, 3.+4.5324j, 3.+0.j ])
432 """
433 x = _fix_real_lt_zero(x)
434 return nx.log2(x)
437def _power_dispatcher(x, p):
438 return (x, p)
441@array_function_dispatch(_power_dispatcher)
442def power(x, p):
443 """
444 Return x to the power p, (x**p).
446 If `x` contains negative values, the output is converted to the
447 complex domain.
449 Parameters
450 ----------
451 x : array_like
452 The input value(s).
453 p : array_like of ints
454 The power(s) to which `x` is raised. If `x` contains multiple values,
455 `p` has to either be a scalar, or contain the same number of values
456 as `x`. In the latter case, the result is
457 ``x[0]**p[0], x[1]**p[1], ...``.
459 Returns
460 -------
461 out : ndarray or scalar
462 The result of ``x**p``. If `x` and `p` are scalars, so is `out`,
463 otherwise an array is returned.
465 See Also
466 --------
467 numpy.power
469 Examples
470 --------
471 >>> np.set_printoptions(precision=4)
473 >>> np.emath.power(2, 2)
474 4
476 >>> np.emath.power([2, 4], 2)
477 array([ 4, 16])
479 >>> np.emath.power([2, 4], -2)
480 array([0.25 , 0.0625])
482 >>> np.emath.power([-2, 4], 2)
483 array([ 4.-0.j, 16.+0.j])
485 >>> np.emath.power([2, 4], [2, 4])
486 array([ 4, 256])
488 """
489 x = _fix_real_lt_zero(x)
490 p = _fix_int_lt_zero(p)
491 return nx.power(x, p)
494@array_function_dispatch(_unary_dispatcher)
495def arccos(x):
496 """
497 Compute the inverse cosine of x.
499 Return the "principal value" (for a description of this, see
500 `numpy.arccos`) of the inverse cosine of `x`. For real `x` such that
501 `abs(x) <= 1`, this is a real number in the closed interval
502 :math:`[0, \\pi]`. Otherwise, the complex principle value is returned.
504 Parameters
505 ----------
506 x : array_like or scalar
507 The value(s) whose arccos is (are) required.
509 Returns
510 -------
511 out : ndarray or scalar
512 The inverse cosine(s) of the `x` value(s). If `x` was a scalar, so
513 is `out`, otherwise an array object is returned.
515 See Also
516 --------
517 numpy.arccos
519 Notes
520 -----
521 For an arccos() that returns ``NAN`` when real `x` is not in the
522 interval ``[-1,1]``, use `numpy.arccos`.
524 Examples
525 --------
526 >>> np.set_printoptions(precision=4)
528 >>> np.emath.arccos(1) # a scalar is returned
529 0.0
531 >>> np.emath.arccos([1,2])
532 array([0.-0.j , 0.-1.317j])
534 """
535 x = _fix_real_abs_gt_1(x)
536 return nx.arccos(x)
539@array_function_dispatch(_unary_dispatcher)
540def arcsin(x):
541 """
542 Compute the inverse sine of x.
544 Return the "principal value" (for a description of this, see
545 `numpy.arcsin`) of the inverse sine of `x`. For real `x` such that
546 `abs(x) <= 1`, this is a real number in the closed interval
547 :math:`[-\\pi/2, \\pi/2]`. Otherwise, the complex principle value is
548 returned.
550 Parameters
551 ----------
552 x : array_like or scalar
553 The value(s) whose arcsin is (are) required.
555 Returns
556 -------
557 out : ndarray or scalar
558 The inverse sine(s) of the `x` value(s). If `x` was a scalar, so
559 is `out`, otherwise an array object is returned.
561 See Also
562 --------
563 numpy.arcsin
565 Notes
566 -----
567 For an arcsin() that returns ``NAN`` when real `x` is not in the
568 interval ``[-1,1]``, use `numpy.arcsin`.
570 Examples
571 --------
572 >>> np.set_printoptions(precision=4)
574 >>> np.emath.arcsin(0)
575 0.0
577 >>> np.emath.arcsin([0,1])
578 array([0. , 1.5708])
580 """
581 x = _fix_real_abs_gt_1(x)
582 return nx.arcsin(x)
585@array_function_dispatch(_unary_dispatcher)
586def arctanh(x):
587 """
588 Compute the inverse hyperbolic tangent of `x`.
590 Return the "principal value" (for a description of this, see
591 `numpy.arctanh`) of ``arctanh(x)``. For real `x` such that
592 ``abs(x) < 1``, this is a real number. If `abs(x) > 1`, or if `x` is
593 complex, the result is complex. Finally, `x = 1` returns``inf`` and
594 ``x=-1`` returns ``-inf``.
596 Parameters
597 ----------
598 x : array_like
599 The value(s) whose arctanh is (are) required.
601 Returns
602 -------
603 out : ndarray or scalar
604 The inverse hyperbolic tangent(s) of the `x` value(s). If `x` was
605 a scalar so is `out`, otherwise an array is returned.
608 See Also
609 --------
610 numpy.arctanh
612 Notes
613 -----
614 For an arctanh() that returns ``NAN`` when real `x` is not in the
615 interval ``(-1,1)``, use `numpy.arctanh` (this latter, however, does
616 return +/-inf for ``x = +/-1``).
618 Examples
619 --------
620 >>> np.set_printoptions(precision=4)
622 >>> np.emath.arctanh(0.5)
623 0.5493061443340549
625 >>> from numpy.testing import suppress_warnings
626 >>> with suppress_warnings() as sup:
627 ... sup.filter(RuntimeWarning)
628 ... np.emath.arctanh(np.eye(2))
629 array([[inf, 0.],
630 [ 0., inf]])
631 >>> np.emath.arctanh([1j])
632 array([0.+0.7854j])
634 """
635 x = _fix_real_abs_gt_1(x)
636 return nx.arctanh(x)