QUBO++ Library with QUBO Solver APIs
Author: Koji Nakano, License: Non-commercial research and evaluation purposes without any guarantees.
qbpp_grb.hpp
Go to the documentation of this file.
1 
7 #ifndef GUROBI_QBPP_HPP
8 #define GUROBI_QBPP_HPP
9 
10 #include <cmath>
11 
12 #include "abs2.hpp"
13 #include "gurobi_c++.h"
14 #include "qbpp.hpp"
15 
16 #define GRB_SAFE_CALL(func) \
17  try { \
18  func; \
19  } catch (GRBException e) { \
20  std::cerr << e.getErrorCode() << ": " << e.getMessage() << std::endl; \
21  exit(1); \
22  }
23 
25 namespace qbpp_grb {
26 
27 //===========================
28 // Class forward declarations
29 //===========================
30 class QuadModel;
31 class Sol;
32 class Callback;
33 
34 //===================
35 // Class declarations
36 //===================
37 
42 class QuadModel : public qbpp::QuadModel {
43  protected:
45  GRBEnv grb_env;
47  std::shared_ptr<GRBModel> grb_model_ptr;
49  GRBVar *grb_x;
50 
51  public:
57 
61  QuadModel(const qbpp::QuadModel &quad_model, bool verbose = false);
62 
65  QuadModel(const QuadModel &grb_model) = default;
66 
70  void set(const std::string &key, const std::string &val) {
71  grb_model_ptr->getEnv().set(key, val);
72  };
73 
76  void set_time_limit(uint32_t time_limit) {
77  set("TimeLimit", std::to_string(time_limit));
78  }
79 
85  void set(Callback &cb);
86 
88 
92  GRBVar get_grb_var(int index) const { return grb_x[index]; };
93 
96  GRBModel &get_grb_model() { return *grb_model_ptr; }
97 
100  const GRBModel &get_grb_model() const { return *grb_model_ptr; }
101 
105  Sol optimize();
107 
112  void write(std::string filename) {
113  GRB_SAFE_CALL(grb_model_ptr->write(filename));
114  }
115 };
116 
120 class Sol : public qbpp::Sol {
123 
124  public:
127 
130  Sol(const qbpp::QuadModel &quad_model) : qbpp::Sol(quad_model) {}
131 
133 
136  qbpp::energy_t get_bound() const { return bound; }
137 
141  bound = eval;
142  return bound;
143  }
144 };
145 
149 class Callback : public GRBCallback {
150  protected:
153 
155  const GRBModel &grb_model;
156 
158  std::optional<qbpp::energy_t> target_energy = std::nullopt;
159 
160  // std::chrono::high_resolution_clock::time_point start_time =
161  // std::chrono::high_resolution_clock::now();
162 
164  mutable std::mutex mtx;
165 
166  public:
170  : quad_model(quad_model), grb_model(quad_model.get_grb_model()) {
171  qbpp::get_time();
172  };
173 
174  virtual ~Callback() = default;
175 
178  Sol get_sol();
179 
183  virtual void callback() override {
184  if (where == GRB_CB_MIPSOL) {
185  qbpp::energy_t energy = get_sol().get_energy();
186  std::cout << "TTS = " << std::fixed << std::setprecision(3)
187  << std::setfill('0') << qbpp::get_time()
188  << "s Energy = " << energy << std::endl;
189  abort_if_target_energy(energy);
190  }
191  }
192 
195  this->target_energy = target_energy;
196  }
197 
202  if (target_energy.has_value() && energy <= target_energy) {
203  abort();
204  }
205  }
206 
210  double getDoubleInfoPublic(int what) { return getDoubleInfo(what); }
211 
215  double getSolutionPublic(GRBVar v) { return getSolution(v); }
216 };
217 
218 //=============================
219 // Class QuadModel member functions
220 //=============================
221 
222 inline QuadModel::QuadModel(const qbpp::QuadModel &quad_model, bool verbose)
223  : qbpp::QuadModel(quad_model), grb_env(true) {
224  // Suppress Gurobi outputs to the screen.
225  grb_env.set(GRB_IntParam_OutputFlag, 0);
226  if (verbose) {
227  grb_env.set("OutputFlag", "1");
228  }
229  GRB_SAFE_CALL(grb_env.start());
230 
231  grb_model_ptr = std::make_unique<GRBModel>(grb_env);
232 
233  // Objective is minimization.
234  GRB_SAFE_CALL(grb_model_ptr->set(GRB_IntAttr_ModelSense, GRB_MINIMIZE));
235 
236  // Add binary variables to the Gurobi model.
237  grb_x = grb_model_ptr->addVars(var_count(), GRB_BINARY);
238  // Compute objective function of QUBO problem.
239  GRBQuadExpr obj;
240  obj += quad_model.get_constant();
241  for (qbpp::vindex_t i = 0; i < var_count(); ++i) {
242  if (quad_model.get_linear(i) != 0)
243  obj += quad_model.get_linear(i) * grb_x[i];
244  }
245  for (qbpp::vindex_t i = 0; i < var_count(); ++i) {
246  for (qbpp::vindex_t j = 0; j < quad_model.get_degree(i); ++j) {
247  auto [k, coeff] = quad_model.get_quadratic(i, j);
248  if (i < k) obj += coeff * grb_x[i] * grb_x[k];
249  }
250  }
251 
252  // Set the objective function to the Gurobi model.
253  GRB_SAFE_CALL(grb_model_ptr->setObjective(obj));
254 }
255 
256 // void QuadModel::set(Callback *cb) { grb_model_ptr->setCallback(cb); }
257 
258 inline void QuadModel::set(Callback &cb) { grb_model_ptr->setCallback(&cb); }
259 
261  Sol sol(*this);
262  GRB_SAFE_CALL(grb_model_ptr->optimize());
263  sol.set_energy(std::round(grb_model_ptr->get(GRB_DoubleAttr_ObjVal)));
264  sol.set_bound(std::round(grb_model_ptr->get(GRB_DoubleAttr_ObjBound)));
265  for (qbpp::vindex_t i = 0; i < var_count(); ++i)
266  sol.set(i, int(grb_x[i].get(GRB_DoubleAttr_X)));
267  return sol;
268 }
269 
270 //================================
271 // Class Callback member functions
272 //================================
273 
275  Sol sol(quad_model);
276  std::lock_guard<std::mutex> lock(mtx);
277  // Intentionally commented out because the solution obtained by getSolution
278  // may provide corrupted values when Gurobi finds an optimal solution.
279  // sol.set_energy(std::round(getDoubleInfoPublic(GRB_CB_MIPSOL_OBJ)));
280  sol.set_bound(std::round(getDoubleInfoPublic(GRB_CB_MIPSOL_OBJBND)));
281  // Get the solution from Gurobi Optimizer.
282  for (qbpp::vindex_t i = 0; i < quad_model.var_count(); ++i) {
283  sol.set(i, int(getSolutionPublic(quad_model.get_grb_var(i))));
284  }
285  // eval is used to compute the energy of the solution instead of MIPSOL_OBJ.
286  sol.set_energy(eval(quad_model, sol));
287  return sol;
288 }
289 
290 } // namespace qbpp_grb
291 #endif // __GUROBI_QBPP_HPP__
API for the ABS2 GPU QUBO Solver.
energy_t get_constant() const
Definition: qbpp.hpp:1168
vindex_t var_count() const
Definition: qbpp.hpp:1154
const std::vector< std::vector< std::pair< vindex_t, coeff_t > > > & get_quadratic() const
Definition: qbpp.hpp:1245
const std::vector< coeff_t > & get_linear() const
Definition: qbpp.hpp:1241
const std::vector< vindex_t > & get_degree() const
Definition: qbpp.hpp:1243
void set_energy(energy_t energy)
Definition: qbpp.hpp:1550
void set(vindex_t index, bool value)
Definition: qbpp.hpp:1523
energy_t get_energy() const
Definition: qbpp.hpp:1545
Class to manage a callback function called by Gurobi Optimizer.
Definition: qbpp_grb.hpp:149
void abort_if_target_energy(qbpp::energy_t energy)
Abort the optimization process if the target energy is achieved.
Definition: qbpp_grb.hpp:201
virtual ~Callback()=default
const QuadModel quad_model
QUBO model.
Definition: qbpp_grb.hpp:152
double getSolutionPublic(GRBVar v)
Calls getSolution() of GRBCallback.
Definition: qbpp_grb.hpp:215
double getDoubleInfoPublic(int what)
Calls GetDoubleInfo() of GRBCallback.
Definition: qbpp_grb.hpp:210
Sol get_sol()
Get the solution obtained by Gurobi Optimizer.
Definition: qbpp_grb.hpp:274
const GRBModel & grb_model
Shortcut to the GRBModel in QuadModel.
Definition: qbpp_grb.hpp:155
virtual void callback() override
Default callback function for Gurobi Optimizer.
Definition: qbpp_grb.hpp:183
Callback(const QuadModel &quad_model)
Constructor: a new Callback object.
Definition: qbpp_grb.hpp:169
std::mutex mtx
Mutex to lock the critical section in get_sol()
Definition: qbpp_grb.hpp:164
void set_target_energy(qbpp::energy_t target_energy)
Set the target energy for Gurobi Optimizer.
Definition: qbpp_grb.hpp:194
std::optional< qbpp::energy_t > target_energy
Target energy to stop the Gurobi optimizer.
Definition: qbpp_grb.hpp:158
Class to store a QUBO model using Gurobi Optimizer through QUBO++ library.
Definition: qbpp_grb.hpp:42
const GRBModel & get_grb_model() const
Get the Gurobi model.
Definition: qbpp_grb.hpp:100
void write(std::string filename)
Write the model to a file.
Definition: qbpp_grb.hpp:112
std::shared_ptr< GRBModel > grb_model_ptr
Gurobi model.
Definition: qbpp_grb.hpp:47
GRBVar get_grb_var(int index) const
Get the Gurobi variable from the index.
Definition: qbpp_grb.hpp:92
Sol optimize()
Optimize the QUBO model.
Definition: qbpp_grb.hpp:260
GRBVar * grb_x
Pointer to Gurobi variables.
Definition: qbpp_grb.hpp:49
GRBEnv grb_env
Gurobi environment.
Definition: qbpp_grb.hpp:45
GRBModel & get_grb_model()
Get the Gurobi model.
Definition: qbpp_grb.hpp:96
Class to store a solution of a QUBO model using Gurobi Optimizer.
Definition: qbpp_grb.hpp:120
qbpp::energy_t get_bound() const
Gets the energy bound of the solution.
Definition: qbpp_grb.hpp:136
qbpp::energy_t bound
Energy Bound obtained by of the Grobi Optimizer.
Definition: qbpp_grb.hpp:122
qbpp::energy_t set_bound(qbpp::energy_t eval)
Sets the energy bound of the solution.
Definition: qbpp_grb.hpp:140
QuadModel(const qbpp::QuadModel &quad_model, bool verbose=false)
Constructor to create a model from QuadModel object.
Definition: qbpp_grb.hpp:222
void set_time_limit(uint32_t time_limit)
Sets time limit to the Gurobi model.
Definition: qbpp_grb.hpp:76
QuadModel(const QuadModel &grb_model)=default
Copy constructor to create a model from another model.
void set(const std::string &key, const std::string &val)
Sets a parameter to the Gurobi environment.
Definition: qbpp_grb.hpp:70
Sol(const qbpp::QuadModel &quad_model)
Creates a solution object from a model.
Definition: qbpp_grb.hpp:130
Namespace to use Gurobi optimizer from QUBO++ library.
Definition: qbpp_grb.hpp:25
Generates a QUBO Expression for the Graph Coloring Problem using QUBO++ library.
Definition: qbpp.hpp:53
double get_time()
Definition: qbpp.hpp:3815
uint32_t vindex_t
Definition: qbpp.hpp:122
ENERGY_TYPE energy_t
Definition: qbpp.hpp:130
energy_t eval(const Expr &expr, const Sol &sol)
Definition: qbpp.hpp:2109
QUBO++, a C++ library for generating expressions for binary and spin variables.
#define GRB_SAFE_CALL(func)
Definition: qbpp_grb.hpp:16