1 import functools

2 import warnings

3 import operator

4 import types

5

6 from . import numeric as _nx

7 from .numeric import result_type, NaN, asanyarray, ndim

8 from numpy.core.multiarray import add_docstring

9 from numpy.core import overrides

10

11__all__ = ['logspace', 'linspace', 'geomspace']

12

13

14 array_function_dispatch = functools.partial(

15 overrides.array_function_dispatch, module='numpy')

16

17

18 def _linspace_dispatcher(start, stop, num=None, endpoint=None, retstep=None,

19 dtype=None, axis=None):

20 return (start, stop)

21

22

23@array_function_dispatch(_linspace_dispatcher)

24 def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None,

25 axis=0):

26 """

27 Return evenly spaced numbers over a specified interval.

28

29 Returns `num` evenly spaced samples, calculated over the

30 interval [`start`, `stop`].

31

32 The endpoint of the interval can optionally be excluded.

33

34 .. versionchanged:: 1.16.0

35 Non-scalar `start` and `stop` are now supported.

36

37 .. versionchanged:: 1.20.0

38 Values are rounded towards ``-inf`` instead of ``0`` when an

39 integer ``dtype`` is specified. The old behavior can

40 still be obtained with ``np.linspace(start, stop, num).astype(int)``

41

42 Parameters

43 ----------

44 start : array_like

45 The starting value of the sequence.

46 stop : array_like

47 The end value of the sequence, unless `endpoint` is set to False.

48 In that case, the sequence consists of all but the last of ``num + 1``

49 evenly spaced samples, so that `stop` is excluded. Note that the step

50 size changes when `endpoint` is False.

51 num : int, optional

52 Number of samples to generate. Default is 50. Must be non-negative.

53 endpoint : bool, optional

54 If True, `stop` is the last sample. Otherwise, it is not included.

55 Default is True.

56 retstep : bool, optional

57 If True, return (`samples`, `step`), where `step` is the spacing

58 between samples.

59 dtype : dtype, optional

60 The type of the output array. If `dtype` is not given, the data type

61 is inferred from `start` and `stop`. The inferred dtype will never be

62 an integer; `float` is chosen even if the arguments would produce an

63 array of integers.

64

65 .. versionadded:: 1.9.0

66

67 axis : int, optional

68 The axis in the result to store the samples. Relevant only if start

69 or stop are array-like. By default (0), the samples will be along a

70 new axis inserted at the beginning. Use -1 to get an axis at the end.

71

72 .. versionadded:: 1.16.0

73

74 Returns

75 -------

76 samples : ndarray

77 There are `num` equally spaced samples in the closed interval

78 ``[start, stop]`` or the half-open interval ``[start, stop)``

79 (depending on whether `endpoint` is True or False).

80 step : float, optional

81 Only returned if `retstep` is True

82

83 Size of spacing between samples.

84

85

86 See Also

87 --------

88 arange : Similar to `linspace`, but uses a step size (instead of the

89 number of samples).

90 geomspace : Similar to `linspace`, but with numbers spaced evenly on a log

91 scale (a geometric progression).

92 logspace : Similar to `geomspace`, but with the end points specified as

93 logarithms.

94 :ref:`how-to-partition`

95

96 Examples

97 --------

98 >>> np.linspace(2.0, 3.0, num=5)

99 array([2. , 2.25, 2.5 , 2.75, 3. ])

100 >>> np.linspace(2.0, 3.0, num=5, endpoint=False)

101 array([2. , 2.2, 2.4, 2.6, 2.8])

102 >>> np.linspace(2.0, 3.0, num=5, retstep=True)

103 (array([2. , 2.25, 2.5 , 2.75, 3. ]), 0.25)

104

105 Graphical illustration:

106

107 >>> import matplotlib.pyplot as plt

108 >>> N = 8

109 >>> y = np.zeros(N)

110 >>> x1 = np.linspace(0, 10, N, endpoint=True)

111 >>> x2 = np.linspace(0, 10, N, endpoint=False)

112 >>> plt.plot(x1, y, 'o')

113 [<matplotlib.lines.Line2D object at 0x...>]

114 >>> plt.plot(x2, y + 0.5, 'o')

115 [<matplotlib.lines.Line2D object at 0x...>]

116 >>> plt.ylim([-0.5, 1])

117 (-0.5, 1)

118 >>> plt.show()

119

120 """

