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

1import functools 

2import warnings 

3import operator 

4import types 

5 

6from . import numeric as _nx 

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

8from numpy.core.multiarray import add_docstring 

9from numpy.core import overrides 

10 

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

12 

13 

14array_function_dispatch = functools.partial( 

15 overrides.array_function_dispatch, module='numpy') 

16 

17 

18def _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) 

24def 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 Parameters 

38 ---------- 

39 start : array_like 

40 The starting value of the sequence. 

41 stop : array_like 

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

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

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

45 size changes when `endpoint` is False. 

46 num : int, optional 

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

48 endpoint : bool, optional 

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

50 Default is True. 

51 retstep : bool, optional 

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

53 between samples. 

54 dtype : dtype, optional 

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

56 type from the other input arguments. 

57 

58 .. versionadded:: 1.9.0 

59 

60 axis : int, optional 

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

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

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

64 

65 .. versionadded:: 1.16.0 

66 

67 Returns 

68 ------- 

69 samples : ndarray 

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

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

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

73 step : float, optional 

74 Only returned if `retstep` is True 

75 

76 Size of spacing between samples. 

77 

78 

79 See Also 

80 -------- 

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

82 number of samples). 

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

84 scale (a geometric progression). 

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

86 logarithms. 

87 

88 Examples 

89 -------- 

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

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

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

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

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

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

96 

97 Graphical illustration: 

98 

99 >>> import matplotlib.pyplot as plt 

100 >>> N = 8 

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

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

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

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

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

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

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

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

109 (-0.5, 1) 

110 >>> plt.show() 

111 

112 """ 

113 num = operator.index(num) 

114 if num < 0: 

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

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

117 

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

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

120 start = asanyarray(start) * 1.0 

121 stop = asanyarray(stop) * 1.0 

122 

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

124 if dtype is None: 

125 dtype = dt 

126 

127 delta = stop - start 

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

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

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

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

132 _mult_inplace = _nx.isscalar(delta) 

133 if div > 0: 

134 step = delta / div 

135 if _nx.any(step == 0): 

136 # Special handling for denormal numbers, gh-5437 

137 y /= div 

138 if _mult_inplace: 

139 y *= delta 

140 else: 

141 y = y * delta 

142 else: 

143 if _mult_inplace: 

144 y *= step 

145 else: 

146 y = y * step 

147 else: 

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

149 # have an undefined step 

150 step = NaN 

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

152 y = y * delta 

153 

154 y += start 

155 

156 if endpoint and num > 1: 

157 y[-1] = stop 

158 

159 if axis != 0: 

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

161 

162 if retstep: 

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

164 else: 

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

166 

167 

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

169 dtype=None, axis=None): 

170 return (start, stop) 

171 

172 

173@array_function_dispatch(_logspace_dispatcher) 

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

175 axis=0): 

176 """ 

177 Return numbers spaced evenly on a log scale. 

178 

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

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

181 (see `endpoint` below). 

182 

183 .. versionchanged:: 1.16.0 

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

185 

186 Parameters 

187 ---------- 

188 start : array_like 

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

190 stop : array_like 

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

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

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

194 length `num`) are returned. 

195 num : integer, optional 

196 Number of samples to generate. Default is 50. 

197 endpoint : boolean, optional 

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

199 Default is True. 

200 base : float, optional 

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

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

203 Default is 10.0. 

204 dtype : dtype 

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

206 type from the other input arguments. 

207 axis : int, optional 

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

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

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

211 

212 .. versionadded:: 1.16.0 

213 

214 

215 Returns 

216 ------- 

217 samples : ndarray 

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

219 

220 See Also 

221 -------- 

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

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

224 endpoint may or may not be included. 

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

226 in linear space, instead of log space. 

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

228 

229 Notes 

230 ----- 

231 Logspace is equivalent to the code 

232 

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

234 ... # doctest: +SKIP 

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

236 ... # doctest: +SKIP 

237 

238 Examples 

239 -------- 

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

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

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

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

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

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

246 

247 Graphical illustration: 

248 

249 >>> import matplotlib.pyplot as plt 

