solver  1.0
GurobiSolver.cpp
1 /*
2  This file is part of the EnergyOptimizatorOfRoboticCells program.
3 
4  EnergyOptimizatorOfRoboticCells is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  EnergyOptimizatorOfRoboticCells is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with EnergyOptimizatorOfRoboticCells. If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include <tuple>
19 #include <string>
20 #include <stdexcept>
21 #include <vector>
22 #include "gurobi_c++.h"
24 
25 using namespace std;
26 
27 vector<GRBEnv> threadEnv;
28 
29 vector<GRBVar> generateProblem(const ILPModel& m, GRBModel& model);
30 
31 string solverIdentification() {
32  string identification = "Gurobi";
33  int major = -1, minor = -1, release = -1;
34  GRBversion(&major, &minor, &release);
35  if (major != -1 && minor != -1 && release != -1)
36  identification += " "+to_string(major)+"."+to_string(minor)+"."+to_string(release);
37  return identification;
38 }
39 
40 void initializeLocalEnvironments(int numberOfThreads) {
41  threadEnv.resize(numberOfThreads);
42 }
43 
44 SolutionILP solveILP(const ILPModel& m, bool verbose, double gap, double timeLimit, int numberOfThreads, int threadId) {
45 
46  SolutionILP s;
47 
48  try {
49  if (threadEnv.size() <= (uint32_t) threadId) {
50  string msg = "Either the Gurobi environments were not initialized or the number of concurrent threads\n";
51  msg += "was specified incorrectly in the initializeLocalEnvironments method!";
52  throw ILPSolverException(caller(), msg);
53  }
54 
55  threadEnv[threadId].set(GRB_IntParam_Threads, numberOfThreads);
56  if (timeLimit != 0.0)
57  threadEnv[threadId].set(GRB_DoubleParam_TimeLimit, timeLimit);
58  if (gap != 0.0)
59  threadEnv[threadId].set(GRB_DoubleParam_MIPGap, gap);
60 
61  if (verbose) {
62  threadEnv[threadId].set(GRB_IntParam_OutputFlag, 1);
63  threadEnv[threadId].set(GRB_IntParam_LogToConsole, 1);
64  } else {
65  threadEnv[threadId].set(GRB_IntParam_OutputFlag, 0);
66  threadEnv[threadId].set(GRB_IntParam_LogToConsole, 0);
67  }
68 
69  GRBModel model(threadEnv[threadId]);
70  const vector<GRBVar>& vars = generateProblem(m, model);
71 
72  model.optimize();
73  switch (model.get(GRB_IntAttr_Status)) {
74  case GRB_OPTIMAL:
75  if (gap == 0.0)
76  s.status = ILP_OPTIMAL;
77  else
78  s.status = ILP_FEASIBLE;
79  break;
80  case GRB_TIME_LIMIT:
81  if (model.get(GRB_IntAttr_SolCount) > 0)
82  s.status = ILP_FEASIBLE;
83  else
84  s.status = ILP_UNKNOWN;
85  break;
86  case GRB_INFEASIBLE:
87  s.status = ILP_INFEASIBLE;
88  break;
89  case GRB_UNBOUNDED:
90  s.status = ILP_UNBOUNDED;
91  break;
92  default:
93  s.status = ILP_UNKNOWN;
94  }
95 
96  if (s.status == ILP_OPTIMAL || s.status == ILP_FEASIBLE) {
97  s.criterion = model.get(GRB_DoubleAttr_ObjVal);
98  for (long v = 0; v < model.get(GRB_IntAttr_NumVars); ++v)
99  s.solution.push_back(vars[v].get(GRB_DoubleAttr_X));
100  }
101 
102  if (model.get(GRB_IntAttr_IsMIP))
103  s.bound = model.get(GRB_DoubleAttr_ObjBound);
104  else if (s.status == ILP_OPTIMAL)
105  s.bound = s.criterion;
106 
107  } catch (GRBException& e) {
108  throw ILPSolverException(caller(), e.getMessage());
109  } catch (...) {
110  throw_with_nested(ILPSolverException(caller(), "Error during solving the ILP problem!"));
111  }
112 
113  return s;
114 }
115 
116 vector<GRBVar> generateProblem(const ILPModel& m, GRBModel& model) {
117  vector<GRBVar> vars;
118  model.set(GRB_IntAttr_ModelSense, (m.obj == MINIMIZE ? GRB_MINIMIZE : GRB_MAXIMIZE));
119  for (unsigned long v = 0; v < m.numberOfVariables(); ++v) {
120  GRBVar var;
121  switch (m.x[v].type) {
122  case FLT:
123  var = model.addVar(m.x[v].lowerBound, m.x[v].upperBound, m.c[v], GRB_CONTINUOUS, m.varDesc[v]);
124  break;
125  case BIN:
126  var = model.addVar(m.x[v].lowerBound, m.x[v].upperBound, m.c[v], GRB_BINARY, m.varDesc[v]);
127  break;
128  default:
129  var = model.addVar(m.x[v].lowerBound, m.x[v].upperBound, m.c[v], GRB_INTEGER, m.varDesc[v]);
130  }
131  vars.push_back(var);
132  }
133 
134  model.update();
135 
136  if (!m.gurobiC.empty()) {
137  assert(m.numberOfVariables() == m.gurobiC.size() && "Invalid initialization of gurobi criterion functions!");
138  for (unsigned long v = 0; v < m.numberOfVariables(); ++v) {
139  const tuple<vector<double>, vector<double>>* cf = m.gurobiC[v];
140  if (cf != nullptr) {
141  const vector<double>& x = get<0>(*cf), & y = get<1>(*cf);
142  assert(x.size() == y.size() && "Invalid initialization of Gurobi functions!");
143  if (!x.empty() && !y.empty()) {
144  // Add a discretized function, a ,,dirty" casting is due to non-const Gurobi call.
145  model.setPWLObj(vars[v], x.size(), (double*) x.data(), (double*) y.data());
146  }
147  }
148  }
149  }
150 
151  model.update();
152 
153  for (unsigned long c = 0; c < m.numberOfConstraints(); ++c) {
154  GRBLinExpr expr;
155  for (const pair<uint32_t, double>& p : m.A[c])
156  expr += p.second*vars[p.first];
157 
158  switch (m.ops[c]) {
159  case LESS_EQUAL:
160  model.addConstr(expr <= m.b[c], m.conDesc[c]);
161  break;
162  case EQUAL:
163  model.addConstr(expr == m.b[c], m.conDesc[c]);
164  break;
165  case GREATER_EQUAL:
166  model.addConstr(expr >= m.b[c], m.conDesc[c]);
167  }
168  }
169 
170  return vars;
171 }
172 
void initializeLocalEnvironments(int numberOfThreads)
It enables the solver to initialize all the data structures (e.g. expensive to construct) required fo...
std::vector< double > b
Constants in the constraints, i.e. the right-hand side vector of .
Definition: ILPModel.h:87
SparseMatrix< double > A
Constraint matrix of the problem.
Definition: ILPModel.h:81
STL namespace.
Integer Linear Programming problem is stored in this data structure.
Definition: ILPModel.h:69
std::vector< double > solution
The best found solution.
Structure storing a solution of an Integer Linear Programming problem.
std::vector< std::string > varDesc
Optional description of the variables.
Definition: ILPModel.h:93
std::vector< const std::tuple< std::vector< double >, std::vector< double > > * > gurobiC
Convex functions in the criterion in the format suitable for Gurobi solver.
Definition: ILPModel.h:85
Solver-independent interface for solving Integer Linear Programming problems.
Exception dedicated to problems with Integer Linear Programming solvers.
Definition: Exceptions.h:127
double criterion
The criterion value of the solution.
std::vector< Operator > ops
Operators of the constraints, see Operator enum.
Definition: ILPModel.h:89
std::string solverIdentification()
Returns an identification of the used solver, e.g. 'Gurobi 6.0.4'.
Definition: CplexSolver.cpp:30
double bound
The best known lower or upper bound.
std::vector< double > c
Vector of the criterion coefficients.
Definition: ILPModel.h:83
Objective obj
Sense of the objective function (minimization/maximization).
Definition: ILPModel.h:79
Status status
Solution status, see Status enum.
std::vector< Variable > x
Variables of the problem.
Definition: ILPModel.h:91
SolutionILP solveILP(const ILPModel &m, bool verbose, double gap=0.0, double timeLimit=0.0, int numberOfThreads=1, int threadId=0)
Integer Linear Programming solver is called to solve the problem and the solution is returned...
Definition: CplexSolver.cpp:39
std::vector< std::string > conDesc
Optional description of the constraints.
Definition: ILPModel.h:95