Esempio n. 1
0
def test_functional_composition(space):
    """Test composition from the right with an operator."""
    # Less strict checking for single precision
    places = 3 if space.dtype == np.float32 else 5

    func = odl.solvers.L2NormSquared(space)

    # Verify that an error is raised if an invalid operator is used
    # (e.g. wrong range)
    scalar = 2.1
    wrong_space = odl.uniform_discr(1, 2, 10)
    op_wrong = odl.operator.ScalingOperator(wrong_space, scalar)

    with pytest.raises(OpTypeError):
        func * op_wrong

    # Test composition with operator from the right
    op = odl.operator.ScalingOperator(space, scalar)
    func_op_comp = func * op
    assert isinstance(func_op_comp, odl.solvers.Functional)

    x = noise_element(space)
    assert almost_equal(func_op_comp(x), func(op(x)), places=places)

    # Test gradient and derivative with composition from the right
    assert all_almost_equal(func_op_comp.gradient(x),
                            (op.adjoint * func.gradient * op)(x),
                            places=places)

    p = noise_element(space)
    assert all_almost_equal(func_op_comp.derivative(x)(p),
                            (op.adjoint * func.gradient * op)(x).inner(p),
                            places=places)
Esempio n. 2
0
def test_arithmetic():
    """Test that all standard arithmetic works."""
    space = odl.rn(3)

    # Create elements needed for later
    functional = odl.solvers.L2Norm(space).translated([1, 2, 3])
    functional2 = odl.solvers.L2NormSquared(space)
    operator = odl.IdentityOperator(space) - space.element([4, 5, 6])
    x = noise_element(functional.domain)
    y = noise_element(functional.domain)
    scalar = np.pi

    # Simple tests here, more in depth comes later
    assert functional(x) == functional(x)
    assert functional(x) != functional2(x)
    assert (scalar * functional)(x) == scalar * functional(x)
    assert (scalar * (scalar * functional))(x) == scalar**2 * functional(x)
    assert (functional * scalar)(x) == functional(scalar * x)
    assert ((functional * scalar) * scalar)(x) == functional(scalar**2 * x)
    assert (functional + functional2)(x) == functional(x) + functional2(x)
    assert (functional - functional2)(x) == functional(x) - functional2(x)
    assert (functional * operator)(x) == functional(operator(x))
    assert all_almost_equal((y * functional)(x), y * functional(x))
    assert all_almost_equal((y * (y * functional))(x), (y * y) * functional(x))
    assert all_almost_equal((functional * y)(x), functional(y * x))
    assert all_almost_equal(((functional * y) * y)(x), functional((y * y) * x))
def test_proximal_convconj_kl_cross_entropy():
    """Test for proximal of convex conjugate of cross entropy KL divergence."""

    # Image space
    space = odl.uniform_discr(0, 1, 10)

    # Data
    g = space.element(np.arange(10, 0, -1))

    # Factory function returning the proximal operator
    lam = 2
    prox_factory = proximal_cconj_kl_cross_entropy(space, lam=lam, g=g)

    # Initialize the proximal operator of F^*
    sigma = 0.25
    prox = prox_factory(sigma)

    assert isinstance(prox, odl.Operator)

    # Element in image space where the proximal operator is evaluated
    x = space.element(np.arange(-5, 5))

    prox_val = prox(x)

    # Explicit computation:
    x_verify = x - lam * scipy.special.lambertw(
        sigma / lam * g * np.exp(x / lam))

    assert all_almost_equal(prox_val, x_verify, HIGH_ACC)

    # Test in-place evaluation
    x_inplace = space.element()
    prox(x, out=x_inplace)

    assert all_almost_equal(x_inplace, x_verify, HIGH_ACC)
Esempio n. 4
0
def test_ufuncs():
    # Cannot use fixture due to bug in pytest
    H = odl.ProductSpace(odl.Rn(1), odl.Rn(2))

    # one arg
    x = H.element([[-1], [-2, -3]])

    z = x.ufunc.absolute()
    assert all_almost_equal(z, [[1], [2, 3]])

    # one arg with out
    x = H.element([[-1], [-2, -3]])
    y = H.element()

    z = x.ufunc.absolute(out=y)
    assert y is z
    assert all_almost_equal(z, [[1], [2, 3]])

    # Two args
    x = H.element([[1], [2, 3]])
    y = H.element([[4], [5, 6]])
    w = H.element()

    z = x.ufunc.add(y)
    assert all_almost_equal(z, [[5], [7, 9]])

    # Two args with out
    x = H.element([[1], [2, 3]])
    y = H.element([[4], [5, 6]])
    w = H.element()

    z = x.ufunc.add(y, out=w)
    assert w is z
    assert all_almost_equal(z, [[5], [7, 9]])
Esempio n. 5
0
def test_proximal_quadratic_perturbation(nonneg_scalar, sigma):
    """Test for the proximal of quadratic perturbation."""
    sigma = float(sigma)
    space = odl.uniform_discr(0, 1, 10)
    lam = 1.2
    prox_factory = proximal_l2_squared(space, lam=lam)

    # parameter for the quadratic perturbation, needs to be non-negative
    a = nonneg_scalar

    # Test without linear term
    if a != 0:
        with pytest.raises(ValueError):
            # negative values not allowed
            proximal_quadratic_perturbation(prox_factory, -a)

    prox = proximal_quadratic_perturbation(prox_factory, a)(sigma)
    x = noise_element(space)
    expected_result = x / (2 * sigma * (lam + a) + 1)
    assert all_almost_equal(prox(x), expected_result, places=PLACES)

    # Test with linear term
    u = noise_element(space)
    prox = proximal_quadratic_perturbation(prox_factory, a, u)(sigma)
    expected_result = (x - sigma * u) / (2 * sigma * (lam + a) + 1)
    assert all_almost_equal(prox(x), expected_result, places=PLACES)
Esempio n. 6
0
def test_proximal_l2_wo_data():
    """Proximal factory for the L2-norm."""

    # Image space
    space = odl.uniform_discr(0, 1, 10)

    # Factory function returning the proximal operator
    lam = 2.0
    prox_factory = proximal_l2(space, lam=lam)

    # Initialize the proximal operator
    sigma = 3.0
    prox = prox_factory(sigma)

    assert isinstance(prox, odl.Operator)

    # Elements
    x = space.element(np.arange(-5, 5))
    x_small = x * 0.5 * lam * sigma / x.norm()
    x_big = x * 2.0 * lam * sigma / x.norm()

    # Explicit computation:
    x_small_opt = x_small * 0
    x_big_opt = (1 - lam * sigma / x_big.norm()) * x_big

    assert all_almost_equal(prox(x_small), x_small_opt, PLACES)
    assert all_almost_equal(prox(x_big), x_big_opt, PLACES)
Esempio n. 7
0
def test_linear_addition():
    A = np.random.rand(4, 3)
    B = np.random.rand(4, 3)
    x = np.random.rand(3)
    y = np.random.rand(4)

    Aop = MatVecOperator(A)
    Bop = MatVecOperator(B)
    xvec = Aop.domain.element(x)
    yvec = Aop.range.element(y)

    # Explicit instantiation
    C = OperatorSum(Aop, Bop)

    assert C.is_linear
    assert C.adjoint.is_linear

    assert all_almost_equal(C(xvec), np.dot(A, x) + np.dot(B, x))
    assert all_almost_equal(C.adjoint(yvec), np.dot(A.T, y) + np.dot(B.T, y))

    # Using operator overloading
    assert all_almost_equal((Aop + Bop)(xvec),
                            np.dot(A, x) + np.dot(B, x))
    assert all_almost_equal((Aop + Bop).adjoint(yvec),
                            np.dot(A.T, y) + np.dot(B.T, y))
Esempio n. 8
0
def test_pointwise_inner_weighted():
    fspace = odl.uniform_discr([0, 0], [1, 1], (2, 2))
    vfspace = ProductSpace(fspace, 3)
    array = np.array([[[-1, -3],
                       [2, 0]],
                      [[0, 0],
                       [0, 1]],
                      [[-1, 1],
                       [1, 1]]])

    weight = np.array([1.0, 2.0, 3.0])
    pwinner = PointwiseInner(vfspace, vecfield=array, weighting=weight)

    testarr = np.array([[[1, 2],
                         [3, 4]],
                        [[0, -1],
                         [0, 1]],
                        [[1, 1],
                         [1, 1]]])

    true_inner = np.sum(weight[:, None, None] * testarr * array, axis=0)

    func = vfspace.element(testarr)
    func_pwinner = pwinner(func)
    assert all_almost_equal(func_pwinner, true_inner.reshape(-1))

    out = fspace.element()
    pwinner(func, out=out)
    assert all_almost_equal(out, true_inner.reshape(-1))
Esempio n. 9
0
def test_nonlinear_addition():
    # Test operator addition
    A = np.random.rand(4, 3)
    B = np.random.rand(4, 3)
    x = np.random.rand(3)

    Aop = MultiplyAndSquareOp(A)
    Bop = MultiplyAndSquareOp(B)
    xvec = Aop.domain.element(x)

    # Explicit instantiation
    C = OperatorSum(Aop, Bop)

    assert not C.is_linear

    assert all_almost_equal(C(xvec),
                            mult_sq_np(A, x) + mult_sq_np(B, x))

    # Using operator overloading
    assert all_almost_equal((Aop + Bop)(xvec),
                            mult_sq_np(A, x) + mult_sq_np(B, x))

    # Verify that unmatched operators domains fail
    C = np.random.rand(4, 4)
    Cop = MultiplyAndSquareOp(C)

    with pytest.raises(TypeError):
        C = OperatorSum(Aop, Cop)
Esempio n. 10
0
def test_functional_scale():
    r3 = odl.Rn(3)

    Aop = SumFunctional(r3)
    x = r3.element([1, 2, 3])
    y = 1

    # Test a range of scalars (scalar multiplication could implement
    # optimizations for (-1, 0, 1).
    scalars = [-1.432, -1, 0, 1, 3.14]
    for scale in scalars:
        C = OperatorRightScalarMult(Aop, scale)

        assert C.is_linear
        assert C.adjoint.is_linear

        assert C(x) == scale * np.sum(x)
        assert all_almost_equal(C.adjoint(y), scale * y * np.ones(3))
        assert all_almost_equal(C.adjoint.adjoint(x), C(x))

        # Using operator overloading
        assert (scale * Aop)(x) == scale * np.sum(x)
        assert (Aop * scale)(x) == scale * np.sum(x)
        assert all_almost_equal((scale * Aop).adjoint(y),
                                scale * y * np.ones(3))
        assert all_almost_equal((Aop * scale).adjoint(y),
                                scale * y * np.ones(3))
Esempio n. 11
0
def test_wavelet_decomposition3d_and_reconstruction3d():
    # Test 3D wavelet decomposition and reconstruction and verify that
    # they perform as expected
    x = np.random.rand(16, 16, 16)
    mode = 'sym'
    wbasis = pywt.Wavelet('db5')
    nscales = 1
    wavelet_coeffs = wavelet_decomposition3d(x, wbasis, mode, nscales)
    aaa = wavelet_coeffs[0]
    reference = pywt.dwtn(x, wbasis, mode)
    aaa_reference = reference['aaa']
    assert all_almost_equal(aaa, aaa_reference)

    reconstruction = wavelet_reconstruction3d(wavelet_coeffs, wbasis, mode,
                                              nscales)
    reconstruction_reference = pywt.idwtn(reference, wbasis, mode)
    assert all_almost_equal(reconstruction, reconstruction_reference)
    assert all_almost_equal(reconstruction, x)
    assert all_almost_equal(reconstruction_reference, x)

    wbasis = pywt.Wavelet('db1')
    nscales = 3
    wavelet_coeffs = wavelet_decomposition3d(x, wbasis, mode, nscales)
    shape_true = (nscales + 1, )
    assert all_equal(np.shape(wavelet_coeffs), shape_true)

    reconstruction = wavelet_reconstruction3d(wavelet_coeffs, wbasis, mode,
                                              nscales)
    assert all_almost_equal(reconstruction, x)
Esempio n. 12
0
def test_collocation_interpolation_identity():
    # Check if interpolation followed by collocation on the same grid
    # is the identity
    rect = odl.Rectangle([0, 0], [1, 1])
    grid = odl.uniform_sampling(rect, [4, 2], as_midp=True)
    space = odl.FunctionSpace(rect)
    dspace = odl.Rn(grid.ntotal)

    # Testing 'C' and 'F' ordering and all interpolation schemes
    coll_op_c = GridCollocation(space, grid, dspace, order='C')
    coll_op_f = GridCollocation(space, grid, dspace, order='F')
    interp_ops_c = [
        NearestInterpolation(space, grid, dspace, order='C', variant='left'),
        NearestInterpolation(space, grid, dspace, order='C', variant='right'),
        LinearInterpolation(space, grid, dspace, order='C'),
        PerAxisInterpolation(space, grid, dspace, order='C',
                             schemes=['linear', 'nearest'])]
    interp_ops_f = [
        NearestInterpolation(space, grid, dspace, order='F', variant='left'),
        NearestInterpolation(space, grid, dspace, order='F', variant='right'),
        LinearInterpolation(space, grid, dspace, order='F'),
        PerAxisInterpolation(space, grid, dspace, order='F',
                             schemes=['linear', 'nearest'])]

    values = np.arange(1, 9, dtype='float64')

    for interp_op_c in interp_ops_c:
        ident_values = coll_op_c(interp_op_c(values))
        assert all_almost_equal(ident_values, values)

    for interp_op_f in interp_ops_f:
        ident_values = coll_op_f(interp_op_f(values))
        assert all_almost_equal(ident_values, values)
Esempio n. 13
0
def test_multiply():
    # Validates multiply against the result on host with randomized data
    rn = odl.CudaRn(100)
    x_host, y_host, z_host, x_device, y_device, z_device = _vectors(rn, 3)

    # Host side calculation
    z_host[:] = x_host * y_host

    # Device side calculation
    rn.multiply(x_device, y_device, out=z_device)

    assert all_almost_equal([x_device, y_device, z_device],
                            [x_host, y_host, z_host])

    # Aliased
    z_host[:] = z_host * x_host
    rn.multiply(z_device, x_device, out=z_device)

    assert all_almost_equal([x_device, z_device],
                            [x_host, z_host])

    # Aliased
    z_host[:] = z_host * z_host
    rn.multiply(z_device, z_device, out=z_device)

    assert all_almost_equal(z_device, z_host)
