Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/numpy/lib/_index_tricks_impl.py: 30%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

260 statements  

1import functools 

2import math 

3import sys 

4from itertools import product 

5 

6import numpy as np 

7import numpy._core.numeric as _nx 

8import numpy.matrixlib as matrixlib 

9from numpy._core import linspace, overrides 

10from numpy._core.multiarray import ravel_multi_index, unravel_index 

11from numpy._core.numeric import ScalarType, array 

12from numpy._core.numerictypes import issubdtype 

13from numpy._utils import set_module 

14from numpy.lib._function_base_impl import diff 

15 

16array_function_dispatch = functools.partial( 

17 overrides.array_function_dispatch, module='numpy') 

18 

19 

20__all__ = [ 

21 'ravel_multi_index', 'unravel_index', 'mgrid', 'ogrid', 'r_', 'c_', 

22 's_', 'index_exp', 'ix_', 'ndenumerate', 'ndindex', 'fill_diagonal', 

23 'diag_indices', 'diag_indices_from' 

24] 

25 

26 

27def _ix__dispatcher(*args): 

28 return args 

29 

30 

31@array_function_dispatch(_ix__dispatcher) 

32def ix_(*args): 

33 """ 

34 Construct an open mesh from multiple sequences. 

35 

36 This function takes N 1-D sequences and returns N outputs with N 

37 dimensions each, such that the shape is 1 in all but one dimension 

38 and the dimension with the non-unit shape value cycles through all 

39 N dimensions. 

40 

41 Using `ix_` one can quickly construct index arrays that will index 

42 the cross product. ``a[np.ix_([1,3],[2,5])]`` returns the array 

43 ``[[a[1,2] a[1,5]], [a[3,2] a[3,5]]]``. 

44 

45 Parameters 

46 ---------- 

47 args : 1-D sequences 

48 Each sequence should be of integer or boolean type. 

49 Boolean sequences will be interpreted as boolean masks for the 

50 corresponding dimension (equivalent to passing in 

51 ``np.nonzero(boolean_sequence)``). 

52 

53 Returns 

54 ------- 

55 out : tuple of ndarrays 

56 N arrays with N dimensions each, with N the number of input 

57 sequences. Together these arrays form an open mesh. 

58 

59 See Also 

60 -------- 

61 ogrid, mgrid, meshgrid 

62 

63 Examples 

64 -------- 

65 >>> import numpy as np 

66 >>> a = np.arange(10).reshape(2, 5) 

67 >>> a 

68 array([[0, 1, 2, 3, 4], 

69 [5, 6, 7, 8, 9]]) 

70 >>> ixgrid = np.ix_([0, 1], [2, 4]) 

71 >>> ixgrid 

72 (array([[0], 

73 [1]]), array([[2, 4]])) 

74 >>> ixgrid[0].shape, ixgrid[1].shape 

75 ((2, 1), (1, 2)) 

76 >>> a[ixgrid] 

77 array([[2, 4], 

78 [7, 9]]) 

79 

80 >>> ixgrid = np.ix_([True, True], [2, 4]) 

81 >>> a[ixgrid] 

82 array([[2, 4], 

83 [7, 9]]) 

84 >>> ixgrid = np.ix_([True, True], [False, False, True, False, True]) 

85 >>> a[ixgrid] 

86 array([[2, 4], 

87 [7, 9]]) 

88 

89 """ 

90 out = [] 

91 nd = len(args) 

92 for k, new in enumerate(args): 

93 if not isinstance(new, _nx.ndarray): 

94 new = np.asarray(new) 

95 if new.size == 0: 

96 # Explicitly type empty arrays to avoid float default 

97 new = new.astype(_nx.intp) 

98 if new.ndim != 1: 

99 raise ValueError("Cross index must be 1 dimensional") 

100 if issubdtype(new.dtype, _nx.bool): 

101 new, = new.nonzero() 

102 new = new.reshape((1,) * k + (new.size,) + (1,) * (nd - k - 1)) 

103 out.append(new) 

104 return tuple(out) 

105 

106 

107class nd_grid: 

