'Adds SOC constraint to the model using the data from mat and vec.
Parameters
model : GUROBI model
The problem model.
variables : list
The problem variables.
rows : range
The rows to be constrained.
nonzero_locs : GUROBI tuplelist
A list of all the nonzero locations.
mat : SciPy COO matrix
The matrix representing the constraints.
vec : NDArray
The constant part of the constraints.
Returns
tuple
A tuple of (QConstr, list of Constr, and list of variables).'

def add_model_soc_constr(self, model, variables, rows, nonzero_locs, mat, vec):

    import gurobipy
    lin_expr_list = []
    soc_vars = []
    for i in rows:
        expr_list = []
        for loc in nonzero_locs.select(i, '*'):
            expr_list.append((mat[loc], variables[loc[1]]))
        lin_expr_list.append((vec[i] - gurobipy.LinExpr(expr_list)))
    soc_vars = [model.addVar(obj=0, name=('soc_t_%d' % rows[0]), vtype=gurobipy.GRB.CONTINUOUS, lb=0, ub=gurobipy.GRB.INFINITY)]
    for i in rows[1:]:
        soc_vars += [model.addVar(obj=0, name=('soc_x_%d' % i), vtype=gurobipy.GRB.CONTINUOUS, lb=(- gurobipy.GRB.INFINITY), ub=gurobipy.GRB.INFINITY)]
    model.update()
    new_lin_constrs = []
    for (i, _) in enumerate(lin_expr_list):
        new_lin_constrs += [model.addConstr((soc_vars[i] == lin_expr_list[i]))]
    t_term = (soc_vars[0] * soc_vars[0])
    x_term = gurobipy.quicksum([(var * var) for var in soc_vars[1:]])
    return (model.addQConstr((x_term <= t_term)), new_lin_constrs, soc_vars)