Esempio n. 14
0
def _test_lincomb(fn, a, b):
    # Validate lincomb against the result on host with randomized
    # data and given a,b, contiguous and non-contiguous

    # Unaliased arguments
    xarr, yarr, zarr, x, y, z = _vectors(fn, 3)
    zarr[:] = a * xarr + b * yarr
    fn.lincomb(a, x, b, y, out=z)
    assert all_almost_equal([x, y, z], [xarr, yarr, zarr])

    # First argument aliased with output
    xarr, yarr, zarr, x, y, z = _vectors(fn, 3)
    zarr[:] = a * zarr + b * yarr
    fn.lincomb(a, z, b, y, out=z)
    assert all_almost_equal([x, y, z], [xarr, yarr, zarr])

    # Second argument aliased with output
    xarr, yarr, zarr, x, y, z = _vectors(fn, 3)
    zarr[:] = a * xarr + b * zarr
    fn.lincomb(a, x, b, z, out=z)
    assert all_almost_equal([x, y, z], [xarr, yarr, zarr])

    # Both arguments aliased with each other
    xarr, yarr, zarr, x, y, z = _vectors(fn, 3)
    zarr[:] = a * xarr + b * xarr
    fn.lincomb(a, x, b, x, out=z)
    assert all_almost_equal([x, y, z], [xarr, yarr, zarr])

    # All aliased
    xarr, yarr, zarr, x, y, z = _vectors(fn, 3)
    zarr[:] = a * zarr + b * zarr
    fn.lincomb(a, z, b, z, out=z)
    assert all_almost_equal([x, y, z], [xarr, yarr, zarr])
Esempio n. 15
0
def test_multiply(fn):
    # Validates multiply against the result on host with randomized data
    [xarr, yarr, zarr], [x_device, y_device, z_device] = example_vectors(fn, 3)

    # Host side calculation
    zarr[:] = xarr * yarr

    # Device side calculation
    fn.multiply(x_device, y_device, out=z_device)

    assert all_almost_equal([x_device, y_device, z_device],
                            [xarr, yarr, zarr])

    # Aliased
    zarr[:] = xarr * zarr
    fn.multiply(z_device, x_device, out=z_device)

    assert all_almost_equal([x_device, z_device],
                            [xarr, zarr])

    # Aliased
    zarr[:] = zarr * zarr
    fn.multiply(z_device, z_device, out=z_device)

    assert all_almost_equal(z_device, zarr)
Esempio n. 16
0
def test_bwt2d():
    # 2D test
    n = 16
    x = np.zeros((n, n))
    x[5:10, 5:10] = 1
    wbasis = 'josbiorth5'
    nscales = 3

    # Define a discretized domain
    domain = odl.FunctionSpace(odl.Rectangle([-1, -1], [1, 1]))
    nPoints = np.array([n, n])
    disc_domain = odl.uniform_discr_fromspace(domain, nPoints)
    disc_phantom = disc_domain.element(x)

    # Create the discrete wavelet transform operator.
    # Only the domain of the operator needs to be defined
    Bop = BiorthWaveletTransform(disc_domain, nscales, wbasis)
    Bop2 = InverseAdjBiorthWaveletTransform(disc_domain, nscales, wbasis)

    # Compute the discrete wavelet transform of discrete imput image
    coeffs = Bop(disc_phantom)
    coeffs2 = Bop2(disc_phantom)

    reconstruction = Bop.inverse(coeffs)
    reconstruction2 = Bop2.inverse(coeffs2)

    assert all_almost_equal(reconstruction.asarray(), x)
    assert all_almost_equal(reconstruction2.asarray(), x)
Esempio n. 17
0
def test_wavelet_transform(wave_impl, shape_setup, floating_dtype):
    # Verify that the operator works as expected
    wavelet, pad_mode, nlevels, shape, _ = shape_setup
    ndim = len(shape)

    space = odl.uniform_discr([-1] * ndim, [1] * ndim, shape,
                              dtype=floating_dtype)
    image = noise_element(space)

    # TODO: check more error scenarios
    if wave_impl == 'pywt' and pad_mode == 'constant':
        with pytest.raises(ValueError):
            wave_trafo = odl.trafos.WaveletTransform(
                space, wavelet, nlevels, pad_mode, pad_const=1, impl=wave_impl)

    wave_trafo = odl.trafos.WaveletTransform(
        space, wavelet, nlevels, pad_mode, impl=wave_impl)

    assert wave_trafo.domain.dtype == floating_dtype
    assert wave_trafo.range.dtype == floating_dtype

    wave_trafo_inv = wave_trafo.inverse
    assert wave_trafo_inv.domain.dtype == floating_dtype
    assert wave_trafo_inv.range.dtype == floating_dtype
    assert wave_trafo_inv.nlevels == wave_trafo.nlevels
    assert wave_trafo_inv.wavelet == wave_trafo.wavelet
    assert wave_trafo_inv.pad_mode == wave_trafo.pad_mode
    assert wave_trafo_inv.pad_const == wave_trafo.pad_const
    assert wave_trafo_inv.pywt_pad_mode == wave_trafo.pywt_pad_mode

    coeffs = wave_trafo(image)
    reco_image = wave_trafo.inverse(coeffs)
    assert all_almost_equal(image.real, reco_image.real)
    assert all_almost_equal(image, reco_image)
Esempio n. 18
0
def test_pointwise_inner_complex():
    fspace = odl.uniform_discr([0, 0], [1, 1], (2, 2), dtype=complex)
    vfspace = ProductSpace(fspace, 3)
    array = np.array([[[-1 - 1j, -3],
                       [2, 2j]],
                      [[-1j, 0],
                       [0, 1]],
                      [[-1, 1 + 2j],
                       [1, 1]]])
    pwinner = PointwiseInner(vfspace, vecfield=array)

    testarr = np.array([[[1 + 1j, 2],
                         [3, 4 - 2j]],
                        [[0, -1],
                         [0, 1]],
                        [[1j, 1j],
                         [1j, 1j]]])

    true_inner = np.sum(testarr * array.conj(), axis=0)

    func = vfspace.element(testarr)
    func_pwinner = pwinner(func)
    assert all_almost_equal(func_pwinner, true_inner.reshape(-1))

    out = fspace.element()
    pwinner(func, out=out)
    assert all_almost_equal(out, true_inner.reshape(-1))
Esempio n. 19
0
def test_collocation_interpolation_identity():
    # Check if interpolation followed by collocation on the same grid
    # is the identity
    rect = odl.IntervalProd([0, 0], [1, 1])
    part = odl.uniform_partition_fromintv(rect, [4, 2])
    space = odl.FunctionSpace(rect)
    dspace = odl.rn(part.size)

    coll_op_c = PointCollocation(space, part, dspace, order='C')
    coll_op_f = PointCollocation(space, part, dspace, order='F')
    interp_ops_c = [
        NearestInterpolation(space, part, dspace, variant='left', order='C'),
        NearestInterpolation(space, part, dspace, variant='right', order='C'),
        LinearInterpolation(space, part, dspace, order='C'),
        PerAxisInterpolation(space, part, dspace, order='C',
                             schemes=['linear', 'nearest'])]
    interp_ops_f = [
        NearestInterpolation(space, part, dspace, variant='left', order='F'),
        NearestInterpolation(space, part, dspace, variant='right', order='F'),
        LinearInterpolation(space, part, dspace, order='F'),
        PerAxisInterpolation(space, part, dspace, order='F',
                             schemes=['linear', 'nearest'])]

    values = np.arange(1, 9, dtype='float64')

    for interp_op_c in interp_ops_c:
        ident_values = coll_op_c(interp_op_c(values))
        assert all_almost_equal(ident_values, values)

    for interp_op_f in interp_ops_f:
        ident_values = coll_op_f(interp_op_f(values))
        assert all_almost_equal(ident_values, values)
Esempio n. 20
0
def test_pointwise_norm_weighted(exponent):
    fspace = odl.uniform_discr([0, 0], [1, 1], (2, 2))
    vfspace = ProductSpace(fspace, 3)
    weight = np.array([1.0, 2.0, 3.0])
    pwnorm = PointwiseNorm(vfspace, exponent, weighting=weight)

    testarr = np.array([[[1, 2],
                         [3, 4]],
                        [[0, -1],
                         [0, 1]],
                        [[1, 1],
                         [1, 1]]])

    if exponent in (1.0, float('inf')):
        true_norm = np.linalg.norm(weight[:, None, None] * testarr,
                                   ord=exponent, axis=0)
    else:
        true_norm = np.linalg.norm(
            weight[:, None, None] ** (1 / exponent) * testarr, ord=exponent,
            axis=0)

    func = vfspace.element(testarr)
    func_pwnorm = pwnorm(func)
    assert all_almost_equal(func_pwnorm, true_norm.reshape(-1))

    out = fspace.element()
    pwnorm(func, out=out)
    assert all_almost_equal(out, true_norm.reshape(-1))
Esempio n. 21
0
def test_power(fn_impl, power):
    space = odl.uniform_discr([0, 0], [1, 1], [2, 2], impl=fn_impl)

    x_arr, x = noise_elements(space, 1)
    x_pos_arr = np.abs(x_arr)
    x_neg_arr = -x_pos_arr
    x_pos = np.abs(x)
    x_neg = -x_pos

    if int(power) != power:
        # Make input positive to get real result
        for y in [x_pos_arr, x_neg_arr, x_pos, x_neg]:
            y += 0.1

    true_pos_pow = np.power(x_pos_arr, power)
    true_neg_pow = np.power(x_neg_arr, power)

    if int(power) != power and fn_impl == 'cuda':
        with pytest.raises(ValueError):
            x_pos ** power
        with pytest.raises(ValueError):
            x_pos **= power
    else:
        assert all_almost_equal(x_pos ** power, true_pos_pow)
        assert all_almost_equal(x_neg ** power, true_neg_pow)

        x_pos **= power
        x_neg **= power
        assert all_almost_equal(x_pos, true_pos_pow)
        assert all_almost_equal(x_neg, true_neg_pow)
Esempio n. 22
0
def test_operators(arithmetic_op):
    # Test of the operators `+`, `-`, etc work as expected by numpy

    space = odl.rn(3)
    pspace = odl.ProductSpace(space, 2)

    # Interactions with scalars

    for scalar in [-31.2, -1, 0, 1, 2.13]:

        # Left op
        x_arr, x = noise_elements(pspace)
        if scalar == 0 and arithmetic_op in [operator.truediv,
                                             operator.itruediv]:
            # Check for correct zero division behaviour
            with pytest.raises(ZeroDivisionError):
                y = arithmetic_op(x, scalar)
        else:
            y_arr = arithmetic_op(x_arr, scalar)
            y = arithmetic_op(x, scalar)

            assert all_almost_equal([x, y], [x_arr, y_arr])

        # Right op
        x_arr, x = noise_elements(pspace)

        y_arr = arithmetic_op(scalar, x_arr)
        y = arithmetic_op(scalar, x)

        assert all_almost_equal([x, y], [x_arr, y_arr])

    # Verify that the statement z=op(x, y) gives equivalent results to NumPy
    x_arr, x = noise_elements(space, 1)
    y_arr, y = noise_elements(pspace, 1)

    # non-aliased left
    if arithmetic_op in [operator.iadd,
                         operator.isub,
                         operator.itruediv,
                         operator.imul]:
        # Check for correct error since in-place op is not possible here
        with pytest.raises(TypeError):
            z = arithmetic_op(x, y)
    else:
        z_arr = arithmetic_op(x_arr, y_arr)
        z = arithmetic_op(x, y)

        assert all_almost_equal([x, y, z], [x_arr, y_arr, z_arr])

    # non-aliased right
    z_arr = arithmetic_op(y_arr, x_arr)
    z = arithmetic_op(y, x)

    assert all_almost_equal([x, y, z], [x_arr, y_arr, z_arr])

    # aliased operation
    z_arr = arithmetic_op(y_arr, y_arr)
    z = arithmetic_op(y, y)

    assert all_almost_equal([x, y, z], [x_arr, y_arr, z_arr])
Esempio n. 23
0
def test_proximal_l2_with_data():
    """Proximal factory for the L2-norm with data term."""

    # Image space
    space = odl.uniform_discr(0, 1, 10)

    # Create data
    g = space.element(np.arange(-5, 5))

    # Factory function returning the proximal operator
    lam = 2.0
    prox_factory = proximal_l2(space, lam=lam, g=g)

    # Initialize the proximal operator
    sigma = 3.0
    prox = prox_factory(sigma)

    assert isinstance(prox, odl.Operator)

    # Elements
    x = space.element(np.arange(-5, 5))
    x_small = g + x * 0.5 * lam * sigma / x.norm()
    x_big = g + x * 2.0 * lam * sigma / x.norm()

    # Explicit computation:
    x_small_opt = g
    const = lam * sigma / (x_big - g).norm()
    x_big_opt = (1 - const) * x_big + const * g

    assert all_almost_equal(prox(x_small), x_small_opt, HIGH_ACC)
    assert all_almost_equal(prox(x_big), x_big_opt, HIGH_ACC)
Esempio n. 24
0
def test_gradient(method, impl, padding):
    """Discretized spatial gradient operator."""

    with pytest.raises(TypeError):
        Gradient(odl.Rn(1), method=method)

    if isinstance(padding, tuple):
        padding_method, padding_value = padding
    else:
        padding_method, padding_value = padding, None

    # DiscreteLp Vector
    discr_space = odl.uniform_discr([0, 0], [1, 1], DATA_2D.shape, impl=impl)
    dom_vec = discr_space.element(DATA_2D)

    # computation of gradient components with helper function
    dx0, dx1 = discr_space.cell_sides
    diff_0 = finite_diff(DATA_2D, axis=0, dx=dx0, method=method,
                         padding_method=padding_method,
                         padding_value=padding_value)
    diff_1 = finite_diff(DATA_2D, axis=1, dx=dx1, method=method,
                         padding_method=padding_method,
                         padding_value=padding_value)

    # gradient
    grad = Gradient(discr_space, method=method,
                    padding_method=padding_method,
                    padding_value=padding_value)
    grad_vec = grad(dom_vec)
    assert len(grad_vec) == DATA_2D.ndim
    assert all_almost_equal(grad_vec[0].asarray(), diff_0)
    assert all_almost_equal(grad_vec[1].asarray(), diff_1)

    # Test adjoint operator
    derivative = grad.derivative()
    ran_vec = derivative.range.element([DATA_2D, DATA_2D ** 2])
    deriv_grad_vec = derivative(dom_vec)
    adj_grad_vec = derivative.adjoint(ran_vec)
    lhs = ran_vec.inner(deriv_grad_vec)
    rhs = dom_vec.inner(adj_grad_vec)
    # Check not to use trivial data
    assert lhs != 0
    assert rhs != 0
    assert almost_equal(lhs, rhs)

    # higher dimensional arrays
    lin_size = 3
    for ndim in [1, 3, 6]:

        # DiscreteLp Vector
        space = odl.uniform_discr([0.] * ndim, [1.] * ndim, [lin_size] * ndim)
        dom_vec = odl.phantom.cuboid(space, [0.2] * ndim, [0.8] * ndim)

        # gradient
        grad = Gradient(space, method=method,
                        padding_method=padding_method,
                        padding_value=padding_value)
        grad(dom_vec)
Esempio n. 25
0
def evaluate(operator, point, expected):
    """Assert that operator(point) == expected."""

    assert all_almost_equal(operator(point), expected)

    out = operator.range.element()
    operator(point, out=out)

    assert all_almost_equal(out, expected)
