Example #1
0
def test_norm(tspace):
    weighting_const = tspace.weighting.const

    xarr, x = noise_elements(tspace)

    correct_norm = np.linalg.norm(xarr) * np.sqrt(weighting_const)

    assert (tspace.norm(x) == pytest.approx(correct_norm,
                                            rel=dtype_tol(tspace.dtype)))
    assert (x.norm() == pytest.approx(correct_norm,
                                      rel=dtype_tol(tspace.dtype)))
Example #2
0
def test_dist(tspace):
    weighting_const = tspace.weighting.const

    [xarr, yarr], [x, y] = noise_elements(tspace, 2)

    correct_dist = np.linalg.norm(xarr - yarr) * np.sqrt(weighting_const)

    assert (tspace.dist(x, y) == pytest.approx(correct_dist,
                                               rel=dtype_tol(tspace.dtype)))
    assert (x.dist(y) == pytest.approx(correct_dist,
                                       rel=dtype_tol(tspace.dtype)))
Example #3
0
def test_inner(tspace):
    weighting_const = tspace.weighting.const

    [xarr, yarr], [x, y] = noise_elements(tspace, 2)

    correct_inner = np.vdot(yarr, xarr) * weighting_const

    assert (tspace.inner(x, y) == pytest.approx(correct_inner,
                                                rel=dtype_tol(tspace.dtype)))
    assert (x.inner(y) == pytest.approx(correct_inner,
                                        rel=dtype_tol(tspace.dtype)))
Example #4
0
def test_resize_array_adj(resize_setup, odl_floating_dtype):
    dtype = odl_floating_dtype
    pad_mode, pad_const, newshp, offset, array, _ = resize_setup

    if pad_const != 0:
        # Not well-defined
        return

    array = np.array(array, dtype=dtype)
    if is_real_dtype(dtype):
        other_arr = np.random.uniform(-10, 10, size=newshp)
    else:
        other_arr = (np.random.uniform(-10, 10, size=newshp) +
                     1j * np.random.uniform(-10, 10, size=newshp))

    resized = resize_array(array,
                           newshp,
                           offset,
                           pad_mode,
                           pad_const,
                           direction='forward')
    resized_adj = resize_array(other_arr,
                               array.shape,
                               offset,
                               pad_mode,
                               pad_const,
                               direction='adjoint')

    assert (np.vdot(resized.ravel(),
                    other_arr.ravel()) == pytest.approx(np.vdot(
                        array.ravel(), resized_adj.ravel()),
                                                        rel=dtype_tol(dtype)))
Example #5
0
def test_resizing_op_adjoint(padding, odl_tspace_impl):

    impl = odl_tspace_impl
    pad_mode, pad_const = padding
    dtypes = [dt for dt in tensor_space_impl(impl).available_dtypes()
              if is_real_floating_dtype(dt)]

    for dtype in dtypes:
        space = odl.uniform_discr([0, -1], [1, 1], (4, 5), dtype=dtype,
                                  impl=impl)
        res_space = odl.uniform_discr([0, -1.4], [1.5, 1.4], (6, 7),
                                      dtype=dtype, impl=impl)
        res_op = odl.ResizingOperator(space, res_space, pad_mode=pad_mode,
                                      pad_const=pad_const)

        if pad_const != 0.0:
            with pytest.raises(NotImplementedError):
                res_op.adjoint
            return

        elem = noise_element(space)
        res_elem = noise_element(res_space)
        inner1 = res_op(elem).inner(res_elem)
        inner2 = elem.inner(res_op.adjoint(res_elem))
        assert inner1 == pytest.approx(
            inner2, rel=space.size * dtype_tol(dtype)
        )
