We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
cupy.linalg.norm returns complex scalar for complex input
```python
>>> a = cupy.array([1j, 2, 3])
>>> a.dtype
dtype('complex128')
>>> cupy.linalg.norm(a).dtype
dtype('complex128')
```
It should be `float64` in this case.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `cupy/linalg/norms.py`
Content:
```
1 import numpy
2 from numpy import linalg
3 
4 import cupy
5 from cupy import cuda
6 from cupy.cuda import device
7 from cupy.linalg import decomposition
8 from cupy.linalg import util
9 
10 
11 if cuda.cusolver_enabled:
12     from cupy.cuda import cusolver
13 
14 
15 def norm(x, ord=None, axis=None, keepdims=False):
16     """Returns one of matrix norms specified by ``ord`` parameter.
17 
18     Complex valued matrices and vectors are not supported.
19     See numpy.linalg.norm for more detail.
20 
21     Args:
22         x (cupy.ndarray): Array to take norm. If ``axis`` is None,
23             ``x`` must be 1-D or 2-D.
24         ord (non-zero int, inf, -inf, 'fro'): Norm type.
25         axis (int, 2-tuple of ints, None): 1-D or 2-D norm is cumputed over
26             ``axis``.
27         keepdims (bool): If this is set ``True``, the axes which are normed
28             over are left.
29 
30     Returns:
31         cupy.ndarray
32 
33     """
34     if not issubclass(x.dtype.type, numpy.inexact):
35         x = x.astype(float)
36 
37     # Immediately handle some default, simple, fast, and common cases.
38     if axis is None:
39         ndim = x.ndim
40         if (ord is None or (ndim == 1 and ord == 2) or
41                 (ndim == 2 and ord in ('f', 'fro'))):
42             ret = cupy.sqrt(cupy.sum(x.ravel() ** 2))
43             if keepdims:
44                 ret = ret.reshape((1,) * ndim)
45             return ret
46 
47     # Normalize the `axis` argument to a tuple.
48     nd = x.ndim
49     if axis is None:
50         axis = tuple(range(nd))
51     elif not isinstance(axis, tuple):
52         try:
53             axis = int(axis)
54         except Exception:
55             raise TypeError(
56                 "'axis' must be None, an integer or a tuple of integers")
57         axis = (axis,)
58 
59     if len(axis) == 1:
60         if ord == numpy.Inf:
61             return abs(x).max(axis=axis, keepdims=keepdims)
62         elif ord == -numpy.Inf:
63             return abs(x).min(axis=axis, keepdims=keepdims)
64         elif ord == 0:
65             # Zero norm
66             # Convert to Python float in accordance with NumPy
67             return (x != 0).sum(axis=axis, keepdims=keepdims, dtype='d')
68         elif ord == 1:
69             # special case for speedup
70             return abs(x).sum(axis=axis, keepdims=keepdims)
71         elif ord is None or ord == 2:
72             # special case for speedup
73             s = x ** 2
74             return cupy.sqrt(s.sum(axis=axis, keepdims=keepdims))
75         else:
76             try:
77                 float(ord)
78             except TypeError:
79                 raise ValueError("Invalid norm order for vectors.")
80             absx = abs(x).astype('d')
81             absx **= ord
82             ret = absx.sum(axis=axis, keepdims=keepdims)
83             ret **= (1.0 / ord)
84             return ret
85     elif len(axis) == 2:
86         row_axis, col_axis = axis
87         if row_axis < 0:
88             row_axis += nd
89         if col_axis < 0:
90             col_axis += nd
91         if not (0 <= row_axis < nd and 0 <= col_axis < nd):
92             raise ValueError('Invalid axis %r for an array with shape %r' %
93                              (axis, x.shape))
94         if row_axis == col_axis:
95             raise ValueError('Duplicate axes given.')
96         if ord == 1:
97             if col_axis > row_axis:
98                 col_axis -= 1
99             ret = abs(x).sum(axis=row_axis).max(axis=col_axis)
100         elif ord == numpy.Inf:
101             if row_axis > col_axis:
102                 row_axis -= 1
103             ret = abs(x).sum(axis=col_axis).max(axis=row_axis)
104         elif ord == -1:
105             if col_axis > row_axis:
106                 col_axis -= 1
107             ret = abs(x).sum(axis=row_axis).min(axis=col_axis)
108         elif ord == -numpy.Inf:
109             if row_axis > col_axis:
110                 row_axis -= 1
111             ret = abs(x).sum(axis=col_axis).min(axis=row_axis)
112         elif ord in [None, 'fro', 'f']:
113             ret = cupy.sqrt((x ** 2).sum(axis=axis))
114         else:
115             raise ValueError("Invalid norm order for matrices.")
116         if keepdims:
117             ret_shape = list(x.shape)
118             ret_shape[axis[0]] = 1
119             ret_shape[axis[1]] = 1
120             ret = ret.reshape(ret_shape)
121         return ret
122     else:
123         raise ValueError("Improper number of dimensions to norm.")
124 
125 
126 # TODO(okuta): Implement cond
127 
128 
129 def det(a):
130     """Retruns the deteminant of an array.
131 
132     Args:
133         a (cupy.ndarray): The input matrix with dimension ``(..., N, N)``.
134 
135     Returns:
136         cupy.ndarray: Determinant of ``a``. Its shape is ``a.shape[:-2]``.
137 
138     .. seealso:: :func:`numpy.linalg.det`
139     """
140     sign, logdet = slogdet(a)
141     return sign * cupy.exp(logdet)
142 
143 
144 def matrix_rank(M, tol=None):
145     """Return matrix rank of array using SVD method
146 
147     Args:
148         M (cupy.ndarray): Input array. Its `ndim` must be less than or equal to
149             2.
150         tol (None or float): Threshold of singular value of `M`.
151             When `tol` is `None`, and `eps` is the epsilon value for datatype
152             of `M`, then `tol` is set to `S.max() * max(M.shape) * eps`,
153             where `S` is the singular value of `M`.
154             It obeys :func:`numpy.linalg.matrix_rank`.
155 
156     Returns:
157         cupy.ndarray: Rank of `M`.
158 
159     .. seealso:: :func:`numpy.linalg.matrix_rank`
160     """
161     if M.ndim < 2:
162         return (M != 0).any().astype('l')
163     S = decomposition.svd(M, compute_uv=False)
164     if tol is None:
165         tol = (S.max(axis=-1, keepdims=True) * max(M.shape[-2:]) *
166                numpy.finfo(S.dtype).eps)
167     return (S > tol).sum(axis=-1)
168 
169 
170 def slogdet(a):
171     """Returns sign and logarithm of the determinat of an array.
172 
173     It calculates the natural logarithm of the deteminant of a given value.
174 
175     Args:
176         a (cupy.ndarray): The input matrix with dimension ``(..., N, N)``.
177 
178     Returns:
179         tuple of :class:`~cupy.ndarray`:
180             It returns a tuple ``(sign, logdet)``. ``sign`` represents each
181             sign of the deteminant as a real number ``0``, ``1`` or ``-1``.
182             'logdet' represents the natural logarithm of the absolute of the
183             deteminant.
184             If the deteninant is zero, ``sign`` will be ``0`` and ``logdet``
185             will be ``-inf``.
186             The shapes of both ``sign`` and ``logdet`` are equal to
187             ``a.shape[:-2]``.
188 
189     .. seealso:: :func:`numpy.linalg.slogdet`
190     """
191     if not cuda.cusolver_enabled:
192         raise RuntimeError('Current cupy only supports cusolver in CUDA 8.0')
193 
194     if a.ndim < 2:
195         msg = ('%d-dimensional array given. '
196                'Array must be at least two-dimensional' % a.ndim)
197         raise linalg.LinAlgError(msg)
198 
199     dtype = numpy.find_common_type((a.dtype.char, 'f'), ())
200     shape = a.shape[:-2]
201     sign = cupy.empty(shape, dtype)
202     logdet = cupy.empty(shape, dtype)
203 
204     a = a.astype(dtype)
205     for index in numpy.ndindex(*shape):
206         s, l = _slogdet_one(a[index])
207         sign[index] = s
208         logdet[index] = l
209     return sign, logdet
210 
211 
212 def _slogdet_one(a):
213     util._assert_rank2(a)
214     util._assert_nd_squareness(a)
215     dtype = a.dtype
216 
217     handle = device.get_cusolver_handle()
218     m = len(a)
219     ipiv = cupy.empty(m, 'i')
220     info = cupy.empty((), 'i')
221 
222     # Need to make a copy because getrf works inplace
223     a_copy = a.copy(order='F')
224 
225     if dtype == 'f':
226         getrf_bufferSize = cusolver.sgetrf_bufferSize
227         getrf = cusolver.sgetrf
228     else:
229         getrf_bufferSize = cusolver.dgetrf_bufferSize
230         getrf = cusolver.dgetrf
231 
232     buffersize = getrf_bufferSize(handle, m, m, a_copy.data.ptr, m)
233     workspace = cupy.empty(buffersize, dtype=dtype)
234     getrf(handle, m, m, a_copy.data.ptr, m, workspace.data.ptr,
235           ipiv.data.ptr, info.data.ptr)
236 
237     if info[()] == 0:
238         diag = cupy.diag(a_copy)
239         # ipiv is 1-origin
240         non_zero = (cupy.count_nonzero(ipiv != cupy.arange(1, m + 1)) +
241                     cupy.count_nonzero(diag < 0))
242         # Note: sign == -1 ** (non_zero % 2)
243         sign = (non_zero % 2) * -2 + 1
244         logdet = cupy.log(abs(diag)).sum()
245     else:
246         sign = cupy.array(0.0, dtype=dtype)
247         logdet = cupy.array(float('-inf'), dtype)
248 
249     return sign, logdet
250 
251 
252 def trace(a, offset=0, axis1=0, axis2=1, dtype=None, out=None):
253     """Returns the sum along the diagonals of an array.
254 
255     It computes the sum along the diagonals at ``axis1`` and ``axis2``.
256 
257     Args:
258         a (cupy.ndarray): Array to take trace.
259         offset (int): Index of diagonals. Zero indicates the main diagonal, a
260             positive value an upper diagonal, and a negative value a lower
261             diagonal.
262         axis1 (int): The first axis along which the trace is taken.
263         axis2 (int): The second axis along which the trace is taken.
264         dtype: Data type specifier of the output.
265         out (cupy.ndarray): Output array.
266 
267     Returns:
268         cupy.ndarray: The trace of ``a`` along axes ``(axis1, axis2)``.
269 
270     .. seealso:: :func:`numpy.trace`
271 
272     """
273     # TODO(okuta): check type
274     return a.trace(offset, axis1, axis2, dtype, out)
275
```
--- 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/cupy/linalg/norms.py b/cupy/linalg/norms.py
--- a/cupy/linalg/norms.py
+++ b/cupy/linalg/norms.py
@@ -39,7 +39,12 @@
         ndim = x.ndim
         if (ord is None or (ndim == 1 and ord == 2) or
                 (ndim == 2 and ord in ('f', 'fro'))):
