@staticmethod
def find_min_norm_element_FW(vecs):
    '\n        Given a list of vectors (vecs), this method finds the minimum norm\n        element in the convex hull\n        as min |u|_2 st. u = \\sum c_i vecs[i] and \\sum c_i = 1.\n        It is quite geometric, and the main idea is the fact that if\n        d_{ij} = min |u|_2 st u = c x_i + (1-c) x_j; the solution lies\n        in (0, d_{i,j})Hence, we find the best 2-task solution, and then\n        run the Frank Wolfe until convergence\n        '
    dps = {}
    (init_sol, dps) = MGDASolver._min_norm_2d(vecs, dps)
    n = len(vecs)
    sol_vec = np.zeros(n)
    sol_vec[init_sol[0][0]] = init_sol[1]
    sol_vec[init_sol[0][1]] = (1 - init_sol[1])
    if (n < 3):
        return (sol_vec, init_sol[2])
    iter_count = 0
    grad_mat = np.zeros((n, n))
    for i in range(n):
        for j in range(n):
            grad_mat[(i, j)] = dps[(i, j)]
    while (iter_count < MGDASolver.MAX_ITER):
        t_iter = np.argmin(np.dot(grad_mat, sol_vec))
        v1v1 = np.dot(sol_vec, np.dot(grad_mat, sol_vec))
        v1v2 = np.dot(sol_vec, grad_mat[:, t_iter])
        v2v2 = grad_mat[(t_iter, t_iter)]
        (nc, nd) = MGDASolver._min_norm_element_from2(v1v1, v1v2, v2v2)
        new_sol_vec = (nc * sol_vec)
        new_sol_vec[t_iter] += (1 - nc)
        change = (new_sol_vec - sol_vec)
        if (np.sum(np.abs(change)) < MGDASolver.STOP_CRIT):
            return (sol_vec, nd)
        sol_vec = new_sol_vec
Given a list of vectors (vecs), this method finds the minimum norm
element in the convex hull
as min |u|_2 st. u = \sum c_i vecs[i] and \sum c_i = 1.
It is quite geometric, and the main idea is the fact that if
d_{ij} = min |u|_2 st u = c x_i + (1-c) x_j; the solution lies
in (0, d_{i,j})Hence, we find the best 2-task solution, and then
run the Frank Wolfe until convergence
@staticmethod
def find_min_norm_element_FW(vecs):
    '\n        Given a list of vectors (vecs), this method finds the minimum norm\n        element in the convex hull\n        as min |u|_2 st. u = \\sum c_i vecs[i] and \\sum c_i = 1.\n        It is quite geometric, and the main idea is the fact that if\n        d_{ij} = min |u|_2 st u = c x_i + (1-c) x_j; the solution lies\n        in (0, d_{i,j})Hence, we find the best 2-task solution, and then\n        run the Frank Wolfe until convergence\n        '
    dps = {}
    (init_sol, dps) = MGDASolver._min_norm_2d(vecs, dps)
    n = len(vecs)
    sol_vec = np.zeros(n)
    sol_vec[init_sol[0][0]] = init_sol[1]
    sol_vec[init_sol[0][1]] = (1 - init_sol[1])
    if (n < 3):
        return (sol_vec, init_sol[2])
    iter_count = 0
    grad_mat = np.zeros((n, n))
    for i in range(n):
        for j in range(n):
            grad_mat[(i, j)] = dps[(i, j)]
    while (iter_count < MGDASolver.MAX_ITER):
        t_iter = np.argmin(np.dot(grad_mat, sol_vec))
        v1v1 = np.dot(sol_vec, np.dot(grad_mat, sol_vec))
        v1v2 = np.dot(sol_vec, grad_mat[:, t_iter])
        v2v2 = grad_mat[(t_iter, t_iter)]
        (nc, nd) = MGDASolver._min_norm_element_from2(v1v1, v1v2, v2v2)
        new_sol_vec = (nc * sol_vec)
        new_sol_vec[t_iter] += (1 - nc)
        change = (new_sol_vec - sol_vec)
        if (np.sum(np.abs(change)) < MGDASolver.STOP_CRIT):
            return (sol_vec, nd)
        sol_vec = new_sol_vec