index_tricks.py 30 KB

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