import torch


def indices_to_coors(voxel_indices, voxel_size, offset):
    """
    transform voxel indices to actual coordinates
    
    Args:
        voxel_indices : indices to be transformed, in N x 4 (B, Z, Y, X) ***[torch.Tensor]***
        voxel_size : size of a single voxel, in [Z, Y, X] ***[python built-in list]***
        offset : lower boundary of the space, in [Z, Y, X] ***[python built-in list]***

    """
    assert isinstance(voxel_indices, torch.Tensor), "invalid type of voxel_indices"
    assert len(voxel_indices.shape) == 2 and voxel_indices.shape[1] == 4, "wrong shape of voxel_indices"
    assert isinstance(voxel_size, list) and len(voxel_size) == 3, "invalid voxel_size"
    assert isinstance(offset, list) and len(offset) == 3, "invalid offset"

    res = voxel_indices.float()
    res[:, 1:] += 0.5
    res[:, 1:] *= torch.tensor(voxel_size, dtype=res.dtype, device=res.device)
    res[:, 1:] += torch.tensor(offset, dtype=res.dtype, device=res.device)
    return res