Esempio n. 1
0
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)
Esempio n. 2
0
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.dspace)

    with pytest.raises(TypeError):
        DiscreteFourierTransform(dom, dom.dspace)

    # 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)
Esempio n. 3
0
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)
Esempio n. 4
0
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)
Esempio n. 5
0
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
Esempio n. 6
0
def test_idft_init(impl):
    # Just check if the code runs at all; this uses the init function of
    # DiscreteFourierTransform, so we don't need exhaustive tests here
    shape = (4, 5)
    ran = odl.discr_sequence_space(shape, dtype="complex128")
    ran_hc = odl.discr_sequence_space(shape, dtype="float64")
    dom = odl.discr_sequence_space(shape, dtype="complex128")
    dom_hc = odl.discr_sequence_space((3, 5), dtype="complex128")

    # Implicit range
    DiscreteFourierTransformInverse(dom, impl=impl)

    # Explicit range
    DiscreteFourierTransformInverse(ran, domain=dom, impl=impl)
    DiscreteFourierTransformInverse(ran_hc, domain=dom_hc, axes=(0,), impl=impl, halfcomplex=True)
Esempio n. 7
0
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
Esempio n. 8
0
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)
Esempio n. 9
0
def test_idft_init(impl):
    # Just check if the code runs at all; this uses the init function of
    # DiscreteFourierTransform, so we don't need exhaustive tests here
    shape = (4, 5)
    ran = odl.discr_sequence_space(shape, dtype='complex128')
    ran_hc = odl.discr_sequence_space(shape, dtype='float64')
    dom = odl.discr_sequence_space(shape, dtype='complex128')
    dom_hc = odl.discr_sequence_space((3, 5), dtype='complex128')

    # Implicit range
    DiscreteFourierTransformInverse(dom, impl=impl)

    # Explicit range
    DiscreteFourierTransformInverse(ran, domain=dom, impl=impl)
    DiscreteFourierTransformInverse(ran_hc,
                                    domain=dom_hc,
                                    axes=(0, ),
                                    impl=impl,
                                    halfcomplex=True)
Esempio n. 10
0
def _grouped_and_flat_arrays(shapes, dtype):
    """Return a grouped and flat list of arrays with specified shapes.

    The lists are constructed as if they were used in a wavelet transform,
    i.e. the array with shape ``shapes[0]`` appears once, while the
    others appear ``2 ** ndim - 1`` times each.
    """
    space = odl.discr_sequence_space(shape=shapes[0], dtype=dtype)
    array = noise_array(space).reshape(space.shape)
    grouped_list = [array]
    flat_list = [array.ravel()]
    ndim = space.ndim

    for shape in shapes[1:]:
        space = odl.discr_sequence_space(shape=shape, dtype=dtype)
        arrays = [noise_array(space).reshape(shape)
                  for _ in range(2 ** ndim - 1)]
        grouped_list.append(tuple(arrays))
        flat_list.extend([arr.ravel() for arr in arrays])

    return grouped_list, flat_list
Esempio n. 11
0
def _grouped_and_flat_arrays(shapes, dtype):
    """Return a grouped and flat list of arrays with specified shapes.

    The lists are constructed as if they were used in a wavelet transform,
    i.e. the array with shape ``shapes[0]`` appears once, while the
    others appear ``2 ** ndim - 1`` times each.
    """
    space = odl.discr_sequence_space(shape=shapes[0], dtype=dtype)
    array = noise_array(space).reshape(space.shape)
    grouped_list = [array]
    flat_list = [array.ravel()]
    ndim = space.ndim

    for shape in shapes[1:]:
        space = odl.discr_sequence_space(shape=shape, dtype=dtype)
        arrays = [noise_array(space).reshape(shape)
                  for _ in range(2 ** ndim - 1)]
        grouped_list.append(tuple(arrays))
        flat_list.extend([arr.ravel() for arr in arrays])

    return grouped_list, flat_list
Esempio n. 12
0
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)
Esempio n. 13
0
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
Esempio n. 14
0
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
Esempio n. 15
0
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
Esempio n. 16
0
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