Example #1
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]:
        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)
def test_forward_backward_with_lin_ops():
    """Test for the forward-backward solver with linear operatros.

    The test is done by minimizing ||x - b||_2^2 + ||alpha * x||_2^2. The
    general problem is of the form

        ``min_x f(x) + sum_i g_i(L_i x) + h(x)``

    and here we take f = 0, g = ||.||_2^2, L = alpha * IndentityOperator,
    and h = ||. - b||_2^2.
    """

    space = odl.rn(10)
    alpha = 0.1
    b = noise_element(space)

    lin_ops = [alpha * odl.IdentityOperator(space)]
    g = [odl.solvers.L2NormSquared(space)]
    f = odl.solvers.ZeroFunctional(space)

    # Gradient of two-norm square
    h = odl.solvers.L2NormSquared(space).translated(b)

    x = noise_element(space)

    # Explicit solution: x_hat = (I^T * I + (alpha*I)^T * (alpha*I))^-1 * (I*b)
    x_global_min = b / (1 + alpha ** 2)

    forward_backward_pd(x, f, g, lin_ops, h, tau=0.5,
                        sigma=[1.0], niter=20)

    assert all_almost_equal(x, x_global_min, places=LOW_ACCURACY)
def test_separable_sum(space):
    """Test for the separable sum."""
    l1 = odl.solvers.L1Norm(space)
    l2 = odl.solvers.L2Norm(space)

    x = noise_element(space)
    y = noise_element(space)

    # Initialization and calling
    func = odl.solvers.SeparableSum(l1, l2)
    assert func([x, y]) == pytest.approx(l1(x) + l2(y))

    power_func = odl.solvers.SeparableSum(l1, 5)
    assert power_func([x, x, x, x, x]) == pytest.approx(5 * l1(x))

    # Gradient
    grad = func.gradient([x, y])
    assert grad[0] == l1.gradient(x)
    assert grad[1] == l2.gradient(y)

    # Proximal
    sigma = 1.0
    prox = func.proximal(sigma)([x, y])
    assert prox[0] == l1.proximal(sigma)(x)
    assert prox[1] == l2.proximal(sigma)(y)

    # Convex conjugate
    assert func.convex_conj([x, y]) == l1.convex_conj(x) + l2.convex_conj(y)
Example #4
0
def test_bregman_functional_l2_squared(space, sigma):
    """Test Bregman distance using l2 norm squared as underlying functional."""
    sigma = float(sigma)

    l2_sq = odl.solvers.L2NormSquared(space)
    point = noise_element(space)
    subgrad = l2_sq.gradient(point)
    bregman_dist = odl.solvers.BregmanDistance(l2_sq, point, subgrad)

    expected_func = odl.solvers.L2NormSquared(space).translated(point)

    x = noise_element(space)

    # Function evaluation
    assert all_almost_equal(bregman_dist(x), expected_func(x))

    # Gradient evaluation
    assert all_almost_equal(bregman_dist.gradient(x),
                            expected_func.gradient(x))

    # Convex conjugate
    cc_bregman_dist = bregman_dist.convex_conj
    cc_expected_func = expected_func.convex_conj
    assert all_almost_equal(cc_bregman_dist(x), cc_expected_func(x))

    # Proximal operator
    prox_bregman_dist = bregman_dist.proximal(sigma)
    prox_expected_func = expected_func.proximal(sigma)
    assert all_almost_equal(prox_bregman_dist(x), prox_expected_func(x))
Example #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)
Example #6
0
def test_mat_op_inverse(fn):
    # Sparse case
    sparse_mat = _sparse_matrix(fn)
    op_sparse = MatrixOperator(sparse_mat, fn, fn)

    op_sparse_inv = op_sparse.inverse
    assert op_sparse_inv.domain == op_sparse.range
    assert op_sparse_inv.range == op_sparse.domain
    assert all_almost_equal(op_sparse_inv.matrix,
                            np.linalg.inv(op_sparse.matrix.todense()))
    assert all_almost_equal(op_sparse_inv.inverse.matrix,
                            op_sparse.matrix.todense())

    # Test application
    x = noise_element(fn)
    assert all_almost_equal(x, op_sparse.inverse(op_sparse(x)))

    # Dense case
    dense_mat = _dense_matrix(fn)
    op_dense = MatrixOperator(dense_mat, fn, fn)
    op_dense_inv = op_dense.inverse
    assert op_dense_inv.domain == op_dense.range
    assert op_dense_inv.range == op_dense.domain
    assert all_almost_equal(op_dense_inv.matrix,
                            np.linalg.inv(op_dense.matrix))
    assert all_almost_equal(op_dense_inv.inverse.matrix, op_dense.matrix)

    # Test application
    x = noise_element(fn)
    assert all_almost_equal(x, op_dense.inverse(op_dense(x)))
def test_cconj_defintion(functional):
    """Test the defintion of the convex conjugate:

        f^*(y) = sup_x {<x, y> - f(x)}

    Hence we expect for all x in the domain of the proximal

        <x, y> - f(x) <= f^*(y)
    """
    f_cconj = functional.convex_conj
    if isinstance(functional.convex_conj, FunctionalDefaultConvexConjugate):
        pytest.skip('functional has no convex conjugate')
        return

    for _ in range(100):
        y = noise_element(functional.domain)
        f_cconj_y = f_cconj(y)

        x = noise_element(functional.domain)
        lhs = x.inner(y) - functional(x)

        if not lhs <= f_cconj_y + EPS:
            print(repr(functional), repr(f_cconj), x, y, lhs, f_cconj_y)

        assert lhs <= f_cconj_y + EPS
