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