121 num = operator.index(num)

122 if num < 0:

123 raise ValueError("Number of samples, %s, must be non-negative." % num)

124 div = (num - 1) if endpoint else num

125

126 # Convert float/complex array scalars to float, gh-3504

127 # and make sure one can use variables that have an __array_interface__, gh-6634

128 start = asanyarray(start) * 1.0

129 stop = asanyarray(stop) * 1.0

130

131 dt = result_type(start, stop, float(num))

132 if dtype is None:

133 dtype = dt

134 integer_dtype = False

135 else:

136 integer_dtype = _nx.issubdtype(dtype, _nx.integer)

137

138 delta = stop - start

139 y = _nx.arange(0, num, dtype=dt).reshape((-1,) + (1,) * ndim(delta))

140 # In-place multiplication y *= delta/div is faster, but prevents the multiplicant

141 # from overriding what class is produced, and thus prevents, e.g. use of Quantities,

142 # see gh-7142. Hence, we multiply in place only for standard scalar types.

143 if div > 0:

144 _mult_inplace = _nx.isscalar(delta)

145 step = delta / div

146 any_step_zero = (

147 step == 0 if _mult_inplace else _nx.asanyarray(step == 0).any())

148 if any_step_zero:

149 # Special handling for denormal numbers, gh-5437

150 y /= div

151 if _mult_inplace:

152 y *= delta

153 else:

154 y = y * delta

155 else:

156 if _mult_inplace:

157 y *= step

158 else:

159 y = y * step

160 else:

161 # sequences with 0 items or 1 item with endpoint=True (i.e. div <= 0)

162 # have an undefined step

163 step = NaN

164 # Multiply with delta to allow possible override of output class.

165 y = y * delta

166

167 y += start

168

169 if endpoint and num > 1:

170 y[-1] = stop

171

172 if axis != 0:

173 y = _nx.moveaxis(y, 0, axis)

174

175 if integer_dtype:

176 _nx.floor(y, out=y)

177

178 if retstep:

179 return y.astype(dtype, copy=False), step

180 else:

181 return y.astype(dtype, copy=False)

182

183

184 def _logspace_dispatcher(start, stop, num=None, endpoint=None, base=None,

185 dtype=None, axis=None):

186 return (start, stop)

187

188

189@array_function_dispatch(_logspace_dispatcher)

190 def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None,

191 axis=0):