Example #8
0
def test_separable_sum(space):
    """Test for the separable sum."""
    l1 = odl.solvers.L1Norm(space)
    l2 = odl.solvers.L2Norm(space)

    x = noise_element(space)
    y = noise_element(space)

    # Initialization and calling
    func = odl.solvers.SeparableSum(l1, l2)
    assert func([x, y]) == pytest.approx(l1(x) + l2(y))

    power_func = odl.solvers.SeparableSum(l1, 5)
    assert power_func([x, x, x, x, x]) == pytest.approx(5 * l1(x))

    # Gradient
    grad = func.gradient([x, y])
    assert grad[0] == l1.gradient(x)
    assert grad[1] == l2.gradient(y)

    # Proximal
    sigma = 1.0
    prox = func.proximal(sigma)([x, y])
    assert prox[0] == l1.proximal(sigma)(x)
    assert prox[1] == l2.proximal(sigma)(y)

    # Convex conjugate
    assert func.convex_conj([x, y]) == l1.convex_conj(x) + l2.convex_conj(y)
Example #9
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_convex_conj_defintion(functional):
    """Test the defintion of the convex conjugate:

        f^*(y) = sup_x {<x, y> - f(x)}

    Hence we expect for all x in the domain of the proximal

        <x, y> - f(x) <= f^*(y)
    """
    if isinstance(functional, FunctionalDefaultConvexConjugate):
        pytest.skip('functional has no call')
        return

    f_convex_conj = functional.convex_conj
    if isinstance(f_convex_conj, FunctionalDefaultConvexConjugate):
        pytest.skip('functional has no convex conjugate')
        return

    for _ in range(100):
        y = noise_element(functional.domain)
        f_convex_conj_y = f_convex_conj(y)

        x = noise_element(functional.domain)
        lhs = x.inner(y) - functional(x)

        if not lhs <= f_convex_conj_y + EPS:
            print(repr(functional), repr(f_convex_conj), x, y, lhs,
                  f_convex_conj_y)

        assert lhs <= f_convex_conj_y + EPS
Example #11
0
def test_resizing_op_mixed_uni_nonuni():
    """Check if resizing along uniform axes in mixed discretizations works."""
    nonuni_part = odl.nonuniform_partition([0, 1, 4])
    uni_part = odl.uniform_partition(-1, 1, 4)
    part = uni_part.append(nonuni_part, uni_part, nonuni_part)
    fspace = odl.FunctionSpace(odl.IntervalProd(part.min_pt, part.max_pt))
    tspace = odl.rn(part.shape)
    space = odl.DiscreteLp(fspace, part, tspace)

    # Keep non-uniform axes fixed
    res_op = odl.ResizingOperator(space, ran_shp=(6, 3, 6, 3))

    assert res_op.axes == (0, 2)
    assert res_op.offset == (1, 0, 1, 0)

    # Evaluation test with a simpler case
    part = uni_part.append(nonuni_part)
    fspace = odl.FunctionSpace(odl.IntervalProd(part.min_pt, part.max_pt))
    tspace = odl.rn(part.shape)
    space = odl.DiscreteLp(fspace, part, tspace)
    res_op = odl.ResizingOperator(space, ran_shp=(6, 3))
    result = res_op(space.one())
    true_result = [[0, 0, 0], [1, 1, 1], [1, 1, 1], [1, 1, 1], [1, 1, 1],
                   [0, 0, 0]]
    assert np.array_equal(result, true_result)

    # Test adjoint
    elem = noise_element(space)
    res_elem = noise_element(res_op.range)
    inner1 = res_op(elem).inner(res_elem)
    inner2 = elem.inner(res_op.adjoint(res_elem))
    assert almost_equal(inner1, inner2)
Example #12
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)
Example #13
0
def test_inner(fn):
    xd = noise_element(fn)
    yd = noise_element(fn)

    correct_inner = np.vdot(yd, xd)
    assert almost_equal(fn.inner(xd, yd), correct_inner)
    assert almost_equal(xd.inner(yd), correct_inner)
Example #14
0
def test_forward_backward_with_lin_ops():
    """Test for the forward-backward solver with linear operatros.

    The test is done by minimizing ||x - b||_2^2 + ||alpha * x||_2^2. The
    general problem is of the form

        ``min_x f(x) + sum_i g_i(L_i x) + h(x)``

    and here we take f = 0, g = ||.||_2^2, L = alpha * IndentityOperator,
    and h = ||. - b||_2^2.
    """

    space = odl.rn(10)
    alpha = 0.1
    b = noise_element(space)

    lin_ops = [alpha * odl.IdentityOperator(space)]
    g = [odl.solvers.L2NormSquared(space)]
    f = odl.solvers.ZeroFunctional(space)

    # Gradient of two-norm square
    h = odl.solvers.L2NormSquared(space).translated(b)

    x = noise_element(space)

    # Explicit solution: x_hat = (I^T * I + (alpha*I)^T * (alpha*I))^-1 * (I*b)
    x_global_min = b / (1 + alpha**2)

    forward_backward_pd(x, f, g, lin_ops, h, tau=0.5, sigma=[1.0], niter=20)

    assert all_almost_equal(x, x_global_min, places=LOW_ACCURACY)