Example #6
0
def test_bregman(functional):
    """Test for the Bregman distance of a functional."""
    rtol = dtype_tol(functional.domain.dtype)

    if isinstance(functional, odl.solvers.functional.IndicatorLpUnitBall):
        # IndicatorFunction has no gradient
        with pytest.raises(NotImplementedError):
            functional.gradient(functional.domain.zero())
        return

    y = noise_element(functional.domain)
    x = noise_element(functional.domain)

    if (isinstance(functional, odl.solvers.KullbackLeibler) or isinstance(
            functional, odl.solvers.KullbackLeiblerCrossEntropy)):
        # The functional is not defined for values <= 0
        x = x.ufuncs.absolute()
        y = y.ufuncs.absolute()

    if isinstance(functional, KullbackLeiblerConvexConj):
        # The functional is not defined for values >= 1
        x = x - x.ufuncs.max() + 0.99
        y = y - y.ufuncs.max() + 0.99

    grad = functional.gradient(y)
    quadratic_func = odl.solvers.QuadraticForm(vector=-grad,
                                               constant=-functional(y) +
                                               grad.inner(y))
    expected_func = functional + quadratic_func

    assert (functional.bregman(y, grad)(x) == pytest.approx(expected_func(x),
                                                            rel=rtol))
Example #7
0
def test_functional_composition(space):
    """Test composition from the right with an operator."""
    # Less strict checking for single precision
    ndigits = dtype_ndigits(space.dtype)
    rtol = dtype_tol(space.dtype)

    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 func_op_comp(x) == pytest.approx(func(op(x)), rel=rtol)

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

    p = noise_element(space)
    assert all_almost_equal(
        func_op_comp.derivative(x)(p),
        (op.adjoint * func.gradient * op)(x).inner(p), ndigits)
Example #8
0
def test_gradient(space, method, padding):
    """Discretized spatial gradient operator."""
    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 lhs == pytest.approx(rhs, rel=dtype_tol(space.dtype))

    # Higher-dimensional arrays
    lin_size = 3
    for ndim in [1, 3, 6]:
        space = odl.uniform_discr([0.] * ndim, [1.] * ndim, [lin_size] * ndim)
        dom_vec = odl.phantom.cuboid(space, [0.2] * ndim, [0.8] * ndim)

        grad = Gradient(space,
                        method=method,
                        pad_mode=pad_mode,
                        pad_const=pad_const)
        grad(dom_vec)
Example #9
0
def test_translation_of_functional(space):
    """Test for the translation of a functional: (f(. - y))^*."""
    # Less strict checking for single precision
    ndigits = dtype_ndigits(space.dtype)
    rtol = dtype_tol(space.dtype)

    # 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, ndigits)

    # 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, ndigits)

    # 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, ndigits)

    # 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, ndigits)

    # 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, ndigits)

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

    # Evaluation
    assert (double_translated_functional(x) == pytest.approx(
        test_functional(x - translation - second_translation), rel=rtol))
Example #10
0
def test_functional_quadratic_perturb(space, linear_term, quadratic_coeff):
    """Test for the functional f(.) + a | . |^2 + <y, .>."""
    # Less strict checking for single precision
    ndigits = dtype_ndigits(space.dtype)
    rtol = dtype_tol(space.dtype)

    orig_func = odl.solvers.L2NormSquared(space)

    if linear_term:
        linear_term_arg = None
        linear_term = space.zero()
    else:
        linear_term_arg = linear_term = noise_element(space)

    # Creating the functional ||x||_2^2 and add the quadratic perturbation
    functional = odl.solvers.FunctionalQuadraticPerturb(
        orig_func,
        quadratic_coeff=quadratic_coeff,
        linear_term=linear_term_arg)

    # Create an element in the space, in which to evaluate
    x = noise_element(space)

    # Test for evaluation of the functional
    assert (functional(x) == pytest.approx(
        orig_func(x) + quadratic_coeff * x.inner(x) + x.inner(linear_term),
        rel=rtol))

    # Test for the gradient
    assert all_almost_equal(
        functional.gradient(x),
        orig_func.gradient(x) + 2.0 * quadratic_coeff * x + linear_term,
        ndigits)

    # Test for the proximal operator if it exists
    sigma = 1.2
    # Explicit computation gives
    c = 1 / np.sqrt(2 * sigma * quadratic_coeff + 1)
    prox = orig_func.proximal(sigma * c**2)
    expected_result = prox((x - sigma * linear_term) * c**2)
    assert all_almost_equal(
        functional.proximal(sigma)(x), expected_result, ndigits)

    # Test convex conjugate functional
    if quadratic_coeff == 0:
        expected = orig_func.convex_conj.translated(linear_term)(x)
        assert functional.convex_conj(x) == pytest.approx(expected, rel=rtol)

    # Test proximal of the convex conjugate
    cconj_prox = odl.solvers.proximal_convex_conj(functional.proximal)
    assert all_almost_equal(
        functional.convex_conj.proximal(sigma)(x),
        cconj_prox(sigma)(x), ndigits)
