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

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. 

5 

6For example, for functions like `log` with branch cuts, the versions in this 

7module provide the mathematically valid answers in the complex plane:: 

8 

9 >>> import math 

10 >>> np.emath.log(-math.exp(1)) == (1+1j*math.pi) 

11 True 

12 

13Similarly, `sqrt`, other base logarithms, `power` and trig functions are 

14correctly handled. See their respective docstrings for specific examples. 

15 

16Functions 

17--------- 

18 

19.. autosummary:: 

20 :toctree: generated/ 

21 

22 sqrt 

23 log 

24 log2 

25 logn 

26 log10 

27 power 

28 arccos 

29 arcsin 

30 arctanh 

31 

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 

38 

39 

40__all__ = [ 

41 'sqrt', 'log', 'log2', 'logn', 'log10', 'power', 'arccos', 'arcsin', 

42 'arctanh' 

43 ] 

44 

45 

46_ln2 = nx.log(2.0) 

47 

48 

49def _tocomplex(arr): 

50 """Convert its input `arr` to a complex array. 

51 

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. 

55 

56 A copy of the input is always made. 

57 

58 Parameters 

59 ---------- 

60 arr : array 

61 

62 Returns 

63 ------- 

64 array 

65 An array with the same input data as the input but in complex form. 

66 

67 Examples 

68 -------- 

69 

70 First, consider an input of type short: 

71 

72 >>> a = np.array([1,2,3],np.short) 

73 

74 >>> ac = np.lib.scimath._tocomplex(a); ac 

75 array([1.+0.j, 2.+0.j, 3.+0.j], dtype=complex64) 

76 

77 >>> ac.dtype 

78 dtype('complex64') 

79 

80 If the input is of type double, the output is correspondingly of the 

81 complex double type as well: 

82 

83 >>> b = np.array([1,2,3],np.double) 

84 

85 >>> bc = np.lib.scimath._tocomplex(b); bc 

86 array([1.+0.j, 2.+0.j, 3.+0.j]) 

87 

88 >>> bc.dtype 

89 dtype('complex128') 

90 

91 Note that even if the input was complex to begin with, a copy is still 

92 made, since the astype() method always copies: 

93 

94 >>> c = np.array([1,2,3],np.csingle) 

95 

96 >>> cc = np.lib.scimath._tocomplex(c); cc 

97 array([1.+0.j, 2.+0.j, 3.+0.j], dtype=complex64) 

98 

99 >>> c *= 2; c 

100 array([2.+0.j, 4.+0.j, 6.+0.j], dtype=complex64) 

101 

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) 

110 

111 

112def _fix_real_lt_zero(x): 

113 """Convert `x` to complex if it has real, negative components. 

114 

115 Otherwise, output is just the array version of the input (via asarray). 

116 

117 Parameters 

118 ---------- 

119 x : array_like 

120 

121 Returns 

122 ------- 

123 array 

124 

125 Examples 

126 -------- 

127 >>> np.lib.scimath._fix_real_lt_zero([1,2]) 

128 array([1, 2]) 

129 

130 >>> np.lib.scimath._fix_real_lt_zero([-1,2]) 

131 array([-1.+0.j, 2.+0.j]) 

132 

133 """ 

134 x = asarray(x) 

135 if any(isreal(x) & (x < 0)): 

136 x = _tocomplex(x) 

137 return x 

138 

139 

140def _fix_int_lt_zero(x): 

141 """Convert `x` to double if it has real, negative components. 

142 

143 Otherwise, output is just the array version of the input (via asarray). 

144 

145 Parameters 

146 ---------- 

147 x : array_like 

148 

149 Returns 

150 ------- 

151 array 

152 

153 Examples 

154 -------- 

155 >>> np.lib.scimath._fix_int_lt_zero([1,2]) 

156 array([1, 2]) 

157 

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 

165 

166 

167def _fix_real_abs_gt_1(x): 

168 """Convert `x` to complex if it has real components x_i with abs(x_i)>1. 

169 

170 Otherwise, output is just the array version of the input (via asarray). 

171 

172 Parameters 

173 ---------- 

174 x : array_like 

175 

176 Returns 

177 ------- 

178 array 

179 

180 Examples 

181 -------- 

182 >>> np.lib.scimath._fix_real_abs_gt_1([0,1]) 

183 array([0, 1]) 

184 

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 

192 

193 

194def _unary_dispatcher(x): 

195 return (x,) 

196 

197 

198@array_function_dispatch(_unary_dispatcher) 

199def sqrt(x): 

200 """ 

