index_tricks.py 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  1. import functools
  2. import sys
  3. import math
  4. import warnings
  5. import numpy as np
  6. from .._utils import set_module
  7. import numpy.core.numeric as _nx
  8. from numpy.core.numeric import ScalarType, array
  9. from numpy.core.numerictypes import issubdtype
  10. import numpy.matrixlib as matrixlib
  11. from .function_base import diff
  12. from numpy.core.multiarray import ravel_multi_index, unravel_index
  13. from numpy.core import overrides, linspace
  14. from numpy.lib.stride_tricks import as_strided
  15. array_function_dispatch = functools.partial(
  16. overrides.array_function_dispatch, module='numpy')
  17. __all__ = [
  18. 'ravel_multi_index', 'unravel_index', 'mgrid', 'ogrid', 'r_', 'c_',
  19. 's_', 'index_exp', 'ix_', 'ndenumerate', 'ndindex', 'fill_diagonal',
  20. 'diag_indices', 'diag_indices_from'
  21. ]
  22. def _ix__dispatcher(*args):
  23. return args
  24. @array_function_dispatch(_ix__dispatcher)
  25. def ix_(*args):
  26. """
  27. Construct an open mesh from multiple sequences.
  28. This function takes N 1-D sequences and returns N outputs with N
  29. dimensions each, such that the shape is 1 in all but one dimension
  30. and the dimension with the non-unit shape value cycles through all
  31. N dimensions.
  32. Using `ix_` one can quickly construct index arrays that will index
  33. the cross product. ``a[np.ix_([1,3],[2,5])]`` returns the array
  34. ``[[a[1,2] a[1,5]], [a[3,2] a[3,5]]]``.
  35. Parameters
  36. ----------
  37. args : 1-D sequences
  38. Each sequence should be of integer or boolean type.
  39. Boolean sequences will be interpreted as boolean masks for the
  40. corresponding dimension (equivalent to passing in
  41. ``np.nonzero(boolean_sequence)``).
  42. Returns
  43. -------
  44. out : tuple of ndarrays
  45. N arrays with N dimensions each, with N the number of input
  46. sequences. Together these arrays form an open mesh.
  47. See Also
  48. --------
  49. ogrid, mgrid, meshgrid
  50. Examples
  51. --------
  52. >>> a = np.arange(10).reshape(2, 5)
  53. >>> a
  54. array([[0, 1, 2, 3, 4],
  55. [5, 6, 7, 8, 9]])
  56. >>> ixgrid = np.ix_([0, 1], [2, 4])
  57. >>> ixgrid
  58. (array([[0],
  59. [1]]), array([[2, 4]]))
  60. >>> ixgrid[0].shape, ixgrid[1].shape
  61. ((2, 1), (1, 2))
  62. >>> a[ixgrid]
  63. array([[2, 4],
  64. [7, 9]])
  65. >>> ixgrid = np.ix_([True, True], [2, 4])
  66. >>> a[ixgrid]
  67. array([[2, 4],
  68. [7, 9]])
  69. >>> ixgrid = np.ix_([True, True], [False, False, True, False, True])
  70. >>> a[ixgrid]
  71. array([[2, 4],
  72. [7, 9]])
  73. """
  74. out = []
  75. nd = len(args)
  76. for k, new in enumerate(args):
  77. if not isinstance(new, _nx.ndarray):
  78. new = np.asarray(new)
  79. if new.size == 0:
  80. # Explicitly type empty arrays to avoid float default
  81. new = new.astype(_nx.intp)
  82. if new.ndim != 1:
  83. raise ValueError("Cross index must be 1 dimensional")
  84. if issubdtype(new.dtype, _nx.bool_):
  85. new, = new.nonzero()
  86. new = new.reshape((1,)*k + (new.size,) + (1,)*(nd-k-1))
  87. out.append(new)
  88. return tuple(out)
  89. class nd_grid:
  90. """
  91. Construct a multi-dimensional "meshgrid".
  92. ``grid = nd_grid()`` creates an instance which will return a mesh-grid
  93. when indexed. The dimension and number of the output arrays are equal
  94. to the number of indexing dimensions. If the step length is not a
  95. complex number, then the stop is not inclusive.
  96. However, if the step length is a **complex number** (e.g. 5j), then the
  97. integer part of its magnitude is interpreted as specifying the
  98. number of points to create between the start and stop values, where
  99. the stop value **is inclusive**.
  100. If instantiated with an argument of ``sparse=True``, the mesh-grid is
  101. open (or not fleshed out) so that only one-dimension of each returned
  102. argument is greater than 1.
  103. Parameters
  104. ----------
  105. sparse : bool, optional
  106. Whether the grid is sparse or not. Default is False.
  107. Notes
  108. -----
  109. Two instances of `nd_grid` are made available in the NumPy namespace,
  110. `mgrid` and `ogrid`, approximately defined as::
  111. mgrid = nd_grid(sparse=False)
  112. ogrid = nd_grid(sparse=True)
  113. Users should use these pre-defined instances instead of using `nd_grid`
  114. directly.
  115. """
  116. def __init__(self, sparse=False):
  117. self.sparse = sparse
  118. def __getitem__(self, key):
  119. try:
  120. size = []
  121. # Mimic the behavior of `np.arange` and use a data type
  122. # which is at least as large as `np.int_`
  123. num_list = [0]
  124. for k in range(len(key)):
  125. step = key[k].step
  126. start = key[k].start
  127. stop = key[k].stop
  128. if start is None:
  129. start = 0
  130. if step is None:
  131. step = 1
  132. if isinstance(step, (_nx.complexfloating, complex)):
  133. step = abs(step)
  134. size.append(int(step))
  135. else:
  136. size.append(
  137. int(math.ceil((stop - start) / (step*1.0))))
  138. num_list += [start, stop, step]
  139. typ = _nx.result_type(*num_list)
  140. if self.sparse:
  141. nn = [_nx.arange(_x, dtype=_t)
  142. for _x, _t in zip(size, (typ,)*len(size))]
  143. else:
  144. nn = _nx.indices(size, typ)
  145. for k, kk in enumerate(key):
  146. step = kk.step
  147. start = kk.start
  148. if start is None:
  149. start = 0
  150. if step is None:
  151. step = 1
  152. if isinstance(step, (_nx.complexfloating, complex)):
  153. step = int(abs(step))
  154. if step != 1:
  155. step = (kk.stop - start) / float(step - 1)
  156. nn[k] = (nn[k]*step+start)
  157. if self.sparse:
  158. slobj = [_nx.newaxis]*len(size)
  159. for k in range(len(size)):
  160. slobj[k] = slice(None, None)
  161. nn[k] = nn[k][tuple(slobj)]
  162. slobj[k] = _nx.newaxis
  163. return nn
  164. except (IndexError, TypeError):
  165. step = key.step
  166. stop = key.stop
  167. start = key.start
  168. if start is None:
  169. start = 0
  170. if isinstance(step, (_nx.complexfloating, complex)):
  171. # Prevent the (potential) creation of integer arrays
  172. step_float = abs(step)
  173. step = length = int(step_float)
  174. if step != 1:
  175. step = (key.stop-start)/float(step-1)
  176. typ = _nx.result_type(start, stop, step_float)
  177. return _nx.arange(0, length, 1, dtype=typ)*step + start
  178. else:
  179. return _nx.arange(start, stop, step)
  180. class MGridClass(nd_grid):
  181. """
  182. An instance which returns a dense multi-dimensional "meshgrid".
  183. An instance which returns a dense (or fleshed out) mesh-grid
  184. when indexed, so that each returned argument has the same shape.
  185. The dimensions and number of the output arrays are equal to the
  186. number of indexing dimensions. If the step length is not a complex
  187. number, then the stop is not inclusive.
  188. However, if the step length is a **complex number** (e.g. 5j), then
  189. the integer part of its magnitude is interpreted as specifying the
  190. number of points to create between the start and stop values, where
  191. the stop value **is inclusive**.
  192. Returns
  193. -------
  194. mesh-grid `ndarrays` all of the same dimensions
  195. See Also
  196. --------
  197. ogrid : like `mgrid` but returns open (not fleshed out) mesh grids
  198. meshgrid: return coordinate matrices from coordinate vectors
  199. r_ : array concatenator
  200. :ref:`how-to-partition`
  201. Examples
  202. --------
  203. >>> np.mgrid[0:5, 0:5]
  204. array([[[0, 0, 0, 0, 0],
  205. [1, 1, 1, 1, 1],
  206. [2, 2, 2, 2, 2],
  207. [3, 3, 3, 3, 3],
  208. [4, 4, 4, 4, 4]],
  209. [[0, 1, 2, 3, 4],
  210. [0, 1, 2, 3, 4],
  211. [0, 1, 2, 3, 4],
  212. [0, 1, 2, 3, 4],
  213. [0, 1, 2, 3, 4]]])
  214. >>> np.mgrid[-1:1:5j]
  215. array([-1. , -0.5, 0. , 0.5, 1. ])
  216. """
  217. def __init__(self):
  218. super().__init__(sparse=False)
  219. mgrid = MGridClass()
  220. class OGridClass(nd_grid):
  221. """
  222. An instance which returns an open multi-dimensional "meshgrid".
  223. An instance which returns an open (i.e. not fleshed out) mesh-grid
  224. when indexed, so that only one dimension of each returned array is
  225. greater than 1. The dimension and number of the output arrays are
  226. equal to the number of indexing dimensions. If the step length is
  227. not a complex number, then the stop is not inclusive.
  228. However, if the step length is a **complex number** (e.g. 5j), then
  229. the integer part of its magnitude is interpreted as specifying the
  230. number of points to create between the start and stop values, where
  231. the stop value **is inclusive**.
  232. Returns
  233. -------
  234. mesh-grid
  235. `ndarrays` with only one dimension not equal to 1
  236. See Also
  237. --------
  238. mgrid : like `ogrid` but returns dense (or fleshed out) mesh grids
  239. meshgrid: return coordinate matrices from coordinate vectors
  240. r_ : array concatenator
  241. :ref:`how-to-partition`
  242. Examples
  243. --------
  244. >>> from numpy import ogrid
  245. >>> ogrid[-1:1:5j]
  246. array([-1. , -0.5, 0. , 0.5, 1. ])
  247. >>> ogrid[0:5,0:5]
  248. [array([[0],
  249. [1],
  250. [2],
  251. [3],
  252. [4]]), array([[0, 1, 2, 3, 4]])]
  253. """
  254. def __init__(self):
  255. super().__init__(sparse=True)
  256. ogrid = OGridClass()
  257. class AxisConcatenator:
  258. """
  259. Translates slice objects to concatenation along an axis.
  260. For detailed documentation on usage, see `r_`.
  261. """
  262. # allow ma.mr_ to override this
  263. concatenate = staticmethod(_nx.concatenate)
  264. makemat = staticmethod(matrixlib.matrix)
  265. def __init__(self, axis=0, matrix=False, ndmin=1, trans1d=-1):
  266. self.axis = axis
  267. self.matrix = matrix
  268. self.trans1d = trans1d
  269. self.ndmin = ndmin
  270. def __getitem__(self, key):
  271. # handle matrix builder syntax
  272. if isinstance(key, str):
  273. frame = sys._getframe().f_back
  274. mymat = matrixlib.bmat(key, frame.f_globals, frame.f_locals)
  275. return mymat
  276. if not isinstance(key, tuple):
  277. key = (key,)
  278. # copy attributes, since they can be overridden in the first argument
  279. trans1d = self.trans1d
  280. ndmin = self.ndmin
  281. matrix = self.matrix
  282. axis = self.axis
  283. objs = []
  284. # dtypes or scalars for weak scalar handling in result_type
  285. result_type_objs = []
  286. for k, item in enumerate(key):
  287. scalar = False
  288. if isinstance(item, slice):
  289. step = item.step
  290. start = item.start
  291. stop = item.stop
  292. if start is None:
  293. start = 0
  294. if step is None:
  295. step = 1
  296. if isinstance(step, (_nx.complexfloating, complex)):
  297. size = int(abs(step))
  298. newobj = linspace(start, stop, num=size)
  299. else:
  300. newobj = _nx.arange(start, stop, step)
  301. if ndmin > 1:
  302. newobj = array(newobj, copy=False, ndmin=ndmin)
  303. if trans1d != -1:
  304. newobj = newobj.swapaxes(-1, trans1d)
  305. elif isinstance(item, str):
  306. if k != 0:
  307. raise ValueError("special directives must be the "
  308. "first entry.")
  309. if item in ('r', 'c'):
  310. matrix = True
  311. col = (item == 'c')
  312. continue
  313. if ',' in item:
  314. vec = item.split(',')
  315. try:
  316. axis, ndmin = [int(x) for x in vec[:2]]
  317. if len(vec) == 3:
  318. trans1d = int(vec[2])
  319. continue
  320. except Exception as e:
  321. raise ValueError(
  322. "unknown special directive {!r}".format(item)
  323. ) from e
  324. try:
  325. axis = int(item)
  326. continue
  327. except (ValueError, TypeError) as e:
  328. raise ValueError("unknown special directive") from e
  329. elif type(item) in ScalarType:
  330. scalar = True
  331. newobj = item
  332. else:
  333. item_ndim = np.ndim(item)
  334. newobj = array(item, copy=False, subok=True, ndmin=ndmin)
  335. if trans1d != -1 and item_ndim < ndmin:
  336. k2 = ndmin - item_ndim
  337. k1 = trans1d
  338. if k1 < 0:
  339. k1 += k2 + 1
  340. defaxes = list(range(ndmin))
  341. axes = defaxes[:k1] + defaxes[k2:] + defaxes[k1:k2]
  342. newobj = newobj.transpose(axes)
  343. objs.append(newobj)
  344. if scalar:
  345. result_type_objs.append(item)
  346. else:
  347. result_type_objs.append(newobj.dtype)
  348. # Ensure that scalars won't up-cast unless warranted, for 0, drops
  349. # through to error in concatenate.
  350. if len(result_type_objs) != 0:
  351. final_dtype = _nx.result_type(*result_type_objs)
  352. # concatenate could do cast, but that can be overriden:
  353. objs = [array(obj, copy=False, subok=True,
  354. ndmin=ndmin, dtype=final_dtype) for obj in objs]
  355. res = self.concatenate(tuple(objs), axis=axis)
  356. if matrix:
  357. oldndim = res.ndim
  358. res = self.makemat(res)
  359. if oldndim == 1 and col:
  360. res = res.T
  361. return res
  362. def __len__(self):
  363. return 0
  364. # separate classes are used here instead of just making r_ = concatentor(0),
  365. # etc. because otherwise we couldn't get the doc string to come out right
  366. # in help(r_)
  367. class RClass(AxisConcatenator):
  368. """
  369. Translates slice objects to concatenation along the first axis.
  370. This is a simple way to build up arrays quickly. There are two use cases.
  371. 1. If the index expression contains comma separated arrays, then stack
  372. them along their first axis.
  373. 2. If the index expression contains slice notation or scalars then create
  374. a 1-D array with a range indicated by the slice notation.
  375. If slice notation is used, the syntax ``start:stop:step`` is equivalent
  376. to ``np.arange(start, stop, step)`` inside of the brackets. However, if
  377. ``step`` is an imaginary number (i.e. 100j) then its integer portion is
  378. interpreted as a number-of-points desired and the start and stop are
  379. inclusive. In other words ``start:stop:stepj`` is interpreted as
  380. ``np.linspace(start, stop, step, endpoint=1)`` inside of the brackets.
  381. After expansion of slice notation, all comma separated sequences are
  382. concatenated together.
  383. Optional character strings placed as the first element of the index
  384. expression can be used to change the output. The strings 'r' or 'c' result
  385. in matrix output. If the result is 1-D and 'r' is specified a 1 x N (row)
  386. matrix is produced. If the result is 1-D and 'c' is specified, then a N x 1
  387. (column) matrix is produced. If the result is 2-D then both provide the
  388. same matrix result.
  389. A string integer specifies which axis to stack multiple comma separated
  390. arrays along. A string of two comma-separated integers allows indication
  391. of the minimum number of dimensions to force each entry into as the
  392. second integer (the axis to concatenate along is still the first integer).
  393. A string with three comma-separated integers allows specification of the
  394. axis to concatenate along, the minimum number of dimensions to force the
  395. entries to, and which axis should contain the start of the arrays which
  396. are less than the specified number of dimensions. In other words the third
  397. integer allows you to specify where the 1's should be placed in the shape
  398. of the arrays that have their shapes upgraded. By default, they are placed
  399. in the front of the shape tuple. The third argument allows you to specify
  400. where the start of the array should be instead. Thus, a third argument of
  401. '0' would place the 1's at the end of the array shape. Negative integers
  402. specify where in the new shape tuple the last dimension of upgraded arrays
  403. should be placed, so the default is '-1'.
  404. Parameters
  405. ----------
  406. Not a function, so takes no parameters
  407. Returns
  408. -------
  409. A concatenated ndarray or matrix.
  410. See Also
  411. --------
  412. concatenate : Join a sequence of arrays along an existing axis.
  413. c_ : Translates slice objects to concatenation along the second axis.
  414. Examples
  415. --------
  416. >>> np.r_[np.array([1,2,3]), 0, 0, np.array([4,5,6])]
  417. array([1, 2, 3, ..., 4, 5, 6])
  418. >>> np.r_[-1:1:6j, [0]*3, 5, 6]
  419. array([-1. , -0.6, -0.2, 0.2, 0.6, 1. , 0. , 0. , 0. , 5. , 6. ])
  420. String integers specify the axis to concatenate along or the minimum
  421. number of dimensions to force entries into.
  422. >>> a = np.array([[0, 1, 2], [3, 4, 5]])
  423. >>> np.r_['-1', a, a] # concatenate along last axis
  424. array([[0, 1, 2, 0, 1, 2],
  425. [3, 4, 5, 3, 4, 5]])
  426. >>> np.r_['0,2', [1,2,3], [4,5,6]] # concatenate along first axis, dim>=2
  427. array([[1, 2, 3],
  428. [4, 5, 6]])
  429. >>> np.r_['0,2,0', [1,2,3], [4,5,6]]
  430. array([[1],
  431. [2],
  432. [3],
  433. [4],
  434. [5],
  435. [6]])
  436. >>> np.r_['1,2,0', [1,2,3], [4,5,6]]
  437. array([[1, 4],
  438. [2, 5],
  439. [3, 6]])
  440. Using 'r' or 'c' as a first string argument creates a matrix.
  441. >>> np.r_['r',[1,2,3], [4,5,6]]
  442. matrix([[1, 2, 3, 4, 5, 6]])
  443. """
  444. def __init__(self):
  445. AxisConcatenator.__init__(self, 0)
  446. r_ = RClass()
  447. class CClass(AxisConcatenator):
  448. """
  449. Translates slice objects to concatenation along the second axis.
  450. This is short-hand for ``np.r_['-1,2,0', index expression]``, which is
  451. useful because of its common occurrence. In particular, arrays will be
  452. stacked along their last axis after being upgraded to at least 2-D with
  453. 1's post-pended to the shape (column vectors made out of 1-D arrays).
  454. See Also
  455. --------
  456. column_stack : Stack 1-D arrays as columns into a 2-D array.
  457. r_ : For more detailed documentation.
  458. Examples
  459. --------
  460. >>> np.c_[np.array([1,2,3]), np.array([4,5,6])]
  461. array([[1, 4],
  462. [2, 5],
  463. [3, 6]])
  464. >>> np.c_[np.array([[1,2,3]]), 0, 0, np.array([[4,5,6]])]
  465. array([[1, 2, 3, ..., 4, 5, 6]])
  466. """
  467. def __init__(self):
  468. AxisConcatenator.__init__(self, -1, ndmin=2, trans1d=0)
  469. c_ = CClass()
  470. @set_module('numpy')
  471. class ndenumerate:
  472. """
  473. Multidimensional index iterator.
  474. Return an iterator yielding pairs of array coordinates and values.
  475. Parameters
  476. ----------
  477. arr : ndarray
  478. Input array.
  479. See Also
  480. --------
  481. ndindex, flatiter
  482. Examples
  483. --------
  484. >>> a = np.array([[1, 2], [3, 4]])
  485. >>> for index, x in np.ndenumerate(a):
  486. ... print(index, x)
  487. (0, 0) 1
  488. (0, 1) 2
  489. (1, 0) 3
  490. (1, 1) 4
  491. """
  492. def __init__(self, arr):
  493. self.iter = np.asarray(arr).flat
  494. def __next__(self):
  495. """
  496. Standard iterator method, returns the index tuple and array value.
  497. Returns
  498. -------
  499. coords : tuple of ints
  500. The indices of the current iteration.
  501. val : scalar
  502. The array element of the current iteration.
  503. """
  504. return self.iter.coords, next(self.iter)
  505. def __iter__(self):
  506. return self
  507. @set_module('numpy')
  508. class ndindex:
  509. """
  510. An N-dimensional iterator object to index arrays.
  511. Given the shape of an array, an `ndindex` instance iterates over
  512. the N-dimensional index of the array. At each iteration a tuple
  513. of indices is returned, the last dimension is iterated over first.
  514. Parameters
  515. ----------
  516. shape : ints, or a single tuple of ints
  517. The size of each dimension of the array can be passed as
  518. individual parameters or as the elements of a tuple.
  519. See Also
  520. --------
  521. ndenumerate, flatiter
  522. Examples
  523. --------
  524. Dimensions as individual arguments
  525. >>> for index in np.ndindex(3, 2, 1):
  526. ... print(index)
  527. (0, 0, 0)
  528. (0, 1, 0)
  529. (1, 0, 0)
  530. (1, 1, 0)
  531. (2, 0, 0)
  532. (2, 1, 0)
  533. Same dimensions - but in a tuple ``(3, 2, 1)``
  534. >>> for index in np.ndindex((3, 2, 1)):
  535. ... print(index)
  536. (0, 0, 0)
  537. (0, 1, 0)
  538. (1, 0, 0)
  539. (1, 1, 0)
  540. (2, 0, 0)
  541. (2, 1, 0)
  542. """
  543. def __init__(self, *shape):
  544. if len(shape) == 1 and isinstance(shape[0], tuple):
  545. shape = shape[0]
  546. x = as_strided(_nx.zeros(1), shape=shape,
  547. strides=_nx.zeros_like(shape))
  548. self._it = _nx.nditer(x, flags=['multi_index', 'zerosize_ok'],
  549. order='C')
  550. def __iter__(self):
  551. return self
  552. def ndincr(self):
  553. """
  554. Increment the multi-dimensional index by one.
  555. This method is for backward compatibility only: do not use.
  556. .. deprecated:: 1.20.0
  557. This method has been advised against since numpy 1.8.0, but only
  558. started emitting DeprecationWarning as of this version.
  559. """
  560. # NumPy 1.20.0, 2020-09-08
  561. warnings.warn(
  562. "`ndindex.ndincr()` is deprecated, use `next(ndindex)` instead",
  563. DeprecationWarning, stacklevel=2)
  564. next(self)
  565. def __next__(self):
  566. """
  567. Standard iterator method, updates the index and returns the index
  568. tuple.
  569. Returns
  570. -------
  571. val : tuple of ints
  572. Returns a tuple containing the indices of the current
  573. iteration.
  574. """
  575. next(self._it)
  576. return self._it.multi_index
  577. # You can do all this with slice() plus a few special objects,
  578. # but there's a lot to remember. This version is simpler because
  579. # it uses the standard array indexing syntax.
  580. #
  581. # Written by Konrad Hinsen <hinsen@cnrs-orleans.fr>
  582. # last revision: 1999-7-23
  583. #
  584. # Cosmetic changes by T. Oliphant 2001
  585. #
  586. #
  587. class IndexExpression:
  588. """
  589. A nicer way to build up index tuples for arrays.
  590. .. note::
  591. Use one of the two predefined instances `index_exp` or `s_`
  592. rather than directly using `IndexExpression`.
  593. For any index combination, including slicing and axis insertion,
  594. ``a[indices]`` is the same as ``a[np.index_exp[indices]]`` for any
  595. array `a`. However, ``np.index_exp[indices]`` can be used anywhere
  596. in Python code and returns a tuple of slice objects that can be
  597. used in the construction of complex index expressions.
  598. Parameters
  599. ----------
  600. maketuple : bool
  601. If True, always returns a tuple.
  602. See Also
  603. --------
  604. index_exp : Predefined instance that always returns a tuple:
  605. `index_exp = IndexExpression(maketuple=True)`.
  606. s_ : Predefined instance without tuple conversion:
  607. `s_ = IndexExpression(maketuple=False)`.
  608. Notes
  609. -----
  610. You can do all this with `slice()` plus a few special objects,
  611. but there's a lot to remember and this version is simpler because
  612. it uses the standard array indexing syntax.
  613. Examples
  614. --------
  615. >>> np.s_[2::2]
  616. slice(2, None, 2)
  617. >>> np.index_exp[2::2]
  618. (slice(2, None, 2),)
  619. >>> np.array([0, 1, 2, 3, 4])[np.s_[2::2]]
  620. array([2, 4])
  621. """
  622. def __init__(self, maketuple):
  623. self.maketuple = maketuple
  624. def __getitem__(self, item):
  625. if self.maketuple and not isinstance(item, tuple):
  626. return (item,)
  627. else:
  628. return item
  629. index_exp = IndexExpression(maketuple=True)
  630. s_ = IndexExpression(maketuple=False)
  631. # End contribution from Konrad.
  632. # The following functions complement those in twodim_base, but are
  633. # applicable to N-dimensions.
  634. def _fill_diagonal_dispatcher(a, val, wrap=None):
  635. return (a,)
  636. @array_function_dispatch(_fill_diagonal_dispatcher)
  637. def fill_diagonal(a, val, wrap=False):
  638. """Fill the main diagonal of the given array of any dimensionality.
  639. For an array `a` with ``a.ndim >= 2``, the diagonal is the list of
  640. locations with indices ``a[i, ..., i]`` all identical. This function
  641. modifies the input array in-place, it does not return a value.
  642. Parameters
  643. ----------
  644. a : array, at least 2-D.
  645. Array whose diagonal is to be filled, it gets modified in-place.
  646. val : scalar or array_like
  647. Value(s) to write on the diagonal. If `val` is scalar, the value is
  648. written along the diagonal. If array-like, the flattened `val` is
  649. written along the diagonal, repeating if necessary to fill all
  650. diagonal entries.
  651. wrap : bool
  652. For tall matrices in NumPy version up to 1.6.2, the
  653. diagonal "wrapped" after N columns. You can have this behavior
  654. with this option. This affects only tall matrices.
  655. See also
  656. --------
  657. diag_indices, diag_indices_from
  658. Notes
  659. -----
  660. .. versionadded:: 1.4.0
  661. This functionality can be obtained via `diag_indices`, but internally
  662. this version uses a much faster implementation that never constructs the
  663. indices and uses simple slicing.
  664. Examples
  665. --------
  666. >>> a = np.zeros((3, 3), int)
  667. >>> np.fill_diagonal(a, 5)
  668. >>> a
  669. array([[5, 0, 0],
  670. [0, 5, 0],
  671. [0, 0, 5]])
  672. The same function can operate on a 4-D array:
  673. >>> a = np.zeros((3, 3, 3, 3), int)
  674. >>> np.fill_diagonal(a, 4)
  675. We only show a few blocks for clarity:
  676. >>> a[0, 0]
  677. array([[4, 0, 0],
  678. [0, 0, 0],
  679. [0, 0, 0]])
  680. >>> a[1, 1]
  681. array([[0, 0, 0],
  682. [0, 4, 0],
  683. [0, 0, 0]])
  684. >>> a[2, 2]
  685. array([[0, 0, 0],
  686. [0, 0, 0],
  687. [0, 0, 4]])
  688. The wrap option affects only tall matrices:
  689. >>> # tall matrices no wrap
  690. >>> a = np.zeros((5, 3), int)
  691. >>> np.fill_diagonal(a, 4)
  692. >>> a
  693. array([[4, 0, 0],
  694. [0, 4, 0],
  695. [0, 0, 4],
  696. [0, 0, 0],
  697. [0, 0, 0]])
  698. >>> # tall matrices wrap
  699. >>> a = np.zeros((5, 3), int)
  700. >>> np.fill_diagonal(a, 4, wrap=True)
  701. >>> a
  702. array([[4, 0, 0],
  703. [0, 4, 0],
  704. [0, 0, 4],
  705. [0, 0, 0],
  706. [4, 0, 0]])
  707. >>> # wide matrices
  708. >>> a = np.zeros((3, 5), int)
  709. >>> np.fill_diagonal(a, 4, wrap=True)
  710. >>> a
  711. array([[4, 0, 0, 0, 0],
  712. [0, 4, 0, 0, 0],
  713. [0, 0, 4, 0, 0]])
  714. The anti-diagonal can be filled by reversing the order of elements
  715. using either `numpy.flipud` or `numpy.fliplr`.
  716. >>> a = np.zeros((3, 3), int);
  717. >>> np.fill_diagonal(np.fliplr(a), [1,2,3]) # Horizontal flip
  718. >>> a
  719. array([[0, 0, 1],
  720. [0, 2, 0],
  721. [3, 0, 0]])
  722. >>> np.fill_diagonal(np.flipud(a), [1,2,3]) # Vertical flip
  723. >>> a
  724. array([[0, 0, 3],
  725. [0, 2, 0],
  726. [1, 0, 0]])
  727. Note that the order in which the diagonal is filled varies depending
  728. on the flip function.
  729. """
  730. if a.ndim < 2:
  731. raise ValueError("array must be at least 2-d")
  732. end = None
  733. if a.ndim == 2:
  734. # Explicit, fast formula for the common case. For 2-d arrays, we
  735. # accept rectangular ones.
  736. step = a.shape[1] + 1
  737. # This is needed to don't have tall matrix have the diagonal wrap.
  738. if not wrap:
  739. end = a.shape[1] * a.shape[1]
  740. else:
  741. # For more than d=2, the strided formula is only valid for arrays with
  742. # all dimensions equal, so we check first.
  743. if not np.all(diff(a.shape) == 0):
  744. raise ValueError("All dimensions of input must be of equal length")
  745. step = 1 + (np.cumprod(a.shape[:-1])).sum()
  746. # Write the value out into the diagonal.
  747. a.flat[:end:step] = val
  748. @set_module('numpy')
  749. def diag_indices(n, ndim=2):
  750. """
  751. Return the indices to access the main diagonal of an array.
  752. This returns a tuple of indices that can be used to access the main
  753. diagonal of an array `a` with ``a.ndim >= 2`` dimensions and shape
  754. (n, n, ..., n). For ``a.ndim = 2`` this is the usual diagonal, for
  755. ``a.ndim > 2`` this is the set of indices to access ``a[i, i, ..., i]``
  756. for ``i = [0..n-1]``.
  757. Parameters
  758. ----------
  759. n : int
  760. The size, along each dimension, of the arrays for which the returned
  761. indices can be used.
  762. ndim : int, optional
  763. The number of dimensions.
  764. See Also
  765. --------
  766. diag_indices_from
  767. Notes
  768. -----
  769. .. versionadded:: 1.4.0
  770. Examples
  771. --------
  772. Create a set of indices to access the diagonal of a (4, 4) array:
  773. >>> di = np.diag_indices(4)
  774. >>> di
  775. (array([0, 1, 2, 3]), array([0, 1, 2, 3]))
  776. >>> a = np.arange(16).reshape(4, 4)
  777. >>> a
  778. array([[ 0, 1, 2, 3],
  779. [ 4, 5, 6, 7],
  780. [ 8, 9, 10, 11],
  781. [12, 13, 14, 15]])
  782. >>> a[di] = 100
  783. >>> a
  784. array([[100, 1, 2, 3],
  785. [ 4, 100, 6, 7],
  786. [ 8, 9, 100, 11],
  787. [ 12, 13, 14, 100]])
  788. Now, we create indices to manipulate a 3-D array:
  789. >>> d3 = np.diag_indices(2, 3)
  790. >>> d3
  791. (array([0, 1]), array([0, 1]), array([0, 1]))
  792. And use it to set the diagonal of an array of zeros to 1:
  793. >>> a = np.zeros((2, 2, 2), dtype=int)
  794. >>> a[d3] = 1
  795. >>> a
  796. array([[[1, 0],
  797. [0, 0]],
  798. [[0, 0],
  799. [0, 1]]])
  800. """
  801. idx = np.arange(n)
  802. return (idx,) * ndim
  803. def _diag_indices_from(arr):
  804. return (arr,)
  805. @array_function_dispatch(_diag_indices_from)
  806. def diag_indices_from(arr):
  807. """
  808. Return the indices to access the main diagonal of an n-dimensional array.
  809. See `diag_indices` for full details.
  810. Parameters
  811. ----------
  812. arr : array, at least 2-D
  813. See Also
  814. --------
  815. diag_indices
  816. Notes
  817. -----
  818. .. versionadded:: 1.4.0
  819. Examples
  820. --------
  821. Create a 4 by 4 array.
  822. >>> a = np.arange(16).reshape(4, 4)
  823. >>> a
  824. array([[ 0, 1, 2, 3],
  825. [ 4, 5, 6, 7],
  826. [ 8, 9, 10, 11],
  827. [12, 13, 14, 15]])
  828. Get the indices of the diagonal elements.
  829. >>> di = np.diag_indices_from(a)
  830. >>> di
  831. (array([0, 1, 2, 3]), array([0, 1, 2, 3]))
  832. >>> a[di]
  833. array([ 0, 5, 10, 15])
  834. This is simply syntactic sugar for diag_indices.
  835. >>> np.diag_indices(a.shape[0])
  836. (array([0, 1, 2, 3]), array([0, 1, 2, 3]))
  837. """
  838. if not arr.ndim >= 2:
  839. raise ValueError("input array must be at least 2-d")
  840. # For more than d=2, the strided formula is only valid for arrays with
  841. # all dimensions equal, so we check first.
  842. if not np.all(diff(arr.shape) == 0):
  843. raise ValueError("All dimensions of input must be of equal length")
  844. return diag_indices(arr.shape[0], arr.ndim)