We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Remove limitation in cholesky decomposition
Cholesky decomposition's tile logic is actually similar to lu decomposition, in #272 , the limitation that all chunks must be square was removed, so should Cholesky.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mars/tensor/expressions/linalg/cholesky.py`
Content:
```
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Copyright 1999-2018 Alibaba Group Holding Ltd.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 #      http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 import numpy as np
18 from numpy.linalg import LinAlgError
19 
20 from .... import operands
21 from ..core import TensorOperandMixin
22 from ..datasource import tensor as astensor
23 
24 
25 def _H(chunk):
26     from ..base.transpose import TensorTranspose
27     from ..arithmetic.conj import TensorConj
28 
29     trans_op = TensorTranspose(dtype=chunk.dtype)
30     c = trans_op.new_chunk([chunk], chunk.shape[::-1], index=chunk.index[::-1])
31     conj_op = TensorConj(dtype=c.dtype)
32     return conj_op.new_chunk([c, None, None], c.shape, index=c.index)
33 
34 
35 class TensorCholesky(operands.Cholesky, TensorOperandMixin):
36     def __init__(self, lower=None, dtype=None, **kw):
37         super(TensorCholesky, self).__init__(_lower=lower, _dtype=dtype, **kw)
38 
39     def _set_inputs(self, inputs):
40         super(TensorCholesky, self)._set_inputs(inputs)
41         self._input = self._inputs[0]
42 
43     def calc_shape(self, *inputs_shape):
44         return inputs_shape[0]
45 
46     def __call__(self, a):
47         return self.new_tensor([a], a.shape)
48 
49     @classmethod
50     def tile(cls, op):
51         from ..datasource.zeros import TensorZeros
52         from ..arithmetic.subtract import TensorSubtract
53         from ..arithmetic.utils import tree_add
54         from .dot import TensorDot
55         from .solve_triangular import TensorSolveTriangular
56 
57         tensor = op.outputs[0]
58         in_tensor = op.input
59         if len(set(in_tensor.nsplits[0] + in_tensor.nsplits[1])) != 1:
60             nsplit = min(in_tensor.nsplits[0] + in_tensor.nsplits[1])
61             # input's chunks must be all square
62             in_tensor = in_tensor.rechunk([nsplit for _ in range(in_tensor.ndim)]).single_tiles()
63             if len(set(in_tensor.nsplits[0] + in_tensor.nsplits[1])) != 1:
64                 raise LinAlgError('All chunks must be a square matrix to perform cholesky decomposition.')
65 
66         lower_chunks, upper_chunks = {}, {}
67         for i in range(in_tensor.chunk_shape[0]):
68             for j in range(in_tensor.chunk_shape[1]):
69                 if i < j:
70                     lower_chunk = TensorZeros(dtype=tensor.dtype).new_chunk(
71                         None, (in_tensor.nsplits[0][i], in_tensor.nsplits[1][j]), index=(i, j))
72                     upper_chunk = TensorZeros(dtype=tensor.dtype).new_chunk(
73                         None, (in_tensor.nsplits[0][i], in_tensor.nsplits[1][j]), index=(j, i))
74                     lower_chunks[lower_chunk.index] = lower_chunk
75                     upper_chunks[upper_chunk.index] = upper_chunk
76                 elif i == j:
77                     target = in_tensor.cix[i, j]
78                     if i > 0:
79                         prev_chunks = []
80                         for p in range(i):
81                             a, b = lower_chunks[i, p], upper_chunks[p, j]
82                             prev_chunk = TensorDot(dtype=tensor.dtype).new_chunk(
83                                 [a, b], (a.shape[0], b.shape[1]))
84                             prev_chunks.append(prev_chunk)
85                         if len(prev_chunks) == 1:
86                             s = prev_chunks[0]
87                         else:
88                             s = tree_add(prev_chunks[0].dtype, prev_chunks,
89                                          None, prev_chunks[0].shape)
90                         target = TensorSubtract(dtype=tensor.dtype).new_chunk(
91                             [target, s, None, None], target.shape)
92                     lower_chunk = TensorCholesky(lower=True, dtype=tensor.dtype).new_chunk(
93                         [target], target.shape, index=(i, j))
94                     upper_chunk = _H(lower_chunk)
95                     lower_chunks[lower_chunk.index] = lower_chunk
96                     upper_chunks[upper_chunk.index] = upper_chunk
97                 else:
98                     target = in_tensor.cix[j, i]
99                     if j > 0:
100                         prev_chunks = []
101                         for p in range(j):
102                             a, b = lower_chunks[j, p], upper_chunks[p, i]
103                             prev_chunk = TensorDot(dtype=tensor.dtype).new_chunk(
104                                 [a, b], (a.shape[0], b.shape[1]))
105                             prev_chunks.append(prev_chunk)
106                         if len(prev_chunks) == 1:
107                             s = prev_chunks[0]
108                         else:
109                             s = tree_add(prev_chunks[0].dtype, prev_chunks,
110                                          None, prev_chunks[0].shape)
111                         target = TensorSubtract(dtype=tensor.dtype).new_chunk(
112                             [target, s, None, None], target.shape)
113                     upper_chunk = TensorSolveTriangular(lower=True, dtype=tensor.dtype).new_chunk(
114                         [lower_chunks[j, j], target], target.shape, index=(j, i))
115                     lower_chunk = _H(upper_chunk)
116                     lower_chunks[lower_chunk.index] = lower_chunk
117                     upper_chunks[upper_chunk.index] = upper_chunk
118 
119         new_op = op.copy()
120         if op.lower:
121             return new_op.new_tensors(op.inputs, tensor.shape,
122                                       chunks=list(lower_chunks.values()), nsplits=in_tensor.nsplits)
123         else:
124             return new_op.new_tensors(op.inputs, tensor.shape,
125                                       chunks=list(upper_chunks.values()), nsplits=in_tensor.nsplits)
126 
127 
128 def cholesky(a, lower=False):
129     """
130     Cholesky decomposition.
131 
132     Return the Cholesky decomposition, `L * L.H`, of the square matrix `a`,
133     where `L` is lower-triangular and .H is the conjugate transpose operator
134     (which is the ordinary transpose if `a` is real-valued).  `a` must be
135     Hermitian (symmetric if real-valued) and positive-definite.  Only `L` is
136     actually returned.
137 
138     Parameters
139     ----------
140     a : (..., M, M) array_like
141         Hermitian (symmetric if all elements are real), positive-definite
142         input matrix.
143     lower : bool
144         Whether to compute the upper or lower triangular Cholesky
145         factorization.  Default is upper-triangular.
146 
147     Returns
148     -------
149     L : (..., M, M) array_like
150         Upper or lower-triangular Cholesky factor of `a`.
151 
152     Raises
153     ------
154     LinAlgError
155        If the decomposition fails, for example, if `a` is not
156        positive-definite.
157 
158     Notes
159     -----
160 
161     Broadcasting rules apply, see the `mt.linalg` documentation for
162     details.
163 
164     The Cholesky decomposition is often used as a fast way of solving
165 
166     .. math:: A \\mathbf{x} = \\mathbf{b}
167 
168     (when `A` is both Hermitian/symmetric and positive-definite).
169 
170     First, we solve for :math:`\\mathbf{y}` in
171 
172     .. math:: L \\mathbf{y} = \\mathbf{b},
173 
174     and then for :math:`\\mathbf{x}` in
175 
176     .. math:: L.H \\mathbf{x} = \\mathbf{y}.
177 
178     Examples
179     --------
180     >>> import mars.tensor as mt
181 
182     >>> A = mt.array([[1,-2j],[2j,5]])
183     >>> A.execute()
184     array([[ 1.+0.j,  0.-2.j],
185            [ 0.+2.j,  5.+0.j]])
186     >>> L = mt.linalg.cholesky(A, lower=True)
187     >>> L.execute()
188     array([[ 1.+0.j,  0.+0.j],
189            [ 0.+2.j,  1.+0.j]])
190     >>> mt.dot(L, L.T.conj()).execute() # verify that L * L.H = A
191     array([[ 1.+0.j,  0.-2.j],
192            [ 0.+2.j,  5.+0.j]])
193     >>> A = [[1,-2j],[2j,5]] # what happens if A is only array_like?
194     >>> mt.linalg.cholesky(A, lower=True).execute()
195     array([[ 1.+0.j,  0.+0.j],
196            [ 0.+2.j,  1.+0.j]])
197 
198     """
199     a = astensor(a)
200 
201     if a.ndim != 2:
202         raise LinAlgError('{0}-dimensional array given. '
203                           'Tensor must be two-dimensional'.format(a.ndim))
204     if a.shape[0] != a.shape[1]:
205         raise LinAlgError('Input must be square')
206 
207     cho = np.linalg.cholesky(np.array([[1, 2], [2, 5]], dtype=a.dtype))
208 
209     op = TensorCholesky(lower=lower, dtype=cho.dtype)
210     return op(a)
211
```
--- 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/mars/tensor/expressions/linalg/cholesky.py b/mars/tensor/expressions/linalg/cholesky.py
--- a/mars/tensor/expressions/linalg/cholesky.py
+++ b/mars/tensor/expressions/linalg/cholesky.py
@@ -56,12 +56,10 @@
 
         tensor = op.outputs[0]
         in_tensor = op.input