250 >>> N = 10 

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

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

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

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

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

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

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

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

259 (-0.5, 1) 

260 >>> plt.show() 

261 

262 """ 

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

264 if dtype is None: 

265 return _nx.power(base, y) 

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

267 

268 

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

270 axis=None): 

271 return (start, stop) 

272 

273 

274@array_function_dispatch(_geomspace_dispatcher) 

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

276 """ 

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

278 

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

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

281 

282 .. versionchanged:: 1.16.0 

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

284 

285 Parameters 

286 ---------- 

287 start : array_like 

288 The starting value of the sequence. 

289 stop : array_like 

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

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

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

293 length `num`) are returned. 

294 num : integer, optional 

295 Number of samples to generate. Default is 50. 

296 endpoint : boolean, optional 

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

298 Default is True. 

299 dtype : dtype 

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

301 type from the other input arguments. 

302 axis : int, optional 

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

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

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

306 

307 .. versionadded:: 1.16.0 

308 

309 Returns 

310 ------- 

311 samples : ndarray 

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

313 

314 See Also 

315 -------- 

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

317 and base. 

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

319 progression. 

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

321 number of samples. 

322 

323 Notes 

324 ----- 

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

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

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

328 

329 Examples 

330 -------- 

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

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

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

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

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

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

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

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

339 

340 Note that the above may not produce exact integers: 

341 

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

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

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

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

346 

347 Negative, decreasing, and complex inputs are allowed: 

348 

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

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

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

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

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

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

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

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

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

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

359 

360 Graphical illustration of ``endpoint`` parameter: 

361 

362 >>> import matplotlib.pyplot as plt 

363 >>> N = 10 

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

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

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

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

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

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

370 [0.5, 2000, 0, 3] 

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

372 >>> plt.show() 

373 

374 """ 

375 start = asanyarray(start) 

376 stop = asanyarray(stop) 

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

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

379 

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

381 if dtype is None: 

382 dtype = dt 

383 else: 

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

385 dtype = _nx.dtype(dtype) 

386 

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

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

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

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

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

392 

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

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

395 # positive real, calculating, then undoing rotation 

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

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

398 if _nx.any(all_imag): 

399 start[all_imag] = start[all_imag].imag 

400 stop[all_imag] = stop[all_imag].imag 

401 out_sign[all_imag] = 1j 

402 

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

404 if _nx.any(both_negative): 

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

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

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

408 

409 log_start = _nx.log10(start) 

410 log_stop = _nx.log10(stop) 

411 result = out_sign * logspace(log_start, log_stop, num=num, 

412 endpoint=endpoint, base=10.0, dtype=dtype) 

413 if axis != 0: 

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

415 

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

417 

418 

419def _needs_add_docstring(obj): 

420 """ 

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

422 via add_docstring. 

423 

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

425 """ 

426 Py_TPFLAGS_HEAPTYPE = 1 << 9 

427 

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

429 return False 

430 

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

432 return False 

433 

434 return True 

435 

436 

437def _add_docstring(obj, doc, warn_on_python): 

438 if warn_on_python and not _needs_add_docstring(obj): 

439 warnings.warn( 

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

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

442 .format(obj), 

443 UserWarning, 

444 stacklevel=3) 

445 try: 

446 add_docstring(obj, doc) 

447 except Exception: 

448 pass 

449 

450 

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

452 """ 

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

454 

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

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

457 

458 Parameters 

459 ---------- 

460 place : str 

461 The absolute name of the module to import from 

462 obj : str 

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

464 function name 

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

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

467 

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

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

470 

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

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

473 warn_on_python : bool 

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

475 documentation to a pure-python object. 

476 

477 Notes 

478 ----- 

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

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

481 

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

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

484 routine never raises an error the caller must check manually 

485 that the docstrings were changed. 

486 

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

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

489 C-API best-practices, by: 

490 

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

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

493 will never be released 

494 

495 If possible it should be avoided. 

496 """ 

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

498 if isinstance(doc, str): 

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

500 elif isinstance(doc, tuple): 

501 attr, docstring = doc 

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

503 elif isinstance(doc, list): 

504 for attr, docstring in doc: 

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