15 * purpose. |
15 * purpose. |
16 * |
16 * |
17 */ |
17 */ |
18 |
18 |
19 #include <iostream> |
19 #include <iostream> |
|
20 #include <vector> |
20 #include<lemon/lp_cplex.h> |
21 #include<lemon/lp_cplex.h> |
21 |
22 |
22 ///\file |
23 ///\file |
23 ///\brief Implementation of the LEMON-CPLEX lp solver interface. |
24 ///\brief Implementation of the LEMON-CPLEX lp solver interface. |
24 namespace lemon { |
25 namespace lemon { |
25 |
26 |
26 LpCplex::LpCplex() : LpSolverBase() { |
27 LpCplex::LpCplex() { |
27 // env = CPXopenCPLEXdevelop(&status); |
28 // env = CPXopenCPLEXdevelop(&status); |
28 env = CPXopenCPLEX(&status); |
29 env = CPXopenCPLEX(&status); |
29 lp = CPXcreateprob(env, &status, "LP problem"); |
30 lp = CPXcreateprob(env, &status, "LP problem"); |
30 } |
31 } |
|
32 |
|
33 LpCplex::LpCplex(const LpCplex& cplex) : LpSolverBase() { |
|
34 env = CPXopenCPLEX(&status); |
|
35 lp = CPXcloneprob(env, cplex.lp, &status); |
|
36 rows = cplex.rows; |
|
37 cols = cplex.cols; |
|
38 } |
31 |
39 |
32 LpCplex::~LpCplex() { |
40 LpCplex::~LpCplex() { |
33 CPXfreeprob(env,&lp); |
41 CPXfreeprob(env,&lp); |
34 CPXcloseCPLEX(&env); |
42 CPXcloseCPLEX(&env); |
35 } |
43 } |
36 |
44 |
37 LpSolverBase &LpCplex::_newLp() |
45 LpSolverBase* LpCplex::_newLp() |
38 { |
46 { |
39 //The first approach opens a new environment |
47 //The first approach opens a new environment |
40 LpCplex* newlp=new LpCplex(); |
48 return new LpCplex(); |
41 return *newlp; |
49 } |
42 } |
50 |
43 |
51 LpSolverBase* LpCplex::_copyLp() { |
44 LpSolverBase &LpCplex::_copyLp() { |
52 return new LpCplex(*this); |
45 ///\bug FixID data is not copied! |
|
46 //The first approach opens a new environment |
|
47 LpCplex* newlp=new LpCplex(); |
|
48 //The routine CPXcloneprob can be used to create a new CPLEX problem |
|
49 //object and copy all the problem data from an existing problem |
|
50 //object to it. Solution and starting information is not copied. |
|
51 newlp->lp = CPXcloneprob(env, lp, &status); |
|
52 return *newlp; |
|
53 } |
53 } |
54 |
54 |
55 int LpCplex::_addCol() |
55 int LpCplex::_addCol() |
56 { |
56 { |
57 int i = CPXgetnumcols(env, lp); |
57 int i = CPXgetnumcols(env, lp); |
58 Value lb[1],ub[1]; |
58 Value lb[1],ub[1]; |
59 lb[0]=-INF;//-CPX_INFBOUND; |
59 lb[0]=-INF; |
60 ub[0]=INF;//CPX_INFBOUND; |
60 ub[0]=INF; |
61 status = CPXnewcols(env, lp, 1, NULL, lb, ub, NULL, NULL); |
61 status = CPXnewcols(env, lp, 1, NULL, lb, ub, NULL, NULL); |
62 return i; |
62 return i; |
63 } |
63 } |
64 |
64 |
65 |
65 |
87 void LpCplex::_getColName(int col, std::string &name) const |
87 void LpCplex::_getColName(int col, std::string &name) const |
88 { |
88 { |
89 ///\bug Untested |
89 ///\bug Untested |
90 int storespace; |
90 int storespace; |
91 CPXgetcolname(env, lp, 0, 0, 0, &storespace, col, col); |
91 CPXgetcolname(env, lp, 0, 0, 0, &storespace, col, col); |
92 |
92 if (storespace == 0) { |
|
93 name.clear(); |
|
94 return; |
|
95 } |
|
96 |
93 storespace *= -1; |
97 storespace *= -1; |
94 std::vector<char> buf(storespace); |
98 std::vector<char> buf(storespace); |
95 char *names[1]; |
99 char *names[1]; |
96 int dontcare; |
100 int dontcare; |
97 ///\bug return code unchecked for error |
101 ///\bug return code unchecked for error |
134 status = CPXchgcoeflist(env, lp, values.size(), |
138 status = CPXchgcoeflist(env, lp, values.size(), |
135 &rowlist[0], &indices[0], &values[0]); |
139 &rowlist[0], &indices[0], &values[0]); |
136 } |
140 } |
137 |
141 |
138 void LpCplex::_getRowCoeffs(int i, RowIterator b) const { |
142 void LpCplex::_getRowCoeffs(int i, RowIterator b) const { |
|
143 int tmp1, tmp2, tmp3, length; |
|
144 CPXgetrows(env, lp, &tmp1, &tmp2, 0, 0, 0, &length, i, i); |
|
145 |
|
146 length = -length; |
|
147 std::vector<int> indices(length); |
|
148 std::vector<double> values(length); |
|
149 |
|
150 CPXgetrows(env, lp, &tmp1, &tmp2, &indices[0], &values[0], |
|
151 length, &tmp3, i, i); |
|
152 |
|
153 for (int i = 0; i < length; ++i) { |
|
154 *b = std::make_pair(indices[i], values[i]); |
|
155 ++b; |
|
156 } |
|
157 |
139 /// \todo implement |
158 /// \todo implement |
140 } |
159 } |
141 |
160 |
142 void LpCplex::_setColCoeffs(int i, ConstColIterator b, ConstColIterator e) |
161 void LpCplex::_setColCoeffs(int i, ConstColIterator b, ConstColIterator e) |
143 { |
162 { |
154 status = CPXchgcoeflist(env, lp, values.size(), |
173 status = CPXchgcoeflist(env, lp, values.size(), |
155 &indices[0], &collist[0], &values[0]); |
174 &indices[0], &collist[0], &values[0]); |
156 } |
175 } |
157 |
176 |
158 void LpCplex::_getColCoeffs(int i, ColIterator b) const { |
177 void LpCplex::_getColCoeffs(int i, ColIterator b) const { |
159 /// \todo implement |
178 |
|
179 int tmp1, tmp2, tmp3, length; |
|
180 CPXgetcols(env, lp, &tmp1, &tmp2, 0, 0, 0, &length, i, i); |
|
181 |
|
182 length = -length; |
|
183 std::vector<int> indices(length); |
|
184 std::vector<double> values(length); |
|
185 |
|
186 CPXgetcols(env, lp, &tmp1, &tmp2, &indices[0], &values[0], |
|
187 length, &tmp3, i, i); |
|
188 |
|
189 for (int i = 0; i < length; ++i) { |
|
190 *b = std::make_pair(indices[i], values[i]); |
|
191 ++b; |
|
192 } |
|
193 |
160 } |
194 } |
161 |
195 |
162 void LpCplex::_setCoeff(int row, int col, Value value) |
196 void LpCplex::_setCoeff(int row, int col, Value value) |
163 { |
197 { |
164 CPXchgcoef(env, lp, row, col, value); |
198 CPXchgcoef(env, lp, row, col, value); |
185 |
219 |
186 LpCplex::Value LpCplex::_getColLowerBound(int i) const |
220 LpCplex::Value LpCplex::_getColLowerBound(int i) const |
187 { |
221 { |
188 LpCplex::Value x; |
222 LpCplex::Value x; |
189 CPXgetlb (env, lp, &x, i, i); |
223 CPXgetlb (env, lp, &x, i, i); |
|
224 if (x <= -CPX_INFBOUND) x = -INF; |
190 return x; |
225 return x; |
191 } |
226 } |
192 |
227 |
193 void LpCplex::_setColUpperBound(int i, Value value) |
228 void LpCplex::_setColUpperBound(int i, Value value) |
194 { |
229 { |
203 |
238 |
204 LpCplex::Value LpCplex::_getColUpperBound(int i) const |
239 LpCplex::Value LpCplex::_getColUpperBound(int i) const |
205 { |
240 { |
206 LpCplex::Value x; |
241 LpCplex::Value x; |
207 CPXgetub (env, lp, &x, i, i); |
242 CPXgetub (env, lp, &x, i, i); |
|
243 if (x >= CPX_INFBOUND) x = INF; |
208 return x; |
244 return x; |
209 } |
245 } |
210 |
246 |
211 //This will be easier to implement |
247 //This will be easier to implement |
212 void LpCplex::_setRowBounds(int i, Value lb, Value ub) |
248 void LpCplex::_setRowBounds(int i, Value lb, Value ub) |
467 // 3 Network Simplex |
503 // 3 Network Simplex |
468 // 4 Standard Barrier |
504 // 4 Standard Barrier |
469 // Default: 0 |
505 // Default: 0 |
470 // Description: Method for linear optimization. |
506 // Description: Method for linear optimization. |
471 // Determines which algorithm is used when CPXlpopt() (or "optimize" in the Interactive Optimizer) is called. Currently the behavior of the "Automatic" setting is that CPLEX simply invokes the dual simplex method, but this capability may be expanded in the future so that CPLEX chooses the method based on problem characteristics |
507 // Determines which algorithm is used when CPXlpopt() (or "optimize" in the Interactive Optimizer) is called. Currently the behavior of the "Automatic" setting is that CPLEX simply invokes the dual simplex method, but this capability may be expanded in the future so that CPLEX chooses the method based on problem characteristics |
|
508 #if CPX_VERSION < 900 |
472 void statusSwitch(CPXENVptr env,int& stat){ |
509 void statusSwitch(CPXENVptr env,int& stat){ |
473 #if CPX_VERSION < 900 |
|
474 int lpmethod; |
510 int lpmethod; |
475 CPXgetintparam (env,CPX_PARAM_LPMETHOD,&lpmethod); |
511 CPXgetintparam (env,CPX_PARAM_LPMETHOD,&lpmethod); |
476 if (lpmethod==2){ |
512 if (lpmethod==2){ |
477 if (stat==CPX_UNBOUNDED){ |
513 if (stat==CPX_UNBOUNDED){ |
478 stat=CPX_INFEASIBLE; |
514 stat=CPX_INFEASIBLE; |