108 """ 

109 Construct a multi-dimensional "meshgrid". 

110 

111 ``grid = nd_grid()`` creates an instance which will return a mesh-grid 

112 when indexed. The dimension and number of the output arrays are equal 

113 to the number of indexing dimensions. If the step length is not a 

114 complex number, then the stop is not inclusive. 

115 

116 However, if the step length is a **complex number** (e.g. 5j), then the 

117 integer part of its magnitude is interpreted as specifying the 

118 number of points to create between the start and stop values, where 

119 the stop value **is inclusive**. 

120 

121 If instantiated with an argument of ``sparse=True``, the mesh-grid is 

122 open (or not fleshed out) so that only one-dimension of each returned 

123 argument is greater than 1. 

124 

125 Parameters 

126 ---------- 

127 sparse : bool, optional 

128 Whether the grid is sparse or not. Default is False. 

129 

130 Notes 

131 ----- 

132 Two instances of `nd_grid` are made available in the NumPy namespace, 

133 `mgrid` and `ogrid`, approximately defined as:: 

134 

135 mgrid = nd_grid(sparse=False) 

136 ogrid = nd_grid(sparse=True) 

137 

138 Users should use these pre-defined instances instead of using `nd_grid` 

139 directly. 

140 """ 

141 __slots__ = ('sparse',) 

142 

143 def __init__(self, sparse=False): 

144 self.sparse = sparse 

145 

146 def __getitem__(self, key): 

147 try: 

148 size = [] 

149 # Mimic the behavior of `np.arange` and use a data type 

150 # which is at least as large as `np.int_` 

151 num_list = [0] 

152 for k in range(len(key)): 

153 step = key[k].step 

154 start = key[k].start 

155 stop = key[k].stop 

156 if start is None: 

157 start = 0 

158 if step is None: 

159 step = 1 

160 if isinstance(step, (_nx.complexfloating, complex)): 

161 step = abs(step) 

162 size.append(int(step)) 

163 else: 

164 size.append( 

165 math.ceil((stop - start) / step)) 

166 num_list += [start, stop, step] 

167 typ = _nx.result_type(*num_list) 

168 if self.sparse: 

169 nn = [_nx.arange(_x, dtype=_t) 

170 for _x, _t in zip(size, (typ,) * len(size))] 

171 else: 

172 nn = _nx.indices(size, typ) 

173 for k, kk in enumerate(key): 

174 step = kk.step 

175 start = kk.start 

176 if start is None: 

177 start = 0 

178 if step is None: 

179 step = 1 

180 if isinstance(step, (_nx.complexfloating, complex)): 

181 step = int(abs(step)) 

182 if step != 1: 

183 step = (kk.stop - start) / float(step - 1) 

184 nn[k] = (nn[k] * step + start) 

185 if self.sparse: 

186 slobj = [_nx.newaxis] * len(size) 

187 for k in range(len(size)): 

188 slobj[k] = slice(None, None) 

189 nn[k] = nn[k][tuple(slobj)] 

190 slobj[k] = _nx.newaxis 

191 return tuple(nn) # ogrid -> tuple of arrays 

192 return nn # mgrid -> ndarray 

193 except (IndexError, TypeError): 

194 step = key.step 

195 stop = key.stop 

196 start = key.start 

197 if start is None: 

198 start = 0 

199 if isinstance(step, (_nx.complexfloating, complex)): 

200 # Prevent the (potential) creation of integer arrays 

201 step_float = abs(step) 

202 step = length = int(step_float) 

203 if step != 1: 

204 step = (key.stop - start) / float(step - 1) 

205 typ = _nx.result_type(start, stop, step_float) 

206 return _nx.arange(0, length, 1, dtype=typ) * step + start 

207 else: 

208 return _nx.arange(start, stop, step) 

209 

210 

211class MGridClass(nd_grid): 

212 """ 

213 An instance which returns a dense multi-dimensional "meshgrid". 

214 

215 An instance which returns a dense (or fleshed out) mesh-grid 

216 when indexed, so that each returned argument has the same shape. 

217 The dimensions and number of the output arrays are equal to the 

218 number of indexing dimensions. If the step length is not a complex 

219 number, then the stop is not inclusive. 

220 

221 However, if the step length is a **complex number** (e.g. 5j), then 

222 the integer part of its magnitude is interpreted as specifying the 

223 number of points to create between the start and stop values, where 

224 the stop value **is inclusive**. 

225 

226 Returns 

227 ------- 

228 mesh-grid : ndarray 

229 A single array, containing a set of `ndarray`\\ s all of the same 

230 dimensions. stacked along the first axis. 

231 

232 See Also 

233 -------- 

234 ogrid : like `mgrid` but returns open (not fleshed out) mesh grids 

235 meshgrid: return coordinate matrices from coordinate vectors 

236 r_ : array concatenator 

237 :ref:`how-to-partition` 

238 

239 Examples 

240 -------- 

241 >>> import numpy as np 

242 >>> np.mgrid[0:5, 0:5] 

243 array([[[0, 0, 0, 0, 0], 

244 [1, 1, 1, 1, 1], 

245 [2, 2, 2, 2, 2], 

246 [3, 3, 3, 3, 3], 

247 [4, 4, 4, 4, 4]], 

248 [[0, 1, 2, 3, 4], 

249 [0, 1, 2, 3, 4], 

250 [0, 1, 2, 3, 4], 

251 [0, 1, 2, 3, 4], 

252 [0, 1, 2, 3, 4]]]) 

253 >>> np.mgrid[-1:1:5j] 

254 array([-1. , -0.5, 0. , 0.5, 1. ]) 

255 

256 >>> np.mgrid[0:4].shape 

257 (4,) 

258 >>> np.mgrid[0:4, 0:5].shape 

259 (2, 4, 5) 

260 >>> np.mgrid[0:4, 0:5, 0:6].shape 

261 (3, 4, 5, 6) 

262 

263 """ 

