# Buggy code
def unify_nsplits(*tensor_axes):
    from .rechunk import rechunk

    tensor_splits = [
        dict((a, split) for a, split in izip(axes, t.nsplits) if split != (1,))
        for t, axes in tensor_axes
    ]
    common_axes = reduce(operator.and_, [set(lkeys(ts)) for ts in tensor_splits])
    axes_unified_splits = dict(
        (ax, decide_unify_split(*(t[ax] for t in tensor_splits))) for ax in common_axes
    )

    if len(common_axes) == 0:
        return tuple(t[0] for t in tensor_axes)

    res = []
    for t, axes in tensor_axes:
        new_chunk = dict(
            (i, axes_unified_splits[ax])
            for ax, i in zip(axes, range(t.ndim))
            if ax in axes_unified_splits
        )
        res.append(rechunk(t, new_chunk).single_tiles())

    return tuple(res)


# Traceback (KeyError)
In [5]: import mars.tensor as mt

In [6]: a = mt.random.rand(1, 10, chunk_size=3)

In [7]: b = mt.add(a[:, :5], 1, out=a[:, 5:])

In [8]: b.execute()
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
~/Documents/mars_dev/mars/mars/tiles.py in _dispatch(self, op)
110         try:
--> 111             handler = self._handlers[op_cls]
112             return handler(op)

KeyError: <class 'mars.tensor.expressions.arithmetic.add.TensorAdd'>

During handling of the above exception, another exception occurred:

ValueError                                Traceback (most recent call last)
<ipython-input-8-be8c8c42b9b4> in <module>
----> 1 b.execute()

~/Documents/mars_dev/mars/mars/tensor/core.py in execute(self, session, **kw)
394
395     def execute(self, session=None, **kw):
--> 396         return self._data.execute(session, **kw)
397
398

~/Documents/mars_dev/mars/mars/core.py in execute(self, session, **kw)
553         if session is None:
554             session = Session.default_or_local()
--> 555         return session.run(self, **kw)
556
557     def fetch(self, session=None, **kw):

~/Documents/mars_dev/mars/mars/session.py in run(self, *tileables, **kw)
113         tileables = tuple(mt.tensor(t) if not isinstance(t, (Entity, Base)) else t
114                           for t in tileables)
--> 115         result = self._sess.run(*tileables, **kw)
116
117         for t in tileables:

~/Documents/mars_dev/mars/mars/session.py in run(self, *tileables, **kw)
54         if 'n_parallel' not in kw:
55             kw['n_parallel'] = cpu_count()
---> 56         res = self._executor.execute_tileables(tileables, **kw)
57         return res
58

~/Documents/mars_dev/mars/mars/utils.py in _wrapped(*args, **kwargs)
387         try:
388             _kernel_mode.eager = False
--> 389             return func(*args, **kwargs)
390         finally:
391             _kernel_mode.eager = None

~/Documents/mars_dev/mars/mars/executor.py in execute_tileables(self, tileables, fetch, n_parallel, n_thread, print_progress, mock, compose)
523         concat_keys = []
524         for tileable in tileables:
--> 525             tileable.tiles()
526             chunk_keys = [c.key for c in tileable.chunks]
527             result_keys.extend(chunk_keys)

~/Documents/mars_dev/mars/mars/core.py in tiles(self)
472
473     def tiles(self):
--> 474         return handler.tiles(self)
475
476     def single_tiles(self):

~/Documents/mars_dev/mars/mars/tiles.py in tiles(self, tiles_obj)
172             if not preds or accessible:
173                 if node.is_coarse() and node.op:
--> 174                     tiled = self._dispatch(node.op)
175                     self._assign_to([t.data for t in tiled], node.op.outputs)
176                 visited.add(node)

~/Documents/mars_dev/mars/mars/utils.py in _wrapped(*args, **kwargs)
387         try:
388             _kernel_mode.eager = False
--> 389             return func(*args, **kwargs)
390         finally:
391             _kernel_mode.eager = None

~/Documents/mars_dev/mars/mars/tiles.py in _dispatch(self, op)
114             if hasattr(op_cls, 'tile'):
115                 # has tile implementation
--> 116                 return op_cls.tile(op)
117             for op_clz in self._handlers.keys():
118                 if issubclass(op_cls, op_clz):

~/Documents/mars_dev/mars/mars/tensor/expressions/arithmetic/core.py in tile(cls, op)
36
37         chunk_shapes = [t.chunk_shape for t in inputs]
---> 38         out_chunk_shape = broadcast_shape(*chunk_shapes)
39
40         out_chunks = [list() for _ in op.outputs]

~/Documents/mars_dev/mars/mars/tensor/expressions/utils.py in broadcast_shape(*shapes)
76         if any(i != -1 and i != 1 and i != shape and not np.isnan(i) for i in ss):
77             raise ValueError('Operands could not be broadcast together '
---> 78                              'with shape {0}'.format(' '.join(map(str, shapes))))
79         out_shapes.append(shape)
80     return tuple(reversed(out_shapes))

ValueError: Operands could not be broadcast together with shape (1, 2) () (1, 3)

# Fixed code
def unify_nsplits(*tensor_axes):
    from .rechunk import rechunk

    tensor_splits = [
        dict((a, split) for a, split in izip(axes, t.nsplits) if split != (1,))
        for t, axes in tensor_axes
        if t.nsplits
    ]
    common_axes = (
        reduce(operator.and_, [set(lkeys(ts)) for ts in tensor_splits])
        if tensor_splits
        else set()
    )
    axes_unified_splits = dict(
        (ax, decide_unify_split(*(t[ax] for t in tensor_splits))) for ax in common_axes
    )

    if len(common_axes) == 0:
        return tuple(t[0] for t in tensor_axes)

    res = []
    for t, axes in tensor_axes:
        new_chunk = dict(
            (i, axes_unified_splits[ax])
            for ax, i in zip(axes, range(t.ndim))
            if ax in axes_unified_splits
        )
        res.append(rechunk(t, new_chunk).single_tiles())

    return tuple(res)