Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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 >>> from numpy.lib import scimath 

11 >>> scimath.log(-math.exp(1)) == (1+1j*math.pi) 

12 True 

13 

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

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

16 

17""" 

18import numpy.core.numeric as nx 

19import numpy.core.numerictypes as nt 

20from numpy.core.numeric import asarray, any 

21from numpy.core.overrides import array_function_dispatch 

22from numpy.lib.type_check import isreal 

23 

24 

25__all__ = [ 

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

27 'arctanh' 

28 ] 

29 

30 

31_ln2 = nx.log(2.0) 

32 

33 

34def _tocomplex(arr): 

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

36 

37 The input is returned as a complex array of the smallest type that will fit 

38 the original data: types like single, byte, short, etc. become csingle, 

39 while others become cdouble. 

40 

41 A copy of the input is always made. 

42 

43 Parameters 

44 ---------- 

45 arr : array 

46 

47 Returns 

48 ------- 

49 array 

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

51 

52 Examples 

53 -------- 

54 

55 First, consider an input of type short: 

56 

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

58 

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

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

61 

62 >>> ac.dtype 

63 dtype('complex64') 

64 

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

66 complex double type as well: 

67 

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

69 

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

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

72 

73 >>> bc.dtype 

74 dtype('complex128') 

75 

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

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

78 

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

80 

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

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

83 

84 >>> c *= 2; c 

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

86 

87 >>> cc 

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

89 """ 

90 if issubclass(arr.dtype.type, (nt.single, nt.byte, nt.short, nt.ubyte, 

91 nt.ushort, nt.csingle)): 

92 return arr.astype(nt.csingle) 

93 else: 

94 return arr.astype(nt.cdouble) 

95 

96 

97def _fix_real_lt_zero(x): 

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

99 

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

101 

102 Parameters 

103 ---------- 

104 x : array_like 

105 

106 Returns 

107 ------- 

108 array 

109 

110 Examples 

111 -------- 

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

113 array([1, 2]) 

114 

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

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

117 

118 """ 

119 x = asarray(x) 

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

121 x = _tocomplex(x) 

122 return x 

123 

124 

125def _fix_int_lt_zero(x): 

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

127 

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

129 

130 Parameters 

131 ---------- 

132 x : array_like 

133 

134 Returns 

135 ------- 

136 array 

137 

138 Examples 

139 -------- 

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

141 array([1, 2]) 

142 

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

144 array([-1., 2.]) 

145 """ 

146 x = asarray(x) 

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

148 x = x * 1.0 

149 return x 

150 

151 

152def _fix_real_abs_gt_1(x): 

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

154 

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

156 

157 Parameters 

158 ---------- 

159 x : array_like 

160 

161 Returns 

162 ------- 

163 array 

164 

165 Examples 

166 -------- 

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

168 array([0, 1]) 

169 

170 >>> np.lib.scimath._fix_real_abs_gt_1([0,2]) 

171 array([0.+0.j, 2.+0.j]) 

172 """ 

173 x = asarray(x) 

174 if any(isreal(x) & (abs(x) > 1)): 

175 x = _tocomplex(x) 

176 return x 

177 

178 

179def _unary_dispatcher(x): 

180 return (x,) 

181 

182 

183@array_function_dispatch(_unary_dispatcher) 

184def sqrt(x): 

185 """ 

186 Compute the square root of x. 

187 

188 For negative input elements, a complex value is returned 

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

190 

191 Parameters 

192 ---------- 

193 x : array_like 

194 The input value(s). 

195 

196 Returns 

197 ------- 

198 out : ndarray or scalar 

199 The square root of `x`. If `x` was a scalar, so is `out`, 

200 otherwise an array is returned. 

201 

202 See Also 

203 -------- 

204 numpy.sqrt 

205 

206 Examples 

207 -------- 

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

209 

210 >>> np.lib.scimath.sqrt(1) 

211 1.0 

212 >>> np.lib.scimath.sqrt([1, 4]) 

213 array([1., 2.]) 

214 

215 But it automatically handles negative inputs: 

216 

217 >>> np.lib.scimath.sqrt(-1) 

218 1j 

219 >>> np.lib.scimath.sqrt([-1,4]) 

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

221 

222 """ 

223 x = _fix_real_lt_zero(x) 

224 return nx.sqrt(x) 

225 

226 

227@array_function_dispatch(_unary_dispatcher) 

228def log(x): 

229 """ 

230 Compute the natural logarithm of `x`. 

231 

232 Return the "principal value" (for a description of this, see `numpy.log`) 

233 of :math:`log_e(x)`. For real `x > 0`, this is a real number (``log(0)`` 

234 returns ``-inf`` and ``log(np.inf)`` returns ``inf``). Otherwise, the 

235 complex principle value is returned. 

236 

237 Parameters 

238 ---------- 

239 x : array_like 

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

241 

242 Returns 

243 ------- 

244 out : ndarray or scalar 

245 The log of the `x` value(s). If `x` was a scalar, so is `out`, 

246 otherwise an array is returned. 

247 

248 See Also 

249 -------- 

