Repository: mars-project/mars

Issue:
[BUG] Arithmetic runs failed with error `TypeError: Cannot interpret '0' as a data type`
<!--
Thank you for your contribution!

Please review https://github.com/mars-project/mars/blob/master/CONTRIBUTING.rst before opening an issue.
-->

**Describe the bug**

Arithmetic runs failed with error `TypeError: Cannot interpret '0' as a data type`.

**To Reproduce**
To help us reproducing this bug, please provide information below:
1. Your Python version
2. The version of Mars you use
3. Versions of crucial packages, such as numpy, scipy and pandas
4. Full stack of the error.
5. Minimized code to reproduce the error.

```
In [1]: import mars

In [2]: mars.new_session()
Web service started at http://0.0.0.0:17929
Out[2]: <mars.deploy.oscar.session.SyncSession at 0x7fc5dc2691f0>

In [3]: import mars.tensor as mt

In [4]: import mars.dataframe as md

In [5]: df = md.DataFrame(mt.random.rand(10, 3, chunk_size=(5, 3)))

In [6]: (df[0] != df.sort_values([0])[0].shift(-1)).execute()
  0%|                                                                                                                                                                               | 0/100 [00:00<?, ?it/s]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-6-0ec930a9c4dd> in <module>
----> 1 (df[0] != df.sort_values([0])[0].shift(-1)).execute()

~/Workspace/mars/mars/core/entity/tileables.py in execute(self, session, **kw)
    442 
    443     def execute(self, session=None, **kw):
--> 444         result = self.data.execute(session=session, **kw)
    445         if isinstance(result, TILEABLE_TYPE):
    446             return self

~/Workspace/mars/mars/core/entity/executable.py in execute(self, session, **kw)
    102 
    103         session = _get_session(self, session)
--> 104         return execute(self, session=session, **kw)
    105 
    106     def _check_session(self,

~/Workspace/mars/mars/deploy/oscar/session.py in execute(tileable, session, wait, new_session_kwargs, show_progress, progress_update_interval, *tileables, **kwargs)
   1465             **(new_session_kwargs or dict()))
   1466     session = _ensure_sync(session)
-> 1467     return session.execute(tileable, *tileables, wait=wait,
   1468                            show_progress=show_progress,
   1469                            progress_update_interval=progress_update_interval,

~/Workspace/mars/mars/deploy/oscar/session.py in execute(self, tileable, show_progress, *tileables, **kwargs)
   1304         fut = asyncio.run_coroutine_threadsafe(coro, self._loop)
   1305         try:
-> 1306             execution_info: ExecutionInfo = fut.result(
   1307                 timeout=self._isolated_session.timeout)
   1308         except KeyboardInterrupt:  # pragma: no cover

~/miniconda3/envs/mars3.8/lib/python3.8/concurrent/futures/_base.py in result(self, timeout)
    437                 raise CancelledError()
    438             elif self._state == FINISHED:
--> 439                 return self.__get_result()
    440             else:
    441                 raise TimeoutError()

~/miniconda3/envs/mars3.8/lib/python3.8/concurrent/futures/_base.py in __get_result(self)
    386     def __get_result(self):
    387         if self._exception:
--> 388             raise self._exception
    389         else:
    390             return self._result

~/Workspace/mars/mars/deploy/oscar/session.py in _execute(session, wait, show_progress, progress_update_interval, cancelled, *tileables, **kwargs)
   1423                 while not cancelled.is_set():
   1424                     try:
-> 1425                         await asyncio.wait_for(asyncio.shield(execution_info),
   1426                                                progress_update_interval)
   1427                         # done

~/miniconda3/envs/mars3.8/lib/python3.8/asyncio/tasks.py in wait_for(fut, timeout, loop)
    481 
    482         if fut.done():
--> 483             return fut.result()
    484         else:
    485             fut.remove_done_callback(cb)

~/miniconda3/envs/mars3.8/lib/python3.8/asyncio/tasks.py in _wrap_awaitable(awaitable)
    682     that will later be wrapped in a Task by ensure_future().
    683     """
--> 684     return (yield from awaitable.__await__())
    685 
    686 _wrap_awaitable._is_coroutine = _is_coroutine

~/Workspace/mars/mars/deploy/oscar/session.py in wait()
     75         except AttributeError:
     76             async def wait():
---> 77                 return await self._aio_task
     78 
     79             self._future_local.future = fut = \

~/Workspace/mars/mars/deploy/oscar/session.py in _run_in_background(self, tileables, task_id, progress)
    707                         raise TimeoutError(f'Task({task_id}) running time > {self.timeout}')
    708             if task_result.error:
--> 709                 raise task_result.error.with_traceback(task_result.traceback)
    710             if cancelled:
    711                 return

~/Workspace/mars/mars/services/task/supervisor/processor.py in inner(processor, *args, **kwargs)
     47     async def inner(processor: "TaskProcessor", *args, **kwargs):
     48         try:
---> 49             return await func(processor, *args, **kwargs)
     50         except:  # noqa: E722  # nosec  # pylint: disable=bare-except  # pragma: no cover
     51             processor._err_infos.append(sys.exc_info())

~/Workspace/mars/mars/services/task/supervisor/processor.py in get_next_stage_processor(self)
    293         self._init_chunk_graph_iter(tileable_graph)
    294 
--> 295         chunk_graph = await self._get_next_chunk_graph(self._chunk_graph_iter)
    296         if chunk_graph is None:
    297             # tile finished

~/Workspace/mars/mars/services/task/supervisor/processor.py in _get_next_chunk_graph(self, chunk_graph_iter)
    228 
    229         fut = asyncio.to_thread(next_chunk_graph)
--> 230         chunk_graph = await fut
    231         return chunk_graph
    232 

~/Workspace/mars/mars/lib/aio/_threads.py in to_thread(func, *args, **kwargs)
     34     ctx = contextvars.copy_context()
     35     func_call = functools.partial(ctx.run, func, *args, **kwargs)
---> 36     return await loop.run_in_executor(None, func_call)

~/miniconda3/envs/mars3.8/lib/python3.8/concurrent/futures/thread.py in run(self)
     55 
     56         try:
---> 57             result = self.fn(*self.args, **self.kwargs)
     58         except BaseException as exc:
     59             self.future.set_exception(exc)

~/Workspace/mars/mars/services/task/supervisor/processor.py in next_chunk_graph()
    223         def next_chunk_graph():
    224             try:
--> 225                 return next(chunk_graph_iter)
    226             except StopIteration:
    227                 return

~/Workspace/mars/mars/services/task/supervisor/preprocessor.py in tile(self, tileable_graph)
    139         optimize = self._config.optimize_chunk_graph
    140         meta_updated = set()
--> 141         for chunk_graph in chunk_graph_builder.build():
    142             # optimize chunk graph
    143             if optimize:

~/Workspace/mars/mars/core/graph/builder/chunk.py in build(self)
    235     def build(self) -> Generator[Union[TileableGraph, ChunkGraph], None, None]:
    236         with enter_mode(build=True, kernel=True):
--> 237             yield from self._build()

~/Workspace/mars/mars/core/graph/builder/chunk.py in _build(self)
    231 
    232     def _build(self) -> Iterable[Union[TileableGraph, ChunkGraph]]:
--> 233         yield from self.tiler
    234 
    235     def build(self) -> Generator[Union[TileableGraph, ChunkGraph], None, None]:

~/Workspace/mars/mars/services/task/supervisor/preprocessor.py in __iter__(self)
     67     def __iter__(self):
     68         while self._tileable_handlers:
---> 69             to_update_tileables = self._iter()
     70             if not self.cancelled:
     71                 yield self._cur_chunk_graph

~/Workspace/mars/mars/core/graph/builder/chunk.py in _iter(self)
    176         for tileable, tile_handler in \
    177                 self._gen_tileable_handlers(next_tileable_handlers):
--> 178             self._tile(chunk_graph, tileable, tile_handler,
    179                        next_tileable_handlers, to_update_tileables, visited)
    180         self._tileable_handlers = next_tileable_handlers

~/Workspace/mars/mars/core/graph/builder/chunk.py in _tile(self, chunk_graph, tileable, tile_handler, next_tileable_handlers, to_update_tileables, visited)
     92               visited: Set[EntityType]):
     93         try:
---> 94             need_process = next(tile_handler)
     95             chunks = []
     96             if need_process is not None:

~/Workspace/mars/mars/core/graph/builder/chunk.py in _tile_handler(self, tileable)
     68         tiled_tileables = [self._get_data(t) for t in tiled_tileables]
     69         # start to tile
---> 70         tiled_tileables = yield from handler.tile(tiled_tileables)
     71         return tiled_tileables
     72 

~/Workspace/mars/mars/core/entity/tileables.py in tile(cls, tileables)
     75                 # they will be put into ChunkGraph and executed first.
     76                 # After execution, resume from the yield place.
---> 77                 tiled_result = yield from tile_handler(op)
     78             else:
     79                 # without iterative tiling

~/Workspace/mars/mars/dataframe/arithmetic/core.py in tile(cls, op)
    225             return cls._tile_both_dataframes(op)
    226         elif isinstance(op.inputs[0], SERIES_TYPE) and isinstance(op.inputs[1], SERIES_TYPE):
--> 227             return cls._tile_both_series(op)
    228         elif isinstance(op.inputs[0], DATAFRAME_TYPE) and isinstance(op.inputs[1], SERIES_TYPE):
    229             return cls._tile_dataframe_series(op)

~/Workspace/mars/mars/dataframe/arithmetic/core.py in _tile_both_series(cls, op)
     65         out_chunks = []
     66         for idx, left_chunk, right_chunk in zip(range(out_shape[0]), left_chunks, right_chunks):
---> 67             out_chunk = op.copy().reset_key().new_chunk([left_chunk, right_chunk],
     68                                                         shape=(nsplits[0][idx],), index=(idx,))
     69             out_chunks.append(out_chunk)

~/Workspace/mars/mars/core/operand/core.py in new_chunk(self, inputs, kws, **kw)
    156             raise TypeError('cannot new chunk with more than 1 outputs')
    157 
--> 158         return self.new_chunks(inputs, kws=kws, **kw)[0]
    159 
    160     @staticmethod

~/Workspace/mars/mars/core/operand/core.py in new_chunks(self, inputs, kws, **kwargs)
    147             Override the method `_new_chunks` if needed.
    148         """
--> 149         return self._new_chunks(inputs, kws=kws, **kwargs)
    150 
    151     def new_chunk(self,

~/Workspace/mars/mars/dataframe/arithmetic/core.py in _new_chunks(self, inputs, kws, **kw)
    425                     isinstance(property_inputs[0], (TENSOR_TYPE, TENSOR_CHUNK_TYPE)):
    426                 property_inputs = reversed(property_inputs)
--> 427             properties = self._calc_properties(*property_inputs)
    428 
    429         inputs = [inp for inp in inputs if isinstance(inp, (Chunk, ChunkData))]

~/Workspace/mars/mars/dataframe/arithmetic/core.py in _calc_properties(cls, x1, x2, axis)
    404 
    405             ret = {'shape': (index_shape,), 'dtype': dtype, 'index_value': index}
--> 406             if x1.name == x2.name:
    407                 ret['name'] = x1.name
    408             return ret

TypeError: Cannot interpret '0' as a data type

```



