Repository: mars-project/mars

Issue:
[BUG][TENSOR] Chunks with same shape tiled by ones as well as zeros generate different key
<!--
Thank you for your contribution!

Please review https://github.com/mars-project/mars/blob/master/CONTRIBUTING.rst before opening an issue.
-->

**Describe the bug**

Chunks with same shape tiled by `ones` as well as `zeros` generate different keys, they should be the same.

**To Reproduce**

```
In [1]: import mars.tensor as mt                                                    

In [2]: a = mt.ones((100, 100), chunk_size=50)                                      

In [3]: a.tiles()                                                                   
Out[3]: Tensor <op=TensorOnes, shape=(100, 100), key=a4095842f813f99d58aa7cd330815190>

In [4]: [c.op.key for c in a.chunks]                                                
Out[4]: 
['1fc86c1b04351958eb2fda3ce467f5bf',
 '0c710bf1f48424bca05d12ee833a1234',
 '78900ebd5fa9c9baeafd17469eb9d757',
 '77942146d3fc310de36f12e1809dc41a']
```



Discussion:

Resolving patch:
diff --git a/mars/tensor/expressions/datasource/core.py b/mars/tensor/expressions/datasource/core.py
--- a/mars/tensor/expressions/datasource/core.py
+++ b/mars/tensor/expressions/datasource/core.py
@@ -37,9 +37,9 @@ class TensorDataSource(DataSource, TensorOperandMixin):
     __slots__ = ()
 
     def to_chunk_op(self, *args):
-        chunk_shape, idx, chunk_size = args
+        chunk_shape, _, chunk_size = args
         chunk_op = self.copy().reset_key()
-        chunk_op.params = {'size': chunk_shape, 'index': idx}  # to make op key different
+        chunk_op.params = {'size': chunk_shape}  # to make op key different
         return chunk_op
 
     @classmethod


Test patch:
diff --git a/mars/scheduler/tests/test_analyzer.py b/mars/scheduler/tests/test_analyzer.py
--- a/mars/scheduler/tests/test_analyzer.py
+++ b/mars/scheduler/tests/test_analyzer.py
@@ -42,8 +42,8 @@ def testDepths(self):
                 self.assertLessEqual(2, depths[n.op.key])
 
     def testDescendantSize(self):
-        arr = mt.ones((10, 10), chunk_size=4)
-        arr2 = mt.zeros((10, 10), chunk_size=4)
+        arr = mt.random.rand(10, 10, chunk_size=4)
+        arr2 = mt.random.rand(10, 10, chunk_size=4)
         arr_dot = arr.dot(arr2)
 
         graph = arr_dot.build_graph(compose=False, tiled=True)
diff --git a/mars/tensor/execution/tests/test_core_execute.py b/mars/tensor/execution/tests/test_core_execute.py
--- a/mars/tensor/execution/tests/test_core_execute.py
+++ b/mars/tensor/execution/tests/test_core_execute.py
@@ -35,7 +35,7 @@ def testDecref(self):
 
         b.execute(session=self.session)
 
-        self.assertEqual(len(self.executor.chunk_result), 8)
+        self.assertEqual(len(self.executor.chunk_result), 1)
 
         del b
         # decref called
diff --git a/mars/tensor/expressions/tests/test_core.py b/mars/tensor/expressions/tests/test_core.py
--- a/mars/tensor/expressions/tests/test_core.py
+++ b/mars/tensor/expressions/tests/test_core.py
@@ -23,7 +23,7 @@
 from mars.tensor import ones, zeros, tensor, full, arange, diag, linspace, triu, tril, ones_like, dot
 from mars.tensor.expressions.datasource import fromdense
 from mars.tensor.expressions.datasource.tri import TensorTriu, TensorTril
-from mars.tensor.expressions.datasource.zeros import TensorZeros
+from mars.tensor.expressions.datasource.zeros import zeros, TensorZeros
 from mars.tensor.expressions.datasource.fromdense import DenseToSparse
 from mars.tensor.expressions.datasource.array import CSRMatrixDataSource
 from mars.tensor.expressions.datasource.ones import TensorOnes, TensorOnesLike