Example #15
0
def test_operator_pointwise_product():
    """Check call and adjoint of operator pointwise multiplication."""
    if dom_eq_ran:
        mat1 = np.random.rand(3, 3)
        mat2 = np.random.rand(3, 3)
    else:
        mat1 = np.random.rand(4, 3)
        mat2 = np.random.rand(4, 3)

    op1 = MultiplyAndSquareOp(mat1)
    op2 = MultiplyAndSquareOp(mat2)
    x = noise_element(op1.domain)

    prod_op = odl.OperatorPointwiseProduct(op1, op2)

    # Evaluate
    expected = op1(x) * op2(x)
    check_call(prod_op, x, expected)

    # Derivative
    y = noise_element(op1.domain)
    expected = (op1.derivative(x)(y) * op2(x) + op2.derivative(x)(y) * op1(x))
    prod_deriv_op = prod_op.derivative(x)
    assert prod_deriv_op.is_linear
    check_call(prod_deriv_op, y, expected)

    # Derivative Adjoint
    z = noise_element(op1.range)
    expected = (op1.derivative(x).adjoint(z * op2(x)) +
                op2.derivative(x).adjoint(z * op1(x)))
    prod_deriv_adj_op = prod_deriv_op.adjoint
    assert prod_deriv_adj_op.is_linear
    check_call(prod_deriv_adj_op, z, expected)
Example #16
0
def newpart(request, space):
    element_form = request.param.strip()

    if element_form == 'space':
        tmp = noise_element(space)
        newreal = space.element(tmp.real)
    elif element_form == 'real_space':
        newreal = noise_element(space).real
    elif element_form == 'numpy_array':
        tmp = noise_element(space)
        newreal = [tmp[0].real.asarray(), tmp[1].real.asarray()]
    elif element_form == 'array':
        if space.is_power_space:
            newreal = [[0, 1, 2], [3, 4, 5]]
        else:
            newreal = [[0, 1, 2], [3, 4]]
    elif element_form == 'scalar':
        newreal = np.random.randn()
    elif element_form == '1d_array':
        if not space.is_power_space:
            pytest.skip('arrays matching only one dimension can only be used '
                        'for power spaces')
        newreal = [0, 1, 2]
    else:
        raise ValueError('undefined form of element')

    return newreal
def test_proximal_defintion(functional, stepsize):
    """Test the defintion of the proximal:

        prox[f](x) = argmin_y {f(y) + 1/2 ||x-y||^2}

    Hence we expect for all x in the domain of the proximal

        x* = prox[f](x)

        f(x*) + 1/2 ||x-x*||^2 <= f(y) + 1/2 ||x-y||^2
    """
    proximal = functional.proximal(stepsize)

    assert proximal.domain == functional.domain
    assert proximal.range == functional.domain

    for _ in range(100):
        x = noise_element(proximal.domain) * 10
        prox_x = proximal(x)
        f_prox_x = proximal_objective(stepsize * functional, x, prox_x)

        y = noise_element(proximal.domain)
        f_y = proximal_objective(stepsize * functional, x, y)

        if not f_prox_x <= f_y + EPS:
            print(repr(functional), x, y, prox_x, f_prox_x, f_y)

        assert f_prox_x <= f_y + EPS
Example #18
0
def test_arithmetic():
    """Test that all standard arithmetic works."""
    # Create elements needed for later
    operator = MultiplyAndSquareOp(np.random.rand(4, 3))
    operator2 = MultiplyAndSquareOp(np.random.rand(4, 3))
    operator3 = MultiplyAndSquareOp(np.random.rand(3, 3))
    operator4 = MultiplyAndSquareOp(np.random.rand(4, 4))
    x = noise_element(operator.domain)
    y = noise_element(operator.domain)
    z = noise_element(operator.range)
    scalar = np.pi

    # Simple tests here, more in depth comes later
    check_call(+operator, x, operator(x))
    check_call(-operator, x, -operator(x))
    check_call(scalar * operator, x, scalar * operator(x))
    check_call(scalar * (scalar * operator), x, scalar**2 * operator(x))
    check_call(operator * scalar, x, operator(scalar * x))
    check_call((operator * scalar) * scalar, x, operator(scalar**2 * x))
    check_call(operator + operator2, x, operator(x) + operator2(x))
    check_call(operator - operator2, x, operator(x) - operator2(x))
    check_call(operator * operator3, x, operator(operator3(x)))
    check_call(operator4 * operator, x, operator4(operator(x)))
    check_call(z * operator, x, z * operator(x))
    check_call(z * (z * operator), x, (z * z) * operator(x))
    check_call(operator * y, x, operator(x * y))
    check_call((operator * y) * y, x, operator((y * y) * x))
    check_call(operator + z, x, operator(x) + z)
    check_call(operator - z, x, operator(x) - z)
    check_call(z + operator, x, z + operator(x))
    check_call(z - operator, x, z - operator(x))
    check_call(operator + scalar, x, operator(x) + scalar)
    check_call(operator - scalar, x, operator(x) - scalar)
    check_call(scalar + operator, x, scalar + operator(x))
    check_call(scalar - operator, x, scalar - operator(x))