def test_L2_norm(space, sigma):
    """Test the L2-norm."""
    func = odl.solvers.L2Norm(space)
    x = noise_element(space)
    x_norm = x.norm()

    # Test functional evaluation
    expected_result = np.sqrt((x ** 2).inner(space.one()))
    assert pytest.approx(func(x), expected_result)

    # Test gradient
    if x_norm > 0:
        expected_result = x / x.norm()
        assert all_almost_equal(func.gradient(x), expected_result)

    # Verify that the gradient at zero is zero
    assert all_almost_equal(func.gradient(func.domain.zero()), space.zero())

    # Test proximal operator - expecting
    # x * (1 - sigma/||x||) if ||x|| > sigma, 0 else
    norm_less_than_sigma = 0.99 * sigma * x / x_norm
    assert all_almost_equal(func.proximal(sigma)(norm_less_than_sigma),
                            space.zero())

    norm_larger_than_sigma = 1.01 * sigma * x / x_norm
    expected_result = (norm_larger_than_sigma *
                       (1.0 - sigma / norm_larger_than_sigma.norm()))
    assert all_almost_equal(func.proximal(sigma)(norm_larger_than_sigma),
                            expected_result)

    # Test convex conjugate
    func_cc = func.convex_conj

    # Test evaluation of the convex conjugate - expecting
    # 0 if ||x|| < 1, infty else
    norm_larger_than_one = 1.01 * x / x_norm
    assert func_cc(norm_larger_than_one) == np.inf

    norm_less_than_one = 0.99 * x / x_norm
    assert func_cc(norm_less_than_one) == 0

    # Gradient of the convex conjugate (not implemeted)
    with pytest.raises(NotImplementedError):
        func_cc.gradient

    # Test the proximal of the convex conjugate - expecting
    # x if ||x||_2 < 1, x/||x|| else
    if x_norm < 1:
        expected_result = x
    else:
        expected_result = x / x_norm
    assert all_almost_equal(func_cc.proximal(sigma)(x), expected_result)

    # Verify that the biconjugate is the functional itself
    func_cc_cc = func_cc.convex_conj
    assert pytest.approx(func_cc_cc(x), func(x))
Esempio n. 27
0
def test_translation_of_functional(space):
    """Test for the translation of a functional: (f(. - y))^*."""
    # Less strict checking for single precision
    places = 3 if space.dtype == np.float32 else 5

    # The translation; an element in the domain
    translation = noise_element(space)

    test_functional = odl.solvers.L2NormSquared(space)
    translated_functional = test_functional.translated(translation)
    x = noise_element(space)

    # Test for evaluation of the functional
    expected_result = test_functional(x - translation)
    assert all_almost_equal(translated_functional(x), expected_result,
                            places=places)

    # Test for the gradient
    expected_result = test_functional.gradient(x - translation)
    translated_gradient = translated_functional.gradient
    assert all_almost_equal(translated_gradient(x), expected_result,
                            places=places)

    # Test for proximal
    sigma = 1.2
    # The helper function below is tested explicitly in proximal_utils_test
    expected_result = odl.solvers.proximal_translation(
        test_functional.proximal, translation)(sigma)(x)
    assert all_almost_equal(translated_functional.proximal(sigma)(x),
                            expected_result, places=places)

    # Test for conjugate functional
    # The helper function below is tested explicitly further down in this file
    expected_result = odl.solvers.FunctionalLinearPerturb(
        test_functional.convex_conj, translation)(x)
    assert all_almost_equal(translated_functional.convex_conj(x),
                            expected_result, places=places)

    # Test for derivative in direction p
    p = noise_element(space)

    # Explicit computation in point x, in direction p: <x/2 + translation, p>
    expected_result = p.inner(test_functional.gradient(x - translation))
    assert all_almost_equal(translated_functional.derivative(x)(p),
                            expected_result, places=places)

    # Test for optimized implementation, when translating a translated
    # functional
    second_translation = noise_element(space)
    double_translated_functional = translated_functional.translated(
        second_translation)

    # Evaluation
    assert almost_equal(double_translated_functional(x),
                        test_functional(x - translation - second_translation),
                        places=places)
Esempio n. 28
0
def test_pspace_op_sum_call():
    r3 = odl.Rn(3)
    I = odl.IdentityOperator(r3)
    op = odl.ProductSpaceOperator([I, I])

    x = r3.element([1, 2, 3])
    y = r3.element([7, 8, 9])
    z = op.domain.element([x, y])

    assert all_almost_equal(op(z)[0], x + y)
    assert all_almost_equal(op(z, out=op.range.element())[0], x + y)
Esempio n. 29
0
def _impl_test_ufuncs(fn, name, n_args, n_out):
    # Get the ufunc from numpy as reference
    ufunc = getattr(np, name)

    # Create some data
    data = _vectors(fn, n_args + n_out)
    in_arrays = data[:n_args]
    out_arrays = data[n_args:n_args + n_out]
    data_vector = data[n_args + n_out]
    in_vectors = data[1 + n_args + n_out:2 * n_args + n_out]
    out_vectors = data[2 * n_args + n_out:]

    # Verify type
    assert isinstance(data_vector.ufunc,
                      odl.util.ufuncs.DiscreteLpVectorUFuncs)

    # Out of place:
    np_result = ufunc(*in_arrays)
    vec_fun = getattr(data_vector.ufunc, name)
    odl_result = vec_fun(*in_vectors)
    assert all_almost_equal(np_result, odl_result)

    # Test type of output
    if n_out == 1:
        assert isinstance(odl_result, fn.element_type)
    elif n_out > 1:
        for i in range(n_out):
            assert isinstance(odl_result[i], fn.element_type)

    # In place:
    np_result = ufunc(*(in_arrays + out_arrays))
    vec_fun = getattr(data_vector.ufunc, name)
    odl_result = vec_fun(*(in_vectors + out_vectors))
    assert all_almost_equal(np_result, odl_result)

    # Test inplace actually holds:
    if n_out == 1:
        assert odl_result is out_vectors[0]
    elif n_out > 1:
        for i in range(n_out):
            assert odl_result[i] is out_vectors[i]

    # Test out of place with np data
    np_result = ufunc(*in_arrays)
    vec_fun = getattr(data_vector.ufunc, name)
    odl_result = vec_fun(*in_arrays[1:])
    assert all_almost_equal(np_result, odl_result)

    # Test type of output
    if n_out == 1:
        assert isinstance(odl_result, fn.element_type)
    elif n_out > 1:
        for i in range(n_out):
            assert isinstance(odl_result[i], fn.element_type)
Esempio n. 30
0
def test_multiplication_with_vector(space):
    """Test for multiplying a functional with a vector, both left and right."""
    # Less strict checking for single precision
    places = 3 if space.dtype == np.float32 else 5

    x = noise_element(space)
    y = noise_element(space)
    func = odl.solvers.L2NormSquared(space)

    wrong_space = odl.uniform_discr(1, 2, 10)
    y_other_space = noise_element(wrong_space)

    # Multiplication from the right. Make sure it is a
    # FunctionalRightVectorMult
    func_times_y = func * y
    assert isinstance(func_times_y, odl.solvers.FunctionalRightVectorMult)

    expected_result = func(y * x)
    assert almost_equal(func_times_y(x), expected_result, places=places)

    # Test for the gradient.
    # Explicit calculations: 2*y*y*x
    expected_result = 2.0 * y * y * x
    assert all_almost_equal(func_times_y.gradient(x), expected_result,
                            places=places)

    # Test for convex_conj
    cc_func_times_y = func_times_y.convex_conj
    # Explicit calculations: 1/4 * ||x/y||_2^2
    expected_result = 1.0 / 4.0 * (x / y).norm()**2
    assert almost_equal(cc_func_times_y(x), expected_result, places=places)

    # Make sure that right muliplication is not allowed with vector from
    # another space
    with pytest.raises(TypeError):
        func * y_other_space

    # Multiplication from the left. Make sure it is a FunctionalLeftVectorMult
    y_times_func = y * func
    assert isinstance(y_times_func, odl.FunctionalLeftVectorMult)

    expected_result = y * func(x)
    assert all_almost_equal(y_times_func(x), expected_result, places=places)

    # Now, multiplication with vector from another space is ok (since it is the
    # same as scaling that vector with the scalar returned by the functional).
    y_other_times_func = y_other_space * func
    assert isinstance(y_other_times_func, odl.FunctionalLeftVectorMult)

    expected_result = y_other_space * func(x)
    assert all_almost_equal(y_other_times_func(x), expected_result,
                            places=places)
Esempio n. 31
0
def test_translation_of_functional(space):
    """Test for the translation of a functional: (f(. - y))^*."""
    # Less strict checking for single precision
    places = 3 if space.dtype == np.float32 else 5

    # The translation; an element in the domain
    translation = noise_element(space)

    test_functional = odl.solvers.L2NormSquared(space)
    translated_functional = test_functional.translated(translation)
    x = noise_element(space)

    # Test for evaluation of the functional
    expected_result = test_functional(x - translation)
    assert all_almost_equal(translated_functional(x),
                            expected_result,
                            places=places)

    # Test for the gradient
    expected_result = test_functional.gradient(x - translation)
    translated_gradient = translated_functional.gradient
    assert all_almost_equal(translated_gradient(x),
                            expected_result,
                            places=places)

    # Test for proximal
    sigma = 1.2
    # The helper function below is tested explicitly in proximal_utils_test
    expected_result = odl.solvers.proximal_translation(
        test_functional.proximal, translation)(sigma)(x)
    assert all_almost_equal(translated_functional.proximal(sigma)(x),
                            expected_result,
                            places=places)

    # Test for conjugate functional
    # The helper function below is tested explicitly further down in this file
    expected_result = odl.solvers.FunctionalQuadraticPerturb(
        test_functional.convex_conj, linear_term=translation)(x)
    assert all_almost_equal(translated_functional.convex_conj(x),
                            expected_result,
                            places=places)

    # Test for derivative in direction p
    p = noise_element(space)

    # Explicit computation in point x, in direction p: <x/2 + translation, p>
    expected_result = p.inner(test_functional.gradient(x - translation))
    assert all_almost_equal(translated_functional.derivative(x)(p),
                            expected_result,
                            places=places)

    # Test for optimized implementation, when translating a translated
    # functional
    second_translation = noise_element(space)
    double_translated_functional = translated_functional.translated(
        second_translation)

    # Evaluation
    assert almost_equal(double_translated_functional(x),
                        test_functional(x - translation - second_translation),
                        places=places)
Esempio n. 32
0
def test_zero(fn):
    assert all_almost_equal(fn.zero(), [0] * fn.size)
Esempio n. 33
0
def test_ufuncs(odl_tspace_impl, odl_ufunc):
    """Test ufuncs in ``x.ufuncs`` against direct Numpy ufuncs."""
    impl = odl_tspace_impl
    space = odl.uniform_discr([0, 0], [1, 1], (2, 3), impl=impl)
    name = odl_ufunc

    # Get the ufunc from numpy as reference
    npy_ufunc = getattr(np, name)
    nin = npy_ufunc.nin
    nout = npy_ufunc.nout
    if (np.issubsctype(space.dtype, np.floating) and name in [
            'bitwise_and', 'bitwise_or', 'bitwise_xor', 'invert', 'left_shift',
            'right_shift'
    ]):
        # Skip integer only methods if floating point type
        return

    # Create some data
    arrays, elements = noise_elements(space, nin + nout)
    in_arrays = arrays[:nin]
    out_arrays = arrays[nin:]
    data_elem = elements[0]
    out_elems = elements[nin:]

    if nout == 1:
        out_arr_kwargs = {'out': out_arrays[0]}
        out_elem_kwargs = {'out': out_elems[0]}
    elif nout > 1:
        out_arr_kwargs = {'out': out_arrays[:nout]}
        out_elem_kwargs = {'out': out_elems[:nout]}

    # Get function to call, using both interfaces:
    # - vec.ufunc(other_args)
    # - np.ufunc(vec, other_args)
    elem_fun_old = getattr(data_elem.ufuncs, name)
    in_elems_old = elements[1:nin]
    elem_fun_new = npy_ufunc
    in_elems_new = elements[:nin]

    # Out-of-place
    with np.errstate(all='ignore'):  # avoid pytest warnings
        npy_result = npy_ufunc(*in_arrays)
        odl_result_old = elem_fun_old(*in_elems_old)
        assert all_almost_equal(npy_result, odl_result_old)
        odl_result_new = elem_fun_new(*in_elems_new)
        assert all_almost_equal(npy_result, odl_result_new)

    # Test type of output
    if nout == 1:
        assert isinstance(odl_result_old, space.element_type)
        assert isinstance(odl_result_new, space.element_type)
    elif nout > 1:
        for i in range(nout):
            assert isinstance(odl_result_old[i], space.element_type)
            assert isinstance(odl_result_new[i], space.element_type)

    # In-place with ODL objects as `out`
    with np.errstate(all='ignore'):  # avoid pytest warnings
        npy_result = npy_ufunc(*in_arrays, **out_arr_kwargs)
        odl_result_old = elem_fun_old(*in_elems_old, **out_elem_kwargs)
        assert all_almost_equal(npy_result, odl_result_old)
        odl_result_new = elem_fun_new(*in_elems_new, **out_elem_kwargs)
        assert all_almost_equal(npy_result, odl_result_new)

    # Check that returned stuff refers to given out
    if nout == 1:
        assert odl_result_old is out_elems[0]
        assert odl_result_new is out_elems[0]
    elif nout > 1:
        for i in range(nout):
            assert odl_result_old[i] is out_elems[i]
            assert odl_result_new[i] is out_elems[i]

    # In-place with Numpy array as `out` for new interface
    out_arrays_new = tuple(np.empty_like(arr) for arr in out_arrays)
    if nout == 1:
        out_arr_kwargs_new = {'out': out_arrays_new[0]}
    elif nout > 1:
        out_arr_kwargs_new = {'out': out_arrays_new[:nout]}

    with np.errstate(all='ignore'):  # avoid pytest warnings
        odl_result_arr_new = elem_fun_new(*in_elems_new, **out_arr_kwargs_new)
    assert all_almost_equal(npy_result, odl_result_arr_new)

    if nout == 1:
        assert odl_result_arr_new is out_arrays_new[0]
    elif nout > 1:
        for i in range(nout):
            assert odl_result_arr_new[i] is out_arrays_new[i]

    # In-place with data container (tensor) as `out` for new interface
    out_tensors_new = tuple(
        space.tspace.element(np.empty_like(arr)) for arr in out_arrays)
    if nout == 1:
        out_tens_kwargs_new = {'out': out_tensors_new[0]}
    elif nout > 1:
        out_tens_kwargs_new = {'out': out_tensors_new[:nout]}

    with np.errstate(all='ignore'):  # avoid pytest warnings
        odl_result_tens_new = elem_fun_new(*in_elems_new,
                                           **out_tens_kwargs_new)
    assert all_almost_equal(npy_result, odl_result_tens_new)

    if nout == 1:
        assert odl_result_tens_new is out_tensors_new[0]
    elif nout > 1:
        for i in range(nout):
            assert odl_result_tens_new[i] is out_tensors_new[i]

    # Check `ufunc.at`
    indices = ([0, 0, 1], [0, 1, 2])

    mod_array = in_arrays[0].copy()
    mod_elem = in_elems_new[0].copy()
    if nout > 1:
        return  # currently not supported by Numpy
    if nin == 1:
        with np.errstate(all='ignore'):  # avoid pytest warnings
            npy_result = npy_ufunc.at(mod_array, indices)
            odl_result = npy_ufunc.at(mod_elem, indices)
    elif nin == 2:
        other_array = in_arrays[1][indices]
        other_elem = in_elems_new[1][indices]
        with np.errstate(all='ignore'):  # avoid pytest warnings
            npy_result = npy_ufunc.at(mod_array, indices, other_array)
            odl_result = npy_ufunc.at(mod_elem, indices, other_elem)

    assert all_almost_equal(odl_result, npy_result)

    # Check `ufunc.reduce`
    if nin == 2 and nout == 1:
        in_array = in_arrays[0]
        in_elem = in_elems_new[0]

        # We only test along one axis since some binary ufuncs are not
        # re-orderable, in which case Numpy raises a ValueError
        with np.errstate(all='ignore'):  # avoid pytest warnings
            npy_result = npy_ufunc.reduce(in_array)
            odl_result = npy_ufunc.reduce(in_elem)
            assert all_almost_equal(odl_result, npy_result)
            # In-place using `out` (with ODL vector and array)
            out_elem = odl_result.space.element()
            out_array = np.empty(odl_result.shape, dtype=odl_result.dtype)
            npy_ufunc.reduce(in_elem, out=out_elem)
            npy_ufunc.reduce(in_elem, out=out_array)
            assert all_almost_equal(out_elem, odl_result)
            assert all_almost_equal(out_array, odl_result)
            # Using a specific dtype
            try:
                npy_result = npy_ufunc.reduce(in_array, dtype=complex)
            except TypeError:
                # Numpy finds no matching loop, bail out
                return
            else:
                odl_result = npy_ufunc.reduce(in_elem, dtype=complex)
                assert odl_result.dtype == npy_result.dtype
                assert all_almost_equal(odl_result, npy_result)
