1fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore#
3fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore# Licensed under the Apache License, Version 2.0 (the "License");
4fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore# you may not use this file except in compliance with the License.
5fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore# You may obtain a copy of the License at
6fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore#
7fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore#     http://www.apache.org/licenses/LICENSE-2.0
8fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore#
9fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore# Unless required by applicable law or agreed to in writing, software
10fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore# distributed under the License is distributed on an "AS IS" BASIS,
11fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore# See the License for the specific language governing permissions and
13fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore# limitations under the License.
14fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore# ==============================================================================
15fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
16fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmorefrom __future__ import absolute_import
17fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmorefrom __future__ import division
18fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmorefrom __future__ import print_function
19fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
2018727ef581297437e20d6df4a08b60e8b021f284Ian Langmoreimport numpy as np
2118727ef581297437e20d6df4a08b60e8b021f284Ian Langmore
22e121667dc609de978a223c56ee906368d2c4ceefJustine Tunneyfrom tensorflow.python.framework import dtypes
23e121667dc609de978a223c56ee906368d2c4ceefJustine Tunneyfrom tensorflow.python.framework import ops
24e121667dc609de978a223c56ee906368d2c4ceefJustine Tunneyfrom tensorflow.python.framework import random_seed
25e121667dc609de978a223c56ee906368d2c4ceefJustine Tunneyfrom tensorflow.python.ops import array_ops
2618727ef581297437e20d6df4a08b60e8b021f284Ian Langmorefrom tensorflow.python.ops import math_ops
2723418e4317b9e2c4a5148368daec873592a0de9eEugene Brevdofrom tensorflow.python.ops.linalg import linalg as linalg_lib
2823418e4317b9e2c4a5148368daec873592a0de9eEugene Brevdofrom tensorflow.python.ops.linalg import linear_operator_test_util
29e121667dc609de978a223c56ee906368d2c4ceefJustine Tunneyfrom tensorflow.python.platform import test
30fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
31e121667dc609de978a223c56ee906368d2c4ceefJustine Tunneylinalg = linalg_lib
32e121667dc609de978a223c56ee906368d2c4ceefJustine Tunneyrandom_seed.set_random_seed(23)
33fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
34fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
35f0357d2bb3b9cbbaec89fb8b0470712b4c2cda5eIan Langmoreclass SquareLinearOperatorFullMatrixTest(
36fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    linear_operator_test_util.SquareLinearOperatorDerivedClassTest):
37fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  """Most tests done in the base class LinearOperatorDerivedClassTest."""
38fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
39fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  def _operator_and_mat_and_feed_dict(self, shape, dtype, use_placeholder):
40fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    shape = list(shape)
41fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
42e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney    matrix = linear_operator_test_util.random_positive_definite_matrix(shape,
43e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney                                                                       dtype)
44fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
45fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    if use_placeholder:
46e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney      matrix_ph = array_ops.placeholder(dtype=dtype)
47fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      # Evaluate here because (i) you cannot feed a tensor, and (ii)
48fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      # values are random and we want the same value used for both mat and
49fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      # feed_dict.
50fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      matrix = matrix.eval()
517bb4cd35457fd7c3fdcb53a92495073aa9adcd5eIan Langmore      operator = linalg.LinearOperatorFullMatrix(matrix_ph, is_square=True)
52fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      feed_dict = {matrix_ph: matrix}
53fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    else:
547bb4cd35457fd7c3fdcb53a92495073aa9adcd5eIan Langmore      # is_square should be auto-detected here.
55f0357d2bb3b9cbbaec89fb8b0470712b4c2cda5eIan Langmore      operator = linalg.LinearOperatorFullMatrix(matrix)
56fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      feed_dict = None
57fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
58fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # Convert back to Tensor.  Needed if use_placeholder, since then we have
59fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # already evaluated matrix to a numpy array.
60e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney    mat = ops.convert_to_tensor(matrix)
61fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
62fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    return operator, mat, feed_dict
63fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
64fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  def test_is_x_flags(self):
65fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # Matrix with two positive eigenvalues.
66fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    matrix = [[1., 0.], [1., 11.]]
67f0357d2bb3b9cbbaec89fb8b0470712b4c2cda5eIan Langmore    operator = linalg.LinearOperatorFullMatrix(
68fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore        matrix,
69fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore        is_positive_definite=True,
70fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore        is_non_singular=True,
71fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore        is_self_adjoint=False)
72fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    self.assertTrue(operator.is_positive_definite)
73fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    self.assertTrue(operator.is_non_singular)
74fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    self.assertFalse(operator.is_self_adjoint)
757bb4cd35457fd7c3fdcb53a92495073aa9adcd5eIan Langmore    # Auto-detected.
767bb4cd35457fd7c3fdcb53a92495073aa9adcd5eIan Langmore    self.assertTrue(operator.is_square)
77fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
7818727ef581297437e20d6df4a08b60e8b021f284Ian Langmore  def test_assert_non_singular_raises_if_cond_too_big_but_finite(self):
7918727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    with self.test_session():
8018727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      tril = linear_operator_test_util.random_tril_matrix(
8118727ef581297437e20d6df4a08b60e8b021f284Ian Langmore          shape=(50, 50), dtype=np.float32)
8218727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      diag = np.logspace(-2, 2, 50).astype(np.float32)
8318727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      tril = array_ops.matrix_set_diag(tril, diag)
8418727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      matrix = math_ops.matmul(tril, tril, transpose_b=True).eval()
8518727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      operator = linalg.LinearOperatorFullMatrix(matrix)
8618727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      with self.assertRaisesOpError("Singular matrix"):
8718727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        # Ensure that we have finite condition number...just HUGE.
8818727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        cond = np.linalg.cond(matrix)
8918727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        self.assertTrue(np.isfinite(cond))
9018727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        self.assertGreater(cond, 1e12)
9118727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        operator.assert_non_singular().run()
9218727ef581297437e20d6df4a08b60e8b021f284Ian Langmore
9318727ef581297437e20d6df4a08b60e8b021f284Ian Langmore  def test_assert_non_singular_raises_if_cond_infinite(self):
9418727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    with self.test_session():
9518727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      matrix = [[1., 1.], [1., 1.]]
9618727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      # We don't pass the is_self_adjoint hint here, which means we take the
9718727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      # generic code path.
9818727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      operator = linalg.LinearOperatorFullMatrix(matrix)
9918727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      with self.assertRaisesOpError("Singular matrix"):
10018727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        operator.assert_non_singular().run()
10118727ef581297437e20d6df4a08b60e8b021f284Ian Langmore
10218727ef581297437e20d6df4a08b60e8b021f284Ian Langmore  def test_assert_self_adjoint(self):
10318727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    matrix = [[0., 1.], [0., 1.]]
10418727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    operator = linalg.LinearOperatorFullMatrix(matrix)
10518727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    with self.test_session():
10618727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      with self.assertRaisesOpError("not equal to its adjoint"):
10718727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        operator.assert_self_adjoint().run()
10818727ef581297437e20d6df4a08b60e8b021f284Ian Langmore
10918727ef581297437e20d6df4a08b60e8b021f284Ian Langmore  def test_assert_positive_definite(self):
11018727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    matrix = [[1., 1.], [1., 1.]]
11118727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    operator = linalg.LinearOperatorFullMatrix(matrix, is_self_adjoint=True)
11218727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    with self.test_session():
11318727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      with self.assertRaisesOpError("Cholesky decomposition was not success"):
11418727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        operator.assert_positive_definite().run()
11518727ef581297437e20d6df4a08b60e8b021f284Ian Langmore
116fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
117f0357d2bb3b9cbbaec89fb8b0470712b4c2cda5eIan Langmoreclass SquareLinearOperatorFullMatrixSymmetricPositiveDefiniteTest(
118fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    linear_operator_test_util.SquareLinearOperatorDerivedClassTest):
119fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  """Most tests done in the base class LinearOperatorDerivedClassTest.
120fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
121fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  In this test, the operator is constructed with hints that invoke the use of
122fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  a Cholesky decomposition for solves/determinant.
123fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  """
124fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
125fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  def setUp(self):
126fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # Increase from 1e-6 to 1e-5.  This reduction in tolerance happens,
127fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # presumably, because we are taking a different code path in the operator
128fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # and the matrix.  The operator uses a Choleksy, the matrix uses standard
129fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # solve.
130e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney    self._atol[dtypes.float32] = 1e-5
131e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney    self._rtol[dtypes.float32] = 1e-5
132e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney    self._atol[dtypes.float64] = 1e-10
133e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney    self._rtol[dtypes.float64] = 1e-10
134fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
135fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  @property
136fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  def _dtypes_to_test(self):
137e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney    return [dtypes.float32, dtypes.float64]
138fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
139fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  def _operator_and_mat_and_feed_dict(self, shape, dtype, use_placeholder):
140fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    shape = list(shape)
141fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
142fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    matrix = linear_operator_test_util.random_positive_definite_matrix(
143fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore        shape, dtype, force_well_conditioned=True)
144fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
145fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    if use_placeholder:
146e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney      matrix_ph = array_ops.placeholder(dtype=dtype)
147fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      # Evaluate here because (i) you cannot feed a tensor, and (ii)
148fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      # values are random and we want the same value used for both mat and
149fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      # feed_dict.
150fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      matrix = matrix.eval()
1517bb4cd35457fd7c3fdcb53a92495073aa9adcd5eIan Langmore      # is_square is auto-set because of self_adjoint/pd.
152f0357d2bb3b9cbbaec89fb8b0470712b4c2cda5eIan Langmore      operator = linalg.LinearOperatorFullMatrix(
15335e9035b8c76306cc85ed4871660ffb78d484a3aIan Langmore          matrix_ph, is_self_adjoint=True, is_positive_definite=True)
154fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      feed_dict = {matrix_ph: matrix}
155fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    else:
156f0357d2bb3b9cbbaec89fb8b0470712b4c2cda5eIan Langmore      operator = linalg.LinearOperatorFullMatrix(
157fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore          matrix, is_self_adjoint=True, is_positive_definite=True)
158fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      feed_dict = None
159fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
160fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # Convert back to Tensor.  Needed if use_placeholder, since then we have
161fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # already evaluated matrix to a numpy array.
162e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney    mat = ops.convert_to_tensor(matrix)
163fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
164fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    return operator, mat, feed_dict
165fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
166fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  def test_is_x_flags(self):
167fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # Matrix with two positive eigenvalues.
168fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    matrix = [[1., 0.], [0., 7.]]
169f0357d2bb3b9cbbaec89fb8b0470712b4c2cda5eIan Langmore    operator = linalg.LinearOperatorFullMatrix(
170e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney        matrix, is_positive_definite=True, is_self_adjoint=True)
171fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
172fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    self.assertTrue(operator.is_positive_definite)
173fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    self.assertTrue(operator.is_self_adjoint)
174fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
175fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # Should be auto-set
176fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    self.assertTrue(operator.is_non_singular)
1777bb4cd35457fd7c3fdcb53a92495073aa9adcd5eIan Langmore    self.assertTrue(operator._can_use_cholesky)
1787bb4cd35457fd7c3fdcb53a92495073aa9adcd5eIan Langmore    self.assertTrue(operator.is_square)
179fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
18018727ef581297437e20d6df4a08b60e8b021f284Ian Langmore  def test_assert_non_singular(self):
18118727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    matrix = [[1., 1.], [1., 1.]]
18218727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    operator = linalg.LinearOperatorFullMatrix(
18318727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        matrix, is_self_adjoint=True, is_positive_definite=True)
18418727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    with self.test_session():
18518727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      # Cholesky decomposition may fail, so the error is not specific to
18618727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      # non-singular.
18718727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      with self.assertRaisesOpError(""):
18818727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        operator.assert_non_singular().run()
18918727ef581297437e20d6df4a08b60e8b021f284Ian Langmore
19018727ef581297437e20d6df4a08b60e8b021f284Ian Langmore  def test_assert_self_adjoint(self):
19118727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    matrix = [[0., 1.], [0., 1.]]
19218727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    operator = linalg.LinearOperatorFullMatrix(
19318727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        matrix, is_self_adjoint=True, is_positive_definite=True)
19418727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    with self.test_session():
19518727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      with self.assertRaisesOpError("not equal to its adjoint"):
19618727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        operator.assert_self_adjoint().run()
19718727ef581297437e20d6df4a08b60e8b021f284Ian Langmore
19818727ef581297437e20d6df4a08b60e8b021f284Ian Langmore  def test_assert_positive_definite(self):
19918727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    matrix = [[1., 1.], [1., 1.]]
20018727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    operator = linalg.LinearOperatorFullMatrix(
20118727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        matrix, is_self_adjoint=True, is_positive_definite=True)
20218727ef581297437e20d6df4a08b60e8b021f284Ian Langmore    with self.test_session():
20318727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      # Cholesky decomposition may fail, so the error is not specific to
20418727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      # non-singular.
20518727ef581297437e20d6df4a08b60e8b021f284Ian Langmore      with self.assertRaisesOpError(""):
20618727ef581297437e20d6df4a08b60e8b021f284Ian Langmore        operator.assert_positive_definite().run()
20718727ef581297437e20d6df4a08b60e8b021f284Ian Langmore
208fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
209f0357d2bb3b9cbbaec89fb8b0470712b4c2cda5eIan Langmoreclass NonSquareLinearOperatorFullMatrixTest(
210fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    linear_operator_test_util.NonSquareLinearOperatorDerivedClassTest):
211fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  """Most tests done in the base class LinearOperatorDerivedClassTest."""
212fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
213fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  def _operator_and_mat_and_feed_dict(self, shape, dtype, use_placeholder):
214fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    matrix = linear_operator_test_util.random_normal(shape, dtype=dtype)
215fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    if use_placeholder:
216e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney      matrix_ph = array_ops.placeholder(dtype=dtype)
217fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      # Evaluate here because (i) you cannot feed a tensor, and (ii)
218fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      # values are random and we want the same value used for both mat and
219fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      # feed_dict.
220fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      matrix = matrix.eval()
22135e9035b8c76306cc85ed4871660ffb78d484a3aIan Langmore      operator = linalg.LinearOperatorFullMatrix(matrix_ph)
222fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      feed_dict = {matrix_ph: matrix}
223fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    else:
224f0357d2bb3b9cbbaec89fb8b0470712b4c2cda5eIan Langmore      operator = linalg.LinearOperatorFullMatrix(matrix)
225fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore      feed_dict = None
226fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
227fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # Convert back to Tensor.  Needed if use_placeholder, since then we have
228fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    # already evaluated matrix to a numpy array.
229e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney    mat = ops.convert_to_tensor(matrix)
230fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
231fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    return operator, mat, feed_dict
232fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
233fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore  def test_is_x_flags(self):
2347bb4cd35457fd7c3fdcb53a92495073aa9adcd5eIan Langmore    matrix = [[3., 2., 1.], [1., 1., 1.]]
235f0357d2bb3b9cbbaec89fb8b0470712b4c2cda5eIan Langmore    operator = linalg.LinearOperatorFullMatrix(
236fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore        matrix,
237fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore        is_self_adjoint=False)
2387bb4cd35457fd7c3fdcb53a92495073aa9adcd5eIan Langmore    self.assertEqual(operator.is_positive_definite, None)
2397bb4cd35457fd7c3fdcb53a92495073aa9adcd5eIan Langmore    self.assertEqual(operator.is_non_singular, None)
240fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore    self.assertFalse(operator.is_self_adjoint)
2417bb4cd35457fd7c3fdcb53a92495073aa9adcd5eIan Langmore    self.assertFalse(operator.is_square)
242fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
2432a7c58fee74d474d300b0e9ef21cd8380895a205Ian Langmore  def test_matrix_must_have_at_least_two_dims_or_raises(self):
2442a7c58fee74d474d300b0e9ef21cd8380895a205Ian Langmore    with self.assertRaisesRegexp(ValueError, "at least 2 dimensions"):
245f0357d2bb3b9cbbaec89fb8b0470712b4c2cda5eIan Langmore      linalg.LinearOperatorFullMatrix([1.])
2462a7c58fee74d474d300b0e9ef21cd8380895a205Ian Langmore
247fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmore
248fc6a0b5269763c07bfe8b0eb25c0dab8a09b3fbaIan Langmoreif __name__ == "__main__":
249e121667dc609de978a223c56ee906368d2c4ceefJustine Tunney  test.main()
250