# Buggy code
def decide_chunk_sizes(shape, chunk_size, itemsize):
    """
    Decide how a given tensor can be split into chunk.

    :param shape: tensor'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 itemsize: element size
    :return: the calculated chunk size for each dimension
    :rtype: tuple
    """

    from ...config import options

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

    max_chunk_size = options.tensor.chunk_store_limit

    # normalize the dimension which specified first
    dim_to_normalized = {
        i: normalize_chunk_sizes((shape[i],), (c,))[0]
        for i, c in six.iteritems(chunk_size)
    }

    left = {j: [] for j in range(len(shape)) if j not in dim_to_normalized}
    left_unsplit = {j: shape[j] for j in left}
    while True:
        nbytes_occupied = (
            np.prod([max(c) for c in six.itervalues(dim_to_normalized)]) * itemsize
        )
        dim_size = np.maximum(
            int(np.power(max_chunk_size / nbytes_occupied, 1 / float(len(left)))), 1
        )
        for j, ns in six.iteritems(left.copy()):
            unsplit = left_unsplit[j]
            ns.append(np.minimum(unsplit, dim_size))
            left_unsplit[j] -= ns[-1]
            if left_unsplit[j] <= 0:
                dim_to_normalized[j] = tuple(ns)
                del left[j]

        if len(left) == 0:
            break

    return tuple(dim_to_normalized[i] for i in range(len(dim_to_normalized)))


# Traceback (IndexError)
In [1]: import mars.tensor as mt

In [2]: a = mt.arange(12)

In [3]: a.totiledb('test_tiledb').execute()
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-3-5174935f197d> in <module>
----> 1 a.totiledb('test_tiledb').execute()

~/Documents/mars_dev/mars/mars/tensor/core.py in execute(self, session, **kw)
378
379     def execute(self, session=None, **kw):
--> 380         return self._data.execute(session, **kw)
381
382

~/Documents/mars_dev/mars/mars/tensor/core.py in execute(self, session, **kw)
168         if session is None:
169             session = Session.default_or_local()
--> 170         return session.run(self, **kw)
171
172     def fetch(self, session=None, **kw):

~/Documents/mars_dev/mars/mars/session.py in run(self, *tensors, **kw)
107
108         tensors = tuple(mt.tensor(t) for t in tensors)
--> 109         result = self._sess.run(*tensors, **kw)
110
111         for t in tensors:

~/Documents/mars_dev/mars/mars/session.py in run(self, *tensors, **kw)
49         if 'n_parallel' not in kw:
50             kw['n_parallel'] = cpu_count()
---> 51         res = self._executor.execute_tensors(tensors, **kw)
52         return res
53

~/Documents/mars_dev/mars/mars/utils.py in _wrapped(*args, **kwargs)
350         try:
351             _kernel_mode.eager = False
--> 352             return func(*args, **kwargs)
353         finally:
354             _kernel_mode.eager = None

~/Documents/mars_dev/mars/mars/executor.py in execute_tensors(self, tensors, fetch, n_parallel, n_thread, print_progress, mock, compose)
530
531         self.execute_graph(graph, result_keys, n_parallel=n_parallel or n_thread,
--> 532                            print_progress=print_progress, mock=mock)
533
534         results = self._chunk_result

~/Documents/mars_dev/mars/mars/executor.py in execute_graph(self, graph, keys, n_parallel, print_progress, mock, retval)
464                                          print_progress=print_progress, mock=mock,
465                                          mock_max_memory=self._mock_max_memory)
--> 466         res = graph_execution.execute(retval)
467         self._mock_max_memory = max(self._mock_max_memory, graph_execution._mock_max_memory)
468         if mock:

~/Documents/mars_dev/mars/mars/executor.py in execute(self, retval)
377         # wait until all the futures completed
378         for future in executed_futures:
--> 379             future.result()
380
381         # update with the maximal memory cost during the whole execution

~/miniconda3/lib/python3.7/concurrent/futures/_base.py in result(self, timeout)
430                 raise CancelledError()
431             elif self._state == FINISHED:
--> 432                 return self.__get_result()
433             else:
434                 raise TimeoutError()

~/miniconda3/lib/python3.7/concurrent/futures/_base.py in __get_result(self)
382     def __get_result(self):
383         if self._exception:
--> 384             raise self._exception
385         else:
386             return self._result

~/miniconda3/lib/python3.7/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)

~/Documents/mars_dev/mars/mars/executor.py in _execute_operand(self, op)
260             # so we pass the first operand's first output to Executor.handle
261             first_op = ops[0]
--> 262             Executor.handle(first_op.outputs[0], results, self._mock)
263
264             # update maximal memory usage during execution

~/Documents/mars_dev/mars/mars/executor.py in handle(cls, chunk, results, mock)
450     def handle(cls, chunk, results, mock=False):
451         if not mock:
--> 452             return cls._get_op_runner(chunk, cls._op_runners)(results, chunk)
453         else:
454             return cls._get_op_runner(chunk, cls._op_size_estimators)(results, chunk)

~/Documents/mars_dev/mars/mars/tensor/execution/datastore.py in _store_tiledb(ctx, chunk)
44         with tiledb.DenseArray(uri=uri, ctx=tiledb_ctx, mode='w',
45                                key=key, timestamp=timestamp) as arr:
---> 46             arr[tuple(slcs)] = to_store
47         ctx[chunk.key] = np.empty((0,) * chunk.ndim, dtype=chunk.dtype)
48     else:

tiledb/libtiledb.pyx in tiledb.libtiledb.DenseArray.__setitem__()

tiledb/libtiledb.pyx in tiledb.libtiledb.index_domain_subarray()

IndexError: too many indices for array

# Fixed code
def decide_chunk_sizes(shape, chunk_size, itemsize):
    """
    Decide how a given tensor can be split into chunk.

    :param shape: tensor'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 itemsize: element size
    :return: the calculated chunk size for each dimension
    :rtype: tuple
    """

    from ...config import options

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

    max_chunk_size = options.tensor.chunk_store_limit

    # normalize the dimension which specified first
    dim_to_normalized = {
        i: normalize_chunk_sizes((shape[i],), (c,))[0]
        for i, c in six.iteritems(chunk_size)
    }

    left = {j: [] for j in range(len(shape)) if j not in dim_to_normalized}
    left_unsplit = {j: shape[j] for j in left}
    while True:
        nbytes_occupied = (
            np.prod([max(c) for c in six.itervalues(dim_to_normalized)]) * itemsize
        )
        dim_size = np.maximum(
            int(np.power(max_chunk_size / nbytes_occupied, 1 / float(len(left)))), 1
        )
        for j, ns in six.iteritems(left.copy()):
            unsplit = left_unsplit[j]
            ns.append(int(np.minimum(unsplit, dim_size)))
            left_unsplit[j] -= ns[-1]
            if left_unsplit[j] <= 0:
                dim_to_normalized[j] = tuple(ns)
                del left[j]

        if len(left) == 0:
            break

    return tuple(dim_to_normalized[i] for i in range(len(dim_to_normalized)))