-        if len(set(in_tensor.nsplits[0] + in_tensor.nsplits[1])) != 1:
-            nsplit = min(in_tensor.nsplits[0] + in_tensor.nsplits[1])
-            # input's chunks must be all square
-            in_tensor = in_tensor.rechunk([nsplit for _ in range(in_tensor.ndim)]).single_tiles()
-            if len(set(in_tensor.nsplits[0] + in_tensor.nsplits[1])) != 1:
-                raise LinAlgError('All chunks must be a square matrix to perform cholesky decomposition.')
+        if in_tensor.nsplits[0] != in_tensor.nsplits[1]:
+            # all chunks on diagonal should be square
+            nsplits = in_tensor.nsplits[0]
+            in_tensor = in_tensor.rechunk([nsplits, nsplits]).single_tiles()
 
         lower_chunks, upper_chunks = {}, {}
         for i in range(in_tensor.chunk_shape[0]):
@@ -70,7 +68,7 @@
                     lower_chunk = TensorZeros(dtype=tensor.dtype).new_chunk(
                         None, (in_tensor.nsplits[0][i], in_tensor.nsplits[1][j]), index=(i, j))
                     upper_chunk = TensorZeros(dtype=tensor.dtype).new_chunk(
-                        None, (in_tensor.nsplits[0][i], in_tensor.nsplits[1][j]), index=(j, i))
+                        None, (in_tensor.nsplits[1][j], in_tensor.nsplits[0][i]), index=(j, i))
                     lower_chunks[lower_chunk.index] = lower_chunk
                     upper_chunks[upper_chunk.index] = upper_chunk
                 elif i == j:

{"golden_diff": "diff --git a/mars/tensor/expressions/linalg/cholesky.py b/mars/tensor/expressions/linalg/cholesky.py\n--- a/mars/tensor/expressions/linalg/cholesky.py\n+++ b/mars/tensor/expressions/linalg/cholesky.py\n@@ -56,12 +56,10 @@\n \n         tensor = op.outputs[0]\n         in_tensor = op.input\n-        if len(set(in_tensor.nsplits[0] + in_tensor.nsplits[1])) != 1:\n-            nsplit = min(in_tensor.nsplits[0] + in_tensor.nsplits[1])\n-            # input's chunks must be all square\n-            in_tensor = in_tensor.rechunk([nsplit for _ in range(in_tensor.ndim)]).single_tiles()\n-            if len(set(in_tensor.nsplits[0] + in_tensor.nsplits[1])) != 1:\n-                raise LinAlgError('All chunks must be a square matrix to perform cholesky decomposition.')\n+        if in_tensor.nsplits[0] != in_tensor.nsplits[1]:\n+            # all chunks on diagonal should be square\n+            nsplits = in_tensor.nsplits[0]\n+            in_tensor = in_tensor.rechunk([nsplits, nsplits]).single_tiles()\n \n         lower_chunks, upper_chunks = {}, {}\n         for i in range(in_tensor.chunk_shape[0]):\n@@ -70,7 +68,7 @@\n                     lower_chunk = TensorZeros(dtype=tensor.dtype).new_chunk(\n                         None, (in_tensor.nsplits[0][i], in_tensor.nsplits[1][j]), index=(i, j))\n                     upper_chunk = TensorZeros(dtype=tensor.dtype).new_chunk(\n-                        None, (in_tensor.nsplits[0][i], in_tensor.nsplits[1][j]), index=(j, i))\n+                        None, (in_tensor.nsplits[1][j], in_tensor.nsplits[0][i]), index=(j, i))\n                     lower_chunks[lower_chunk.index] = lower_chunk\n                     upper_chunks[upper_chunk.index] = upper_chunk\n                 elif i == j:\n", "issue": "Remove limitation in cholesky decomposition\nCholesky decomposition's tile logic is actually similar to lu decomposition, in #272 , the limitation that all chunks must be square was removed, so should Cholesky.\n", "before_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# Copyright 1999-2018 Alibaba Group Holding Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport numpy as np\nfrom numpy.linalg import LinAlgError\n\nfrom .... import operands\nfrom ..core import TensorOperandMixin\nfrom ..datasource import tensor as astensor\n\n\ndef _H(chunk):\n    from ..base.transpose import TensorTranspose\n    from ..arithmetic.conj import TensorConj\n\n    trans_op = TensorTranspose(dtype=chunk.dtype)\n    c = trans_op.new_chunk([chunk], chunk.shape[::-1], index=chunk.index[::-1])\n    conj_op = TensorConj(dtype=c.dtype)\n    return conj_op.new_chunk([c, None, None], c.shape, index=c.index)\n\n\nclass TensorCholesky(operands.Cholesky, TensorOperandMixin):\n    def __init__(self, lower=None, dtype=None, **kw):\n        super(TensorCholesky, self).__init__(_lower=lower, _dtype=dtype, **kw)\n\n    def _set_inputs(self, inputs):\n        super(TensorCholesky, self)._set_inputs(inputs)\n        self._input = self._inputs[0]\n\n    def calc_shape(self, *inputs_shape):\n        return inputs_shape[0]\n\n    def __call__(self, a):\n        return self.new_tensor([a], a.shape)\n\n    @classmethod\n    def tile(cls, op):\n        from ..datasource.zeros import TensorZeros\n        from ..arithmetic.subtract import TensorSubtract\n        from ..arithmetic.utils import tree_add\n        from .dot import TensorDot\n        from .solve_triangular import TensorSolveTriangular\n\n        tensor = op.outputs[0]\n        in_tensor = op.input\n        if len(set(in_tensor.nsplits[0] + in_tensor.nsplits[1])) != 1:\n            nsplit = min(in_tensor.nsplits[0] + in_tensor.nsplits[1])\n            # input's chunks must be all square\n            in_tensor = in_tensor.rechunk([nsplit for _ in range(in_tensor.ndim)]).single_tiles()\n            if len(set(in_tensor.nsplits[0] + in_tensor.nsplits[1])) != 1:\n                raise LinAlgError('All chunks must be a square matrix to perform cholesky decomposition.')\n\n        lower_chunks, upper_chunks = {}, {}\n        for i in range(in_tensor.chunk_shape[0]):\n            for j in range(in_tensor.chunk_shape[1]):\n                if i < j:\n                    lower_chunk = TensorZeros(dtype=tensor.dtype).new_chunk(\n                        None, (in_tensor.nsplits[0][i], in_tensor.nsplits[1][j]), index=(i, j))\n                    upper_chunk = TensorZeros(dtype=tensor.dtype).new_chunk(\n                        None, (in_tensor.nsplits[0][i], in_tensor.nsplits[1][j]), index=(j, i))\n                    lower_chunks[lower_chunk.index] = lower_chunk\n                    upper_chunks[upper_chunk.index] = upper_chunk\n                elif i == j:\n                    target = in_tensor.cix[i, j]\n                    if i > 0:\n                        prev_chunks = []\n                        for p in range(i):\n                            a, b = lower_chunks[i, p], upper_chunks[p, j]\n                            prev_chunk = TensorDot(dtype=tensor.dtype).new_chunk(\n                                [a, b], (a.shape[0], b.shape[1]))\n                            prev_chunks.append(prev_chunk)\n                        if len(prev_chunks) == 1:\n                            s = prev_chunks[0]\n                        else:\n                            s = tree_add(prev_chunks[0].dtype, prev_chunks,\n                                         None, prev_chunks[0].shape)\n                        target = TensorSubtract(dtype=tensor.dtype).new_chunk(\n                            [target, s, None, None], target.shape)\n                    lower_chunk = TensorCholesky(lower=True, dtype=tensor.dtype).new_chunk(\n                        [target], target.shape, index=(i, j))\n                    upper_chunk = _H(lower_chunk)\n                    lower_chunks[lower_chunk.index] = lower_chunk\n                    upper_chunks[upper_chunk.index] = upper_chunk\n                else:\n                    target = in_tensor.cix[j, i]\n                    if j > 0:\n                        prev_chunks = []\n                        for p in range(j):\n                            a, b = lower_chunks[j, p], upper_chunks[p, i]\n                            prev_chunk = TensorDot(dtype=tensor.dtype).new_chunk(\n                                [a, b], (a.shape[0], b.shape[1]))\n                            prev_chunks.append(prev_chunk)\n                        if len(prev_chunks) == 1:\n                            s = prev_chunks[0]\n                        else:\n                            s = tree_add(prev_chunks[0].dtype, prev_chunks,\n                                         None, prev_chunks[0].shape)\n                        target = TensorSubtract(dtype=tensor.dtype).new_chunk(\n                            [target, s, None, None], target.shape)\n                    upper_chunk = TensorSolveTriangular(lower=True, dtype=tensor.dtype).new_chunk(\n                        [lower_chunks[j, j], target], target.shape, index=(j, i))\n                    lower_chunk = _H(upper_chunk)\n                    lower_chunks[lower_chunk.index] = lower_chunk\n                    upper_chunks[upper_chunk.index] = upper_chunk\n\n        new_op = op.copy()\n        if op.lower:\n            return new_op.new_tensors(op.inputs, tensor.shape,\n                                      chunks=list(lower_chunks.values()), nsplits=in_tensor.nsplits)\n        else:\n            return new_op.new_tensors(op.inputs, tensor.shape,\n                                      chunks=list(upper_chunks.values()), nsplits=in_tensor.nsplits)\n\n\ndef cholesky(a, lower=False):\n    \"\"\"\n    Cholesky decomposition.\n\n    Return the Cholesky decomposition, `L * L.H`, of the square matrix `a`,\n    where `L` is lower-triangular and .H is the conjugate transpose operator\n    (which is the ordinary transpose if `a` is real-valued).  `a` must be\n    Hermitian (symmetric if real-valued) and positive-definite.  Only `L` is\n    actually returned.\n\n    Parameters\n    ----------\n    a : (..., M, M) array_like\n        Hermitian (symmetric if all elements are real), positive-definite\n        input matrix.\n    lower : bool\n        Whether to compute the upper or lower triangular Cholesky\n        factorization.  Default is upper-triangular.\n\n    Returns\n    -------\n    L : (..., M, M) array_like\n        Upper or lower-triangular Cholesky factor of `a`.\n\n    Raises\n    ------\n    LinAlgError\n       If the decomposition fails, for example, if `a` is not\n       positive-definite.\n\n    Notes\n    -----\n\n    Broadcasting rules apply, see the `mt.linalg` documentation for\n    details.\n\n    The Cholesky decomposition is often used as a fast way of solving\n\n    .. math:: A \\\\mathbf{x} = \\\\mathbf{b}\n\n    (when `A` is both Hermitian/symmetric and positive-definite).\n\n    First, we solve for :math:`\\\\mathbf{y}` in\n\n    .. math:: L \\\\mathbf{y} = \\\\mathbf{b},\n\n    and then for :math:`\\\\mathbf{x}` in\n\n    .. math:: L.H \\\\mathbf{x} = \\\\mathbf{y}.\n\n    Examples\n    --------\n    >>> import mars.tensor as mt\n\n    >>> A = mt.array([[1,-2j],[2j,5]])\n    >>> A.execute()\n    array([[ 1.+0.j,  0.-2.j],\n           [ 0.+2.j,  5.+0.j]])\n    >>> L = mt.linalg.cholesky(A, lower=True)\n    >>> L.execute()\n    array([[ 1.+0.j,  0.+0.j],\n           [ 0.+2.j,  1.+0.j]])\n    >>> mt.dot(L, L.T.conj()).execute() # verify that L * L.H = A\n    array([[ 1.+0.j,  0.-2.j],\n           [ 0.+2.j,  5.+0.j]])\n    >>> A = [[1,-2j],[2j,5]] # what happens if A is only array_like?\n    >>> mt.linalg.cholesky(A, lower=True).execute()\n    array([[ 1.+0.j,  0.+0.j],\n           [ 0.+2.j,  1.+0.j]])\n\n    \"\"\"\n    a = astensor(a)\n\n    if a.ndim != 2:\n        raise LinAlgError('{0}-dimensional array given. '\n                          'Tensor must be two-dimensional'.format(a.ndim))\n    if a.shape[0] != a.shape[1]:\n        raise LinAlgError('Input must be square')\n\n    cho = np.linalg.cholesky(np.array([[1, 2], [2, 5]], dtype=a.dtype))\n\n    op = TensorCholesky(lower=lower, dtype=cho.dtype)\n    return op(a)\n", "path": "mars/tensor/expressions/linalg/cholesky.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n# Copyright 1999-2018 Alibaba Group Holding Ltd.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport numpy as np\nfrom numpy.linalg import LinAlgError\n\nfrom .... import operands\nfrom ..core import TensorOperandMixin\nfrom ..datasource import tensor as astensor\n\n\ndef _H(chunk):\n    from ..base.transpose import TensorTranspose\n    from ..arithmetic.conj import TensorConj\n\n    trans_op = TensorTranspose(dtype=chunk.dtype)\n    c = trans_op.new_chunk([chunk], chunk.shape[::-1], index=chunk.index[::-1])\n    conj_op = TensorConj(dtype=c.dtype)\n    return conj_op.new_chunk([c, None, None], c.shape, index=c.index)\n\n\nclass TensorCholesky(operands.Cholesky, TensorOperandMixin):\n    def __init__(self, lower=None, dtype=None, **kw):\n        super(TensorCholesky, self).__init__(_lower=lower, _dtype=dtype, **kw)\n\n    def _set_inputs(self, inputs):\n        super(TensorCholesky, self)._set_inputs(inputs)\n        self._input = self._inputs[0]\n\n    def calc_shape(self, *inputs_shape):\n        return inputs_shape[0]\n\n    def __call__(self, a):\n        return self.new_tensor([a], a.shape)\n\n    @classmethod\n    def tile(cls, op):\n        from ..datasource.zeros import TensorZeros\n        from ..arithmetic.subtract import TensorSubtract\n        from ..arithmetic.utils import tree_add\n        from .dot import TensorDot\n        from .solve_triangular import TensorSolveTriangular\n\n        tensor = op.outputs[0]\n        in_tensor = op.input\n        if in_tensor.nsplits[0] != in_tensor.nsplits[1]:\n            # all chunks on diagonal should be square\n            nsplits = in_tensor.nsplits[0]\n            in_tensor = in_tensor.rechunk([nsplits, nsplits]).single_tiles()\n\n        lower_chunks, upper_chunks = {}, {}\n        for i in range(in_tensor.chunk_shape[0]):\n            for j in range(in_tensor.chunk_shape[1]):\n                if i < j:\n                    lower_chunk = TensorZeros(dtype=tensor.dtype).new_chunk(\n                        None, (in_tensor.nsplits[0][i], in_tensor.nsplits[1][j]), index=(i, j))\n                    upper_chunk = TensorZeros(dtype=tensor.dtype).new_chunk(\n                        None, (in_tensor.nsplits[1][j], in_tensor.nsplits[0][i]), index=(j, i))\n                    lower_chunks[lower_chunk.index] = lower_chunk\n                    upper_chunks[upper_chunk.index] = upper_chunk\n                elif i == j:\n                    target = in_tensor.cix[i, j]\n                    if i > 0:\n                        prev_chunks = []\n                        for p in range(i):\n                            a, b = lower_chunks[i, p], upper_chunks[p, j]\n                            prev_chunk = TensorDot(dtype=tensor.dtype).new_chunk(\n                                [a, b], (a.shape[0], b.shape[1]))\n                            prev_chunks.append(prev_chunk)\n                        if len(prev_chunks) == 1:\n                            s = prev_chunks[0]\n                        else:\n                            s = tree_add(prev_chunks[0].dtype, prev_chunks,\n                                         None, prev_chunks[0].shape)\n                        target = TensorSubtract(dtype=tensor.dtype).new_chunk(\n                            [target, s, None, None], target.shape)\n                    lower_chunk = TensorCholesky(lower=True, dtype=tensor.dtype).new_chunk(\n                        [target], target.shape, index=(i, j))\n                    upper_chunk = _H(lower_chunk)\n                    lower_chunks[lower_chunk.index] = lower_chunk\n                    upper_chunks[upper_chunk.index] = upper_chunk\n                else:\n                    target = in_tensor.cix[j, i]\n                    if j > 0:\n                        prev_chunks = []\n                        for p in range(j):\n                            a, b = lower_chunks[j, p], upper_chunks[p, i]\n                            prev_chunk = TensorDot(dtype=tensor.dtype).new_chunk(\n                                [a, b], (a.shape[0], b.shape[1]))\n                            prev_chunks.append(prev_chunk)\n                        if len(prev_chunks) == 1:\n                            s = prev_chunks[0]\n                        else:\n                            s = tree_add(prev_chunks[0].dtype, prev_chunks,\n                                         None, prev_chunks[0].shape)\n                        target = TensorSubtract(dtype=tensor.dtype).new_chunk(\n                            [target, s, None, None], target.shape)\n                    upper_chunk = TensorSolveTriangular(lower=True, dtype=tensor.dtype).new_chunk(\n                        [lower_chunks[j, j], target], target.shape, index=(j, i))\n                    lower_chunk = _H(upper_chunk)\n                    lower_chunks[lower_chunk.index] = lower_chunk\n                    upper_chunks[upper_chunk.index] = upper_chunk\n\n        new_op = op.copy()\n        if op.lower:\n            return new_op.new_tensors(op.inputs, tensor.shape,\n                                      chunks=list(lower_chunks.values()), nsplits=in_tensor.nsplits)\n        else:\n            return new_op.new_tensors(op.inputs, tensor.shape,\n                                      chunks=list(upper_chunks.values()), nsplits=in_tensor.nsplits)\n\n\ndef cholesky(a, lower=False):\n    \"\"\"\n    Cholesky decomposition.\n\n    Return the Cholesky decomposition, `L * L.H`, of the square matrix `a`,\n    where `L` is lower-triangular and .H is the conjugate transpose operator\n    (which is the ordinary transpose if `a` is real-valued).  `a` must be\n    Hermitian (symmetric if real-valued) and positive-definite.  Only `L` is\n    actually returned.\n\n    Parameters\n    ----------\n    a : (..., M, M) array_like\n        Hermitian (symmetric if all elements are real), positive-definite\n        input matrix.\n    lower : bool\n        Whether to compute the upper or lower triangular Cholesky\n        factorization.  Default is upper-triangular.\n\n    Returns\n    -------\n    L : (..., M, M) array_like\n        Upper or lower-triangular Cholesky factor of `a`.\n\n    Raises\n    ------\n    LinAlgError\n       If the decomposition fails, for example, if `a` is not\n       positive-definite.\n\n    Notes\n    -----\n\n    Broadcasting rules apply, see the `mt.linalg` documentation for\n    details.\n\n    The Cholesky decomposition is often used as a fast way of solving\n\n    .. math:: A \\\\mathbf{x} = \\\\mathbf{b}\n\n    (when `A` is both Hermitian/symmetric and positive-definite).\n\n    First, we solve for :math:`\\\\mathbf{y}` in\n\n    .. math:: L \\\\mathbf{y} = \\\\mathbf{b},\n\n    and then for :math:`\\\\mathbf{x}` in\n\n    .. math:: L.H \\\\mathbf{x} = \\\\mathbf{y}.\n\n    Examples\n    --------\n    >>> import mars.tensor as mt\n\n    >>> A = mt.array([[1,-2j],[2j,5]])\n    >>> A.execute()\n    array([[ 1.+0.j,  0.-2.j],\n           [ 0.+2.j,  5.+0.j]])\n    >>> L = mt.linalg.cholesky(A, lower=True)\n    >>> L.execute()\n    array([[ 1.+0.j,  0.+0.j],\n           [ 0.+2.j,  1.+0.j]])\n    >>> mt.dot(L, L.T.conj()).execute() # verify that L * L.H = A\n    array([[ 1.+0.j,  0.-2.j],\n           [ 0.+2.j,  5.+0.j]])\n    >>> A = [[1,-2j],[2j,5]] # what happens if A is only array_like?\n    >>> mt.linalg.cholesky(A, lower=True).execute()\n    array([[ 1.+0.j,  0.+0.j],\n           [ 0.+2.j,  1.+0.j]])\n\n    \"\"\"\n    a = astensor(a)\n\n    if a.ndim != 2:\n        raise LinAlgError('{0}-dimensional array given. '\n                          'Tensor must be two-dimensional'.format(a.ndim))\n    if a.shape[0] != a.shape[1]:\n        raise LinAlgError('Input must be square')\n\n    cho = np.linalg.cholesky(np.array([[1, 2], [2, 5]], dtype=a.dtype))\n\n    op = TensorCholesky(lower=lower, dtype=cho.dtype)\n    return op(a)\n", "path": "mars/tensor/expressions/linalg/cholesky.py"}]}