250 numpy.log 

251 

252 Notes 

253 ----- 

254 For a log() that returns ``NAN`` when real `x < 0`, use `numpy.log` 

255 (note, however, that otherwise `numpy.log` and this `log` are identical, 

256 i.e., both return ``-inf`` for `x = 0`, ``inf`` for `x = inf`, and, 

257 notably, the complex principle value if ``x.imag != 0``). 

258 

259 Examples 

260 -------- 

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

262 1.0 

263 

264 Negative arguments are handled "correctly" (recall that 

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

266 

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

268 True 

269 

270 """ 

271 x = _fix_real_lt_zero(x) 

272 return nx.log(x) 

273 

274 

275@array_function_dispatch(_unary_dispatcher) 

276def log10(x): 

277 """ 

278 Compute the logarithm base 10 of `x`. 

279 

280 Return the "principal value" (for a description of this, see 

281 `numpy.log10`) of :math:`log_{10}(x)`. For real `x > 0`, this 

282 is a real number (``log10(0)`` returns ``-inf`` and ``log10(np.inf)`` 

283 returns ``inf``). Otherwise, the complex principle value is returned. 

284 

285 Parameters 

286 ---------- 

287 x : array_like or scalar 

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

289 

290 Returns 

291 ------- 

292 out : ndarray or scalar 

293 The log base 10 of the `x` value(s). If `x` was a scalar, so is `out`, 

294 otherwise an array object is returned. 

295 

296 See Also 

297 -------- 

298 numpy.log10 

299 

300 Notes 

301 ----- 

302 For a log10() that returns ``NAN`` when real `x < 0`, use `numpy.log10` 

303 (note, however, that otherwise `numpy.log10` and this `log10` are 

304 identical, i.e., both return ``-inf`` for `x = 0`, ``inf`` for `x = inf`, 

305 and, notably, the complex principle value if ``x.imag != 0``). 

306 

307 Examples 

308 -------- 

309 

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

311 

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

313 

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

315 1.0 

316 

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

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

319 

320 """ 

321 x = _fix_real_lt_zero(x) 

322 return nx.log10(x) 

323 

324 

325def _logn_dispatcher(n, x): 

326 return (n, x,) 

327 

328 

329@array_function_dispatch(_logn_dispatcher) 

330def logn(n, x): 

331 """ 

332 Take log base n of x. 

333 

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

335 complex domain. 

336 

337 Parameters 

338 ---------- 

339 n : array_like 

340 The integer base(s) in which the log is taken. 

341 x : array_like 

342 The value(s) whose log base `n` is (are) required. 

343 

344 Returns 

345 ------- 

346 out : ndarray or scalar 

347 The log base `n` of the `x` value(s). If `x` was a scalar, so is 

348 `out`, otherwise an array is returned. 

349 

350 Examples 

351 -------- 

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

353 

354 >>> np.lib.scimath.logn(2, [4, 8]) 

355 array([2., 3.]) 

356 >>> np.lib.scimath.logn(2, [-4, -8, 8]) 

357 array([2.+4.5324j, 3.+4.5324j, 3.+0.j ]) 

358 

359 """ 

360 x = _fix_real_lt_zero(x) 

361 n = _fix_real_lt_zero(n) 

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

363 

364 

365@array_function_dispatch(_unary_dispatcher) 

366def log2(x): 

367 """ 

368 Compute the logarithm base 2 of `x`. 

369 

370 Return the "principal value" (for a description of this, see 

371 `numpy.log2`) of :math:`log_2(x)`. For real `x > 0`, this is 

372 a real number (``log2(0)`` returns ``-inf`` and ``log2(np.inf)`` returns 

373 ``inf``). Otherwise, the complex principle value is returned. 

374 

375 Parameters 

376 ---------- 

377 x : array_like 

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

379 

380 Returns 

381 ------- 

382 out : ndarray or scalar 

383 The log base 2 of the `x` value(s). If `x` was a scalar, so is `out`, 

384 otherwise an array is returned. 

385 

386 See Also 

387 -------- 

388 numpy.log2 

389 

390 Notes 

391 ----- 

392 For a log2() that returns ``NAN`` when real `x < 0`, use `numpy.log2` 

393 (note, however, that otherwise `numpy.log2` and this `log2` are 

394 identical, i.e., both return ``-inf`` for `x = 0`, ``inf`` for `x = inf`, 

395 and, notably, the complex principle value if ``x.imag != 0``). 

396 

397 Examples 

398 -------- 

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

400 

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

402 

403 >>> np.emath.log2(8) 

404 3.0 

405 >>> np.emath.log2([-4, -8, 8]) 

406 array([2.+4.5324j, 3.+4.5324j, 3.+0.j ]) 

407 

408 """ 

409 x = _fix_real_lt_zero(x) 

410 return nx.log2(x) 

411 

412 

413def _power_dispatcher(x, p): 

414 return (x, p) 

415 

416 

417@array_function_dispatch(_power_dispatcher) 

418def power(x, p): 

419 """ 

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

421 

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

423 complex domain. 

424 

425 Parameters 

426 ---------- 

427 x : array_like 

428 The input value(s). 

429 p : array_like of ints 

430 The power(s) to which `x` is raised. If `x` contains multiple values, 

431 `p` has to either be a scalar, or contain the same number of values 

432 as `x`. In the latter case, the result is 

433 ``x[0]**p[0], x[1]**p[1], ...``. 

434 

435 Returns 

436 ------- 

437 out : ndarray or scalar 

438 The result of ``x**p``. If `x` and `p` are scalars, so is `out`, 

439 otherwise an array is returned. 

440 

441 See Also 

442 -------- 

443 numpy.power 

444 

445 Examples 

446 -------- 

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

448 

449 >>> np.lib.scimath.power([2, 4], 2) 

450 array([ 4, 16]) 

451 >>> np.lib.scimath.power([2, 4], -2) 

452 array([0.25 , 0.0625]) 

453 >>> np.lib.scimath.power([-2, 4], 2) 

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

455 

456 """ 

457 x = _fix_real_lt_zero(x) 

458 p = _fix_int_lt_zero(p) 

459 return nx.power(x, p) 

460 

461 

462@array_function_dispatch(_unary_dispatcher) 

463def arccos(x): 

464 """ 

465 Compute the inverse cosine of x. 

466 

467 Return the "principal value" (for a description of this, see 

468 `numpy.arccos`) of the inverse cosine of `x`. For real `x` such that 

469 `abs(x) <= 1`, this is a real number in the closed interval 

470 :math:`[0, \\pi]`. Otherwise, the complex principle value is returned. 

471 

472 Parameters 

473 ---------- 

474 x : array_like or scalar 

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

476 

477 Returns 

478 ------- 

479 out : ndarray or scalar 

480 The inverse cosine(s) of the `x` value(s). If `x` was a scalar, so 

481 is `out`, otherwise an array object is returned. 

482 

483 See Also 

484 -------- 

485 numpy.arccos 

486 

487 Notes 

488 ----- 

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

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

491 

492 Examples 

493 -------- 

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

495 

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

497 0.0 

498 

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

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

501 

502 """ 

503 x = _fix_real_abs_gt_1(x) 

504 return nx.arccos(x) 

505 

506 

507@array_function_dispatch(_unary_dispatcher) 

508def arcsin(x): 

509 """ 

510 Compute the inverse sine of x. 

511 

512 Return the "principal value" (for a description of this, see 

513 `numpy.arcsin`) of the inverse sine of `x`. For real `x` such that 

514 `abs(x) <= 1`, this is a real number in the closed interval 

515 :math:`[-\\pi/2, \\pi/2]`. Otherwise, the complex principle value is 

516 returned. 

517 

518 Parameters 

519 ---------- 

520 x : array_like or scalar 

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

522 

523 Returns 

524 ------- 

525 out : ndarray or scalar 

526 The inverse sine(s) of the `x` value(s). If `x` was a scalar, so 

527 is `out`, otherwise an array object is returned. 

528 

529 See Also 

530 -------- 

531 numpy.arcsin 

532 

533 Notes 

534 ----- 

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

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

537 

538 Examples 

539 -------- 

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

541 

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

543 0.0 

544 

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

546 array([0. , 1.5708]) 

547 

548 """ 

549 x = _fix_real_abs_gt_1(x) 

550 return nx.arcsin(x) 

551 

552 

553@array_function_dispatch(_unary_dispatcher) 

554def arctanh(x): 

555 """ 

556 Compute the inverse hyperbolic tangent of `x`. 

557 

558 Return the "principal value" (for a description of this, see 

559 `numpy.arctanh`) of `arctanh(x)`. For real `x` such that 

560 `abs(x) < 1`, this is a real number. If `abs(x) > 1`, or if `x` is 

561 complex, the result is complex. Finally, `x = 1` returns``inf`` and 

562 `x=-1` returns ``-inf``. 

563 

564 Parameters 

565 ---------- 

566 x : array_like 

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

568 

569 Returns 

570 ------- 

571 out : ndarray or scalar 

572 The inverse hyperbolic tangent(s) of the `x` value(s). If `x` was 

573 a scalar so is `out`, otherwise an array is returned. 

574 

575 

576 See Also 

577 -------- 

578 numpy.arctanh 

579 

580 Notes 

581 ----- 

582 For an arctanh() that returns ``NAN`` when real `x` is not in the 

583 interval ``(-1,1)``, use `numpy.arctanh` (this latter, however, does 

584 return +/-inf for `x = +/-1`). 

585 

586 Examples 

587 -------- 

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

589 

590 >>> from numpy.testing import suppress_warnings 

591 >>> with suppress_warnings() as sup: 

592 ... sup.filter(RuntimeWarning) 

593 ... np.emath.arctanh(np.eye(2)) 

594 array([[inf, 0.], 

595 [ 0., inf]]) 

596 >>> np.emath.arctanh([1j]) 

597 array([0.+0.7854j]) 

598 

599 """ 

600 x = _fix_real_abs_gt_1(x) 

601 return nx.arctanh(x)