test_interpolation.py 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499
  1. import sys
  2. import warnings
  3. import numpy as np
  4. from scipy._lib._array_api import (
  5. _asarray, assert_array_almost_equal,
  6. is_jax, np_compat,
  7. xp_assert_equal, xp_assert_close,
  8. make_xp_test_case,
  9. )
  10. import pytest
  11. from pytest import raises as assert_raises
  12. import scipy.ndimage as ndimage
  13. from . import types
  14. skip_xp_backends = pytest.mark.skip_xp_backends
  15. xfail_xp_backends = pytest.mark.xfail_xp_backends
  16. # lazy_xp_modules = [ndimage]
  17. eps = 1e-12
  18. ndimage_to_numpy_mode = {
  19. 'mirror': 'reflect',
  20. 'reflect': 'symmetric',
  21. 'grid-mirror': 'symmetric',
  22. 'grid-wrap': 'wrap',
  23. 'nearest': 'edge',
  24. 'grid-constant': 'constant',
  25. }
  26. class TestBoundaries:
  27. @make_xp_test_case(ndimage.geometric_transform)
  28. @pytest.mark.parametrize(
  29. 'mode, expected_value',
  30. [('nearest', [1.5, 2.5, 3.5, 4, 4, 4, 4]),
  31. ('wrap', [1.5, 2.5, 3.5, 1.5, 2.5, 3.5, 1.5]),
  32. ('grid-wrap', [1.5, 2.5, 3.5, 2.5, 1.5, 2.5, 3.5]),
  33. ('mirror', [1.5, 2.5, 3.5, 3.5, 2.5, 1.5, 1.5]),
  34. ('reflect', [1.5, 2.5, 3.5, 4, 3.5, 2.5, 1.5]),
  35. ('constant', [1.5, 2.5, 3.5, -1, -1, -1, -1]),
  36. ('grid-constant', [1.5, 2.5, 3.5, 1.5, -1, -1, -1])]
  37. )
  38. def test_boundaries(self, mode, expected_value, xp):
  39. def shift(x):
  40. return (x[0] + 0.5,)
  41. data = xp.asarray([1, 2, 3, 4.])
  42. xp_assert_equal(
  43. ndimage.geometric_transform(data, shift, cval=-1, mode=mode,
  44. output_shape=(7,), order=1),
  45. xp.asarray(expected_value))
  46. @make_xp_test_case(ndimage.geometric_transform)
  47. @pytest.mark.parametrize(
  48. 'mode, expected_value',
  49. [('nearest', [1, 1, 2, 3]),
  50. ('wrap', [3, 1, 2, 3]),
  51. ('grid-wrap', [4, 1, 2, 3]),
  52. ('mirror', [2, 1, 2, 3]),
  53. ('reflect', [1, 1, 2, 3]),
  54. ('constant', [-1, 1, 2, 3]),
  55. ('grid-constant', [-1, 1, 2, 3])]
  56. )
  57. def test_boundaries2(self, mode, expected_value, xp):
  58. def shift(x):
  59. return (x[0] - 0.9,)
  60. data = xp.asarray([1, 2, 3, 4])
  61. xp_assert_equal(
  62. ndimage.geometric_transform(data, shift, cval=-1, mode=mode,
  63. output_shape=(4,)),
  64. xp.asarray(expected_value))
  65. @make_xp_test_case(ndimage.map_coordinates)
  66. @pytest.mark.parametrize('mode', ['mirror', 'reflect', 'grid-mirror',
  67. 'grid-wrap', 'grid-constant',
  68. 'nearest'])
  69. @pytest.mark.parametrize('order', range(6))
  70. def test_boundary_spline_accuracy(self, mode, order, xp):
  71. """Tests based on examples from gh-2640"""
  72. if (is_jax(xp) and
  73. (mode not in ['mirror', 'reflect', 'constant', 'wrap', 'nearest']
  74. or order > 1)
  75. ):
  76. pytest.xfail("Jax does not support grid- modes or order > 1")
  77. np_data = np.arange(-6, 7, dtype=np.float64)
  78. data = xp.asarray(np_data)
  79. x = xp.asarray(np.linspace(-8, 15, num=1000))
  80. y = ndimage.map_coordinates(data, x[xp.newaxis, ...], order=order, mode=mode)
  81. # compute expected value using explicit padding via np.pad
  82. npad = 32
  83. pad_mode = ndimage_to_numpy_mode.get(mode)
  84. padded = xp.asarray(np.pad(np_data, npad, mode=pad_mode))
  85. coords = xp.asarray(npad + x)[xp.newaxis, ...]
  86. expected = ndimage.map_coordinates(padded, coords, order=order, mode=mode)
  87. atol = 1e-5 if mode == 'grid-constant' else 1e-12
  88. xp_assert_close(y, expected, rtol=1e-7, atol=atol)
  89. @make_xp_test_case(ndimage.spline_filter)
  90. @pytest.mark.parametrize('order', range(2, 6))
  91. @pytest.mark.parametrize('dtype', types)
  92. class TestSpline:
  93. def test_spline01(self, dtype, order, xp):
  94. dtype = getattr(xp, dtype)
  95. data = xp.ones([], dtype=dtype)
  96. out = ndimage.spline_filter(data, order=order)
  97. assert out == xp.asarray(1, dtype=out.dtype)
  98. def test_spline02(self, dtype, order, xp):
  99. dtype = getattr(xp, dtype)
  100. data = xp.asarray([1], dtype=dtype)
  101. out = ndimage.spline_filter(data, order=order)
  102. assert_array_almost_equal(out, xp.asarray([1]))
  103. @skip_xp_backends(np_only=True, exceptions=["cupy"],
  104. reason='output=dtype is numpy-specific')
  105. def test_spline03(self, dtype, order, xp):
  106. dtype = getattr(xp, dtype)
  107. data = xp.ones([], dtype=dtype)
  108. out = ndimage.spline_filter(data, order, output=dtype)
  109. assert out == xp.asarray(1, dtype=out.dtype)
  110. def test_spline04(self, dtype, order, xp):
  111. dtype = getattr(xp, dtype)
  112. data = xp.ones([4], dtype=dtype)
  113. out = ndimage.spline_filter(data, order)
  114. assert_array_almost_equal(out, xp.asarray([1, 1, 1, 1]))
  115. def test_spline05(self, dtype, order, xp):
  116. dtype = getattr(xp, dtype)
  117. data = xp.ones([4, 4], dtype=dtype)
  118. out = ndimage.spline_filter(data, order=order)
  119. expected = xp.asarray([[1, 1, 1, 1],
  120. [1, 1, 1, 1],
  121. [1, 1, 1, 1],
  122. [1, 1, 1, 1]])
  123. assert_array_almost_equal(out, expected)
  124. @make_xp_test_case(ndimage.geometric_transform)
  125. @pytest.mark.parametrize('order', range(0, 6))
  126. class TestGeometricTransform:
  127. def test_geometric_transform01(self, order, xp):
  128. data = xp.asarray([1])
  129. def mapping(x):
  130. return x
  131. out = ndimage.geometric_transform(data, mapping, data.shape,
  132. order=order)
  133. assert_array_almost_equal(out, xp.asarray([1], dtype=out.dtype))
  134. def test_geometric_transform02(self, order, xp):
  135. data = xp.ones([4])
  136. def mapping(x):
  137. return x
  138. out = ndimage.geometric_transform(data, mapping, data.shape,
  139. order=order)
  140. assert_array_almost_equal(out, xp.asarray([1, 1, 1, 1], dtype=out.dtype))
  141. def test_geometric_transform03(self, order, xp):
  142. data = xp.ones([4])
  143. def mapping(x):
  144. return (x[0] - 1,)
  145. out = ndimage.geometric_transform(data, mapping, data.shape,
  146. order=order)
  147. assert_array_almost_equal(out, xp.asarray([0, 1, 1, 1], dtype=out.dtype))
  148. def test_geometric_transform04(self, order, xp):
  149. data = xp.asarray([4, 1, 3, 2])
  150. def mapping(x):
  151. return (x[0] - 1,)
  152. out = ndimage.geometric_transform(data, mapping, data.shape,
  153. order=order)
  154. assert_array_almost_equal(out, xp.asarray([0, 4, 1, 3], dtype=out.dtype))
  155. @pytest.mark.parametrize('dtype', ["float64", "complex128"])
  156. def test_geometric_transform05(self, order, dtype, xp):
  157. dtype = getattr(xp, dtype)
  158. data = xp.asarray([[1, 1, 1, 1],
  159. [1, 1, 1, 1],
  160. [1, 1, 1, 1]], dtype=dtype)
  161. expected = xp.asarray([[0, 1, 1, 1],
  162. [0, 1, 1, 1],
  163. [0, 1, 1, 1]], dtype=dtype)
  164. if xp.isdtype(data.dtype, 'complex floating'):
  165. data -= 1j * data
  166. expected -= 1j * expected
  167. def mapping(x):
  168. return (x[0], x[1] - 1)
  169. out = ndimage.geometric_transform(data, mapping, data.shape,
  170. order=order)
  171. assert_array_almost_equal(out, expected)
  172. def test_geometric_transform06(self, order, xp):
  173. data = xp.asarray([[4, 1, 3, 2],
  174. [7, 6, 8, 5],
  175. [3, 5, 3, 6]])
  176. def mapping(x):
  177. return (x[0], x[1] - 1)
  178. out = ndimage.geometric_transform(data, mapping, data.shape,
  179. order=order)
  180. expected = xp.asarray([[0, 4, 1, 3],
  181. [0, 7, 6, 8],
  182. [0, 3, 5, 3]], dtype=out.dtype)
  183. assert_array_almost_equal(out, expected)
  184. def test_geometric_transform07(self, order, xp):
  185. data = xp.asarray([[4, 1, 3, 2],
  186. [7, 6, 8, 5],
  187. [3, 5, 3, 6]])
  188. def mapping(x):
  189. return (x[0] - 1, x[1])
  190. out = ndimage.geometric_transform(data, mapping, data.shape,
  191. order=order)
  192. expected = xp.asarray([[0, 0, 0, 0],
  193. [4, 1, 3, 2],
  194. [7, 6, 8, 5]], dtype=out.dtype)
  195. assert_array_almost_equal(out, expected)
  196. def test_geometric_transform08(self, order, xp):
  197. data = xp.asarray([[4, 1, 3, 2],
  198. [7, 6, 8, 5],
  199. [3, 5, 3, 6]])
  200. def mapping(x):
  201. return (x[0] - 1, x[1] - 1)
  202. out = ndimage.geometric_transform(data, mapping, data.shape,
  203. order=order)
  204. expected = xp.asarray([[0, 0, 0, 0],
  205. [0, 4, 1, 3],
  206. [0, 7, 6, 8]], dtype=out.dtype)
  207. assert_array_almost_equal(out, expected)
  208. def test_geometric_transform10(self, order, xp):
  209. data = xp.asarray([[4, 1, 3, 2],
  210. [7, 6, 8, 5],
  211. [3, 5, 3, 6]])
  212. def mapping(x):
  213. return (x[0] - 1, x[1] - 1)
  214. if (order > 1):
  215. filtered = ndimage.spline_filter(data, order=order)
  216. else:
  217. filtered = data
  218. out = ndimage.geometric_transform(filtered, mapping, data.shape,
  219. order=order, prefilter=False)
  220. expected = xp.asarray([[0, 0, 0, 0],
  221. [0, 4, 1, 3],
  222. [0, 7, 6, 8]], dtype=out.dtype)
  223. assert_array_almost_equal(out, expected)
  224. def test_geometric_transform13(self, order, xp):
  225. data = xp.ones([2], dtype=xp.float64)
  226. def mapping(x):
  227. return (x[0] // 2,)
  228. out = ndimage.geometric_transform(data, mapping, [4], order=order)
  229. assert_array_almost_equal(out, xp.asarray([1, 1, 1, 1], dtype=out.dtype))
  230. def test_geometric_transform14(self, order, xp):
  231. data = xp.asarray([1, 5, 2, 6, 3, 7, 4, 4])
  232. def mapping(x):
  233. return (2 * x[0],)
  234. out = ndimage.geometric_transform(data, mapping, [4], order=order)
  235. assert_array_almost_equal(out, xp.asarray([1, 2, 3, 4], dtype=out.dtype))
  236. def test_geometric_transform15(self, order, xp):
  237. data = xp.asarray([1, 2, 3, 4])
  238. def mapping(x):
  239. return (x[0] / 2,)
  240. out = ndimage.geometric_transform(data, mapping, [8], order=order)
  241. assert_array_almost_equal(out[::2], xp.asarray([1, 2, 3, 4]))
  242. def test_geometric_transform16(self, order, xp):
  243. data = [[1, 2, 3, 4],
  244. [5, 6, 7, 8],
  245. [9.0, 10, 11, 12]]
  246. data = xp.asarray(data)
  247. def mapping(x):
  248. return (x[0], x[1] * 2)
  249. out = ndimage.geometric_transform(data, mapping, (3, 2),
  250. order=order)
  251. assert_array_almost_equal(out, xp.asarray([[1, 3], [5, 7], [9, 11]]))
  252. def test_geometric_transform17(self, order, xp):
  253. data = [[1, 2, 3, 4],
  254. [5, 6, 7, 8],
  255. [9, 10, 11, 12]]
  256. data = xp.asarray(data)
  257. def mapping(x):
  258. return (x[0] * 2, x[1])
  259. out = ndimage.geometric_transform(data, mapping, (1, 4),
  260. order=order)
  261. assert_array_almost_equal(out, xp.asarray([[1, 2, 3, 4]]))
  262. def test_geometric_transform18(self, order, xp):
  263. data = [[1, 2, 3, 4],
  264. [5, 6, 7, 8],
  265. [9, 10, 11, 12]]
  266. data = xp.asarray(data)
  267. def mapping(x):
  268. return (x[0] * 2, x[1] * 2)
  269. out = ndimage.geometric_transform(data, mapping, (1, 2),
  270. order=order)
  271. assert_array_almost_equal(out, xp.asarray([[1, 3]]))
  272. def test_geometric_transform19(self, order, xp):
  273. data = [[1, 2, 3, 4],
  274. [5, 6, 7, 8],
  275. [9, 10, 11, 12]]
  276. data = xp.asarray(data)
  277. def mapping(x):
  278. return (x[0], x[1] / 2)
  279. out = ndimage.geometric_transform(data, mapping, (3, 8),
  280. order=order)
  281. assert_array_almost_equal(out[..., ::2], data)
  282. def test_geometric_transform20(self, order, xp):
  283. data = [[1, 2, 3, 4],
  284. [5, 6, 7, 8],
  285. [9, 10, 11, 12]]
  286. data = xp.asarray(data)
  287. def mapping(x):
  288. return (x[0] / 2, x[1])
  289. out = ndimage.geometric_transform(data, mapping, (6, 4),
  290. order=order)
  291. assert_array_almost_equal(out[::2, ...], data)
  292. def test_geometric_transform21(self, order, xp):
  293. data = [[1, 2, 3, 4],
  294. [5, 6, 7, 8],
  295. [9, 10, 11, 12]]
  296. data = xp.asarray(data)
  297. def mapping(x):
  298. return (x[0] / 2, x[1] / 2)
  299. out = ndimage.geometric_transform(data, mapping, (6, 8),
  300. order=order)
  301. assert_array_almost_equal(out[::2, ::2], data)
  302. def test_geometric_transform22(self, order, xp):
  303. data = [[1, 2, 3, 4],
  304. [5, 6, 7, 8],
  305. [9, 10, 11, 12]]
  306. data = xp.asarray(data, dtype=xp.float64)
  307. def mapping1(x):
  308. return (x[0] / 2, x[1] / 2)
  309. def mapping2(x):
  310. return (x[0] * 2, x[1] * 2)
  311. out = ndimage.geometric_transform(data, mapping1,
  312. (6, 8), order=order)
  313. out = ndimage.geometric_transform(out, mapping2,
  314. (3, 4), order=order)
  315. assert_array_almost_equal(out, data)
  316. def test_geometric_transform23(self, order, xp):
  317. data = [[1, 2, 3, 4],
  318. [5, 6, 7, 8],
  319. [9, 10, 11, 12]]
  320. data = xp.asarray(data)
  321. def mapping(x):
  322. return (1, x[0] * 2)
  323. out = ndimage.geometric_transform(data, mapping, (2,), order=order)
  324. assert_array_almost_equal(out, xp.asarray([5, 7]))
  325. def test_geometric_transform24(self, order, xp):
  326. data = [[1, 2, 3, 4],
  327. [5, 6, 7, 8],
  328. [9, 10, 11, 12]]
  329. data = xp.asarray(data)
  330. def mapping(x, a, b):
  331. return (a, x[0] * b)
  332. out = ndimage.geometric_transform(
  333. data, mapping, (2,), order=order, extra_arguments=(1,),
  334. extra_keywords={'b': 2})
  335. assert_array_almost_equal(out, xp.asarray([5, 7]))
  336. @make_xp_test_case(ndimage.geometric_transform)
  337. class TestGeometricTransformExtra:
  338. def test_geometric_transform_grid_constant_order1(self, xp):
  339. # verify interpolation outside the original bounds
  340. x = xp.asarray([[1, 2, 3],
  341. [4, 5, 6]], dtype=xp.float64)
  342. def mapping(x):
  343. return (x[0] - 0.5), (x[1] - 0.5)
  344. expected_result = xp.asarray([[0.25, 0.75, 1.25],
  345. [1.25, 3.00, 4.00]])
  346. assert_array_almost_equal(
  347. ndimage.geometric_transform(x, mapping, mode='grid-constant',
  348. order=1),
  349. expected_result,
  350. )
  351. @pytest.mark.parametrize('mode', ['grid-constant', 'grid-wrap', 'nearest',
  352. 'mirror', 'reflect'])
  353. @pytest.mark.parametrize('order', range(6))
  354. def test_geometric_transform_vs_padded(self, order, mode, xp):
  355. def mapping(x):
  356. return (x[0] - 0.4), (x[1] + 2.3)
  357. # Manually pad and then extract center after the transform to get the
  358. # expected result.
  359. x = np.arange(144, dtype=float).reshape(12, 12)
  360. npad = 24
  361. pad_mode = ndimage_to_numpy_mode.get(mode)
  362. x_padded = np.pad(x, npad, mode=pad_mode)
  363. x = xp.asarray(x)
  364. x_padded = xp.asarray(x_padded)
  365. center_slice = tuple([slice(npad, -npad)] * x.ndim)
  366. expected_result = ndimage.geometric_transform(
  367. x_padded, mapping, mode=mode, order=order)[center_slice]
  368. xp_assert_close(
  369. ndimage.geometric_transform(x, mapping, mode=mode,
  370. order=order),
  371. expected_result,
  372. rtol=1e-7,
  373. )
  374. @skip_xp_backends(np_only=True, reason='endianness is numpy-specific')
  375. def test_geometric_transform_endianness_with_output_parameter(self, xp):
  376. # geometric transform given output ndarray or dtype with
  377. # non-native endianness. see issue #4127
  378. data = np.asarray([1])
  379. def mapping(x):
  380. return x
  381. for out in [data.dtype, data.dtype.newbyteorder(),
  382. np.empty_like(data),
  383. np.empty_like(data).astype(data.dtype.newbyteorder())]:
  384. returned = ndimage.geometric_transform(data, mapping, data.shape,
  385. output=out)
  386. result = out if returned is None else returned
  387. assert_array_almost_equal(result, [1])
  388. @skip_xp_backends(np_only=True, reason='string `output` is numpy-specific')
  389. def test_geometric_transform_with_string_output(self, xp):
  390. data = xp.asarray([1])
  391. def mapping(x):
  392. return x
  393. out = ndimage.geometric_transform(data, mapping, output='f')
  394. assert out.dtype is np.dtype('f')
  395. assert_array_almost_equal(out, [1])
  396. @make_xp_test_case(ndimage.map_coordinates)
  397. class TestMapCoordinates:
  398. @pytest.mark.parametrize('order', range(0, 6))
  399. @pytest.mark.parametrize('dtype', [np.float64, np.complex128])
  400. def test_map_coordinates01(self, order, dtype, xp):
  401. if is_jax(xp) and order > 1:
  402. pytest.xfail("jax map_coordinates requires order <= 1")
  403. data = xp.asarray([[4, 1, 3, 2],
  404. [7, 6, 8, 5],
  405. [3, 5, 3, 6]])
  406. expected = xp.asarray([[0, 0, 0, 0],
  407. [0, 4, 1, 3],
  408. [0, 7, 6, 8]])
  409. if xp.isdtype(data.dtype, 'complex floating'):
  410. data = data - 1j * data
  411. expected = expected - 1j * expected
  412. idx = np.indices(data.shape)
  413. idx -= 1
  414. idx = xp.asarray(idx)
  415. out = ndimage.map_coordinates(data, idx, order=order)
  416. assert_array_almost_equal(out, expected)
  417. @pytest.mark.parametrize('order', range(0, 6))
  418. def test_map_coordinates02(self, order, xp):
  419. if is_jax(xp):
  420. if order > 1:
  421. pytest.xfail("jax map_coordinates requires order <= 1")
  422. if order == 1:
  423. pytest.xfail("output differs. jax bug?")
  424. data = xp.asarray([[4, 1, 3, 2],
  425. [7, 6, 8, 5],
  426. [3, 5, 3, 6]])
  427. idx = np.indices(data.shape, np.float64)
  428. idx -= 0.5
  429. idx = xp.asarray(idx)
  430. out1 = ndimage.shift(data, 0.5, order=order)
  431. out2 = ndimage.map_coordinates(data, idx, order=order)
  432. assert_array_almost_equal(out1, out2)
  433. @skip_xp_backends("jax.numpy", reason="`order` is required in jax")
  434. def test_map_coordinates03(self, xp):
  435. data = _asarray([[4, 1, 3, 2],
  436. [7, 6, 8, 5],
  437. [3, 5, 3, 6]], order='F', xp=xp)
  438. idx = np.indices(data.shape) - 1
  439. idx = xp.asarray(idx)
  440. out = ndimage.map_coordinates(data, idx)
  441. expected = xp.asarray([[0, 0, 0, 0],
  442. [0, 4, 1, 3],
  443. [0, 7, 6, 8]])
  444. assert_array_almost_equal(out, expected)
  445. assert_array_almost_equal(out, ndimage.shift(data, (1, 1)))
  446. idx = np.indices(data[::2, ...].shape) - 1
  447. idx = xp.asarray(idx)
  448. out = ndimage.map_coordinates(data[::2, ...], idx)
  449. assert_array_almost_equal(out, xp.asarray([[0, 0, 0, 0],
  450. [0, 4, 1, 3]]))
  451. assert_array_almost_equal(out, ndimage.shift(data[::2, ...], (1, 1)))
  452. idx = np.indices(data[:, ::2].shape) - 1
  453. idx = xp.asarray(idx)
  454. out = ndimage.map_coordinates(data[:, ::2], idx)
  455. assert_array_almost_equal(out, xp.asarray([[0, 0], [0, 4], [0, 7]]))
  456. assert_array_almost_equal(out, ndimage.shift(data[:, ::2], (1, 1)))
  457. @skip_xp_backends(np_only=True)
  458. def test_map_coordinates_endianness_with_output_parameter(self, xp):
  459. # output parameter given as array or dtype with either endianness
  460. # see issue #4127
  461. # NB: NumPy-only
  462. data = np.asarray([[1, 2], [7, 6]])
  463. expected = np.asarray([[0, 0], [0, 1]])
  464. idx = np.indices(data.shape)
  465. idx -= 1
  466. for out in [
  467. data.dtype,
  468. data.dtype.newbyteorder(),
  469. np.empty_like(expected),
  470. np.empty_like(expected).astype(expected.dtype.newbyteorder())
  471. ]:
  472. returned = ndimage.map_coordinates(data, idx, output=out)
  473. result = out if returned is None else returned
  474. assert_array_almost_equal(result, expected)
  475. @skip_xp_backends(np_only=True, reason='string `output` is numpy-specific')
  476. def test_map_coordinates_with_string_output(self, xp):
  477. data = xp.asarray([[1]])
  478. idx = np.indices(data.shape)
  479. idx = xp.asarray(idx)
  480. out = ndimage.map_coordinates(data, idx, output='f')
  481. assert out.dtype is np.dtype('f')
  482. assert_array_almost_equal(out, xp.asarray([[1]]))
  483. @pytest.mark.skip_xp_backends(cpu_only=True)
  484. @pytest.mark.skipif('win32' in sys.platform or np.intp(0).itemsize < 8,
  485. reason='do not run on 32 bit or windows '
  486. '(no sparse memory)')
  487. def test_map_coordinates_large_data(self, xp):
  488. # check crash on large data
  489. try:
  490. n = 30000
  491. # a = xp.reshape(xp.empty(n**2, dtype=xp.float32), (n, n))
  492. a = np.empty(n**2, dtype=np.float32).reshape(n, n)
  493. # fill the part we might read
  494. a[n - 3:, n - 3:] = 0
  495. ndimage.map_coordinates(
  496. xp.asarray(a), xp.asarray([[n - 1.5], [n - 1.5]]), order=1
  497. )
  498. except MemoryError as e:
  499. raise pytest.skip('Not enough memory available') from e
  500. @make_xp_test_case(ndimage.affine_transform)
  501. class TestAffineTransform:
  502. @pytest.mark.parametrize('order', range(0, 6))
  503. def test_affine_transform01(self, order, xp):
  504. data = xp.asarray([1])
  505. out = ndimage.affine_transform(data, xp.asarray([[1]]), order=order)
  506. assert_array_almost_equal(out, xp.asarray([1]))
  507. @pytest.mark.parametrize('order', range(0, 6))
  508. def test_affine_transform02(self, order, xp):
  509. data = xp.ones([4])
  510. out = ndimage.affine_transform(data, xp.asarray([[1]]), order=order)
  511. assert_array_almost_equal(out, xp.asarray([1, 1, 1, 1]))
  512. @pytest.mark.parametrize('order', range(0, 6))
  513. def test_affine_transform03(self, order, xp):
  514. data = xp.ones([4])
  515. out = ndimage.affine_transform(data, xp.asarray([[1]]), -1, order=order)
  516. assert_array_almost_equal(out, xp.asarray([0, 1, 1, 1]))
  517. @pytest.mark.parametrize('order', range(0, 6))
  518. def test_affine_transform04(self, order, xp):
  519. data = xp.asarray([4, 1, 3, 2])
  520. out = ndimage.affine_transform(data, xp.asarray([[1]]), -1, order=order)
  521. assert_array_almost_equal(out, xp.asarray([0, 4, 1, 3]))
  522. @pytest.mark.parametrize('order', range(0, 6))
  523. @pytest.mark.parametrize('dtype', ["float64", "complex128"])
  524. def test_affine_transform05(self, order, dtype, xp):
  525. dtype = getattr(xp, dtype)
  526. data = xp.asarray([[1, 1, 1, 1],
  527. [1, 1, 1, 1],
  528. [1, 1, 1, 1]], dtype=dtype)
  529. expected = xp.asarray([[0, 1, 1, 1],
  530. [0, 1, 1, 1],
  531. [0, 1, 1, 1]], dtype=dtype)
  532. if xp.isdtype(data.dtype, 'complex floating'):
  533. data -= 1j * data
  534. expected -= 1j * expected
  535. out = ndimage.affine_transform(data, xp.asarray([[1, 0], [0, 1]]),
  536. [0, -1], order=order)
  537. assert_array_almost_equal(out, expected)
  538. @pytest.mark.parametrize('order', range(0, 6))
  539. def test_affine_transform06(self, order, xp):
  540. data = xp.asarray([[4, 1, 3, 2],
  541. [7, 6, 8, 5],
  542. [3, 5, 3, 6]])
  543. out = ndimage.affine_transform(data, xp.asarray([[1, 0], [0, 1]]),
  544. [0, -1], order=order)
  545. assert_array_almost_equal(out, xp.asarray([[0, 4, 1, 3],
  546. [0, 7, 6, 8],
  547. [0, 3, 5, 3]]))
  548. @pytest.mark.parametrize('order', range(0, 6))
  549. def test_affine_transform07(self, order, xp):
  550. data = xp.asarray([[4, 1, 3, 2],
  551. [7, 6, 8, 5],
  552. [3, 5, 3, 6]])
  553. out = ndimage.affine_transform(data, xp.asarray([[1, 0], [0, 1]]),
  554. [-1, 0], order=order)
  555. assert_array_almost_equal(out, xp.asarray([[0, 0, 0, 0],
  556. [4, 1, 3, 2],
  557. [7, 6, 8, 5]]))
  558. @pytest.mark.parametrize('order', range(0, 6))
  559. def test_affine_transform08(self, order, xp):
  560. data = xp.asarray([[4, 1, 3, 2],
  561. [7, 6, 8, 5],
  562. [3, 5, 3, 6]])
  563. out = ndimage.affine_transform(data, xp.asarray([[1, 0], [0, 1]]),
  564. [-1, -1], order=order)
  565. assert_array_almost_equal(out, xp.asarray([[0, 0, 0, 0],
  566. [0, 4, 1, 3],
  567. [0, 7, 6, 8]]))
  568. @pytest.mark.parametrize('order', range(0, 6))
  569. def test_affine_transform09(self, order, xp):
  570. data = xp.asarray([[4, 1, 3, 2],
  571. [7, 6, 8, 5],
  572. [3, 5, 3, 6]])
  573. if (order > 1):
  574. filtered = ndimage.spline_filter(data, order=order)
  575. else:
  576. filtered = data
  577. out = ndimage.affine_transform(filtered, xp.asarray([[1, 0], [0, 1]]),
  578. [-1, -1], order=order,
  579. prefilter=False)
  580. assert_array_almost_equal(out, xp.asarray([[0, 0, 0, 0],
  581. [0, 4, 1, 3],
  582. [0, 7, 6, 8]]))
  583. @pytest.mark.parametrize('order', range(0, 6))
  584. def test_affine_transform10(self, order, xp):
  585. data = xp.ones([2], dtype=xp.float64)
  586. out = ndimage.affine_transform(data, xp.asarray([[0.5]]), output_shape=(4,),
  587. order=order)
  588. assert_array_almost_equal(out, xp.asarray([1, 1, 1, 0]))
  589. @pytest.mark.parametrize('order', range(0, 6))
  590. def test_affine_transform11(self, order, xp):
  591. data = xp.asarray([1, 5, 2, 6, 3, 7, 4, 4])
  592. out = ndimage.affine_transform(data, xp.asarray([[2]]), 0, (4,), order=order)
  593. assert_array_almost_equal(out, xp.asarray([1, 2, 3, 4]))
  594. @pytest.mark.parametrize('order', range(0, 6))
  595. def test_affine_transform12(self, order, xp):
  596. data = xp.asarray([1, 2, 3, 4])
  597. out = ndimage.affine_transform(data, xp.asarray([[0.5]]), 0, (8,), order=order)
  598. assert_array_almost_equal(out[::2], xp.asarray([1, 2, 3, 4]))
  599. @pytest.mark.parametrize('order', range(0, 6))
  600. def test_affine_transform13(self, order, xp):
  601. data = [[1, 2, 3, 4],
  602. [5, 6, 7, 8],
  603. [9.0, 10, 11, 12]]
  604. data = xp.asarray(data)
  605. out = ndimage.affine_transform(data, xp.asarray([[1, 0], [0, 2]]), 0, (3, 2),
  606. order=order)
  607. assert_array_almost_equal(out, xp.asarray([[1, 3], [5, 7], [9, 11]]))
  608. @pytest.mark.parametrize('order', range(0, 6))
  609. def test_affine_transform14(self, order, xp):
  610. data = [[1, 2, 3, 4],
  611. [5, 6, 7, 8],
  612. [9, 10, 11, 12]]
  613. data = xp.asarray(data)
  614. out = ndimage.affine_transform(data, xp.asarray([[2, 0], [0, 1]]), 0, (1, 4),
  615. order=order)
  616. assert_array_almost_equal(out, xp.asarray([[1, 2, 3, 4]]))
  617. @pytest.mark.parametrize('order', range(0, 6))
  618. def test_affine_transform15(self, order, xp):
  619. data = [[1, 2, 3, 4],
  620. [5, 6, 7, 8],
  621. [9, 10, 11, 12]]
  622. data = xp.asarray(data)
  623. out = ndimage.affine_transform(data, xp.asarray([[2, 0], [0, 2]]), 0, (1, 2),
  624. order=order)
  625. assert_array_almost_equal(out, xp.asarray([[1, 3]]))
  626. @pytest.mark.parametrize('order', range(0, 6))
  627. def test_affine_transform16(self, order, xp):
  628. data = [[1, 2, 3, 4],
  629. [5, 6, 7, 8],
  630. [9, 10, 11, 12]]
  631. data = xp.asarray(data)
  632. out = ndimage.affine_transform(data, xp.asarray([[1, 0.0], [0, 0.5]]), 0,
  633. (3, 8), order=order)
  634. assert_array_almost_equal(out[..., ::2], data)
  635. @pytest.mark.parametrize('order', range(0, 6))
  636. def test_affine_transform17(self, order, xp):
  637. data = [[1, 2, 3, 4],
  638. [5, 6, 7, 8],
  639. [9, 10, 11, 12]]
  640. data = xp.asarray(data)
  641. out = ndimage.affine_transform(data, xp.asarray([[0.5, 0], [0, 1]]), 0,
  642. (6, 4), order=order)
  643. assert_array_almost_equal(out[::2, ...], data)
  644. @pytest.mark.parametrize('order', range(0, 6))
  645. def test_affine_transform18(self, order, xp):
  646. data = xp.asarray([[1, 2, 3, 4],
  647. [5, 6, 7, 8],
  648. [9, 10, 11, 12]])
  649. out = ndimage.affine_transform(data, xp.asarray([[0.5, 0], [0, 0.5]]), 0,
  650. (6, 8), order=order)
  651. assert_array_almost_equal(out[::2, ::2], data)
  652. @pytest.mark.parametrize('order', range(0, 6))
  653. def test_affine_transform19(self, order, xp):
  654. data = xp.asarray([[1, 2, 3, 4],
  655. [5, 6, 7, 8],
  656. [9, 10, 11, 12]], dtype=xp.float64)
  657. out = ndimage.affine_transform(data, xp.asarray([[0.5, 0], [0, 0.5]]), 0,
  658. (6, 8), order=order)
  659. out = ndimage.affine_transform(out, xp.asarray([[2.0, 0], [0, 2.0]]), 0,
  660. (3, 4), order=order)
  661. assert_array_almost_equal(out, data)
  662. @xfail_xp_backends("cupy", reason="https://github.com/cupy/cupy/issues/8394")
  663. @pytest.mark.parametrize('order', range(0, 6))
  664. def test_affine_transform20(self, order, xp):
  665. data = [[1, 2, 3, 4],
  666. [5, 6, 7, 8],
  667. [9, 10, 11, 12]]
  668. data = xp.asarray(data)
  669. out = ndimage.affine_transform(data, xp.asarray([[0], [2]]), 0, (2,),
  670. order=order)
  671. assert_array_almost_equal(out, xp.asarray([1, 3]))
  672. @xfail_xp_backends("cupy", reason="https://github.com/cupy/cupy/issues/8394")
  673. @pytest.mark.parametrize('order', range(0, 6))
  674. def test_affine_transform21(self, order, xp):
  675. data = [[1, 2, 3, 4],
  676. [5, 6, 7, 8],
  677. [9, 10, 11, 12]]
  678. data = xp.asarray(data)
  679. out = ndimage.affine_transform(data, xp.asarray([[2], [0]]), 0, (2,),
  680. order=order)
  681. assert_array_almost_equal(out, xp.asarray([1, 9]))
  682. @pytest.mark.parametrize('order', range(0, 6))
  683. def test_affine_transform22(self, order, xp):
  684. # shift and offset interaction; see issue #1547
  685. data = xp.asarray([4, 1, 3, 2])
  686. out = ndimage.affine_transform(data, xp.asarray([[2]]), [-1], (3,),
  687. order=order)
  688. assert_array_almost_equal(out, xp.asarray([0, 1, 2]))
  689. @pytest.mark.parametrize('order', range(0, 6))
  690. def test_affine_transform23(self, order, xp):
  691. # shift and offset interaction; see issue #1547
  692. data = xp.asarray([4, 1, 3, 2])
  693. out = ndimage.affine_transform(data, xp.asarray([[0.5]]), [-1], (8,),
  694. order=order)
  695. assert_array_almost_equal(out[::2], xp.asarray([0, 4, 1, 3]))
  696. @pytest.mark.parametrize('order', range(0, 6))
  697. def test_affine_transform24(self, order, xp):
  698. # consistency between diagonal and non-diagonal case; see issue #1547
  699. data = xp.asarray([4, 1, 3, 2])
  700. with warnings.catch_warnings():
  701. warnings.filterwarnings(
  702. "ignore",
  703. 'The behavior of affine_transform with a 1-D array .* has changed',
  704. UserWarning)
  705. out1 = ndimage.affine_transform(data, xp.asarray([2]), -1, order=order)
  706. out2 = ndimage.affine_transform(data, xp.asarray([[2]]), -1, order=order)
  707. assert_array_almost_equal(out1, out2)
  708. @pytest.mark.parametrize('order', range(0, 6))
  709. def test_affine_transform25(self, order, xp):
  710. # consistency between diagonal and non-diagonal case; see issue #1547
  711. data = xp.asarray([4, 1, 3, 2])
  712. with warnings.catch_warnings():
  713. warnings.filterwarnings("ignore",
  714. 'The behavior of affine_transform with a 1-D array .* '
  715. 'has changed', UserWarning)
  716. out1 = ndimage.affine_transform(data, xp.asarray([0.5]), -1, order=order)
  717. out2 = ndimage.affine_transform(data, xp.asarray([[0.5]]), -1, order=order)
  718. assert_array_almost_equal(out1, out2)
  719. @pytest.mark.parametrize('order', range(0, 6))
  720. def test_affine_transform26(self, order, xp):
  721. # test homogeneous coordinates
  722. data = xp.asarray([[4, 1, 3, 2],
  723. [7, 6, 8, 5],
  724. [3, 5, 3, 6]])
  725. if (order > 1):
  726. filtered = ndimage.spline_filter(data, order=order)
  727. else:
  728. filtered = data
  729. tform_original = xp.eye(2)
  730. offset_original = -xp.ones((2, 1))
  731. tform_h1 = xp.concat((tform_original, offset_original), axis=1) # hstack
  732. tform_h2 = xp.concat((tform_h1, xp.asarray([[0.0, 0, 1]])), axis=0) # vstack
  733. offs = [float(x) for x in xp.reshape(offset_original, (-1,))]
  734. out1 = ndimage.affine_transform(filtered, tform_original,
  735. offs,
  736. order=order, prefilter=False)
  737. out2 = ndimage.affine_transform(filtered, tform_h1, order=order,
  738. prefilter=False)
  739. out3 = ndimage.affine_transform(filtered, tform_h2, order=order,
  740. prefilter=False)
  741. for out in [out1, out2, out3]:
  742. assert_array_almost_equal(out, xp.asarray([[0, 0, 0, 0],
  743. [0, 4, 1, 3],
  744. [0, 7, 6, 8]]))
  745. @xfail_xp_backends("cupy", reason="does not raise")
  746. def test_affine_transform27(self, xp):
  747. # test valid homogeneous transformation matrix
  748. data = xp.asarray([[4, 1, 3, 2],
  749. [7, 6, 8, 5],
  750. [3, 5, 3, 6]])
  751. tform_h1 = xp.concat((xp.eye(2), -xp.ones((2, 1))) , axis=1) # vstack
  752. tform_h2 = xp.concat((tform_h1, xp.asarray([[5.0, 2, 1]])), axis=0) # hstack
  753. assert_raises(ValueError, ndimage.affine_transform, data, tform_h2)
  754. @skip_xp_backends(np_only=True, reason='byteorder is numpy-specific')
  755. def test_affine_transform_1d_endianness_with_output_parameter(self, xp):
  756. # 1d affine transform given output ndarray or dtype with
  757. # either endianness. see issue #7388
  758. data = xp.ones((2, 2))
  759. for out in [xp.empty_like(data),
  760. xp.empty_like(data).astype(data.dtype.newbyteorder()),
  761. data.dtype, data.dtype.newbyteorder()]:
  762. with warnings.catch_warnings():
  763. warnings.filterwarnings("ignore",
  764. 'The behavior of affine_transform with a 1-D array '
  765. '.* has changed', UserWarning)
  766. matrix = xp.asarray([1, 1])
  767. returned = ndimage.affine_transform(data, matrix, output=out)
  768. result = out if returned is None else returned
  769. assert_array_almost_equal(result, xp.asarray([[1, 1], [1, 1]]))
  770. @skip_xp_backends(np_only=True, reason='byteorder is numpy-specific')
  771. def test_affine_transform_multi_d_endianness_with_output_parameter(self, xp):
  772. # affine transform given output ndarray or dtype with either endianness
  773. # see issue #4127
  774. # NB: byteorder is numpy-specific
  775. data = np.asarray([1])
  776. for out in [data.dtype, data.dtype.newbyteorder(),
  777. np.empty_like(data),
  778. np.empty_like(data).astype(data.dtype.newbyteorder())]:
  779. returned = ndimage.affine_transform(data, np.asarray([[1]]), output=out)
  780. result = out if returned is None else returned
  781. assert_array_almost_equal(result, np.asarray([1]))
  782. @skip_xp_backends(np_only=True,
  783. reason='`out` of a different size is numpy-specific'
  784. )
  785. def test_affine_transform_output_shape(self, xp):
  786. # don't require output_shape when out of a different size is given
  787. data = xp.arange(8, dtype=xp.float64)
  788. out = xp.ones((16,))
  789. ndimage.affine_transform(data, xp.asarray([[1]]), output=out)
  790. assert_array_almost_equal(out[:8], data)
  791. # mismatched output shape raises an error
  792. with pytest.raises(RuntimeError):
  793. ndimage.affine_transform(
  794. data, [[1]], output=out, output_shape=(12,))
  795. @skip_xp_backends(np_only=True, reason='string `output` is numpy-specific')
  796. def test_affine_transform_with_string_output(self, xp):
  797. data = xp.asarray([1])
  798. out = ndimage.affine_transform(data, xp.asarray([[1]]), output='f')
  799. assert out.dtype is np.dtype('f')
  800. assert_array_almost_equal(out, xp.asarray([1]))
  801. @pytest.mark.parametrize('shift',
  802. [(1, 0), (0, 1), (-1, 1), (3, -5), (2, 7)])
  803. @pytest.mark.parametrize('order', range(0, 6))
  804. def test_affine_transform_shift_via_grid_wrap(self, shift, order, xp):
  805. # For mode 'grid-wrap', integer shifts should match np.roll
  806. x = np.asarray([[0, 1],
  807. [2, 3]])
  808. affine = np.zeros((2, 3))
  809. affine[:2, :2] = np.eye(2)
  810. affine[:, 2] = np.asarray(shift)
  811. expected = np.roll(x, shift, axis=(0, 1))
  812. x = xp.asarray(x)
  813. affine = xp.asarray(affine)
  814. expected = xp.asarray(expected)
  815. assert_array_almost_equal(
  816. ndimage.affine_transform(x, affine, mode='grid-wrap', order=order),
  817. expected
  818. )
  819. @pytest.mark.parametrize('order', range(0, 6))
  820. def test_affine_transform_shift_reflect(self, order, xp):
  821. # shift by x.shape results in reflection
  822. x = np.asarray([[0, 1, 2],
  823. [3, 4, 5]])
  824. expected = x[::-1, ::-1].copy() # strides >0 for torch
  825. x = xp.asarray(x)
  826. expected = xp.asarray(expected)
  827. affine = np.zeros([2, 3])
  828. affine[:2, :2] = np.eye(2)
  829. affine[:, 2] = np.asarray(x.shape)
  830. affine = xp.asarray(affine)
  831. assert_array_almost_equal(
  832. ndimage.affine_transform(x, affine, mode='reflect', order=order),
  833. expected,
  834. )
  835. @make_xp_test_case(ndimage.shift)
  836. class TestShift:
  837. @pytest.mark.parametrize('order', range(0, 6))
  838. def test_shift01(self, order, xp):
  839. data = xp.asarray([1])
  840. out = ndimage.shift(data, [1], order=order)
  841. assert_array_almost_equal(out, xp.asarray([0]))
  842. @pytest.mark.parametrize('order', range(0, 6))
  843. def test_shift02(self, order, xp):
  844. data = xp.ones([4])
  845. out = ndimage.shift(data, [1], order=order)
  846. assert_array_almost_equal(out, xp.asarray([0, 1, 1, 1]))
  847. @pytest.mark.parametrize('order', range(0, 6))
  848. def test_shift03(self, order, xp):
  849. data = xp.ones([4])
  850. out = ndimage.shift(data, -1, order=order)
  851. assert_array_almost_equal(out, xp.asarray([1, 1, 1, 0]))
  852. @pytest.mark.parametrize('order', range(0, 6))
  853. def test_shift04(self, order, xp):
  854. data = xp.asarray([4, 1, 3, 2])
  855. out = ndimage.shift(data, 1, order=order)
  856. assert_array_almost_equal(out, xp.asarray([0, 4, 1, 3]))
  857. @pytest.mark.parametrize('order', range(0, 6))
  858. @pytest.mark.parametrize('dtype', ["float64", "complex128"])
  859. def test_shift05(self, order, dtype, xp):
  860. dtype = getattr(xp, dtype)
  861. data = xp.asarray([[1, 1, 1, 1],
  862. [1, 1, 1, 1],
  863. [1, 1, 1, 1]], dtype=dtype)
  864. expected = xp.asarray([[0, 1, 1, 1],
  865. [0, 1, 1, 1],
  866. [0, 1, 1, 1]], dtype=dtype)
  867. if xp.isdtype(data.dtype, 'complex floating'):
  868. data -= 1j * data
  869. expected -= 1j * expected
  870. out = ndimage.shift(data, [0, 1], order=order)
  871. assert_array_almost_equal(out, expected)
  872. @pytest.mark.parametrize('order', range(0, 6))
  873. @pytest.mark.parametrize('mode', ['constant', 'grid-constant'])
  874. @pytest.mark.parametrize('dtype', ['float64', 'complex128'])
  875. def test_shift_with_nonzero_cval(self, order, mode, dtype, xp):
  876. data = np.asarray([[1, 1, 1, 1],
  877. [1, 1, 1, 1],
  878. [1, 1, 1, 1]], dtype=dtype)
  879. expected = np.asarray([[0, 1, 1, 1],
  880. [0, 1, 1, 1],
  881. [0, 1, 1, 1]], dtype=dtype)
  882. if np_compat.isdtype(data.dtype, 'complex floating'):
  883. data -= 1j * data
  884. expected -= 1j * expected
  885. cval = 5.0
  886. expected[:, 0] = cval # specific to shift of [0, 1] used below
  887. data = xp.asarray(data)
  888. expected = xp.asarray(expected)
  889. out = ndimage.shift(data, [0, 1], order=order, mode=mode, cval=cval)
  890. assert_array_almost_equal(out, expected)
  891. @pytest.mark.parametrize('order', range(0, 6))
  892. def test_shift06(self, order, xp):
  893. data = xp.asarray([[4, 1, 3, 2],
  894. [7, 6, 8, 5],
  895. [3, 5, 3, 6]])
  896. out = ndimage.shift(data, [0, 1], order=order)
  897. assert_array_almost_equal(out, xp.asarray([[0, 4, 1, 3],
  898. [0, 7, 6, 8],
  899. [0, 3, 5, 3]]))
  900. @pytest.mark.parametrize('order', range(0, 6))
  901. def test_shift07(self, order, xp):
  902. data = xp.asarray([[4, 1, 3, 2],
  903. [7, 6, 8, 5],
  904. [3, 5, 3, 6]])
  905. out = ndimage.shift(data, [1, 0], order=order)
  906. assert_array_almost_equal(out, xp.asarray([[0, 0, 0, 0],
  907. [4, 1, 3, 2],
  908. [7, 6, 8, 5]]))
  909. @pytest.mark.parametrize('order', range(0, 6))
  910. def test_shift08(self, order, xp):
  911. data = xp.asarray([[4, 1, 3, 2],
  912. [7, 6, 8, 5],
  913. [3, 5, 3, 6]])
  914. out = ndimage.shift(data, [1, 1], order=order)
  915. assert_array_almost_equal(out, xp.asarray([[0, 0, 0, 0],
  916. [0, 4, 1, 3],
  917. [0, 7, 6, 8]]))
  918. @pytest.mark.parametrize('order', range(0, 6))
  919. def test_shift09(self, order, xp):
  920. data = xp.asarray([[4, 1, 3, 2],
  921. [7, 6, 8, 5],
  922. [3, 5, 3, 6]])
  923. if (order > 1):
  924. filtered = ndimage.spline_filter(data, order=order)
  925. else:
  926. filtered = data
  927. out = ndimage.shift(filtered, [1, 1], order=order, prefilter=False)
  928. assert_array_almost_equal(out, xp.asarray([[0, 0, 0, 0],
  929. [0, 4, 1, 3],
  930. [0, 7, 6, 8]]))
  931. @pytest.mark.parametrize('shift',
  932. [(1, 0), (0, 1), (-1, 1), (3, -5), (2, 7)])
  933. @pytest.mark.parametrize('order', range(0, 6))
  934. def test_shift_grid_wrap(self, shift, order, xp):
  935. # For mode 'grid-wrap', integer shifts should match np.roll
  936. x = np.asarray([[0, 1],
  937. [2, 3]])
  938. expected = np.roll(x, shift, axis=(0,1))
  939. x = xp.asarray(x)
  940. expected = xp.asarray(expected)
  941. assert_array_almost_equal(
  942. ndimage.shift(x, shift, mode='grid-wrap', order=order),
  943. expected
  944. )
  945. @pytest.mark.parametrize('shift',
  946. [(1, 0), (0, 1), (-1, 1), (3, -5), (2, 7)])
  947. @pytest.mark.parametrize('order', range(0, 6))
  948. def test_shift_grid_constant1(self, shift, order, xp):
  949. # For integer shifts, 'constant' and 'grid-constant' should be equal
  950. x = xp.reshape(xp.arange(20), (5, 4))
  951. assert_array_almost_equal(
  952. ndimage.shift(x, shift, mode='grid-constant', order=order),
  953. ndimage.shift(x, shift, mode='constant', order=order),
  954. )
  955. def test_shift_grid_constant_order1(self, xp):
  956. x = xp.asarray([[1, 2, 3],
  957. [4, 5, 6]], dtype=xp.float64)
  958. expected_result = xp.asarray([[0.25, 0.75, 1.25],
  959. [1.25, 3.00, 4.00]])
  960. assert_array_almost_equal(
  961. ndimage.shift(x, (0.5, 0.5), mode='grid-constant', order=1),
  962. expected_result,
  963. )
  964. @pytest.mark.parametrize('order', range(0, 6))
  965. def test_shift_reflect(self, order, xp):
  966. # shift by x.shape results in reflection
  967. x = np.asarray([[0, 1, 2],
  968. [3, 4, 5]])
  969. expected = x[::-1, ::-1].copy() # strides > 0 for torch
  970. x = xp.asarray(x)
  971. expected = xp.asarray(expected)
  972. assert_array_almost_equal(
  973. ndimage.shift(x, x.shape, mode='reflect', order=order),
  974. expected,
  975. )
  976. @pytest.mark.parametrize('order', range(0, 6))
  977. @pytest.mark.parametrize('prefilter', [False, True])
  978. def test_shift_nearest_boundary(self, order, prefilter, xp):
  979. # verify that shifting at least order // 2 beyond the end of the array
  980. # gives a value equal to the edge value.
  981. x = xp.arange(16)
  982. kwargs = dict(mode='nearest', order=order, prefilter=prefilter)
  983. assert_array_almost_equal(
  984. ndimage.shift(x, order // 2 + 1, **kwargs)[0], x[0],
  985. )
  986. assert_array_almost_equal(
  987. ndimage.shift(x, -order // 2 - 1, **kwargs)[-1], x[-1],
  988. )
  989. @pytest.mark.parametrize('mode', ['grid-constant', 'grid-wrap', 'nearest',
  990. 'mirror', 'reflect'])
  991. @pytest.mark.parametrize('order', range(6))
  992. def test_shift_vs_padded(self, order, mode, xp):
  993. x_np = np.arange(144, dtype=float).reshape(12, 12)
  994. shift = (0.4, -2.3)
  995. # manually pad and then extract center to get expected result
  996. npad = 32
  997. pad_mode = ndimage_to_numpy_mode.get(mode)
  998. x_padded = xp.asarray(np.pad(x_np, npad, mode=pad_mode))
  999. x = xp.asarray(x_np)
  1000. center_slice = tuple([slice(npad, -npad)] * x.ndim)
  1001. expected_result = ndimage.shift(
  1002. x_padded, shift, mode=mode, order=order)[center_slice]
  1003. xp_assert_close(
  1004. ndimage.shift(x, shift, mode=mode, order=order),
  1005. expected_result,
  1006. rtol=1e-7,
  1007. )
  1008. @make_xp_test_case(ndimage.zoom)
  1009. class TestZoom:
  1010. @pytest.mark.parametrize('order', range(0, 6))
  1011. def test_zoom1(self, order, xp):
  1012. for z in [2, [2, 2]]:
  1013. arr = xp.reshape(xp.arange(25, dtype=xp.float64), (5, 5))
  1014. arr = ndimage.zoom(arr, z, order=order)
  1015. assert arr.shape == (10, 10)
  1016. assert xp.all(arr[-1, :] != 0)
  1017. assert xp.all(arr[-1, :] >= (20 - eps))
  1018. assert xp.all(arr[0, :] <= (5 + eps))
  1019. assert xp.all(arr >= (0 - eps))
  1020. assert xp.all(arr <= (24 + eps))
  1021. def test_zoom2(self, xp):
  1022. arr = xp.reshape(xp.arange(12), (3, 4))
  1023. out = ndimage.zoom(ndimage.zoom(arr, 2), 0.5)
  1024. xp_assert_equal(out, arr)
  1025. def test_zoom3(self, xp):
  1026. arr = xp.asarray([[1, 2]])
  1027. out1 = ndimage.zoom(arr, (2, 1))
  1028. out2 = ndimage.zoom(arr, (1, 2))
  1029. assert_array_almost_equal(out1, xp.asarray([[1, 2], [1, 2]]))
  1030. assert_array_almost_equal(out2, xp.asarray([[1, 1, 2, 2]]))
  1031. @pytest.mark.parametrize('order', range(0, 6))
  1032. @pytest.mark.parametrize('dtype', ["float64", "complex128"])
  1033. def test_zoom_affine01(self, order, dtype, xp):
  1034. dtype = getattr(xp, dtype)
  1035. data = xp.asarray([[1, 2, 3, 4],
  1036. [5, 6, 7, 8],
  1037. [9, 10, 11, 12]], dtype=dtype)
  1038. if xp.isdtype(data.dtype, 'complex floating'):
  1039. data -= 1j * data
  1040. with warnings.catch_warnings():
  1041. warnings.filterwarnings("ignore",
  1042. 'The behavior of affine_transform with a 1-D array .* '
  1043. 'has changed', UserWarning)
  1044. out = ndimage.affine_transform(data, xp.asarray([0.5, 0.5]), 0,
  1045. (6, 8), order=order)
  1046. assert_array_almost_equal(out[::2, ::2], data)
  1047. def test_zoom_infinity(self, xp):
  1048. # Ticket #1419 regression test
  1049. dim = 8
  1050. ndimage.zoom(xp.zeros((dim, dim)), 1. / dim, mode='nearest')
  1051. def test_zoom_zoomfactor_one(self, xp):
  1052. # Ticket #1122 regression test
  1053. arr = xp.zeros((1, 5, 5))
  1054. zoom = (1.0, 2.0, 2.0)
  1055. out = ndimage.zoom(arr, zoom, cval=7)
  1056. ref = xp.zeros((1, 10, 10))
  1057. assert_array_almost_equal(out, ref)
  1058. def test_zoom_output_shape_roundoff(self, xp):
  1059. arr = xp.zeros((3, 11, 25))
  1060. zoom = (4.0 / 3, 15.0 / 11, 29.0 / 25)
  1061. out = ndimage.zoom(arr, zoom)
  1062. assert out.shape == (4, 15, 29)
  1063. @pytest.mark.parametrize('zoom', [(1, 1), (3, 5), (8, 2), (8, 8)])
  1064. @pytest.mark.parametrize('mode', ['nearest', 'constant', 'wrap', 'reflect',
  1065. 'mirror', 'grid-wrap', 'grid-mirror',
  1066. 'grid-constant'])
  1067. def test_zoom_by_int_order0(self, zoom, mode, xp):
  1068. # order 0 zoom should be the same as replication via np.kron
  1069. # Note: This is not True for general x shapes when grid_mode is False,
  1070. # but works here for all modes because the size ratio happens to
  1071. # always be an integer when x.shape = (2, 2).
  1072. x_np = np.asarray([[0, 1],
  1073. [2, 3]], dtype=np.float64)
  1074. expected = np.kron(x_np, np.ones(zoom))
  1075. x = xp.asarray(x_np)
  1076. expected = xp.asarray(expected)
  1077. assert_array_almost_equal(
  1078. ndimage.zoom(x, zoom, order=0, mode=mode),
  1079. expected
  1080. )
  1081. @pytest.mark.parametrize('shape', [(2, 3), (4, 4)])
  1082. @pytest.mark.parametrize('zoom', [(1, 1), (3, 5), (8, 2), (8, 8)])
  1083. @pytest.mark.parametrize('mode', ['nearest', 'reflect', 'mirror',
  1084. 'grid-wrap', 'grid-constant'])
  1085. def test_zoom_grid_by_int_order0(self, shape, zoom, mode, xp):
  1086. # When grid_mode is True, order 0 zoom should be the same as
  1087. # replication via np.kron. The only exceptions to this are the
  1088. # non-grid modes 'constant' and 'wrap'.
  1089. x_np = np.arange(np.prod(shape), dtype=float).reshape(shape)
  1090. x = xp.asarray(x_np)
  1091. assert_array_almost_equal(
  1092. ndimage.zoom(x, zoom, order=0, mode=mode, grid_mode=True),
  1093. xp.asarray(np.kron(x_np, np.ones(zoom)))
  1094. )
  1095. @pytest.mark.parametrize('mode', ['constant', 'wrap'])
  1096. def test_zoom_grid_mode_warnings(self, mode, xp):
  1097. # Warn on use of non-grid modes when grid_mode is True
  1098. x = xp.reshape(xp.arange(9, dtype=xp.float64), (3, 3))
  1099. with pytest.warns(UserWarning,
  1100. match="It is recommended to use mode"):
  1101. ndimage.zoom(x, 2, mode=mode, grid_mode=True),
  1102. @skip_xp_backends("dask.array", reason="output=array requires buffer view")
  1103. @skip_xp_backends("jax.numpy", reason="output=array requires buffer view")
  1104. def test_zoom_output_shape(self, xp):
  1105. """Ticket #643"""
  1106. x = xp.reshape(xp.arange(12), (3, 4))
  1107. ndimage.zoom(x, 2, output=xp.zeros((6, 8)))
  1108. def test_zoom_0d_array(self, xp):
  1109. # Ticket #21670 regression test
  1110. a = xp.arange(10.)
  1111. factor = 2
  1112. actual = ndimage.zoom(a, np.array(factor))
  1113. expected = ndimage.zoom(a, factor)
  1114. xp_assert_close(actual, expected)
  1115. @xfail_xp_backends("cupy", reason="CuPy `zoom` needs similar fix.")
  1116. def test_zoom_1_gh20999(self, xp):
  1117. # gh-20999 reported that zoom with `zoom=1` (or sequence of ones)
  1118. # introduced noise. Check that this is resolved.
  1119. x = xp.eye(3)
  1120. xp_assert_equal(ndimage.zoom(x, 1), x)
  1121. xp_assert_equal(ndimage.zoom(x, (1, 1)), x)
  1122. @xfail_xp_backends("cupy", reason="CuPy `zoom` needs similar fix.")
  1123. @skip_xp_backends("jax.numpy", reason="read-only backend")
  1124. @xfail_xp_backends("dask.array", reason="numpy round-trip")
  1125. def test_zoom_1_gh20999_output(self, xp):
  1126. x = xp.eye(3)
  1127. output = xp.zeros_like(x)
  1128. ndimage.zoom(x, 1, output=output)
  1129. xp_assert_equal(output, x)
  1130. @make_xp_test_case(ndimage.rotate)
  1131. class TestRotate:
  1132. @pytest.mark.parametrize('order', range(0, 6))
  1133. def test_rotate01(self, order, xp):
  1134. data = xp.asarray([[0, 0, 0, 0],
  1135. [0, 1, 1, 0],
  1136. [0, 0, 0, 0]], dtype=xp.float64)
  1137. out = ndimage.rotate(data, 0, order=order)
  1138. assert_array_almost_equal(out, data)
  1139. @pytest.mark.parametrize('order', range(0, 6))
  1140. def test_rotate02(self, order, xp):
  1141. data = xp.asarray([[0, 0, 0, 0],
  1142. [0, 1, 0, 0],
  1143. [0, 0, 0, 0]], dtype=xp.float64)
  1144. expected = xp.asarray([[0, 0, 0],
  1145. [0, 0, 0],
  1146. [0, 1, 0],
  1147. [0, 0, 0]], dtype=xp.float64)
  1148. out = ndimage.rotate(data, 90, order=order)
  1149. assert_array_almost_equal(out, expected)
  1150. @pytest.mark.parametrize('order', range(0, 6))
  1151. @pytest.mark.parametrize('dtype', ["float64", "complex128"])
  1152. def test_rotate03(self, order, dtype, xp):
  1153. dtype = getattr(xp, dtype)
  1154. data = xp.asarray([[0, 0, 0, 0, 0],
  1155. [0, 1, 1, 0, 0],
  1156. [0, 0, 0, 0, 0]], dtype=dtype)
  1157. expected = xp.asarray([[0, 0, 0],
  1158. [0, 0, 0],
  1159. [0, 1, 0],
  1160. [0, 1, 0],
  1161. [0, 0, 0]], dtype=dtype)
  1162. if xp.isdtype(data.dtype, 'complex floating'):
  1163. data -= 1j * data
  1164. expected -= 1j * expected
  1165. out = ndimage.rotate(data, 90, order=order)
  1166. assert_array_almost_equal(out, expected)
  1167. @pytest.mark.parametrize('order', range(0, 6))
  1168. def test_rotate04(self, order, xp):
  1169. data = xp.asarray([[0, 0, 0, 0, 0],
  1170. [0, 1, 1, 0, 0],
  1171. [0, 0, 0, 0, 0]], dtype=xp.float64)
  1172. expected = xp.asarray([[0, 0, 0, 0, 0],
  1173. [0, 0, 1, 0, 0],
  1174. [0, 0, 1, 0, 0]], dtype=xp.float64)
  1175. out = ndimage.rotate(data, 90, reshape=False, order=order)
  1176. assert_array_almost_equal(out, expected)
  1177. @pytest.mark.parametrize('order', range(0, 6))
  1178. def test_rotate05(self, order, xp):
  1179. data = np.empty((4, 3, 3))
  1180. for i in range(3):
  1181. data[:, :, i] = np.asarray([[0, 0, 0],
  1182. [0, 1, 0],
  1183. [0, 1, 0],
  1184. [0, 0, 0]], dtype=np.float64)
  1185. data = xp.asarray(data)
  1186. expected = xp.asarray([[0, 0, 0, 0],
  1187. [0, 1, 1, 0],
  1188. [0, 0, 0, 0]], dtype=xp.float64)
  1189. out = ndimage.rotate(data, 90, order=order)
  1190. for i in range(3):
  1191. assert_array_almost_equal(out[:, :, i], expected)
  1192. @pytest.mark.parametrize('order', range(0, 6))
  1193. def test_rotate06(self, order, xp):
  1194. data = np.empty((3, 4, 3))
  1195. for i in range(3):
  1196. data[:, :, i] = np.asarray([[0, 0, 0, 0],
  1197. [0, 1, 1, 0],
  1198. [0, 0, 0, 0]], dtype=np.float64)
  1199. data = xp.asarray(data)
  1200. expected = xp.asarray([[0, 0, 0],
  1201. [0, 1, 0],
  1202. [0, 1, 0],
  1203. [0, 0, 0]], dtype=xp.float64)
  1204. out = ndimage.rotate(data, 90, order=order)
  1205. for i in range(3):
  1206. assert_array_almost_equal(out[:, :, i], expected)
  1207. @pytest.mark.parametrize('order', range(0, 6))
  1208. def test_rotate07(self, order, xp):
  1209. data = xp.asarray([[[0, 0, 0, 0, 0],
  1210. [0, 1, 1, 0, 0],
  1211. [0, 0, 0, 0, 0]]] * 2, dtype=xp.float64)
  1212. data = xp.permute_dims(data, (2, 1, 0))
  1213. expected = xp.asarray([[[0, 0, 0],
  1214. [0, 1, 0],
  1215. [0, 1, 0],
  1216. [0, 0, 0],
  1217. [0, 0, 0]]] * 2, dtype=xp.float64)
  1218. expected = xp.permute_dims(expected, (2, 1, 0))
  1219. out = ndimage.rotate(data, 90, axes=(0, 1), order=order)
  1220. assert_array_almost_equal(out, expected)
  1221. @pytest.mark.parametrize('order', range(0, 6))
  1222. def test_rotate08(self, order, xp):
  1223. data = xp.asarray([[[0, 0, 0, 0, 0],
  1224. [0, 1, 1, 0, 0],
  1225. [0, 0, 0, 0, 0]]] * 2, dtype=xp.float64)
  1226. data = xp.permute_dims(data, (2, 1, 0)) # == np.transpose
  1227. expected = xp.asarray([[[0, 0, 1, 0, 0],
  1228. [0, 0, 1, 0, 0],
  1229. [0, 0, 0, 0, 0]]] * 2, dtype=xp.float64)
  1230. expected = xp.permute_dims(expected, (2, 1, 0))
  1231. out = ndimage.rotate(data, 90, axes=(0, 1), reshape=False, order=order)
  1232. assert_array_almost_equal(out, expected)
  1233. def test_rotate09(self, xp):
  1234. data = xp.asarray([[0, 0, 0, 0, 0],
  1235. [0, 1, 1, 0, 0],
  1236. [0, 0, 0, 0, 0]] * 2, dtype=xp.float64)
  1237. with assert_raises(ValueError):
  1238. ndimage.rotate(data, 90, axes=(0, data.ndim))
  1239. def test_rotate10(self, xp):
  1240. data = xp.reshape(xp.arange(45, dtype=xp.float64), (3, 5, 3))
  1241. # The output of ndimage.rotate before refactoring
  1242. expected = xp.asarray([[[0.0, 0.0, 0.0],
  1243. [0.0, 0.0, 0.0],
  1244. [6.54914793, 7.54914793, 8.54914793],
  1245. [10.84520162, 11.84520162, 12.84520162],
  1246. [0.0, 0.0, 0.0]],
  1247. [[6.19286575, 7.19286575, 8.19286575],
  1248. [13.4730712, 14.4730712, 15.4730712],
  1249. [21.0, 22.0, 23.0],
  1250. [28.5269288, 29.5269288, 30.5269288],
  1251. [35.80713425, 36.80713425, 37.80713425]],
  1252. [[0.0, 0.0, 0.0],
  1253. [31.15479838, 32.15479838, 33.15479838],
  1254. [35.45085207, 36.45085207, 37.45085207],
  1255. [0.0, 0.0, 0.0],
  1256. [0.0, 0.0, 0.0]]], dtype=xp.float64)
  1257. out = ndimage.rotate(data, angle=12, reshape=False)
  1258. #assert_array_almost_equal(out, expected)
  1259. xp_assert_close(out, expected, rtol=1e-6, atol=2e-6)
  1260. @xfail_xp_backends("cupy", reason="https://github.com/cupy/cupy/issues/8400")
  1261. def test_rotate_exact_180(self, xp):
  1262. a = xp.asarray(np.tile(np.arange(5), (5, 1)))
  1263. b = ndimage.rotate(ndimage.rotate(a, 180), -180)
  1264. xp_assert_equal(a, b)