def test_theano_operator(): """Test the ODL->Theano operator wrapper.""" # Define ODL operator matrix = np.random.rand(3, 2) odl_op = odl.MatrixOperator(matrix) # Define evaluation points x = [1., 2.] dy = [1., 2., 3.] # Create Theano placeholders x_theano = T.dvector() dy_theano = T.dvector() # Create Theano layer from odl operator odl_op_layer = odl.contrib.theano.TheanoOperator(odl_op) # Build computation graphs y_theano = odl_op_layer(x_theano) y_theano_func = theano.function([x_theano], y_theano) dy_theano_func = theano.function([x_theano, dy_theano], T.Rop(y_theano, x_theano, dy_theano)) # Evaluate using Theano result = y_theano_func(x) expected = odl_op(x) assert all_almost_equal(result, expected) # Evaluate the adjoint of the derivative, called gradient in Theano result = dy_theano_func(x, dy) expected = odl_op.derivative(x).adjoint(dy) assert all_almost_equal(result, expected)
def test_as_tensorflow_layer(): # Define ODL operator matrix = np.random.rand(3, 2) odl_op = odl.MatrixOperator(matrix) # Define evaluation points x = np.random.rand(2) z = np.random.rand(3) # Add empty axes for batch and channel x_tf = tf.constant(x)[None, ..., None] z_tf = tf.constant(z)[None, ..., None] # Create tensorflow layer from odl operator odl_op_layer = odl.contrib.tensorflow.as_tensorflow_layer( odl_op, 'MatrixOperator') y_tf = odl_op_layer(x_tf) # Evaluate using tensorflow result = y_tf.eval().ravel() expected = odl_op(x) assert all_almost_equal(result, expected) # Evaluate the adjoint of the derivative, called gradient in tensorflow result = tf.gradients(y_tf, [x_tf], z_tf)[0].eval().ravel() expected = odl_op.derivative(x).adjoint(z) assert all_almost_equal(result, expected)
def test_reciprocal_grid_nd_axes(): grid = odl.uniform_grid([0] * 3, [1] * 3, shape=(3, 4, 5)) s = grid.stride n = np.array(grid.shape) axes_list = [[1, -1], [0], 0, [0, 2, 1], [2, 0]] for axes in axes_list: active = np.zeros(grid.ndim, dtype=bool) active[axes] = True inactive = np.logical_not(active) true_recip_stride = np.empty(grid.ndim) true_recip_stride[active] = 2 * np.pi / (s[active] * n[active]) true_recip_stride[inactive] = s[inactive] # Without shift altogether rgrid = reciprocal_grid(grid, shift=False, axes=axes, halfcomplex=False) assert all_equal(rgrid.shape, n) assert all_almost_equal(rgrid.stride, true_recip_stride) assert all_almost_equal(rgrid.min_pt[active], -rgrid.max_pt[active]) assert all_equal(rgrid.min_pt[inactive], grid.min_pt[inactive]) assert all_equal(rgrid.max_pt[inactive], grid.max_pt[inactive]) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, axes=axes, halfcomplex=False) assert irgrid.approx_equals(grid, atol=1e-6)
def test_reciprocal_grid_nd_axes(): grid = odl.uniform_sampling([0] * 3, [1] * 3, shape=(3, 4, 5)) s = grid.stride n = np.array(grid.shape) axes_list = [[1, -1], [0], 0, [0, 2, 1], [2, 0]] for axes in axes_list: active = np.zeros(grid.ndim, dtype=bool) active[axes] = True inactive = np.logical_not(active) true_recip_stride = np.empty(grid.ndim) true_recip_stride[active] = 2 * np.pi / (s[active] * n[active]) true_recip_stride[inactive] = s[inactive] # Without shift altogether rgrid = reciprocal_grid(grid, shift=False, axes=axes, halfcomplex=False) assert all_equal(rgrid.shape, n) assert all_almost_equal(rgrid.stride, true_recip_stride) assert all_almost_equal(rgrid.min_pt[active], -rgrid.max_pt[active]) assert all_equal(rgrid.min_pt[inactive], grid.min_pt[inactive]) assert all_equal(rgrid.max_pt[inactive], grid.max_pt[inactive]) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, axes=axes, halfcomplex=False) assert irgrid.approx_equals(grid, atol=1e-6)
def test_pyfftw_call_plan_preserve_input(planning): for shape in [(10,), (3, 4)]: arr = _random_array(shape, dtype='complex128') arr_cpy = arr.copy() idft_scaling = np.prod(shape) true_idft = np.fft.ifftn(arr) * idft_scaling idft_arr = np.empty(shape, dtype='complex128') pyfftw_call(arr, idft_arr, direction='backward', halfcomplex=False, planning=planning) assert all_almost_equal(arr, arr_cpy) # Input perserved assert all_almost_equal(idft_arr, true_idft)
def test_pyfftw_call_backward_with_axes(floating_dtype): if floating_dtype == np.dtype('float16'): # not supported, skipping return halfcomplex, in_dtype = _params_from_dtype(floating_dtype) shape = (3, 4, 5) test_axes = [(0, 1), [1], (-1,), (1, 0), (-1, -2, -3)] for axes in test_axes: # Only the shape indexed by axes count for the scaling active_shape = np.take(shape, axes) idft_scaling = np.prod(active_shape) if halfcomplex: arr = _random_array(_halfcomplex_shape(shape, axes), in_dtype) true_idft = (np.fft.irfftn(arr, s=active_shape, axes=axes) * idft_scaling) else: arr = _random_array(shape, in_dtype) true_idft = (np.fft.ifftn(arr, s=active_shape, axes=axes) * idft_scaling) idft_arr = np.empty(shape, dtype=floating_dtype) pyfftw_call(arr, idft_arr, direction='backward', axes=axes, halfcomplex=halfcomplex) assert all_almost_equal(idft_arr, true_idft)
def test_pyfftw_call_threads(): shape = (3, 4, 5) arr = _random_array(shape, dtype='complex64') true_dft = np.fft.fftn(arr) dft_arr = np.empty(shape, dtype='complex64') pyfftw_call(arr, dft_arr, direction='forward', preserve_input=False, threads=4) assert all_almost_equal(dft_arr, true_dft) shape = (1000,) # Trigger cpu_count() as number of threads arr = _random_array(shape, dtype='complex64') true_dft = np.fft.fftn(arr) dft_arr = np.empty(shape, dtype='complex64') pyfftw_call(arr, dft_arr, direction='forward', preserve_input=False) assert all_almost_equal(dft_arr, true_dft)
def test_reciprocal_grid_nd(): grid = odl.uniform_grid([0] * 3, [1] * 3, shape=(3, 4, 5)) s = grid.stride n = np.array(grid.shape) true_recip_stride = 2 * np.pi / (s * n) # Without shift altogether rgrid = reciprocal_grid(grid, shift=False, halfcomplex=False) assert all_equal(rgrid.shape, n) assert all_almost_equal(rgrid.stride, true_recip_stride) assert all_almost_equal(rgrid.min_pt, -rgrid.max_pt) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, halfcomplex=False) assert irgrid.approx_equals(grid, atol=1e-6)
def test_reciprocal_grid_nd(): grid = odl.uniform_sampling([0] * 3, [1] * 3, shape=(3, 4, 5)) s = grid.stride n = np.array(grid.shape) true_recip_stride = 2 * np.pi / (s * n) # Without shift altogether rgrid = reciprocal_grid(grid, shift=False, halfcomplex=False) assert all_equal(rgrid.shape, n) assert all_almost_equal(rgrid.stride, true_recip_stride) assert all_almost_equal(rgrid.min_pt, -rgrid.max_pt) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, halfcomplex=False) assert irgrid.approx_equals(grid, atol=1e-6)
def test_pyfftw_call_forward_real_not_halfcomplex(): # Test against Numpy's FFT for shape in [(10,), (3, 4, 5)]: arr = _random_array(shape, dtype='float64') true_dft = np.fft.fftn(arr) dft_arr = np.empty(shape, dtype='complex128') pyfftw_call(arr, dft_arr, direction='forward', halfcomplex=False) assert all_almost_equal(dft_arr, true_dft)
def test_pyfftw_call_forward_with_plan(): for shape in [(10,), (3, 4, 5)]: arr = _random_array(shape, dtype='complex128') arr_cpy = arr.copy() true_dft = np.fft.fftn(arr) # First run, create plan dft_arr = np.empty(shape, dtype='complex128') plan = pyfftw_call(arr, dft_arr, direction='forward', halfcomplex=False, planning_effort='measure') # Second run, reuse with fresh output array dft_arr = np.empty(shape, dtype='complex128') pyfftw_call(arr, dft_arr, direction='forward', fftw_plan=plan, halfcomplex=False) assert all_almost_equal(arr, arr_cpy) # Input perserved assert all_almost_equal(dft_arr, true_dft)
def test_reciprocal_grid_nd_shift_list(): grid = odl.uniform_sampling([0] * 3, [1] * 3, shape=(3, 4, 5)) s = grid.stride n = np.array(grid.shape) shift = [False, True, False] true_recip_stride = 2 * np.pi / (s * n) # Shift only the even dimension, then zero must be contained rgrid = reciprocal_grid(grid, shift=shift, halfcomplex=False) noshift = np.where(np.logical_not(shift)) assert all_equal(rgrid.shape, n) assert all_almost_equal(rgrid.stride, true_recip_stride) assert all_almost_equal(rgrid.min_pt[noshift], -rgrid.max_pt[noshift]) assert all_almost_equal(rgrid[n // 2], [0] * 3) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, halfcomplex=False) assert irgrid.approx_equals(grid, atol=1e-6)
def test_reciprocal_grid_nd_shift_list(): grid = odl.uniform_grid([0] * 3, [1] * 3, shape=(3, 4, 5)) s = grid.stride n = np.array(grid.shape) shift = [False, True, False] true_recip_stride = 2 * np.pi / (s * n) # Shift only the even dimension, then zero must be contained rgrid = reciprocal_grid(grid, shift=shift, halfcomplex=False) noshift = np.where(np.logical_not(shift)) assert all_equal(rgrid.shape, n) assert all_almost_equal(rgrid.stride, true_recip_stride) assert all_almost_equal(rgrid.min_pt[noshift], -rgrid.max_pt[noshift]) assert all_almost_equal(rgrid[n // 2], [0] * 3) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, halfcomplex=False) assert irgrid.approx_equals(grid, atol=1e-6)
def test_pyfftw_call_backward_real_not_halfcomplex(): # Test against Numpy's IFFT, no normalization for shape in [(10,), (3, 4, 5)]: # Scaling happens wrt output (large) shape idft_scaling = np.prod(shape) arr = _random_array(shape, dtype='float64') true_idft = np.fft.ifftn(arr) * idft_scaling idft_arr = np.empty(shape, dtype='complex128') pyfftw_call(arr, idft_arr, direction='backward', halfcomplex=False) assert all_almost_equal(idft_arr, true_idft)
def test_dft_preprocess_data_halfcomplex(sign): shape = (2, 3, 4) # With shift correct_arr = [] for i, j, k in product(range(shape[0]), range(shape[1]), range(shape[2])): correct_arr.append(1 - 2 * ((i + j + k) % 2)) arr = np.ones(shape, dtype='float64') preproc = dft_preprocess_data(arr, shift=True, sign=sign) # out-of-place out = np.empty_like(arr) dft_preprocess_data(arr, shift=True, out=out, sign=sign) # in-place dft_preprocess_data(arr, shift=True, out=arr, sign=sign) # in-place assert all_almost_equal(preproc.ravel(), correct_arr) assert all_almost_equal(arr.ravel(), correct_arr) assert all_almost_equal(out.ravel(), correct_arr) # Without shift imag = 1j if sign == '-' else -1j correct_arr = [] for i, j, k in product(range(shape[0]), range(shape[1]), range(shape[2])): argsum = sum((idx * (1 - 1 / shp)) for idx, shp in zip((i, j, k), shape)) correct_arr.append(np.exp(imag * np.pi * argsum)) arr = np.ones(shape, dtype='float64') preproc = dft_preprocess_data(arr, shift=False, sign=sign) assert all_almost_equal(preproc.ravel(), correct_arr) # Non-float input works, too arr = np.ones(shape, dtype='int') preproc = dft_preprocess_data(arr, shift=False, sign=sign) assert all_almost_equal(preproc.ravel(), correct_arr) # In-place modification not possible for float array and no shift arr = np.ones(shape, dtype='float64') with pytest.raises(ValueError): dft_preprocess_data(arr, shift=False, out=arr, sign=sign)
def test_reciprocal_grid_1d(halfcomplex, shift, parity): shape = 10 if parity == 'even' else 11 grid = odl.uniform_grid(0, 1, shape=shape) s = grid.stride n = np.array(grid.shape) rgrid = reciprocal_grid(grid, shift=shift, halfcomplex=halfcomplex) # Independent of halfcomplex, shift and parity true_recip_stride = 2 * np.pi / (s * n) assert all_almost_equal(rgrid.stride, true_recip_stride) if halfcomplex: assert all_equal(rgrid.shape, n // 2 + 1) if parity == 'odd' and shift: # Max point should be half a negative recip stride assert all_almost_equal(rgrid.max_pt, -true_recip_stride / 2) elif parity == 'even' and not shift: # Max point should be half a positive recip stride assert all_almost_equal(rgrid.max_pt, true_recip_stride / 2) elif (parity == 'odd' and not shift) or (parity == 'even' and shift): # Max should be zero assert all_almost_equal(rgrid.max_pt, 0) else: raise RuntimeError('parameter combination not covered') else: # halfcomplex = False assert all_equal(rgrid.shape, n) if (parity == 'even' and shift) or (parity == 'odd' and not shift): # Zero should be at index n // 2 assert all_almost_equal(rgrid[n // 2], 0) elif (parity == 'odd' and shift) or (parity == 'even' and not shift): # No point should be closer to 0 than half a recip stride atol = 0.999 * true_recip_stride / 2 assert not rgrid.approx_contains(0, atol=atol) else: raise RuntimeError('parameter combination not covered') if not shift: # Grid Should be symmetric assert all_almost_equal(rgrid.min_pt, -rgrid.max_pt) if parity == 'odd': # Midpoint should be 0 assert all_almost_equal(rgrid.mid_pt, 0) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, halfcomplex=halfcomplex, halfcx_parity=parity) assert irgrid.approx_equals(grid, atol=1e-6)
def test_dft_preprocess_data_with_axes(sign): shape = (2, 3, 4) axes = 1 # Only middle index counts correct_arr = [] for _, j, __ in product(range(shape[0]), range(shape[1]), range(shape[2])): correct_arr.append(1 - 2 * (j % 2)) arr = np.ones(shape, dtype='complex64') dft_preprocess_data(arr, shift=True, axes=axes, out=arr, sign=sign) assert all_almost_equal(arr.ravel(), correct_arr) axes = [0, -1] # First and last correct_arr = [] for i, _, k in product(range(shape[0]), range(shape[1]), range(shape[2])): correct_arr.append(1 - 2 * ((i + k) % 2)) arr = np.ones(shape, dtype='complex64') dft_preprocess_data(arr, shift=True, axes=axes, out=arr, sign=sign) assert all_almost_equal(arr.ravel(), correct_arr)
def test_dft_preprocess_data(sign): shape = (2, 3, 4) # With shift correct_arr = [] for i, j, k in product(range(shape[0]), range(shape[1]), range(shape[2])): correct_arr.append((1 + 1j) * (1 - 2 * ((i + j + k) % 2))) arr = np.ones(shape, dtype='complex64') * (1 + 1j) preproc = dft_preprocess_data(arr, shift=True, sign=sign) # out-of-place dft_preprocess_data(arr, shift=True, out=arr, sign=sign) # in-place assert all_almost_equal(preproc.ravel(), correct_arr) assert all_almost_equal(arr.ravel(), correct_arr) # Without shift imag = 1j if sign == '-' else -1j correct_arr = [] for i, j, k in product(range(shape[0]), range(shape[1]), range(shape[2])): argsum = sum((idx * (1 - 1 / shp)) for idx, shp in zip((i, j, k), shape)) correct_arr.append((1 + 1j) * np.exp(imag * np.pi * argsum)) arr = np.ones(shape, dtype='complex64') * (1 + 1j) dft_preprocess_data(arr, shift=False, out=arr, sign=sign) assert all_almost_equal(arr.ravel(), correct_arr) # Bad input with pytest.raises(ValueError): dft_preprocess_data(arr, out=arr, sign=1) arr = np.zeros(shape, dtype='S2') with pytest.raises(ValueError): dft_preprocess_data(arr)
def test_fourier_trafo_inverse(impl, sign): # Test if the inverse really is the inverse def char_interval(x): return (x >= 0) & (x <= 1) # Complex-to-complex discr = odl.uniform_discr(-2, 2, 40, impl='numpy', dtype='complex64') discr_char = discr.element(char_interval) ft = FourierTransform(discr, sign=sign, impl=impl) assert all_almost_equal(ft.inverse(ft(char_interval)), discr_char) assert all_almost_equal(ft.adjoint(ft(char_interval)), discr_char) # Half-complex discr = odl.uniform_discr(-2, 2, 40, impl='numpy', dtype='float32') ft = FourierTransform(discr, impl=impl, halfcomplex=True) assert all_almost_equal(ft.inverse(ft(char_interval)), discr_char) def char_rect(x): return (x[0] >= 0) & (x[0] <= 1) & (x[1] >= 0) & (x[1] <= 1) # 2D with axes, C2C discr = odl.uniform_discr([-2, -2], [2, 2], (20, 10), impl='numpy', dtype='complex64') discr_rect = discr.element(char_rect) for axes in [(0, ), 1]: ft = FourierTransform(discr, sign=sign, impl=impl, axes=axes) assert all_almost_equal(ft.inverse(ft(char_rect)), discr_rect) assert all_almost_equal(ft.adjoint(ft(char_rect)), discr_rect) # 2D with axes, halfcomplex discr = odl.uniform_discr([-2, -2], [2, 2], (20, 10), impl='numpy', dtype='float32') discr_rect = discr.element(char_rect) for halfcomplex in [False, True]: if halfcomplex and sign == '+': continue # cannot mix halfcomplex with sign for axes in [(0, ), (1, )]: ft = FourierTransform(discr, sign=sign, impl=impl, axes=axes, halfcomplex=halfcomplex) assert all_almost_equal(ft.inverse(ft(char_rect)), discr_rect) assert all_almost_equal(ft.adjoint(ft(char_rect)), discr_rect)
def test_reciprocal_grid_1d(halfcomplex, shift, parity): shape = 10 if parity == 'even' else 11 grid = odl.uniform_sampling(0, 1, shape=shape) s = grid.stride n = np.array(grid.shape) rgrid = reciprocal_grid(grid, shift=shift, halfcomplex=halfcomplex) # Independent of halfcomplex, shift and parity true_recip_stride = 2 * np.pi / (s * n) assert all_almost_equal(rgrid.stride, true_recip_stride) if halfcomplex: assert all_equal(rgrid.shape, n // 2 + 1) if parity == 'odd' and shift: # Max point should be half a negative recip stride assert all_almost_equal(rgrid.max_pt, -true_recip_stride / 2) elif parity == 'even' and not shift: # Max point should be half a positive recip stride assert all_almost_equal(rgrid.max_pt, true_recip_stride / 2) elif (parity == 'odd' and not shift) or (parity == 'even' and shift): # Max should be zero assert all_almost_equal(rgrid.max_pt, 0) else: raise RuntimeError('parameter combination not covered') else: # halfcomplex = False assert all_equal(rgrid.shape, n) if (parity == 'even' and shift) or (parity == 'odd' and not shift): # Zero should be at index n // 2 assert all_almost_equal(rgrid[n // 2], 0) elif (parity == 'odd' and shift) or (parity == 'even' and not shift): # No point should be closer to 0 than half a recip stride atol = 0.999 * true_recip_stride / 2 assert not rgrid.approx_contains(0, atol=atol) else: raise RuntimeError('parameter combination not covered') if not shift: # Grid Should be symmetric assert all_almost_equal(rgrid.min_pt, -rgrid.max_pt) if parity == 'odd': # Midpoint should be 0 assert all_almost_equal(rgrid.mid_pt, 0) # Inverting should give back the original irgrid = realspace_grid(rgrid, grid.min_pt, halfcomplex=halfcomplex, halfcx_parity=parity) assert irgrid.approx_equals(grid, atol=1e-6)
def test_dft_sign(impl): # Test if the FT sign behaves as expected, i.e. that the FT with sign # '+' and '-' have same real parts and opposite imaginary parts. # 2d, complex, all ones and random back & forth shape = (4, 5) dft_dom = odl.discr_sequence_space(shape, dtype='complex64') dft_minus = DiscreteFourierTransform(domain=dft_dom, impl=impl, sign='-') dft_plus = DiscreteFourierTransform(domain=dft_dom, impl=impl, sign='+') arr = dft_dom.element([[0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0]]) arr_dft_minus = dft_minus(arr, flags=('FFTW_ESTIMATE', )) arr_dft_plus = dft_plus(arr, flags=('FFTW_ESTIMATE', )) assert all_almost_equal(arr_dft_minus.real, arr_dft_plus.real) assert all_almost_equal(arr_dft_minus.imag, -arr_dft_plus.imag) assert all_almost_equal(dft_minus.inverse(arr_dft_minus), arr) assert all_almost_equal(dft_plus.inverse(arr_dft_plus), arr) assert all_almost_equal(dft_minus.inverse.inverse(arr), dft_minus(arr)) assert all_almost_equal(dft_plus.inverse.inverse(arr), dft_plus(arr)) # 2d, halfcomplex, first axis shape = (4, 5) axes = (0, ) dft_dom = odl.discr_sequence_space(shape, dtype='float32') arr = dft_dom.element([[0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0]]) dft = DiscreteFourierTransform(domain=dft_dom, impl=impl, halfcomplex=True, sign='-', axes=axes) arr_dft_minus = dft(arr, flags=('FFTW_ESTIMATE', )) arr_idft_minus = dft.inverse(arr_dft_minus, flags=('FFTW_ESTIMATE', )) assert all_almost_equal(arr_idft_minus, arr) with pytest.raises(ValueError): DiscreteFourierTransform(domain=dft_dom, impl=impl, halfcomplex=True, sign='+', axes=axes)
def test_fourier_trafo_inverse(impl, sign): # Test if the inverse really is the inverse def char_interval(x): return (x >= 0) & (x <= 1) # Complex-to-complex discr = odl.uniform_discr(-2, 2, 40, impl="numpy", dtype="complex64") discr_char = discr.element(char_interval) ft = FourierTransform(discr, sign=sign, impl=impl) assert all_almost_equal(ft.inverse(ft(char_interval)), discr_char) assert all_almost_equal(ft.adjoint(ft(char_interval)), discr_char) # Half-complex discr = odl.uniform_discr(-2, 2, 40, impl="numpy", dtype="float32") ft = FourierTransform(discr, impl=impl, halfcomplex=True) assert all_almost_equal(ft.inverse(ft(char_interval)), discr_char) def char_rect(x): return (x[0] >= 0) & (x[0] <= 1) & (x[1] >= 0) & (x[1] <= 1) # 2D with axes, C2C discr = odl.uniform_discr([-2, -2], [2, 2], (20, 10), impl="numpy", dtype="complex64") discr_rect = discr.element(char_rect) for axes in [(0,), 1]: ft = FourierTransform(discr, sign=sign, impl=impl, axes=axes) assert all_almost_equal(ft.inverse(ft(char_rect)), discr_rect) assert all_almost_equal(ft.adjoint(ft(char_rect)), discr_rect) # 2D with axes, halfcomplex discr = odl.uniform_discr([-2, -2], [2, 2], (20, 10), impl="numpy", dtype="float32") discr_rect = discr.element(char_rect) for halfcomplex in [False, True]: if halfcomplex and sign == "+": continue # cannot mix halfcomplex with sign for axes in [(0,), (1,)]: ft = FourierTransform(discr, sign=sign, impl=impl, axes=axes, halfcomplex=halfcomplex) assert all_almost_equal(ft.inverse(ft(char_rect)), discr_rect) assert all_almost_equal(ft.adjoint(ft(char_rect)), discr_rect)
def test_pyfftw_call_forward(floating_dtype): # Test against Numpy's FFT if floating_dtype == np.dtype('float16'): # not supported, skipping return halfcomplex, out_dtype = _params_from_dtype(floating_dtype) for shape in [(10,), (3, 4, 5)]: arr = _random_array(shape, floating_dtype) if halfcomplex: true_dft = np.fft.rfftn(arr) dft_arr = np.empty(_halfcomplex_shape(shape), dtype=out_dtype) else: true_dft = np.fft.fftn(arr) dft_arr = np.empty(shape, dtype=out_dtype) pyfftw_call(arr, dft_arr, direction='forward', halfcomplex=halfcomplex, preserve_input=False) assert all_almost_equal(dft_arr, true_dft)
def test_pyfftw_call_forward_with_axes(floating_dtype): if floating_dtype == np.dtype('float16'): # not supported, skipping return halfcomplex, out_dtype = _params_from_dtype(floating_dtype) shape = (3, 4, 5) test_axes = [(0, 1), [1], (-1,), (1, 0), (-1, -2, -3)] for axes in test_axes: arr = _random_array(shape, floating_dtype) if halfcomplex: true_dft = np.fft.rfftn(arr, axes=axes) dft_arr = np.empty(_halfcomplex_shape(shape, axes), dtype=out_dtype) else: true_dft = np.fft.fftn(arr, axes=axes) dft_arr = np.empty(shape, dtype=out_dtype) pyfftw_call(arr, dft_arr, direction='forward', axes=axes, halfcomplex=halfcomplex) assert all_almost_equal(dft_arr, true_dft)
def test_pyfftw_call_backward(floating_dtype): # Test against Numpy's IFFT, no normalization if floating_dtype == np.dtype('float16'): # not supported, skipping return halfcomplex, in_dtype = _params_from_dtype(floating_dtype) for shape in [(10,), (3, 4, 5)]: # Scaling happens wrt output (large) shape idft_scaling = np.prod(shape) if halfcomplex: arr = _random_array(_halfcomplex_shape(shape), in_dtype) true_idft = np.fft.irfftn(arr, shape) * idft_scaling else: arr = _random_array(shape, in_dtype) true_idft = np.fft.ifftn(arr) * idft_scaling idft_arr = np.empty(shape, dtype=floating_dtype) pyfftw_call(arr, idft_arr, direction='backward', halfcomplex=halfcomplex) assert all_almost_equal(idft_arr, true_idft)
def test_theano_gradient(): """Test the gradient of ODL functionals wrapped as Theano Ops.""" # Define ODL operator matrix = np.random.rand(3, 2) odl_op = odl.MatrixOperator(matrix) # Define evaluation point x = [1., 2.] # Define ODL cost and the composed functional odl_cost = odl.solvers.L2NormSquared(odl_op.range) odl_functional = odl_cost * odl_op # Create Theano placeholder x_theano = T.dvector() # Create Theano layers from odl operators odl_op_layer = odl.contrib.theano.TheanoOperator(odl_op) odl_cost_layer = odl.contrib.theano.TheanoOperator(odl_cost) # Build computation graph y_theano = odl_op_layer(x_theano) cost_theano = odl_cost_layer(y_theano) cost_theano_func = theano.function([x_theano], cost_theano) cost_grad_theano = T.grad(cost_theano, x_theano) cost_grad_theano_func = theano.function([x_theano], cost_grad_theano) # Evaluate using Theano result = cost_theano_func(x) expected = odl_functional(x) assert result == pytest.approx(expected) # Evaluate the gradient of the cost, should be 2 * matrix^T.dot(x) result = cost_grad_theano_func(x) expected = odl_functional.gradient(x) assert all_almost_equal(result, expected)
def test_dft_sign(impl): # Test if the FT sign behaves as expected, i.e. that the FT with sign # '+' and '-' have same real parts and opposite imaginary parts. # 2d, complex, all ones and random back & forth shape = (4, 5) dft_dom = odl.discr_sequence_space(shape, dtype="complex64") dft_minus = DiscreteFourierTransform(domain=dft_dom, impl=impl, sign="-") dft_plus = DiscreteFourierTransform(domain=dft_dom, impl=impl, sign="+") arr = dft_dom.element([[0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0]]) arr_dft_minus = dft_minus(arr, flags=("FFTW_ESTIMATE",)) arr_dft_plus = dft_plus(arr, flags=("FFTW_ESTIMATE",)) assert all_almost_equal(arr_dft_minus.real, arr_dft_plus.real) assert all_almost_equal(arr_dft_minus.imag, -arr_dft_plus.imag) assert all_almost_equal(dft_minus.inverse(arr_dft_minus), arr) assert all_almost_equal(dft_plus.inverse(arr_dft_plus), arr) assert all_almost_equal(dft_minus.inverse.inverse(arr), dft_minus(arr)) assert all_almost_equal(dft_plus.inverse.inverse(arr), dft_plus(arr)) # 2d, halfcomplex, first axis shape = (4, 5) axes = (0,) dft_dom = odl.discr_sequence_space(shape, dtype="float32") arr = dft_dom.element([[0, 0, 0, 0, 0], [0, 0, 1, 1, 0], [0, 0, 1, 1, 0], [0, 0, 0, 0, 0]]) dft = DiscreteFourierTransform(domain=dft_dom, impl=impl, halfcomplex=True, sign="-", axes=axes) arr_dft_minus = dft(arr, flags=("FFTW_ESTIMATE",)) arr_idft_minus = dft.inverse(arr_dft_minus, flags=("FFTW_ESTIMATE",)) assert all_almost_equal(arr_idft_minus, arr) with pytest.raises(ValueError): DiscreteFourierTransform(domain=dft_dom, impl=impl, halfcomplex=True, sign="+", axes=axes)