def multi_dot(
    arrays: Sequence[ndarray], *, out: ndarray | None = None
) -> ndarray:
    """
    Compute the dot product of two or more arrays in a single function call,
    while automatically selecting the fastest evaluation order.
    `multi_dot` chains `dot` and uses optimal parenthesization
    of the matrices.

    Parameters
    ----------
    arrays : Sequence[array_like]
        If the first argument is 1-D it is treated as a row vector.
        If the last argument is 1-D it is treated as a column vector.
        The other arguments must be 2-D.
    out : ndarray, optional
        Output argument. This must have the same shape and dtype that would be
        returned if it was not used.

    Returns
    -------
    output : ndarray
        Returns the dot product of the supplied arrays.

    See Also
    --------
    numpy.linalg.multi_dot

    Availability
    --------
    Multiple GPUs, Multiple CPUs
    """
    arrays = [convert_to_cupynumeric_ndarray(x) for x in arrays]
    if out is not None:
        out = convert_to_cupynumeric_ndarray(out, share=True)

    n = len(arrays)
    # optimization only makes sense for len(arrays) > 2
    if n < 2:
        raise ValueError("multi_dot expects at least two arrays")
    elif n == 2:
        return dot(arrays[0], arrays[1], out=out)

    # save original ndim to reshape the result array into the proper form later
    ndim_first, ndim_last = arrays[0].ndim, arrays[-1].ndim
    # Explicitly convert vectors to 2D arrays to keep the logic of the internal
    # _multi_dot_* functions as simple as possible.
    if arrays[0].ndim == 1:
        arrays[0] = arrays[0][np.newaxis, :]
        if out is not None:
            out = out[np.newaxis, ...]
    if arrays[-1].ndim == 1:
        arrays[-1] = arrays[-1][:, np.newaxis]
        if out is not None:
            out = out[..., np.newaxis]
    for x in arrays:
        if x.ndim != 2:
            raise ValueError("Invalid shape for multi_dot input array")
    if out is not None and out.ndim != 2:
        raise ValueError("Invalid shape for multi_dot output array")

    # _multi_dot_three is much faster than _multi_dot_matrix_chain_order
    if n == 3:
        result = _multi_dot_three(arrays[0], arrays[1], arrays[2], out=out)
    else:
        order = _multi_dot_matrix_chain_order(arrays)
        result = _multi_dot(arrays, order, 0, n - 1, out=out)

    # return proper shape
    if ndim_first == 1 and ndim_last == 1:
        return result.reshape(())  # scalar
    elif ndim_first == 1 or ndim_last == 1:
        return result.ravel()  # 1-D
    else:
        return result

    Compute the dot product of two or more arrays in a single function call,
    while automatically selecting the fastest evaluation order.
    `multi_dot` chains `dot` and uses optimal parenthesization
    of the matrices.

    Parameters
    ----------
    arrays : Sequence[array_like]
        If the first argument is 1-D it is treated as a row vector.
        If the last argument is 1-D it is treated as a column vector.
        The other arguments must be 2-D.
    out : ndarray, optional
        Output argument. This must have the same shape and dtype that would be
        returned if it was not used.

    Returns
    -------
    output : ndarray
        Returns the dot product of the supplied arrays.

    See Also
    --------
    numpy.linalg.multi_dot

    Availability
    --------
    Multiple GPUs, Multiple CPUs
    
cupynumeric/linalg/linalg.py