
"""
Auto-generated by CVXPYgen on April 02, 2023 at 17:02:12.
Content: Custom solve method for CVXPY interface.
"""

import time
import warnings
import numpy as np
from cvxpy.reductions import Solution
from cvxpy.problems.problem import SolverStats
from test import cpg_module


status_int_to_string = {0: "Optimal solution found", 
                        1: "Certificate of primal infeasibility found", 
                        2: "Certificate of dual infeasibility found", 
                        10: "Optimal solution found subject to reduced tolerances", 
                        11: "Certificate of primal infeasibility found subject to reduced tolerances", 
                        12: "Certificate of dual infeasibility found subject to reduced tolerances", 
                        -1: "Maximum number of iterations reached", 
                        -2: "Numerical problems (unreliable search direction)", 
                        -3: "Numerical problems (slacks or multipliers outside cone)", 
                        -4: "Interrupted by signal or CTRL-C", 
                        -7: "Unknown problem in solver", 
                        -99: "Unknown problem before solving"}


def cpg_solve(prob, updated_params=None, **kwargs):

    # set flags for updated parameters
    upd = cpg_module.cpg_updated()
    if updated_params is None:
        updated_params = ["L_inv_param"]
    for p in updated_params:
        try:
            setattr(upd, p, True)
        except AttributeError:
            raise(AttributeError("%s is not a parameter." % p))

    # set solver settings
    cpg_module.set_solver_default_settings()
    for key, value in kwargs.items():
        if key == "max_iters":
            key = "maxit"
        try:
            eval('cpg_module.set_solver_%s(value)' % key)
        except AttributeError:
            raise(AttributeError('Solver setting "%s" not available.' % key))

    # set parameter values
    par = cpg_module.cpg_params()
    par.L_inv_param = list(prob.param_dict['L_inv_param'].value.flatten(order='F'))

    # solve
    t0 = time.time()
    res = cpg_module.solve(upd, par)
    t1 = time.time()

    # store solution in problem object
    prob._clear_solution()
    prob.var_dict['w'].value = np.array(res.cpg_prim.w).reshape((3, 1), order='F')
    prob.constraints[0].save_dual_value(np.array(res.cpg_dual.d0).reshape((1, 1), order='F'))

    # store additional solver information in problem object
    prob._status = status_int_to_string[res.cpg_info.status]
    if abs(res.cpg_info.obj_val) == 1e30:
        prob._value = np.sign(res.cpg_info.obj_val)*np.inf
    else:
        prob._value = res.cpg_info.obj_val
    primal_vars = {var.id: var.value for var in prob.variables()}
    dual_vars = {c.id: c.dual_value for c in prob.constraints}
    solver_specific_stats = {'obj_val': res.cpg_info.obj_val,
                             'status': prob._status,
                             'iter': res.cpg_info.iter,
                             'pri_res': res.cpg_info.pri_res,
                             'dua_res': res.cpg_info.dua_res,
                             'time': res.cpg_info.time}
    attr = {'solve_time': t1-t0, 'solver_specific_stats': solver_specific_stats, 'num_iters': res.cpg_info.iter}
    prob._solution = Solution(prob.status, prob.value, primal_vars, dual_vars, attr)
    results_dict = {'solver_specific_stats': solver_specific_stats,
                    'num_iters': res.cpg_info.iter,
                    'solve_time': t1-t0}
    prob._solver_stats = SolverStats(results_dict, 'ECOS')

    return prob.value
