def _vector_space(self): print('\nVector.space') with FailCounter() as counter: for [n_x, x] in samples(self.space): if not x.space == self.space: counter.fail('failed with x={:25s}'.format(n_x))
def norm(self): """Estimate the operator norm of the operator. The norm is estimated by calculating ``A(x).norm() / x.norm()`` for some nonzero ``x`` Returns ------- norm : `float` Estimate of operator norm References ---------- Wikipedia article on `Operator norm <https://en.wikipedia.org/wiki/Operator_norm>`_. """ print('\n== Calculating operator norm ==\n') operator_norm = 0.0 for [n_x, x] in samples(self.operator.domain): result = self.operator(x) x_norm = x.norm() estimate = 0 if x_norm == 0 else result.norm() / x_norm operator_norm = max(operator_norm, estimate) print('Norm is at least: {}'.format(operator_norm)) self.operator_norm = operator_norm return operator_norm
def vector_equals(self): """Verify `LinearSpaceVector.__eq__`.""" print('\nVector.__eq__()') try: zero = self.space.zero() zero == zero except NotImplementedError: print('Vector has no __eq__') return with FailCounter() 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))
def _derivative_convergence(self): name = 'Testing derivative is linear approximation' with FailCounter(name, "Error = " "inf_c ||A(x+c*p)-A(x)-A'(x)(c*p)|| / c") as counter: for [name_x, x], [name_dx, dx] in samples(self.operator.domain, self.operator.domain): # Precompute some values deriv = self.operator.derivative(x) derivdx = deriv(dx) opx = self.operator(x) c = 1e-4 # initial step derivative_ok = False minerror = float('inf') while c > 1e-14: exact_step = self.operator(x + dx * c) - opx expected_step = c * derivdx err = (exact_step - expected_step).norm() / c if err < 1e-4: derivative_ok = True break else: minerror = min(minerror, err) c /= 10.0 if not derivative_ok: counter.fail('x={:15s} p={:15s}, error={}' ''.format(name_x, name_dx, minerror))
def self_adjoint(self): """Verify (Ax, y) = (x, Ay).""" name = 'Verifying the identity (Ax, y) = (x, Ay)' left_inner_vals = [] right_inner_vals = [] with FailCounter(name, 'error = ||(Ax, y) - (x, Ay)|| / ' '||A|| ||x|| ||y||') as counter: for [name_x, x], [name_y, y] in samples(self.operator.domain, self.operator.range): x_norm = x.norm() y_norm = y.norm() l_inner = self.operator(x).inner(y) r_inner = x.inner(self.operator(y)) denom = self.operator_norm * x_norm * y_norm error = 0 if denom == 0 else abs(l_inner - r_inner) / denom if error > 0.00001: counter.fail('x={:25s} y={:25s} : error={:6.5f}' ''.format(name_x, name_y, error)) left_inner_vals.append(l_inner) right_inner_vals.append(r_inner) scale = np.polyfit(left_inner_vals, right_inner_vals, 1)[0] print('\nThe adjoint seems to be scaled according to:') print('(x, Ay) / (Ax, y) = {}. Should be 1.0'.format(scale))
def _adjoint_definition(self): """Verify (Ax, y) = (x, A^T y)""" print('\nVerifying the identity (Ax, y) = (x, A^T y)') Axy_vals = [] xAty_vals = [] with FailCounter('error = ||(Ax, y) - (x, A^T y)|| / ' '||A|| ||x|| ||y||') as counter: for [n_x, x], [n_y, y] in samples(self.operator.domain, self.operator.range): x_norm = x.norm() y_norm = y.norm() Axy = self.operator(x).inner(y) xAty = x.inner(self.operator.adjoint(y)) denom = self.operator_norm * x_norm * y_norm error = 0 if denom == 0 else abs(Axy - xAty) / denom if error > 0.00001: counter.fail('x={:25s} y={:25s} : error={:6.5f}' ''.format(n_x, n_y, error)) Axy_vals.append(Axy) xAty_vals.append(xAty) scale = np.polyfit(Axy_vals, xAty_vals, 1)[0] print('\nThe adjoint seems to be scaled according to:') print('(x, A^T y) / (Ax, y) = {}. Should be 1.0'.format(scale))
def _identity_of_mult(self): print('\nIdentity element of multiplication, 1 * x = x') with FailCounter() as counter: for [n_x, x] in samples(self.space): ok = _apprimately_equal(1 * x, x, self.eps) if not ok: counter.fail('failed with x={:25s}'.format(n_x))
def vector_space(self): """Verify `LinearSpaceVector.space`.""" print('\nVector.space') with FailCounter() as counter: for [n_x, x] in samples(self.space): if not x.space == self.space: counter.fail('failed with x={:25s}'.format(n_x))
def element_space(self): """Verify `LinearSpaceElement.space`.""" with FailCounter( 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))
def _identity_of_mult(self): """Check multiplicative neutral element ('one').""" print('\nIdentity element of multiplication, 1 * x = x') with FailCounter() as counter: for [n_x, x] in samples(self.space): correct = _approx_equal(1 * x, x, self.eps) if not correct: counter.fail('failed with x={:25s}'.format(n_x))
def _inverse_element_of_addition(self): print('\nInverse element of addition, x + (-x) = 0') zero = self.space.zero() with FailCounter() as counter: for [n_x, x] in samples(self.space): ok = _apprimately_equal(x + (-x), zero, self.eps) if not ok: counter.fail('failed with x={:25s}'.format(n_x))
def _inverse_element_of_addition(self): """Check additional inverse.""" print('\nInverse element of addition, x + (-x) = 0') zero = self.space.zero() with FailCounter() as counter: for [n_x, x] in samples(self.space): correct = _approx_equal(x + (-x), zero, self.eps) if not correct: counter.fail('failed with x={:25s}'.format(n_x))
def _commutativity_of_addition(self): print('\nCommutativity of addition, x + y = y + x') with FailCounter() as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): ok = _apprimately_equal(x + y, y + x, self.eps) if not ok: counter.fail('failed with x={:25s} y={:25s}' ''.format(n_x, n_y))
def _inner_conjugate_symmetry(self): print('\nConjugate symmetry, (x, y) = (y, x).conj()') with FailCounter('error = |(x, y) - (y, x).conj()|') 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.eps: counter.fail('x={:25s}, y={:25s}: error={}' ''.format(n_x, n_y, error))
def _norm_homogeneity(self): print('\nHomogeneity, ||a*x|| = |a| ||x||') with FailCounter('error = abs(||a*x|| - |a| ||x||)') as counter: for [name, vec], scalar in samples(self.space, self.space.field): error = abs((scalar * vec).norm() - abs(scalar) * vec.norm()) if error > self.eps: counter.fail('x={:25s} a={}: ||x||={}' ''.format(name, scalar, error))
def _division(self): print('\nDivision, x / a = x * (1/a)') with FailCounter() as counter: for [n_x, x], a in samples(self.space, self.space.field): if a != 0: ok = _apprimately_equal(x / a, x * (1.0 / a), self.eps) if not ok: counter.fail('failed with x={:25s}, a={}' ''.format(n_x, a))
def _multiply_associative(self): print('\nMultiplication associative, x * (y * z) = (x * y) * z') with FailCounter() as counter: for [n_x, x], [n_y, y], [n_z, z] in samples(self.space, self.space, self.space): ok = _apprimately_equal(x * (y * z), (x * y) * z, self.eps) if not ok: counter.fail('failed with x={:25s} y={:25s} z={:25s}' ''.format(n_x, n_y, n_z))
def _multiply_commutative(self): print('\nMultiplication commutative, x * y = y * x') with FailCounter() as counter: for [n_x, x], [n_y, y], [n_z, z] in samples(self.space, self.space, self.space): ok = _apprimately_equal(x * y, y * x, self.eps) if not ok: counter.fail('failed with x={:25s} y={:25s}' ''.format(n_x, n_y))
def _commutativity_of_addition(self): """Check addition commutativity.""" print('\nCommutativity of addition, x + y = y + x') with FailCounter() as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): correct = _approx_equal(x + y, y + x, self.eps) if not correct: counter.fail('failed with x={:25s} y={:25s}' ''.format(n_x, n_y))
def _subtraction(self): print('\nSubtraction, x - y = x + (-1 * y)') with FailCounter() as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): ok = (_apprimately_equal(x - y, x + (-1 * y), self.eps) and _apprimately_equal(x - y, x + (-y), self.eps)) if not ok: counter.fail('failed with x={:25s}, y={:25s}' ''.format(n_x, n_y))
def _vector_assign(self): print('\nVector.assign()') with FailCounter() as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): x.assign(y) ok = _apprimately_equal(x, y, self.eps) if not ok: counter.fail('failed with x={:25s} y={:25s}' ''.format(n_x, n_y))
def _vector_set_zero(self): print('\nVector.set_zero()') zero = self.space.zero() with FailCounter() as counter: for [n_x, x] in samples(self.space): x.set_zero() ok = _apprimately_equal(x, zero, self.eps) if not ok: counter.fail('failed with x={:25s}' ''.format(n_x))
def _inner_linear_scalar(self): print('\nLinearity scalar, (a*x, y) = a*(x, y)') with FailCounter('error = |(a*x, y) - a*(x, y)|') 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.eps: counter.fail('x={:25s}, y={:25s}, a={}: error={}' ''.format(n_x, n_y, a, error))
def _identity_of_mult(self): """Verify multiplicative neutral element ('one').""" with FailCounter( 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 _inner_linear_sum(self): print('\nLinearity sum, (x+y, z) = (x, z) + (y, z)') with FailCounter('error = |(x+y, z) - ((x, z)+(y, z))|') 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.eps: counter.fail('x={:25s}, y={:25s}, z={:25s}: error={}' ''.format(n_x, n_y, n_z, error))
def _multiply_zero(self): print('\nMultiplication by zero, x * 0 = 0') zero = self.space.zero() with FailCounter('error = ||x*0||') as counter: for [n_x, x] in samples(self.space): error = (zero * x).norm() if error > self.eps: counter.fail('x={:25s},: error={}' ''.format(n_x, error))
def _multiply_distributive_scalar(self): print('\nMultiplication distributive wrt scal, a * (x + y) = ' 'a * x + a * y') with FailCounter() as counter: for [n_x, x], [n_y, y], a in samples(self.space, self.space, self.space.field): ok = _apprimately_equal(a * (x + y), a * x + a * y, self.eps) if not ok: counter.fail('failed with x={:25s} y={:25s} a={}' ''.format(n_x, n_y, a))
def _multiply_distributive_vec(self): print('\nMultiplication distributive wrt vec, x * (y + z) = ' 'x * y + x * z') with FailCounter() as counter: for [n_x, x], [n_y, y], [n_z, z] in samples(self.space, self.space, self.space): ok = _apprimately_equal(x * (y + z), x * y + x * z, self.eps) if not ok: counter.fail('failed with x={:25s} y={:25s} z={:25s}' ''.format(n_x, n_y, n_z))
def _distributivity_of_mult_scalar(self): print('\nDistributivity of multiplication wrt scalar add, ' '(a + b) * x = a * x + b * x') with FailCounter() as counter: for [n_x, x], a, b in samples(self.space, self.space.field, self.space.field): ok = _apprimately_equal((a + b) * x, a * x + b * x, self.eps) if not ok: counter.fail('failed with x={:25s}, a={}, b={}' ''.format(n_x, a, b))
def _distributivity_of_mult_vector(self): print('\nDistributivity of multiplication wrt vector add, ' 'a * (x + y) = a * x + a * y') with FailCounter() as counter: for [n_x, x], [n_y, y], a in samples(self.space, self.space, self.space.field): ok = _apprimately_equal(a * (x + y), a * x + a * y, self.eps) if not ok: counter.fail('failed with x={:25s}, y={:25s}, a={}' ''.format(n_x, n_y, a))
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 _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_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 _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 _commutativity_of_scalar_mult(self): """Verify scalar multiplication commutativity.""" with FailCounter( 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 _norm_subadditive(self): """Check subadditivity of the norm.""" name = 'Sub-additivity, ||x+y|| <= ||x|| + ||y||' with FailCounter(name, 'error = ||x+y|| - ||x|| + ||y||') 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 _dist_positivity(self): """Verify nonnegativity of the distance.""" with FailCounter(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 _norm_positive(self): """Check nonnegativity of the norm.""" name = 'Positivity, ||x|| >= 0' with FailCounter(name) 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 _distributivity_of_mult_scalar(self): """Verify scalar multiplication distributivity wrt scalar addition.""" with FailCounter( 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 _inner_linear_sum(self): """Verify distributivity of the inner product in the first argument.""" with FailCounter( 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 _multiply_distributive_vector(self): """Verify distributivity of vector multiplication.""" with FailCounter( 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))
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 FailCounter(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 _norm_subadditive(self): """Verify subadditivity of the norm.""" with FailCounter(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 _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 FailCounter(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 _norm_positive(self): """Verify positive definiteness of the norm.""" with FailCounter( 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 _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 element_set_zero(self): """Verify `LinearSpaceElement.set_zero`.""" try: zero = self.space.zero() except NotImplementedError: print('*** SPACE HAS NO ZERO VECTOR ***') return with FailCounter( 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))
def _norm_inner_compatible(self): """Check compatibility of norm and inner product.""" name = 'Inner compatibility, ||x||^2 = (x, x)' try: zero = self.space.zero() zero.inner(zero) except NotImplementedError: print('Space is not a inner product space') return with FailCounter(name, 'error = | ||x||^2 = (x, x) |') as counter: for [n_x, x] in samples(self.space): error = abs(x.norm()**2 - x.inner(x)) if error > self.eps: counter.fail('x={:25s}: error={}' ''.format(n_x, error))
def _dist_norm_compatible(self): """Check compatibility of distance and norm.""" name = 'Norm compatibility, d(x, y) = ||x-y||' try: self.space.zero().norm() except NotImplementedError: print('Space is not normed') return with FailCounter(name, 'error = |d(x, y) - ||x-y|| |') 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.eps: counter.fail('x={:25s}, y={:25s}: error={}' ''.format(n_x, n_y, error))
def _dist_subadditive(self): """Check subadditivity of the distance.""" name = 'Sub-additivity, d(x, y) = d(y, x)' with FailCounter(name, 'error = d(x,z) - (d(x, y) + d(y, z))') 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.eps: counter.fail('x={:25s}, y={:25s}, z={:25s}: error={}' ''.format(n_x, n_y, n_z, error))
def _dist_subtransitive(self): """Verify sub-transitivity of the distance.""" with FailCounter( 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 _inner_positive(self): """Check positive definiteness of the inner product.""" name = 'Positivity, (x, x) >= 0' with FailCounter(name) as counter: for [n_x, x] in samples(self.space): inner = x.inner(x) if abs(inner.imag) > self.eps: counter.fail('(x, x).imag != 0, x={:25s}' ''.format(n_x)) 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))
def _scale_invariance(self): """Verify ``A(c*x) = c * A(x)``.""" with FailCounter( test_name='Verifying homogeneity under scalar multiplication', err_msg='error = ||A(c*x)-c*A(x)|| / |c| ||A|| ||x||', logger=self.log) as counter: for [name_x, x], [_, scale] in samples(self.operator.domain, self.operator.domain.field): opx = self.operator(x) scaled_opx = self.operator(scale * x) denom = self.operator_norm * scale * x.norm() error = (0 if denom == 0 else (scaled_opx - opx * scale).norm() / denom) if error > self.tol: counter.fail('x={:25s} scale={:7.2f} error={:6.5f}' ''.format(name_x, scale, error))
def _scale_invariance(self): name = "Calculating invariance under scaling" # Test scaling with FailCounter(name, 'error = ||A(c*x)-c*A(x)|| / ' '|c| ||A|| ||x||') as counter: for [name_x, x], [_, scale] in samples(self.operator.domain, self.operator.domain.field): opx = self.operator(x) scaled_opx = self.operator(scale * x) denom = self.operator_norm * scale * x.norm() error = (0 if denom == 0 else (scaled_opx - opx * scale).norm() / denom) if error > 0.00001: counter.fail('x={:25s} scale={:7.2f} error={:6.5f}' ''.format(name_x, scale, error))
def _derivative_convergence(self): """Verify that the derivative is a first-order approximation. The code verifies if ``||A(x+c*p) - A(x) - A'(x)(c*p)|| / c = o(c)`` for ``c --> 0``. """ with FailCounter( test_name='Verifying that derivative is a first-order ' 'approximation', err_msg="error = inf_c ||A(x+c*p)-A(x)-A'(x)(c*p)|| / c", logger=self.log) as counter: for [name_x, x], [name_dx, dx] in samples(self.operator.domain, self.operator.domain): # Precompute some values deriv = self.operator.derivative(x) derivdx = deriv(dx) opx = self.operator(x) c = 1e-4 # initial step derivative_ok = False minerror = float('inf') while c > 1e-14: exact_step = self.operator(x + dx * c) - opx expected_step = c * derivdx err = (exact_step - expected_step).norm() / c # Need to be slightly more generous here due to possible # numerical instabilities. # TODO: perform more tests to find a good threshold here. if err < 10 * self.tol: derivative_ok = True break else: minerror = min(minerror, err) c /= 10.0 if not derivative_ok: counter.fail('x={:15s} p={:15s}, error={}' ''.format(name_x, name_dx, minerror))
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 FailCounter( 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))
def contains(self): """Verify `LinearSpace.__contains__`.""" with FailCounter(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))
def element_copy(self): """Verify `LinearSpaceElement.copy`.""" with FailCounter( 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))
def vector_copy(self): """Verify `LinearSpaceVector.copy`.""" name = 'Vector.copy()' with FailCounter(name) as counter: for [n_x, x] in samples(self.space): # equal after copy y = x.copy() correct = _approx_equal(x, y, self.eps) 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.eps) if not correct: counter.fail('modified y, x changed with x={:25s}' ''.format(n_x))
def _addition_invariance(self): name = "Calculating invariance under addition" # Test addition with FailCounter(name, 'error = ||A(x+y) - A(x) - A(y)|| / ' '||A||(||x|| + ||y||)') as counter: for [name_x, x], [name_y, y] in samples(self.operator.domain, self.operator.domain): opx = self.operator(x) opy = self.operator(y) opxy = self.operator(x + y) denom = self.operator_norm * (x.norm() + y.norm()) error = (0 if denom == 0 else (opxy - opx - opy).norm() / denom) if error > 0.00001: counter.fail('x={:25s} y={:25s} error={:6.5f}' ''.format(name_x, name_y, error))