Source code for QHyper.solvers.classical.gurobi.gurobi

# This work was supported by the EuroHPC PL infrastructure funded at the
# Smart Growth Operational Programme (2014-2020), Measure 4.2
# under the grant agreement no. POIR.04.02.00-00-D014/20-00


from typing import Any, Optional

from dataclasses import dataclass

import numpy as np
import gurobipy as gp
from QHyper.problems.base import Problem
from QHyper.solvers.base import Solver, SolverResult
from QHyper.polynomial import Polynomial
from QHyper.constraint import Operator


def polynomial_to_gurobi(gurobi_vars: dict[str, Any], poly: Polynomial) -> Any:
    cost_function_1: float = 0
    for vars, coeff in poly.terms.items():
        tmp = 1
        for v in vars:
            tmp *= gurobi_vars[v]
        cost_function_1 += tmp * coeff
    return cost_function_1


[docs] @dataclass class Gurobi(Solver): # todo works only for quadratic expressions """ Gurobi solver class. Attributes ---------- problem : Problem The problem to be solved. model_name : str, optional The name of the gurobi model. mip_gap : float | None, optional The MIP gap. suppress_output : bool, optional, default=True If True, the solver's output will be suppressed. threads : int, optional, default=1 The number of threads to be used by the solver. """ problem: Problem model_name: str = "" mip_gap: float | None = None suppress_output: bool = True threads: int = 1
[docs] def solve(self) -> Any: if self.suppress_output: env = gp.Env(empty=True) env.setParam("OutputFlag", 0) env.start() else: env = None gpm = gp.Model(self.model_name, env=env) if self.mip_gap: gpm.Params.MIPGap = self.mip_gap gpm.setParam('Threads', self.threads) all_vars = self.problem.objective_function.get_variables() for con in self.problem.constraints: all_vars |= con.get_variables() vars = { str(var_name): gpm.addVar(vtype=gp.GRB.BINARY, name=str(var_name)) for var_name in all_vars } objective_function = polynomial_to_gurobi( vars, self.problem.objective_function ) gpm.setObjective(objective_function, gp.GRB.MINIMIZE) for i, constraint in enumerate(self.problem.constraints): lhs = polynomial_to_gurobi(vars, constraint.lhs) rhs = polynomial_to_gurobi(vars, constraint.rhs) if constraint.operator == Operator.EQ: gpm.addConstr(lhs == rhs, f"constr_{i}") elif constraint.operator == Operator.LE: gpm.addConstr(lhs <= rhs, f"constr_{i}") elif constraint.operator == Operator.GE: gpm.addConstr(lhs >= rhs, f"constr_{i}") gpm.update() gpm.optimize() allvars = gpm.getVars() solution = {} for v in allvars: solution[v.VarName] = v.X recarray = np.recarray( (1, ), dtype=[(var, 'i4') for var in vars]+[('probability', 'f8')]) recarray[0] = *(solution[var] for var in vars), 1.0 return SolverResult(recarray, {}, [])