Example #19
0
def test_operator_pointwise_product():
    """Test OperatorPointwiseProduct."""
    Aop = MultiplyAndSquareOp(np.random.rand(4, 3))
    Bop = MultiplyAndSquareOp(np.random.rand(4, 3))
    x = noise_element(Aop.domain)

    prod = odl.OperatorPointwiseProduct(Aop, Bop)

    # Evaluate
    expected = Aop(x) * Bop(x)
    check_call(prod, x, expected)

    # Derivative
    y = noise_element(Aop.domain)
    expected = (Aop.derivative(x)(y) * Bop(x) +
                Bop.derivative(x)(y) * Aop(x))
    derivative = prod.derivative(x)
    assert derivative.is_linear
    check_call(derivative, y, expected)

    # Adjoint
    z = noise_element(Aop.range)
    expected = (Aop.derivative(x).adjoint(z * Bop(x)) +
                Bop.derivative(x).adjoint(z * Aop(x)))
    adjoint = derivative.adjoint
    assert adjoint.is_linear
    check_call(adjoint, z, expected)
Example #20
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)
Example #21
0
def test_matrix_op_adjoint(matrix):
    """Test if the adjoint of matrix operators is correct."""
    dense_matrix = matrix
    sparse_matrix = scipy.sparse.coo_matrix(dense_matrix)

    tol = 2 * matrix.size * np.finfo(matrix.dtype).resolution

    # Default 1d case
    dmat_op = MatrixOperator(dense_matrix)
    smat_op = MatrixOperator(sparse_matrix)
    x = noise_element(dmat_op.domain)
    y = noise_element(dmat_op.range)

    inner_ran = dmat_op(x).inner(y)
    inner_dom = x.inner(dmat_op.adjoint(y))
    assert inner_ran == pytest.approx(inner_dom, rel=tol, abs=tol)
    inner_ran = smat_op(x).inner(y)
    inner_dom = x.inner(smat_op.adjoint(y))
    assert inner_ran == pytest.approx(inner_dom, rel=tol, abs=tol)

    # Multi-dimensional case
    domain = odl.tensor_space((2, 2, 4), matrix.dtype)
    mat_op = MatrixOperator(dense_matrix, domain, axis=2)
    x = noise_element(mat_op.domain)
    y = noise_element(mat_op.range)
    inner_ran = mat_op(x).inner(y)
    inner_dom = x.inner(mat_op.adjoint(y))
    assert inner_ran == pytest.approx(inner_dom, rel=tol, abs=tol)
def functional(request, linear_offset, quadratic_offset, dual):
    """Return functional whose proximal should be tested."""
    name = request.param.strip()

    space = odl.uniform_discr(0, 1, 2)

    if name == 'l1':
        func = odl.solvers.L1Norm(space)
    elif name == 'l2':
        func = odl.solvers.L2Norm(space)
    elif name == 'l2^2':
        func = odl.solvers.L2NormSquared(space)
    elif name == 'kl':
        func = odl.solvers.KullbackLeibler(space)
    elif name == 'kl_cross_ent':
        func = odl.solvers.KullbackLeiblerCrossEntropy(space)
    elif name == 'const':
        func = odl.solvers.ConstantFunctional(space, constant=2)
    elif name.startswith('groupl1'):
        exponent = float(name.split('-')[1])
        space = odl.ProductSpace(space, 2)
        func = odl.solvers.GroupL1Norm(space, exponent=exponent)
    elif name.startswith('nuclearnorm'):
        outer_exp = float(name.split('-')[1])
        singular_vector_exp = float(name.split('-')[2])

        space = odl.ProductSpace(odl.ProductSpace(space, 2), 3)
        func = odl.solvers.NuclearNorm(space,
                                       outer_exp=outer_exp,
                                       singular_vector_exp=singular_vector_exp)
    elif name == 'quadratic':
        func = odl.solvers.QuadraticForm(operator=odl.IdentityOperator(space),
                                         vector=space.one(),
                                         constant=0.623)
    elif name == 'linear':
        func = odl.solvers.QuadraticForm(vector=space.one(), constant=0.623)
    else:
        assert False

    if quadratic_offset:
        if linear_offset:
            g = noise_element(space)
            if name.startswith('kl'):
                g = np.abs(g)
        else:
            g = None

        quadratic_coeff = 1.32
        func = odl.solvers.FunctionalQuadraticPerturb(
            func, quadratic_coeff=quadratic_coeff, linear_term=g)
    elif linear_offset:
        g = noise_element(space)
        if name.startswith('kl'):
            g = np.abs(g)
        func = func.translated(g)

    if dual:
        func = func.convex_conj

    return func
Example #23
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))
Example #24
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)
Example #25
0
def test_operator_pointwise_product():
    """Test OperatorPointwiseProduct."""
    Aop = MultiplyAndSquareOp(np.random.rand(4, 3))
    Bop = MultiplyAndSquareOp(np.random.rand(4, 3))
    x = noise_element(Aop.domain)

    prod = odl.OperatorPointwiseProduct(Aop, Bop)

    # Evaluate
    expected = Aop(x) * Bop(x)
    check_call(prod, x, expected)

    # Derivative
    y = noise_element(Aop.domain)
    expected = (Aop.derivative(x)(y) * Bop(x) + Bop.derivative(x)(y) * Aop(x))
    derivative = prod.derivative(x)
    assert derivative.is_linear
    check_call(derivative, y, expected)

    # Adjoint
    z = noise_element(Aop.range)
    expected = (Aop.derivative(x).adjoint(z * Bop(x)) +
                Bop.derivative(x).adjoint(z * Aop(x)))
    adjoint = derivative.adjoint
    assert adjoint.is_linear
    check_call(adjoint, z, expected)
