• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Tests for tensorflow.ops.tf.MatrixDeterminant."""
16
17import numpy as np
18
19from tensorflow.python.client import session
20from tensorflow.python.framework import constant_op
21from tensorflow.python.framework import ops
22from tensorflow.python.framework import test_util
23from tensorflow.python.ops import control_flow_ops
24from tensorflow.python.ops import gen_linalg_ops
25from tensorflow.python.ops import linalg_ops
26from tensorflow.python.ops import random_ops
27from tensorflow.python.ops import variables
28from tensorflow.python.platform import benchmark
29from tensorflow.python.platform import test
30
31
32class DeterminantOpTest(test.TestCase):
33
34  def _compareDeterminantBase(self, matrix_x, tf_ans):
35    out = self.evaluate(tf_ans)
36    shape = matrix_x.shape
37    if shape[-1] == 0 and shape[-2] == 0:
38      np_ans = np.ones(shape[:-2]).astype(matrix_x.dtype)
39    else:
40      np_ans = np.array(np.linalg.det(matrix_x)).astype(matrix_x.dtype)
41    self.assertShapeEqual(np_ans, tf_ans)
42    self.assertAllClose(np_ans, out, atol=5e-5)
43
44  def _compareLogDeterminantBase(self, matrix_x, tf_ans):
45    sign_tf, abs_log_det_tf = tf_ans
46    shape = matrix_x.shape
47    if shape[-1] == 0 or shape[-2] == 0:
48      np_sign, np_ans = (1.0, np.zeros(shape[:-2]).astype(matrix_x.dtype))
49    else:
50      np_sign, np_ans = np.linalg.slogdet(matrix_x)
51      np_ans = np_ans.astype(matrix_x.dtype)
52
53    self.assertShapeEqual(np_ans, abs_log_det_tf)
54    sign_tf_val = self.evaluate(sign_tf)
55    abs_log_det_tf_val = self.evaluate(abs_log_det_tf)
56    self.assertAllClose(
57        sign_tf_val * np.exp(abs_log_det_tf_val),
58        np_sign * np.exp(np_ans),
59        atol=5e-5)
60
61  def _compareDeterminant(self, matrix_x):
62    with test_util.use_gpu():
63      self._compareDeterminantBase(matrix_x,
64                                   linalg_ops.matrix_determinant(matrix_x))
65      self._compareLogDeterminantBase(
66          matrix_x, gen_linalg_ops.log_matrix_determinant(matrix_x))
67
68  def testBasic(self):
69    # 2x2 matrices
70    self._compareDeterminant(np.array([[2., 3.], [3., 4.]]).astype(np.float32))
71    self._compareDeterminant(np.array([[0., 0.], [0., 0.]]).astype(np.float32))
72    # 5x5 matrices (Eigen forces LU decomposition)
73    self._compareDeterminant(
74        np.array([[2., 3., 4., 5., 6.], [3., 4., 9., 2., 0.], [
75            2., 5., 8., 3., 8.
76        ], [1., 6., 7., 4., 7.], [2., 3., 4., 5., 6.]]).astype(np.float32))
77    # A multidimensional batch of 2x2 matrices
78    self._compareDeterminant(np.random.rand(3, 4, 5, 2, 2).astype(np.float32))
79
80  def testBasicDouble(self):
81    # 2x2 matrices
82    self._compareDeterminant(np.array([[2., 3.], [3., 4.]]).astype(np.float64))
83    self._compareDeterminant(np.array([[0., 0.], [0., 0.]]).astype(np.float64))
84    # 5x5 matrices (Eigen forces LU decomposition)
85    self._compareDeterminant(
86        np.array([[2., 3., 4., 5., 6.], [3., 4., 9., 2., 0.], [
87            2., 5., 8., 3., 8.
88        ], [1., 6., 7., 4., 7.], [2., 3., 4., 5., 6.]]).astype(np.float64))
89    # A multidimensional batch of 2x2 matrices
90    self._compareDeterminant(np.random.rand(3, 4, 5, 2, 2).astype(np.float64))
91
92  def testBasicComplex64(self):
93    # 2x2 matrices
94    self._compareDeterminant(
95        np.array([[2., 3.], [3., 4.]]).astype(np.complex64))
96    self._compareDeterminant(
97        np.array([[0., 0.], [0., 0.]]).astype(np.complex64))
98    self._compareDeterminant(
99        np.array([[1. + 1.j, 1. - 1.j], [-1. + 1.j, -1. - 1.j]]).astype(
100            np.complex64))
101    # 5x5 matrices (Eigen forces LU decomposition)
102    self._compareDeterminant(
103        np.array([[2., 3., 4., 5., 6.], [3., 4., 9., 2., 0.], [
104            2., 5., 8., 3., 8.
105        ], [1., 6., 7., 4., 7.], [2., 3., 4., 5., 6.]]).astype(np.complex64))
106    # A multidimensional batch of 2x2 matrices
107    self._compareDeterminant(np.random.rand(3, 4, 5, 2, 2).astype(np.complex64))
108
109  def testBasicComplex128(self):
110    # 2x2 matrices
111    self._compareDeterminant(
112        np.array([[2., 3.], [3., 4.]]).astype(np.complex128))
113    self._compareDeterminant(
114        np.array([[0., 0.], [0., 0.]]).astype(np.complex128))
115    self._compareDeterminant(
116        np.array([[1. + 1.j, 1. - 1.j], [-1. + 1.j, -1. - 1.j]]).astype(
117            np.complex128))
118    # 5x5 matrices (Eigen forces LU decomposition)
119    self._compareDeterminant(
120        np.array([[2., 3., 4., 5., 6.], [3., 4., 9., 2., 0.], [
121            2., 5., 8., 3., 8.
122        ], [1., 6., 7., 4., 7.], [2., 3., 4., 5., 6.]]).astype(np.complex128))
123    # A multidimensional batch of 2x2 matrices
124    self._compareDeterminant(
125        np.random.rand(3, 4, 5, 2, 2).astype(np.complex128))
126
127  def testInfiniteDeterminant(self):
128    max_double = np.finfo("d").max
129    huge_matrix = np.array([[max_double, 0.0], [0.0, max_double]])
130    self._compareDeterminant(huge_matrix)
131
132  @test_util.run_v1_only("b/120545219")
133  def testNonSquareMatrix(self):
134    # When the determinant of a non-square matrix is attempted we should return
135    # an error
136    with self.assertRaises(ValueError):
137      linalg_ops.matrix_determinant(
138          np.array([[1., 2., 3.], [3., 5., 4.]]).astype(np.float32))
139
140  @test_util.run_v1_only("b/120545219")
141  def testWrongDimensions(self):
142    # The input to the determinant should be a 2-dimensional tensor.
143    tensor1 = constant_op.constant([1., 2.])
144    with self.assertRaises(ValueError):
145      linalg_ops.matrix_determinant(tensor1)
146
147  def testEmpty(self):
148    self._compareDeterminant(np.empty([0, 2, 2]))
149    self._compareDeterminant(np.empty([2, 0, 0]))
150
151  @test_util.run_v1_only("b/120545219")
152  def testConcurrentExecutesWithoutError(self):
153    with self.session():
154      matrix1 = random_ops.random_normal([5, 5], seed=42)
155      matrix2 = random_ops.random_normal([5, 5], seed=42)
156      det1 = linalg_ops.matrix_determinant(matrix1)
157      det2 = linalg_ops.matrix_determinant(matrix2)
158      det1_val, det2_val = self.evaluate([det1, det2])
159      self.assertEqual(det1_val, det2_val)
160
161
162class MatrixDeterminantBenchmark(test.Benchmark):
163
164  shapes = [
165      (4, 4),
166      (10, 10),
167      (16, 16),
168      (101, 101),
169      (256, 256),
170      (1000, 1000),
171      (1024, 1024),
172      (2048, 2048),
173      (513, 4, 4),
174      (513, 16, 16),
175      (513, 256, 256),
176  ]
177
178  def _GenerateMatrix(self, shape):
179    batch_shape = shape[:-2]
180    shape = shape[-2:]
181    assert shape[0] == shape[1]
182    n = shape[0]
183    matrix = np.ones(shape).astype(np.float32) / (
184        2.0 * n) + np.diag(np.ones(n).astype(np.float32))
185    return variables.Variable(np.tile(matrix, batch_shape + (1, 1)))
186
187  def benchmarkMatrixDeterminantOp(self):
188    for shape in self.shapes:
189      with ops.Graph().as_default(), session.Session(
190          config=benchmark.benchmark_config()) as sess, ops.device("/cpu:0"):
191        matrix = self._GenerateMatrix(shape)
192        d = linalg_ops.matrix_determinant(matrix)
193        self.evaluate(variables.global_variables_initializer())
194        self.run_op_benchmark(
195            sess,
196            control_flow_ops.group(
197                d,),
198            min_iters=25,
199            name="matrix_determinant_cpu_{shape}".format(shape=shape))
200
201      if test.is_gpu_available(True):
202        with ops.Graph().as_default(), session.Session(
203            config=benchmark.benchmark_config()) as sess, ops.device("/gpu:0"):
204          matrix = self._GenerateMatrix(shape)
205          d = linalg_ops.matrix_determinant(matrix)
206          self.evaluate(variables.global_variables_initializer())
207          self.run_op_benchmark(
208              sess,
209              control_flow_ops.group(
210                  d,),
211              min_iters=25,
212              name="matrix_determinant_gpu_{shape}".format(shape=shape))
213
214
215if __name__ == "__main__":
216  test.main()
217