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