201 Compute the square root of x. 

202 

203 For negative input elements, a complex value is returned 

204 (unlike `numpy.sqrt` which returns NaN). 

205 

206 Parameters 

207 ---------- 

208 x : array_like 

209 The input value(s). 

210 

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. 

216 

217 See Also 

218 -------- 

219 numpy.sqrt 

220 

221 Examples 

222 -------- 

223 For real, non-negative inputs this works just like `numpy.sqrt`: 

224 

225 >>> np.emath.sqrt(1) 

226 1.0 

227 >>> np.emath.sqrt([1, 4]) 

228 array([1., 2.]) 

229 

230 But it automatically handles negative inputs: 

231 

232 >>> np.emath.sqrt(-1) 

233 1j 

234 >>> np.emath.sqrt([-1,4]) 

235 array([0.+1.j, 2.+0.j]) 

236 

237 Different results are expected because: 

238 floating point 0.0 and -0.0 are distinct. 

239 

240 For more control, explicitly use complex() as follows: 

241 

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) 

249 

250 

251@array_function_dispatch(_unary_dispatcher) 

252def log(x): 

253 """ 

254 Compute the natural logarithm of `x`. 

255 

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. 

260 

261 Parameters 

262 ---------- 

263 x : array_like 

264 The value(s) whose log is (are) required. 

265 

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. 

271 

272 See Also 

273 -------- 

274 numpy.log 

275 

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``). 

282 

283 Examples 

284 -------- 

285 >>> np.emath.log(np.exp(1)) 

286 1.0 

287 

288 Negative arguments are handled "correctly" (recall that 

289 ``exp(log(x)) == x`` does *not* hold for real ``x < 0``): 

290 

291 >>> np.emath.log(-np.exp(1)) == (1 + np.pi * 1j) 

292 True 

293 

294 """ 

295 x = _fix_real_lt_zero(x) 

296 return nx.log(x) 

297 

298 

299@array_function_dispatch(_unary_dispatcher) 

300def log10(x): 

301 """ 

302 Compute the logarithm base 10 of `x`. 

303 

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. 

308 

309 Parameters 

310 ---------- 

311 x : array_like or scalar 

312 The value(s) whose log base 10 is (are) required. 

313 

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. 

319 

320 See Also 

321 -------- 

322 numpy.log10 

323 

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``). 

330 

331 Examples 

332 -------- 

333 

334 (We set the printing precision so the example can be auto-tested) 

335 

336 >>> np.set_printoptions(precision=4) 

337 

338 >>> np.emath.log10(10**1) 

339 1.0 

340 

341 >>> np.emath.log10([-10**1, -10**2, 10**2]) 

342 array([1.+1.3644j, 2.+1.3644j, 2.+0.j ]) 

343 

344 """ 

345 x = _fix_real_lt_zero(x) 

346 return nx.log10(x) 

347 

348 

349def _logn_dispatcher(n, x): 

350 return (n, x,) 

351 

352 

353@array_function_dispatch(_logn_dispatcher) 

354def logn(n, x): 

355 """ 

356 Take log base n of x. 

357 

358 If `x` contains negative inputs, the answer is computed and returned in the 

359 complex domain. 

360 

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. 

367 

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. 

373 

374 Examples 

375 -------- 

376 >>> np.set_printoptions(precision=4) 

377 

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 ]) 

382 

383 """ 

384 x = _fix_real_lt_zero(x) 

385 n = _fix_real_lt_zero(n) 

386 return nx.log(x)/nx.log(n) 

387 

388 

389@array_function_dispatch(_unary_dispatcher) 

390def log2(x): 

391 """ 

392 Compute the logarithm base 2 of `x`. 

393 

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. 

398 

399 Parameters 

400 ---------- 

401 x : array_like 

402 The value(s) whose log base 2 is (are) required. 

403 

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. 

409 

410 See Also 

411 -------- 

412 numpy.log2 

413 

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``). 

420 

421 Examples 

422 -------- 

423 We set the printing precision so the example can be auto-tested: 

424 

425 >>> np.set_printoptions(precision=4) 

426 

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 ]) 

431 

432 """ 