Example #11
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
    ndigits = dtype_ndigits(space.dtype)
    rtol = dtype_tol(space.dtype)

    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 func_times_y(x) == pytest.approx(expected_result, rel=rtol)

    # 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, ndigits)

    # 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 cc_func_times_y(x) == pytest.approx(expected_result, rel=rtol)

    # 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, ndigits)

    # 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, ndigits)
Example #12
0
def test_laplacian(space, padding):
    """Discretized spatial laplacian operator."""
    if isinstance(padding, tuple):
        pad_mode, pad_const = padding
    else:
        pad_mode, pad_const = padding, 0

    if pad_mode in ('order1', 'order2'):
        return  # these pad modes not supported for laplacian

    # Operator instance
    lap = Laplacian(space, pad_mode=pad_mode, pad_const=pad_const)

    # Apply operator
    dom_vec = noise_element(space)
    div_dom_vec = lap(dom_vec)

    # computation of divergence with helper function
    expected_result = np.zeros(space.shape)
    for axis, dx in enumerate(space.cell_sides):
        diff_f = finite_diff(dom_vec.asarray(),
                             axis=axis,
                             dx=dx**2,
                             method='forward',
                             pad_mode=pad_mode,
                             pad_const=pad_const)
        diff_b = finite_diff(dom_vec.asarray(),
                             axis=axis,
                             dx=dx**2,
                             method='backward',
                             pad_mode=pad_mode,
                             pad_const=pad_const)
        expected_result += diff_f - diff_b

    assert all_almost_equal(expected_result, div_dom_vec.asarray())

    # Adjoint operator
    derivative = lap.derivative()
    deriv_lap_dom_vec = derivative(dom_vec)
    ran_vec = noise_element(lap.range)
    adj_lap_ran_vec = derivative.adjoint(ran_vec)

    # Adjoint condition
    lhs = ran_vec.inner(deriv_lap_dom_vec)
    rhs = dom_vec.inner(adj_lap_ran_vec)

    # Check not to use trivial data
    assert lhs != 0
    assert rhs != 0
    assert lhs == pytest.approx(rhs, rel=dtype_tol(space.dtype))
Example #13
0
def test_divergence(space, method, padding):
    """Discretized spatial divergence operator."""
    # Invalid space
    with pytest.raises(TypeError):
        Divergence(range=odl.rn(1), method=method)

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

    # Operator instance
    div = Divergence(range=space,
                     method=method,
                     pad_mode=pad_mode,
                     pad_const=pad_const)

    # Apply operator
    dom_vec = noise_element(div.domain)
    div_dom_vec = div(dom_vec)

    # computation of divergence with helper function
    expected_result = np.zeros(space.shape)
    for axis, dx in enumerate(space.cell_sides):
        expected_result += finite_diff(dom_vec[axis],
                                       axis=axis,
                                       dx=dx,
                                       method=method,
                                       pad_mode=pad_mode,
                                       pad_const=pad_const)

    assert all_almost_equal(expected_result, div_dom_vec.asarray())

    # Adjoint operator
    derivative = div.derivative()
    deriv_div_dom_vec = derivative(dom_vec)
    ran_vec = noise_element(div.range)
    adj_div_ran_vec = derivative.adjoint(ran_vec)

    # Adjoint condition
    lhs = ran_vec.inner(deriv_div_dom_vec)
    rhs = dom_vec.inner(adj_div_ran_vec)
    # Check not to use trivial data
    assert lhs != 0
    assert rhs != 0
    assert lhs == pytest.approx(rhs, rel=dtype_tol(space.dtype))