264 __slots__ = () 

265 

266 def __init__(self): 

267 super().__init__(sparse=False) 

268 

269 

270mgrid = MGridClass() 

271 

272 

273class OGridClass(nd_grid): 

274 """ 

275 An instance which returns an open multi-dimensional "meshgrid". 

276 

277 An instance which returns an open (i.e. not fleshed out) mesh-grid 

278 when indexed, so that only one dimension of each returned array is 

279 greater than 1. The dimension and number of the output arrays are 

280 equal to the number of indexing dimensions. If the step length is 

281 not a complex number, then the stop is not inclusive. 

282 

283 However, if the step length is a **complex number** (e.g. 5j), then 

284 the integer part of its magnitude is interpreted as specifying the 

285 number of points to create between the start and stop values, where 

286 the stop value **is inclusive**. 

287 

288 Returns 

289 ------- 

290 mesh-grid : ndarray or tuple of ndarrays 

291 If the input is a single slice, returns an array. 

292 If the input is multiple slices, returns a tuple of arrays, with 

293 only one dimension not equal to 1. 

294 

295 See Also 

296 -------- 

297 mgrid : like `ogrid` but returns dense (or fleshed out) mesh grids 

298 meshgrid: return coordinate matrices from coordinate vectors 

299 r_ : array concatenator 

300 :ref:`how-to-partition` 

301 

302 Examples 

303 -------- 

304 >>> from numpy import ogrid 

305 >>> ogrid[-1:1:5j] 

306 array([-1. , -0.5, 0. , 0.5, 1. ]) 

307 >>> ogrid[0:5, 0:5] 

308 (array([[0], 

309 [1], 

310 [2], 

311 [3], 

312 [4]]), 

313 array([[0, 1, 2, 3, 4]])) 

314 

315 """ 

316 __slots__ = () 

317 

318 def __init__(self): 

319 super().__init__(sparse=True) 

320 

321 

322ogrid = OGridClass() 

323 

324 

325class AxisConcatenator: 

326 """ 

327 Translates slice objects to concatenation along an axis. 

328 

329 For detailed documentation on usage, see `r_`. 

330 """ 

331 __slots__ = ('axis', 'matrix', 'ndmin', 'trans1d') 

332 

333 # allow ma.mr_ to override this 

334 concatenate = staticmethod(_nx.concatenate) 

335 makemat = staticmethod(matrixlib.matrix) 

336 

337 def __init__(self, axis=0, matrix=False, ndmin=1, trans1d=-1): 

338 self.axis = axis 

339 self.matrix = matrix 

340 self.trans1d = trans1d 

341 self.ndmin = ndmin 

342 

343 def __getitem__(self, key): 

344 # handle matrix builder syntax 

345 if isinstance(key, str): 

346 frame = sys._getframe().f_back 

347 mymat = matrixlib.bmat(key, frame.f_globals, frame.f_locals) 

348 return mymat 

349 

350 if not isinstance(key, tuple): 

351 key = (key,) 

352 

353 # copy attributes, since they can be overridden in the first argument 

354 trans1d = self.trans1d 

355 ndmin = self.ndmin 

356 matrix = self.matrix 

357 axis = self.axis 

358 

359 objs = [] 

360 # dtypes or scalars for weak scalar handling in result_type 

361 result_type_objs = [] 

362 

363 for k, item in enumerate(key): 

364 scalar = False 

365 if isinstance(item, slice): 

366 step = item.step 

367 start = item.start 

368 stop = item.stop 

369 if start is None: 

370 start = 0 

371 if step is None: 

372 step = 1 

373 if isinstance(step, (_nx.complexfloating, complex)): 

374 size = int(abs(step)) 

375 newobj = linspace(start, stop, num=size) 

376 else: 

377 newobj = _nx.arange(start, stop, step) 

378 if ndmin > 1: 

379 newobj = array(newobj, copy=None, ndmin=ndmin) 

380 if trans1d != -1: 

381 newobj = newobj.swapaxes(-1, trans1d) 

382 elif isinstance(item, str): 

