def operator_and_matrix( self, build_info, dtype, use_placeholder, ensure_self_adjoint_and_pd=False): del ensure_self_adjoint_and_pd shape = list(build_info.shape) # Create 2 matrices/operators, A1, A2, which becomes A = A1 A2. # Use inner dimension of 2. k = 2 batch_shape = shape[:-2] shape_1 = batch_shape + [shape[-2], k] shape_2 = batch_shape + [k, shape[-1]] matrices = [ linear_operator_test_util.random_normal( shape_1, dtype=dtype), linear_operator_test_util.random_normal( shape_2, dtype=dtype) ] lin_op_matrices = matrices if use_placeholder: lin_op_matrices = [ array_ops.placeholder_with_default( matrix, shape=None) for matrix in matrices] operator = linalg.LinearOperatorComposition( [linalg.LinearOperatorFullMatrix(l) for l in lin_op_matrices]) matmul_order_list = list(reversed(matrices)) mat = matmul_order_list[0] for other_mat in matmul_order_list[1:]: mat = math_ops.matmul(other_mat, mat) return operator, mat
def test_block_diag_matmul_type(self): matrices1 = [] matrices2 = [] for i in range(1, 5): matrices1.append( linalg.LinearOperatorFullMatrix( linear_operator_test_util.random_normal( [2, i], dtype=dtypes.float32))) matrices2.append( linalg.LinearOperatorFullMatrix( linear_operator_test_util.random_normal( [i, 3], dtype=dtypes.float32))) operator1 = block_diag.LinearOperatorBlockDiag(matrices1, is_square=False) operator2 = block_diag.LinearOperatorBlockDiag(matrices2, is_square=False) expected_matrix = math_ops.matmul(operator1.to_dense(), operator2.to_dense()) actual_operator = operator1.matmul(operator2) self.assertIsInstance(actual_operator, block_diag.LinearOperatorBlockDiag) actual_, expected_ = self.evaluate( [actual_operator.to_dense(), expected_matrix]) self.assertAllClose(actual_, expected_)
def test_block_diag_solve_raises(self): matrices1 = [] for i in range(1, 5): matrices1.append(linalg.LinearOperatorFullMatrix( linear_operator_test_util.random_normal( [i, i], dtype=dtypes.float32))) operator1 = block_diag.LinearOperatorBlockDiag(matrices1) operator2 = linalg.LinearOperatorFullMatrix( linear_operator_test_util.random_normal( [15, 3], dtype=dtypes.float32)) with self.assertRaisesRegex(ValueError, "Operators are incompatible"): operator1.solve(operator2)
def _operator_and_mat_and_feed_dict(self, build_info, dtype, use_placeholder): sess = ops.get_default_session() shape = list(build_info.shape) # Test only the case of 2 matrices. # The Square test uses either 1 or 2, so we have tested the case of 1 matrix # sufficiently. num_operators = 2 # Create 2 matrices/operators, A1, A2, which becomes A = A1 A2. # Use inner dimension of 2. k = 2 batch_shape = shape[:-2] shape_1 = batch_shape + [shape[-2], k] shape_2 = batch_shape + [k, shape[-1]] matrices = [ linear_operator_test_util.random_normal(shape_1, dtype=dtype), linear_operator_test_util.random_normal(shape_2, dtype=dtype) ] if use_placeholder: matrices_ph = [ array_ops.placeholder(dtype=dtype) for _ in range(num_operators) ] # Evaluate here because (i) you cannot feed a tensor, and (ii) # values are random and we want the same value used for both mat and # feed_dict. matrices = sess.run(matrices) operator = linalg.LinearOperatorComposition([ linalg.LinearOperatorFullMatrix(m_ph) for m_ph in matrices_ph ]) feed_dict = {m_ph: m for (m_ph, m) in zip(matrices_ph, matrices)} else: operator = linalg.LinearOperatorComposition( [linalg.LinearOperatorFullMatrix(m) for m in matrices]) feed_dict = None # Convert back to Tensor. Needed if use_placeholder, since then we have # already evaluated each matrix to a numpy array. matmul_order_list = list(reversed(matrices)) mat = ops.convert_to_tensor(matmul_order_list[0]) for other_mat in matmul_order_list[1:]: mat = math_ops.matmul(other_mat, mat) return operator, mat, feed_dict
def test_real_spectrum_gives_self_adjoint_operator(self): with self.cached_session(): # This is a real and hermitian spectrum. spectrum = linear_operator_test_util.random_normal( shape=(2, 2, 3, 5), dtype=dtypes.float32) operator = linalg.LinearOperatorCirculant3D(spectrum) self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), operator.shape) self.assertEqual( operator.parameters, { "input_output_dtype": dtypes.complex64, "is_non_singular": None, "is_positive_definite": None, "is_self_adjoint": None, "is_square": True, "name": "LinearOperatorCirculant3D", "spectrum": spectrum, }) matrix_tensor = operator.to_dense() self.assertEqual(matrix_tensor.dtype, dtypes.complex64) matrix_h = linalg.adjoint(matrix_tensor) matrix, matrix_h = self.evaluate([matrix_tensor, matrix_h]) self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), matrix.shape) self.assertAllClose(matrix, matrix_h)
def test_block_diag_solve_type(self): matrices1 = [] matrices2 = [] for i in range(1, 5): matrices1.append( linalg.LinearOperatorFullMatrix( linear_operator_test_util.random_tril_matrix( [i, i], dtype=dtypes.float32, force_well_conditioned=True))) matrices2.append( linalg.LinearOperatorFullMatrix( linear_operator_test_util.random_normal( [i, 3], dtype=dtypes.float32))) operator1 = block_diag.LinearOperatorBlockDiag(matrices1) operator2 = block_diag.LinearOperatorBlockDiag(matrices2, is_square=False) expected_matrix = linalg.solve(operator1.to_dense(), operator2.to_dense()) actual_operator = operator1.solve(operator2) self.assertIsInstance(actual_operator, block_diag.LinearOperatorBlockDiag) actual_, expected_ = self.evaluate( [actual_operator.to_dense(), expected_matrix]) self.assertAllClose(actual_, expected_)
def _operator_and_mat_and_feed_dict(self, shape, dtype, use_placeholder): sess = ops.get_default_session() shape = list(shape) # Test only the case of 2 matrices. # The Square test uses either 1 or 2, so we have tested the case of 1 matrix # sufficiently. num_operators = 2 # Create 2 matrices/operators, A1, A2, which becomes A = A1 A2. # Use inner dimension of 2. k = 2 batch_shape = shape[:-2] shape_1 = batch_shape + [shape[-2], k] shape_2 = batch_shape + [k, shape[-1]] matrices = [ linear_operator_test_util.random_normal( shape_1, dtype=dtype), linear_operator_test_util.random_normal( shape_2, dtype=dtype) ] if use_placeholder: matrices_ph = [ array_ops.placeholder(dtype=dtype) for _ in range(num_operators) ] # Evaluate here because (i) you cannot feed a tensor, and (ii) # values are random and we want the same value used for both mat and # feed_dict. matrices = sess.run(matrices) operator = linalg.LinearOperatorComposition( [linalg.LinearOperatorFullMatrix(m_ph) for m_ph in matrices_ph]) feed_dict = {m_ph: m for (m_ph, m) in zip(matrices_ph, matrices)} else: operator = linalg.LinearOperatorComposition( [linalg.LinearOperatorFullMatrix(m) for m in matrices]) feed_dict = None # Convert back to Tensor. Needed if use_placeholder, since then we have # already evaluated each matrix to a numpy array. matmul_order_list = list(reversed(matrices)) mat = ops.convert_to_tensor(matmul_order_list[0]) for other_mat in matmul_order_list[1:]: mat = math_ops.matmul(other_mat, mat) return operator, mat, feed_dict
def generate_well_conditioned(shape, dtype): m, n = shape[-2], shape[-1] min_dim = min(m, n) # Generate singular values that are close to 1. d = linear_operator_test_util.random_normal(shape[:-2] + [min_dim], mean=1., stddev=0.1, dtype=dtype) zeros = array_ops.zeros(shape=shape[:-2] + [m, n], dtype=dtype) d = linalg_lib.set_diag(zeros, d) u, _ = linalg_lib.qr( linear_operator_test_util.random_normal(shape[:-2] + [m, m], dtype=dtype)) v, _ = linalg_lib.qr( linear_operator_test_util.random_normal(shape[:-2] + [n, n], dtype=dtype)) return math_ops.matmul(u, math_ops.matmul(d, v))
def test_slice_single_param_operator(self): matrix = linear_operator_test_util.random_normal(shape=[1, 4, 3, 2, 2], dtype=dtypes.float32) operator = linalg.LinearOperatorFullMatrix(matrix, is_square=True) sliced = operator[..., array_ops.newaxis, 2:, array_ops.newaxis] self.assertAllEqual( list( array_ops.zeros([1, 4, 3])[..., array_ops.newaxis, 2:, array_ops.newaxis].shape), sliced.batch_shape_tensor())
def test_real_spectrum_gives_self_adjoint_operator(self): with self.cached_session(): # This is a real and hermitian spectrum. spectrum = linear_operator_test_util.random_normal( shape=(3, 3), dtype=dtypes.float32) operator = linalg.LinearOperatorCirculant2D(spectrum) matrix_tensor = operator.to_dense() self.assertEqual(matrix_tensor.dtype, dtypes.complex64) matrix_h = linalg.adjoint(matrix_tensor) matrix, matrix_h = self.evaluate([matrix_tensor, matrix_h]) self.assertAllClose(matrix, matrix_h, atol=0)
def _operator_and_matrix(self, build_info, dtype, use_placeholder): shape = list(build_info.shape) matrix = linear_operator_test_util.random_normal(shape, dtype=dtype) lin_op_matrix = matrix if use_placeholder: lin_op_matrix = array_ops.placeholder_with_default(matrix, shape=None) operator = linalg.LinearOperatorFullMatrix(lin_op_matrix, is_square=True) return operator, matrix
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_real_spectrum_gives_self_adjoint_operator(self): with self.cached_session(): # This is a real and hermitian spectrum. spectrum = linear_operator_test_util.random_normal( shape=(3, 3), dtype=dtypes.float32) operator = linalg.LinearOperatorCirculant2D(spectrum) matrix_tensor = operator.to_dense() self.assertEqual(matrix_tensor.dtype, dtypes.complex64) matrix_h = linalg.adjoint(matrix_tensor) matrix, matrix_h = self.evaluate([matrix_tensor, matrix_h]) self.assertAllClose(matrix, matrix_h, atol=0)
def _operator_and_matrix(self, build_info, dtype, use_placeholder): shape = list(build_info.shape) matrix = linear_operator_test_util.random_normal(shape, dtype=dtype) lin_op_matrix = matrix if use_placeholder: lin_op_matrix = array_ops.placeholder_with_default(matrix, shape=None) operator = linalg.LinearOperatorFullMatrix(lin_op_matrix, is_square=True) return operator, matrix
def test_hermitian_spectrum_gives_operator_with_zero_imag_part(self): with self.cached_session(): # Make spectrum the FFT of a real convolution kernel h. This ensures that # spectrum is Hermitian. h = linear_operator_test_util.random_normal(shape=(3, 4)) spectrum = fft_ops.fft(math_ops.cast(h, dtypes.complex64)) operator = linalg.LinearOperatorCirculant( spectrum, input_output_dtype=dtypes.complex64) matrix = operator.to_dense() imag_matrix = math_ops.imag(matrix) eps = np.finfo(np.float32).eps np.testing.assert_allclose( 0, self.evaluate(imag_matrix), rtol=0, atol=eps * 3 * 4)
def test_hermitian_spectrum_gives_operator_with_zero_imag_part(self): with self.cached_session(): # Make spectrum the FFT of a real convolution kernel h. This ensures that # spectrum is Hermitian. h = linear_operator_test_util.random_normal(shape=(3, 4)) spectrum = fft_ops.fft(math_ops.cast(h, dtypes.complex64)) operator = linalg.LinearOperatorCirculant( spectrum, input_output_dtype=dtypes.complex64) matrix = operator.to_dense() imag_matrix = math_ops.imag(matrix) eps = np.finfo(np.float32).eps np.testing.assert_allclose( 0, self.evaluate(imag_matrix), rtol=0, atol=eps * 3 * 4)
def test_real_spectrum_gives_self_adjoint_operator(self): with self.test_session() as sess: # This is a real and hermitian spectrum. spectrum = linear_operator_test_util.random_normal( shape=(3, 3), dtype=dtypes.float32) operator = linalg.LinearOperatorCirculant2D(spectrum) matrix_tensor = operator.to_dense() self.assertEqual(matrix_tensor.dtype, linear_operator_circulant._DTYPE_COMPLEX) matrix_h = linalg.adjoint(matrix_tensor) matrix, matrix_h = sess.run([matrix_tensor, matrix_h]) self.assertAllClose(matrix, matrix_h, atol=0)
def test_real_spectrum_gives_self_adjoint_operator(self): with self.test_session() as sess: # This is a real and hermitian spectrum. spectrum = linear_operator_test_util.random_normal( shape=(3, 3), dtype=dtypes.float32) operator = linalg.LinearOperatorCirculant2D(spectrum) matrix_tensor = operator.to_dense() self.assertEqual(matrix_tensor.dtype, linear_operator_circulant._DTYPE_COMPLEX) matrix_h = linalg.adjoint(matrix_tensor) matrix, matrix_h = sess.run([matrix_tensor, matrix_h]) self.assertAllClose(matrix, matrix_h, atol=0)
def operator_and_matrix(self, build_info, dtype, use_placeholder): sess = ops.get_default_session() shape = list(build_info.shape) # Test only the case of 2 matrices. # The Square test uses either 1 or 2, so we have tested the case of 1 matrix # sufficiently. num_operators = 2 # Create 2 matrices/operators, A1, A2, which becomes A = A1 A2. # Use inner dimension of 2. k = 2 batch_shape = shape[:-2] shape_1 = batch_shape + [shape[-2], k] shape_2 = batch_shape + [k, shape[-1]] matrices = [ linear_operator_test_util.random_normal(shape_1, dtype=dtype), linear_operator_test_util.random_normal(shape_2, dtype=dtype) ] lin_op_matrices = matrices if use_placeholder: lin_op_matrices = [ array_ops.placeholder_with_default(matrix, shape=None) for matrix in matrices ] operator = linalg.LinearOperatorComposition( [linalg.LinearOperatorFullMatrix(l) for l in lin_op_matrices]) matmul_order_list = list(reversed(matrices)) mat = matmul_order_list[0] for other_mat in matmul_order_list[1:]: mat = math_ops.matmul(other_mat, mat) return operator, mat
def _operator_and_matrix(self, build_info, dtype, use_placeholder): sess = ops.get_default_session() shape = list(build_info.shape) # Test only the case of 2 matrices. # The Square test uses either 1 or 2, so we have tested the case of 1 matrix # sufficiently. num_operators = 2 # Create 2 matrices/operators, A1, A2, which becomes A = A1 A2. # Use inner dimension of 2. k = 2 batch_shape = shape[:-2] shape_1 = batch_shape + [shape[-2], k] shape_2 = batch_shape + [k, shape[-1]] matrices = [ linear_operator_test_util.random_normal( shape_1, dtype=dtype), linear_operator_test_util.random_normal( shape_2, dtype=dtype) ] lin_op_matrices = matrices if use_placeholder: lin_op_matrices = [ array_ops.placeholder_with_default( matrix, shape=None) for matrix in matrices] operator = linalg.LinearOperatorComposition( [linalg.LinearOperatorFullMatrix(l) for l in lin_op_matrices]) matmul_order_list = list(reversed(matrices)) mat = matmul_order_list[0] for other_mat in matmul_order_list[1:]: mat = math_ops.matmul(other_mat, mat) return operator, mat
def test_real_spectrum_gives_self_adjoint_operator(self): with self.cached_session() as sess: # This is a real and hermitian spectrum. spectrum = linear_operator_test_util.random_normal( shape=(2, 2, 3, 5), dtype=dtypes.float32) operator = linalg.LinearOperatorCirculant3D(spectrum) self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), operator.shape) matrix_tensor = operator.to_dense() self.assertEqual(matrix_tensor.dtype, linear_operator_circulant._DTYPE_COMPLEX) matrix_h = linalg.adjoint(matrix_tensor) matrix, matrix_h = self.evaluate([matrix_tensor, matrix_h]) self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), matrix.shape) self.assertAllClose(matrix, matrix_h)
def test_slice_nested_operator(self): linop = linalg.LinearOperatorKronecker([ linalg.LinearOperatorBlockDiag([ linalg.LinearOperatorDiag(array_ops.ones([1, 2, 2])), linalg.LinearOperatorDiag(array_ops.ones([3, 5, 2, 2])) ]), linalg.LinearOperatorFullMatrix( linear_operator_test_util.random_normal( shape=[4, 1, 1, 1, 3, 3], dtype=dtypes.float32)) ]) self.assertAllEqual(linop[0, ...].batch_shape_tensor(), [3, 5, 2]) self.assertAllEqual( linop[0, ..., array_ops.newaxis].batch_shape_tensor(), [3, 5, 2, 1]) self.assertAllEqual(linop[..., array_ops.newaxis].batch_shape_tensor(), [4, 3, 5, 2, 1])
def test_real_spectrum_gives_self_adjoint_operator(self): with self.cached_session() as sess: # This is a real and hermitian spectrum. spectrum = linear_operator_test_util.random_normal( shape=(2, 2, 3, 5), dtype=dtypes.float32) operator = linalg.LinearOperatorCirculant3D(spectrum) self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), operator.shape) matrix_tensor = operator.to_dense() self.assertEqual(matrix_tensor.dtype, linear_operator_circulant._DTYPE_COMPLEX) matrix_h = linalg.adjoint(matrix_tensor) matrix, matrix_h = self.evaluate([matrix_tensor, matrix_h]) self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), matrix.shape) self.assertAllClose(matrix, matrix_h)
def test_defining_operator_using_real_convolution_kernel(self): with self.cached_session(): convolution_kernel = linear_operator_test_util.random_normal( shape=(2, 2, 3, 5), dtype=dtypes.float32) # Convolution kernel is real ==> spectrum is Hermitian. spectrum = fft_ops.fft3d( math_ops.cast(convolution_kernel, dtypes.complex64)) # spectrum is Hermitian ==> operator is real. operator = linalg.LinearOperatorCirculant3D(spectrum) self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), operator.shape) # Allow for complex output so we can make sure it has zero imag part. self.assertEqual(operator.dtype, dtypes.complex64) matrix = operator.to_dense().eval() self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), matrix.shape) np.testing.assert_allclose(0, np.imag(matrix), atol=1e-6)
def test_defining_operator_using_real_convolution_kernel(self): with self.cached_session(): convolution_kernel = linear_operator_test_util.random_normal( shape=(2, 2, 3, 5), dtype=dtypes.float32) # Convolution kernel is real ==> spectrum is Hermitian. spectrum = fft_ops.fft3d( math_ops.cast(convolution_kernel, dtypes.complex64)) # spectrum is Hermitian ==> operator is real. operator = linalg.LinearOperatorCirculant3D(spectrum) self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), operator.shape) # Allow for complex output so we can make sure it has zero imag part. self.assertEqual(operator.dtype, dtypes.complex64) matrix = operator.to_dense().eval() self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), matrix.shape) np.testing.assert_allclose(0, np.imag(matrix), atol=1e-6)
def operator_and_matrix(self, build_info, dtype, use_placeholder): shape_before_adjoint = list(build_info.shape) # We need to swap the last two dimensions because we are taking the adjoint # of this operator shape_before_adjoint[-1], shape_before_adjoint[-2] = ( shape_before_adjoint[-2], shape_before_adjoint[-1]) matrix = linear_operator_test_util.random_normal( shape_before_adjoint, dtype=dtype) lin_op_matrix = matrix if use_placeholder: lin_op_matrix = array_ops.placeholder_with_default(matrix, shape=None) operator = LinearOperatorAdjoint( linalg.LinearOperatorFullMatrix(lin_op_matrix)) return operator, linalg.adjoint(matrix)
def operator_and_matrix(self, build_info, dtype, use_placeholder): shape_before_adjoint = list(build_info.shape) # We need to swap the last two dimensions because we are taking the adjoint # of this operator shape_before_adjoint[-1], shape_before_adjoint[-2] = ( shape_before_adjoint[-2], shape_before_adjoint[-1]) matrix = linear_operator_test_util.random_normal( shape_before_adjoint, dtype=dtype) lin_op_matrix = matrix if use_placeholder: lin_op_matrix = array_ops.placeholder_with_default(matrix, shape=None) operator = LinearOperatorAdjoint( linalg.LinearOperatorFullMatrix(lin_op_matrix)) return operator, linalg.adjoint(matrix)
def _operator_and_mat_and_feed_dict(self, shape, dtype, use_placeholder): matrix = linear_operator_test_util.random_normal(shape, dtype=dtype) if use_placeholder: matrix_ph = array_ops.placeholder(dtype=dtype) # Evaluate here because (i) you cannot feed a tensor, and (ii) # values are random and we want the same value used for both mat and # feed_dict. matrix = matrix.eval() operator = linalg.LinearOperatorFullMatrix(matrix_ph) feed_dict = {matrix_ph: matrix} else: operator = linalg.LinearOperatorFullMatrix(matrix) feed_dict = None # Convert back to Tensor. Needed if use_placeholder, since then we have # already evaluated matrix to a numpy array. mat = ops.convert_to_tensor(matrix) return operator, mat, feed_dict
def _operator_and_mat_and_feed_dict(self, shape, dtype, use_placeholder): matrix = linear_operator_test_util.random_normal(shape, dtype=dtype) if use_placeholder: matrix_ph = array_ops.placeholder(dtype=dtype) # Evaluate here because (i) you cannot feed a tensor, and (ii) # values are random and we want the same value used for both mat and # feed_dict. matrix = matrix.eval() operator = linalg.LinearOperatorFullMatrix(matrix_ph) feed_dict = {matrix_ph: matrix} else: operator = linalg.LinearOperatorFullMatrix(matrix) feed_dict = None # Convert back to Tensor. Needed if use_placeholder, since then we have # already evaluated matrix to a numpy array. mat = ops.convert_to_tensor(matrix) return operator, mat, feed_dict
def operator_and_matrix(self, shape_info, dtype, use_placeholder, ensure_self_adjoint_and_pd=False): del ensure_self_adjoint_and_pd shape = list(shape_info.shape) expected_blocks = (shape_info.__dict__["blocks"] if "blocks" in shape_info.__dict__ else [shape]) matrices = [ linear_operator_test_util.random_normal(block_shape, dtype=dtype) for block_shape in expected_blocks ] lin_op_matrices = matrices if use_placeholder: lin_op_matrices = [ array_ops.placeholder_with_default(matrix, shape=None) for matrix in matrices ] blocks = [] for l in lin_op_matrices: blocks.append( linalg.LinearOperatorFullMatrix(l, is_square=False, is_self_adjoint=False, is_positive_definite=False)) operator = block_diag.LinearOperatorBlockDiag(blocks) # Broadcast the shapes. expected_shape = list(shape_info.shape) matrices = linear_operator_util.broadcast_matrix_batch_dims(matrices) block_diag_dense = _block_diag_dense(expected_shape, matrices) if not use_placeholder: block_diag_dense.set_shape(expected_shape) return operator, block_diag_dense
def test_real_spectrum_gives_self_adjoint_operator(self): if test.is_built_with_rocm(): # ROCm does not yet support BLAS operations with complext types self.skipTest("ROCm does not support BLAS operations for complex types") with self.cached_session(): # This is a real and hermitian spectrum. spectrum = linear_operator_test_util.random_normal( shape=(2, 2, 3, 5), dtype=dtypes.float32) operator = linalg.LinearOperatorCirculant3D(spectrum) self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), operator.shape) matrix_tensor = operator.to_dense() self.assertEqual(matrix_tensor.dtype, dtypes.complex64) matrix_h = linalg.adjoint(matrix_tensor) matrix, matrix_h = self.evaluate([matrix_tensor, matrix_h]) self.assertAllEqual((2, 2 * 3 * 5, 2 * 3 * 5), matrix.shape) self.assertAllClose(matrix, matrix_h)
def operator_and_matrix(self, shape_info, dtype, use_placeholder, ensure_self_adjoint_and_pd=False): # Recall A = L + UDV^H shape = list(shape_info.shape) diag_shape = shape[:-1] k = shape[-2] // 2 + 1 u_perturbation_shape = shape[:-1] + [k] diag_update_shape = shape[:-2] + [k] # base_operator L will be a symmetric positive definite diagonal linear # operator, with condition number as high as 1e4. base_diag = self._gen_positive_diag(dtype, diag_shape) lin_op_base_diag = base_diag # U u = linear_operator_test_util.random_normal_correlated_columns( u_perturbation_shape, dtype=dtype) lin_op_u = u # V v = linear_operator_test_util.random_normal_correlated_columns( u_perturbation_shape, dtype=dtype) lin_op_v = v # D if self._is_diag_update_positive or ensure_self_adjoint_and_pd: diag_update = self._gen_positive_diag(dtype, diag_update_shape) else: diag_update = linear_operator_test_util.random_normal( diag_update_shape, stddev=1e-4, dtype=dtype) lin_op_diag_update = diag_update if use_placeholder: lin_op_base_diag = array_ops.placeholder_with_default(base_diag, shape=None) lin_op_u = array_ops.placeholder_with_default(u, shape=None) lin_op_v = array_ops.placeholder_with_default(v, shape=None) lin_op_diag_update = array_ops.placeholder_with_default( diag_update, shape=None) base_operator = linalg.LinearOperatorDiag(lin_op_base_diag, is_positive_definite=True, is_self_adjoint=True) operator = linalg.LinearOperatorLowRankUpdate( base_operator, lin_op_u, v=lin_op_v if self._use_v else None, diag_update=lin_op_diag_update if self._use_diag_update else None, is_diag_update_positive=self._is_diag_update_positive) # The matrix representing L base_diag_mat = array_ops.matrix_diag(base_diag) # The matrix representing D diag_update_mat = array_ops.matrix_diag(diag_update) # Set up mat as some variant of A = L + UDV^H if self._use_v and self._use_diag_update: # In this case, we have L + UDV^H and it isn't symmetric. expect_use_cholesky = False matrix = base_diag_mat + math_ops.matmul( u, math_ops.matmul(diag_update_mat, v, adjoint_b=True)) elif self._use_v: # In this case, we have L + UDV^H and it isn't symmetric. expect_use_cholesky = False matrix = base_diag_mat + math_ops.matmul(u, v, adjoint_b=True) elif self._use_diag_update: # In this case, we have L + UDU^H, which is PD if D > 0, since L > 0. expect_use_cholesky = self._is_diag_update_positive matrix = base_diag_mat + math_ops.matmul( u, math_ops.matmul(diag_update_mat, u, adjoint_b=True)) else: # In this case, we have L + UU^H, which is PD since L > 0. expect_use_cholesky = True matrix = base_diag_mat + math_ops.matmul(u, u, adjoint_b=True) if expect_use_cholesky: self.assertTrue(operator._use_cholesky) else: self.assertFalse(operator._use_cholesky) return operator, matrix
def _operator_and_mat_and_feed_dict(self, build_info, dtype, use_placeholder): # Recall A = L + UDV^H shape = list(build_info.shape) diag_shape = shape[:-1] k = shape[-2] // 2 + 1 u_perturbation_shape = shape[:-1] + [k] diag_update_shape = shape[:-2] + [k] # base_operator L will be a symmetric positive definite diagonal linear # operator, with condition number as high as 1e4. base_diag = linear_operator_test_util.random_uniform( diag_shape, minval=1e-4, maxval=1., dtype=dtype) base_diag_ph = array_ops.placeholder(dtype=dtype) # U u = linear_operator_test_util.random_normal_correlated_columns( u_perturbation_shape, dtype=dtype) u_ph = array_ops.placeholder(dtype=dtype) # V v = linear_operator_test_util.random_normal_correlated_columns( u_perturbation_shape, dtype=dtype) v_ph = array_ops.placeholder(dtype=dtype) # D if self._is_diag_update_positive: diag_update = linear_operator_test_util.random_uniform( diag_update_shape, minval=1e-4, maxval=1., dtype=dtype) else: diag_update = linear_operator_test_util.random_normal( diag_update_shape, stddev=1e-4, dtype=dtype) diag_update_ph = array_ops.placeholder(dtype=dtype) if use_placeholder: # Evaluate here because (i) you cannot feed a tensor, and (ii) # values are random and we want the same value used for both mat and # feed_dict. base_diag = base_diag.eval() u = u.eval() v = v.eval() diag_update = diag_update.eval() # In all cases, set base_operator to be positive definite. base_operator = linalg.LinearOperatorDiag( base_diag_ph, is_positive_definite=True) operator = linalg.LinearOperatorLowRankUpdate( base_operator, u=u_ph, v=v_ph if self._use_v else None, diag_update=diag_update_ph if self._use_diag_update else None, is_diag_update_positive=self._is_diag_update_positive) feed_dict = { base_diag_ph: base_diag, u_ph: u, v_ph: v, diag_update_ph: diag_update} else: base_operator = linalg.LinearOperatorDiag( base_diag, is_positive_definite=True) operator = linalg.LinearOperatorLowRankUpdate( base_operator, u, v=v if self._use_v else None, diag_update=diag_update if self._use_diag_update else None, is_diag_update_positive=self._is_diag_update_positive) feed_dict = None # The matrix representing L base_diag_mat = array_ops.matrix_diag(base_diag) # The matrix representing D diag_update_mat = array_ops.matrix_diag(diag_update) # Set up mat as some variant of A = L + UDV^H if self._use_v and self._use_diag_update: # In this case, we have L + UDV^H and it isn't symmetric. expect_use_cholesky = False mat = base_diag_mat + math_ops.matmul( u, math_ops.matmul(diag_update_mat, v, adjoint_b=True)) elif self._use_v: # In this case, we have L + UDV^H and it isn't symmetric. expect_use_cholesky = False mat = base_diag_mat + math_ops.matmul(u, v, adjoint_b=True) elif self._use_diag_update: # In this case, we have L + UDU^H, which is PD if D > 0, since L > 0. expect_use_cholesky = self._is_diag_update_positive mat = base_diag_mat + math_ops.matmul( u, math_ops.matmul(diag_update_mat, u, adjoint_b=True)) else: # In this case, we have L + UU^H, which is PD since L > 0. expect_use_cholesky = True mat = base_diag_mat + math_ops.matmul(u, u, adjoint_b=True) if expect_use_cholesky: self.assertTrue(operator._use_cholesky) else: self.assertFalse(operator._use_cholesky) return operator, mat, feed_dict
def _operator_and_mat_and_feed_dict(self, shape, dtype, use_placeholder): # Recall A = L + UDV^H shape = list(shape) diag_shape = shape[:-1] k = shape[-2] // 2 + 1 u_perturbation_shape = shape[:-1] + [k] diag_update_shape = shape[:-2] + [k] # base_operator L will be a symmetric positive definite diagonal linear # operator, with condition number as high as 1e4. base_diag = linear_operator_test_util.random_uniform( diag_shape, minval=1e-4, maxval=1., dtype=dtype) base_diag_ph = array_ops.placeholder(dtype=dtype) # U u = linear_operator_test_util.random_normal_correlated_columns( u_perturbation_shape, dtype=dtype) u_ph = array_ops.placeholder(dtype=dtype) # V v = linear_operator_test_util.random_normal_correlated_columns( u_perturbation_shape, dtype=dtype) v_ph = array_ops.placeholder(dtype=dtype) # D if self._is_diag_update_positive: diag_update = linear_operator_test_util.random_uniform( diag_update_shape, minval=1e-4, maxval=1., dtype=dtype) else: diag_update = linear_operator_test_util.random_normal( diag_update_shape, stddev=1e-4, dtype=dtype) diag_update_ph = array_ops.placeholder(dtype=dtype) if use_placeholder: # Evaluate here because (i) you cannot feed a tensor, and (ii) # values are random and we want the same value used for both mat and # feed_dict. base_diag = base_diag.eval() u = u.eval() v = v.eval() diag_update = diag_update.eval() # In all cases, set base_operator to be positive definite. base_operator = linalg.LinearOperatorDiag( base_diag_ph, is_positive_definite=True) operator = linalg.LinearOperatorLowRankUpdate( base_operator, u=u_ph, v=v_ph if self._use_v else None, diag_update=diag_update_ph if self._use_diag_update else None, is_diag_update_positive=self._is_diag_update_positive) feed_dict = { base_diag_ph: base_diag, u_ph: u, v_ph: v, diag_update_ph: diag_update} else: base_operator = linalg.LinearOperatorDiag( base_diag, is_positive_definite=True) operator = linalg.LinearOperatorLowRankUpdate( base_operator, u, v=v if self._use_v else None, diag_update=diag_update if self._use_diag_update else None, is_diag_update_positive=self._is_diag_update_positive) feed_dict = None # The matrix representing L base_diag_mat = array_ops.matrix_diag(base_diag) # The matrix representing D diag_update_mat = array_ops.matrix_diag(diag_update) # Set up mat as some variant of A = L + UDV^H if self._use_v and self._use_diag_update: # In this case, we have L + UDV^H and it isn't symmetric. expect_use_cholesky = False mat = base_diag_mat + math_ops.matmul( u, math_ops.matmul(diag_update_mat, v, adjoint_b=True)) elif self._use_v: # In this case, we have L + UDV^H and it isn't symmetric. expect_use_cholesky = False mat = base_diag_mat + math_ops.matmul(u, v, adjoint_b=True) elif self._use_diag_update: # In this case, we have L + UDU^H, which is PD if D > 0, since L > 0. expect_use_cholesky = self._is_diag_update_positive mat = base_diag_mat + math_ops.matmul( u, math_ops.matmul(diag_update_mat, u, adjoint_b=True)) else: # In this case, we have L + UU^H, which is PD since L > 0. expect_use_cholesky = True mat = base_diag_mat + math_ops.matmul(u, u, adjoint_b=True) if expect_use_cholesky: self.assertTrue(operator._use_cholesky) else: self.assertFalse(operator._use_cholesky) return operator, mat, feed_dict
def operator_and_matrix(self, shape_info, dtype, use_placeholder, ensure_self_adjoint_and_pd=False): # Recall A = L + UDV^H shape = list(shape_info.shape) diag_shape = shape[:-1] k = shape[-2] // 2 + 1 u_perturbation_shape = shape[:-1] + [k] diag_update_shape = shape[:-2] + [k] # base_operator L will be a symmetric positive definite diagonal linear # operator, with condition number as high as 1e4. base_diag = self._gen_positive_diag(dtype, diag_shape) lin_op_base_diag = base_diag # U u = linear_operator_test_util.random_normal_correlated_columns( u_perturbation_shape, dtype=dtype) lin_op_u = u # V v = linear_operator_test_util.random_normal_correlated_columns( u_perturbation_shape, dtype=dtype) lin_op_v = v # D if self._is_diag_update_positive or ensure_self_adjoint_and_pd: diag_update = self._gen_positive_diag(dtype, diag_update_shape) else: diag_update = linear_operator_test_util.random_normal( diag_update_shape, stddev=1e-4, dtype=dtype) lin_op_diag_update = diag_update if use_placeholder: lin_op_base_diag = array_ops.placeholder_with_default( base_diag, shape=None) lin_op_u = array_ops.placeholder_with_default(u, shape=None) lin_op_v = array_ops.placeholder_with_default(v, shape=None) lin_op_diag_update = array_ops.placeholder_with_default( diag_update, shape=None) base_operator = linalg.LinearOperatorDiag( lin_op_base_diag, is_positive_definite=True, is_self_adjoint=True) operator = linalg.LinearOperatorLowRankUpdate( base_operator, lin_op_u, v=lin_op_v if self._use_v else None, diag_update=lin_op_diag_update if self._use_diag_update else None, is_diag_update_positive=self._is_diag_update_positive) # The matrix representing L base_diag_mat = array_ops.matrix_diag(base_diag) # The matrix representing D diag_update_mat = array_ops.matrix_diag(diag_update) # Set up mat as some variant of A = L + UDV^H if self._use_v and self._use_diag_update: # In this case, we have L + UDV^H and it isn't symmetric. expect_use_cholesky = False matrix = base_diag_mat + math_ops.matmul( u, math_ops.matmul(diag_update_mat, v, adjoint_b=True)) elif self._use_v: # In this case, we have L + UDV^H and it isn't symmetric. expect_use_cholesky = False matrix = base_diag_mat + math_ops.matmul(u, v, adjoint_b=True) elif self._use_diag_update: # In this case, we have L + UDU^H, which is PD if D > 0, since L > 0. expect_use_cholesky = self._is_diag_update_positive matrix = base_diag_mat + math_ops.matmul( u, math_ops.matmul(diag_update_mat, u, adjoint_b=True)) else: # In this case, we have L + UU^H, which is PD since L > 0. expect_use_cholesky = True matrix = base_diag_mat + math_ops.matmul(u, u, adjoint_b=True) if expect_use_cholesky: self.assertTrue(operator._use_cholesky) else: self.assertFalse(operator._use_cholesky) return operator, matrix