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 17 from __future__ import absolute_import 18 from __future__ import division 19 from __future__ import print_function 20 21 import numpy as np 22 23 from tensorflow.python.client import session 24 from tensorflow.python.framework import constant_op 25 from tensorflow.python.framework import ops 26 from tensorflow.python.ops import control_flow_ops 27 from tensorflow.python.ops import gen_linalg_ops 28 from tensorflow.python.ops import linalg_ops 29 from tensorflow.python.ops import random_ops 30 from tensorflow.python.ops import variables 31 from tensorflow.python.platform import test 32 33 34 class DeterminantOpTest(test.TestCase): 35 36 def _compareDeterminantBase(self, matrix_x, tf_ans): 37 out = tf_ans.eval() 38 shape = matrix_x.shape 39 if shape[-1] == 0 and shape[-2] == 0: 40 np_ans = np.ones(shape[:-2]).astype(matrix_x.dtype) 41 else: 42 np_ans = np.array(np.linalg.det(matrix_x)).astype(matrix_x.dtype) 43 self.assertShapeEqual(np_ans, tf_ans) 44 self.assertAllClose(np_ans, out, atol=5e-5) 45 46 def _compareLogDeterminantBase(self, matrix_x, tf_ans): 47 sign_tf, abs_log_det_tf = tf_ans 48 shape = matrix_x.shape 49 if shape[-1] == 0 or shape[-2] == 0: 50 np_sign, np_ans = (1.0, np.zeros(shape[:-2]).astype(matrix_x.dtype)) 51 else: 52 np_sign, np_ans = np.linalg.slogdet(matrix_x) 53 np_ans = np_ans.astype(matrix_x.dtype) 54 55 self.assertShapeEqual(np_ans, abs_log_det_tf) 56 sign_tf_val = sign_tf.eval() 57 abs_log_det_tf_val = abs_log_det_tf.eval() 58 self.assertAllClose( 59 sign_tf_val * np.exp(abs_log_det_tf_val), 60 np_sign * np.exp(np_ans), 61 atol=5e-5) 62 63 def _compareDeterminant(self, matrix_x): 64 with self.test_session(use_gpu=True): 65 self._compareDeterminantBase(matrix_x, 66 linalg_ops.matrix_determinant(matrix_x)) 67 self._compareLogDeterminantBase( 68 matrix_x, gen_linalg_ops._log_matrix_determinant(matrix_x)) 69 70 def testBasic(self): 71 # 2x2 matrices 72 self._compareDeterminant(np.array([[2., 3.], [3., 4.]]).astype(np.float32)) 73 self._compareDeterminant(np.array([[0., 0.], [0., 0.]]).astype(np.float32)) 74 # 5x5 matrices (Eigen forces LU decomposition) 75 self._compareDeterminant( 76 np.array([[2., 3., 4., 5., 6.], [3., 4., 9., 2., 0.], [ 77 2., 5., 8., 3., 8. 78 ], [1., 6., 7., 4., 7.], [2., 3., 4., 5., 6.]]).astype(np.float32)) 79 # A multidimensional batch of 2x2 matrices 80 self._compareDeterminant(np.random.rand(3, 4, 5, 2, 2).astype(np.float32)) 81 82 def testBasicDouble(self): 83 # 2x2 matrices 84 self._compareDeterminant(np.array([[2., 3.], [3., 4.]]).astype(np.float64)) 85 self._compareDeterminant(np.array([[0., 0.], [0., 0.]]).astype(np.float64)) 86 # 5x5 matrices (Eigen forces LU decomposition) 87 self._compareDeterminant( 88 np.array([[2., 3., 4., 5., 6.], [3., 4., 9., 2., 0.], [ 89 2., 5., 8., 3., 8. 90 ], [1., 6., 7., 4., 7.], [2., 3., 4., 5., 6.]]).astype(np.float64)) 91 # A multidimensional batch of 2x2 matrices 92 self._compareDeterminant(np.random.rand(3, 4, 5, 2, 2).astype(np.float64)) 93 94 def testBasicComplex64(self): 95 # 2x2 matrices 96 self._compareDeterminant( 97 np.array([[2., 3.], [3., 4.]]).astype(np.complex64)) 98 self._compareDeterminant( 99 np.array([[0., 0.], [0., 0.]]).astype(np.complex64)) 100 self._compareDeterminant( 101 np.array([[1. + 1.j, 1. - 1.j], [-1. + 1.j, -1. - 1.j]]).astype( 102 np.complex64)) 103 # 5x5 matrices (Eigen forces LU decomposition) 104 self._compareDeterminant( 105 np.array([[2., 3., 4., 5., 6.], [3., 4., 9., 2., 0.], [ 106 2., 5., 8., 3., 8. 107 ], [1., 6., 7., 4., 7.], [2., 3., 4., 5., 6.]]).astype(np.complex64)) 108 # A multidimensional batch of 2x2 matrices 109 self._compareDeterminant(np.random.rand(3, 4, 5, 2, 2).astype(np.complex64)) 110 111 def testBasicComplex128(self): 112 # 2x2 matrices 113 self._compareDeterminant( 114 np.array([[2., 3.], [3., 4.]]).astype(np.complex128)) 115 self._compareDeterminant( 116 np.array([[0., 0.], [0., 0.]]).astype(np.complex128)) 117 self._compareDeterminant( 118 np.array([[1. + 1.j, 1. - 1.j], [-1. + 1.j, -1. - 1.j]]).astype( 119 np.complex128)) 120 # 5x5 matrices (Eigen forces LU decomposition) 121 self._compareDeterminant( 122 np.array([[2., 3., 4., 5., 6.], [3., 4., 9., 2., 0.], [ 123 2., 5., 8., 3., 8. 124 ], [1., 6., 7., 4., 7.], [2., 3., 4., 5., 6.]]).astype(np.complex128)) 125 # A multidimensional batch of 2x2 matrices 126 self._compareDeterminant( 127 np.random.rand(3, 4, 5, 2, 2).astype(np.complex128)) 128 129 def testInfiniteDeterminant(self): 130 max_double = np.finfo("d").max 131 huge_matrix = np.array([[max_double, 0.0], [0.0, max_double]]) 132 self._compareDeterminant(huge_matrix) 133 134 def testNonSquareMatrix(self): 135 # When the determinant of a non-square matrix is attempted we should return 136 # an error 137 with self.assertRaises(ValueError): 138 linalg_ops.matrix_determinant( 139 np.array([[1., 2., 3.], [3., 5., 4.]]).astype(np.float32)) 140 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 def testConcurrentExecutesWithoutError(self): 152 with self.test_session(use_gpu=True) as sess: 153 matrix1 = random_ops.random_normal([5, 5], seed=42) 154 matrix2 = random_ops.random_normal([5, 5], seed=42) 155 det1 = linalg_ops.matrix_determinant(matrix1) 156 det2 = linalg_ops.matrix_determinant(matrix2) 157 det1_val, det2_val = sess.run([det1, det2]) 158 self.assertEqual(det1_val, det2_val) 159 160 161 class MatrixDeterminantBenchmark(test.Benchmark): 162 163 shapes = [ 164 (4, 4), 165 (10, 10), 166 (16, 16), 167 (101, 101), 168 (256, 256), 169 (1000, 1000), 170 (1024, 1024), 171 (2048, 2048), 172 (513, 4, 4), 173 (513, 16, 16), 174 (513, 256, 256), 175 ] 176 177 def _GenerateMatrix(self, shape): 178 batch_shape = shape[:-2] 179 shape = shape[-2:] 180 assert shape[0] == shape[1] 181 n = shape[0] 182 matrix = np.ones(shape).astype(np.float32) / ( 183 2.0 * n) + np.diag(np.ones(n).astype(np.float32)) 184 return variables.Variable(np.tile(matrix, batch_shape + (1, 1))) 185 186 def benchmarkMatrixDeterminantOp(self): 187 for shape in self.shapes: 188 with ops.Graph().as_default(), session.Session() as sess, ops.device( 189 "/cpu:0"): 190 matrix = self._GenerateMatrix(shape) 191 d = linalg_ops.matrix_determinant(matrix) 192 variables.global_variables_initializer().run() 193 self.run_op_benchmark( 194 sess, 195 control_flow_ops.group( 196 d,), 197 min_iters=25, 198 name="matrix_determinant_cpu_{shape}".format(shape=shape)) 199 200 if test.is_gpu_available(True): 201 with ops.Graph().as_default(), session.Session() as sess, ops.device( 202 "/gpu:0"): 203 matrix = self._GenerateMatrix(shape) 204 d = linalg_ops.matrix_determinant(matrix) 205 variables.global_variables_initializer().run() 206 self.run_op_benchmark( 207 sess, 208 control_flow_ops.group( 209 d,), 210 min_iters=25, 211 name="matrix_determinant_gpu_{shape}".format(shape=shape)) 212 213 214 if __name__ == "__main__": 215 test.main() 216