Example #26
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 #27
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 almost_equal(inner1, inner2, places=dtype_places(dtype))
Example #28
0
def test_bregman_functional_no_gradient(space):
    """Test Bregman distance for functional without gradient.

    Test that the Bregman distance functional fails if the underlying
    functional does not have a gradient and no subgradient operator is
    given. Also test giving the subgradient operator separately.
    """

    ind_func = odl.solvers.IndicatorNonnegativity(space)
    point = noise_element(space)

    # Indicator function has no gradient, hence one cannot create a bregman
    # distance functional
    with pytest.raises(NotImplementedError):
        odl.solvers.BregmanDistance(ind_func, point)

    # If a subgradient operator is given separately, it is possible to create
    # an instance of the functional
    subgrad_op = odl.IdentityOperator(space)
    bregman_dist = odl.solvers.BregmanDistance(ind_func, point, subgrad_op)

    # In this case we should be able to call the gradient of the bregman
    # distance, which would give us a subgradient
    x = np.abs(noise_element(space))
    expected_result = subgrad_op(x) - subgrad_op(point)
    assert all_almost_equal(bregman_dist.gradient(x), expected_result)
Example #29
0
def test_arithmetic():
    """Test that all standard arithmetic works."""
    # Create elements needed for later
    operator = MultiplyAndSquareOp(np.random.rand(4, 3))
    operator2 = MultiplyAndSquareOp(np.random.rand(4, 3))
    operator3 = MultiplyAndSquareOp(np.random.rand(3, 3))
    operator4 = MultiplyAndSquareOp(np.random.rand(4, 4))
    x = noise_element(operator.domain)
    y = noise_element(operator.domain)
    z = noise_element(operator.range)
    scalar = np.pi

    # Simple tests here, more in depth comes later
    check_call(+operator, x, operator(x))
    check_call(-operator, x, -operator(x))
    check_call(scalar * operator, x, scalar * operator(x))
    check_call(scalar * (scalar * operator), x, scalar**2 * operator(x))
    check_call(operator * scalar, x, operator(scalar * x))
    check_call((operator * scalar) * scalar, x, operator(scalar**2 * x))
    check_call(operator + operator2, x, operator(x) + operator2(x))
    check_call(operator - operator2, x, operator(x) - operator2(x))
    check_call(operator * operator3, x, operator(operator3(x)))
    check_call(operator4 * operator, x, operator4(operator(x)))
    check_call(z * operator, x, z * operator(x))
    check_call(z * (z * operator), x, (z * z) * operator(x))
    check_call(operator * y, x, operator(x * y))
    check_call((operator * y) * y, x, operator((y * y) * x))
    check_call(operator + z, x, operator(x) + z)
    check_call(operator - z, x, operator(x) - z)
    check_call(z + operator, x, z + operator(x))
    check_call(z - operator, x, z - operator(x))
    check_call(operator + scalar, x, operator(x) + scalar)
    check_call(operator - scalar, x, operator(x) - scalar)
    check_call(scalar + operator, x, scalar + operator(x))
    check_call(scalar - operator, x, scalar - operator(x))
Example #30
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
    places = 3 if space.dtype == np.float32 else 5

    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 all_almost_equal(functional(x),
                            (orig_func(x) +
                             quadratic_coeff * x.inner(x) +
                             x.inner(linear_term)),
                            places=places)

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

    # 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,
                            places=places)

    # Test convex conjugate functional
    if quadratic_coeff == 0:
        expected = orig_func.convex_conj.translated(linear_term)(x)
        assert almost_equal(functional.convex_conj(x),
                            expected,
                            places=places)

    # 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),
        places=places)
Example #31
0
def test_equality(metric_space):
    """Verify that equality testing works."""
    x = noise_element(metric_space)
    y = noise_element(metric_space)

    assert x == x
    assert y == y
    assert x != y