383 if k != 0: 

384 raise ValueError("special directives must be the " 

385 "first entry.") 

386 if item in ('r', 'c'): 

387 matrix = True 

388 col = (item == 'c') 

389 continue 

390 if ',' in item: 

391 vec = item.split(',') 

392 try: 

393 axis, ndmin = [int(x) for x in vec[:2]] 

394 if len(vec) == 3: 

395 trans1d = int(vec[2]) 

396 continue 

397 except Exception as e: 

398 raise ValueError( 

399 f"unknown special directive {item!r}" 

400 ) from e 

401 try: 

402 axis = int(item) 

403 continue 

404 except (ValueError, TypeError) as e: 

405 raise ValueError("unknown special directive") from e 

406 elif type(item) in ScalarType: 

407 scalar = True 

408 newobj = item 

409 else: 

410 item_ndim = np.ndim(item) 

411 newobj = array(item, copy=None, subok=True, ndmin=ndmin) 

412 if trans1d != -1 and item_ndim < ndmin: 

413 k2 = ndmin - item_ndim 

414 k1 = trans1d 

415 if k1 < 0: 

416 k1 += k2 + 1 

417 defaxes = list(range(ndmin)) 

418 axes = defaxes[:k1] + defaxes[k2:] + defaxes[k1:k2] 

419 newobj = newobj.transpose(axes) 

420 

421 objs.append(newobj) 

422 if scalar: 

423 result_type_objs.append(item) 

424 else: 

425 result_type_objs.append(newobj.dtype) 

426 

427 # Ensure that scalars won't up-cast unless warranted, for 0, drops 

428 # through to error in concatenate. 

429 if len(result_type_objs) != 0: 

430 final_dtype = _nx.result_type(*result_type_objs) 

431 # concatenate could do cast, but that can be overridden: 

432 objs = [array(obj, copy=None, subok=True, 

433 ndmin=ndmin, dtype=final_dtype) for obj in objs] 

434 

435 res = self.concatenate(tuple(objs), axis=axis) 

436 

437 if matrix: 

438 oldndim = res.ndim 

439 res = self.makemat(res) 

440 if oldndim == 1 and col: 

441 res = res.T 

442 return res 

443 

444 def __len__(self): 

445 return 0 

446 

447# separate classes are used here instead of just making r_ = concatenator(0), 

448# etc. because otherwise we couldn't get the doc string to come out right 

449# in help(r_) 

450 

451 

452class RClass(AxisConcatenator): 

453 """ 

454 Translates slice objects to concatenation along the first axis. 

455 

456 This is a simple way to build up arrays quickly. There are two use cases. 

457 

458 1. If the index expression contains comma separated arrays, then stack 

459 them along their first axis. 

460 2. If the index expression contains slice notation or scalars then create 

461 a 1-D array with a range indicated by the slice notation. 

462 

463 If slice notation is used, the syntax ``start:stop:step`` is equivalent 

464 to ``np.arange(start, stop, step)`` inside of the brackets. However, if 

465 ``step`` is an imaginary number (i.e. 100j) then its integer portion is 

466 interpreted as a number-of-points desired and the start and stop are 

467 inclusive. In other words ``start:stop:stepj`` is interpreted as 

468 ``np.linspace(start, stop, step, endpoint=1)`` inside of the brackets. 

469 After expansion of slice notation, all comma separated sequences are 

470 concatenated together. 

471 

472 Optional character strings placed as the first element of the index 

473 expression can be used to change the output. The strings 'r' or 'c' result 

474 in matrix output. If the result is 1-D and 'r' is specified a 1 x N (row) 

475 matrix is produced. If the result is 1-D and 'c' is specified, then 

476 an N x 1 (column) matrix is produced. 

477 If the result is 2-D then both provide the same matrix result. 

478 

479 A string integer specifies which axis to stack multiple comma separated 

480 arrays along. A string of two comma-separated integers allows indication 

481 of the minimum number of dimensions to force each entry into as the 

482 second integer (the axis to concatenate along is still the first integer). 

483 

484 A string with three comma-separated integers allows specification of the 

485 axis to concatenate along, the minimum number of dimensions to force the 

486 entries to, and which axis should contain the start of the arrays which 

487 are less than the specified number of dimensions. In other words the third 

488 integer allows you to specify where the 1's should be placed in the shape 

489 of the arrays that have their shapes upgraded. By default, they are placed 

490 in the front of the shape tuple. The third argument allows you to specify 

491 where the start of the array should be instead. Thus, a third argument of 

492 '0' would place the 1's at the end of the array shape. Negative integers 

493 specify where in the new shape tuple the last dimension of upgraded arrays 

494 should be placed, so the default is '-1'. 

495 

496 Parameters 

497 ---------- 

498 Not a function, so takes no parameters 

499 

500 

501 Returns 

502 ------- 

503 A concatenated ndarray or matrix. 

504 

505 See Also 

506 -------- 

507 concatenate : Join a sequence of arrays along an existing axis. 

508 c_ : Translates slice objects to concatenation along the second axis. 

509 

510 Examples 

511 -------- 

512 >>> import numpy as np 

513 >>> np.r_[np.array([1,2,3]), 0, 0, np.array([4,5,6])] 

514 array([1, 2, 3, ..., 4, 5, 6]) 

515 >>> np.r_[-1:1:6j, [0]*3, 5, 6] 

516 array([-1. , -0.6, -0.2, 0.2, 0.6, 1. , 0. , 0. , 0. , 5. , 6. ]) 

517 

518 String integers specify the axis to concatenate along or the minimum 

519 number of dimensions to force entries into. 

520 

521 >>> a = np.array([[0, 1, 2], [3, 4, 5]]) 

522 >>> np.r_['-1', a, a] # concatenate along last axis 

523 array([[0, 1, 2, 0, 1, 2], 

524 [3, 4, 5, 3, 4, 5]]) 

525 >>> np.r_['0,2', [1,2,3], [4,5,6]] # concatenate along first axis, dim>=2 

526 array([[1, 2, 3], 

527 [4, 5, 6]]) 

528 

529 >>> np.r_['0,2,0', [1,2,3], [4,5,6]] 

530 array([[1], 

531 [2], 

532 [3], 

533 [4], 

534 [5], 

535 [6]]) 

536 >>> np.r_['1,2,0', [1,2,3], [4,5,6]] 

537 array([[1, 4], 

538 [2, 5], 

539 [3, 6]]) 

540 

541 Using 'r' or 'c' as a first string argument creates a matrix. 

542 

543 >>> np.r_['r',[1,2,3], [4,5,6]] 

544 matrix([[1, 2, 3, 4, 5, 6]]) 

545 

546 """ 

