blob: 02ce5b810eb105c2880dc70cc4d313229d1feb0c [file] [log] [blame]
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import variables as variables_module
from tensorflow.python.ops.linalg import linalg as linalg_lib
from tensorflow.python.ops.linalg import linear_operator_test_util
from tensorflow.python.platform import test
linalg = linalg_lib
@test_util.run_all_in_graph_and_eager_modes
class LinearOperatorLowerTriangularTest(
linear_operator_test_util.SquareLinearOperatorDerivedClassTest):
"""Most tests done in the base class LinearOperatorDerivedClassTest."""
@staticmethod
def tests_to_skip():
# Cholesky does not make sense for triangular matrices.
return ["cholesky"]
def operator_and_matrix(self, build_info, dtype, use_placeholder):
shape = list(build_info.shape)
# Upper triangle will be nonzero, but ignored.
# Use a diagonal that ensures this matrix is well conditioned.
tril = linear_operator_test_util.random_tril_matrix(
shape, dtype=dtype, force_well_conditioned=True, remove_upper=False)
lin_op_tril = tril
if use_placeholder:
lin_op_tril = array_ops.placeholder_with_default(lin_op_tril, shape=None)
operator = linalg.LinearOperatorLowerTriangular(lin_op_tril)
matrix = array_ops.matrix_band_part(tril, -1, 0)
return operator, matrix
def test_assert_non_singular(self):
# Singlular matrix with one positive eigenvalue and one zero eigenvalue.
with self.cached_session():
tril = [[1., 0.], [1., 0.]]
operator = linalg.LinearOperatorLowerTriangular(tril)
with self.assertRaisesOpError("Singular operator"):
operator.assert_non_singular().run()
def test_is_x_flags(self):
# Matrix with two positive eigenvalues.
tril = [[1., 0.], [1., 1.]]
operator = linalg.LinearOperatorLowerTriangular(
tril,
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 test_tril_must_have_at_least_two_dims_or_raises(self):
with self.assertRaisesRegexp(ValueError, "at least 2 dimensions"):
linalg.LinearOperatorLowerTriangular([1.])
def test_triangular_diag_matmul(self):
operator1 = linalg_lib.LinearOperatorLowerTriangular(
[[1., 0., 0.], [2., 1., 0.], [2., 3., 3.]])
operator2 = linalg_lib.LinearOperatorDiag([2., 2., 3.])
operator_matmul = operator1.matmul(operator2)
self.assertTrue(isinstance(
operator_matmul,
linalg_lib.LinearOperatorLowerTriangular))
self.assertAllClose(
math_ops.matmul(
operator1.to_dense(),
operator2.to_dense()),
self.evaluate(operator_matmul.to_dense()))
operator_matmul = operator2.matmul(operator1)
self.assertTrue(isinstance(
operator_matmul,
linalg_lib.LinearOperatorLowerTriangular))
self.assertAllClose(
math_ops.matmul(
operator2.to_dense(),
operator1.to_dense()),
self.evaluate(operator_matmul.to_dense()))
def test_tape_safe(self):
tril = variables_module.Variable([[1., 0.], [0., 1.]])
operator = linalg_lib.LinearOperatorLowerTriangular(
tril, is_non_singular=True)
self.check_tape_safe(operator)
if __name__ == "__main__":
linear_operator_test_util.add_tests(LinearOperatorLowerTriangularTest)
test.main()