test_index_tricks.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. import pytest
  2. import numpy as np
  3. from numpy.lib._index_tricks_impl import (
  4. c_,
  5. diag_indices,
  6. diag_indices_from,
  7. fill_diagonal,
  8. index_exp,
  9. ix_,
  10. mgrid,
  11. ndenumerate,
  12. ndindex,
  13. ogrid,
  14. r_,
  15. s_,
  16. )
  17. from numpy.testing import (
  18. assert_,
  19. assert_almost_equal,
  20. assert_array_almost_equal,
  21. assert_array_equal,
  22. assert_equal,
  23. assert_raises,
  24. assert_raises_regex,
  25. )
  26. class TestRavelUnravelIndex:
  27. def test_basic(self):
  28. assert_equal(np.unravel_index(2, (2, 2)), (1, 0))
  29. # test that new shape argument works properly
  30. assert_equal(np.unravel_index(indices=2,
  31. shape=(2, 2)),
  32. (1, 0))
  33. # test that an invalid second keyword argument
  34. # is properly handled, including the old name `dims`.
  35. with assert_raises(TypeError):
  36. np.unravel_index(indices=2, hape=(2, 2))
  37. with assert_raises(TypeError):
  38. np.unravel_index(2, hape=(2, 2))
  39. with assert_raises(TypeError):
  40. np.unravel_index(254, ims=(17, 94))
  41. with assert_raises(TypeError):
  42. np.unravel_index(254, dims=(17, 94))
  43. assert_equal(np.ravel_multi_index((1, 0), (2, 2)), 2)
  44. assert_equal(np.unravel_index(254, (17, 94)), (2, 66))
  45. assert_equal(np.ravel_multi_index((2, 66), (17, 94)), 254)
  46. assert_raises(ValueError, np.unravel_index, -1, (2, 2))
  47. assert_raises(TypeError, np.unravel_index, 0.5, (2, 2))
  48. assert_raises(ValueError, np.unravel_index, 4, (2, 2))
  49. assert_raises(ValueError, np.ravel_multi_index, (-3, 1), (2, 2))
  50. assert_raises(ValueError, np.ravel_multi_index, (2, 1), (2, 2))
  51. assert_raises(ValueError, np.ravel_multi_index, (0, -3), (2, 2))
  52. assert_raises(ValueError, np.ravel_multi_index, (0, 2), (2, 2))
  53. assert_raises(TypeError, np.ravel_multi_index, (0.1, 0.), (2, 2))
  54. assert_equal(np.unravel_index((2 * 3 + 1) * 6 + 4, (4, 3, 6)), [2, 1, 4])
  55. assert_equal(
  56. np.ravel_multi_index([2, 1, 4], (4, 3, 6)), (2 * 3 + 1) * 6 + 4)
  57. arr = np.array([[3, 6, 6], [4, 5, 1]])
  58. assert_equal(np.ravel_multi_index(arr, (7, 6)), [22, 41, 37])
  59. assert_equal(
  60. np.ravel_multi_index(arr, (7, 6), order='F'), [31, 41, 13])
  61. assert_equal(
  62. np.ravel_multi_index(arr, (4, 6), mode='clip'), [22, 23, 19])
  63. assert_equal(np.ravel_multi_index(arr, (4, 4), mode=('clip', 'wrap')),
  64. [12, 13, 13])
  65. assert_equal(np.ravel_multi_index((3, 1, 4, 1), (6, 7, 8, 9)), 1621)
  66. assert_equal(np.unravel_index(np.array([22, 41, 37]), (7, 6)),
  67. [[3, 6, 6], [4, 5, 1]])
  68. assert_equal(
  69. np.unravel_index(np.array([31, 41, 13]), (7, 6), order='F'),
  70. [[3, 6, 6], [4, 5, 1]])
  71. assert_equal(np.unravel_index(1621, (6, 7, 8, 9)), [3, 1, 4, 1])
  72. def test_empty_indices(self):
  73. msg1 = 'indices must be integral: the provided empty sequence was'
  74. msg2 = 'only int indices permitted'
  75. assert_raises_regex(TypeError, msg1, np.unravel_index, [], (10, 3, 5))
  76. assert_raises_regex(TypeError, msg1, np.unravel_index, (), (10, 3, 5))
  77. assert_raises_regex(TypeError, msg2, np.unravel_index, np.array([]),
  78. (10, 3, 5))
  79. assert_equal(np.unravel_index(np.array([], dtype=int), (10, 3, 5)),
  80. [[], [], []])
  81. assert_raises_regex(TypeError, msg1, np.ravel_multi_index, ([], []),
  82. (10, 3))
  83. assert_raises_regex(TypeError, msg1, np.ravel_multi_index, ([], ['abc']),
  84. (10, 3))
  85. assert_raises_regex(TypeError, msg2, np.ravel_multi_index,
  86. (np.array([]), np.array([])), (5, 3))
  87. assert_equal(np.ravel_multi_index(
  88. (np.array([], dtype=int), np.array([], dtype=int)), (5, 3)), [])
  89. assert_equal(np.ravel_multi_index(np.array([[], []], dtype=int),
  90. (5, 3)), [])
  91. def test_big_indices(self):
  92. # ravel_multi_index for big indices (issue #7546)
  93. if np.intp == np.int64:
  94. arr = ([1, 29], [3, 5], [3, 117], [19, 2],
  95. [2379, 1284], [2, 2], [0, 1])
  96. assert_equal(
  97. np.ravel_multi_index(arr, (41, 7, 120, 36, 2706, 8, 6)),
  98. [5627771580, 117259570957])
  99. # test unravel_index for big indices (issue #9538)
  100. assert_raises(ValueError, np.unravel_index, 1, (2**32 - 1, 2**31 + 1))
  101. # test overflow checking for too big array (issue #7546)
  102. dummy_arr = ([0], [0])
  103. half_max = np.iinfo(np.intp).max // 2
  104. assert_equal(
  105. np.ravel_multi_index(dummy_arr, (half_max, 2)), [0])
  106. assert_raises(ValueError,
  107. np.ravel_multi_index, dummy_arr, (half_max + 1, 2))
  108. assert_equal(
  109. np.ravel_multi_index(dummy_arr, (half_max, 2), order='F'), [0])
  110. assert_raises(ValueError,
  111. np.ravel_multi_index, dummy_arr, (half_max + 1, 2), order='F')
  112. def test_dtypes(self):
  113. # Test with different data types
  114. for dtype in [np.int16, np.uint16, np.int32,
  115. np.uint32, np.int64, np.uint64]:
  116. coords = np.array(
  117. [[1, 0, 1, 2, 3, 4], [1, 6, 1, 3, 2, 0]], dtype=dtype)
  118. shape = (5, 8)
  119. uncoords = 8 * coords[0] + coords[1]
  120. assert_equal(np.ravel_multi_index(coords, shape), uncoords)
  121. assert_equal(coords, np.unravel_index(uncoords, shape))
  122. uncoords = coords[0] + 5 * coords[1]
  123. assert_equal(
  124. np.ravel_multi_index(coords, shape, order='F'), uncoords)
  125. assert_equal(coords, np.unravel_index(uncoords, shape, order='F'))
  126. coords = np.array(
  127. [[1, 0, 1, 2, 3, 4], [1, 6, 1, 3, 2, 0], [1, 3, 1, 0, 9, 5]],
  128. dtype=dtype)
  129. shape = (5, 8, 10)
  130. uncoords = 10 * (8 * coords[0] + coords[1]) + coords[2]
  131. assert_equal(np.ravel_multi_index(coords, shape), uncoords)
  132. assert_equal(coords, np.unravel_index(uncoords, shape))
  133. uncoords = coords[0] + 5 * (coords[1] + 8 * coords[2])
  134. assert_equal(
  135. np.ravel_multi_index(coords, shape, order='F'), uncoords)
  136. assert_equal(coords, np.unravel_index(uncoords, shape, order='F'))
  137. def test_clipmodes(self):
  138. # Test clipmodes
  139. assert_equal(
  140. np.ravel_multi_index([5, 1, -1, 2], (4, 3, 7, 12), mode='wrap'),
  141. np.ravel_multi_index([1, 1, 6, 2], (4, 3, 7, 12)))
  142. assert_equal(np.ravel_multi_index([5, 1, -1, 2], (4, 3, 7, 12),
  143. mode=(
  144. 'wrap', 'raise', 'clip', 'raise')),
  145. np.ravel_multi_index([1, 1, 0, 2], (4, 3, 7, 12)))
  146. assert_raises(
  147. ValueError, np.ravel_multi_index, [5, 1, -1, 2], (4, 3, 7, 12))
  148. def test_writeability(self):
  149. # gh-7269
  150. x, y = np.unravel_index([1, 2, 3], (4, 5))
  151. assert_(x.flags.writeable)
  152. assert_(y.flags.writeable)
  153. def test_0d(self):
  154. # gh-580
  155. x = np.unravel_index(0, ())
  156. assert_equal(x, ())
  157. assert_raises_regex(ValueError, "0d array", np.unravel_index, [0], ())
  158. assert_raises_regex(
  159. ValueError, "out of bounds", np.unravel_index, [1], ())
  160. @pytest.mark.parametrize("mode", ["clip", "wrap", "raise"])
  161. def test_empty_array_ravel(self, mode):
  162. res = np.ravel_multi_index(
  163. np.zeros((3, 0), dtype=np.intp), (2, 1, 0), mode=mode)
  164. assert res.shape == (0,)
  165. with assert_raises(ValueError):
  166. np.ravel_multi_index(
  167. np.zeros((3, 1), dtype=np.intp), (2, 1, 0), mode=mode)
  168. def test_empty_array_unravel(self):
  169. res = np.unravel_index(np.zeros(0, dtype=np.intp), (2, 1, 0))
  170. # res is a tuple of three empty arrays
  171. assert len(res) == 3
  172. assert all(a.shape == (0,) for a in res)
  173. with assert_raises(ValueError):
  174. np.unravel_index([1], (2, 1, 0))
  175. def test_regression_size_1_index(self):
  176. # actually tests the nditer size one index tracking
  177. # regression test for gh-29690
  178. np.unravel_index(np.array([[1, 0, 1, 0]], dtype=np.uint32), (4,))
  179. class TestGrid:
  180. def test_basic(self):
  181. a = mgrid[-1:1:10j]
  182. b = mgrid[-1:1:0.1]
  183. assert_(a.shape == (10,))
  184. assert_(b.shape == (20,))
  185. assert_(a[0] == -1)
  186. assert_almost_equal(a[-1], 1)
  187. assert_(b[0] == -1)
  188. assert_almost_equal(b[1] - b[0], 0.1, 11)
  189. assert_almost_equal(b[-1], b[0] + 19 * 0.1, 11)
  190. assert_almost_equal(a[1] - a[0], 2.0 / 9.0, 11)
  191. def test_linspace_equivalence(self):
  192. y, st = np.linspace(2, 10, retstep=True)
  193. assert_almost_equal(st, 8 / 49.0)
  194. assert_array_almost_equal(y, mgrid[2:10:50j], 13)
  195. def test_nd(self):
  196. c = mgrid[-1:1:10j, -2:2:10j]
  197. d = mgrid[-1:1:0.1, -2:2:0.2]
  198. assert_(c.shape == (2, 10, 10))
  199. assert_(d.shape == (2, 20, 20))
  200. assert_array_equal(c[0][0, :], -np.ones(10, 'd'))
  201. assert_array_equal(c[1][:, 0], -2 * np.ones(10, 'd'))
  202. assert_array_almost_equal(c[0][-1, :], np.ones(10, 'd'), 11)
  203. assert_array_almost_equal(c[1][:, -1], 2 * np.ones(10, 'd'), 11)
  204. assert_array_almost_equal(d[0, 1, :] - d[0, 0, :],
  205. 0.1 * np.ones(20, 'd'), 11)
  206. assert_array_almost_equal(d[1, :, 1] - d[1, :, 0],
  207. 0.2 * np.ones(20, 'd'), 11)
  208. def test_sparse(self):
  209. grid_full = mgrid[-1:1:10j, -2:2:10j]
  210. grid_sparse = ogrid[-1:1:10j, -2:2:10j]
  211. # sparse grids can be made dense by broadcasting
  212. grid_broadcast = np.broadcast_arrays(*grid_sparse)
  213. for f, b in zip(grid_full, grid_broadcast):
  214. assert_equal(f, b)
  215. @pytest.mark.parametrize("start, stop, step, expected", [
  216. (None, 10, 10j, (200, 10)),
  217. (-10, 20, None, (1800, 30)),
  218. ])
  219. def test_mgrid_size_none_handling(self, start, stop, step, expected):
  220. # regression test None value handling for
  221. # start and step values used by mgrid;
  222. # internally, this aims to cover previously
  223. # unexplored code paths in nd_grid()
  224. grid = mgrid[start:stop:step, start:stop:step]
  225. # need a smaller grid to explore one of the
  226. # untested code paths
  227. grid_small = mgrid[start:stop:step]
  228. assert_equal(grid.size, expected[0])
  229. assert_equal(grid_small.size, expected[1])
  230. def test_accepts_npfloating(self):
  231. # regression test for #16466
  232. grid64 = mgrid[0.1:0.33:0.1, ]
  233. grid32 = mgrid[np.float32(0.1):np.float32(0.33):np.float32(0.1), ]
  234. assert_array_almost_equal(grid64, grid32)
  235. # At some point this was float64, but NEP 50 changed it:
  236. assert grid32.dtype == np.float32
  237. assert grid64.dtype == np.float64
  238. # different code path for single slice
  239. grid64 = mgrid[0.1:0.33:0.1]
  240. grid32 = mgrid[np.float32(0.1):np.float32(0.33):np.float32(0.1)]
  241. assert_(grid32.dtype == np.float64)
  242. assert_array_almost_equal(grid64, grid32)
  243. def test_accepts_longdouble(self):
  244. # regression tests for #16945
  245. grid64 = mgrid[0.1:0.33:0.1, ]
  246. grid128 = mgrid[
  247. np.longdouble(0.1):np.longdouble(0.33):np.longdouble(0.1),
  248. ]
  249. assert_(grid128.dtype == np.longdouble)
  250. assert_array_almost_equal(grid64, grid128)
  251. grid128c_a = mgrid[0:np.longdouble(1):3.4j]
  252. grid128c_b = mgrid[0:np.longdouble(1):3.4j, ]
  253. assert_(grid128c_a.dtype == grid128c_b.dtype == np.longdouble)
  254. assert_array_equal(grid128c_a, grid128c_b[0])
  255. # different code path for single slice
  256. grid64 = mgrid[0.1:0.33:0.1]
  257. grid128 = mgrid[
  258. np.longdouble(0.1):np.longdouble(0.33):np.longdouble(0.1)
  259. ]
  260. assert_(grid128.dtype == np.longdouble)
  261. assert_array_almost_equal(grid64, grid128)
  262. def test_accepts_npcomplexfloating(self):
  263. # Related to #16466
  264. assert_array_almost_equal(
  265. mgrid[0.1:0.3:3j, ], mgrid[0.1:0.3:np.complex64(3j), ]
  266. )
  267. # different code path for single slice
  268. assert_array_almost_equal(
  269. mgrid[0.1:0.3:3j], mgrid[0.1:0.3:np.complex64(3j)]
  270. )
  271. # Related to #16945
  272. grid64_a = mgrid[0.1:0.3:3.3j]
  273. grid64_b = mgrid[0.1:0.3:3.3j, ][0]
  274. assert_(grid64_a.dtype == grid64_b.dtype == np.float64)
  275. assert_array_equal(grid64_a, grid64_b)
  276. grid128_a = mgrid[0.1:0.3:np.clongdouble(3.3j)]
  277. grid128_b = mgrid[0.1:0.3:np.clongdouble(3.3j), ][0]
  278. assert_(grid128_a.dtype == grid128_b.dtype == np.longdouble)
  279. assert_array_equal(grid64_a, grid64_b)
  280. class TestConcatenator:
  281. def test_1d(self):
  282. assert_array_equal(r_[1, 2, 3, 4, 5, 6], np.array([1, 2, 3, 4, 5, 6]))
  283. b = np.ones(5)
  284. c = r_[b, 0, 0, b]
  285. assert_array_equal(c, [1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1])
  286. def test_mixed_type(self):
  287. g = r_[10.1, 1:10]
  288. assert_(g.dtype == 'f8')
  289. def test_more_mixed_type(self):
  290. g = r_[-10.1, np.array([1]), np.array([2, 3, 4]), 10.0]
  291. assert_(g.dtype == 'f8')
  292. def test_complex_step(self):
  293. # Regression test for #12262
  294. g = r_[0:36:100j]
  295. assert_(g.shape == (100,))
  296. # Related to #16466
  297. g = r_[0:36:np.complex64(100j)]
  298. assert_(g.shape == (100,))
  299. def test_2d(self):
  300. b = np.random.rand(5, 5)
  301. c = np.random.rand(5, 5)
  302. d = r_['1', b, c] # append columns
  303. assert_(d.shape == (5, 10))
  304. assert_array_equal(d[:, :5], b)
  305. assert_array_equal(d[:, 5:], c)
  306. d = r_[b, c]
  307. assert_(d.shape == (10, 5))
  308. assert_array_equal(d[:5, :], b)
  309. assert_array_equal(d[5:, :], c)
  310. def test_0d(self):
  311. assert_equal(r_[0, np.array(1), 2], [0, 1, 2])
  312. assert_equal(r_[[0, 1, 2], np.array(3)], [0, 1, 2, 3])
  313. assert_equal(r_[np.array(0), [1, 2, 3]], [0, 1, 2, 3])
  314. class TestNdenumerate:
  315. def test_basic(self):
  316. a = np.array([[1, 2], [3, 4]])
  317. assert_equal(list(ndenumerate(a)),
  318. [((0, 0), 1), ((0, 1), 2), ((1, 0), 3), ((1, 1), 4)])
  319. class TestIndexExpression:
  320. def test_regression_1(self):
  321. # ticket #1196
  322. a = np.arange(2)
  323. assert_equal(a[:-1], a[s_[:-1]])
  324. assert_equal(a[:-1], a[index_exp[:-1]])
  325. def test_simple_1(self):
  326. a = np.random.rand(4, 5, 6)
  327. assert_equal(a[:, :3, [1, 2]], a[index_exp[:, :3, [1, 2]]])
  328. assert_equal(a[:, :3, [1, 2]], a[s_[:, :3, [1, 2]]])
  329. class TestIx_:
  330. def test_regression_1(self):
  331. # Test empty untyped inputs create outputs of indexing type, gh-5804
  332. a, = np.ix_(range(0))
  333. assert_equal(a.dtype, np.intp)
  334. a, = np.ix_([])
  335. assert_equal(a.dtype, np.intp)
  336. # but if the type is specified, don't change it
  337. a, = np.ix_(np.array([], dtype=np.float32))
  338. assert_equal(a.dtype, np.float32)
  339. def test_shape_and_dtype(self):
  340. sizes = (4, 5, 3, 2)
  341. # Test both lists and arrays
  342. for func in (range, np.arange):
  343. arrays = np.ix_(*[func(sz) for sz in sizes])
  344. for k, (a, sz) in enumerate(zip(arrays, sizes)):
  345. assert_equal(a.shape[k], sz)
  346. assert_(all(sh == 1 for j, sh in enumerate(a.shape) if j != k))
  347. assert_(np.issubdtype(a.dtype, np.integer))
  348. def test_bool(self):
  349. bool_a = [True, False, True, True]
  350. int_a, = np.nonzero(bool_a)
  351. assert_equal(np.ix_(bool_a)[0], int_a)
  352. def test_1d_only(self):
  353. idx2d = [[1, 2, 3], [4, 5, 6]]
  354. assert_raises(ValueError, np.ix_, idx2d)
  355. def test_repeated_input(self):
  356. length_of_vector = 5
  357. x = np.arange(length_of_vector)
  358. out = ix_(x, x)
  359. assert_equal(out[0].shape, (length_of_vector, 1))
  360. assert_equal(out[1].shape, (1, length_of_vector))
  361. # check that input shape is not modified
  362. assert_equal(x.shape, (length_of_vector,))
  363. def test_c_():
  364. a = c_[np.array([[1, 2, 3]]), 0, 0, np.array([[4, 5, 6]])]
  365. assert_equal(a, [[1, 2, 3, 0, 0, 4, 5, 6]])
  366. class TestFillDiagonal:
  367. def test_basic(self):
  368. a = np.zeros((3, 3), int)
  369. fill_diagonal(a, 5)
  370. assert_array_equal(
  371. a, np.array([[5, 0, 0],
  372. [0, 5, 0],
  373. [0, 0, 5]])
  374. )
  375. def test_tall_matrix(self):
  376. a = np.zeros((10, 3), int)
  377. fill_diagonal(a, 5)
  378. assert_array_equal(
  379. a, np.array([[5, 0, 0],
  380. [0, 5, 0],
  381. [0, 0, 5],
  382. [0, 0, 0],
  383. [0, 0, 0],
  384. [0, 0, 0],
  385. [0, 0, 0],
  386. [0, 0, 0],
  387. [0, 0, 0],
  388. [0, 0, 0]])
  389. )
  390. def test_tall_matrix_wrap(self):
  391. a = np.zeros((10, 3), int)
  392. fill_diagonal(a, 5, True)
  393. assert_array_equal(
  394. a, np.array([[5, 0, 0],
  395. [0, 5, 0],
  396. [0, 0, 5],
  397. [0, 0, 0],
  398. [5, 0, 0],
  399. [0, 5, 0],
  400. [0, 0, 5],
  401. [0, 0, 0],
  402. [5, 0, 0],
  403. [0, 5, 0]])
  404. )
  405. def test_wide_matrix(self):
  406. a = np.zeros((3, 10), int)
  407. fill_diagonal(a, 5)
  408. assert_array_equal(
  409. a, np.array([[5, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  410. [0, 5, 0, 0, 0, 0, 0, 0, 0, 0],
  411. [0, 0, 5, 0, 0, 0, 0, 0, 0, 0]])
  412. )
  413. def test_operate_4d_array(self):
  414. a = np.zeros((3, 3, 3, 3), int)
  415. fill_diagonal(a, 4)
  416. i = np.array([0, 1, 2])
  417. assert_equal(np.where(a != 0), (i, i, i, i))
  418. def test_low_dim_handling(self):
  419. # raise error with low dimensionality
  420. a = np.zeros(3, int)
  421. with assert_raises_regex(ValueError, "at least 2-d"):
  422. fill_diagonal(a, 5)
  423. def test_hetero_shape_handling(self):
  424. # raise error with high dimensionality and
  425. # shape mismatch
  426. a = np.zeros((3, 3, 7, 3), int)
  427. with assert_raises_regex(ValueError, "equal length"):
  428. fill_diagonal(a, 2)
  429. def test_diag_indices():
  430. di = diag_indices(4)
  431. a = np.array([[1, 2, 3, 4],
  432. [5, 6, 7, 8],
  433. [9, 10, 11, 12],
  434. [13, 14, 15, 16]])
  435. a[di] = 100
  436. assert_array_equal(
  437. a, np.array([[100, 2, 3, 4],
  438. [5, 100, 7, 8],
  439. [9, 10, 100, 12],
  440. [13, 14, 15, 100]])
  441. )
  442. # Now, we create indices to manipulate a 3-d array:
  443. d3 = diag_indices(2, 3)
  444. # And use it to set the diagonal of a zeros array to 1:
  445. a = np.zeros((2, 2, 2), int)
  446. a[d3] = 1
  447. assert_array_equal(
  448. a, np.array([[[1, 0],
  449. [0, 0]],
  450. [[0, 0],
  451. [0, 1]]])
  452. )
  453. class TestDiagIndicesFrom:
  454. def test_diag_indices_from(self):
  455. x = np.random.random((4, 4))
  456. r, c = diag_indices_from(x)
  457. assert_array_equal(r, np.arange(4))
  458. assert_array_equal(c, np.arange(4))
  459. def test_error_small_input(self):
  460. x = np.ones(7)
  461. with assert_raises_regex(ValueError, "at least 2-d"):
  462. diag_indices_from(x)
  463. def test_error_shape_mismatch(self):
  464. x = np.zeros((3, 3, 2, 3), int)
  465. with assert_raises_regex(ValueError, "equal length"):
  466. diag_indices_from(x)
  467. def test_ndindex():
  468. x = list(ndindex(1, 2, 3))
  469. expected = [ix for ix, e in ndenumerate(np.zeros((1, 2, 3)))]
  470. assert_array_equal(x, expected)
  471. x = list(ndindex((1, 2, 3)))
  472. assert_array_equal(x, expected)
  473. # Test use of scalars and tuples
  474. x = list(ndindex((3,)))
  475. assert_array_equal(x, list(ndindex(3)))
  476. # Make sure size argument is optional
  477. x = list(ndindex())
  478. assert_equal(x, [()])
  479. x = list(ndindex(()))
  480. assert_equal(x, [()])
  481. # Make sure 0-sized ndindex works correctly
  482. x = list(ndindex(*[0]))
  483. assert_equal(x, [])
  484. def test_ndindex_zero_dimensions_explicit():
  485. """Test ndindex produces empty iterators for explicit
  486. zero-length dimensions."""
  487. assert list(np.ndindex(0, 3)) == []
  488. assert list(np.ndindex(3, 0, 2)) == []
  489. assert list(np.ndindex(0)) == []
  490. @pytest.mark.parametrize("bad_shape", [2.5, "2", [2, 3], (2.0, 3)])
  491. def test_ndindex_non_integer_dimensions(bad_shape):
  492. """Test that non-integer dimensions raise TypeError."""
  493. with pytest.raises(TypeError):
  494. # Passing invalid_shape_arg directly to ndindex. It will try to use it
  495. # as a dimension and should trigger a TypeError.
  496. list(np.ndindex(bad_shape))
  497. def test_ndindex_stop_iteration_behavior():
  498. """Test that StopIteration is raised properly after exhaustion."""
  499. it = np.ndindex(2, 2)
  500. # Exhaust the iterator
  501. list(it)
  502. # Should raise StopIteration on subsequent calls
  503. with pytest.raises(StopIteration):
  504. next(it)
  505. def test_ndindex_iterator_independence():
  506. """Test that each ndindex instance creates independent iterators."""
  507. shape = (2, 3)
  508. iter1 = np.ndindex(*shape)
  509. iter2 = np.ndindex(*shape)
  510. next(iter1)
  511. next(iter1)
  512. assert_equal(next(iter2), (0, 0))
  513. assert_equal(next(iter1), (0, 2))
  514. def test_ndindex_tuple_vs_args_consistency():
  515. """Test that ndindex(shape) and ndindex(*shape) produce same results."""
  516. # Single dimension
  517. assert_equal(list(np.ndindex(5)), list(np.ndindex((5,))))
  518. # Multiple dimensions
  519. assert_equal(list(np.ndindex(2, 3)), list(np.ndindex((2, 3))))
  520. # Complex shape
  521. shape = (2, 1, 4)
  522. assert_equal(list(np.ndindex(*shape)), list(np.ndindex(shape)))
  523. def test_ndindex_against_ndenumerate_compatibility():
  524. """Test ndindex produces same indices as ndenumerate."""
  525. for shape in [(1, 2, 3), (3,), (2, 2), ()]:
  526. ndindex_result = list(np.ndindex(shape))
  527. ndenumerate_indices = [ix for ix, _ in np.ndenumerate(np.zeros(shape))]
  528. assert_array_equal(ndindex_result, ndenumerate_indices)
  529. def test_ndindex_multidimensional_correctness():
  530. """Test ndindex produces correct indices for multidimensional arrays."""
  531. shape = (2, 1, 3)
  532. result = list(np.ndindex(*shape))
  533. expected = [
  534. (0, 0, 0),
  535. (0, 0, 1),
  536. (0, 0, 2),
  537. (1, 0, 0),
  538. (1, 0, 1),
  539. (1, 0, 2),
  540. ]
  541. assert_equal(result, expected)
  542. def test_ndindex_large_dimensions_behavior():
  543. """Test ndindex behaves correctly when initialized with large dimensions."""
  544. large_shape = (1000, 1000)
  545. iter_obj = np.ndindex(*large_shape)
  546. first_element = next(iter_obj)
  547. assert_equal(first_element, (0, 0))
  548. def test_ndindex_empty_iterator_behavior():
  549. """Test detailed behavior of empty iterators."""
  550. empty_iter = np.ndindex(0, 5)
  551. assert_equal(list(empty_iter), [])
  552. empty_iter2 = np.ndindex(3, 0, 2)
  553. with pytest.raises(StopIteration):
  554. next(empty_iter2)
  555. @pytest.mark.parametrize(
  556. "negative_shape_arg",
  557. [
  558. (-1,), # Single negative dimension
  559. (2, -3, 4), # Negative dimension in the middle
  560. (5, 0, -2), # Mix of valid (0) and invalid (negative) dimensions
  561. ],
  562. )
  563. def test_ndindex_negative_dimensions(negative_shape_arg):
  564. """Test that negative dimensions raise ValueError."""
  565. with pytest.raises(ValueError):
  566. ndindex(negative_shape_arg)
  567. def test_ndindex_empty_shape():
  568. import numpy as np
  569. # ndindex() and ndindex(()) should return a single empty tuple
  570. assert list(np.ndindex()) == [()]
  571. assert list(np.ndindex(())) == [()]
  572. def test_ndindex_negative_dim_raises():
  573. # ndindex(-1) should raise a ValueError
  574. with pytest.raises(ValueError):
  575. list(np.ndindex(-1))