547 __slots__ = () 

548 

549 def __init__(self): 

550 AxisConcatenator.__init__(self, 0) 

551 

552 

553r_ = RClass() 

554 

555 

556class CClass(AxisConcatenator): 

557 """ 

558 Translates slice objects to concatenation along the second axis. 

559 

560 This is short-hand for ``np.r_['-1,2,0', index expression]``, which is 

561 useful because of its common occurrence. In particular, arrays will be 

562 stacked along their last axis after being upgraded to at least 2-D with 

563 1's post-pended to the shape (column vectors made out of 1-D arrays). 

564 

565 See Also 

566 -------- 

567 column_stack : Stack 1-D arrays as columns into a 2-D array. 

568 r_ : For more detailed documentation. 

569 

570 Examples 

571 -------- 

572 >>> import numpy as np 

573 >>> np.c_[np.array([1,2,3]), np.array([4,5,6])] 

574 array([[1, 4], 

575 [2, 5], 

576 [3, 6]]) 

577 >>> np.c_[np.array([[1,2,3]]), 0, 0, np.array([[4,5,6]])] 

578 array([[1, 2, 3, ..., 4, 5, 6]]) 

579 

580 """ 

581 __slots__ = () 

582 

583 def __init__(self): 

584 AxisConcatenator.__init__(self, -1, ndmin=2, trans1d=0) 

585 

586 

587c_ = CClass() 

588 

589 

590@set_module('numpy') 

591class ndenumerate: 

592 """ 

593 Multidimensional index iterator. 

594 

595 Return an iterator yielding pairs of array coordinates and values. 

596 

597 Parameters 

598 ---------- 

599 arr : ndarray 

600 Input array. 

601 

602 See Also 

603 -------- 

604 ndindex, flatiter 

605 

606 Examples 

607 -------- 

608 >>> import numpy as np 

609 >>> a = np.array([[1, 2], [3, 4]]) 

610 >>> for index, x in np.ndenumerate(a): 

611 ... print(index, x) 

612 (0, 0) 1 

613 (0, 1) 2 

614 (1, 0) 3 

615 (1, 1) 4 

616 

617 """ 

618 

619 def __init__(self, arr): 

620 self.iter = np.asarray(arr).flat 

621 

622 def __next__(self): 

623 """ 

624 Standard iterator method, returns the index tuple and array value. 

625 

626 Returns 

627 ------- 

628 coords : tuple of ints 

629 The indices of the current iteration. 

630 val : scalar 

631 The array element of the current iteration. 

632 

633 """ 

634 return self.iter.coords, next(self.iter) 

635 

636 def __iter__(self): 