192 """

193 Return numbers spaced evenly on a log scale.

194

195 In linear space, the sequence starts at ``base ** start``

196 (`base` to the power of `start`) and ends with ``base ** stop``

197 (see `endpoint` below).

198

199 .. versionchanged:: 1.16.0

200 Non-scalar `start` and `stop` are now supported.

201

202 Parameters

203 ----------

204 start : array_like

205 ``base ** start`` is the starting value of the sequence.

206 stop : array_like

207 ``base ** stop`` is the final value of the sequence, unless `endpoint`

208 is False. In that case, ``num + 1`` values are spaced over the

209 interval in log-space, of which all but the last (a sequence of

210 length `num`) are returned.

211 num : integer, optional

212 Number of samples to generate. Default is 50.

213 endpoint : boolean, optional

214 If true, `stop` is the last sample. Otherwise, it is not included.

215 Default is True.

216 base : array_like, optional

217 The base of the log space. The step size between the elements in

218 ``ln(samples) / ln(base)`` (or ``log_base(samples)``) is uniform.

219 Default is 10.0.

220 dtype : dtype

221 The type of the output array. If `dtype` is not given, the data type

222 is inferred from `start` and `stop`. The inferred type will never be

223 an integer; `float` is chosen even if the arguments would produce an

224 array of integers.

225 axis : int, optional

226 The axis in the result to store the samples. Relevant only if start

227 or stop are array-like. By default (0), the samples will be along a

228 new axis inserted at the beginning. Use -1 to get an axis at the end.

229

230 .. versionadded:: 1.16.0

231

232

233 Returns

234 -------

235 samples : ndarray

236 `num` samples, equally spaced on a log scale.

237

238 See Also

239 --------

240 arange : Similar to linspace, with the step size specified instead of the

241 number of samples. Note that, when used with a float endpoint, the

242 endpoint may or may not be included.

243 linspace : Similar to logspace, but with the samples uniformly distributed

244 in linear space, instead of log space.

245 geomspace : Similar to logspace, but with endpoints specified directly.

246 :ref:`how-to-partition`

247

248 Notes

249 -----

250 Logspace is equivalent to the code

251

252 >>> y = np.linspace(start, stop, num=num, endpoint=endpoint)

253 ... # doctest: +SKIP

254 >>> power(base, y).astype(dtype)

255 ... # doctest: +SKIP

256

257 Examples

258 --------

259 >>> np.logspace(2.0, 3.0, num=4)

260 array([ 100. , 215.443469 , 464.15888336, 1000. ])

261 >>> np.logspace(2.0, 3.0, num=4, endpoint=False)

262 array([100. , 177.827941 , 316.22776602, 562.34132519])

263 >>> np.logspace(2.0, 3.0, num=4, base=2.0)

264 array([4. , 5.0396842 , 6.34960421, 8. ])

265

266 Graphical illustration:

267

268 >>> import matplotlib.pyplot as plt

269 >>> N = 10

270 >>> x1 = np.logspace(0.1, 1, N, endpoint=True)

271 >>> x2 = np.logspace(0.1, 1, N, endpoint=False)

272 >>> y = np.zeros(N)

273 >>> plt.plot(x1, y, 'o')

274 [<matplotlib.lines.Line2D object at 0x...>]

275 >>> plt.plot(x2, y + 0.5, 'o')

276 [<matplotlib.lines.Line2D object at 0x...>]

277 >>> plt.ylim([-0.5, 1])

278 (-0.5, 1)

279 >>> plt.show()

280

281 """

282 y = linspace(start, stop, num=num, endpoint=endpoint, axis=axis)

283 if dtype is None:

284 return _nx.power(base, y)

285 return _nx.power(base, y).astype(dtype, copy=False)

286

287

288 def _geomspace_dispatcher(start, stop, num=None, endpoint=None, dtype=None,

289 axis=None):

290 return (start, stop)

291

292

293@array_function_dispatch(_geomspace_dispatcher)

294 def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0):