Example #32
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)
Example #33
0
def functional(request, space):
    name = request.param.strip()

    if name == 'l1':
        func = odl.solvers.functional.L1Norm(space)
    elif name == 'l2':
        func = odl.solvers.functional.L2Norm(space)
    elif name == 'l2^2':
        func = odl.solvers.functional.L2NormSquared(space)
    elif name == 'constant':
        func = odl.solvers.functional.ConstantFunctional(space, 2)
    elif name == 'zero':
        func = odl.solvers.functional.ZeroFunctional(space)
    elif name == 'ind_unit_ball_1':
        func = odl.solvers.functional.IndicatorLpUnitBall(space, 1)
    elif name == 'ind_unit_ball_2':
        func = odl.solvers.functional.IndicatorLpUnitBall(space, 2)
    elif name == 'ind_unit_ball_pi':
        func = odl.solvers.functional.IndicatorLpUnitBall(space, np.pi)
    elif name == 'ind_unit_ball_inf':
        func = odl.solvers.functional.IndicatorLpUnitBall(space, np.inf)
    elif name == 'product':
        left = odl.solvers.functional.L2Norm(space)
        right = odl.solvers.functional.ConstantFunctional(space, 2)
        func = odl.solvers.functional.FunctionalProduct(left, right)
    elif name == 'quotient':
        dividend = odl.solvers.functional.L2Norm(space)
        divisor = odl.solvers.functional.ConstantFunctional(space, 2)
        func = odl.solvers.functional.FunctionalQuotient(dividend, divisor)
    elif name == 'kl':
        func = odl.solvers.functional.KullbackLeibler(space)
    elif name == 'kl_cc':
        func = odl.solvers.KullbackLeibler(space).convex_conj
    elif name == 'kl_cross_ent':
        func = odl.solvers.functional.KullbackLeiblerCrossEntropy(space)
    elif name == 'kl_cc_cross_ent':
        func = odl.solvers.KullbackLeiblerCrossEntropy(space).convex_conj
    elif name == 'huber':
        func = odl.solvers.Huber(space, gamma=0.1)
    elif name == 'groupl1':
        if isinstance(space, odl.ProductSpace):
            pytest.skip("The `GroupL1Norm` is not supported on `ProductSpace`")
        space = odl.ProductSpace(space, 3)
        func = odl.solvers.GroupL1Norm(space)
    elif name == 'bregman_l2squared':
        point = noise_element(space)
        l2_squared = odl.solvers.L2NormSquared(space)
        subgrad = l2_squared.gradient(point)
        func = odl.solvers.BregmanDistance(l2_squared, point, subgrad)
    elif name == 'bregman_l1':
        point = noise_element(space)
        l1 = odl.solvers.L1Norm(space)
        subgrad = l1.gradient(point)
        func = odl.solvers.BregmanDistance(l1, point, subgrad)
    else:
        assert False

    return func
def test_proximal_defintion(functional, stepsize):
    """Test the defintion of the proximal:

        prox[f](x) = argmin_y {f(y) + 1/2 ||x-y||^2}

    Hence we expect for all x in the domain of the proximal

        x* = prox[f](x)

        f(x*) + 1/2 ||x-x*||^2 <= f(y) + 1/2 ||x-y||^2
    """
    if isinstance(functional, FunctionalDefaultConvexConjugate):
        pytest.skip('functional has no call method')
        return

    # No implementation of the proximal for convex conj of
    # FunctionalQuadraticPerturb unless the quadratic term is 0.
    if (isinstance(functional, odl.solvers.FunctionalQuadraticPerturb)
            and functional.quadratic_coeff != 0):
        pytest.skip('functional has no proximal')
        return

    # No implementation of the proximal for quardartic form
    if isinstance(functional, odl.solvers.QuadraticForm):
        pytest.skip('functional has no proximal')
        return

    # No implementation of the proximal for translations of quardartic form
    if (isinstance(functional, odl.solvers.FunctionalTranslation)
            and isinstance(functional.functional, odl.solvers.QuadraticForm)):
        pytest.skip('functional has no proximal')
        return

    # No implementation of the proximal for convex conj of quardartic form,
    # except if the quadratic part is 0.
    if (isinstance(functional, odl.solvers.FunctionalQuadraticPerturb)
            and isinstance(functional.functional, odl.solvers.QuadraticForm)
            and functional.functional.operator is not None):
        pytest.skip('functional has no proximal')
        return

    proximal = functional.proximal(stepsize)

    assert proximal.domain == functional.domain
    assert proximal.range == functional.domain

    for _ in range(100):
        x = noise_element(proximal.domain) * 10
        prox_x = proximal(x)
        f_prox_x = proximal_objective(stepsize * functional, x, prox_x)

        y = noise_element(proximal.domain)
        f_y = proximal_objective(stepsize * functional, x, y)

        if not f_prox_x <= f_y + EPS:
            print(repr(functional), x, y, prox_x, f_prox_x, f_y)

        assert f_prox_x <= f_y + EPS
Example #35
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)
Example #36
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)
Example #37
0
def test_laplacian(space, padding):
    """Discretized spatial laplacian operator."""

    # Invalid space
    with pytest.raises(TypeError):
        Laplacian(range=odl.rn(1))

    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 almost_equal(lhs, rhs, places=4)
Example #38
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)
Example #39
0
def test_assign(fn):
    x = noise_element(fn)
    y = noise_element(fn)

    y.assign(x)

    assert y == x
    assert y is not x

    # test alignment
    x *= 2
    assert y != x
Example #40
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 almost_equal(lhs, rhs, places=4)

    # Higher dimensional arrays
    for ndim in range(1, 6):
        # DiscreteLpElement
        lin_size = 3
        space = odl.uniform_discr([0.] * ndim, [1.] * ndim, [lin_size] * ndim)
Example #41
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)
Example #42
0
def test_transpose(fn):
    x = noise_element(fn)
    y = noise_element(fn)

    # Assert linear operator
    assert isinstance(x.T, Operator)
    assert x.T.is_linear

    # Check result
    assert almost_equal(x.T(y), y.inner(x))
    assert all_equal(x.T.adjoint(1.0), x)

    # x.T.T returns self
    assert x.T.T == x
Example #43
0
def test_transpose(fn):
    x = noise_element(fn)
    y = noise_element(fn)

    # Assert linear operator
    assert isinstance(x.T, odl.Operator)
    assert x.T.is_linear

    # Check result
    assert almost_equal(x.T(y), x.inner(y))
    assert all_almost_equal(x.T.adjoint(1.0), x)

    # x.T.T returns self
    assert x.T.T == x