@@ -232,6 +232,11 @@ def testOnes(self):
         self.assertNotEqual(chunk1.op.key, chunk2.op.key)
         self.assertNotEqual(chunk1.key, chunk2.key)
 
+        tensor = ones((100, 100), chunk_size=50)
+        tensor.tiles()
+        self.assertEqual(len({c.op.key for c in tensor.chunks}), 1)
+        self.assertEqual(len({c.key for c in tensor.chunks}), 1)
+
     def testZeros(self):
         tensor = zeros((2, 3, 4))
         self.assertEqual(len(list(tensor)), 2)
@@ -253,6 +258,11 @@ def testZeros(self):
         self.assertNotEqual(chunk1.op.key, chunk2.op.key)
         self.assertNotEqual(chunk1.key, chunk2.key)
 
+        tensor = zeros((100, 100), chunk_size=50)
+        tensor.tiles()
+        self.assertEqual(len({c.op.key for c in tensor.chunks}), 1)
+        self.assertEqual(len({c.key for c in tensor.chunks}), 1)
+
     def testDataSource(self):
         from mars.tensor.expressions.base.broadcast_to import TensorBroadcastTo
 
@@ -357,7 +367,7 @@ def testTensorGraphTiledSerialize(self):
         self.assertEqual(chunk.shape, chunk2.shape)
         self.assertEqual(sorted(i.key for i in chunk.inputs), sorted(i.key for i in chunk2.inputs))
 
-        t = ones((10, 3), chunk_size=(5, 2)) + 2
+        t = ones((10, 3), chunk_size=((3, 5, 2), 2)) + 2
         graph = t.build_graph(tiled=True)
 
         pb = graph.to_pb()
diff --git a/mars/tests/test_eager_mode.py b/mars/tests/test_eager_mode.py
--- a/mars/tests/test_eager_mode.py
+++ b/mars/tests/test_eager_mode.py
@@ -130,7 +130,7 @@ def testFetch(self):
             arr2 = mt.ones((10, 5), chunk_size=4) - 1
             result = arr2.fetch()
             np.testing.assert_array_equal(result[:4, :4], np.ones((4, 4)))
-            np.testing.assert_array_equal(result[4:8, :4], np.zeros((4, 4)))
+            np.testing.assert_array_equal(result[8:, :4], np.zeros((2, 4)))
 
         arr3 = mt.ones((10, 5), chunk_size=4) - 1
 
@@ -139,7 +139,7 @@ def testFetch(self):
 
         result = arr3.execute()
         np.testing.assert_array_equal(result[:4, :4], np.ones((4, 4)))
-        np.testing.assert_array_equal(result[4:8, :4], np.zeros((4, 4)))
+        np.testing.assert_array_equal(result[8:, :4], np.zeros((2, 4)))
 
     def testKernelMode(self):
         from mars.session import Session
diff --git a/mars/tests/test_session.py b/mars/tests/test_session.py
--- a/mars/tests/test_session.py
+++ b/mars/tests/test_session.py
@@ -249,8 +249,8 @@ def testDecref(self):
 
         executor = sess._sess._executor
 
-        self.assertEqual(len(executor.chunk_result), 8)
+        self.assertEqual(len(executor.chunk_result), 4)  # 4 kinds of shapes
         del arr1
-        self.assertEqual(len(executor.chunk_result), 8)
+        self.assertEqual(len(executor.chunk_result), 4)
         del arr2
         self.assertEqual(len(executor.chunk_result), 0)
diff --git a/mars/worker/tests/test_main.py b/mars/worker/tests/test_main.py
--- a/mars/worker/tests/test_main.py
+++ b/mars/worker/tests/test_main.py
@@ -43,8 +43,8 @@ def run_test(self, worker):
 
         session_id = str(uuid.uuid4())
 
-        a = mt.ones((100, 50), chunk_size=30)
-        b = mt.ones((50, 200), chunk_size=30)
+        a = mt.random.rand(100, 50, chunk_size=30)
+        b = mt.random.rand(50, 200, chunk_size=30)
         result = a.dot(b)
 
         graph = result.build_graph(tiled=True)