433 x = _fix_real_lt_zero(x) 

434 return nx.log2(x) 

435 

436 

437def _power_dispatcher(x, p): 

438 return (x, p) 

439 

440 

441@array_function_dispatch(_power_dispatcher) 

442def power(x, p): 

443 """ 

444 Return x to the power p, (x**p). 

445 

446 If `x` contains negative values, the output is converted to the 

447 complex domain. 

448 

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], ...``. 

458 

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. 

464 

465 See Also 

466 -------- 

467 numpy.power 

468 

469 Examples 

470 -------- 

471 >>> np.set_printoptions(precision=4) 

472 

473 >>> np.emath.power(2, 2) 

474 4 

475 

476 >>> np.emath.power([2, 4], 2) 

477 array([ 4, 16]) 

478 

479 >>> np.emath.power([2, 4], -2) 

480 array([0.25 , 0.0625]) 

481 

482 >>> np.emath.power([-2, 4], 2) 

483 array([ 4.-0.j, 16.+0.j]) 

484 

485 >>> np.emath.power([2, 4], [2, 4]) 

486 array([ 4, 256]) 

487 

488 """ 

489 x = _fix_real_lt_zero(x) 

490 p = _fix_int_lt_zero(p) 

491 return nx.power(x, p) 

492 

493 

494@array_function_dispatch(_unary_dispatcher) 

495def arccos(x): 

496 """ 

497 Compute the inverse cosine of x. 

498 

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. 

503 

504 Parameters 

505 ---------- 

506 x : array_like or scalar 

507 The value(s) whose arccos is (are) required. 

508 

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. 

514 

515 See Also 

516 -------- 

517 numpy.arccos 

518 

519 Notes 

520 ----- 

521 For an arccos() that returns ``NAN`` when real `x` is not in the 

522 interval ``[-1,1]``, use `numpy.arccos`. 

523 

524 Examples 

525 -------- 

526 >>> np.set_printoptions(precision=4) 

527 

528 >>> np.emath.arccos(1) # a scalar is returned 

529 0.0 

530 

531 >>> np.emath.arccos([1,2]) 

532 array([0.-0.j , 0.-1.317j]) 

533 

534 """ 

535 x = _fix_real_abs_gt_1(x) 

536 return nx.arccos(x) 

537 

538 

539@array_function_dispatch(_unary_dispatcher) 

540def arcsin(x): 

541 """ 

542 Compute the inverse sine of x. 

543 

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. 

549 

550 Parameters 

551 ---------- 

552 x : array_like or scalar 

553 The value(s) whose arcsin is (are) required. 

554 

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. 

560 

561 See Also 

562 -------- 

563 numpy.arcsin 

564 

565 Notes 

566 ----- 

567 For an arcsin() that returns ``NAN`` when real `x` is not in the 

568 interval ``[-1,1]``, use `numpy.arcsin`. 

569 

570 Examples 

571 -------- 

572 >>> np.set_printoptions(precision=4) 

573 

574 >>> np.emath.arcsin(0) 

575 0.0 

576 

577 >>> np.emath.arcsin([0,1]) 

578 array([0. , 1.5708]) 

579 

580 """ 

581 x = _fix_real_abs_gt_1(x) 

582 return nx.arcsin(x) 

583 

584 

585@array_function_dispatch(_unary_dispatcher) 

586def arctanh(x): 

587 """ 

588 Compute the inverse hyperbolic tangent of `x`. 

589 

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``. 

595 

596 Parameters 

597 ---------- 

598 x : array_like 

599 The value(s) whose arctanh is (are) required. 

600 

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. 

606 

607 

608 See Also 

609 -------- 

610 numpy.arctanh 

611 

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``). 

617 

618 Examples 

619 -------- 

620 >>> np.set_printoptions(precision=4) 

621 

622 >>> np.emath.arctanh(0.5) 

623 0.5493061443340549 

624 

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]) 

633 

634 """ 

635 x = _fix_real_abs_gt_1(x) 

636 return nx.arctanh(x)