Example #44
0
def test_laplacian(space, padding):
    """Discretized spatial laplacian operator."""

    # Invalid space
    with pytest.raises(TypeError):
        Laplacian(range=odl.rn(1))

    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 almost_equal(lhs, rhs, places=4)
Example #45
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 almost_equal(lhs, rhs, places=4)

    # Higher dimensional arrays
    for ndim in range(1, 6):
        # DiscreteLpElement
        lin_size = 3
        space = odl.uniform_discr([0.] * ndim, [1.] * ndim, [lin_size] * ndim)
Example #46
0
def test_proximal_translation(sigma):
    """Test for the proximal of a translation: ``prox[F(. - g)]``."""
    sigma = float(sigma)
    space = odl.uniform_discr(0, 1, 10)
    lam = 1.2
    prox_factory = proximal_l2_squared(space, lam=lam)

    translation = noise_element(space)
    prox = proximal_translation(prox_factory, translation)(sigma)

    x = noise_element(space)
    expected_result = ((x + 2 * sigma * lam * translation) /
                       (1 + 2 * sigma * lam))

    assert all_almost_equal(prox(x), expected_result, places=PLACES)
def test_forward_backward_basic():
    """Test for the forward-backward solver by minimizing ||x||_2^2.

    The general problem is of the form

        ``min_x f(x) + sum_i g_i(L_i x) + h(x)``

    and here we take f(x) = g(x) = 0, h(x) = ||x||_2^2 and L is the
    zero-operator.
    """

    space = odl.rn(10)

    lin_ops = [odl.ZeroOperator(space)]
    g = [odl.solvers.ZeroFunctional(space)]
    f = odl.solvers.ZeroFunctional(space)
    h = odl.solvers.L2NormSquared(space)

    x = noise_element(space)
    x_global_min = space.zero()

    forward_backward_pd(x, f, g, lin_ops, h, tau=0.5,
                        sigma=[1.0], niter=10)

    assert all_almost_equal(x, x_global_min, places=HIGH_ACCURACY)
Example #48
0
def test_quadratic_form(space):
    """Test the quadratic form functional."""
    operator = odl.IdentityOperator(space)
    vector = space.one()
    constant = 0.363
    func = odl.solvers.QuadraticForm(operator, vector, constant)

    x = noise_element(space)

    # Checking that values is stored correctly
    assert func.operator == operator
    assert func.vector == vector
    assert func.constant == constant

    # Evaluation of the functional
    expected_result = x.inner(operator(x)) + vector.inner(x) + constant
    assert almost_equal(func(x), expected_result)

    # Also test with some values as none
    func_no_offset = odl.solvers.QuadraticForm(operator, constant=constant)
    expected_result = x.inner(operator(x)) + constant
    assert almost_equal(func_no_offset(x), expected_result)

    func_no_operator = odl.solvers.QuadraticForm(vector=vector,
                                                 constant=constant)
    expected_result = vector.inner(x) + constant
    assert almost_equal(func_no_operator(x), expected_result)

    # The gradient
    expected_gradient = 2 * operator(x) + vector
    assert all_almost_equal(func.gradient(x), expected_gradient)

    # The convex conjugate
    assert isinstance(func.convex_conj, odl.solvers.QuadraticForm)