Example #14
0
def test_left_scalar_mult(space, scalar):
    """Test for right and left multiplication of a functional with a scalar."""
    # Less strict checking for single precision
    ndigits = dtype_ndigits(space.dtype)
    rtol = dtype_tol(space.dtype)

    x = noise_element(space)
    func = odl.solvers.functional.L2Norm(space)
    lmul_func = scalar * func

    if scalar == 0:
        assert isinstance(scalar * func, odl.solvers.ZeroFunctional)
        return

    # Test functional evaluation
    assert lmul_func(x) == pytest.approx(scalar * func(x), rel=rtol)

    # Test gradient of left scalar multiplication
    assert all_almost_equal(lmul_func.gradient(x), scalar * func.gradient(x),
                            ndigits)

    # Test derivative of left scalar multiplication
    p = noise_element(space)
    assert all_almost_equal(
        lmul_func.derivative(x)(p),
        scalar * (func.derivative(x))(p), ndigits)

    # Test convex conjugate. This requires positive scaling to work
    pos_scalar = abs(scalar)
    neg_scalar = -pos_scalar

    with pytest.raises(ValueError):
        (neg_scalar * func).convex_conj

    assert all_almost_equal((pos_scalar * func).convex_conj(x),
                            pos_scalar * func.convex_conj(x / pos_scalar),
                            ndigits)

    # Test proximal operator. This requires scaling to be positive.
    sigma = 1.2
    with pytest.raises(ValueError):
        (neg_scalar * func).proximal(sigma)

    assert all_almost_equal((pos_scalar * func).proximal(sigma)(x),
                            func.proximal(sigma * pos_scalar)(x))
Example #15
0
def test_right_scalar_mult(space, scalar):
    """Test for right and left multiplication of a functional with a scalar."""
    # Less strict checking for single precision
    ndigits = dtype_ndigits(space.dtype)
    rtol = dtype_tol(space.dtype)

    x = noise_element(space)
    func = odl.solvers.functional.L2NormSquared(space)
    rmul_func = func * scalar

    if scalar == 0:
        # expecting the constant functional x -> func(0)
        assert isinstance(rmul_func, odl.solvers.ConstantFunctional)
        assert all_almost_equal(rmul_func(x), func(space.zero()), ndigits)
        # Nothing more to do, rest is part of ConstantFunctional test
        return

    # Test functional evaluation
    assert rmul_func(x) == pytest.approx(func(scalar * x), rel=rtol)

    # Test gradient of right scalar multiplication
    assert all_almost_equal(rmul_func.gradient(x),
                            scalar * func.gradient(scalar * x), ndigits)

    # Test derivative of right scalar multiplication
    p = noise_element(space)
    assert all_almost_equal(
        rmul_func.derivative(x)(p),
        scalar * func.derivative(scalar * x)(p), ndigits)

    # Test convex conjugate conjugate
    assert all_almost_equal(rmul_func.convex_conj(x),
                            func.convex_conj(x / scalar), ndigits)

    # Test proximal operator
    sigma = 1.2
    assert all_almost_equal(
        rmul_func.proximal(sigma)(x),
        (1.0 / scalar) * func.proximal(sigma * scalar**2)(x * scalar), ndigits)

    # Verify that for linear functionals, left multiplication is used.
    func = odl.solvers.ZeroFunctional(space)
    assert isinstance(func * scalar, odl.solvers.FunctionalLeftScalarMult)
