import torch


def maybe_cat(tensors, dim, nullable=None):
    """Like torch.cat, but skips elements in `tensors` which are None.

    Args:
        tensors: List of tensors (compare torch.cat())
        dim: Dimension along which to concatenate (compare to torch.cat())
        nullable: List of the same length as `tensors`. If specified, throw
            a RuntimeError if the i-th element in `tensors` is None and the
            i-th element in nullable is False.

    Returns:
        Concatenation of all tensors in `tensors` along `dim` which are not
        None.

    Throws:
        RuntimeError is `nullable` constraint is violated or all alements in
        `tensors` are None.
    """
    if nullable is not None and any(
        (t is None) and not n for t, n in zip(tensors, nullable)
    ):
        raise RuntimeError("Unexpected element in tensors is None.")
    filtered = [t for t in tensors if t is not None]
    if len(filtered) == 1:
        return filtered[0]
    return torch.cat(filtered, dim=dim)