637 return self 

638 

639 

640@set_module('numpy') 

641class ndindex: 

642 """ 

643 An N-dimensional iterator object to index arrays. 

644 

645 Given the shape of an array, an `ndindex` instance iterates over 

646 the N-dimensional index of the array. At each iteration a tuple 

647 of indices is returned, the last dimension is iterated over first. 

648 

649 Parameters 

650 ---------- 

651 shape : ints, or a single tuple of ints 

652 The size of each dimension of the array can be passed as 

653 individual parameters or as the elements of a tuple. 

654 

655 See Also 

656 -------- 

657 ndenumerate, flatiter 

658 

659 Examples 

660 -------- 

661 >>> import numpy as np 

662 

663 Dimensions as individual arguments 

664 

665 >>> for index in np.ndindex(3, 2, 1): 

666 ... print(index) 

667 (0, 0, 0) 

668 (0, 1, 0) 

669 (1, 0, 0) 

670 (1, 1, 0) 

671 (2, 0, 0) 

672 (2, 1, 0) 

673 

674 Same dimensions - but in a tuple ``(3, 2, 1)`` 

675 

676 >>> for index in np.ndindex((3, 2, 1)): 

677 ... print(index) 

678 (0, 0, 0) 

679 (0, 1, 0) 

680 (1, 0, 0) 

681 (1, 1, 0) 

682 (2, 0, 0) 

683 (2, 1, 0) 

684 

685 """ 

686 

687 def __init__(self, *shape): 

688 if len(shape) == 1 and isinstance(shape[0], tuple): 

689 shape = shape[0] 

690 if min(shape, default=0) < 0: 

691 raise ValueError("negative dimensions are not allowed") 

692 self._iter = product(*map(range, shape)) 

693 

694 def __iter__(self): 

695 return self 

696 

697 def __next__(self): 

698 """ 

699 Standard iterator method, updates the index and returns the index 

700 tuple. 

701 

702 Returns 

703 ------- 

704 val : tuple of ints 

705 Returns a tuple containing the indices of the current 

706 iteration. 

707 

708 """ 

709 return next(self._iter) 

710 

711 

712# You can do all this with slice() plus a few special objects, 

713# but there's a lot to remember. This version is simpler because 

714# it uses the standard array indexing syntax. 

715# 

716# Written by Konrad Hinsen <hinsen@cnrs-orleans.fr> 

717# last revision: 1999-7-23 

718# 

719# Cosmetic changes by T. Oliphant 2001 

720# 

721# 

722 

723class IndexExpression: 

724 """ 

725 A nicer way to build up index tuples for arrays. 

726 

727 .. note:: 

728 Use one of the two predefined instances ``index_exp`` or `s_` 

729 rather than directly using `IndexExpression`. 

730 

731 For any index combination, including slicing and axis insertion, 

732 ``a[indices]`` is the same as ``a[np.index_exp[indices]]`` for any 

733 array `a`. However, ``np.index_exp[indices]`` can be used anywhere 

734 in Python code and returns a tuple of slice objects that can be 

735 used in the construction of complex index expressions. 

736 

737 Parameters 

738 ---------- 

739 maketuple : bool 

740 If True, always returns a tuple. 

741 

742 See Also 

743 -------- 

744 s_ : Predefined instance without tuple conversion: 

745 `s_ = IndexExpression(maketuple=False)`. 

746 The ``index_exp`` is another predefined instance that 

747 always returns a tuple: 

748 `index_exp = IndexExpression(maketuple=True)`. 

749 

750 Notes 

751 ----- 

752 You can do all this with :class:`slice` plus a few special objects, 

753 but there's a lot to remember and this version is simpler because 

754 it uses the standard array indexing syntax. 

755 

756 Examples 

757 -------- 

758 >>> import numpy as np 

759 >>> np.s_[2::2] 

760 slice(2, None, 2) 

761 >>> np.index_exp[2::2] 

762 (slice(2, None, 2),) 

763 

764 >>> np.array([0, 1, 2, 3, 4])[np.s_[2::2]] 

765 array([2, 4]) 

766 

767 """ 

768 __slots__ = ('maketuple',) 

769 

770 def __init__(self, maketuple): 

771 self.maketuple = maketuple 

772 

773 def __getitem__(self, item): 

774 if self.maketuple and not isinstance(item, tuple): 

775 return (item,) 

776 else: 

777 return item 

778 

779 

780index_exp = IndexExpression(maketuple=True) 

781s_ = IndexExpression(maketuple=False) 

782 

783# End contribution from Konrad. 

784 

785 

786# The following functions complement those in twodim_base, but are 

787# applicable to N-dimensions. 

788 

789 