Discussion:

Resolving patch:
diff --git a/mars/dataframe/align.py b/mars/dataframe/align.py
--- a/mars/dataframe/align.py
+++ b/mars/dataframe/align.py
@@ -154,7 +154,7 @@ def build_map_chunk_kw(self, inputs, **kw):
             if kw.get('dtype', None) is None and getattr(inputs[0], 'dtype', None) is not None:
                 kw['dtype'] = inputs[0].dtype
             if kw.get('name', None) is None and getattr(inputs[0], 'name', None) is not None:
-                kw['name'] = inputs[0].dtype
+                kw['name'] = inputs[0].name
         return kw
 
     def build_reduce_chunk_kw(self, inputs, index, **kw):
@@ -192,7 +192,7 @@ def build_reduce_chunk_kw(self, inputs, index, **kw):
             if kw.get('dtype', None) is None and getattr(inputs[0].inputs[0], 'dtype', None) is not None:
                 kw['dtype'] = inputs[0].inputs[0].dtype
             if kw.get('name', None) is None and getattr(inputs[0].inputs[0], 'name', None) is not None:
-                kw['name'] = inputs[0].inputs[0].dtype
+                kw['name'] = inputs[0].inputs[0].name
         return kw
 
     @classmethod


Test patch:
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
@@ -472,3 +472,12 @@ def print_fun():
     rm.execute()
     logs = str(rm.fetch_log()).strip()
     assert logs == 'inner\nafter'
+
+
+def test_align_series(setup):
+    t = np.random.rand(10, 3)
+    pdf = pd.DataFrame(t)
+    df = md.DataFrame(pdf, chunk_size=(5, 3))
+    r = df[0] != df.sort_index()[0].shift(-1)
+    expected = pdf[0] != pdf.sort_index()[0].shift(-1)
+    pd.testing.assert_series_equal(r.execute().fetch(), expected)