Limbo 3.5.4
Loading...
Searching...
No Matches
CplexApi.h
Go to the documentation of this file.
1
7
8#ifndef LIMBO_SOLVERS_API_CPLEXAPI_H
9#define LIMBO_SOLVERS_API_CPELXAPI_H
10
11#include <iostream>
12#include <string>
13#include <vector>
14#include <list>
15#include <boost/lexical_cast.hpp>
16#include <boost/shared_ptr.hpp>
17#include <boost/assert.hpp>
19
21// 1. Add option to control the verbose level
22// 2. Support to set starting point
23
24// make sure CPLEX is configured properly
25extern "C"
26{
27#include <ilcplex/cplexx.h>
28#include <string.h>
29#include <stdlib.h>
30}
31
33namespace limbo
34{
36namespace solvers
37{
38
41{
42 public:
45 : m_outputFlag(0)
46 , m_numThreads(std::numeric_limits<int>::max())
47 {
48 }
49
50 virtual ~CplexParameters() {}
53 virtual void operator()(CPXENVptr env) const
54 {
55 // mute the log from the LP solver
56 if (m_outputFlag < 3)
57 {
58 // CPXXsetlogfilename(env, NULL, NULL);
59 }
60 if (m_outputFlag < 2)
61 {
62 }
63 if (m_numThreads > 0 && m_numThreads != std::numeric_limits<int>::max())
64 CPXXsetintparam(env, CPXPARAM_Threads, m_numThreads);
65 }
66
69 virtual void operator()(CPXLPptr /*model*/) const
70 {
71 }
72
75 void setOutputFlag(int v) {m_outputFlag = v;}
78 void setNumThreads(int v) {m_numThreads = v;}
79
80 protected:
83};
84
87template <typename T, std::size_t = std::numeric_limits<T>::is_integer>
89{
90 inline T operator()(double value) const
91 {
92 return value;
93 }
94};
95
96template <typename T>
97struct SmartRound<T, 1>
98{
99 inline T operator()(double value) const
100 {
101 return std::round(value);
102 }
103};
104
108template <typename T, typename V>
110{
111 public:
115 typedef typename model_type::coefficient_value_type coefficient_value_type;
116 typedef typename model_type::variable_value_type variable_value_type;
117 typedef typename model_type::variable_type variable_type;
118 typedef typename model_type::constraint_type constraint_type;
119 typedef typename model_type::expression_type expression_type;
120 typedef typename model_type::term_type term_type;
121 typedef typename model_type::property_type property_type;
122 typedef CplexParameters parameter_type;
124
128 : m_model(model)
129 , m_cplexModel(NULL)
130 {
131 }
132
134 {
135 }
136
139 SolverProperty operator()(parameter_type* param = NULL)
140 {
141 bool defaultParam = false;
142 if (param == NULL)
143 {
144 param = new CplexParameters;
145 defaultParam = true;
146 }
147
148 // ILP environment
149 CPXENVptr env = NULL;
150 m_cplexModel = NULL;
151 int status;
152 // Create environment
153 env = CPXXopenCPLEX (&status);
154 if (env == NULL)
155 {
156 char errmsg[CPXMESSAGEBUFSIZE];
157 CPXXgeterrorstring (env, status, errmsg);
158 limboAssertMsg(0, "Could not open CPLEX environment: %s", errmsg);
159 }
160 param->operator()(env);
161 // Create an empty model
162 m_cplexModel = CPXXcreateprob (env, &status, "CplexLinearApi");
163 if (status)
164 {
165 limboAssertMsg(0, "Could not create model");
166 }
167
168 CPXDIM numcols = m_model->numVariables();
169 CPXDIM numrows = m_model->constraints().size();
170 int objsen;
171 std::vector<double> obj (numcols, 0);
172 std::vector<double> rhs (numrows, 0);
173 std::vector<char> sense (numrows, '=');
174 // follows compressed sparse column format
175 std::vector<CPXNNZ> matbeg (numcols, 0);
176 std::vector<CPXDIM> matcnt (numcols, 0);
177 std::vector<double> lb (numcols);
178 std::vector<double> ub (numcols);
179 std::vector<char> ctype (numcols);
180 // create variables
181 for (unsigned int i = 0, ie = m_model->numVariables(); i < ie; ++i)
182 {
183 variable_type var (i);
184 lb[var.id()] = m_model->variableLowerBound(var);
185 ub[var.id()] = m_model->variableUpperBound(var);
186 // error = GRBsetdblattrelement(m_cplexModel, GRB_DBL_ATTR_START, var.id(), m_model->variableSolution(var));
187 ctype[var.id()] = m_model->variableNumericType(var) == CONTINUOUS? 'C' : 'I';
188 limboAssertMsg(!(std::numeric_limits<V>::is_integer && m_model->variableNumericType(var) == CONTINUOUS),
189 "LinearModel<T, V> is declared as V = integer type, but variable %s is CONTINUOUS", m_model->variableName(var).c_str());
190 }
191
192 // create constraints
193 // initialize matcnt
194 for (unsigned int i = 0, ie = m_model->constraints().size(); i < ie; ++i)
195 {
196 constraint_type const& constr = m_model->constraints().at(i);
197
198 for (typename std::vector<term_type>::const_iterator it = constr.expression().terms().begin(), ite = constr.expression().terms().end(); it != ite; ++it)
199 {
200 if (it->coefficient() != 0)
201 {
202 matcnt[it->variable().id()] += 1;
203 limboAssert(it->variable().id() < matcnt.size());
204 }
205 }
206 }
207 // initialize matbeg
208 int numnz = 0; // number of non-zeros in constraint matrix
209 for (unsigned int i = 0; i < numcols - 1; ++i)
210 {
211 matbeg[i + 1] = matbeg[i] + matcnt[i];
212 numnz += matcnt[i];
213 }
214 numnz += matcnt.back();
215 // initialize matind, matval, sense, rhs
216 std::vector<CPXDIM> matind (numnz, 0);
217 std::vector<double> matval (numnz, 0);
218 std::vector<CPXDIM> curcnt (numcols, 0); // intermediate count of how many elements filled in each column
219 for (unsigned int i = 0, ie = m_model->constraints().size(); i < ie; ++i)
220 {
221 constraint_type const& constr = m_model->constraints().at(i);
222
223 for (typename std::vector<term_type>::const_iterator it = constr.expression().terms().begin(), ite = constr.expression().terms().end(); it != ite; ++it)
224 {
225 if (it->coefficient() != 0)
226 {
227 matind[matbeg[it->variable().id()] + curcnt[it->variable().id()]] = i;
228 matval[matbeg[it->variable().id()] + curcnt[it->variable().id()]] = it->coefficient();
229 limboAssert(matbeg[it->variable().id()] + curcnt[it->variable().id()] < matind.size());
230 curcnt[it->variable().id()] += 1;
231 }
232 }
233
234 switch (constr.sense())
235 {
236 case '<':
237 sense[i] = 'L'; break;
238 case '=':
239 sense[i] = 'E'; break;
240 case '>':
241 sense[i] = 'G'; break;
242 default:
243 limboAssertMsg(0, "Unknown sense for row %u: %c", i, constr.sense());
244 break;
245 }
246
247 rhs[i] = constr.rightHandSide();
248 }
249
250 // create objective
251 for (typename std::vector<term_type>::const_iterator it = m_model->objective().terms().begin(), ite = m_model->objective().terms().end(); it != ite; ++it)
252 {
253 obj[it->variable().id()] = it->coefficient();
254 }
255 objsen = m_model->optimizeType() == MIN? CPX_MIN : CPX_MAX;
256
257 // call parameter setting before optimization
258 param->operator()(m_cplexModel);
259 status = CPXXcopylp (env, m_cplexModel, numcols, numrows, objsen, obj.data(), rhs.data(),
260 sense.data(), matbeg.data(), matcnt.data(), matind.data(), matval.data(),
261 lb.data(), ub.data(), NULL);
262 if (status)
263 {
264 limboAssertMsg(0, "CPXXcopylp failed");
265 }
266 status = CPXXcopyctype (env, m_cplexModel, ctype.data());
267 if (status)
268 {
269 limboAssertMsg(0, "CPXXcopyctype failed");
270 }
271
272#ifdef DEBUG_CPLEXAPI
273 status = CPXXwriteprob (env, m_cplexModel, "problem.lp", NULL);
274 if (status)
275 {
276 limboAssertMsg(0, "CPXXwriteprob failed");
277 }
278#endif
279 status = CPXXmipopt (env, m_cplexModel);
280 if (status)
281 {
282 limboAssertMsg(0, "CPXXmipopt failed");
283 }
284
285 int solstat = CPXXgetstat (env, m_cplexModel);
286 if (status)
287 {
288 limboAssertMsg(0, "CPXXgetstat failed");
289 }
290
291 if (solstat == CPXMIP_INFEASIBLE)
292 {
293 status = CPXXrefineconflictext (env, m_cplexModel, 0, 0, NULL, NULL, NULL, NULL);
294 if (status)
295 {
296 limboAssertMsg(0, "CPXXrefineconflictext failed");
297 }
298 status = CPXXclpwrite (env, m_cplexModel, "problem.ilp");
299 if (status)
300 {
301 limboAssertMsg(0, "CPXXclpwrite failed");
302 }
303 limboPrint(kERROR, "Model is infeasible, compute IIS and write to problem.ilp\n");
304 }
305#ifdef DEBUG_CPLEXAPI
306 status = CPXXwriteprob (env, m_cplexModel, "problem.sol.lp", NULL);
307 if (status)
308 {
309 limboAssertMsg(0, "CPXXwriteprob failed");
310 }
311#endif
312
313 std::vector<double> x (numcols, 0);
314 status = CPXXgetx (env, m_cplexModel, x.data(), 0, numcols-1);
315 if (status)
316 {
317 limboAssertMsg(0, "CPXXgetx failed");
318 }
319 // round if the variable type is integer
320 SmartRound<V> sround;
321 for (unsigned int i = 0; i < m_model->numVariables(); ++i)
322 {
323 variable_type var = m_model->variable(i);
324 double value = x[var.id()];
325 m_model->setVariableSolution(m_model->variable(i), sround(value));
326 }
327
328 if (defaultParam)
329 delete param;
330 // Free model
331 if (m_cplexModel != NULL)
332 {
333 status = CPXXfreeprob (env, &m_cplexModel);
334 if (status)
335 {
336 limboAssertMsg(0, "CPXXfreeprob failed");
337 }
338 }
339 // Free environment
340 if (env != NULL)
341 {
342 status = CPXXcloseCPLEX (&env);
343 if (status)
344 {
345 limboAssertMsg(0, "CPXXcloseCPLEX failed");
346 }
347 }
348
349 switch (solstat)
350 {
351 //case CPX_STAT_OPTIMAL:
352 case CPXMIP_OPTIMAL:
353 return OPTIMAL;
354 //case CPX_STAT_INFEASIBLE:
355 case CPXMIP_INFEASIBLE:
356 return INFEASIBLE;
357 //case CPX_STAT_INForUNBD:
358 //case CPX_STAT_UNBOUNDED:
359 case CPXMIP_INForUNBD:
360 case CPXMIP_UNBOUNDED:
361 return UNBOUNDED;
362 default:
363 limboAssertMsg(0, "unknown status %d", solstat);
364 }
365 }
366
367 protected:
374
376 CPXLPptr m_cplexModel;
377};
378
379} // namespace solvers
380} // namespace limbo
381
382#endif
#define limboAssertMsg(condition, args...)
custom assertion with message
Definition AssertMsg.h:24
#define limboAssert(condition)
custom assertion without message
Definition AssertMsg.h:36
Basic utilities such as variables and linear expressions in solvers.
Check string is integer, floating point, number... Convert string to upper/lower cases.
CPXLPptr m_cplexModel
model for CPLEX
Definition CplexApi.h:376
CplexLinearApi(model_type *model)
constructor
Definition CplexApi.h:127
LinearModel< T, V > model_type
linear model type for the problem
Definition CplexApi.h:113
model_type * m_model
model for the problem
Definition CplexApi.h:375
SolverProperty operator()(parameter_type *param=NULL)
API to run the algorithm.
Definition CplexApi.h:139
CplexLinearApi & operator=(CplexLinearApi const &rhs)
assignment, forbidden
CplexLinearApi(CplexLinearApi const &rhs)
copy constructor, forbidden
Base class for custom CPLEX parameters.
Definition CplexApi.h:41
int m_outputFlag
control log from CPLEX
Definition CplexApi.h:81
void setNumThreads(int v)
set number of threads
Definition CplexApi.h:78
virtual ~CplexParameters()
destructor
Definition CplexApi.h:50
int m_numThreads
number of threads
Definition CplexApi.h:82
virtual void operator()(CPXENVptr env) const
customize environment
Definition CplexApi.h:53
virtual void operator()(CPXLPptr) const
customize model
Definition CplexApi.h:69
void setOutputFlag(int v)
set output flag
Definition CplexApi.h:75
coefficient_value_type rightHandSide() const
Definition Solvers.h:1034
expression_type const & expression() const
Definition Solvers.h:1028
std::vector< term_type > const & terms() const
Definition Solvers.h:655
model to describe an optimization problem
Definition Solvers.h:1161
V variable_value_type
V variable.
Definition Solvers.h:1166
VariableProperty< variable_value_type > property_type
variable property type
Definition Solvers.h:1178
Variable< coefficient_value_type > variable_type
variable type
Definition Solvers.h:1170
T coefficient_value_type
T coefficient.
Definition Solvers.h:1164
LinearConstraint< coefficient_value_type > constraint_type
constraint type
Definition Solvers.h:1176
LinearExpression< coefficient_value_type > expression_type
expression type
Definition Solvers.h:1174
LinearTerm< coefficient_value_type > term_type
term type
Definition Solvers.h:1172
unsigned int id() const
Definition Solvers.h:117
namespace for Limbo.Solvers
SolverProperty
Some enums used in solver.
Definition Solvers.h:30
@ OPTIMAL
optimally solved
Definition Solvers.h:36
@ CONTINUOUS
floating point number
Definition Solvers.h:35
@ MIN
minimize objective
Definition Solvers.h:31
@ INFEASIBLE
the model is infeasible
Definition Solvers.h:37
@ UNBOUNDED
the model is unbounded
Definition Solvers.h:39
namespace for Limbo
std::iterator_traits< Iterator >::value_type max(Iterator first, Iterator last)
get max of an array
Definition Math.h:61
int limboPrint(MessageType m, const char *format,...)
formatted print with prefix
Definition PrintMsg.h:49
Round floating point solutions to integer if the variable type is integer. If not rounded,...
Definition CplexApi.h:89