790def _fill_diagonal_dispatcher(a, val, wrap=None): 

791 return (a,) 

792 

793 

794@array_function_dispatch(_fill_diagonal_dispatcher) 

795def fill_diagonal(a, val, wrap=False): 

796 """Fill the main diagonal of the given array of any dimensionality. 

797 

798 For an array `a` with ``a.ndim >= 2``, the diagonal is the list of 

799 values ``a[i, ..., i]`` with indices ``i`` all identical. This function 

800 modifies the input array in-place without returning a value. 

801 

802 Parameters 

803 ---------- 

804 a : array, at least 2-D. 

805 Array whose diagonal is to be filled in-place. 

806 val : scalar or array_like 

807 Value(s) to write on the diagonal. If `val` is scalar, the value is 

808 written along the diagonal. If array-like, the flattened `val` is 

809 written along the diagonal, repeating if necessary to fill all 

810 diagonal entries. 

811 

812 wrap : bool 

813 For tall matrices in NumPy version up to 1.6.2, the 

814 diagonal "wrapped" after N columns. You can have this behavior 

815 with this option. This affects only tall matrices. 

816 

817 See also 

818 -------- 

819 diag_indices, diag_indices_from 

820 

821 Notes 

822 ----- 

823 This functionality can be obtained via `diag_indices`, but internally 

824 this version uses a much faster implementation that never constructs the 

825 indices and uses simple slicing. 

826 

827 Examples 

828 -------- 

829 >>> import numpy as np 

830 >>> a = np.zeros((3, 3), int) 

831 >>> np.fill_diagonal(a, 5) 

832 >>> a 

833 array([[5, 0, 0], 

834 [0, 5, 0], 

835 [0, 0, 5]]) 

836 

837 The same function can operate on a 4-D array: 

838 

839 >>> a = np.zeros((3, 3, 3, 3), int) 

840 >>> np.fill_diagonal(a, 4) 

841 

842 We only show a few blocks for clarity: 

843 

844 >>> a[0, 0] 

845 array([[4, 0, 0], 

846 [0, 0, 0], 

847 [0, 0, 0]]) 

848 >>> a[1, 1] 

849 array([[0, 0, 0], 

850 [0, 4, 0], 

851 [0, 0, 0]]) 

852 >>> a[2, 2] 

853 array([[0, 0, 0], 

854 [0, 0, 0], 

855 [0, 0, 4]]) 

856 

857 The wrap option affects only tall matrices: 

858 

859 >>> # tall matrices no wrap 

860 >>> a = np.zeros((5, 3), int) 

861 >>> np.fill_diagonal(a, 4) 

862 >>> a 

863 array([[4, 0, 0], 

864 [0, 4, 0], 

865 [0, 0, 4], 

866 [0, 0, 0], 

867 [0, 0, 0]]) 

868 

869 >>> # tall matrices wrap 

870 >>> a = np.zeros((5, 3), int) 

871 >>> np.fill_diagonal(a, 4, wrap=True) 

872 >>> a 

873 array([[4, 0, 0], 

874 [0, 4, 0], 

875 [0, 0, 4], 

876 [0, 0, 0], 

877 [4, 0, 0]]) 

878 

879 >>> # wide matrices 

880 >>> a = np.zeros((3, 5), int) 

881 >>> np.fill_diagonal(a, 4, wrap=True) 

882 >>> a 

883 array([[4, 0, 0, 0, 0], 

884 [0, 4, 0, 0, 0], 

885 [0, 0, 4, 0, 0]]) 

886 

887 The anti-diagonal can be filled by reversing the order of elements 

888 using either `numpy.flipud` or `numpy.fliplr`. 

889 

890 >>> a = np.zeros((3, 3), int); 

891 >>> np.fill_diagonal(np.fliplr(a), [1,2,3]) # Horizontal flip 

892 >>> a 

893 array([[0, 0, 1], 

894 [0, 2, 0], 

895 [3, 0, 0]]) 

896 >>> np.fill_diagonal(np.flipud(a), [1,2,3]) # Vertical flip 

897 >>> a 

898 array([[0, 0, 3], 

899 [0, 2, 0], 

900 [1, 0, 0]]) 

901 

902 Note that the order in which the diagonal is filled varies depending 

903 on the flip function. 

904 """ 

905 if a.ndim < 2: 

906 raise ValueError("array must be at least 2-d") 

907 end = None 

908 if a.ndim == 2: 

909 # Explicit, fast formula for the common case. For 2-d arrays, we 

910 # accept rectangular ones. 

911 step = a.shape[1] + 1 

912 # This is needed to don't have tall matrix have the diagonal wrap. 

913 if not wrap: 

914 end = a.shape[1] * a.shape[1] 

