def test_is_non_singular_auto_set(self): # Matrix with two positive eigenvalues, 11 and 8. # The matrix values do not effect auto-setting of the flags. matrix = [[11., 0.], [1., 8.]] operator_1 = linalg.LinearOperatorFullMatrix(matrix, is_non_singular=True) operator_2 = linalg.LinearOperatorFullMatrix(matrix, is_non_singular=True) operator_3 = linalg.LinearOperatorFullMatrix(matrix, is_non_singular=True) operator = block_lower_triangular.LinearOperatorBlockLowerTriangular( [[operator_1], [operator_2, operator_3]], is_positive_definite=False, # No reason it HAS to be False... is_non_singular=None) self.assertFalse(operator.is_positive_definite) self.assertTrue(operator.is_non_singular) with self.assertRaisesRegex(ValueError, "always non-singular"): block_lower_triangular.LinearOperatorBlockLowerTriangular( [[operator_1], [operator_2, operator_3]], is_non_singular=False) operator_4 = linalg.LinearOperatorFullMatrix([[1., 0.], [2., 0.]], is_non_singular=False) # A singular operator off of the main diagonal shouldn't raise block_lower_triangular.LinearOperatorBlockLowerTriangular( [[operator_1], [operator_4, operator_2]], is_non_singular=True) with self.assertRaisesRegex(ValueError, "always singular"): block_lower_triangular.LinearOperatorBlockLowerTriangular( [[operator_1], [operator_2, operator_4]], is_non_singular=True)
def test_tape_safe(self): operator_1 = linalg.LinearOperatorFullMatrix(variables_module.Variable( [[1., 0.], [0., 1.]]), is_self_adjoint=True, is_positive_definite=True) operator_2 = linalg.LinearOperatorFullMatrix( variables_module.Variable([[2., 0.], [1., 0.]])) operator_3 = linalg.LinearOperatorFullMatrix(variables_module.Variable( [[3., 1.], [1., 3.]]), is_self_adjoint=True, is_positive_definite=True) operator = block_lower_triangular.LinearOperatorBlockLowerTriangular( [[operator_1], [operator_2, operator_3]], is_self_adjoint=False, is_positive_definite=True) diagonal_grads_only = [ "diag_part", "trace", "determinant", "log_abs_determinant" ] self.check_tape_safe(operator, skip_options=diagonal_grads_only) for y in diagonal_grads_only: for diag_block in [operator_1, operator_3]: with backprop.GradientTape() as tape: grads = tape.gradient( getattr(operator, y)(), diag_block.variables) for item in grads: self.assertIsNotNone(item)
def test_operators_wrong_length_raises(self): with self.assertRaisesRegex(ValueError, "must contain `2` blocks"): block_lower_triangular.LinearOperatorBlockLowerTriangular( [[linalg.LinearOperatorFullMatrix(rng.rand(2, 2))], [ linalg.LinearOperatorFullMatrix(rng.rand(2, 2)) for _ in range(3) ]])
def test_operators_mismatched_dimension_raises(self): operators = [ [linalg.LinearOperatorFullMatrix(rng.rand(3, 3))], [linalg.LinearOperatorFullMatrix(rng.rand(3, 4)), linalg.LinearOperatorFullMatrix(rng.rand(3, 3))] ] with self.assertRaisesRegexp(ValueError, "must be equal"): block_lower_triangular.LinearOperatorBlockLowerTriangular(operators)
def test_non_square_operator_raises(self): operators = [ [linalg.LinearOperatorFullMatrix(rng.rand(3, 4), is_square=False)], [linalg.LinearOperatorFullMatrix(rng.rand(4, 4)), linalg.LinearOperatorFullMatrix(rng.rand(4, 4))] ] with self.assertRaisesRegexp(ValueError, "must be square"): block_lower_triangular.LinearOperatorBlockLowerTriangular(operators)
def test_different_dtypes_raises(self): operators = [ [linalg.LinearOperatorFullMatrix(rng.rand(2, 3, 3))], [linalg.LinearOperatorFullMatrix(rng.rand(2, 3, 3)), linalg.LinearOperatorFullMatrix(rng.rand(2, 3, 3).astype(np.float32))] ] with self.assertRaisesRegexp(TypeError, "same dtype"): block_lower_triangular.LinearOperatorBlockLowerTriangular(operators)
def test_is_x_flags(self): # Matrix with two positive eigenvalues, 1, and 1. # The matrix values do not effect auto-setting of the flags. matrix = [[1., 0.], [1., 1.]] operator = block_lower_triangular.LinearOperatorBlockLowerTriangular( [[linalg.LinearOperatorFullMatrix(matrix)]], is_positive_definite=True, is_non_singular=True, is_self_adjoint=False) self.assertTrue(operator.is_positive_definite) self.assertTrue(operator.is_non_singular) self.assertFalse(operator.is_self_adjoint)
def operator_and_matrix( self, shape_info, dtype, use_placeholder, ensure_self_adjoint_and_pd=False): expected_blocks = ( shape_info.__dict__["blocks"] if "blocks" in shape_info.__dict__ else [[list(shape_info.shape)]]) matrices = [] for i, row_shapes in enumerate(expected_blocks): row = [] for j, block_shape in enumerate(row_shapes): if i == j: # operator is on the diagonal row.append( linear_operator_test_util.random_positive_definite_matrix( block_shape, dtype, force_well_conditioned=True)) else: row.append( linear_operator_test_util.random_normal(block_shape, dtype=dtype)) matrices.append(row) lin_op_matrices = matrices if use_placeholder: lin_op_matrices = [[ array_ops.placeholder_with_default( matrix, shape=None) for matrix in row] for row in matrices] operator = block_lower_triangular.LinearOperatorBlockLowerTriangular( [[linalg.LinearOperatorFullMatrix( # pylint:disable=g-complex-comprehension l, is_square=True, is_self_adjoint=True if ensure_self_adjoint_and_pd else None, is_positive_definite=True if ensure_self_adjoint_and_pd else None) for l in row] for row in lin_op_matrices]) # Should be auto-set. self.assertTrue(operator.is_square) # Broadcast the shapes. expected_shape = list(shape_info.shape) broadcasted_matrices = linear_operator_util.broadcast_matrix_batch_dims( [op for row in matrices for op in row]) # pylint: disable=g-complex-comprehension matrices = [broadcasted_matrices[i * (i + 1) // 2:(i + 1) * (i + 2) // 2] for i in range(len(matrices))] block_lower_triangular_dense = _block_lower_triangular_dense( expected_shape, matrices) if not use_placeholder: block_lower_triangular_dense.set_shape(expected_shape) return operator, block_lower_triangular_dense
def test_block_lower_triangular_inverse_type(self): matrix = [[1., 0.], [0., 1.]] operator = block_lower_triangular.LinearOperatorBlockLowerTriangular( [[linalg.LinearOperatorFullMatrix(matrix, is_non_singular=True)], [linalg.LinearOperatorFullMatrix(matrix, is_non_singular=True), linalg.LinearOperatorFullMatrix(matrix, is_non_singular=True)]], is_non_singular=True, ) inverse = operator.inverse() self.assertIsInstance( inverse, block_lower_triangular.LinearOperatorBlockLowerTriangular) self.assertEqual(2, len(inverse.operators)) self.assertEqual(1, len(inverse.operators[0])) self.assertEqual(2, len(inverse.operators[1]))
def test_convert_variables_to_tensors(self): operator_1 = linalg.LinearOperatorFullMatrix(variables_module.Variable( [[1., 0.], [0., 1.]]), is_self_adjoint=True, is_positive_definite=True) operator_2 = linalg.LinearOperatorFullMatrix( variables_module.Variable([[2., 0.], [1., 0.]])) operator_3 = linalg.LinearOperatorFullMatrix(variables_module.Variable( [[3., 1.], [1., 3.]]), is_self_adjoint=True, is_positive_definite=True) operator = block_lower_triangular.LinearOperatorBlockLowerTriangular( [[operator_1], [operator_2, operator_3]], is_self_adjoint=False, is_positive_definite=True) with self.cached_session() as sess: sess.run([x.initializer for x in operator.variables]) self.check_convert_variables_to_tensors(operator)
def test_incompatible_input_blocks_raises(self): matrix_1 = array_ops.placeholder_with_default(rng.rand(4, 4), shape=None) matrix_2 = array_ops.placeholder_with_default(rng.rand(3, 4), shape=None) matrix_3 = array_ops.placeholder_with_default(rng.rand(3, 3), shape=None) operators = [[ linalg.LinearOperatorFullMatrix(matrix_1, is_square=True) ], [ linalg.LinearOperatorFullMatrix(matrix_2), linalg.LinearOperatorFullMatrix(matrix_3, is_square=True) ]] operator = block_lower_triangular.LinearOperatorBlockLowerTriangular( operators) x = np.random.rand(2, 4, 5).tolist() msg = ("dimension does not match" if context.executing_eagerly() else "input structure is ambiguous") with self.assertRaisesRegex(ValueError, msg): operator.matmul(x)
def test_empty_operators_raises(self): with self.assertRaisesRegex(ValueError, "must be a list of >=1"): block_lower_triangular.LinearOperatorBlockLowerTriangular([])
def test_empty_operators_raises(self): with self.assertRaisesRegexp(ValueError, "non-empty"): block_lower_triangular.LinearOperatorBlockLowerTriangular([])