Example #16
0
def test_part_deriv(space, method, padding):
    """Discretized partial derivative."""
    if isinstance(padding, tuple):
        pad_mode, pad_const = padding
    else:
        pad_mode, pad_const = padding, 0

    dom_vec = noise_element(space)
    dom_vec_arr = dom_vec.asarray()

    for axis in range(space.ndim):
        partial = PartialDerivative(space,
                                    axis=axis,
                                    method=method,
                                    pad_mode=pad_mode,
                                    pad_const=pad_const)

        # Compare to helper function
        dx = space.cell_sides[axis]
        diff = finite_diff(dom_vec_arr,
                           axis=axis,
                           dx=dx,
                           method=method,
                           pad_mode=pad_mode,
                           pad_const=pad_const)

        partial_vec = partial(dom_vec)
        assert all_almost_equal(partial_vec, diff)

        # Test adjoint operator
        derivative = partial.derivative()
        ran_vec = noise_element(space)
        deriv_vec = derivative(dom_vec)
        adj_vec = derivative.adjoint(ran_vec)
        lhs = ran_vec.inner(deriv_vec)
        rhs = dom_vec.inner(adj_vec)

        # Check not to use trivial data
        assert lhs != 0
        assert rhs != 0
        assert lhs == pytest.approx(rhs, rel=dtype_tol(space.dtype))
Example #17
0
def test_functional_sum(space):
    """Test for the sum of two functionals."""
    # Less strict checking for single precision
    ndigits = dtype_ndigits(space.dtype)
    rtol = dtype_tol(space.dtype)

    func1 = odl.solvers.L2NormSquared(space)
    func2 = odl.solvers.L2Norm(space)

    # Verify that an error is raised if one operand is "wrong"
    op = odl.operator.IdentityOperator(space)
    with pytest.raises(OpTypeError):
        func1 + op

    wrong_space = odl.uniform_discr(1, 2, 10)
    func_wrong_domain = odl.solvers.L2Norm(wrong_space)
    with pytest.raises(OpTypeError):
        func1 + func_wrong_domain

    func_sum = func1 + func2
    x = noise_element(space)
    p = noise_element(space)

    # Test functional evaluation
    assert func_sum(x) == pytest.approx(func1(x) + func2(x), rel=rtol)

    # Test gradient and derivative
    assert all_almost_equal(func_sum.gradient(x),
                            func1.gradient(x) + func2.gradient(x), ndigits)

    assert (func_sum.derivative(x)(p) == pytest.approx(
        func1.gradient(x).inner(p) + func2.gradient(x).inner(p), rel=rtol))

    # Verify that proximal raises
    with pytest.raises(NotImplementedError):
        func_sum.proximal

    # Test the convex conjugate raises
    with pytest.raises(NotImplementedError):
        func_sum.convex_conj(x)
Example #18
0
def test_functional_plus_scalar(space):
    """Test for sum of functioanl and scalar."""
    # Less strict checking for single precision
    ndigits = dtype_ndigits(space.dtype)
    rtol = dtype_tol(space.dtype)

    func = odl.solvers.L2NormSquared(space)
    scalar = -1.3

    # Test for scalar not in the field (field of unifor_discr is RealNumbers)
    complex_scalar = 1j
    with pytest.raises(TypeError):
        func + complex_scalar

    func_scalar_sum = func + scalar
    x = noise_element(space)
    p = noise_element(space)

    # Test for evaluation
    assert func_scalar_sum(x) == pytest.approx(func(x) + scalar, rel=rtol)

    # Test for derivative and gradient
    assert all_almost_equal(func_scalar_sum.gradient(x), func.gradient(x),
                            ndigits)

    assert (func_scalar_sum.derivative(x)(p) == pytest.approx(
        func.gradient(x).inner(p), rel=rtol))

    # Test proximal operator
    sigma = 1.2
    assert all_almost_equal(
        func_scalar_sum.proximal(sigma)(x),
        func.proximal(sigma)(x), ndigits)

    # Test convex conjugate
    assert (func_scalar_sum.convex_conj(x) == pytest.approx(
        func.convex_conj(x) - scalar, rel=rtol))

    assert all_almost_equal(func_scalar_sum.convex_conj.gradient(x),
                            func.convex_conj.gradient(x), ndigits)