We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
F.det should not raise error in forward propagation when input matrix is singular
Currently, `F.det` raises `ValueError` in forward propagation when input matrix is singular [here](https://github.com/pfnet/chainer/pull/613/files#diff-4d0027dd8b2ecc0d9eae073ddfefdb26R65).

It is beneficial when we do backward propagation because it calculates the inverse of the input matrix. But some users can use `F.det` without backward propagation, in which case singular matrices are not exceptional. So we should not raise errors.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `chainer/functions/math/inv.py`
Content:
```
1 import numpy.linalg
2 import six
3 
4 from chainer import cuda
5 from chainer import function
6 from chainer.functions.math import matmul
7 from chainer import utils
8 from chainer.utils import type_check
9 
10 
11 def _inv_gpu(b):
12     # We do a batched LU decomposition on the GPU to compute the inverse
13     # Change the shape of the array to be size=1 minibatch if necessary
14     # Also copy the matrix as the elments will be modified in-place
15     a = matmul._as_batch_mat(b).copy()
16     n = a.shape[1]
17     n_matrices = len(a)
18     # Pivot array
19     p = cuda.cupy.empty((n, n_matrices), dtype='int32')
20     # Output array
21     c = cuda.cupy.empty_like(a)
22     # These arrays hold information on the execution success
23     # or if the matrix was singular
24     info = cuda.cupy.empty(n_matrices, dtype=numpy.intp)
25     ap = matmul._mat_ptrs(a)
26     cp = matmul._mat_ptrs(c)
27     _, lda = matmul._get_ld(a)
28     _, ldc = matmul._get_ld(c)
29     handle = cuda.Device().cublas_handle
30     cuda.cublas.sgetrfBatched(
31         handle, n, ap.data.ptr, lda, p.data.ptr, info.data.ptr, n_matrices)
32     cuda.cublas.sgetriBatched(
33         handle, n, ap.data.ptr, lda, p.data.ptr, cp.data.ptr, ldc,
34         info.data.ptr, n_matrices)
35     return c
36 
37 
38 class Inv(function.Function):
39 
40     def check_type_forward(self, in_types):
41         type_check.expect(in_types.size() == 1)
42         a_type, = in_types
43         type_check.expect(a_type.dtype == numpy.float32)
44         # Only 2D array shapes allowed
45         type_check.expect(a_type.ndim == 2)
46         # Matrix inversion only allowed for square matrices
47         type_check.expect(a_type.shape[0] == a_type.shape[1])
48 
49     def forward_cpu(self, x):
50         self.invx = utils.force_array(numpy.linalg.inv(x[0]))
51         return self.invx,
52 
53     def forward_gpu(self, x):
54         shape = x[0].shape
55         self.invx = _inv_gpu(x[0].reshape(1, *shape)).reshape(shape)
56         return self.invx,
57 
58     def backward(self, x, gy):
59         # Gradient is - x^-T (dx) x^-T
60         x, = x
61         xp = cuda.get_array_module(x)
62         gx = xp.dot(xp.dot(-self.invx.T, gy[0]), self.invx.T)
63         return gx,
64 
65 
66 class BatchInv(function.Function):
67 
68     def check_type_forward(self, in_types):
69         type_check.expect(in_types.size() == 1)
70         a_type, = in_types
71         type_check.expect(a_type.dtype == numpy.float32)
72         # Only a minibatch of 2D array shapes allowed
73         type_check.expect(a_type.ndim == 3)
74         # Matrix inversion only allowed for square matrices
75         # so assert the last two dimensions are equal
76         type_check.expect(a_type.shape[-1] == a_type.shape[-2])
77 
78     def forward_cpu(self, x):
79         self.invx = utils.force_array(numpy.linalg.inv(x[0]))
80         return self.invx,
81 
82     def forward_gpu(self, x):
83         self.invx = _inv_gpu(x[0])
84         return self.invx,
85 
86     def backward_cpu(self, x, gy):
87         # Gradient is - x^-T (dx) x^-T
88         x, = x
89         gy, = gy
90         batch_size = len(x)
91         gx = numpy.empty_like(x)
92         for i in six.moves.range(batch_size):
93             gx[i] = numpy.dot(-self.invx[i].T, gy[i])
94             gx[i] = numpy.dot(gx[i], self.invx[i].T)
95         return gx,
96 
97     def backward_gpu(self, x, gy):
98         # Unpack 1-length tuples
99         gy, = gy
100         shape = gy.shape
101         dtype = x[0].dtype
102         ret = cuda.cupy.empty(shape, dtype)
103         matmul._batch_matmul_gpu(-self.invx, gy, out=ret, transa=True)
104         ret2 = cuda.cupy.empty(shape, dtype)
105         matmul._batch_matmul_gpu(ret, self.invx, out=ret2, transb=True)
106         return ret2,
107 
108 
109 def inv(a):
110     """Computes the inverse of of square matrix.
111 
112     Args:
113         a (Variable): Input array to compute the determinant for.
114         Shape of the array should be ``(n, n)`` where ``n`` is the
115         dimensionality of a square matrix.
116 
117     Returns:
118         ~chainer.Variable: Matrix inverse of ``a``.
119     """
120     return Inv()(a)
121 
122 
123 def batch_inv(a):
124     """Computes the inverse of a batch of square matrices.
125 
126     Args:
127         a (Variable): Input array to compute the determinant for.
128         Shape of the array should be ``(m, n, n)`` where m is the number
129         of matrices in the batch, and ``n`` is the dimensionality of a square
130         matrix.
131 
132     Returns:
133         ~chainer.Variable: Inverse of every matrix in the batch of matrices.
134     """
135     return BatchInv()(a)
136
```

Path: `chainer/functions/math/det.py`
Content:
```
1 import numpy
2 
3 from chainer import cuda
4 from chainer import function
5 from chainer.functions.array import reshape
6 from chainer.functions.math import inv
7 from chainer.functions.math import matmul
8 from chainer import utils
9 from chainer.utils import type_check
10 
11 
12 def _det_gpu(b):
13     # We do a batched LU decomposition on the GPU to compute
14     # and compute the determinant by multiplying the diagonal.
15     # Change the shape of the array to be size=1 minibatch if necessary.
16     # Also copy the matrix as the elments will be modified in-place.
17     a = matmul._as_batch_mat(b).copy()
18     n = a.shape[1]
19     n_matrices = len(a)
20     # Pivot array
21     p = cuda.cupy.zeros((n_matrices, n), dtype='int32')
22     # Output array
23     # These arrays hold information on the execution success
24     # or if the matrix was singular.
25     info1 = cuda.cupy.zeros(n_matrices, dtype=numpy.intp)
26     ap = matmul._mat_ptrs(a)
27     _, lda = matmul._get_ld(a)
28     cuda.cublas.sgetrfBatched(cuda.Device().cublas_handle, n, ap.data.ptr, lda,
29                               p.data.ptr, info1.data.ptr, n_matrices)
30     det = cuda.cupy.prod(a.diagonal(axis1=1, axis2=2), axis=1)
31     # The determinant is equal to the product of the diagonal entries
32     # of `a` where the sign of `a` is flipped depending on whether
33     # the pivot array is equal to its index.
34     rng = cuda.cupy.arange(1, n + 1, dtype='int32')
35     parity = cuda.cupy.sum(p != rng, axis=1) % 2
36     sign = 1. - 2. * parity.astype('float32')
37     success = cuda.cupy.all(info1 == 0)
38     return det * sign, success
39 
40 
41 class BatchDet(function.Function):
42 
43     @property
44     def label(self):
45         return 'det'
46 
47     def check_type_forward(self, in_types):
48         type_check.expect(in_types.size() == 1)
49         a_type, = in_types
50         a_type = matmul._convert_type(a_type)
51         type_check.expect(a_type.dtype.kind == 'f')
52         # Only a minibatch of 2D array shapes allowed.
53         type_check.expect(a_type.ndim == 3)
54         # Matrix inversion only allowed for square matrices
55         # so assert the last two dimensions are equal.
56         type_check.expect(a_type.shape[-1] == a_type.shape[-2])
57 
58     def forward_cpu(self, x):
59         self.detx = utils.force_array(numpy.linalg.det(x[0]))
60         return self.detx,
61 
62     def forward_gpu(self, x):
63         self.detx, success = _det_gpu(x[0])
64         if not success:
65             raise ValueError('Singular Matrix')
66         return self.detx,
67 
68     def backward_cpu(self, x, gy):
69         x, = x
70         gy, = gy
71         grad = (gy[:, None, None] * self.detx[:, None, None] *
72                 numpy.linalg.inv(x.transpose((0, 2, 1))))
73         return utils.force_array(grad),
74 
75     def backward_gpu(self, x, gy):
76         x, = x
77         gy, = gy
78         grad = (gy[:, None, None] * self.detx[:, None, None] *
79                 inv._inv_gpu(x.transpose((0, 2, 1))))
80         return utils.force_array(grad),
81 
82 
83 def batch_det(a):
84     """Computes the determinant of a batch of square matrices.
85 
86     Args:
87         a (Variable): Input array to compute the determinant for.
88         The first dimension should iterate over each matrix and be
89         of the batchsize.
90 
91     Returns:
92         ~chainer.Variable: vector of determinants for every matrix
93         in the batch.
94 
95     """
96     return BatchDet()(a)
97 
98 
99 def det(a):
100     """Computes the determinant of a single square matrix.
101 
102     Args:
103         a (Variable): Input array to compute the determinant for.
104 
105     Returns:
106         ~chainer.Variable: Scalar determinant of the matrix a.
107 
108     """
109     shape = (1, len(a.data), a.data.shape[1])
110     batched_a = reshape.Reshape(shape)(a)
111     batched_det = BatchDet()(batched_a)
112     return reshape.Reshape(())(batched_det)
113
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/chainer/functions/math/det.py b/chainer/functions/math/det.py
--- a/chainer/functions/math/det.py
+++ b/chainer/functions/math/det.py
@@ -22,11 +22,11 @@
     # Output array
     # These arrays hold information on the execution success
     # or if the matrix was singular.
-    info1 = cuda.cupy.zeros(n_matrices, dtype=numpy.intp)
+    info = cuda.cupy.zeros(n_matrices, dtype=numpy.intp)
     ap = matmul._mat_ptrs(a)
     _, lda = matmul._get_ld(a)
     cuda.cublas.sgetrfBatched(cuda.Device().cublas_handle, n, ap.data.ptr, lda,
-                              p.data.ptr, info1.data.ptr, n_matrices)
+                              p.data.ptr, info.data.ptr, n_matrices)
     det = cuda.cupy.prod(a.diagonal(axis1=1, axis2=2), axis=1)
     # The determinant is equal to the product of the diagonal entries
     # of `a` where the sign of `a` is flipped depending on whether
@@ -34,8 +34,7 @@
     rng = cuda.cupy.arange(1, n + 1, dtype='int32')
     parity = cuda.cupy.sum(p != rng, axis=1) % 2
     sign = 1. - 2. * parity.astype('float32')
-    success = cuda.cupy.all(info1 == 0)
-    return det * sign, success
+    return det * sign, info
 
 
 class BatchDet(function.Function):
@@ -60,23 +59,26 @@
         return self.detx,
 
     def forward_gpu(self, x):
-        self.detx, success = _det_gpu(x[0])
-        if not success:
-            raise ValueError('Singular Matrix')
+        self.detx, _ = _det_gpu(x[0])
         return self.detx,
 
     def backward_cpu(self, x, gy):
         x, = x
         gy, = gy
-        grad = (gy[:, None, None] * self.detx[:, None, None] *
-                numpy.linalg.inv(x.transpose((0, 2, 1))))
+        try:
+            inv_x = numpy.linalg.inv(x.transpose((0, 2, 1)))
+        except numpy.linalg.LinAlgError:
+            raise ValueError('Input has singular matrices.')
+        grad = gy[:, None, None] * self.detx[:, None, None] * inv_x
         return utils.force_array(grad),
 
     def backward_gpu(self, x, gy):
         x, = x
         gy, = gy
-        grad = (gy[:, None, None] * self.detx[:, None, None] *
-                inv._inv_gpu(x.transpose((0, 2, 1))))
+        inv_x, info = inv._inv_gpu(x.transpose((0, 2, 1)))
+        if cuda.cupy.any(info != 0):
+            raise ValueError('Input has singular matrices.')
+        grad = gy[:, None, None] * self.detx[:, None, None] * inv_x
         return utils.force_array(grad),
 
 
diff --git a/chainer/functions/math/inv.py b/chainer/functions/math/inv.py
--- a/chainer/functions/math/inv.py
+++ b/chainer/functions/math/inv.py
@@ -32,7 +32,7 @@
     cuda.cublas.sgetriBatched(
         handle, n, ap.data.ptr, lda, p.data.ptr, cp.data.ptr, ldc,
         info.data.ptr, n_matrices)
-    return c
+    return c, info
 
 
 class Inv(function.Function):
@@ -52,7 +52,7 @@
 
     def forward_gpu(self, x):
         shape = x[0].shape
-        self.invx = _inv_gpu(x[0].reshape(1, *shape)).reshape(shape)
+        self.invx = _inv_gpu(x[0].reshape(1, *shape))[0].reshape(shape)
         return self.invx,
 
     def backward(self, x, gy):
@@ -80,7 +80,7 @@
         return self.invx,
 
     def forward_gpu(self, x):
-        self.invx = _inv_gpu(x[0])
+        self.invx, _ = _inv_gpu(x[0])
         return self.invx,
 
     def backward_cpu(self, x, gy):

{"golden_diff": "diff --git a/chainer/functions/math/det.py b/chainer/functions/math/det.py\n--- a/chainer/functions/math/det.py\n+++ b/chainer/functions/math/det.py\n@@ -22,11 +22,11 @@\n     # Output array\n     # These arrays hold information on the execution success\n     # or if the matrix was singular.\n-    info1 = cuda.cupy.zeros(n_matrices, dtype=numpy.intp)\n+    info = cuda.cupy.zeros(n_matrices, dtype=numpy.intp)\n     ap = matmul._mat_ptrs(a)\n     _, lda = matmul._get_ld(a)\n     cuda.cublas.sgetrfBatched(cuda.Device().cublas_handle, n, ap.data.ptr, lda,\n-                              p.data.ptr, info1.data.ptr, n_matrices)\n+                              p.data.ptr, info.data.ptr, n_matrices)\n     det = cuda.cupy.prod(a.diagonal(axis1=1, axis2=2), axis=1)\n     # The determinant is equal to the product of the diagonal entries\n     # of `a` where the sign of `a` is flipped depending on whether\n@@ -34,8 +34,7 @@\n     rng = cuda.cupy.arange(1, n + 1, dtype='int32')\n     parity = cuda.cupy.sum(p != rng, axis=1) % 2\n     sign = 1. - 2. * parity.astype('float32')\n-    success = cuda.cupy.all(info1 == 0)\n-    return det * sign, success\n+    return det * sign, info\n \n \n class BatchDet(function.Function):\n@@ -60,23 +59,26 @@\n         return self.detx,\n \n     def forward_gpu(self, x):\n-        self.detx, success = _det_gpu(x[0])\n-        if not success:\n-            raise ValueError('Singular Matrix')\n+        self.detx, _ = _det_gpu(x[0])\n         return self.detx,\n \n     def backward_cpu(self, x, gy):\n         x, = x\n         gy, = gy\n-        grad = (gy[:, None, None] * self.detx[:, None, None] *\n-                numpy.linalg.inv(x.transpose((0, 2, 1))))\n+        try:\n+            inv_x = numpy.linalg.inv(x.transpose((0, 2, 1)))\n+        except numpy.linalg.LinAlgError:\n+            raise ValueError('Input has singular matrices.')\n+        grad = gy[:, None, None] * self.detx[:, None, None] * inv_x\n         return utils.force_array(grad),\n \n     def backward_gpu(self, x, gy):\n         x, = x\n         gy, = gy\n-        grad = (gy[:, None, None] * self.detx[:, None, None] *\n-                inv._inv_gpu(x.transpose((0, 2, 1))))\n+        inv_x, info = inv._inv_gpu(x.transpose((0, 2, 1)))\n+        if cuda.cupy.any(info != 0):\n+            raise ValueError('Input has singular matrices.')\n+        grad = gy[:, None, None] * self.detx[:, None, None] * inv_x\n         return utils.force_array(grad),\n \n \ndiff --git a/chainer/functions/math/inv.py b/chainer/functions/math/inv.py\n--- a/chainer/functions/math/inv.py\n+++ b/chainer/functions/math/inv.py\n@@ -32,7 +32,7 @@\n     cuda.cublas.sgetriBatched(\n         handle, n, ap.data.ptr, lda, p.data.ptr, cp.data.ptr, ldc,\n         info.data.ptr, n_matrices)\n-    return c\n+    return c, info\n \n \n class Inv(function.Function):\n@@ -52,7 +52,7 @@\n \n     def forward_gpu(self, x):\n         shape = x[0].shape\n-        self.invx = _inv_gpu(x[0].reshape(1, *shape)).reshape(shape)\n+        self.invx = _inv_gpu(x[0].reshape(1, *shape))[0].reshape(shape)\n         return self.invx,\n \n     def backward(self, x, gy):\n@@ -80,7 +80,7 @@\n         return self.invx,\n \n     def forward_gpu(self, x):\n-        self.invx = _inv_gpu(x[0])\n+        self.invx, _ = _inv_gpu(x[0])\n         return self.invx,\n \n     def backward_cpu(self, x, gy):\n", "issue": "F.det should not raise error in forward propagation when input matrix is singular\nCurrently, `F.det` raises `ValueError` in forward propagation when input matrix is singular [here](https://github.com/pfnet/chainer/pull/613/files#diff-4d0027dd8b2ecc0d9eae073ddfefdb26R65).\n\nIt is beneficial when we do backward propagation because it calculates the inverse of the input matrix. But some users can use `F.det` without backward propagation, in which case singular matrices are not exceptional. So we should not raise errors.\n\n", "before_files": [{"content": "import numpy.linalg\nimport six\n\nfrom chainer import cuda\nfrom chainer import function\nfrom chainer.functions.math import matmul\nfrom chainer import utils\nfrom chainer.utils import type_check\n\n\ndef _inv_gpu(b):\n    # We do a batched LU decomposition on the GPU to compute the inverse\n    # Change the shape of the array to be size=1 minibatch if necessary\n    # Also copy the matrix as the elments will be modified in-place\n    a = matmul._as_batch_mat(b).copy()\n    n = a.shape[1]\n    n_matrices = len(a)\n    # Pivot array\n    p = cuda.cupy.empty((n, n_matrices), dtype='int32')\n    # Output array\n    c = cuda.cupy.empty_like(a)\n    # These arrays hold information on the execution success\n    # or if the matrix was singular\n    info = cuda.cupy.empty(n_matrices, dtype=numpy.intp)\n    ap = matmul._mat_ptrs(a)\n    cp = matmul._mat_ptrs(c)\n    _, lda = matmul._get_ld(a)\n    _, ldc = matmul._get_ld(c)\n    handle = cuda.Device().cublas_handle\n    cuda.cublas.sgetrfBatched(\n        handle, n, ap.data.ptr, lda, p.data.ptr, info.data.ptr, n_matrices)\n    cuda.cublas.sgetriBatched(\n        handle, n, ap.data.ptr, lda, p.data.ptr, cp.data.ptr, ldc,\n        info.data.ptr, n_matrices)\n    return c\n\n\nclass Inv(function.Function):\n\n    def check_type_forward(self, in_types):\n        type_check.expect(in_types.size() == 1)\n        a_type, = in_types\n        type_check.expect(a_type.dtype == numpy.float32)\n        # Only 2D array shapes allowed\n        type_check.expect(a_type.ndim == 2)\n        # Matrix inversion only allowed for square matrices\n        type_check.expect(a_type.shape[0] == a_type.shape[1])\n\n    def forward_cpu(self, x):\n        self.invx = utils.force_array(numpy.linalg.inv(x[0]))\n        return self.invx,\n\n    def forward_gpu(self, x):\n        shape = x[0].shape\n        self.invx = _inv_gpu(x[0].reshape(1, *shape)).reshape(shape)\n        return self.invx,\n\n    def backward(self, x, gy):\n        # Gradient is - x^-T (dx) x^-T\n        x, = x\n        xp = cuda.get_array_module(x)\n        gx = xp.dot(xp.dot(-self.invx.T, gy[0]), self.invx.T)\n        return gx,\n\n\nclass BatchInv(function.Function):\n\n    def check_type_forward(self, in_types):\n        type_check.expect(in_types.size() == 1)\n        a_type, = in_types\n        type_check.expect(a_type.dtype == numpy.float32)\n        # Only a minibatch of 2D array shapes allowed\n        type_check.expect(a_type.ndim == 3)\n        # Matrix inversion only allowed for square matrices\n        # so assert the last two dimensions are equal\n        type_check.expect(a_type.shape[-1] == a_type.shape[-2])\n\n    def forward_cpu(self, x):\n        self.invx = utils.force_array(numpy.linalg.inv(x[0]))\n        return self.invx,\n\n    def forward_gpu(self, x):\n        self.invx = _inv_gpu(x[0])\n        return self.invx,\n\n    def backward_cpu(self, x, gy):\n        # Gradient is - x^-T (dx) x^-T\n        x, = x\n        gy, = gy\n        batch_size = len(x)\n        gx = numpy.empty_like(x)\n        for i in six.moves.range(batch_size):\n            gx[i] = numpy.dot(-self.invx[i].T, gy[i])\n            gx[i] = numpy.dot(gx[i], self.invx[i].T)\n        return gx,\n\n    def backward_gpu(self, x, gy):\n        # Unpack 1-length tuples\n        gy, = gy\n        shape = gy.shape\n        dtype = x[0].dtype\n        ret = cuda.cupy.empty(shape, dtype)\n        matmul._batch_matmul_gpu(-self.invx, gy, out=ret, transa=True)\n        ret2 = cuda.cupy.empty(shape, dtype)\n        matmul._batch_matmul_gpu(ret, self.invx, out=ret2, transb=True)\n        return ret2,\n\n\ndef inv(a):\n    \"\"\"Computes the inverse of of square matrix.\n\n    Args:\n        a (Variable): Input array to compute the determinant for.\n        Shape of the array should be ``(n, n)`` where ``n`` is the\n        dimensionality of a square matrix.\n\n    Returns:\n        ~chainer.Variable: Matrix inverse of ``a``.\n    \"\"\"\n    return Inv()(a)\n\n\ndef batch_inv(a):\n    \"\"\"Computes the inverse of a batch of square matrices.\n\n    Args:\n        a (Variable): Input array to compute the determinant for.\n        Shape of the array should be ``(m, n, n)`` where m is the number\n        of matrices in the batch, and ``n`` is the dimensionality of a square\n        matrix.\n\n    Returns:\n        ~chainer.Variable: Inverse of every matrix in the batch of matrices.\n    \"\"\"\n    return BatchInv()(a)\n", "path": "chainer/functions/math/inv.py"}, {"content": "import numpy\n\nfrom chainer import cuda\nfrom chainer import function\nfrom chainer.functions.array import reshape\nfrom chainer.functions.math import inv\nfrom chainer.functions.math import matmul\nfrom chainer import utils\nfrom chainer.utils import type_check\n\n\ndef _det_gpu(b):\n    # We do a batched LU decomposition on the GPU to compute\n    # and compute the determinant by multiplying the diagonal.\n    # Change the shape of the array to be size=1 minibatch if necessary.\n    # Also copy the matrix as the elments will be modified in-place.\n    a = matmul._as_batch_mat(b).copy()\n    n = a.shape[1]\n    n_matrices = len(a)\n    # Pivot array\n    p = cuda.cupy.zeros((n_matrices, n), dtype='int32')\n    # Output array\n    # These arrays hold information on the execution success\n    # or if the matrix was singular.\n    info1 = cuda.cupy.zeros(n_matrices, dtype=numpy.intp)\n    ap = matmul._mat_ptrs(a)\n    _, lda = matmul._get_ld(a)\n    cuda.cublas.sgetrfBatched(cuda.Device().cublas_handle, n, ap.data.ptr, lda,\n                              p.data.ptr, info1.data.ptr, n_matrices)\n    det = cuda.cupy.prod(a.diagonal(axis1=1, axis2=2), axis=1)\n    # The determinant is equal to the product of the diagonal entries\n    # of `a` where the sign of `a` is flipped depending on whether\n    # the pivot array is equal to its index.\n    rng = cuda.cupy.arange(1, n + 1, dtype='int32')\n    parity = cuda.cupy.sum(p != rng, axis=1) % 2\n    sign = 1. - 2. * parity.astype('float32')\n    success = cuda.cupy.all(info1 == 0)\n    return det * sign, success\n\n\nclass BatchDet(function.Function):\n\n    @property\n    def label(self):\n        return 'det'\n\n    def check_type_forward(self, in_types):\n        type_check.expect(in_types.size() == 1)\n        a_type, = in_types\n        a_type = matmul._convert_type(a_type)\n        type_check.expect(a_type.dtype.kind == 'f')\n        # Only a minibatch of 2D array shapes allowed.\n        type_check.expect(a_type.ndim == 3)\n        # Matrix inversion only allowed for square matrices\n        # so assert the last two dimensions are equal.\n        type_check.expect(a_type.shape[-1] == a_type.shape[-2])\n\n    def forward_cpu(self, x):\n        self.detx = utils.force_array(numpy.linalg.det(x[0]))\n        return self.detx,\n\n    def forward_gpu(self, x):\n        self.detx, success = _det_gpu(x[0])\n        if not success:\n            raise ValueError('Singular Matrix')\n        return self.detx,\n\n    def backward_cpu(self, x, gy):\n        x, = x\n        gy, = gy\n        grad = (gy[:, None, None] * self.detx[:, None, None] *\n                numpy.linalg.inv(x.transpose((0, 2, 1))))\n        return utils.force_array(grad),\n\n    def backward_gpu(self, x, gy):\n        x, = x\n        gy, = gy\n        grad = (gy[:, None, None] * self.detx[:, None, None] *\n                inv._inv_gpu(x.transpose((0, 2, 1))))\n        return utils.force_array(grad),\n\n\ndef batch_det(a):\n    \"\"\"Computes the determinant of a batch of square matrices.\n\n    Args:\n        a (Variable): Input array to compute the determinant for.\n        The first dimension should iterate over each matrix and be\n        of the batchsize.\n\n    Returns:\n        ~chainer.Variable: vector of determinants for every matrix\n        in the batch.\n\n    \"\"\"\n    return BatchDet()(a)\n\n\ndef det(a):\n    \"\"\"Computes the determinant of a single square matrix.\n\n    Args:\n        a (Variable): Input array to compute the determinant for.\n\n    Returns:\n        ~chainer.Variable: Scalar determinant of the matrix a.\n\n    \"\"\"\n    shape = (1, len(a.data), a.data.shape[1])\n    batched_a = reshape.Reshape(shape)(a)\n    batched_det = BatchDet()(batched_a)\n    return reshape.Reshape(())(batched_det)\n", "path": "chainer/functions/math/det.py"}], "after_files": [{"content": "import numpy.linalg\nimport six\n\nfrom chainer import cuda\nfrom chainer import function\nfrom chainer.functions.math import matmul\nfrom chainer import utils\nfrom chainer.utils import type_check\n\n\ndef _inv_gpu(b):\n    # We do a batched LU decomposition on the GPU to compute the inverse\n    # Change the shape of the array to be size=1 minibatch if necessary\n    # Also copy the matrix as the elments will be modified in-place\n    a = matmul._as_batch_mat(b).copy()\n    n = a.shape[1]\n    n_matrices = len(a)\n    # Pivot array\n    p = cuda.cupy.empty((n, n_matrices), dtype='int32')\n    # Output array\n    c = cuda.cupy.empty_like(a)\n    # These arrays hold information on the execution success\n    # or if the matrix was singular\n    info = cuda.cupy.empty(n_matrices, dtype=numpy.intp)\n    ap = matmul._mat_ptrs(a)\n    cp = matmul._mat_ptrs(c)\n    _, lda = matmul._get_ld(a)\n    _, ldc = matmul._get_ld(c)\n    handle = cuda.Device().cublas_handle\n    cuda.cublas.sgetrfBatched(\n        handle, n, ap.data.ptr, lda, p.data.ptr, info.data.ptr, n_matrices)\n    cuda.cublas.sgetriBatched(\n        handle, n, ap.data.ptr, lda, p.data.ptr, cp.data.ptr, ldc,\n        info.data.ptr, n_matrices)\n    return c, info\n\n\nclass Inv(function.Function):\n\n    def check_type_forward(self, in_types):\n        type_check.expect(in_types.size() == 1)\n        a_type, = in_types\n        type_check.expect(a_type.dtype == numpy.float32)\n        # Only 2D array shapes allowed\n        type_check.expect(a_type.ndim == 2)\n        # Matrix inversion only allowed for square matrices\n        type_check.expect(a_type.shape[0] == a_type.shape[1])\n\n    def forward_cpu(self, x):\n        self.invx = utils.force_array(numpy.linalg.inv(x[0]))\n        return self.invx,\n\n    def forward_gpu(self, x):\n        shape = x[0].shape\n        self.invx = _inv_gpu(x[0].reshape(1, *shape))[0].reshape(shape)\n        return self.invx,\n\n    def backward(self, x, gy):\n        # Gradient is - x^-T (dx) x^-T\n        x, = x\n        xp = cuda.get_array_module(x)\n        gx = xp.dot(xp.dot(-self.invx.T, gy[0]), self.invx.T)\n        return gx,\n\n\nclass BatchInv(function.Function):\n\n    def check_type_forward(self, in_types):\n        type_check.expect(in_types.size() == 1)\n        a_type, = in_types\n        type_check.expect(a_type.dtype == numpy.float32)\n        # Only a minibatch of 2D array shapes allowed\n        type_check.expect(a_type.ndim == 3)\n        # Matrix inversion only allowed for square matrices\n        # so assert the last two dimensions are equal\n        type_check.expect(a_type.shape[-1] == a_type.shape[-2])\n\n    def forward_cpu(self, x):\n        self.invx = utils.force_array(numpy.linalg.inv(x[0]))\n        return self.invx,\n\n    def forward_gpu(self, x):\n        self.invx, _ = _inv_gpu(x[0])\n        return self.invx,\n\n    def backward_cpu(self, x, gy):\n        # Gradient is - x^-T (dx) x^-T\n        x, = x\n        gy, = gy\n        batch_size = len(x)\n        gx = numpy.empty_like(x)\n        for i in six.moves.range(batch_size):\n            gx[i] = numpy.dot(-self.invx[i].T, gy[i])\n            gx[i] = numpy.dot(gx[i], self.invx[i].T)\n        return gx,\n\n    def backward_gpu(self, x, gy):\n        # Unpack 1-length tuples\n        gy, = gy\n        shape = gy.shape\n        dtype = x[0].dtype\n        ret = cuda.cupy.empty(shape, dtype)\n        matmul._batch_matmul_gpu(-self.invx, gy, out=ret, transa=True)\n        ret2 = cuda.cupy.empty(shape, dtype)\n        matmul._batch_matmul_gpu(ret, self.invx, out=ret2, transb=True)\n        return ret2,\n\n\ndef inv(a):\n    \"\"\"Computes the inverse of of square matrix.\n\n    Args:\n        a (Variable): Input array to compute the determinant for.\n        Shape of the array should be ``(n, n)`` where ``n`` is the\n        dimensionality of a square matrix.\n\n    Returns:\n        ~chainer.Variable: Matrix inverse of ``a``.\n    \"\"\"\n    return Inv()(a)\n\n\ndef batch_inv(a):\n    \"\"\"Computes the inverse of a batch of square matrices.\n\n    Args:\n        a (Variable): Input array to compute the determinant for.\n        Shape of the array should be ``(m, n, n)`` where m is the number\n        of matrices in the batch, and ``n`` is the dimensionality of a square\n        matrix.\n\n    Returns:\n        ~chainer.Variable: Inverse of every matrix in the batch of matrices.\n    \"\"\"\n    return BatchInv()(a)\n", "path": "chainer/functions/math/inv.py"}, {"content": "import numpy\n\nfrom chainer import cuda\nfrom chainer import function\nfrom chainer.functions.array import reshape\nfrom chainer.functions.math import inv\nfrom chainer.functions.math import matmul\nfrom chainer import utils\nfrom chainer.utils import type_check\n\n\ndef _det_gpu(b):\n    # We do a batched LU decomposition on the GPU to compute\n    # and compute the determinant by multiplying the diagonal.\n    # Change the shape of the array to be size=1 minibatch if necessary.\n    # Also copy the matrix as the elments will be modified in-place.\n    a = matmul._as_batch_mat(b).copy()\n    n = a.shape[1]\n    n_matrices = len(a)\n    # Pivot array\n    p = cuda.cupy.zeros((n_matrices, n), dtype='int32')\n    # Output array\n    # These arrays hold information on the execution success\n    # or if the matrix was singular.\n    info = cuda.cupy.zeros(n_matrices, dtype=numpy.intp)\n    ap = matmul._mat_ptrs(a)\n    _, lda = matmul._get_ld(a)\n    cuda.cublas.sgetrfBatched(cuda.Device().cublas_handle, n, ap.data.ptr, lda,\n                              p.data.ptr, info.data.ptr, n_matrices)\n    det = cuda.cupy.prod(a.diagonal(axis1=1, axis2=2), axis=1)\n    # The determinant is equal to the product of the diagonal entries\n    # of `a` where the sign of `a` is flipped depending on whether\n    # the pivot array is equal to its index.\n    rng = cuda.cupy.arange(1, n + 1, dtype='int32')\n    parity = cuda.cupy.sum(p != rng, axis=1) % 2\n    sign = 1. - 2. * parity.astype('float32')\n    return det * sign, info\n\n\nclass BatchDet(function.Function):\n\n    @property\n    def label(self):\n        return 'det'\n\n    def check_type_forward(self, in_types):\n        type_check.expect(in_types.size() == 1)\n        a_type, = in_types\n        a_type = matmul._convert_type(a_type)\n        type_check.expect(a_type.dtype.kind == 'f')\n        # Only a minibatch of 2D array shapes allowed.\n        type_check.expect(a_type.ndim == 3)\n        # Matrix inversion only allowed for square matrices\n        # so assert the last two dimensions are equal.\n        type_check.expect(a_type.shape[-1] == a_type.shape[-2])\n\n    def forward_cpu(self, x):\n        self.detx = utils.force_array(numpy.linalg.det(x[0]))\n        return self.detx,\n\n    def forward_gpu(self, x):\n        self.detx, _ = _det_gpu(x[0])\n        return self.detx,\n\n    def backward_cpu(self, x, gy):\n        x, = x\n        gy, = gy\n        try:\n            inv_x = numpy.linalg.inv(x.transpose((0, 2, 1)))\n        except numpy.linalg.LinAlgError:\n            raise ValueError('Input has singular matrices.')\n        grad = gy[:, None, None] * self.detx[:, None, None] * inv_x\n        return utils.force_array(grad),\n\n    def backward_gpu(self, x, gy):\n        x, = x\n        gy, = gy\n        inv_x, info = inv._inv_gpu(x.transpose((0, 2, 1)))\n        if cuda.cupy.any(info != 0):\n            raise ValueError('Input has singular matrices.')\n        grad = gy[:, None, None] * self.detx[:, None, None] * inv_x\n        return utils.force_array(grad),\n\n\ndef batch_det(a):\n    \"\"\"Computes the determinant of a batch of square matrices.\n\n    Args:\n        a (Variable): Input array to compute the determinant for.\n        The first dimension should iterate over each matrix and be\n        of the batchsize.\n\n    Returns:\n        ~chainer.Variable: vector of determinants for every matrix\n        in the batch.\n\n    \"\"\"\n    return BatchDet()(a)\n\n\ndef det(a):\n    \"\"\"Computes the determinant of a single square matrix.\n\n    Args:\n        a (Variable): Input array to compute the determinant for.\n\n    Returns:\n        ~chainer.Variable: Scalar determinant of the matrix a.\n\n    \"\"\"\n    shape = (1, len(a.data), a.data.shape[1])\n    batched_a = reshape.Reshape(shape)(a)\n    batched_det = BatchDet()(batched_a)\n    return reshape.Reshape(())(batched_det)\n", "path": "chainer/functions/math/det.py"}]}