from operator import inv


def woodbury_inverse_full(Ai, U, Ci, V):
    """
    Matrix inversion lemma Woodbury-Sherman-Morrison in its general form.

    .. math::
        (\mathbf{A} + \mathbf{UCV})^{-1}

    :param Ai: (``numpy.ndarray``)  Inverse of a square matrix of shape ``(n, n)``.

    :param U: (``numpy.ndarray``)  Matrix of shape ``(n, k)``.

    :param Ci: (``numpy.ndarray``)  Inverse of square matrix of shape ``(k, k)``.

    :param V: (``numpy.ndarray``)  Matrix of shape ``(k, n)``.

    :return: (``numpy.ndarray``)  The solution to the above equation by inverting A and C. The solution is of shape ``(n, n)``.
    """
    return Ai - Ai.dot(U).dot(inv(Ci + V.dot(Ai).dot(U))).dot(V.dot(Ai))