-            ret = cupy.sqrt(cupy.sum(x.ravel() ** 2))
+            if issubclass(x.dtype.type, numpy.complexfloating):
+                s = abs(x.ravel())
+                s *= s
+                ret = cupy.sqrt(s.sum())
+            else:
+                ret = cupy.sqrt((x.ravel() ** 2).sum())
             if keepdims:
                 ret = ret.reshape((1,) * ndim)
             return ret
@@ -70,14 +75,27 @@
             return abs(x).sum(axis=axis, keepdims=keepdims)
         elif ord is None or ord == 2:
             # special case for speedup
-            s = x ** 2
+            if issubclass(x.dtype.type, numpy.complexfloating):
+                s = abs(x)
+                s *= s
+            else:
+                s = x ** 2
             return cupy.sqrt(s.sum(axis=axis, keepdims=keepdims))
         else:
             try:
                 float(ord)
             except TypeError:
                 raise ValueError("Invalid norm order for vectors.")
-            absx = abs(x).astype('d')
+
+            # Mirror Numpy behavior of casting to double for non-complex
+            # dtypes, and to float32 or float64 for complex dtypes and
+            # no reduction over all axes.
+            cast_dtype = 'd'
+            if issubclass(x.dtype.type, numpy.complexfloating):
+                if keepdims or tuple(sorted(axis)) != tuple(range(nd)):
+                    cast_dtype = x.dtype.char.lower()  # 'D'->'d' and 'F'->'f'
+
+            absx = abs(x).astype(cast_dtype)
             absx **= ord
             ret = absx.sum(axis=axis, keepdims=keepdims)
             ret **= (1.0 / ord)
