<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def gram_schmidt(matrix, return_opt='orthonormal'):
 r"""Gram-Schmit This method orthonormalizes the row vectors of the input matrix. Parameters matrix : np.ndarray Input matrix array return_opt : str {orthonormal, orthogonal, both} Option to return u, e or both. Returns ------- Lists of orthogonal vectors, u, and/or orthonormal vectors, e Examples -------- array([[ 0. , 0.4472136 , 0.89442719], [ 0.91287093, 0.36514837, -0.18257419], [-1. , 0. , 0. ]]) Notes ----- Implementation from: https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process """


    if return_opt not in ('orthonormal', 'orthogonal', 'both'):
        raise ValueError('Invalid return_opt, options are: "orthonormal", '
                         '"orthogonal" or "both"')

    u = []
    e = []

    for vector in matrix:

        if len(u) == 0:
            u_now = vector
        else:
            u_now = vector - sum([project(u_i, vector) for u_i in u])

        u.append(u_now)
        e.append(u_now / np.linalg.norm(u_now, 2))

    u = np.array(u)
    e = np.array(e)

    if return_opt == 'orthonormal':
        return e
    elif return_opt == 'orthogonal':
        return u
    elif return_opt == 'both':
        return u, e