Example #49
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)
Example #50
0
def test_functional_linear_perturb(space):
    """Test for the 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
    linear_term = noise_element(space)

    # Creating the functional ||x||_2^2 and add the linear perturbation
    orig_func = odl.solvers.L2NormSquared(space)
    functional = odl.solvers.FunctionalLinearPerturb(orig_func, linear_term)

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

    # Test for evaluation of the functional
    assert all_almost_equal(functional(x), x.norm()**2 + x.inner(linear_term),
                            places=places)

    # Test for the gradient
    assert all_almost_equal(functional.gradient(x), 2.0 * x + linear_term,
                            places=places)

    # Test for derivative in direction p
    p = noise_element(space)
    assert all_almost_equal(functional.derivative(x)(p),
                            p.inner(2 * x + linear_term),
                            places=places)

    # Test for the proximal operator
    sigma = 1.2
    # Explicit computation gives (x - sigma * translation)/(2 * sigma + 1)
    expected_result = (x - sigma * linear_term) / (2.0 * sigma + 1.0)
    assert all_almost_equal(functional.proximal(sigma)(x), expected_result,
                            places=places)

    # Test convex conjugate functional
    assert almost_equal(functional.convex_conj(x),
                        orig_func.convex_conj.translated(linear_term)(x),
                        places=places)

    # Test proximal of the convex conjugate
    assert all_almost_equal(
        functional.convex_conj.proximal(sigma)(x),
        orig_func.convex_conj.translated(linear_term).proximal(sigma)(x),
        places=places)
Example #51
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
    places = 3 if space.dtype == np.float32 else 5

    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()),
                                places=places)
        # Nothing more to do, rest is part of ConstantFunctional test
        return

    # Test functional evaluation
    assert almost_equal(rmul_func(x), func(scalar * x), places=places)

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

    # 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),
                            places=places)

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

    # 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),
        places=places)

    # Verify that for linear functionals, left multiplication is used.
    func = odl.solvers.ZeroFunctional(space)
    assert isinstance(func * scalar, odl.solvers.FunctionalLeftScalarMult)
Example #52
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
    places = 3 if space.dtype == np.float32 else 5

    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 almost_equal(lmul_func(x), scalar * func(x), places=places)

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

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

    # 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),
                            places=places)

    # 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))
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))
Example #54
0
def test_part_deriv(space, method, padding):
    """Discretized partial derivative."""

    with pytest.raises(TypeError):
        PartialDerivative(odl.rn(1))

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

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

    # operator
    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.asarray(), 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 almost_equal(lhs, rhs, places=4)
def test_forward_backward_input_handling():
    """Test to see that input is handled correctly."""

    space1 = odl.uniform_discr(0, 1, 10)

    lin_ops = [odl.ZeroOperator(space1), odl.ZeroOperator(space1)]
    g = [odl.solvers.ZeroFunctional(space1),
         odl.solvers.ZeroFunctional(space1)]
    f = odl.solvers.ZeroFunctional(space1)
    h = odl.solvers.ZeroFunctional(space1)

    # Check that the algorithm runs. With the above operators, the algorithm
    # returns the input.
    x0 = noise_element(space1)
    x = x0.copy()
    niter = 3

    forward_backward_pd(x, f, g, lin_ops, h, tau=1.0,
                        sigma=[1.0, 1.0], niter=niter)

    assert x == x0

    # Testing that sizes needs to agree:
    # Too few sigma_i:s
    with pytest.raises(ValueError):
        forward_backward_pd(x, f, g, lin_ops, h, tau=1.0,
                            sigma=[1.0], niter=niter)

    # Too many operators
    g_too_many = [odl.solvers.ZeroFunctional(space1),
                  odl.solvers.ZeroFunctional(space1),
                  odl.solvers.ZeroFunctional(space1)]
    with pytest.raises(ValueError):
        forward_backward_pd(x, f, g_too_many, lin_ops, h,
                            tau=1.0, sigma=[1.0, 1.0], niter=niter)

    # Test for correct space
    space2 = odl.uniform_discr(1, 2, 10)
    x = noise_element(space2)
    with pytest.raises(ValueError):
        forward_backward_pd(x, f, g, lin_ops, h, tau=1.0,
                            sigma=[1.0, 1.0], niter=niter)
Example #56
0
def test_functional_plus_scalar(space):
    """Test for sum of functioanl and scalar."""
    # Less strict checking for single precision
    places = 3 if space.dtype == np.float32 else 5

    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 almost_equal(func_scalar_sum(x), func(x) + scalar, places=places)

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

    assert almost_equal(func_scalar_sum.derivative(x)(p),
                        func.gradient(x).inner(p),
                        places=places)

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

    # Test convex conjugate functional
    assert almost_equal(func_scalar_sum.convex_conj(x),
                        func.convex_conj(x) - scalar,
                        places=places)

    assert all_almost_equal(func_scalar_sum.convex_conj.gradient(x),
                            func.convex_conj.gradient(x),
                            places=places)
Example #57
0
def test_functional_sum(space):
    """Test for the sum of two functionals."""
    # Less strict checking for single precision
    places = 3 if space.dtype == np.float32 else 5

    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 almost_equal(func_sum(x), func1(x) + func2(x), places=places)

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

    assert almost_equal(
        func_sum.derivative(x)(p),
        func1.gradient(x).inner(p) + func2.gradient(x).inner(p),
        places=places)

    # 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)
def test_moreau_envelope_l2_sq(space, sigma):
    """Test for the Moreau envelope with l2 norm squared."""

    # Result is ||x||_2^2 / (1 + 2 sigma)
    # Gradient is x * 2 / (1 + 2 * sigma)
    l2_sq = odl.solvers.L2NormSquared(space)

    smoothed_l2_sq = odl.solvers.MoreauEnvelope(l2_sq, sigma=sigma)
    x = noise_element(space)
    assert all_almost_equal(smoothed_l2_sq.gradient(x),
                            x * 2 / (1 + 2 * sigma))
Example #59
0
def test_copy(fn):
    import copy

    x = noise_element(fn)
    y = copy.copy(x)

    assert x == y
    assert y is not x

    z = copy.deepcopy(x)

    assert x == z
    assert z is not x
Example #60
0
def test_derivative(functional):
    """Test for the derivative of a functional.

    The test checks that the directional derivative in a point is the same as
    the inner product of the gradient and the direction, if the gradient is
    defined.
    """
    if isinstance(functional, odl.solvers.functional.IndicatorLpUnitBall):
        # IndicatorFunction has no derivative
        with pytest.raises(NotImplementedError):
            functional.derivative(functional.domain.zero())
        return

    x = noise_element(functional.domain)
    y = 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.ufunc.absolute()
        y = y.ufunc.absolute()

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

    # Compute a "small" step size according to dtype of space
    step = float(np.sqrt(np.finfo(functional.domain.dtype).eps))

    # Numerical test of gradient, only low accuracy can be guaranteed.
    assert all_almost_equal((functional(x + step * y) - functional(x)) / step,
                            y.inner(functional.gradient(x)),
                            places=1)

    # Check that derivative and gradient is consistent
    assert all_almost_equal(functional.derivative(x)(y),
                            y.inner(functional.gradient(x)))