def equals(self): """Verify `LinearSpace.__eq__`.""" print('\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 FailCounter('Space equal to non-space') 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))
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_of_adjoint(self): """Verify ``(A^*)^* == A``""" try: self.operator.adjoint.adjoint except AttributeError: print('A^* has no adjoint') return if self.operator.adjoint.adjoint is self.operator: self.log('(A^*)^* == A') return with FailCounter( test_name='\nVerifying the identity Ax = (A^*)^* x', err_msg='error = ||Ax - (A^*)^* x|| / ||A|| ||x||', logger=self.log) as counter: for [name_x, x] in self.operator.domain.examples: opx = self.operator(x) op_adj_adj_x = self.operator.adjoint.adjoint(x) denom = self.operator_norm * x.norm() if denom == 0: error = 0 else: error = (opx - op_adj_adj_x).norm() / denom if error > self.tol: counter.fail('x={:25s} : error={:6.5f}' ''.format(name_x, error))
def _adjoint_of_adjoint(self): """Verify (A^*)^* = A""" try: self.operator.adjoint.adjoint except AttributeError: print('A^* has no adjoint') return if self.operator.adjoint.adjoint is self.operator: print('(A^*)^* == A') return name = '\nVerifying the identity Ax = (A^T)^T x' with FailCounter(name, 'error = ||Ax - (A^T)^T x|| /' '||A|| ||x||') as counter: for [name_x, x] in self.operator.domain.examples: opx = self.operator(x) op_adj_adj_x = self.operator.adjoint.adjoint(x) denom = self.operator_norm * x.norm() if denom == 0: error = 0 else: error = (opx - op_adj_adj_x).norm() / denom if error > 0.00001: counter.fail('x={:25s} : error={:6.5f}' ''.format(name_x, error))
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 FailCounter(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))
def _adjoint_definition(self): """Verify ``<Ax, y> == <x, A^* y>``.""" left_inner_vals = [] right_inner_vals = [] with FailCounter( test_name='Verifying the identity <Ax, y> = <x, A^T y>', err_msg='error = |<Ax, y< - <x, A^* y>| / ||A|| ||x|| ||y||', logger=self.log) 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.adjoint(y)) denom = self.operator_norm * x_norm * y_norm error = 0 if denom == 0 else abs(l_inner - r_inner) / denom if error > self.tol: 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] self.log('\nThe adjoint seems to be scaled according to:') self.log('(x, A^T y) / (Ax, y) = {}. Should be 1.0'.format(scale))
def vector_equals(self): """Verify `LinearSpaceVector.__eq__`.""" name = 'Vector.__eq__()' try: zero = self.space.zero() zero == zero except NotImplementedError: print('Vector has no __eq__') return with FailCounter(name) 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 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 FailCounter( 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))
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 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 vector_space(self): """Verify `LinearSpaceVector.space`.""" name = 'Vector.space' with FailCounter(name) 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').""" name = 'Identity element of multiplication, 1 * x = x' with FailCounter(name) 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): """Check additional inverse.""" name = 'Inverse element of addition, x + (-x) = 0' zero = self.space.zero() with FailCounter(name) 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 _inner_conjugate_symmetry(self): """Check conjugate symmetry of the inner product.""" name = 'Conjugate symmetry, (x, y) = (y, x).conj()' with FailCounter(name, '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 _commutativity_of_addition(self): """Check addition commutativity.""" name = 'Commutativity of addition, x + y = y + x' with FailCounter(name) 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 _norm_homogeneity(self): """Check positive homogeneity of the norm.""" name = 'Homogeneity, ||a*x|| = |a| ||x||' with FailCounter(name, 'error = abs(||a*x|| - |a| ||x||)') as counter: for [name, vec], [_, a] in samples(self.space, self.space.field): error = abs((a * vec).norm() - abs(a) * vec.norm()) if error > self.eps: counter.fail('x={:25s} a={}: ||x||={}' ''.format(name, 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 _subtraction(self): """Check subtraction as addition of additive inverse.""" name = 'Subtraction, x - y = x + (-1 * y)' with FailCounter(name) as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): correct = (_approx_equal(x - y, x + (-1 * y), self.eps) and _approx_equal(x - y, x + (-y), self.eps)) if not correct: counter.fail('failed with x={:25s}, y={:25s}' ''.format(n_x, n_y))
def _division(self): """Check scalar division as multiplication with mult. inverse.""" name = 'Division, x / a = x * (1/a)' with FailCounter(name) 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.eps) if not correct: counter.fail('failed with x={:25s}, a={}' ''.format(n_x, a))
def _inner_linear_scalar(self): """Check homogeneity of the inner product in the first argument.""" name = 'Linearity scalar, (a*x, y) = a*(x, y)' with FailCounter(name, '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 _multiply_commutative(self): """Check commutativity of vector multiplication.""" name = 'Multiplication commutative, x * y = y * x' with FailCounter(name) 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.eps) if not correct: counter.fail('failed with x={:25s} y={:25s}' ''.format(n_x, n_y))
def _commutativity_of_addition(self): """Verify addition commutativity.""" with FailCounter(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 vector_assign(self): """Verify `LinearSpaceVector.assign`.""" name = 'Vector.assign()' with FailCounter(name) as counter: for [n_x, x], [n_y, y] in samples(self.space, self.space): x.assign(y) correct = _approx_equal(x, y, self.eps) if not correct: counter.fail('failed with x={:25s} y={:25s}' ''.format(n_x, n_y))
def _multiply_associative(self): """Check associativity of vector multiplication.""" name = 'Multiplication associative, x * (y * z) = (x * y) * z' with FailCounter(name) 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.eps) if not correct: counter.fail('failed with x={:25s} y={:25s} z={:25s}' ''.format(n_x, n_y, n_z))
def _multiply_zero(self): """Check vector multiplication with zero is zero.""" name = 'Multiplication by zero, x * 0 = 0' zero = self.space.zero() with FailCounter(name, '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): """Check distributivity of scalar multiplication.""" name = ('Multiplication distributive wrt scal, a * (x + y) = ' 'a * x + a * y') with FailCounter(name) 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.eps) if not correct: counter.fail('failed with x={:25s} y={:25s} a={}' ''.format(n_x, n_y, a))
def vector_set_zero(self): """Verify `LinearSpaceVector.set_zero`.""" name = 'Vector.set_zero()' zero = self.space.zero() with FailCounter(name) as counter: for [n_x, x] in samples(self.space): x.set_zero() correct = _approx_equal(x, zero, self.eps) if not correct: counter.fail('failed with x={:25s}' ''.format(n_x))
def _inner_conjugate_symmetry(self): """Verify conjugate symmetry of the inner product.""" with FailCounter( 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 element_method(self): """Verify `LinearSpace.element`.""" with FailCounter(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 ***')
def _norm_homogeneity(self): """Verify positive homogeneity of the norm.""" with FailCounter( 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))