# Buggy code
def decide_dataframe_chunk_sizes(shape, chunk_size, memory_usage):
    """
    Decide how a given DataFrame can be split into chunk.

    :param shape: DataFrame's shape
    :param chunk_size: if dict provided, it's dimension id to chunk size;
                       if provided, it's the chunk size for each dimension.
    :param memory_usage: pandas Series in which each column's memory usage
    :type memory_usage: pandas.Series
    :return: the calculated chunk size for each dimension
    :rtype: tuple
    """
    from ..config import options

    chunk_size = dictify_chunk_size(shape, chunk_size)
    average_memory_usage = memory_usage / shape[0]

    nleft = len(shape) - len(chunk_size)
    if nleft < 0:
        raise ValueError("chunks have more than two dimensions")
    if nleft == 0:
        return normalize_chunk_sizes(
            shape, tuple(chunk_size[j] for j in range(len(shape)))
        )

    max_chunk_size = options.chunk_store_limit

    # for the row side, along axis 0
    if 0 not in chunk_size:
        row_chunk_size = []
        row_left_size = shape[0]
    else:
        row_chunk_size = normalize_chunk_sizes((shape[0],), (chunk_size[0],))[0]
        row_left_size = -1
    # for the column side, along axis 1
    if 1 not in chunk_size:
        col_chunk_size = []
        col_chunk_store = []
        col_left_size = shape[1]
    else:
        col_chunk_size = normalize_chunk_sizes((shape[1],), (chunk_size[1],))[0]
        acc = [0] + np.cumsum(col_chunk_size).tolist()
        col_chunk_store = [
            average_memory_usage[acc[i] : acc[i + 1]].sum()
            for i in range(len(col_chunk_size))
        ]
        col_left_size = -1

    while True:
        nbytes_occupied = np.prod(
            [max(it) for it in (row_chunk_size, col_chunk_store) if it]
        )
        dim_size = np.maximum(
            int(np.power(max_chunk_size / nbytes_occupied, 1 / float(nleft))), 1
        )

        if col_left_size == 0:
            col_chunk_size.append(0)

        if row_left_size == 0:
            row_chunk_size.append(0)

        # check col first
        if col_left_size > 0:
            cs = min(col_left_size, dim_size)
            col_chunk_size.append(cs)
            start = int(np.sum(col_chunk_size[:-1]))
            col_chunk_store.append(average_memory_usage.iloc[start : start + cs].sum())
            col_left_size -= cs
        if row_left_size > 0:
            max_col_chunk_store = max(col_chunk_store)
            cs = min(row_left_size, int(max_chunk_size / max_col_chunk_store))
            row_chunk_size.append(cs)
            row_left_size -= cs

        if col_left_size <= 0 and row_left_size <= 0:
            break

    return tuple(row_chunk_size), tuple(col_chunk_size)


# Traceback (NotImplementedError)
In [52]: df = md.DataFrame(index=[1, 2, 3])

In [53]: df['a'] = md.Series(['a', 'b', 'c'], index=[2, 3, 4])
---------------------------------------------------------------------------
NotImplementedError                       Traceback (most recent call last)
<ipython-input-53-f550a59ef82c> in <module>
----> 1 df['a'] = md.Series(['a', 'b', 'c'], index=[2, 3, 4])

~/Workspace/mars/mars/dataframe/indexing/setitem.py in dataframe_setitem(df, col, value)
182 def dataframe_setitem(df, col, value):
183     op = DataFrameSetitem(target=df, indexes=col, value=value)
--> 184     return op(df, value)

~/Workspace/mars/mars/utils.py in _inner(*args, **kwargs)
457         @functools.wraps(func)
458         def _inner(*args, **kwargs):
--> 459             with self:
460                 return func(*args, **kwargs)
461

~/Workspace/mars/mars/dataframe/indexing/setitem.py in __call__(self, target, value)
83
84             if value.index_value.key != target.index_value.key:  # pragma: no cover
---> 85                 raise NotImplementedError('Does not support setting value '
86                                           'with different index for now')
87

NotImplementedError: Does not support setting value with different index for now

# Fixed code
def decide_dataframe_chunk_sizes(shape, chunk_size, memory_usage):
    """
    Decide how a given DataFrame can be split into chunk.

    :param shape: DataFrame's shape
    :param chunk_size: if dict provided, it's dimension id to chunk size;
                       if provided, it's the chunk size for each dimension.
    :param memory_usage: pandas Series in which each column's memory usage
    :type memory_usage: pandas.Series
    :return: the calculated chunk size for each dimension
    :rtype: tuple
    """
    from ..config import options

    chunk_size = dictify_chunk_size(shape, chunk_size)
    average_memory_usage = memory_usage / shape[0]

    nleft = len(shape) - len(chunk_size)
    if nleft < 0:
        raise ValueError("chunks have more than two dimensions")
    if nleft == 0:
        return normalize_chunk_sizes(
            shape, tuple(chunk_size[j] for j in range(len(shape)))
        )

    max_chunk_size = options.chunk_store_limit

    # for the row side, along axis 0
    if 0 not in chunk_size:
        row_chunk_size = []
        row_left_size = shape[0]
    else:
        row_chunk_size = normalize_chunk_sizes((shape[0],), (chunk_size[0],))[0]
        row_left_size = -1
    # for the column side, along axis 1
    if 1 not in chunk_size:
        col_chunk_size = []
        col_chunk_store = []
        col_left_size = shape[1]
    else:
        col_chunk_size = normalize_chunk_sizes((shape[1],), (chunk_size[1],))[0]
        acc = [0] + np.cumsum(col_chunk_size).tolist()
        col_chunk_store = [
            average_memory_usage[acc[i] : acc[i + 1]].sum()
            for i in range(len(col_chunk_size))
        ]
        col_left_size = -1

    while True:
        nbytes_occupied = np.prod(
            [max(it) for it in (row_chunk_size, col_chunk_store) if it]
        )
        dim_size = np.maximum(
            int(np.power(max_chunk_size / nbytes_occupied, 1 / float(nleft))), 1
        )

        if col_left_size == 0:
            col_chunk_size.append(0)

        if row_left_size == 0:
            row_chunk_size.append(0)

        # check col first
        if col_left_size > 0:
            cs = min(col_left_size, dim_size)
            col_chunk_size.append(cs)
            start = int(np.sum(col_chunk_size[:-1]))
            col_chunk_store.append(average_memory_usage.iloc[start : start + cs].sum())
            col_left_size -= cs
        if row_left_size > 0:
            if col_chunk_store:
                max_col_chunk_store = max(col_chunk_store)
                cs = min(row_left_size, int(max_chunk_size / max_col_chunk_store))
            else:
                cs = row_left_size
            row_chunk_size.append(cs)
            row_left_size -= cs

        if col_left_size <= 0 and row_left_size <= 0:
            break

    return tuple(row_chunk_size), tuple(col_chunk_size)