@@ -110,7 +128,12 @@
                 row_axis -= 1
             ret = abs(x).sum(axis=col_axis).min(axis=row_axis)
         elif ord in [None, 'fro', 'f']:
-            ret = cupy.sqrt((x ** 2).sum(axis=axis))
+            if issubclass(x.dtype.type, numpy.complexfloating):
+                s = abs(x)
+                s *= s
+                ret = cupy.sqrt(s.sum(axis=axis))
+            else:
+                ret = cupy.sqrt((x ** 2).sum(axis=axis))
         else:
             raise ValueError("Invalid norm order for matrices.")
         if keepdims:

{"golden_diff": "diff --git a/cupy/linalg/norms.py b/cupy/linalg/norms.py\n--- a/cupy/linalg/norms.py\n+++ b/cupy/linalg/norms.py\n@@ -39,7 +39,12 @@\n         ndim = x.ndim\n         if (ord is None or (ndim == 1 and ord == 2) or\n                 (ndim == 2 and ord in ('f', 'fro'))):\n-            ret = cupy.sqrt(cupy.sum(x.ravel() ** 2))\n+            if issubclass(x.dtype.type, numpy.complexfloating):\n+                s = abs(x.ravel())\n+                s *= s\n+                ret = cupy.sqrt(s.sum())\n+            else:\n+                ret = cupy.sqrt((x.ravel() ** 2).sum())\n             if keepdims:\n                 ret = ret.reshape((1,) * ndim)\n             return ret\n@@ -70,14 +75,27 @@\n             return abs(x).sum(axis=axis, keepdims=keepdims)\n         elif ord is None or ord == 2:\n             # special case for speedup\n-            s = x ** 2\n+            if issubclass(x.dtype.type, numpy.complexfloating):\n+                s = abs(x)\n+                s *= s\n+            else:\n+                s = x ** 2\n             return cupy.sqrt(s.sum(axis=axis, keepdims=keepdims))\n         else:\n             try:\n                 float(ord)\n             except TypeError:\n                 raise ValueError(\"Invalid norm order for vectors.\")\n-            absx = abs(x).astype('d')\n+\n+            # Mirror Numpy behavior of casting to double for non-complex\n+            # dtypes, and to float32 or float64 for complex dtypes and\n+            # no reduction over all axes.\n+            cast_dtype = 'd'\n+            if issubclass(x.dtype.type, numpy.complexfloating):\n+                if keepdims or tuple(sorted(axis)) != tuple(range(nd)):\n+                    cast_dtype = x.dtype.char.lower()  # 'D'->'d' and 'F'->'f'\n+\n+            absx = abs(x).astype(cast_dtype)\n             absx **= ord\n             ret = absx.sum(axis=axis, keepdims=keepdims)\n             ret **= (1.0 / ord)\n@@ -110,7 +128,12 @@\n                 row_axis -= 1\n             ret = abs(x).sum(axis=col_axis).min(axis=row_axis)\n         elif ord in [None, 'fro', 'f']:\n-            ret = cupy.sqrt((x ** 2).sum(axis=axis))\n+            if issubclass(x.dtype.type, numpy.complexfloating):\n+                s = abs(x)\n+                s *= s\n+                ret = cupy.sqrt(s.sum(axis=axis))\n+            else:\n+                ret = cupy.sqrt((x ** 2).sum(axis=axis))\n         else:\n             raise ValueError(\"Invalid norm order for matrices.\")\n         if keepdims:\n", "issue": "cupy.linalg.norm returns complex scalar for complex input\n```python\r\n>>> a = cupy.array([1j, 2, 3])\r\n>>> a.dtype\r\ndtype('complex128')\r\n>>> cupy.linalg.norm(a).dtype\r\ndtype('complex128')\r\n```\r\nIt should be `float64` in this case.\n", "before_files": [{"content": "import numpy\nfrom numpy import linalg\n\nimport cupy\nfrom cupy import cuda\nfrom cupy.cuda import device\nfrom cupy.linalg import decomposition\nfrom cupy.linalg import util\n\n\nif cuda.cusolver_enabled:\n    from cupy.cuda import cusolver\n\n\ndef norm(x, ord=None, axis=None, keepdims=False):\n    \"\"\"Returns one of matrix norms specified by ``ord`` parameter.\n\n    Complex valued matrices and vectors are not supported.\n    See numpy.linalg.norm for more detail.\n\n    Args:\n        x (cupy.ndarray): Array to take norm. If ``axis`` is None,\n            ``x`` must be 1-D or 2-D.\n        ord (non-zero int, inf, -inf, 'fro'): Norm type.\n        axis (int, 2-tuple of ints, None): 1-D or 2-D norm is cumputed over\n            ``axis``.\n        keepdims (bool): If this is set ``True``, the axes which are normed\n            over are left.\n\n    Returns:\n        cupy.ndarray\n\n    \"\"\"\n    if not issubclass(x.dtype.type, numpy.inexact):\n        x = x.astype(float)\n\n    # Immediately handle some default, simple, fast, and common cases.\n    if axis is None:\n        ndim = x.ndim\n        if (ord is None or (ndim == 1 and ord == 2) or\n                (ndim == 2 and ord in ('f', 'fro'))):\n            ret = cupy.sqrt(cupy.sum(x.ravel() ** 2))\n            if keepdims:\n                ret = ret.reshape((1,) * ndim)\n            return ret\n\n    # Normalize the `axis` argument to a tuple.\n    nd = x.ndim\n    if axis is None:\n        axis = tuple(range(nd))\n    elif not isinstance(axis, tuple):\n        try:\n            axis = int(axis)\n        except Exception:\n            raise TypeError(\n                \"'axis' must be None, an integer or a tuple of integers\")\n        axis = (axis,)\n\n    if len(axis) == 1:\n        if ord == numpy.Inf:\n            return abs(x).max(axis=axis, keepdims=keepdims)\n        elif ord == -numpy.Inf:\n            return abs(x).min(axis=axis, keepdims=keepdims)\n        elif ord == 0:\n            # Zero norm\n            # Convert to Python float in accordance with NumPy\n            return (x != 0).sum(axis=axis, keepdims=keepdims, dtype='d')\n        elif ord == 1:\n            # special case for speedup\n            return abs(x).sum(axis=axis, keepdims=keepdims)\n        elif ord is None or ord == 2:\n            # special case for speedup\n            s = x ** 2\n            return cupy.sqrt(s.sum(axis=axis, keepdims=keepdims))\n        else:\n            try:\n                float(ord)\n            except TypeError:\n                raise ValueError(\"Invalid norm order for vectors.\")\n            absx = abs(x).astype('d')\n            absx **= ord\n            ret = absx.sum(axis=axis, keepdims=keepdims)\n            ret **= (1.0 / ord)\n            return ret\n    elif len(axis) == 2:\n        row_axis, col_axis = axis\n        if row_axis < 0:\n            row_axis += nd\n        if col_axis < 0:\n            col_axis += nd\n        if not (0 <= row_axis < nd and 0 <= col_axis < nd):\n            raise ValueError('Invalid axis %r for an array with shape %r' %\n                             (axis, x.shape))\n        if row_axis == col_axis:\n            raise ValueError('Duplicate axes given.')\n        if ord == 1:\n            if col_axis > row_axis:\n                col_axis -= 1\n            ret = abs(x).sum(axis=row_axis).max(axis=col_axis)\n        elif ord == numpy.Inf:\n            if row_axis > col_axis:\n                row_axis -= 1\n            ret = abs(x).sum(axis=col_axis).max(axis=row_axis)\n        elif ord == -1:\n            if col_axis > row_axis:\n                col_axis -= 1\n            ret = abs(x).sum(axis=row_axis).min(axis=col_axis)\n        elif ord == -numpy.Inf:\n            if row_axis > col_axis:\n                row_axis -= 1\n            ret = abs(x).sum(axis=col_axis).min(axis=row_axis)\n        elif ord in [None, 'fro', 'f']:\n            ret = cupy.sqrt((x ** 2).sum(axis=axis))\n        else:\n            raise ValueError(\"Invalid norm order for matrices.\")\n        if keepdims:\n            ret_shape = list(x.shape)\n            ret_shape[axis[0]] = 1\n            ret_shape[axis[1]] = 1\n            ret = ret.reshape(ret_shape)\n        return ret\n    else:\n        raise ValueError(\"Improper number of dimensions to norm.\")\n\n\n# TODO(okuta): Implement cond\n\n\ndef det(a):\n    \"\"\"Retruns the deteminant of an array.\n\n    Args:\n        a (cupy.ndarray): The input matrix with dimension ``(..., N, N)``.\n\n    Returns:\n        cupy.ndarray: Determinant of ``a``. Its shape is ``a.shape[:-2]``.\n\n    .. seealso:: :func:`numpy.linalg.det`\n    \"\"\"\n    sign, logdet = slogdet(a)\n    return sign * cupy.exp(logdet)\n\n\ndef matrix_rank(M, tol=None):\n    \"\"\"Return matrix rank of array using SVD method\n\n    Args:\n        M (cupy.ndarray): Input array. Its `ndim` must be less than or equal to\n            2.\n        tol (None or float): Threshold of singular value of `M`.\n            When `tol` is `None`, and `eps` is the epsilon value for datatype\n            of `M`, then `tol` is set to `S.max() * max(M.shape) * eps`,\n            where `S` is the singular value of `M`.\n            It obeys :func:`numpy.linalg.matrix_rank`.\n\n    Returns:\n        cupy.ndarray: Rank of `M`.\n\n    .. seealso:: :func:`numpy.linalg.matrix_rank`\n    \"\"\"\n    if M.ndim < 2:\n        return (M != 0).any().astype('l')\n    S = decomposition.svd(M, compute_uv=False)\n    if tol is None:\n        tol = (S.max(axis=-1, keepdims=True) * max(M.shape[-2:]) *\n               numpy.finfo(S.dtype).eps)\n    return (S > tol).sum(axis=-1)\n\n\ndef slogdet(a):\n    \"\"\"Returns sign and logarithm of the determinat of an array.\n\n    It calculates the natural logarithm of the deteminant of a given value.\n\n    Args:\n        a (cupy.ndarray): The input matrix with dimension ``(..., N, N)``.\n\n    Returns:\n        tuple of :class:`~cupy.ndarray`:\n            It returns a tuple ``(sign, logdet)``. ``sign`` represents each\n            sign of the deteminant as a real number ``0``, ``1`` or ``-1``.\n            'logdet' represents the natural logarithm of the absolute of the\n            deteminant.\n            If the deteninant is zero, ``sign`` will be ``0`` and ``logdet``\n            will be ``-inf``.\n            The shapes of both ``sign`` and ``logdet`` are equal to\n            ``a.shape[:-2]``.\n\n    .. seealso:: :func:`numpy.linalg.slogdet`\n    \"\"\"\n    if not cuda.cusolver_enabled:\n        raise RuntimeError('Current cupy only supports cusolver in CUDA 8.0')\n\n    if a.ndim < 2:\n        msg = ('%d-dimensional array given. '\n               'Array must be at least two-dimensional' % a.ndim)\n        raise linalg.LinAlgError(msg)\n\n    dtype = numpy.find_common_type((a.dtype.char, 'f'), ())\n    shape = a.shape[:-2]\n    sign = cupy.empty(shape, dtype)\n    logdet = cupy.empty(shape, dtype)\n\n    a = a.astype(dtype)\n    for index in numpy.ndindex(*shape):\n        s, l = _slogdet_one(a[index])\n        sign[index] = s\n        logdet[index] = l\n    return sign, logdet\n\n\ndef _slogdet_one(a):\n    util._assert_rank2(a)\n    util._assert_nd_squareness(a)\n    dtype = a.dtype\n\n    handle = device.get_cusolver_handle()\n    m = len(a)\n    ipiv = cupy.empty(m, 'i')\n    info = cupy.empty((), 'i')\n\n    # Need to make a copy because getrf works inplace\n    a_copy = a.copy(order='F')\n\n    if dtype == 'f':\n        getrf_bufferSize = cusolver.sgetrf_bufferSize\n        getrf = cusolver.sgetrf\n    else:\n        getrf_bufferSize = cusolver.dgetrf_bufferSize\n        getrf = cusolver.dgetrf\n\n    buffersize = getrf_bufferSize(handle, m, m, a_copy.data.ptr, m)\n    workspace = cupy.empty(buffersize, dtype=dtype)\n    getrf(handle, m, m, a_copy.data.ptr, m, workspace.data.ptr,\n          ipiv.data.ptr, info.data.ptr)\n\n    if info[()] == 0:\n        diag = cupy.diag(a_copy)\n        # ipiv is 1-origin\n        non_zero = (cupy.count_nonzero(ipiv != cupy.arange(1, m + 1)) +\n                    cupy.count_nonzero(diag < 0))\n        # Note: sign == -1 ** (non_zero % 2)\n        sign = (non_zero % 2) * -2 + 1\n        logdet = cupy.log(abs(diag)).sum()\n    else:\n        sign = cupy.array(0.0, dtype=dtype)\n        logdet = cupy.array(float('-inf'), dtype)\n\n    return sign, logdet\n\n\ndef trace(a, offset=0, axis1=0, axis2=1, dtype=None, out=None):\n    \"\"\"Returns the sum along the diagonals of an array.\n\n    It computes the sum along the diagonals at ``axis1`` and ``axis2``.\n\n    Args:\n        a (cupy.ndarray): Array to take trace.\n        offset (int): Index of diagonals. Zero indicates the main diagonal, a\n            positive value an upper diagonal, and a negative value a lower\n            diagonal.\n        axis1 (int): The first axis along which the trace is taken.\n        axis2 (int): The second axis along which the trace is taken.\n        dtype: Data type specifier of the output.\n        out (cupy.ndarray): Output array.\n\n    Returns:\n        cupy.ndarray: The trace of ``a`` along axes ``(axis1, axis2)``.\n\n    .. seealso:: :func:`numpy.trace`\n\n    \"\"\"\n    # TODO(okuta): check type\n    return a.trace(offset, axis1, axis2, dtype, out)\n", "path": "cupy/linalg/norms.py"}], "after_files": [{"content": "import numpy\nfrom numpy import linalg\n\nimport cupy\nfrom cupy import cuda\nfrom cupy.cuda import device\nfrom cupy.linalg import decomposition\nfrom cupy.linalg import util\n\n\nif cuda.cusolver_enabled:\n    from cupy.cuda import cusolver\n\n\ndef norm(x, ord=None, axis=None, keepdims=False):\n    \"\"\"Returns one of matrix norms specified by ``ord`` parameter.\n\n    Complex valued matrices and vectors are not supported.\n    See numpy.linalg.norm for more detail.\n\n    Args:\n        x (cupy.ndarray): Array to take norm. If ``axis`` is None,\n            ``x`` must be 1-D or 2-D.\n        ord (non-zero int, inf, -inf, 'fro'): Norm type.\n        axis (int, 2-tuple of ints, None): 1-D or 2-D norm is cumputed over\n            ``axis``.\n        keepdims (bool): If this is set ``True``, the axes which are normed\n            over are left.\n\n    Returns:\n        cupy.ndarray\n\n    \"\"\"\n    if not issubclass(x.dtype.type, numpy.inexact):\n        x = x.astype(float)\n\n    # Immediately handle some default, simple, fast, and common cases.\n    if axis is None:\n        ndim = x.ndim\n        if (ord is None or (ndim == 1 and ord == 2) or\n                (ndim == 2 and ord in ('f', 'fro'))):\n            if issubclass(x.dtype.type, numpy.complexfloating):\n                s = abs(x.ravel())\n                s *= s\n                ret = cupy.sqrt(s.sum())\n            else:\n                ret = cupy.sqrt((x.ravel() ** 2).sum())\n            if keepdims:\n                ret = ret.reshape((1,) * ndim)\n            return ret\n\n    # Normalize the `axis` argument to a tuple.\n    nd = x.ndim\n    if axis is None:\n        axis = tuple(range(nd))\n    elif not isinstance(axis, tuple):\n        try:\n            axis = int(axis)\n        except Exception:\n            raise TypeError(\n                \"'axis' must be None, an integer or a tuple of integers\")\n        axis = (axis,)\n\n    if len(axis) == 1:\n        if ord == numpy.Inf:\n            return abs(x).max(axis=axis, keepdims=keepdims)\n        elif ord == -numpy.Inf:\n            return abs(x).min(axis=axis, keepdims=keepdims)\n        elif ord == 0:\n            # Zero norm\n            # Convert to Python float in accordance with NumPy\n            return (x != 0).sum(axis=axis, keepdims=keepdims, dtype='d')\n        elif ord == 1:\n            # special case for speedup\n            return abs(x).sum(axis=axis, keepdims=keepdims)\n        elif ord is None or ord == 2:\n            # special case for speedup\n            if issubclass(x.dtype.type, numpy.complexfloating):\n                s = abs(x)\n                s *= s\n            else:\n                s = x ** 2\n            return cupy.sqrt(s.sum(axis=axis, keepdims=keepdims))\n        else:\n            try:\n                float(ord)\n            except TypeError:\n                raise ValueError(\"Invalid norm order for vectors.\")\n\n            # Mirror Numpy behavior of casting to double for non-complex\n            # dtypes, and to float32 or float64 for complex dtypes and\n            # no reduction over all axes.\n            cast_dtype = 'd'\n            if issubclass(x.dtype.type, numpy.complexfloating):\n                if keepdims or tuple(sorted(axis)) != tuple(range(nd)):\n                    cast_dtype = x.dtype.char.lower()  # 'D'->'d' and 'F'->'f'\n\n            absx = abs(x).astype(cast_dtype)\n            absx **= ord\n            ret = absx.sum(axis=axis, keepdims=keepdims)\n            ret **= (1.0 / ord)\n            return ret\n    elif len(axis) == 2:\n        row_axis, col_axis = axis\n        if row_axis < 0:\n            row_axis += nd\n        if col_axis < 0:\n            col_axis += nd\n        if not (0 <= row_axis < nd and 0 <= col_axis < nd):\n            raise ValueError('Invalid axis %r for an array with shape %r' %\n                             (axis, x.shape))\n        if row_axis == col_axis:\n            raise ValueError('Duplicate axes given.')\n        if ord == 1:\n            if col_axis > row_axis:\n                col_axis -= 1\n            ret = abs(x).sum(axis=row_axis).max(axis=col_axis)\n        elif ord == numpy.Inf:\n            if row_axis > col_axis:\n                row_axis -= 1\n            ret = abs(x).sum(axis=col_axis).max(axis=row_axis)\n        elif ord == -1:\n            if col_axis > row_axis:\n                col_axis -= 1\n            ret = abs(x).sum(axis=row_axis).min(axis=col_axis)\n        elif ord == -numpy.Inf:\n            if row_axis > col_axis:\n                row_axis -= 1\n            ret = abs(x).sum(axis=col_axis).min(axis=row_axis)\n        elif ord in [None, 'fro', 'f']:\n            if issubclass(x.dtype.type, numpy.complexfloating):\n                s = abs(x)\n                s *= s\n                ret = cupy.sqrt(s.sum(axis=axis))\n            else:\n                ret = cupy.sqrt((x ** 2).sum(axis=axis))\n        else:\n            raise ValueError(\"Invalid norm order for matrices.\")\n        if keepdims:\n            ret_shape = list(x.shape)\n            ret_shape[axis[0]] = 1\n            ret_shape[axis[1]] = 1\n            ret = ret.reshape(ret_shape)\n        return ret\n    else:\n        raise ValueError(\"Improper number of dimensions to norm.\")\n\n\n# TODO(okuta): Implement cond\n\n\ndef det(a):\n    \"\"\"Retruns the deteminant of an array.\n\n    Args:\n        a (cupy.ndarray): The input matrix with dimension ``(..., N, N)``.\n\n    Returns:\n        cupy.ndarray: Determinant of ``a``. Its shape is ``a.shape[:-2]``.\n\n    .. seealso:: :func:`numpy.linalg.det`\n    \"\"\"\n    sign, logdet = slogdet(a)\n    return sign * cupy.exp(logdet)\n\n\ndef matrix_rank(M, tol=None):\n    \"\"\"Return matrix rank of array using SVD method\n\n    Args:\n        M (cupy.ndarray): Input array. Its `ndim` must be less than or equal to\n            2.\n        tol (None or float): Threshold of singular value of `M`.\n            When `tol` is `None`, and `eps` is the epsilon value for datatype\n            of `M`, then `tol` is set to `S.max() * max(M.shape) * eps`,\n            where `S` is the singular value of `M`.\n            It obeys :func:`numpy.linalg.matrix_rank`.\n\n    Returns:\n        cupy.ndarray: Rank of `M`.\n\n    .. seealso:: :func:`numpy.linalg.matrix_rank`\n    \"\"\"\n    if M.ndim < 2:\n        return (M != 0).any().astype('l')\n    S = decomposition.svd(M, compute_uv=False)\n    if tol is None:\n        tol = (S.max(axis=-1, keepdims=True) * max(M.shape[-2:]) *\n               numpy.finfo(S.dtype).eps)\n    return (S > tol).sum(axis=-1)\n\n\ndef slogdet(a):\n    \"\"\"Returns sign and logarithm of the determinat of an array.\n\n    It calculates the natural logarithm of the deteminant of a given value.\n\n    Args:\n        a (cupy.ndarray): The input matrix with dimension ``(..., N, N)``.\n\n    Returns:\n        tuple of :class:`~cupy.ndarray`:\n            It returns a tuple ``(sign, logdet)``. ``sign`` represents each\n            sign of the deteminant as a real number ``0``, ``1`` or ``-1``.\n            'logdet' represents the natural logarithm of the absolute of the\n            deteminant.\n            If the deteninant is zero, ``sign`` will be ``0`` and ``logdet``\n            will be ``-inf``.\n            The shapes of both ``sign`` and ``logdet`` are equal to\n            ``a.shape[:-2]``.\n\n    .. seealso:: :func:`numpy.linalg.slogdet`\n    \"\"\"\n    if not cuda.cusolver_enabled:\n        raise RuntimeError('Current cupy only supports cusolver in CUDA 8.0')\n\n    if a.ndim < 2:\n        msg = ('%d-dimensional array given. '\n               'Array must be at least two-dimensional' % a.ndim)\n        raise linalg.LinAlgError(msg)\n\n    dtype = numpy.find_common_type((a.dtype.char, 'f'), ())\n    shape = a.shape[:-2]\n    sign = cupy.empty(shape, dtype)\n    logdet = cupy.empty(shape, dtype)\n\n    a = a.astype(dtype)\n    for index in numpy.ndindex(*shape):\n        s, l = _slogdet_one(a[index])\n        sign[index] = s\n        logdet[index] = l\n    return sign, logdet\n\n\ndef _slogdet_one(a):\n    util._assert_rank2(a)\n    util._assert_nd_squareness(a)\n    dtype = a.dtype\n\n    handle = device.get_cusolver_handle()\n    m = len(a)\n    ipiv = cupy.empty(m, 'i')\n    info = cupy.empty((), 'i')\n\n    # Need to make a copy because getrf works inplace\n    a_copy = a.copy(order='F')\n\n    if dtype == 'f':\n        getrf_bufferSize = cusolver.sgetrf_bufferSize\n        getrf = cusolver.sgetrf\n    else:\n        getrf_bufferSize = cusolver.dgetrf_bufferSize\n        getrf = cusolver.dgetrf\n\n    buffersize = getrf_bufferSize(handle, m, m, a_copy.data.ptr, m)\n    workspace = cupy.empty(buffersize, dtype=dtype)\n    getrf(handle, m, m, a_copy.data.ptr, m, workspace.data.ptr,\n          ipiv.data.ptr, info.data.ptr)\n\n    if info[()] == 0:\n        diag = cupy.diag(a_copy)\n        # ipiv is 1-origin\n        non_zero = (cupy.count_nonzero(ipiv != cupy.arange(1, m + 1)) +\n                    cupy.count_nonzero(diag < 0))\n        # Note: sign == -1 ** (non_zero % 2)\n        sign = (non_zero % 2) * -2 + 1\n        logdet = cupy.log(abs(diag)).sum()\n    else:\n        sign = cupy.array(0.0, dtype=dtype)\n        logdet = cupy.array(float('-inf'), dtype)\n\n    return sign, logdet\n\n\ndef trace(a, offset=0, axis1=0, axis2=1, dtype=None, out=None):\n    \"\"\"Returns the sum along the diagonals of an array.\n\n    It computes the sum along the diagonals at ``axis1`` and ``axis2``.\n\n    Args:\n        a (cupy.ndarray): Array to take trace.\n        offset (int): Index of diagonals. Zero indicates the main diagonal, a\n            positive value an upper diagonal, and a negative value a lower\n            diagonal.\n        axis1 (int): The first axis along which the trace is taken.\n        axis2 (int): The second axis along which the trace is taken.\n        dtype: Data type specifier of the output.\n        out (cupy.ndarray): Output array.\n\n    Returns:\n        cupy.ndarray: The trace of ``a`` along axes ``(axis1, axis2)``.\n\n    .. seealso:: :func:`numpy.trace`\n\n    \"\"\"\n    # TODO(okuta): check type\n    return a.trace(offset, axis1, axis2, dtype, out)\n", "path": "cupy/linalg/norms.py"}]}