295 """

296 Return numbers spaced evenly on a log scale (a geometric progression).

297

298 This is similar to `logspace`, but with endpoints specified directly.

299 Each output sample is a constant multiple of the previous.

300

301 .. versionchanged:: 1.16.0

302 Non-scalar `start` and `stop` are now supported.

303

304 Parameters

305 ----------

306 start : array_like

307 The starting value of the sequence.

308 stop : array_like

309 The final value of the sequence, unless `endpoint` is False.

310 In that case, ``num + 1`` values are spaced over the

311 interval in log-space, of which all but the last (a sequence of

312 length `num`) are returned.

313 num : integer, optional

314 Number of samples to generate. Default is 50.

315 endpoint : boolean, optional

316 If true, `stop` is the last sample. Otherwise, it is not included.

317 Default is True.

318 dtype : dtype

319 The type of the output array. If `dtype` is not given, the data type

320 is inferred from `start` and `stop`. The inferred dtype will never be

321 an integer; `float` is chosen even if the arguments would produce an

322 array of integers.

323 axis : int, optional

324 The axis in the result to store the samples. Relevant only if start

325 or stop are array-like. By default (0), the samples will be along a

326 new axis inserted at the beginning. Use -1 to get an axis at the end.

327

328 .. versionadded:: 1.16.0

329

330 Returns

331 -------

332 samples : ndarray

333 `num` samples, equally spaced on a log scale.

334

335 See Also

336 --------

337 logspace : Similar to geomspace, but with endpoints specified using log

338 and base.

339 linspace : Similar to geomspace, but with arithmetic instead of geometric

340 progression.

341 arange : Similar to linspace, with the step size specified instead of the

342 number of samples.

343 :ref:`how-to-partition`

344

345 Notes

346 -----

347 If the inputs or dtype are complex, the output will follow a logarithmic

348 spiral in the complex plane. (There are an infinite number of spirals

349 passing through two points; the output will follow the shortest such path.)

350

351 Examples

352 --------

353 >>> np.geomspace(1, 1000, num=4)

354 array([ 1., 10., 100., 1000.])

355 >>> np.geomspace(1, 1000, num=3, endpoint=False)

356 array([ 1., 10., 100.])

357 >>> np.geomspace(1, 1000, num=4, endpoint=False)

358 array([ 1. , 5.62341325, 31.6227766 , 177.827941 ])

359 >>> np.geomspace(1, 256, num=9)

360 array([ 1., 2., 4., 8., 16., 32., 64., 128., 256.])

361

362 Note that the above may not produce exact integers:

363

364 >>> np.geomspace(1, 256, num=9, dtype=int)

365 array([ 1, 2, 4, 7, 16, 32, 63, 127, 256])

366 >>> np.around(np.geomspace(1, 256, num=9)).astype(int)

367 array([ 1, 2, 4, 8, 16, 32, 64, 128, 256])

368

369 Negative, decreasing, and complex inputs are allowed:

370

371 >>> np.geomspace(1000, 1, num=4)

372 array([1000., 100., 10., 1.])

373 >>> np.geomspace(-1000, -1, num=4)

374 array([-1000., -100., -10., -1.])

375 >>> np.geomspace(1j, 1000j, num=4) # Straight line

376 array([0. +1.j, 0. +10.j, 0. +100.j, 0.+1000.j])

377 >>> np.geomspace(-1+0j, 1+0j, num=5) # Circle

378 array([-1.00000000e+00+1.22464680e-16j, -7.07106781e-01+7.07106781e-01j,

379 6.12323400e-17+1.00000000e+00j, 7.07106781e-01+7.07106781e-01j,

380 1.00000000e+00+0.00000000e+00j])

381

382 Graphical illustration of `endpoint` parameter:

383

384 >>> import matplotlib.pyplot as plt

385 >>> N = 10

386 >>> y = np.zeros(N)

387 >>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=True), y + 1, 'o')

388 [<matplotlib.lines.Line2D object at 0x...>]

389 >>> plt.semilogx(np.geomspace(1, 1000, N, endpoint=False), y + 2, 'o')

390 [<matplotlib.lines.Line2D object at 0x...>]

391 >>> plt.axis([0.5, 2000, 0, 3])

392 [0.5, 2000, 0, 3]

393 >>> plt.grid(True, color='0.7', linestyle='-', which='both', axis='both')

394 >>> plt.show()

395

396 """

397 start = asanyarray(start)

398 stop = asanyarray(stop)

399 if _nx.any(start == 0) or _nx.any(stop == 0):

400 raise ValueError('Geometric sequence cannot include zero')

401

402 dt = result_type(start, stop, float(num), _nx.zeros((), dtype))

403 if dtype is None:

404 dtype = dt

405 else:

406 # complex to dtype('complex128'), for instance

407 dtype = _nx.dtype(dtype)

408

409 # Promote both arguments to the same dtype in case, for instance, one is

410 # complex and another is negative and log would produce NaN otherwise.

411 # Copy since we may change things in-place further down.

412 start = start.astype(dt, copy=True)

413 stop = stop.astype(dt, copy=True)

414

415 out_sign = _nx.ones(_nx.broadcast(start, stop).shape, dt)

416 # Avoid negligible real or imaginary parts in output by rotating to

417 # positive real, calculating, then undoing rotation

418 if _nx.issubdtype(dt, _nx.complexfloating):

419 all_imag = (start.real == 0.) & (stop.real == 0.)

420 if _nx.any(all_imag):

421 start[all_imag] = start[all_imag].imag

422 stop[all_imag] = stop[all_imag].imag

423 out_sign[all_imag] = 1j

424

