Checks orthonormality of the column vectors of a matrix.

    If a one-dimensional |nparray| is passed to `a`, it is treated as a single
    column vector, rather than a row matrix of length-one column vectors.

    The matrix `a` does not need to be square, though it must have at least
    as many rows as columns, since orthonormality is only possible in N-space
    with a set of no more than N vectors. (This condition is not directly
    checked.)

    Parameters
    ----------
    a
        R x S |npfloat_| --
        2-D array of column vectors to be checked for orthonormality.

    tol
        |npfloat_|, optional --
        Tolerance for deviation of dot products from one or zero. Default
        value is :data:`opan.const.DEF.ORTHONORM_TOL`.

    report
        |bool|, optional --
        Whether to record and return vectors / vector pairs failing the
        orthonormality condition. Default is |False|.

    Returns
    -------
    o
        |bool| --
        Indicates whether column vectors of `a` are orthonormal to within
        tolerance `tol`.

    n_fail
        |list| of |int|, or |None| --

        If `report` == |True|:

            A list of indices of column vectors
            failing the normality condition, or an empty list if all vectors
            are normalized.

        If `report` == |False|:

            |None|

    o_fail
        |list| of 2-tuples of |int|, or |None| --

        If `report` == |True|:

            A list of 2-tuples of indices of
            column vectors failing the orthogonality condition, or an
            empty list if all vectors are orthogonal.

        If `report` == |False|:

            |None|

def orthonorm_check(a, tol=_DEF.ORTHONORM_TOL, report=False):
    """Checks orthonormality of the column vectors of a matrix.

    If a one-dimensional |nparray| is passed to `a`, it is treated as a single
    column vector, rather than a row matrix of length-one column vectors.

    The matrix `a` does not need to be square, though it must have at least
    as many rows as columns, since orthonormality is only possible in N-space
    with a set of no more than N vectors. (This condition is not directly
    checked.)

    Parameters
    ----------
    a
        R x S |npfloat_| --
        2-D array of column vectors to be checked for orthonormality.

    tol
        |npfloat_|, optional --
        Tolerance for deviation of dot products from one or zero. Default
        value is :data:`opan.const.DEF.ORTHONORM_TOL`.

    report
        |bool|, optional --
        Whether to record and return vectors / vector pairs failing the
        orthonormality condition. Default is |False|.

    Returns
    -------
    o
        |bool| --
        Indicates whether column vectors of `a` are orthonormal to within
        tolerance `tol`.

    n_fail
        |list| of |int|, or |None| --

        If `report` == |True|:

            A list of indices of column vectors
            failing the normality condition, or an empty list if all vectors
            are normalized.

        If `report` == |False|:

            |None|

    o_fail
        |list| of 2-tuples of |int|, or |None| --

        If `report` == |True|:

            A list of 2-tuples of indices of
            column vectors failing the orthogonality condition, or an
            empty list if all vectors are orthogonal.

        If `report` == |False|:

            |None|

    """

    # Imports
    import numpy as np
    from .base import delta_fxn

    #!TODO? orthonorm_check Must add traps to ensure a is a single array,
    #    that it is 2D, that it's all real? To enforce the limits stated
    #    in the docstring?

    # Initialize return variables
    orth = True
    n_fail = []
    o_fail = []

    # Coerce to float_ matrix. Must treat 1-D vector as column vector.
    #  Should raise an exception for any objects with more than
    #  two dimensions; real and all-numeric are still not yet checked, but
    #  will probably be run-time caught if too bad an object is passed.
    if len(a.shape) == 1:
        a_mx = np.matrix(a, dtype=np.float_).T
    else:
        a_mx = np.matrix(a, dtype=np.float_)

    # Split matrix into separate vectors for convenient indexing.
    a_split = np.hsplit(a_mx, a_mx.shape[1])

    # Loop over vectors and check orthonormality.
    for iter1 in range(a_mx.shape[1]):
        for iter2 in range(iter1,a_mx.shape[1]):
            if not abs((a_split[iter1].T * a_split[iter2])[0,0] -
                        np.float_(delta_fxn(iter1, iter2))) <= tol:
                orth = False
                if report:
                    if iter1 == iter2:
                        n_fail.append(iter1)
                    else:
                        o_fail.append((iter1, iter2))

    # Return results
    if report:
        return orth, n_fail, o_fail
    else:
        return orth, None, None