915 else: 

916 # For more than d=2, the strided formula is only valid for arrays with 

917 # all dimensions equal, so we check first. 

918 if not np.all(diff(a.shape) == 0): 

919 raise ValueError("All dimensions of input must be of equal length") 

920 step = 1 + (np.cumprod(a.shape[:-1])).sum() 

921 

922 # Write the value out into the diagonal. 

923 a.flat[:end:step] = val 

924 

925 

926@set_module('numpy') 

927def diag_indices(n, ndim=2): 

928 """ 

929 Return the indices to access the main diagonal of an array. 

930 

931 This returns a tuple of indices that can be used to access the main 

932 diagonal of an array `a` with ``a.ndim >= 2`` dimensions and shape 

933 (n, n, ..., n). For ``a.ndim = 2`` this is the usual diagonal, for 

934 ``a.ndim > 2`` this is the set of indices to access ``a[i, i, ..., i]`` 

935 for ``i = [0..n-1]``. 

936 

937 Parameters 

938 ---------- 

939 n : int 

940 The size, along each dimension, of the arrays for which the returned 

941 indices can be used. 

942 

943 ndim : int, optional 

944 The number of dimensions. 

945 

946 See Also 

947 -------- 

948 diag_indices_from 

949 

950 Examples 

951 -------- 

952 >>> import numpy as np 

953 

954 Create a set of indices to access the diagonal of a (4, 4) array: 

955 

956 >>> di = np.diag_indices(4) 

957 >>> di 

958 (array([0, 1, 2, 3]), array([0, 1, 2, 3])) 

959 >>> a = np.arange(16).reshape(4, 4) 

960 >>> a 

961 array([[ 0, 1, 2, 3], 

962 [ 4, 5, 6, 7], 

963 [ 8, 9, 10, 11], 

964 [12, 13, 14, 15]]) 

965 >>> a[di] = 100 

966 >>> a 

967 array([[100, 1, 2, 3], 

968 [ 4, 100, 6, 7], 

969 [ 8, 9, 100, 11], 

970 [ 12, 13, 14, 100]]) 

971 

972 Now, we create indices to manipulate a 3-D array: 

973 

974 >>> d3 = np.diag_indices(2, 3) 

975 >>> d3 

976 (array([0, 1]), array([0, 1]), array([0, 1])) 

977 

978 And use it to set the diagonal of an array of zeros to 1: 

979 

980 >>> a = np.zeros((2, 2, 2), dtype=int) 

981 >>> a[d3] = 1 

982 >>> a 

983 array([[[1, 0], 

984 [0, 0]], 

985 [[0, 0], 

986 [0, 1]]]) 

987 

988 """ 

989 idx = np.arange(n) 

990 return (idx,) * ndim 

991 

992 

993def _diag_indices_from(arr): 

994 return (arr,) 

995 

996 

997@array_function_dispatch(_diag_indices_from) 

998def diag_indices_from(arr): 

999 """ 

1000 Return the indices to access the main diagonal of an n-dimensional array. 

1001 

1002 See `diag_indices` for full details. 

1003 

1004 Parameters 

1005 ---------- 

1006 arr : array, at least 2-D 

1007 

1008 See Also 

1009 -------- 

1010 diag_indices 

1011 

1012 Examples 

1013 -------- 

1014 >>> import numpy as np 

1015 

1016 Create a 4 by 4 array. 

1017 

1018 >>> a = np.arange(16).reshape(4, 4) 

1019 >>> a 

1020 array([[ 0, 1, 2, 3], 

1021 [ 4, 5, 6, 7], 

1022 [ 8, 9, 10, 11], 

1023 [12, 13, 14, 15]]) 

1024 

1025 Get the indices of the diagonal elements. 

1026 

1027 >>> di = np.diag_indices_from(a) 

1028 >>> di 

1029 (array([0, 1, 2, 3]), array([0, 1, 2, 3])) 

1030 

1031 >>> a[di] 

1032 array([ 0, 5, 10, 15]) 

1033 

1034 This is simply syntactic sugar for diag_indices. 

1035 

1036 >>> np.diag_indices(a.shape[0]) 

1037 (array([0, 1, 2, 3]), array([0, 1, 2, 3])) 

1038 

1039 """ 

1040 

1041 if not arr.ndim >= 2: 

1042 raise ValueError("input array must be at least 2-d") 

1043 # For more than d=2, the strided formula is only valid for arrays with 

1044 # all dimensions equal, so we check first. 

1045 if not np.all(diff(arr.shape) == 0): 

1046 raise ValueError("All dimensions of input must be of equal length") 

1047 

1048 return diag_indices(arr.shape[0], arr.ndim)