def test_dft_call(impl): # 2d, complex, all ones and random back & forth shape = (4, 5) dft_dom = odl.discr_sequence_space(shape, dtype="complex64") dft = DiscreteFourierTransform(domain=dft_dom, impl=impl) idft = DiscreteFourierTransformInverse(range=dft_dom, impl=impl) assert dft.domain == idft.range assert dft.range == idft.domain one = dft.domain.one() one_dft1 = dft(one, flags=("FFTW_ESTIMATE",)) one_dft2 = dft.inverse.inverse(one, flags=("FFTW_ESTIMATE",)) one_dft3 = dft.adjoint.adjoint(one, flags=("FFTW_ESTIMATE",)) true_dft = [[20, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] # along all axes by default assert np.allclose(one_dft1, true_dft) assert np.allclose(one_dft2, true_dft) assert np.allclose(one_dft3, true_dft) one_idft1 = idft(one_dft1, flags=("FFTW_ESTIMATE",)) one_idft2 = dft.inverse(one_dft1, flags=("FFTW_ESTIMATE",)) one_idft3 = dft.adjoint(one_dft1, flags=("FFTW_ESTIMATE",)) assert np.allclose(one_idft1, one) assert np.allclose(one_idft2, one) assert np.allclose(one_idft3, one) rand_arr = noise_element(dft_dom) rand_arr_dft = dft(rand_arr, flags=("FFTW_ESTIMATE",)) rand_arr_idft = idft(rand_arr_dft, flags=("FFTW_ESTIMATE",)) assert (rand_arr_idft - rand_arr).norm() < 1e-6 # 2d, halfcomplex, first axis shape = (4, 5) axes = 0 dft_dom = odl.discr_sequence_space(shape, dtype="float32") dft = DiscreteFourierTransform(domain=dft_dom, impl=impl, halfcomplex=True, axes=axes) idft = DiscreteFourierTransformInverse(range=dft_dom, impl=impl, halfcomplex=True, axes=axes) assert dft.domain == idft.range assert dft.range == idft.domain one = dft.domain.one() one_dft = dft(one, flags=("FFTW_ESTIMATE",)) true_dft = [[4, 4, 4, 4, 4], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]] # transform axis shortened assert np.allclose(one_dft, true_dft) one_idft1 = idft(one_dft, flags=("FFTW_ESTIMATE",)) one_idft2 = dft.inverse(one_dft, flags=("FFTW_ESTIMATE",)) assert np.allclose(one_idft1, one) assert np.allclose(one_idft2, one) rand_arr = noise_element(dft_dom) rand_arr_dft = dft(rand_arr, flags=("FFTW_ESTIMATE",)) rand_arr_idft = idft(rand_arr_dft, flags=("FFTW_ESTIMATE",)) assert (rand_arr_idft - rand_arr).norm() < 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_dft_range(): # 1d shape = 10 dom = odl.discr_sequence_space(shape, dtype='complex128') fft = DiscreteFourierTransform(dom) true_ran = odl.discr_sequence_space(shape, dtype='complex128') assert fft.range == true_ran # 3d shape = (3, 4, 5) ran = odl.discr_sequence_space(shape, dtype='complex64') fft = DiscreteFourierTransform(ran) true_ran = odl.discr_sequence_space(shape, dtype='complex64') assert fft.range == true_ran # 3d, with axes and halfcomplex shape = (3, 4, 5) axes = (-1, -2) ran_shape = (3, 3, 5) dom = odl.discr_sequence_space(shape, dtype='float32') fft = DiscreteFourierTransform(dom, axes=axes, halfcomplex=True) true_ran = odl.discr_sequence_space(ran_shape, dtype='complex64') assert fft.range == true_ran
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_dft_init_plan(impl): # 2d, halfcomplex, first axis shape = (4, 5) axes = 0 dft_dom = odl.discr_sequence_space(shape, dtype="float32") dft = DiscreteFourierTransform(dft_dom, impl=impl, axes=axes, halfcomplex=True) if impl != "pyfftw": with pytest.raises(ValueError): dft.init_fftw_plan() with pytest.raises(ValueError): dft.clear_fftw_plan() else: dft.init_fftw_plan() # Make sure plan can be used dft._fftw_plan(dft.domain.element().asarray(), dft.range.element().asarray()) dft.clear_fftw_plan() assert dft._fftw_plan is None
def test_dft_init_raise(): # Test different error scenarios shape = (4, 5) dom = odl.discr_sequence_space(shape) dom_f32 = odl.discr_sequence_space(shape, dtype='float32') # Bad types with pytest.raises(TypeError): DiscreteFourierTransform(dom.tspace) with pytest.raises(TypeError): DiscreteFourierTransform(dom, dom.tspace) # Illegal arguments with pytest.raises(ValueError): DiscreteFourierTransform(dom, impl='fftw') with pytest.raises(ValueError): DiscreteFourierTransform(dom, axes=(1, 2)) with pytest.raises(ValueError): DiscreteFourierTransform(dom, axes=(1, -3)) # Badly shaped range bad_ran = odl.discr_sequence_space((3, 5), dtype='complex128') with pytest.raises(ValueError): DiscreteFourierTransform(dom, bad_ran) bad_ran = odl.discr_sequence_space((10, 10), dtype='complex128') with pytest.raises(ValueError): DiscreteFourierTransform(dom, bad_ran) bad_ran = odl.discr_sequence_space((4, 5), dtype='complex128') with pytest.raises(ValueError): DiscreteFourierTransform(dom, bad_ran, halfcomplex=True) bad_ran = odl.discr_sequence_space((4, 3), dtype='complex128') with pytest.raises(ValueError): DiscreteFourierTransform(dom, bad_ran, halfcomplex=True, axes=(0, )) # Bad data types bad_ran = odl.discr_sequence_space(shape, dtype='complex64') with pytest.raises(ValueError): DiscreteFourierTransform(dom, bad_ran) bad_ran = odl.discr_sequence_space(shape, dtype='float64') with pytest.raises(ValueError): DiscreteFourierTransform(dom, bad_ran) bad_ran = odl.discr_sequence_space((4, 3), dtype='float64') with pytest.raises(ValueError): DiscreteFourierTransform(dom, bad_ran, halfcomplex=True) bad_ran = odl.discr_sequence_space((4, 3), dtype='complex128') with pytest.raises(ValueError): DiscreteFourierTransform(dom_f32, bad_ran, halfcomplex=True) # Bad sign with pytest.raises(ValueError): DiscreteFourierTransform(dom, sign=-1)
def test_dft_init(impl): # Just check if the code runs at all shape = (4, 5) dom = odl.discr_sequence_space(shape) dom_nonseq = odl.uniform_discr([0, 0], [1, 1], shape) dom_f32 = odl.discr_sequence_space(shape, dtype='float32') ran = odl.discr_sequence_space(shape, dtype='complex128') ran_c64 = odl.discr_sequence_space(shape, dtype='complex64') ran_hc = odl.discr_sequence_space((3, 5), dtype='complex128') # Implicit range DiscreteFourierTransform(dom, impl=impl) DiscreteFourierTransform(dom_nonseq, impl=impl) DiscreteFourierTransform(dom_f32, impl=impl) DiscreteFourierTransform(dom, axes=(0, ), impl=impl) DiscreteFourierTransform(dom, axes=(0, -1), impl=impl) DiscreteFourierTransform(dom, axes=(0, ), halfcomplex=True, impl=impl) DiscreteFourierTransform(dom, impl=impl, sign='+') # Explicit range DiscreteFourierTransform(dom, range=ran, impl=impl) DiscreteFourierTransform(dom_f32, range=ran_c64, impl=impl) DiscreteFourierTransform(dom, range=ran, axes=(0, ), impl=impl) DiscreteFourierTransform(dom, range=ran, axes=(0, ), impl=impl, sign='+') DiscreteFourierTransform(dom, range=ran, axes=(0, -1), impl=impl) DiscreteFourierTransform(dom, range=ran_hc, axes=(0, ), impl=impl, halfcomplex=True)
def test_dft_init_plan(impl): # 2d, halfcomplex, first axis shape = (4, 5) axes = 0 dft_dom = odl.discr_sequence_space(shape, dtype='float32') dft = DiscreteFourierTransform(dft_dom, impl=impl, axes=axes, halfcomplex=True) if impl != 'pyfftw': with pytest.raises(ValueError): dft.init_fftw_plan() with pytest.raises(ValueError): dft.clear_fftw_plan() else: dft.init_fftw_plan() # Make sure plan can be used dft._fftw_plan(dft.domain.element().asarray(), dft.range.element().asarray()) dft.clear_fftw_plan() assert dft._fftw_plan is None
def test_dft_call(impl): # 2d, complex, all ones and random back & forth shape = (4, 5) dft_dom = odl.discr_sequence_space(shape, dtype='complex64') dft = DiscreteFourierTransform(domain=dft_dom, impl=impl) idft = DiscreteFourierTransformInverse(range=dft_dom, impl=impl) assert dft.domain == idft.range assert dft.range == idft.domain one = dft.domain.one() one_dft1 = dft(one, flags=('FFTW_ESTIMATE', )) one_dft2 = dft.inverse.inverse(one, flags=('FFTW_ESTIMATE', )) one_dft3 = dft.adjoint.adjoint(one, flags=('FFTW_ESTIMATE', )) true_dft = [ [20, 0, 0, 0, 0], # along all axes by default [0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] ] assert np.allclose(one_dft1, true_dft) assert np.allclose(one_dft2, true_dft) assert np.allclose(one_dft3, true_dft) one_idft1 = idft(one_dft1, flags=('FFTW_ESTIMATE', )) one_idft2 = dft.inverse(one_dft1, flags=('FFTW_ESTIMATE', )) one_idft3 = dft.adjoint(one_dft1, flags=('FFTW_ESTIMATE', )) assert np.allclose(one_idft1, one) assert np.allclose(one_idft2, one) assert np.allclose(one_idft3, one) rand_arr = noise_element(dft_dom) rand_arr_dft = dft(rand_arr, flags=('FFTW_ESTIMATE', )) rand_arr_idft = idft(rand_arr_dft, flags=('FFTW_ESTIMATE', )) assert (rand_arr_idft - rand_arr).norm() < 1e-6 # 2d, halfcomplex, first axis shape = (4, 5) axes = 0 dft_dom = odl.discr_sequence_space(shape, dtype='float32') dft = DiscreteFourierTransform(domain=dft_dom, impl=impl, halfcomplex=True, axes=axes) idft = DiscreteFourierTransformInverse(range=dft_dom, impl=impl, halfcomplex=True, axes=axes) assert dft.domain == idft.range assert dft.range == idft.domain one = dft.domain.one() one_dft = dft(one, flags=('FFTW_ESTIMATE', )) true_dft = [ [4, 4, 4, 4, 4], # transform axis shortened [0, 0, 0, 0, 0], [0, 0, 0, 0, 0] ] assert np.allclose(one_dft, true_dft) one_idft1 = idft(one_dft, flags=('FFTW_ESTIMATE', )) one_idft2 = dft.inverse(one_dft, flags=('FFTW_ESTIMATE', )) assert np.allclose(one_idft1, one) assert np.allclose(one_idft2, one) rand_arr = noise_element(dft_dom) rand_arr_dft = dft(rand_arr, flags=('FFTW_ESTIMATE', )) rand_arr_idft = idft(rand_arr_dft, flags=('FFTW_ESTIMATE', )) assert (rand_arr_idft - rand_arr).norm() < 1e-6