Source code for odl.diagnostics.space

# Copyright 2014-2019 The ODL contributors
#
# This file is part of ODL.
#
# This Source Code Form is subject to the terms of the Mozilla Public License,
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/.

"""Standardized tests for ``LinearSpace``."""

from __future__ import absolute_import, division, print_function

from builtins import object
from copy import copy, deepcopy

from odl.diagnostics.examples import samples
from odl.set import Field
from odl.util.testutils import fail_counter

__all__ = ('SpaceTest',)


def _approx_equal(x, y, eps):
    """Test if elements ``x`` and ``y`` are approximately equal.

    ``eps`` is a given absolute tolerance.
    """
    if x.space != y.space:
        return False

    if x is y:
        return True

    try:
        return x.dist(y) <= eps
    except NotImplementedError:
        try:
            return x == y
        except NotImplementedError:
            return False


[docs]class SpaceTest(object): """Automated tests for `LinearSpace` instances. This class allows users to automatically test various features of a `LinearSpace` such as linearity and vector space operations. """
[docs] def __init__(self, space, verbose=True, tol=1e-5): """Initialize a new instance. Parameters ---------- space : `LinearSpace` Space that should be tested. verbose : bool, optional If ``True``, print additional info text. tol : float, optional Tolerance parameter used as a base for the actual tolerance in the tests. Depending on the expected accuracy, the actual tolerance used in a test can be a factor times this number. """ self.space = space self.verbose = bool(verbose) self.tol = float(tol)
[docs] def log(self, message): """Print message if ``self.verbose == True``.""" if self.verbose: print(message)
[docs] def element_method(self): """Verify `LinearSpace.element`.""" with fail_counter( test_name='Verifying element method', logger=self.log ) as counter: try: elem = self.space.element() except NotImplementedError: counter.fail('*** element failed ***') return if elem not in self.space: counter.fail('*** space.element() not in space ***')
[docs] def field(self): """Verify `LinearSpace.field`.""" with fail_counter( test_name='Verifying field property', logger=self.log ) as counter: try: field = self.space.field except NotImplementedError: counter.fail('*** field failed ***') return if not isinstance(field, Field): counter.fail('*** space.field not a `Field` ***') return try: zero = field.element(0) except NotImplementedError: counter.fail('*** field.element(0) failed ***') zero = None if zero is not None and zero != 0: counter.fail('*** field.element(0) != 0 ***') if zero is not None and zero != 0.0: counter.fail('*** field.element(0) != 0.0 ***') try: one = field.element(1) except NotImplementedError: counter.fail('*** field.element(1) failed ***') one = None if one is not None and one != 1: counter.fail('*** field.element(1) != 1 ***') if one is not None and one != 1.0: counter.fail('*** field.element(1) != 1.0 ***') try: minus_one = field.element(-1) except NotImplementedError: counter.fail('field.element(-1) failed') minus_one = None if minus_one is not None and minus_one != -1: counter.fail('field.element(-1) != -1') if minus_one is not None and minus_one != -1.0: counter.fail('field.element(-1) != -1.0')
def _associativity_of_addition(self): """Verify addition associativity.""" with fail_counter( test_name='Verifying associativity of addition', err_msg='error = dist(x + (y + z), (x + y) + z)', logger=self.log ) as counter: for [n_x, x], [n_y, y], [n_z, z] in samples(self.space, self.space, self.space): correct = _approx_equal(x + (y + z), (x + y) + z, self.tol) if not correct: counter.fail('failed with x={:25s} y={:25s} z={:25s}' ''.format(n_x, n_y, n_z)) def _commutativity_of_addition(self): """Verify addition commutativity.""" with fail_counter( test_name='Verifying commutativity of addition', err_msg='error = dist(x + y, y + x)', logger=self.log ) as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): correct = _approx_equal(x + y, y + x, self.tol) if not correct: counter.fail('failed with x={:25s} y={:25s}' ''.format(n_x, n_y)) def _identity_of_addition(self): """Verify additive neutral element ('zero').""" try: zero = self.space.zero() except (AttributeError, NotImplementedError): print('*** SPACE HAS NO ZERO VECTOR ***') return with fail_counter( test_name='Verifying identity element of addition', err_msg='error = dist(x + 0, x)', logger=self.log ) as counter: for [n_x, x] in samples(self.space): correct = _approx_equal(x + zero, x, self.tol) if not correct: counter.fail('failed with x={:25s}'.format(n_x)) def _inverse_element_of_addition(self): """Verify additive inverse.""" try: zero = self.space.zero() except (AttributeError, NotImplementedError): print('*** SPACE HAS NO ZERO VECTOR ***') return with fail_counter( test_name='Verifying inverse element of addition', err_msg='error = dist(x + (-x), 0)', logger=self.log ) as counter: for [n_x, x] in samples(self.space): correct = _approx_equal(x + (-x), zero, self.tol) if not correct: counter.fail('failed with x={:25s}'.format(n_x)) def _commutativity_of_scalar_mult(self): """Verify scalar multiplication commutativity.""" with fail_counter( test_name='Verifying commutativity of scalar multiplication', err_msg='error = dist(a * (b * x), (a * b) * x)', logger=self.log ) as counter: for [n_x, x], [_, a], [_, b] in samples(self.space, self.space.field, self.space.field): correct = _approx_equal(a * (b * x), (a * b) * x, self.tol) if not correct: counter.fail('failed with x={:25s}, a={}, b={}' ''.format(n_x, a, b)) def _identity_of_mult(self): """Verify multiplicative neutral element ('one').""" with fail_counter( test_name='Verifying identity element of multiplication', err_msg='error = dist(1 * x, x)', logger=self.log ) as counter: for [n_x, x] in samples(self.space): correct = _approx_equal(1 * x, x, self.tol) if not correct: counter.fail('failed with x={:25s}'.format(n_x)) def _distributivity_of_mult_vector(self): """Verify scalar multiplication distributivity wrt vector addition.""" with fail_counter( test_name='Verifying distributivity of scalar multiplication ' 'under vector addition', err_msg='error = dist(a * (x + y), a * x + a * y)', logger=self.log ) as counter: for [n_x, x], [n_y, y], [_, a] in samples(self.space, self.space, self.space.field): correct = _approx_equal(a * (x + y), a * x + a * y, self.tol) if not correct: counter.fail('failed with x={:25s}, y={:25s}, a={}' ''.format(n_x, n_y, a)) def _distributivity_of_mult_scalar(self): """Verify scalar multiplication distributivity wrt scalar addition.""" with fail_counter( test_name='Verifying distributivity of scalar multiplication ' 'under scalar addition', err_msg='error = dist((a + b) * x, a * x + b * x)', logger=self.log ) as counter: for [n_x, x], [_, a], [_, b] in samples(self.space, self.space.field, self.space.field): correct = _approx_equal((a + b) * x, a * x + b * x, self.tol) if not correct: counter.fail('failed with x={:25s}, a={}, b={}' ''.format(n_x, a, b)) def _subtraction(self): """Verify element subtraction as addition of additive inverse.""" with fail_counter( test_name='Verifying element subtraction', err_msg='error = dist(x - y, x + (-1 * y))', logger=self.log ) as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): correct = (_approx_equal(x - y, x + (-1 * y), self.tol) and _approx_equal(x - y, x + (-y), self.tol)) if not correct: counter.fail('failed with x={:25s}, y={:25s}' ''.format(n_x, n_y)) def _division(self): """Verify scalar division as multiplication with mult. inverse.""" with fail_counter( test_name='Verifying scalar division', err_msg='error = dist(x / a, x * (1/a))', logger=self.log ) as counter: for [n_x, x], [_, a] in samples(self.space, self.space.field): if a != 0: correct = _approx_equal(x / a, x * (1.0 / a), self.tol) if not correct: counter.fail('failed with x={:25s}, a={}' ''.format(n_x, a)) def _lincomb_aliased(self): """Verify several scenarios of aliased linear combination.""" with fail_counter( test_name='Verifying linear combination with aliased input', err_msg='error = dist(aliased, non-aliased)', logger=self.log ) as counter: for [n_x, x_in], [n_y, y] in samples(self.space, self.space): x = x_in.copy() x.lincomb(1, x, 1, y) correct = _approx_equal(x, x_in + y, self.tol) if not correct: counter.fail('failed with x.lincomb(1, x, 1, y),' 'x={:25s} y={:25s} ' ''.format(n_x, n_y)) x = x_in.copy() x.lincomb(1, x, 1, x) correct = _approx_equal(x, x_in + x_in, self.tol) if not correct: counter.fail('failed with x.lincomb(1, x, 1, x),' 'x={:25s} ' ''.format(n_x))
[docs] def _lincomb(self): """Verify linear combination.""" self.log('\nTesting lincomb') self._lincomb_aliased()
[docs] def linearity(self): """Verify the linear space properties by examples. These properties include things such as associativity ``x + y = y + x`` and identity of the ``LinearSpace.zero`` element ``x + 0 = x`` References ---------- Wikipedia article on `Vector space`_. .. _Vector space: https://en.wikipedia.org/wiki/Vector_space """ self.log('\n== Verifying linear space properties ==\n') self._associativity_of_addition() self._commutativity_of_addition() self._identity_of_addition() self._inverse_element_of_addition() self._commutativity_of_scalar_mult() self._identity_of_mult() self._distributivity_of_mult_vector() self._distributivity_of_mult_scalar() self._subtraction() self._division() self._lincomb()
def _inner_linear_scalar(self): """Verify homogeneity of the inner product in the first argument.""" with fail_counter( test_name='Verifying homogeneity of the inner product in the ' 'first argument', err_msg='error = |<a*x, y> - a*<x, y>|', logger=self.log ) as counter: for [n_x, x], [n_y, y], [_, a] in samples(self.space, self.space, self.space.field): error = abs((a * x).inner(y) - a * x.inner(y)) if error > self.tol: counter.fail('x={:25s}, y={:25s}, a={}: error={}' ''.format(n_x, n_y, a, error)) def _inner_conjugate_symmetry(self): """Verify conjugate symmetry of the inner product.""" with fail_counter( test_name='Verifying conjugate symmetry of the inner product', err_msg='error = |<x, y> - <y, x>.conj()|', logger=self.log ) as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): error = abs((x).inner(y) - y.inner(x).conjugate()) if error > self.tol: counter.fail('x={:25s}, y={:25s}: error={}' ''.format(n_x, n_y, error)) def _inner_linear_sum(self): """Verify distributivity of the inner product in the first argument.""" with fail_counter( test_name='Verifying distributivity of the inner product' 'in the first argument', err_msg='error = |<x+y, z> - (<x, z> + <y, z>)|', logger=self.log ) as counter: for [n_x, x], [n_y, y], [n_z, z] in samples(self.space, self.space, self.space): error = abs((x + y).inner(z) - (x.inner(z) + y.inner(z))) if error > self.tol: counter.fail('x={:25s}, y={:25s}, z={:25s}: error={}' ''.format(n_x, n_y, n_z, error)) def _inner_positive(self): """Verify positive definiteness of the inner product.""" with fail_counter( test_name='Verifying positive definiteness of the inner ' 'product', logger=self.log ) as counter: for [n_x, x] in samples(self.space): inner = x.inner(x) if abs(inner.imag) > self.tol: counter.fail('<x, x>.imag != 0, x={:25s}, <x, x>.imag = {}' ''.format(n_x, inner.imag)) if n_x == 'Zero' and inner.real != 0: counter.fail('<0, 0> != 0.0, x={:25s}: <0, 0>={}' ''.format(n_x, inner)) elif n_x != 'Zero' and inner.real <= 0: counter.fail('<x, x> <= 0, x={:25s}: <x, x>={}' ''.format(n_x, inner))
[docs] def inner(self): """Verify ``LinearSpace.inner``. The inner product is checked for the following properties: - conjugate symmetry: ``<x, y> = <y, x>^*`` (^* complex conjugate) - linearity: ``<a * x, y> = a * <x, y>`` ``<x + y, z> = <x, z> + <y, z>`` - positive definiteness: ``<x, x> >= 0`` References ---------- Wikipedia article on `inner product`_. .. _inner product: https://en.wikipedia.org/wiki/Inner_product_space """ self.log('\n== Verifying inner product ==\n') try: zero = self.space.zero() zero.inner(zero) except NotImplementedError: self.log('Space has no inner product') return self._inner_conjugate_symmetry() self._inner_linear_scalar() self._inner_linear_sum() self._inner_positive()
def _norm_positive(self): """Verify positive definiteness of the norm.""" with fail_counter( test_name='Verifying positive definiteness of the norm', logger=self.log ) as counter: for [n_x, x] in samples(self.space): norm = x.norm() if n_x == 'Zero' and norm != 0: counter.fail('||0|| != 0.0, x={:25s}: ||x||={}' ''.format(n_x, norm)) elif n_x != 'Zero' and norm <= 0: counter.fail('||x|| <= 0, x={:25s}: ||x||={}' ''.format(n_x, norm)) def _norm_subadditive(self): """Verify subadditivity of the norm.""" with fail_counter( test_name='Verifying sub-additivity of the norm', err_msg='error = max(||x+y|| - (||x|| + ||y||), 0)', logger=self.log ) as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): norm_x = x.norm() norm_y = y.norm() norm_xy = (x + y).norm() error = norm_xy - norm_x - norm_y if error > 0: counter.fail('x={:25s} y={:25s}: error={}' ''.format(n_x, n_y, error)) def _norm_homogeneity(self): """Verify positive homogeneity of the norm.""" with fail_counter( test_name='Verifying positive homogeneity of the norm', err_msg='error = | ||a*x|| - |a|*||x|| |', logger=self.log ) as counter: for [n_x, x], [_, a] in samples(self.space, self.space.field): error = abs((a * x).norm() - abs(a) * x.norm()) if error > self.tol: counter.fail('x={:25s} a={}: error={}' ''.format(n_x, a, error)) def _norm_inner_compatible(self): """Verify compatibility of norm and inner product.""" try: zero = self.space.zero() zero.inner(zero) except NotImplementedError: self.log('Space has no inner product') return with fail_counter( test_name='Verifying compatibility of norm and inner product', err_msg='error = | ||x||^2 - <x, x> |', logger=self.log ) as counter: for [n_x, x] in samples(self.space): error = abs(x.norm() ** 2 - x.inner(x)) if error > self.tol: counter.fail('x={:25s}: error={}' ''.format(n_x, error))
[docs] def norm(self): """Verify ``LinearSpace.norm``. The norm is checked for the following properties: - linearity: ``||a * x|| = |a| * ||x||`` - subadditivity: ``||x + y|| <= ||x|| + ||y||`` - positive homogeneity: ``||a * x|| = |a| * ||x||`` - positive definiteness: ``||x|| >= 0`` ``||x|| = 0`` iff ``x = 0`` - compatibility with the inner product (if available): ``||x||^2 = <x, x>`` References ---------- Wikipedia article on norm_. .. _norm: https://en.wikipedia.org/wiki/Norm_(mathematics) """ self.log('\n== Verifying norm ==\n') try: self.space.zero().norm() except NotImplementedError: self.log('Space has no norm') return self._norm_positive() self._norm_subadditive() self._norm_homogeneity() self._norm_inner_compatible()
def _dist_positivity(self): """Verify nonnegativity of the distance.""" with fail_counter( test_name='Verifying nonnegativity of the distance', logger=self.log ) as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): dist = x.dist(y) if n_x == n_y and dist != 0: counter.fail('d(x, x) != 0.0, x={:25s}: dist={}' ''.format(n_x, dist)) elif n_x != n_y and dist <= 0: counter.fail('d(x, y) <= 0, x={:25s} y={:25s}: dist={}' ''.format(n_x, n_y, dist)) def _dist_symmetric(self): """Verify symmetry of the distance.""" with fail_counter( test_name='Verifying symmetry of the distance', err_msg='error = |d(x, y) - d(y, x)|', logger=self.log ) as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): dist_1 = x.dist(y) dist_2 = y.dist(x) error = abs(dist_1 - dist_2) if error > self.tol: counter.fail('x={:25s}, y={:25s}: error={}' ''.format(n_x, n_y, error)) def _dist_subtransitive(self): """Verify sub-transitivity of the distance.""" with fail_counter( test_name='Verifying sub-additivity of the distance', err_msg='error = max(d(x,z) - (d(x, y) + d(y, z)), 0)', logger=self.log ) as counter: for [n_x, x], [n_y, y], [n_z, z] in samples(self.space, self.space, self.space): dxz = x.dist(z) dxy = x.dist(y) dyz = y.dist(z) error = dxz - (dxy + dyz) if error > self.tol: counter.fail('x={:25s}, y={:25s}, z={:25s}: error={}' ''.format(n_x, n_y, n_z, error)) def _dist_norm_compatible(self): """Verify compatibility of distance and norm.""" try: self.space.zero().norm() except NotImplementedError: self.log('Space has no norm') return with fail_counter( test_name='Verifying compatibility of distance and norm', err_msg='error = |d(x, y) - ||x-y|| |', logger=self.log ) as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): error = abs(x.dist(y) - (x - y).norm()) if error > self.tol: counter.fail('x={:25s}, y={:25s}: error={}' ''.format(n_x, n_y, error))
[docs] def dist(self): """Verify ``LinearSpace.dist``. The distance metric is checked for the following properties: - positive definiteness: ``d(x, y) >= 0`` ``d(x, y) = 0`` iff ``x = y`` - symmetry: ``d(x, y) = d(y, x)`` - sub-transitivity: ``d(x, z) <= d(x, y) + d(y, z)`` - compatibility with the norm (if available): ``d(x, y) = ||x - y||`` References ---------- Wikipedia article on metric_ .. _metric: https://en.wikipedia.org/wiki/Metric_(mathematics) """ self.log('\n== Verifying dist ==\n') try: zero = self.space.zero() self.space.dist(zero, zero) except NotImplementedError: self.log('Space has no distance metric') return self._dist_positivity() self._dist_symmetric() self._dist_subtransitive() self._dist_norm_compatible()
def _multiply_zero(self): """Verify that vector multiplication with zero is zero.""" try: zero = self.space.zero() except NotImplementedError: print('*** SPACE HAS NO ZERO VECTOR ***') return with fail_counter( test_name='Verifying vector multiplication with zero', err_msg='error = ||x * 0||', logger=self.log ) as counter: for [n_x, x] in samples(self.space): error = (zero * x).norm() if error > self.tol: counter.fail('x={:25s},: error={}' ''.format(n_x, error)) def _multiply_commutative(self): """Verify commutativity of vector multiplication.""" with fail_counter( test_name='Verifying commutativity of vector multiplication', err_msg='error = dist(x * y, y * x)', logger=self.log ) as counter: for [n_x, x], [n_y, y], _ in samples(self.space, self.space, self.space): correct = _approx_equal(x * y, y * x, self.tol) if not correct: counter.fail('failed with x={:25s} y={:25s}' ''.format(n_x, n_y)) def _multiply_associative(self): """Verify associativity of vector multiplication.""" with fail_counter( test_name='Verifying associativity of vector multiplication', err_msg='error = dist(x * (y * z), (x * y) * z)', logger=self.log ) as counter: for [n_x, x], [n_y, y], [n_z, z] in samples(self.space, self.space, self.space): correct = _approx_equal(x * (y * z), (x * y) * z, self.tol) if not correct: counter.fail('failed with x={:25s} y={:25s} z={:25s}' ''.format(n_x, n_y, n_z)) def _multiply_distributive_scalar(self): """Verify distributivity of scalar multiplication.""" with fail_counter( test_name='Verifying distributivity of vector multiplication ' 'under scalar multiplication', err_msg='error = dist(a * (x + y), a * x + a * y)', logger=self.log ) as counter: for [n_x, x], [n_y, y], [_, a] in samples(self.space, self.space, self.space.field): correct = _approx_equal(a * (x + y), a * x + a * y, self.tol) if not correct: counter.fail('failed with x={:25s} y={:25s} a={}' ''.format(n_x, n_y, a)) def _multiply_distributive_vector(self): """Verify distributivity of vector multiplication.""" with fail_counter( test_name='Verifying distributivity of vector multiplication ' 'under vector multiplication', err_msg='error = dist(x * (y + z), x * y + x * z)', logger=self.log ) as counter: for [n_x, x], [n_y, y], [n_z, z] in samples(self.space, self.space, self.space): correct = _approx_equal(x * (y + z), x * y + x * z, self.tol) if not correct: counter.fail('failed with x={:25s} y={:25s} z={:25s}' ''.format(n_x, n_y, n_z))
[docs] def multiply(self): """Verify ``LinearSpace.multiply``. The vector multiplication is checked for the following properties: - Zero element: ``0 * x = 0`` - Commutativity: ``x * y = y * x`` - Associativity: ``x * (y * z) = (x * y) * z`` - Distributivity: ``a * (x + y) = a * x + a * y`` ``x * (y + z) = x * y + x * z`` """ self.log('\n== Verifying multiplication ==\n') try: zero = self.space.zero() except NotImplementedError: print('*** SPACE HAS NO ZERO VECTOR ***') return try: self.space.multiply(zero, zero) except NotImplementedError: self.log('Space has no vector multiplication.') return self._multiply_zero() self._multiply_commutative() self._multiply_associative() self._multiply_distributive_scalar() self._multiply_distributive_vector()
[docs] def equals(self): """Verify `LinearSpace.__eq__`.""" self.log('\n== Verifying __eq__ ==\n') if not self.space == self.space: print('** space == space failed ***') if self.space != self.space: print('** not space != space failed***') if self.space != copy(self.space): print('** space == copy(space) failed***') if self.space != deepcopy(self.space): print('** space == deepcopy(space) failed***') with fail_counter( test_name='Verify behavior of `space == obj` when `obj` ' 'is not a space', logger=self.log ) as counter: for obj in [[1, 2], list(), tuple(), dict(), 5.0]: if self.space == obj: counter.fail('space == obj, with obj={}' ''.format(obj)) if not self.space != obj: counter.fail('not space != obj, with obj={}' ''.format(obj))
[docs] def contains(self): """Verify `LinearSpace.__contains__`.""" with fail_counter( test_name='Verify behavior of `obj in space`', logger=self.log ) as counter: for [n_x, x] in samples(self.space): if x not in self.space: counter.fail('x not in space, with x={}' ''.format(n_x)) if x not in self.space: counter.fail('not x in space, with x={}' ''.format(n_x)) for obj in [[1, 2], list(), tuple(), dict(), 5.0]: if obj in self.space: counter.fail('obj in space, with obj={}' ''.format(obj)) if not obj not in self.space: counter.fail('not obj not in space, with obj={}' ''.format(obj))
[docs] def element_assign(self): """Verify `LinearSpaceElement.assign`.""" with fail_counter( test_name='Verify behavior of `LinearSpaceElement.assign`', logger=self.log ) as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): x.assign(y) correct = _approx_equal(x, y, self.tol) if not correct: counter.fail('failed with x={:25s} y={:25s}' ''.format(n_x, n_y))
[docs] def element_copy(self): """Verify `LinearSpaceElement.copy`.""" with fail_counter( test_name='Verify behavior of `LinearSpaceElement.copy`', logger=self.log ) as counter: for [n_x, x] in samples(self.space): # equal after copy y = x.copy() correct = _approx_equal(x, y, self.tol) if not correct: counter.fail('failed with x={:s5s}' ''.format(n_x)) # modify y, x stays the same y *= 2.0 correct = n_x == 'Zero' or not _approx_equal(x, y, self.tol) if not correct: counter.fail('modified y, x changed with x={:25s}' ''.format(n_x))
[docs] def element_set_zero(self): """Verify `LinearSpaceElement.set_zero`.""" try: zero = self.space.zero() except NotImplementedError: print('*** SPACE HAS NO ZERO VECTOR ***') return with fail_counter( test_name='Verify behavior of `LinearSpaceElement.set_zero`', logger=self.log ) as counter: for [n_x, x] in samples(self.space): x.set_zero() correct = _approx_equal(x, zero, self.tol) if not correct: counter.fail('failed with x={:25s}' ''.format(n_x))
[docs] def element_equals(self): """Verify `LinearSpaceElement.__eq__`.""" try: zero = self.space.zero() except NotImplementedError: print('*** SPACE HAS NO ZERO VECTOR ***') return try: zero == zero except NotImplementedError: self.log('Vector has no __eq__') return with fail_counter( test_name='Verify behavior of `element1 == element2`', logger=self.log ) as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): if n_x == n_y: if not x == y: counter.fail('failed x == x with x={:25s}' ''.format(n_x)) if x != y: counter.fail('failed not x != x with x={:25s}' ''.format(n_x)) else: if x == y: counter.fail('failed not x == y with x={:25s}, ' 'x={:25s}'.format(n_x, n_y)) if not x != y: counter.fail('failed x != y with x={:25s}, x={:25s}' ''.format(n_x, n_y))
[docs] def element_space(self): """Verify `LinearSpaceElement.space`.""" with fail_counter( test_name='Verify `LinearSpaceElement.space`', logger=self.log ) as counter: for [n_x, x] in samples(self.space): if x.space != self.space: counter.fail('failed with x={:25s}'.format(n_x))
[docs] def element(self): """Verify `LinearSpaceElement`.""" self.log('\n== Verifying element attributes ==\n') self.element_assign() self.element_copy() self.element_set_zero() self.element_equals() self.element_space()
[docs] def run_tests(self): """Run all tests on this space.""" self.log('\n== RUNNING ALL TESTS ==\n') self.log('Space = {}'.format(self.space)) self.field() self.element_method() self.linearity() self.inner() self.norm() self.dist() self.multiply() self.equals() self.contains() self.element()
def __str__(self): """Return ``str(self)``.""" return '{}({})'.format(self.__class__.__name__, self.space) def __repr__(self): """Return ``repr(self)``.""" inner_str = '{!r}'.format(self.space) if not self.verbose: inner_str += ', verbose=False' if self.tol != 1e-5: inner_str += ', tol={}'.format(self.tol) return '{}({})'.format(self.__class__.__name__, inner_str)
if __name__ == '__main__': from odl import rn, uniform_discr SpaceTest(rn(10), verbose=False).run_tests() SpaceTest(uniform_discr([0, 0], [1, 1], [5, 5])).run_tests()