425 both_negative = (_nx.sign(start) == -1) & (_nx.sign(stop) == -1)

426 if _nx.any(both_negative):

427 _nx.negative(start, out=start, where=both_negative)

428 _nx.negative(stop, out=stop, where=both_negative)

429 _nx.negative(out_sign, out=out_sign, where=both_negative)

430

431 log_start = _nx.log10(start)

432 log_stop = _nx.log10(stop)

433 result = logspace(log_start, log_stop, num=num,

434 endpoint=endpoint, base=10.0, dtype=dtype)

435

436 # Make sure the endpoints match the start and stop arguments. This is

437 # necessary because np.exp(np.log(x)) is not necessarily equal to x.

438 if num > 0:

439 result[0] = start

440 if num > 1 and endpoint:

441 result[-1] = stop

442

443 result = out_sign * result

444

445 if axis != 0:

446 result = _nx.moveaxis(result, 0, axis)

447

448 return result.astype(dtype, copy=False)

449

450

451 def _needs_add_docstring(obj):

452 """

453 Returns true if the only way to set the docstring of `obj` from python is

454 via add_docstring.

455

456 This function errs on the side of being overly conservative.

457 """

458 Py_TPFLAGS_HEAPTYPE = 1 << 9

459

460 if isinstance(obj, (types.FunctionType, types.MethodType, property)):

461 return False

462

463 if isinstance(obj, type) and obj.__flags__ & Py_TPFLAGS_HEAPTYPE:

464 return False

465

466 return True

467

468

469 def _add_docstring(obj, doc, warn_on_python):

470 if warn_on_python and not _needs_add_docstring(obj):

471 warnings.warn(

472 "add_newdoc was used on a pure-python object {}. "

473 "Prefer to attach it directly to the source."

474 .format(obj),

475 UserWarning,

476 stacklevel=3)

477 try:

478 add_docstring(obj, doc)

479 except Exception:

480 pass

481

482

483 def add_newdoc(place, obj, doc, warn_on_python=True):

484 """

485 Add documentation to an existing object, typically one defined in C

486

487 The purpose is to allow easier editing of the docstrings without requiring

488 a re-compile. This exists primarily for internal use within numpy itself.

489

490 Parameters

491 ----------

492 place : str

493 The absolute name of the module to import from

494 obj : str

495 The name of the object to add documentation to, typically a class or

496 function name

497 doc : {str, Tuple[str, str], List[Tuple[str, str]]}

498 If a string, the documentation to apply to `obj`

499

500 If a tuple, then the first element is interpreted as an attribute of

501 `obj` and the second as the docstring to apply - ``(method, docstring)``

502

503 If a list, then each element of the list should be a tuple of length

504 two - ``[(method1, docstring1), (method2, docstring2), ...]``

505 warn_on_python : bool

506 If True, the default, emit `UserWarning` if this is used to attach

507 documentation to a pure-python object.

508

509 Notes

510 -----

511 This routine never raises an error if the docstring can't be written, but

512 will raise an error if the object being documented does not exist.

513

514 This routine cannot modify read-only docstrings, as appear

515 in new-style classes or built-in functions. Because this

516 routine never raises an error the caller must check manually

517 that the docstrings were changed.

518

519 Since this function grabs the ``char *`` from a c-level str object and puts

520 it into the ``tp_doc`` slot of the type of `obj`, it violates a number of

521 C-API best-practices, by:

522

523 - modifying a `PyTypeObject` after calling `PyType_Ready`

524 - calling `Py_INCREF` on the str and losing the reference, so the str

525 will never be released

526

527 If possible it should be avoided.

528 """

529 new = getattr(__import__(place, globals(), {}, [obj]), obj)

530 if isinstance(doc, str):

531 _add_docstring(new, doc.strip(), warn_on_python)

532 elif isinstance(doc, tuple):

533 attr, docstring = doc

534 _add_docstring(getattr(new, attr), docstring.strip(), warn_on_python)

535 elif isinstance(doc, list):

536 for attr, docstring in doc:

537 _add_docstring(getattr(new, attr), docstring.strip(), warn_on_python)