Esempio n. 34
0
def test_conebeam_source_detector_shifts():
    """Test source/detector shifts in 3d cone beam geometry."""
    full_angle = np.pi
    n_angles = 2 * 7
    apart = odl.uniform_partition(0, full_angle, n_angles)
    dpart = odl.uniform_partition([-1, -1], [1, 1], (10, 10))
    src_rad = 10
    det_rad = 5
    pitch = 3
    # Source positions with flying focal spot should correspond to
    # source positions of 2 geometries with different starting positions
    shift1 = np.array([2.0, -3.0, 1.0])
    shift2 = np.array([-2.0, 3.0, -1.0])
    init = np.array([1, 0, 0], dtype=np.float32)
    ffs = partial(odl.tomo.flying_focal_spot,
                  apart=apart,
                  shifts=[shift1, shift2])
    geom_ffs = odl.tomo.ConeBeamGeometry(apart,
                                         dpart,
                                         src_rad,
                                         det_rad,
                                         src_to_det_init=init,
                                         src_shift_func=ffs,
                                         pitch=pitch)
    # angles must be shifted to match discretization of apart
    ang1 = -full_angle / (n_angles * 2)
    apart1 = odl.uniform_partition(ang1, full_angle + ang1, n_angles // 2)
    ang2 = full_angle / (n_angles * 2)
    apart2 = odl.uniform_partition(ang2, full_angle + ang2, n_angles // 2)

    init1 = init + np.array([0, shift1[1], 0]) / (src_rad + shift1[0])
    init2 = init + np.array([0, shift2[1], 0]) / (src_rad + shift2[0])
    # radius also changes when a shift is applied
    src_rad1 = np.linalg.norm(np.array([src_rad + shift1[0], shift1[1], 0]))
    src_rad2 = np.linalg.norm(np.array([src_rad + shift2[0], shift2[1], 0]))
    geom1 = odl.tomo.ConeBeamGeometry(apart1,
                                      dpart,
                                      src_rad1,
                                      det_rad,
                                      src_to_det_init=init1,
                                      offset_along_axis=shift1[2],
                                      pitch=pitch)
    geom2 = odl.tomo.ConeBeamGeometry(apart2,
                                      dpart,
                                      src_rad2,
                                      det_rad,
                                      src_to_det_init=init2,
                                      offset_along_axis=shift2[2],
                                      pitch=pitch)

    sp1 = geom1.src_position(geom1.angles)
    sp2 = geom2.src_position(geom2.angles)
    sp = geom_ffs.src_position(geom_ffs.angles)
    assert all_almost_equal(sp[0::2], sp1)
    assert all_almost_equal(sp[1::2], sp2)

    # detector positions are not affected by flying focal spot
    geom = odl.tomo.ConeBeamGeometry(apart,
                                     dpart,
                                     src_rad,
                                     det_rad,
                                     src_to_det_init=init,
                                     pitch=pitch)
    assert all_almost_equal(geom.det_refpoint(geom.angles),
                            geom_ffs.det_refpoint(geom_ffs.angles))

    # However, detector can be shifted similarly as the source
    coef = det_rad / src_rad

    def det_shift(angle):
        return ffs(angle) * coef

    geom_ds = odl.tomo.ConeBeamGeometry(apart,
                                        dpart,
                                        src_rad,
                                        det_rad,
                                        src_to_det_init=init,
                                        det_shift_func=det_shift,
                                        pitch=pitch)
    det_rad1 = src_rad1 / src_rad * det_rad
    det_rad2 = src_rad2 / src_rad * det_rad
    geom1 = odl.tomo.ConeBeamGeometry(apart1,
                                      dpart,
                                      src_rad,
                                      det_rad1,
                                      src_to_det_init=init1,
                                      offset_along_axis=shift1[2] * coef,
                                      pitch=pitch)
    geom2 = odl.tomo.ConeBeamGeometry(apart2,
                                      dpart,
                                      src_rad,
                                      det_rad2,
                                      src_to_det_init=init2,
                                      offset_along_axis=shift2[2] * coef,
                                      pitch=pitch)
    dr1 = geom1.det_refpoint(geom1.angles)
    dr2 = geom2.det_refpoint(geom2.angles)
    dr = geom_ds.det_refpoint(geom_ds.angles)
    assert all_almost_equal(dr[0::2], dr1)
    assert all_almost_equal(dr[1::2], dr2)

    # source positions are not affected
    assert all_almost_equal(geom.src_position(geom.angles),
                            geom_ds.src_position(geom_ds.angles))
Esempio n. 35
0
def test_ndarray_init(fn):
    x0 = np.arange(fn.size)
    x = fn.element(x0)

    assert all_almost_equal(x0, x)
Esempio n. 36
0
def test_uniform_discr_fromdiscr_one_attr():
    # Change 1 attribute

    discr = odl.uniform_discr([0, -1], [1, 1], [10, 5])
    # csides = [0.1, 0.4]

    # min_pt -> translate, keep cells
    new_min_pt = [3, 7]
    true_new_max_pt = [4, 9]

    new_discr = odl.uniform_discr_fromdiscr(discr, min_pt=new_min_pt)
    assert all_almost_equal(new_discr.min_pt, new_min_pt)
    assert all_almost_equal(new_discr.max_pt, true_new_max_pt)
    assert all_equal(new_discr.shape, discr.shape)
    assert all_almost_equal(new_discr.cell_sides, discr.cell_sides)

    # max_pt -> translate, keep cells
    new_max_pt = [3, 7]
    true_new_min_pt = [2, 5]

    new_discr = odl.uniform_discr_fromdiscr(discr, max_pt=new_max_pt)
    assert all_almost_equal(new_discr.min_pt, true_new_min_pt)
    assert all_almost_equal(new_discr.max_pt, new_max_pt)
    assert all_equal(new_discr.shape, discr.shape)
    assert all_almost_equal(new_discr.cell_sides, discr.cell_sides)

    # shape -> resize cells, keep corners
    new_shape = (5, 20)
    true_new_csides = [0.2, 0.1]
    new_discr = odl.uniform_discr_fromdiscr(discr, shape=new_shape)
    assert all_almost_equal(new_discr.min_pt, discr.min_pt)
    assert all_almost_equal(new_discr.max_pt, discr.max_pt)
    assert all_equal(new_discr.shape, new_shape)
    assert all_almost_equal(new_discr.cell_sides, true_new_csides)

    # cell_sides -> resize cells, keep corners
    new_csides = [0.5, 0.2]
    true_new_shape = (2, 10)
    new_discr = odl.uniform_discr_fromdiscr(discr, cell_sides=new_csides)
    assert all_almost_equal(new_discr.min_pt, discr.min_pt)
    assert all_almost_equal(new_discr.max_pt, discr.max_pt)
    assert all_equal(new_discr.shape, true_new_shape)
    assert all_almost_equal(new_discr.cell_sides, new_csides)
Esempio n. 37
0
def test_parallel_2d_props(shift):
    """Test basic properties of 2D parallel geometries."""
    full_angle = np.pi
    apart = odl.uniform_partition(0, full_angle, 10)
    dpart = odl.uniform_partition(0, 1, 10)
    translation = np.array([shift, shift], dtype=float)
    geom = odl.tomo.Parallel2dGeometry(apart, dpart, translation=translation)

    assert geom.ndim == 2
    assert isinstance(geom.detector, odl.tomo.Flat1dDetector)

    # Check defaults
    assert all_almost_equal(geom.det_pos_init, translation + [0, 1])
    assert all_almost_equal(geom.det_refpoint(0), geom.det_pos_init)
    assert all_almost_equal(geom.det_point_position(0, 0), geom.det_pos_init)
    assert all_almost_equal(geom.det_axis_init, [1, 0])
    assert all_almost_equal(geom.det_axis(0), [1, 0])
    assert all_almost_equal(geom.translation, translation)

    # Check that we first rotate, then shift along the rotated axis, which
    # is equivalent to shifting first and then rotating.
    # Here we expect to rotate the reference point to [-1, 0] and then shift
    # by 1 (=detector param) along the detector axis [0, 1] at that angle.
    # Global translation should be added afterwards.
    assert all_almost_equal(geom.det_point_position(np.pi / 2, 1),
                            translation + [-1, 1])
    assert all_almost_equal(geom.det_axis(np.pi / 2), [0, 1])

    # Detector to source vector, should be independent of the detector
    # parameter and of translation.
    # At pi/2 it should point into the (+x) direction.
    assert all_almost_equal(geom.det_to_src(np.pi / 2, 0), [1, 0])
    assert all_almost_equal(geom.det_to_src(np.pi / 2, 1), [1, 0])

    # Rotation matrix, should correspond to counter-clockwise rotation
    assert all_almost_equal(geom.rotation_matrix(np.pi / 2), [[0, -1], [1, 0]])

    # Make sure that the boundary cases are treated as valid
    geom.det_point_position(0, 0)
    geom.det_point_position(full_angle, 1)

    # Invalid parameter
    with pytest.raises(ValueError):
        geom.rotation_matrix(2 * full_angle)

    # Check that str and repr work without crashing and return something
    assert str(geom)
    assert repr(geom)
Esempio n. 38
0
def test_list_init(fn):
    x_list = list(range(fn.size))
    x = fn.element(x_list)
    assert all_almost_equal(x, x_list)
Esempio n. 39
0
def test_helical_cone_flat():
    """Conebeam geometry with helical acquisition and a flat 2D detector."""

    # Parameters
    full_angle = 2 * np.pi
    apart = odl.uniform_partition(0, full_angle, 10)
    dpart = odl.uniform_partition([0, 0], [1, 1], [10, 10])
    src_rad = 10.0
    det_rad = 5.0
    pitch = 1.5

    with pytest.raises(TypeError):
        odl.tomo.HelicalConeFlatGeometry([0, 1], dpart, src_rad, det_rad,
                                         pitch)
    with pytest.raises(TypeError):
        odl.tomo.HelicalConeFlatGeometry(apart, [0, 1], src_rad, det_rad,
                                         pitch)
    with pytest.raises(ValueError):
        odl.tomo.HelicalConeFlatGeometry(apart, dpart, -1, det_rad, pitch)
    with pytest.raises(ValueError):
        odl.tomo.HelicalConeFlatGeometry(apart, dpart, src_rad, -1, pitch)

    # Initialize
    geom = odl.tomo.HelicalConeFlatGeometry(apart, dpart, src_rad, det_rad,
                                            pitch)

    assert all_almost_equal(geom.angles, apart.points().ravel())

    with pytest.raises(ValueError):
        geom.det_refpoint(2 * full_angle)

    assert np.linalg.norm(geom.det_refpoint(0)) == det_rad
    assert almost_equal(np.linalg.norm(geom.det_refpoint(np.pi / 4)[0:2]),
                        det_rad)

    assert geom.ndim == 3
    assert isinstance(geom.detector, odl.tomo.Flat2dDetector)

    det_refpoint = geom.det_refpoint(2 * np.pi)
    assert almost_equal(np.linalg.norm(det_refpoint[0:2]), det_rad)

    angles = geom.angles
    num_angles = geom.angles.size

    src_rad = geom.src_radius
    det_rad = geom.det_radius
    pitch = geom.pitch

    for ang_ind in range(num_angles):
        angle = angles[ang_ind]
        z = pitch * angle / (2 * np.pi)

        # source
        pnt = (-np.cos(angle) * src_rad, -np.sin(angle) * src_rad, z)
        assert all_almost_equal(geom.src_position(angle), pnt)

        # center of detector
        det = geom.det_refpoint(angle)
        src = geom.src_position(angle)
        val0 = np.linalg.norm(src[0:2]) / src_rad
        val1 = np.linalg.norm(det[0:2]) / det_rad
        assert almost_equal(val0, val1)
        assert almost_equal(src[2], det[2])

    # check str and repr work without crashing and return something
    assert str(geom)
    assert repr(geom)
Esempio n. 40
0
def test_solver(optimization_problem, iterative_solver):
    """Test iterative solver for solving some simple problems."""
    op, x, rhs = optimization_problem

    iterative_solver(op, x, rhs)
    assert all_almost_equal(op(x), rhs, ndigits=2)
Esempio n. 41
0
def test_ndarray_init(tspace):
    x0 = np.arange(tspace.size).reshape(tspace.shape)
    x = tspace.element(x0)

    assert all_almost_equal(x0, x)
Esempio n. 42
0
def test_detector_transformations():
    """ Tests projecting data from one detector to another
    using interpolation.

    Given 2 detectors C and F. If data is sampled from a smooth function,
    projecting C -> F -> C must be close to an identity mapping.
      """
    # 1D, circular <-> flat
    r = 3
    part = odl.uniform_partition(-np.pi / 4, np.pi / 4, 21, nodes_on_bdry=True)
    C = odl.tomo.CircularDetector(part, axis=[1, 0], radius=r)
    F = odl.tomo.curved_to_flat(C)
    C2 = odl.tomo.flat_to_curved(F, radius=r)
    assert C.partition == C2.partition
    assert C.radius == C2.radius
    # take linear function
    data0 = part.points().squeeze()
    data1 = odl.tomo.project_data(data0, C, F)
    data2 = odl.tomo.project_data(data1, F, C)
    data3 = odl.tomo.project_data(data2, C, F)
    assert all_almost_equal(data0, data2, 3)
    assert all_almost_equal(data1, data3, 3)

    # 2D, spherical <-> flat
    r = 5
    part = odl.uniform_partition([-np.pi / 4, -np.pi / 4],
                                 [np.pi / 4, np.pi / 4], (31, 31),
                                 nodes_on_bdry=True)
    S = odl.tomo.SphericalDetector(part, axes=[[1, 0, 0], [0, 0, 1]], radius=r)
    F = odl.tomo.curved_to_flat(S)
    S2 = odl.tomo.flat_to_curved(F, radius=(r, r))
    # height is going to increase after projecting to flat detector and back
    assert all_almost_equal(S.partition.meshgrid[0], S2.partition.meshgrid[0])
    assert S.radius == S2.radius
    # take linear function
    data0 = np.sum(part.points(), axis=-1).reshape(part.shape)
    data1 = odl.tomo.project_data(data0, S, F)
    data2 = odl.tomo.project_data(data1, F, S)
    data3 = odl.tomo.project_data(data2, S, F)
    # there is some loss of energy at the upper and lower boundaries,
    # even with nodes_on_bdry=True
    # (since the boundary of a spherical detector is not a straight line,
    # when projected on a flat detector), affects around 30% from each side
    l = part.shape[1] // 3
    u = part.shape[1] - l
    assert all_almost_equal(data0[:, l:u], data2[:, l:u], 3)
    assert all_almost_equal(data1[:, l:u], data3[:, l:u], 3)

    # 2D, flat <-> cylindrical
    C = odl.tomo.flat_to_curved(F, radius=r)
    F2 = odl.tomo.curved_to_flat(C)
    # height is going to increase after projecting to curved detector and back
    assert all_almost_equal(F.partition.meshgrid[0], F2.partition.meshgrid[0])
    data1 = odl.tomo.project_data(data0, F, C)
    data2 = odl.tomo.project_data(data1, C, F)
    data3 = odl.tomo.project_data(data2, F, C)
    assert all_almost_equal(data0[:, l:u], data2[:, l:u], 3)
    assert all_almost_equal(data1[:, l:u], data3[:, l:u], 3)

    # 2D, spherical <-> cylindrical
    data1 = odl.tomo.project_data(data0, S, C)
    data2 = odl.tomo.project_data(data1, C, S)
    data3 = odl.tomo.project_data(data2, S, C)
    assert all_almost_equal(data0[:, l:u], data2[:, l:u], 3)
    assert all_almost_equal(data1[:, l:u], data3[:, l:u], 3)

    # testing in the context of tomography
    if not odl.tomo.ASTRA_CUDA_AVAILABLE:
        pytest.skip(msg='ASTRA_CUDA not available, skipping 3d test')

    space = odl.uniform_discr([-1] * 3, [1] * 3, [10] * 3)
    x = odl.phantom.shepp_logan(space)
    apart = odl.uniform_partition(0, np.pi, 180)
    dpart = odl.uniform_partition([-1, -1], [1, 1], (128, 32))
    geom_flat = odl.tomo.ConeBeamGeometry(apart,
                                          dpart,
                                          src_radius=1,
                                          det_radius=1)
    curved_det = odl.tomo.flat_to_curved(geom_flat.detector, radius=30)
    operator_flat = odl.tomo.RayTransform(space, geom_flat)
    data_flat = operator_flat(x).asarray()
    data_curved = odl.tomo.project_data(data_flat, geom_flat.detector,
                                        curved_det)
    data_flat2 = odl.tomo.project_data(data_curved, curved_det,
                                       geom_flat.detector)
    assert all_almost_equal(data_flat, data_flat2, 2)
Esempio n. 43
0
def test_fspace_elem_real_imag_conj(out_shape):
    """Check taking real/imaginary parts of fspace elements."""
    fspace = FunctionSpace(odl.IntervalProd(0, 1),
                           out_dtype=(complex, out_shape))

    ndim = len(out_shape)
    if ndim == 0:
        f_elem = fspace.element(func_complex_nd_oop)
    elif ndim == 1:
        f_elem = fspace.element(func_vec_complex_nd_oop)
    elif ndim == 2:
        f_elem = fspace.element(func_tens_complex_oop)
    else:
        assert False

    points = _points(fspace.domain, 4)
    mesh_shape = (5, )
    mesh = _meshgrid(fspace.domain, mesh_shape)
    point = 0.5
    values_points_shape = out_shape + (4, )
    values_mesh_shape = out_shape + mesh_shape

    result_points = f_elem(points)
    result_point = f_elem(point)
    result_mesh = f_elem(mesh)

    assert all_almost_equal(f_elem.real(points), result_points.real)
    assert all_almost_equal(f_elem.real(point), result_point.real)
    assert all_almost_equal(f_elem.real(mesh), result_mesh.real)
    assert all_almost_equal(f_elem.imag(points), result_points.imag)
    assert all_almost_equal(f_elem.imag(point), result_point.imag)
    assert all_almost_equal(f_elem.imag(mesh), result_mesh.imag)
    assert all_almost_equal(f_elem.conj()(points), result_points.conj())
    assert all_almost_equal(f_elem.conj()(point), np.conj(result_point))
    assert all_almost_equal(f_elem.conj()(mesh), result_mesh.conj())

    out_points = np.empty(values_points_shape, dtype=float)
    out_mesh = np.empty(values_mesh_shape, dtype=float)

    f_elem.real(points, out=out_points)
    f_elem.real(mesh, out=out_mesh)

    assert all_almost_equal(out_points, result_points.real)
    assert all_almost_equal(out_mesh, result_mesh.real)

    f_elem.imag(points, out=out_points)
    f_elem.imag(mesh, out=out_mesh)

    assert all_almost_equal(out_points, result_points.imag)
    assert all_almost_equal(out_mesh, result_mesh.imag)

    out_points = np.empty(values_points_shape, dtype=complex)
    out_mesh = np.empty(values_mesh_shape, dtype=complex)

    f_elem.conj()(points, out=out_points)
    f_elem.conj()(mesh, out=out_mesh)

    assert all_almost_equal(out_points, result_points.conj())
    assert all_almost_equal(out_mesh, result_mesh.conj())
Esempio n. 44
0
def test_uniform_discr_fromdiscr_one_attr():
    # Change 1 attribute

    discr = odl.uniform_discr([0, -1], [1, 1], [10, 5])
    # csides = [0.1, 0.4]

    # min_corner -> translate, keep cells
    new_min_corner = [3, 7]
    true_new_end = [4, 9]

    new_discr = odl.uniform_discr_fromdiscr(discr, min_corner=new_min_corner)
    assert all_almost_equal(new_discr.min_corner, new_min_corner)
    assert all_almost_equal(new_discr.max_corner, true_new_end)
    assert all_equal(new_discr.shape, discr.shape)
    assert all_almost_equal(new_discr.cell_sides, discr.cell_sides)

    # max_corner -> translate, keep cells
    new_max_corner = [3, 7]
    true_new_begin = [2, 5]

    new_discr = odl.uniform_discr_fromdiscr(discr, max_corner=new_max_corner)
    assert all_almost_equal(new_discr.min_corner, true_new_begin)
    assert all_almost_equal(new_discr.max_corner, new_max_corner)
    assert all_equal(new_discr.shape, discr.shape)
    assert all_almost_equal(new_discr.cell_sides, discr.cell_sides)

    # nsamples -> resize cells, keep corners
    new_nsamples = (5, 20)
    true_new_csides = [0.2, 0.1]
    new_discr = odl.uniform_discr_fromdiscr(discr, nsamples=new_nsamples)
    assert all_almost_equal(new_discr.min_corner, discr.min_corner)
    assert all_almost_equal(new_discr.max_corner, discr.max_corner)
    assert all_equal(new_discr.shape, new_nsamples)
    assert all_almost_equal(new_discr.cell_sides, true_new_csides)

    # cell_sides -> resize cells, keep corners
    new_csides = [0.5, 0.2]
    true_new_nsamples = (2, 10)
    new_discr = odl.uniform_discr_fromdiscr(discr, cell_sides=new_csides)
    assert all_almost_equal(new_discr.min_corner, discr.min_corner)
    assert all_almost_equal(new_discr.max_corner, discr.max_corner)
    assert all_equal(new_discr.shape, true_new_nsamples)
    assert all_almost_equal(new_discr.cell_sides, new_csides)
Esempio n. 45
0
def test_fanflat_props(shift):
    """Test basic properties of 2d fanflat geometries."""
    full_angle = 2 * np.pi
    apart = odl.uniform_partition(0, full_angle, 10)
    dpart = odl.uniform_partition(0, 1, 10)
    src_rad = 10
    det_rad = 5
    translation = np.array([shift, shift], dtype=float)
    geom = odl.tomo.FanFlatGeometry(apart,
                                    dpart,
                                    src_rad,
                                    det_rad,
                                    translation=translation)

    assert geom.ndim == 2
    assert isinstance(geom.detector, odl.tomo.Flat1dDetector)

    # Check defaults
    assert all_almost_equal(geom.src_to_det_init, [0, 1])
    assert all_almost_equal(geom.src_position(0), translation + [0, -src_rad])
    assert all_almost_equal(geom.det_refpoint(0), translation + [0, det_rad])
    assert all_almost_equal(geom.det_point_position(0, 0),
                            geom.det_refpoint(0))
    assert all_almost_equal(geom.det_axis_init, [1, 0])
    assert all_almost_equal(geom.det_axis(0), [1, 0])
    assert all_almost_equal(geom.translation, translation)

    # Check that we first rotate, then shift along the rotated axis, which
    # is equivalent to shifting first and then rotating.
    # Here we expect to rotate the reference point to [-det_rad, 0] and then
    # shift by 1 (=detector param) along the detector axis [0, 1] at that
    # angle.
    # Global translation should come afterwards.
    assert all_almost_equal(geom.det_point_position(np.pi / 2, 1),
                            translation + [-det_rad, 1])
    assert all_almost_equal(geom.det_axis(np.pi / 2), [0, 1])

    # Detector to source vector. At param=0 it should be perpendicular to
    # the detector towards the source, here at pi/2 it should point into
    # the (+x) direction.
    # At any other parameter, when adding the non-normalized vector to the
    # detector point position, one should get the source position.
    assert all_almost_equal(geom.det_to_src(np.pi / 2, 0), [1, 0])
    src_pos = (geom.det_point_position(np.pi / 2, 1) +
               geom.det_to_src(np.pi / 2, 1, normalized=False))
    assert all_almost_equal(src_pos, geom.src_position(np.pi / 2))

    # Rotation matrix, should correspond to counter-clockwise rotation
    assert all_almost_equal(geom.rotation_matrix(np.pi / 2), [[0, -1], [1, 0]])

    # Make sure that the boundary cases are treated as valid
    geom.det_point_position(0, 0)
    geom.det_point_position(full_angle, 1)

    # Invalid parameter
    with pytest.raises(ValueError):
        geom.rotation_matrix(2 * full_angle)

    # Both radii zero
    with pytest.raises(ValueError):
        odl.tomo.FanFlatGeometry(apart, dpart, src_radius=0, det_radius=0)

    # Check that str and repr work without crashing and return something
    assert str(geom)
    assert repr(geom)
Esempio n. 46
0
def test_uniform_partition():

    min_pt = [0, 0]
    max_pt = [1, 2]
    shape = (4, 10)
    csides = [0.25, 0.2]

    # Test standard case
    part = odl.uniform_partition(min_pt, max_pt, shape, nodes_on_bdry=True)

    assert all_equal(part.min_pt, min_pt)
    assert all_equal(part.max_pt, max_pt)
    assert all_equal(part.grid.min_pt, min_pt)
    assert all_equal(part.grid.max_pt, max_pt)
    for cs in part.cell_sizes_vecs:
        # Check that all cell sizes are equal (except first and last which
        # are halved)
        assert np.allclose(np.diff(cs[1:-1]), 0)
        assert all_almost_equal(cs[0], cs[1] / 2)
        assert all_almost_equal(cs[-1], cs[-2] / 2)

    assert part[1:, 2:5].is_uniform
    assert part[1:, ::3].is_uniform

    # Test combinations of parameters
    true_part = odl.uniform_partition(min_pt,
                                      max_pt,
                                      shape,
                                      nodes_on_bdry=False)
    part = odl.uniform_partition(min_pt=min_pt,
                                 max_pt=max_pt,
                                 shape=shape,
                                 cell_sides=None)
    assert part == true_part
    part = odl.uniform_partition(min_pt=min_pt,
                                 max_pt=max_pt,
                                 shape=None,
                                 cell_sides=csides)
    assert part == true_part
    part = odl.uniform_partition(min_pt=min_pt,
                                 max_pt=None,
                                 shape=shape,
                                 cell_sides=csides)
    assert part == true_part
    part = odl.uniform_partition(min_pt=None,
                                 max_pt=max_pt,
                                 shape=shape,
                                 cell_sides=csides)
    assert part == true_part
    part = odl.uniform_partition(min_pt=min_pt,
                                 max_pt=max_pt,
                                 shape=shape,
                                 cell_sides=csides)
    assert part == true_part

    # Test parameters per axis
    part = odl.uniform_partition(min_pt=[0, None],
                                 max_pt=[None, 2],
                                 shape=shape,
                                 cell_sides=csides)
    assert part == true_part
    part = odl.uniform_partition(min_pt=min_pt,
                                 max_pt=[None, 2],
                                 shape=(4, None),
                                 cell_sides=csides)
    assert part == true_part
    part = odl.uniform_partition(min_pt=min_pt,
                                 max_pt=max_pt,
                                 shape=(None, 4),
                                 cell_sides=[0.25, None])

    # Test robustness against numerical error
    part = odl.uniform_partition(min_pt=min_pt,
                                 max_pt=[None, np.sqrt(2)**2],
                                 shape=shape,
                                 cell_sides=[0.25, np.log(np.exp(0.2))])
    assert part.approx_equals(true_part, atol=1e-8)

    # Test nodes_on_bdry
    # Here we compute stuff, so we can only expect approximate equality
    csides = [1 / 3., 2 / 9.5]
    true_part = odl.uniform_partition(min_pt,
                                      max_pt,
                                      shape,
                                      nodes_on_bdry=(True, (False, True)))
    part = odl.uniform_partition(min_pt=[0, None],
                                 max_pt=[None, 2],
                                 shape=shape,
                                 cell_sides=csides,
                                 nodes_on_bdry=(True, (False, True)))
    assert part.approx_equals(true_part, atol=1e-8)
    part = odl.uniform_partition(min_pt=min_pt,
                                 max_pt=[None, 2],
                                 shape=(4, None),
                                 cell_sides=csides,
                                 nodes_on_bdry=(True, (False, True)))
    assert part.approx_equals(true_part, atol=1e-8)
    part = odl.uniform_partition(min_pt=min_pt,
                                 max_pt=max_pt,
                                 shape=(None, 10),
                                 cell_sides=[1 / 3., None],
                                 nodes_on_bdry=(True, (False, True)))
    assert part.approx_equals(true_part, atol=1e-8)

    # Test error scenarios

    # Not enough parameters (total / per axis)
    with pytest.raises(ValueError):
        odl.uniform_partition()

    with pytest.raises(ValueError):
        odl.uniform_partition(min_pt, max_pt)

    with pytest.raises(ValueError):
        part = odl.uniform_partition(min_pt=[0, None],
                                     max_pt=[1, None],
                                     shape=shape,
                                     cell_sides=csides)

    with pytest.raises(ValueError):
        part = odl.uniform_partition(min_pt=min_pt,
                                     max_pt=[1, None],
                                     shape=(4, None),
                                     cell_sides=csides)

    # Parameters with inconsistent sizes
    with pytest.raises(ValueError):
        part = odl.uniform_partition(min_pt=min_pt,
                                     max_pt=[1, None, None],
                                     shape=shape)

    # Too large rounding error in computing shape
    with pytest.raises(ValueError):
        part = odl.uniform_partition(min_pt=min_pt,
                                     max_pt=max_pt,
                                     cell_sides=[0.25, 0.2001])

    # Inconsistent values
    with pytest.raises(ValueError):
        part = odl.uniform_partition(min_pt=min_pt,
                                     max_pt=max_pt,
                                     shape=shape,
                                     cell_sides=[0.25, 0.2001])
Esempio n. 47
0
def test_chambolle_pock_solver_simple_space():
    """Test for the Chambolle-Pock algorithm."""

    # Create a discretized image space
    space = odl.uniform_discr(0, 1, DATA.size)

    # Operator
    op = odl.IdentityOperator(space)

    # Starting point (image)
    discr_vec = op.domain.element(DATA)

    # Relaxation variable required to resume iteration
    discr_vec_relax = discr_vec.copy()

    # Dual variable required to resume iteration
    discr_dual = op.range.zero()

    # Functional, use the same functional for F^* and G
    g = odl.solvers.ZeroFunctional(space)
    f = g.convex_conj

    # Run the algorithm
    chambolle_pock_solver(discr_vec,
                          f,
                          g,
                          op,
                          tau=TAU,
                          sigma=SIGMA,
                          theta=THETA,
                          niter=1,
                          callback=None,
                          x_relax=discr_vec_relax,
                          y=discr_dual)

    # Explicit computation
    vec_expl = (1 - TAU * SIGMA) * DATA

    assert all_almost_equal(discr_vec, vec_expl, PLACES)

    # Explicit computation of the value of the relaxation variable
    vec_relax_expl = (1 + THETA) * vec_expl - THETA * DATA

    assert all_almost_equal(discr_vec_relax, vec_relax_expl, PLACES)

    # Resume iteration with previous x but without previous relaxation
    chambolle_pock_solver(discr_vec,
                          f,
                          g,
                          op,
                          tau=TAU,
                          sigma=SIGMA,
                          theta=THETA,
                          niter=1)

    vec_expl *= (1 - SIGMA * TAU)
    assert all_almost_equal(discr_vec, vec_expl, PLACES)

    # Resume iteration with x1 as above and with relaxation parameter
    discr_vec[:] = vec_expl
    chambolle_pock_solver(discr_vec,
                          f,
                          g,
                          op,
                          tau=TAU,
                          sigma=SIGMA,
                          theta=THETA,
                          niter=1,
                          x_relax=discr_vec_relax,
                          y=discr_dual)

    vec_expl = vec_expl - TAU * SIGMA * (DATA + vec_relax_expl)
    assert all_almost_equal(discr_vec, vec_expl, PLACES)

    # Test acceleration parameter: use output argument for the relaxation
    # variable since otherwise two iterations are required for the
    # relaxation to take effect on the input variable
    # Acceleration parameter gamma=0 corresponds to relaxation parameter
    # theta=1 without acceleration

    # Relaxation parameter 1 and no acceleration
    discr_vec = op.domain.element(DATA)
    discr_vec_relax_no_gamma = op.domain.element(DATA)
    chambolle_pock_solver(discr_vec,
                          f,
                          g,
                          op,
                          tau=TAU,
                          sigma=SIGMA,
                          theta=1,
                          gamma=None,
                          niter=1,
                          x_relax=discr_vec_relax_no_gamma)

    # Acceleration parameter 0, overwrites relaxation parameter
    discr_vec = op.domain.element(DATA)
    discr_vec_relax_g0 = op.domain.element(DATA)
    chambolle_pock_solver(discr_vec,
                          f,
                          g,
                          op,
                          tau=TAU,
                          sigma=SIGMA,
                          theta=0,
                          gamma=0,
                          niter=1,
                          x_relax=discr_vec_relax_g0)

    assert discr_vec != discr_vec_relax_no_gamma
    assert all_almost_equal(discr_vec_relax_no_gamma, discr_vec_relax_g0)

    # Test callback execution
    chambolle_pock_solver(discr_vec,
                          f,
                          g,
                          op,
                          tau=TAU,
                          sigma=SIGMA,
                          theta=THETA,
                          niter=1,
                          callback=odl.solvers.CallbackPrintIteration())
Esempio n. 48
0
def test_helical_cone_flat_props(shift):
    """Test basic properties of 3D helical cone beam geometries."""
    full_angle = 2 * np.pi
    apart = odl.uniform_partition(0, full_angle, 10)
    dpart = odl.uniform_partition([0, 0], [1, 1], (10, 10))
    src_rad = 10
    det_rad = 5
    pitch = 2.0
    translation = np.array([shift, shift, shift], dtype=float)
    geom = odl.tomo.ConeFlatGeometry(apart,
                                     dpart,
                                     src_rad,
                                     det_rad,
                                     pitch=pitch,
                                     translation=translation)

    assert geom.ndim == 3
    assert isinstance(geom.detector, odl.tomo.Flat2dDetector)

    # Check defaults
    assert all_almost_equal(geom.axis, [0, 0, 1])
    assert all_almost_equal(geom.src_to_det_init, [0, 1, 0])
    assert all_almost_equal(geom.src_position(0),
                            translation + [0, -src_rad, 0])
    assert all_almost_equal(geom.det_refpoint(0),
                            translation + [0, det_rad, 0])
    assert all_almost_equal(geom.det_point_position(0, [0, 0]),
                            geom.det_refpoint(0))
    assert all_almost_equal(geom.det_axes_init, ([1, 0, 0], [0, 0, 1]))
    assert all_almost_equal(geom.det_axes(0), ([1, 0, 0], [0, 0, 1]))
    assert all_almost_equal(geom.translation, translation)

    # Check that we first rotate, then shift along the initial detector
    # axes rotated according to the angle, which is equivalent to shifting
    # first and then rotating.
    # Here we expect to rotate the reference point to [-det_rad, 0, 0] and
    # then shift by (1, 1) (=detector param) along the detector axes
    # ([0, 1, 0], [0, 0, 1]) at that angle. In addition, everything is
    # shifted along the rotation axis [0, 0, 1] by 1/4 of the pitch
    # (since the pitch is the vertical distance after a full turn 2*pi).
    # Global translation should come last.
    assert all_almost_equal(geom.det_point_position(np.pi / 2, [1, 1]),
                            translation + [-det_rad, 1, 1 + pitch / 4])

    # Make sure that source and detector move at the same height and stay
    # opposite of each other
    src_to_det_ref = (geom.det_refpoint(np.pi / 2) -
                      geom.src_position(np.pi / 2))
    assert np.dot(geom.axis, src_to_det_ref) == pytest.approx(0)
    assert np.linalg.norm(src_to_det_ref) == pytest.approx(src_rad + det_rad)

    # Detector to source vector. At param=0 it should be perpendicular to
    # the detector towards the source, here at pi/2 it should point into
    # the (+x) direction.
    # At any other parameter, when adding the non-normalized vector to the
    # detector point position, one should get the source position.
    assert all_almost_equal(geom.det_to_src(np.pi / 2, [0, 0]), [1, 0, 0])
    src_pos = (geom.det_point_position(np.pi / 2, [1, 1]) +
               geom.det_to_src(np.pi / 2, [1, 1], normalized=False))
    assert all_almost_equal(src_pos, geom.src_position(np.pi / 2))

    # Rotation matrix, should correspond to counter-clockwise rotation
    # arond the z axis
    assert all_almost_equal(geom.rotation_matrix(np.pi / 2),
                            [[0, -1, 0], [1, 0, 0], [0, 0, 1]])

    # offset_along_axis
    geom = odl.tomo.ConeFlatGeometry(apart,
                                     dpart,
                                     src_rad,
                                     det_rad,
                                     pitch=pitch,
                                     offset_along_axis=0.5)
    assert all_almost_equal(geom.det_refpoint(0), [0, det_rad, 0.5])

    # Make sure that the boundary cases are treated as valid
    geom.det_point_position(0, [0, 0])
    geom.det_point_position(full_angle, [1, 1])

    # Invalid parameter
    with pytest.raises(ValueError):
        geom.rotation_matrix(2 * full_angle)

    # Zero not allowed as axis
    with pytest.raises(ValueError):
        odl.tomo.ConeFlatGeometry(apart,
                                  dpart,
                                  src_rad,
                                  det_rad,
                                  pitch=pitch,
                                  axis=[0, 0, 0])

    # Detector axex should not be parallel or otherwise result in a
    # linear dependent triplet
    with pytest.raises(ValueError):
        odl.tomo.ConeFlatGeometry(apart,
                                  dpart,
                                  src_rad,
                                  det_rad,
                                  pitch=pitch,
                                  det_axes_init=([0, 1, 0], [0, 1, 0]))
    with pytest.raises(ValueError):
        odl.tomo.ConeFlatGeometry(apart,
                                  dpart,
                                  src_rad,
                                  det_rad,
                                  pitch=pitch,
                                  det_axes_init=([0, 0, 0], [0, 1, 0]))

    # Both radii zero
    with pytest.raises(ValueError):
        odl.tomo.ConeFlatGeometry(apart,
                                  dpart,
                                  src_radius=0,
                                  det_radius=0,
                                  pitch=pitch)

    # Check that str and repr work without crashing and return something
    assert str(geom)
    assert repr(geom)
Esempio n. 49
0
def test_ufunc(impl, ufunc):
    space = odl.uniform_discr([0, 0], [1, 1], (2, 2), impl=impl)
    name, n_args, n_out, _ = ufunc
    if (np.issubsctype(space.dtype, np.floating) and
            name in ['bitwise_and',
                     'bitwise_or',
                     'bitwise_xor',
                     'invert',
                     'left_shift',
                     'right_shift']):
        # Skip integer only methods if floating point type
        return

    # Get the ufunc from numpy as reference
    ufunc = getattr(np, name)

    # Create some data
    arrays, vectors = example_vectors(space, n_args + n_out)
    in_arrays = arrays[:n_args]
    out_arrays = arrays[n_args:]
    data_vector = vectors[0]
    in_vectors = vectors[1:n_args]
    out_vectors = vectors[n_args:]

    # Verify type
    assert isinstance(data_vector.ufunc,
                      odl.util.ufuncs.DiscreteLpUFuncs)

    # Out of place:
    np_result = ufunc(*in_arrays)
    vec_fun = getattr(data_vector.ufunc, name)
    odl_result = vec_fun(*in_vectors)
    assert all_almost_equal(np_result, odl_result)

    # Test type of output
    if n_out == 1:
        assert isinstance(odl_result, space.element_type)
    elif n_out > 1:
        for i in range(n_out):
            assert isinstance(odl_result[i], space.element_type)

    # In place:
    np_result = ufunc(*(in_arrays + out_arrays))
    vec_fun = getattr(data_vector.ufunc, name)
    odl_result = vec_fun(*(in_vectors + out_vectors))
    assert all_almost_equal(np_result, odl_result)

    # Test inplace actually holds:
    if n_out == 1:
        assert odl_result is out_vectors[0]
    elif n_out > 1:
        for i in range(n_out):
            assert odl_result[i] is out_vectors[i]

    # Test out of place with np data
    np_result = ufunc(*in_arrays)
    vec_fun = getattr(data_vector.ufunc, name)
    odl_result = vec_fun(*in_arrays[1:])
    assert all_almost_equal(np_result, odl_result)

    # Test type of output
    if n_out == 1:
        assert isinstance(odl_result, space.element_type)
    elif n_out > 1:
        for i in range(n_out):
            assert isinstance(odl_result[i], space.element_type)
Esempio n. 50
0
def test_gradient(space, method, padding):
    """Discretized spatial gradient operator."""

    places = 2 if space.dtype == np.float32 else 4

    with pytest.raises(TypeError):
        Gradient(odl.rn(1), method=method)

    if isinstance(padding, tuple):
        pad_mode, pad_const = padding
    else:
        pad_mode, pad_const = padding, 0

    # DiscreteLp Vector
    dom_vec = noise_element(space)
    dom_vec_arr = dom_vec.asarray()

    # gradient
    grad = Gradient(space,
                    method=method,
                    pad_mode=pad_mode,
                    pad_const=pad_const)
    grad_vec = grad(dom_vec)
    assert len(grad_vec) == space.ndim

    # computation of gradient components with helper function
    for axis, dx in enumerate(space.cell_sides):
        diff = finite_diff(dom_vec_arr,
                           axis=axis,
                           dx=dx,
                           method=method,
                           pad_mode=pad_mode,
                           pad_const=pad_const)

        assert all_almost_equal(grad_vec[axis].asarray(), diff)

    # Test adjoint operator
    derivative = grad.derivative()
    ran_vec = noise_element(derivative.range)
    deriv_grad_vec = derivative(dom_vec)
    adj_grad_vec = derivative.adjoint(ran_vec)
    lhs = ran_vec.inner(deriv_grad_vec)
    rhs = dom_vec.inner(adj_grad_vec)

    # Check not to use trivial data
    assert lhs != 0
    assert rhs != 0
    assert almost_equal(lhs, rhs, places=places)

    # higher dimensional arrays
    lin_size = 3
    for ndim in [1, 3, 6]:

        # DiscreteLpElement
        space = odl.uniform_discr([0.] * ndim, [1.] * ndim, [lin_size] * ndim)
        dom_vec = odl.phantom.cuboid(space, [0.2] * ndim, [0.8] * ndim)

        # gradient
        grad = Gradient(space,
                        method=method,
                        pad_mode=pad_mode,
                        pad_const=pad_const)
        grad(dom_vec)
Esempio n. 51
0
def test_source_shifts_2d():
    """Check that source shifts are handled correctly.

    We forward project a Shepp-Logan phantom and check that reconstruction
    with flying focal spot is equal to a sum of reconstructions with two
    geometries which mimic ffs by using initial angular offsets and
    detector shifts
    """

    if not odl.tomo.ASTRA_AVAILABLE:
        pytest.skip(msg='ASTRA required but not available')

    d = 10
    space = odl.uniform_discr([-1] * 2, [1] * 2, [d] * 2)
    phantom = odl.phantom.cuboid(space, [-1/3] * 2, [1/3] * 2)

    full_angle = 2 * np.pi
    n_angles = 2 * 10
    src_rad = 2
    det_rad = 2
    apart = odl.uniform_partition(0, full_angle, n_angles)
    dpart = odl.uniform_partition(-4, 4, 8 * d)
    # Source positions with flying focal spot should correspond to
    # source positions of 2 geometries with different starting positions
    shift1 = np.array([0.0, -0.3])
    shift2 = np.array([0.0, 0.3])
    init = np.array([1, 0], dtype=np.float32)
    det_init = np.array([0, -1], dtype=np.float32)

    ffs = partial(odl.tomo.flying_focal_spot,
                  apart=apart,
                  shifts=[shift1, shift2])
    geom_ffs = odl.tomo.FanBeamGeometry(apart, dpart,
                                        src_rad, det_rad,
                                        src_to_det_init=init,
                                        det_axis_init=det_init,
                                        src_shift_func=ffs,
                                        det_shift_func=ffs)
    # angles must be shifted to match discretization of apart
    ang1 = -full_angle / (n_angles * 2)
    apart1 = odl.uniform_partition(ang1, full_angle + ang1, n_angles // 2)
    ang2 = full_angle / (n_angles * 2)
    apart2 = odl.uniform_partition(ang2, full_angle + ang2, n_angles // 2)

    init1 = init + np.array([0, shift1[1]]) / (src_rad + shift1[0])
    init2 = init + np.array([0, shift2[1]]) / (src_rad + shift2[0])
    # radius also changes when a shift is applied
    src_rad1 = np.linalg.norm(np.array([src_rad, 0]) + shift1)
    src_rad2 = np.linalg.norm(np.array([src_rad, 0]) + shift2)
    det_rad1 = np.linalg.norm(
        np.array([det_rad, shift1[1] / src_rad * det_rad]))
    det_rad2 = np.linalg.norm(
        np.array([det_rad, shift2[1] / src_rad * det_rad]))
    geom1 = odl.tomo.FanBeamGeometry(apart1, dpart,
                                     src_rad1, det_rad1,
                                     src_to_det_init=init1,
                                     det_axis_init=det_init)
    geom2 = odl.tomo.FanBeamGeometry(apart2, dpart,
                                     src_rad2, det_rad2,
                                     src_to_det_init=init2,
                                     det_axis_init=det_init)

    # check ray transform
    op_ffs = odl.tomo.RayTransform(space, geom_ffs)
    op1 = odl.tomo.RayTransform(space, geom1)
    op2 = odl.tomo.RayTransform(space, geom2)
    y_ffs = op_ffs(phantom)
    y1 = op1(phantom).asarray()
    y2 = op2(phantom).asarray()
    assert all_almost_equal(y_ffs[::2], y1)
    assert all_almost_equal(y_ffs[1::2], y2)

    # check back-projection
    im = op_ffs.adjoint(y_ffs).asarray()
    im1 = op1.adjoint(y1).asarray()
    im2 = op2.adjoint(y2).asarray()
    im_combined = (im1 + im2) / 2
    rel_error = np.abs((im - im_combined)[im > 0] / im[im > 0])
    assert np.max(rel_error) < 1e-6
Esempio n. 52
0
def test_ufunc_corner_cases(odl_tspace_impl):
    """Check if some corner cases are handled correctly."""
    impl = odl_tspace_impl
    space = odl.uniform_discr([0, 0], [1, 1], (2, 3), impl=impl)
    x = space.element([[-1, 0, 1], [1, 2, 3]])
    space_no_w = odl.uniform_discr([0, 0], [1, 1], (2, 3),
                                   impl=impl,
                                   weighting=1.0)

    # --- UFuncs with nin = 1, nout = 1 --- #

    with pytest.raises(ValueError):
        # Too many arguments
        x.__array_ufunc__(np.sin, '__call__', x, np.ones((2, 3)))

    # Check that `out=(None,)` is the same as not providing `out`
    res = x.__array_ufunc__(np.sin, '__call__', x, out=(None, ))
    assert all_almost_equal(res, np.sin(x.asarray()))
    # Check that the result space is the same
    assert res.space == space

    # Check usage of `order` argument
    for order in ('C', 'F'):
        res = x.__array_ufunc__(np.sin, '__call__', x, order=order)
        assert all_almost_equal(res, np.sin(x.asarray()))
        assert res.tensor.data.flags[order + '_CONTIGUOUS']

    # Check usage of `dtype` argument
    res = x.__array_ufunc__(np.sin, '__call__', x, dtype=complex)
    assert all_almost_equal(res, np.sin(x.asarray(), dtype=complex))
    assert res.dtype == complex

    # Check propagation of weightings
    y = space_no_w.one()
    res = y.__array_ufunc__(np.sin, '__call__', y)
    assert res.space.weighting == space_no_w.weighting
    y = space_no_w.one()
    res = y.__array_ufunc__(np.sin, '__call__', y)
    assert res.space.weighting == space_no_w.weighting

    # --- UFuncs with nin = 2, nout = 1 --- #

    with pytest.raises(ValueError):
        # Too few arguments
        x.__array_ufunc__(np.add, '__call__', x)

    with pytest.raises(ValueError):
        # Too many outputs
        out1, out2 = np.empty_like(x), np.empty_like(x)
        x.__array_ufunc__(np.add, '__call__', x, x, out=(out1, out2))

    # Check that npy_array += odl_vector works
    arr = np.ones((2, 3))
    arr += x
    assert all_almost_equal(arr, x.asarray() + 1)
    # For Numpy >= 1.13, this will be equivalent
    arr = np.ones((2, 3))
    res = x.__array_ufunc__(np.add, '__call__', arr, x, out=(arr, ))
    assert all_almost_equal(arr, x.asarray() + 1)
    assert res is arr

    # --- `accumulate` --- #

    res = x.__array_ufunc__(np.add, 'accumulate', x)
    assert all_almost_equal(res, np.add.accumulate(x.asarray()))
    assert res.space == space
    arr = np.empty_like(x)
    res = x.__array_ufunc__(np.add, 'accumulate', x, out=(arr, ))
    assert all_almost_equal(arr, np.add.accumulate(x.asarray()))
    assert res is arr

    # `accumulate` with other dtype
    res = x.__array_ufunc__(np.add, 'accumulate', x, dtype='float32')
    assert res.dtype == 'float32'

    # Error scenarios
    with pytest.raises(ValueError):
        # Too many `out` arguments
        out1, out2 = np.empty_like(x), np.empty_like(x)
        x.__array_ufunc__(np.add, 'accumulate', x, out=(out1, out2))

    # --- `reduce` --- #

    res = x.__array_ufunc__(np.add, 'reduce', x)
    assert all_almost_equal(res, np.add.reduce(x.asarray()))

    with pytest.raises(ValueError):
        x.__array_ufunc__(np.add, 'reduce', x, keepdims=True)

    # With `out` argument and `axis`
    out_ax0 = np.empty(3)
    res = x.__array_ufunc__(np.add, 'reduce', x, axis=0, out=(out_ax0, ))
    assert all_almost_equal(out_ax0, np.add.reduce(x.asarray(), axis=0))
    assert res is out_ax0
    out_ax1 = odl.rn(2).element()
    res = x.__array_ufunc__(np.add, 'reduce', x, axis=1, out=(out_ax1, ))
    assert all_almost_equal(out_ax1, np.add.reduce(x.asarray(), axis=1))
    assert res is out_ax1

    # Addition is re-orderable, so we can give multiple axes
    res = x.__array_ufunc__(np.add, 'reduce', x, axis=(0, 1))
    assert res == pytest.approx(np.add.reduce(x.asarray(), axis=(0, 1)))

    # Constant weighting should be preserved (recomputed from cell
    # volume)
    y = space.one()
    res = y.__array_ufunc__(np.add, 'reduce', y, axis=0)
    assert res.space.weighting.const == pytest.approx(space.cell_sides[1])

    # Check that `exponent` is propagated
    space_1 = odl.uniform_discr([0, 0], [1, 1], (2, 3), impl=impl, exponent=1)
    z = space_1.one()
    res = z.__array_ufunc__(np.add, 'reduce', z, axis=0)
    assert res.space.exponent == 1

    # --- `outer` --- #

    # Check that weightings are propagated correctly
    x = y = space.one()
    res = x.__array_ufunc__(np.add, 'outer', x, y)
    assert isinstance(res.space.weighting, ConstWeighting)
    assert res.space.weighting.const == pytest.approx(x.space.weighting.const *
                                                      y.space.weighting.const)

    x = space.one()
    y = space_no_w.one()
    res = x.__array_ufunc__(np.add, 'outer', x, y)
    assert isinstance(res.space.weighting, ConstWeighting)
    assert res.space.weighting.const == pytest.approx(x.space.weighting.const)

    x = y = space_no_w.one()
    res = x.__array_ufunc__(np.add, 'outer', x, y)
    assert not res.space.is_weighted
Esempio n. 53
0
def test_source_shifts_3d():
    """Check that source shifts are handled correctly.

    We forward project a Shepp-Logan phantom and check that reconstruction
    with flying focal spot is equal to a sum of reconstructions with two
    geometries which mimic ffs by using initial angular offsets and
    detector shifts
    """
    if not odl.tomo.ASTRA_CUDA_AVAILABLE:
        pytest.skip(msg='ASTRA_CUDA not available, skipping 3d test')

    d = 10
    space = odl.uniform_discr([-1] * 3, [1] * 3, [d] * 3)
    phantom = odl.phantom.cuboid(space, [-1/3] * 3, [1/3] * 3)

    full_angle = 2 * np.pi
    n_angles = 2 * 10
    apart = odl.uniform_partition(0, full_angle, n_angles)
    dpart = odl.uniform_partition([-4] * 2, [4] * 2, [8 * d] * 2)
    src_rad = 2
    det_rad = 2
    pitch = 0.2
    # Source positions with flying focal spot should correspond to
    # source positions of 2 geometries with different starting positions
    shift1 = np.array([0.0, -0.2, 0.1])
    shift2 = np.array([0.0, 0.2, -0.1])
    init = np.array([1, 0, 0], dtype=np.float32)
    det_init = np.array([[0, -1, 0], [0, 0, 1]], dtype=np.float32)
    ffs = partial(odl.tomo.flying_focal_spot,
                  apart=apart,
                  shifts=[shift1, shift2])
    geom_ffs = odl.tomo.ConeBeamGeometry(apart, dpart,
                                         src_rad, det_rad,
                                         src_to_det_init=init,
                                         det_axes_init=det_init,
                                         src_shift_func=ffs,
                                         det_shift_func=ffs,
                                         pitch=pitch)
    # angles must be shifted to match discretization of apart
    ang1 = -full_angle / (n_angles * 2)
    apart1 = odl.uniform_partition(ang1, full_angle + ang1, n_angles // 2)
    ang2 = full_angle / (n_angles * 2)
    apart2 = odl.uniform_partition(ang2, full_angle + ang2, n_angles // 2)

    init1 = init + np.array([0, shift1[1], 0]) / (src_rad + shift1[0])
    init2 = init + np.array([0, shift2[1], 0]) / (src_rad + shift2[0])
    # radius also changes when a shift is applied
    src_rad1 = np.linalg.norm(np.array([src_rad + shift1[0], shift1[1], 0]))
    src_rad2 = np.linalg.norm(np.array([src_rad + shift2[0], shift2[1], 0]))
    det_rad1 = np.linalg.norm(
        np.array([det_rad, det_rad / src_rad * shift1[1], 0]))
    det_rad2 = np.linalg.norm(
        np.array([det_rad, det_rad / src_rad * shift2[1], 0]))
    geom1 = odl.tomo.ConeBeamGeometry(apart1, dpart, src_rad1, det_rad1,
                                      src_to_det_init=init1,
                                      det_axes_init=det_init,
                                      offset_along_axis=shift1[2],
                                      pitch=pitch)
    geom2 = odl.tomo.ConeBeamGeometry(apart2, dpart, src_rad2, det_rad2,
                                      src_to_det_init=init2,
                                      det_axes_init=det_init,
                                      offset_along_axis=shift2[2],
                                      pitch=pitch)

    assert all_almost_equal(geom_ffs.src_position(geom_ffs.angles)[::2],
                            geom1.src_position(geom1.angles))
    assert all_almost_equal(geom_ffs.src_position(geom_ffs.angles)[1::2],
                            geom2.src_position(geom2.angles))

    assert all_almost_equal(geom_ffs.det_refpoint(geom_ffs.angles)[::2],
                            geom1.det_refpoint(geom1.angles))
    assert all_almost_equal(geom_ffs.det_refpoint(geom_ffs.angles)[1::2],
                            geom2.det_refpoint(geom2.angles))

    assert all_almost_equal(geom_ffs.det_axes(geom_ffs.angles)[::2],
                            geom1.det_axes(geom1.angles))
    assert all_almost_equal(geom_ffs.det_axes(geom_ffs.angles)[1::2],
                            geom2.det_axes(geom2.angles))

    op_ffs = odl.tomo.RayTransform(space, geom_ffs)
    op1 = odl.tomo.RayTransform(space, geom1)
    op2 = odl.tomo.RayTransform(space, geom2)
    y_ffs = op_ffs(phantom)
    y1 = op1(phantom)
    y2 = op2(phantom)
    assert all_almost_equal(np.mean(y_ffs[::2], axis=(1, 2)),
                            np.mean(y1, axis=(1, 2)))
    assert all_almost_equal(np.mean(y_ffs[1::2], axis=(1, 2)),
                            np.mean(y2, axis=(1, 2)))
    im = op_ffs.adjoint(y_ffs).asarray()
    im_combined = (op1.adjoint(y1).asarray() + op2.adjoint(y2).asarray())
    # the scaling is a bit off for older versions of astra
    im_combined = im_combined / np.sum(im_combined) * np.sum(im)
    rel_error = np.abs((im - im_combined)[im > 0] / im[im > 0])
    assert np.max(rel_error) < 1e-6
def test_parallel_3d_props(shift):
    """Test basic properties of 3D parallel geometries."""
    full_angle = np.pi
    apart = odl.uniform_partition(0, full_angle, 10)
    dpart = odl.uniform_partition([0, 0], [1, 1], (10, 10))
    translation = np.array([shift, shift, shift], dtype=float)
    geom = odl.tomo.Parallel3dAxisGeometry(apart,
                                           dpart,
                                           translation=translation)

    assert geom.ndim == 3
    assert isinstance(geom.detector, odl.tomo.Flat2dDetector)

    # Check defaults
    assert all_almost_equal(geom.axis, [0, 0, 1])
    assert all_almost_equal(geom.det_pos_init, translation + [0, 1, 0])
    assert all_almost_equal(geom.det_refpoint(0), geom.det_pos_init)
    assert all_almost_equal(geom.det_point_position(0, [0, 0]),
                            geom.det_pos_init)
    assert all_almost_equal(geom.det_axes_init, ([1, 0, 0], [0, 0, 1]))
    assert all_almost_equal(geom.det_axes(0), ([1, 0, 0], [0, 0, 1]))
    assert all_almost_equal(geom.translation, translation)

    # Check that we first rotate, then shift along the initial detector
    # axes rotated according to the angle, which is equivalent to shifting
    # first and then rotating.
    # Here we expect to rotate the reference point to [-1, 0, 0] and then
    # shift by (1, 1) (=detector param) along the detector axes
    # ([0, 1, 0], [0, 0, 1]) at that angle.
    # Global translation should come last.
    assert all_almost_equal(geom.det_point_position(np.pi / 2, [1, 1]),
                            translation + [-1, 1, 1])

    # Detector to source vector, should be independent of the detector
    # parameter. At pi/2 it should point into the (+x) direction.
    assert all_almost_equal(geom.det_to_src(np.pi / 2, [0, 0]), [1, 0, 0])
    assert all_almost_equal(geom.det_to_src(np.pi / 2, [1, 1]), [1, 0, 0])

    # Rotation matrix, should correspond to counter-clockwise rotation
    # arond the z axis
    assert all_almost_equal(geom.rotation_matrix(np.pi / 2),
                            [[0, -1, 0], [1, 0, 0], [0, 0, 1]])

    # Make sure that the boundary cases are treated as valid
    geom.det_point_position(0, [0, 0])
    geom.det_point_position(full_angle, [1, 1])

    # Invalid parameter
    with pytest.raises(ValueError):
        geom.rotation_matrix(2 * full_angle)

    # Zero not allowed as axis
    with pytest.raises(ValueError):
        odl.tomo.Parallel3dAxisGeometry(apart, dpart, axis=[0, 0, 0])

    # Detector axex should not be parallel or otherwise result in a
    # linear dependent triplet
    with pytest.raises(ValueError):
        odl.tomo.Parallel3dAxisGeometry(apart,
                                        dpart,
                                        det_axes_init=([0, 1, 0], [0, 1, 0]))
    with pytest.raises(ValueError):
        odl.tomo.Parallel3dAxisGeometry(apart,
                                        dpart,
                                        det_axes_init=([0, 0, 0], [0, 1, 0]))

    # Check that str and repr work without crashing and return something
    assert str(geom)
    assert repr(geom)
Esempio n. 55
0
def test_dwt():
    # Verify that the operator works as axpected
    # 1D test
    n = 16
    x = np.zeros(n)
    x[5:10] = 1
    wbasis = pywt.Wavelet('db1')
    nscales = 2
    mode = 'sym'
    size_list = coeff_size_list((n,), nscales, wbasis, mode)

    # Define a discretized domain
    domain = odl.FunctionSpace(odl.Interval([-1], [1]))
    nPoints = np.array([n])
    disc_domain = odl.uniform_discr_fromspace(domain, nPoints)
    disc_phantom = disc_domain.element(x)

    # Create the discrete wavelet transform operator.
    # Only the domain of the operator needs to be defined
    Wop = WaveletTransform(disc_domain, nscales, wbasis, mode)

    # Compute the discrete wavelet transform of discrete imput image
    coeffs = Wop(disc_phantom)

    # Determine the correct range for Wop and verify that coeffs
    # is an element of it
    ran_size = np.prod(size_list[0])
    ran_size += sum(np.prod(shape) for shape in size_list[1:-1])
    disc_range = disc_domain.dspace_type(ran_size, dtype=disc_domain.dtype)
    assert coeffs in disc_range

    # Compute the inverse wavelet transform
    reconstruction1 = Wop.inverse(coeffs)
    # With othogonal wavelets the inverse is the adjoint
    reconstruction2 = Wop.adjoint(coeffs)
    # Verify that the output of Wop.inverse and Wop.adjoint are the same
    assert all_almost_equal(reconstruction1.asarray(),
                            reconstruction2.asarray())

    # Verify that reconstructions lie in correct discretized domain
    assert reconstruction1 in disc_domain
    assert reconstruction2 in disc_domain
    assert all_almost_equal(reconstruction1.asarray(), x)
    assert all_almost_equal(reconstruction2.asarray(), x)

    # ---------------------------------------------------------------
    # 2D test
    n = 16
    x = np.zeros((n, n))
    x[5:10, 5:10] = 1
    wbasis = pywt.Wavelet('db1')
    nscales = 2
    mode = 'sym'
    size_list = coeff_size_list((n, n), nscales, wbasis, mode)

    # Define a discretized domain
    domain = odl.FunctionSpace(odl.Rectangle([-1, -1], [1, 1]))
    nPoints = np.array([n, n])
    disc_domain = odl.uniform_discr_fromspace(domain, nPoints)
    disc_phantom = disc_domain.element(x)

    # Create the discrete wavelet transform operator.
    # Only the domain of the operator needs to be defined
    Wop = WaveletTransform(disc_domain, nscales, wbasis, mode)

    # Compute the discrete wavelet transform of discrete imput image
    coeffs = Wop(disc_phantom)

    # Determine the correct range for Wop and verify that coeffs
    # is an element of it
    ran_size = np.prod(size_list[0])
    ran_size += sum(3 * np.prod(shape) for shape in size_list[1:-1])
    disc_range = disc_domain.dspace_type(ran_size, dtype=disc_domain.dtype)
    assert coeffs in disc_range

    # Compute the inverse wavelet transform
    reconstruction1 = Wop.inverse(coeffs)
    # With othogonal wavelets the inverse is the adjoint
    reconstruction2 = Wop.adjoint(coeffs)
    # Verify that the output of Wop.inverse and Wop.adjoint are the same
    assert all_almost_equal(reconstruction1.asarray(),
                            reconstruction2.asarray())

    # Verify that reconstructions lie in correct discretized domain
    assert reconstruction1 in disc_domain
    assert reconstruction2 in disc_domain
    assert all_almost_equal(reconstruction1.asarray(), x)
    assert all_almost_equal(reconstruction2.asarray(), x)

    # -------------------------------------------------------------
    # 3D test
    n = 16
    x = np.zeros((n, n, n))
    x[5:10, 5:10, 5:10] = 1
    wbasis = pywt.Wavelet('db2')
    nscales = 1
    mode = 'per'
    size_list = coeff_size_list((n, n, n), nscales, wbasis, mode)

    # Define a discretized domain
    domain = odl.FunctionSpace(odl.Cuboid([-1, -1, -1], [1, 1, 1]))
    nPoints = np.array([n, n, n])
    disc_domain = odl.uniform_discr_fromspace(domain, nPoints)
    disc_phantom = disc_domain.element(x)

    # Create the discrete wavelet transform operator related to 3D transform.
    Wop = WaveletTransform(disc_domain, nscales, wbasis, mode)
    # Compute the discrete wavelet transform of discrete imput image
    coeffs = Wop(disc_phantom)
    # Determine the correct range for Wop and verify that coeffs
    # is an element of it
    ran_size = np.prod(size_list[0])
    ran_size += sum(7 * np.prod(shape) for shape in size_list[1:-1])
    disc_range = disc_domain.dspace_type(ran_size, dtype=disc_domain.dtype)
    assert coeffs in disc_range

    # Compute the inverse wavelet transform
    reconstruction1 = Wop.inverse(coeffs)
    # With othogonal wavelets the inverse is the adjoint
    reconstruction2 = Wop.adjoint(coeffs)

    # Verify that the output of Wop.inverse and Wop.adjoint are the same
    assert all_almost_equal(reconstruction1, reconstruction2)

    # Verify that reconstructions lie in correct discretized domain
    assert reconstruction1 in disc_domain
    assert reconstruction2 in disc_domain
    assert all_almost_equal(reconstruction1.asarray(), x)
    assert all_almost_equal(reconstruction2, disc_phantom)
Esempio n. 56
0
def test_one(fn):
    assert all_almost_equal(fn.one(), [1] * fn.size)
Esempio n. 57
0
def test_kullback_leibler(space):
    """Test the kullback leibler functional and its convex conjugate."""
    # The prior needs to be positive
    prior = noise_element(space)
    prior = np.abs(prior)

    func = odl.solvers.KullbackLeibler(space, prior)

    # The fucntional is only defined for positive elements
    x = noise_element(space)
    x = np.abs(x)
    one_elem = space.one()

    # Evaluation of the functional
    expected_result = ((x - prior + prior * np.log(prior / x))
                       .inner(one_elem))
    assert pytest.approx(func(x), expected_result)

    # Check property for prior
    assert all_almost_equal(func.prior, prior)

    # For elements with (a) negative components it should return inf
    x_neg = noise_element(space)
    x_neg = x_neg - x_neg.ufuncs.max()
    assert func(x_neg) == np.inf

    # The gradient
    expected_result = 1 - prior / x
    assert all_almost_equal(func.gradient(x), expected_result)

    # The proximal operator
    sigma = np.random.rand()
    expected_result = odl.solvers.proximal_cconj(
        odl.solvers.proximal_cconj_kl(space, g=prior))(sigma)(x)
    assert all_almost_equal(func.proximal(sigma)(x), expected_result)

    # The convex conjugate functional
    cc_func = func.convex_conj

    assert isinstance(cc_func, KullbackLeiblerConvexConj)

    # The convex conjugate functional is only finite for elements with all
    # components smaller than 1.
    x = noise_element(space)
    x = x - x.ufuncs.max() + 0.99

    # Evaluation of convex conjugate
    expected_result = - (prior * np.log(1 - x)).inner(one_elem)
    assert pytest.approx(cc_func(x), expected_result)

    x_wrong = noise_element(space)
    x_wrong = x_wrong - x_wrong.ufuncs.max() + 1.01
    assert cc_func(x_wrong) == np.inf

    # The gradient of the convex conjugate
    expected_result = prior / (1 - x)
    assert all_almost_equal(cc_func.gradient(x), expected_result)

    # The proximal of the convex conjugate
    expected_result = 0.5 * (1 + x - np.sqrt((x - 1)**2 + 4 * sigma * prior))
    assert all_almost_equal(cc_func.proximal(sigma)(x), expected_result)

    # The biconjugate, which is the functional itself since it is proper,
    # convex and lower-semicontinuous
    cc_cc_func = cc_func.convex_conj

    # Check that they evaluate the same
    assert pytest.approx(cc_cc_func(x), func(x))
Esempio n. 58
0
def test_uniform_discr_fromdiscr_two_attrs():
    # Change 2 attributes -> resize and translate

    discr = odl.uniform_discr([0, -1], [1, 1], [10, 5])
    # csides = [0.1, 0.4]

    new_min_pt = [-2, 1]
    new_max_pt = [4, 2]
    true_new_csides = [0.6, 0.2]
    new_discr = odl.uniform_discr_fromdiscr(discr,
                                            min_pt=new_min_pt,
                                            max_pt=new_max_pt)
    assert all_almost_equal(new_discr.min_pt, new_min_pt)
    assert all_almost_equal(new_discr.max_pt, new_max_pt)
    assert all_equal(new_discr.shape, discr.shape)
    assert all_almost_equal(new_discr.cell_sides, true_new_csides)

    new_min_pt = [-2, 1]
    new_shape = (5, 20)
    true_new_max_pt = [-1.5, 9]
    new_discr = odl.uniform_discr_fromdiscr(discr,
                                            min_pt=new_min_pt,
                                            shape=new_shape)
    assert all_almost_equal(new_discr.min_pt, new_min_pt)
    assert all_almost_equal(new_discr.max_pt, true_new_max_pt)
    assert all_equal(new_discr.shape, new_shape)
    assert all_almost_equal(new_discr.cell_sides, discr.cell_sides)

    new_min_pt = [-2, 1]
    new_csides = [0.6, 0.2]
    true_new_max_pt = [4, 2]
    new_discr = odl.uniform_discr_fromdiscr(discr,
                                            min_pt=new_min_pt,
                                            cell_sides=new_csides)
    assert all_almost_equal(new_discr.min_pt, new_min_pt)
    assert all_almost_equal(new_discr.max_pt, true_new_max_pt)
    assert all_equal(new_discr.shape, discr.shape)
    assert all_almost_equal(new_discr.cell_sides, new_csides)

    new_max_pt = [4, 2]
    new_shape = (5, 20)
    true_new_min_pt = [3.5, -6]
    new_discr = odl.uniform_discr_fromdiscr(discr,
                                            max_pt=new_max_pt,
                                            shape=new_shape)
    assert all_almost_equal(new_discr.min_pt, true_new_min_pt)
    assert all_almost_equal(new_discr.max_pt, new_max_pt)
    assert all_equal(new_discr.shape, new_shape)
    assert all_almost_equal(new_discr.cell_sides, discr.cell_sides)

    new_max_pt = [4, 2]
    new_csides = [0.6, 0.2]
    true_new_min_pt = [-2, 1]
    new_discr = odl.uniform_discr_fromdiscr(discr,
                                            max_pt=new_max_pt,
                                            cell_sides=new_csides)
    assert all_almost_equal(new_discr.min_pt, true_new_min_pt)
    assert all_almost_equal(new_discr.max_pt, new_max_pt)
    assert all_equal(new_discr.shape, discr.shape)
    assert all_almost_equal(new_discr.cell_sides, new_csides)
Esempio n. 59
0
def test_kullback_leibler_cross_entorpy(space):
    """Test the kullback leibler cross entropy and its convex conjugate."""
    # The prior needs to be positive
    prior = noise_element(space)
    prior = np.abs(prior)

    func = odl.solvers.KullbackLeiblerCrossEntropy(space, prior)

    # The fucntional is only defined for positive elements
    x = noise_element(space)
    x = np.abs(x)
    one_elem = space.one()

    # Evaluation of the functional
    expected_result = ((prior - x + x * np.log(x / prior))
                       .inner(one_elem))
    assert pytest.approx(func(x), expected_result)

    # Check property for prior
    assert all_almost_equal(func.prior, prior)

    # For elements with (a) negative components it should return inf
    x_neg = noise_element(space)
    x_neg = x_neg - x_neg.ufuncs.max()
    assert func(x_neg) == np.inf

    # The gradient
    expected_result = np.log(x / prior)
    assert all_almost_equal(func.gradient(x), expected_result)

    # The proximal operator
    sigma = np.random.rand()
    expected_result = odl.solvers.proximal_cconj(
        odl.solvers.proximal_cconj_kl_cross_entropy(space, g=prior))(sigma)(x)
    assert all_almost_equal(func.proximal(sigma)(x), expected_result)

    # The convex conjugate functional
    cc_func = func.convex_conj

    assert isinstance(cc_func, KullbackLeiblerCrossEntropyConvexConj)

    # The convex conjugate functional is defined for all values of x.
    x = noise_element(space)

    # Evaluation of convex conjugate
    expected_result = (prior * (np.exp(x) - 1)).inner(one_elem)
    assert pytest.approx(cc_func(x), expected_result)

    # The gradient of the convex conjugate
    expected_result = prior * np.exp(x)
    assert all_almost_equal(cc_func.gradient(x), expected_result)

    # The proximal of the convex conjugate
    expected_result = x - scipy.special.lambertw(sigma * prior * np.exp(x))
    assert all_almost_equal(cc_func.proximal(sigma)(x), expected_result)

    # The biconjugate, which is the functional itself since it is proper,
    # convex and lower-semicontinuous
    cc_cc_func = cc_func.convex_conj

    # Check that they evaluate the same
    assert pytest.approx(cc_cc_func(x), func(x))
Esempio n. 60
0
 def check_shifts(ffs, shifts):
     i = 0
     while i < part_angles.size:
         j = min(len(ffs), i + len(shifts))
         assert all_almost_equal(ffs[i:j], shifts[:(j - i)])
         i = j