diff options
author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2012-08-13 16:40:19 -0400 |
---|---|---|
committer | Bjoern Brandenburg <bbb@mpi-sws.org> | 2013-02-12 06:55:15 -0500 |
commit | 79818e276e30d037501b4eceaa25b9b2ccffbff6 (patch) | |
tree | 5f488f868440f51f4aebb43720e94d62aa605c0d | |
parent | 15a7af46ccdbdcc9871113a927104e596638dfc5 (diff) |
Implement CPLEX integration via C API
Using the plain, old C API seems to be *much* faster.
single:
lp_dpcp_bounds::cpu_costs: total=19569.9ms last=93.2767ms average=88.9543ms count=220
lp_dflp_bounds::cpu_costs: total=21537.3ms last=102.459ms average=97.8969ms count=220
-rw-r--r-- | native/Makefile | 2 | ||||
-rw-r--r-- | native/include/linprog/cplex.h | 4 | ||||
-rw-r--r-- | native/src/linprog/cpx.cpp | 243 |
3 files changed, 248 insertions, 1 deletions
diff --git a/native/Makefile b/native/Makefile index 36cb08f..d722fcd 100644 --- a/native/Makefile +++ b/native/Makefile | |||
@@ -121,7 +121,7 @@ ifneq ($(CPLEX_PATH)$(GLPK_PATH),) | |||
121 | LP_OBJ = lp_common.o io.o lp_dflp.o lp_dpcp.o | 121 | LP_OBJ = lp_common.o io.o lp_dflp.o lp_dpcp.o |
122 | 122 | ||
123 | ifneq ($(CPLEX_PATH),) | 123 | ifneq ($(CPLEX_PATH),) |
124 | LP_OBJ += cplex.o | 124 | LP_OBJ += cplex.o cpx.o |
125 | endif | 125 | endif |
126 | 126 | ||
127 | ifneq ($(GLPK_PATH),) | 127 | ifneq ($(GLPK_PATH),) |
diff --git a/native/include/linprog/cplex.h b/native/include/linprog/cplex.h index c68bd24..5e7addf 100644 --- a/native/include/linprog/cplex.h +++ b/native/include/linprog/cplex.h | |||
@@ -3,6 +3,10 @@ | |||
3 | 3 | ||
4 | #include "linprog/solver.h" | 4 | #include "linprog/solver.h" |
5 | 5 | ||
6 | // solve with CPLEX connected via the "Concert Technology" API | ||
6 | Solution *cplex_solve(const LinearProgram& lp, unsigned int max_num_vars); | 7 | Solution *cplex_solve(const LinearProgram& lp, unsigned int max_num_vars); |
7 | 8 | ||
9 | // solve with CPLEX connected via the plain, old C API | ||
10 | Solution *cpx_solve(const LinearProgram& lp, unsigned int max_num_vars); | ||
11 | |||
8 | #endif | 12 | #endif |
diff --git a/native/src/linprog/cpx.cpp b/native/src/linprog/cpx.cpp new file mode 100644 index 0000000..f421b0e --- /dev/null +++ b/native/src/linprog/cpx.cpp | |||
@@ -0,0 +1,243 @@ | |||
1 | #define IL_STD // required by CPLEX when using STL classes. | ||
2 | |||
3 | #include <assert.h> | ||
4 | #include <ilcplex/cplex.h> | ||
5 | |||
6 | #include "cpu_time.h" | ||
7 | |||
8 | #include "linprog/cplex.h" | ||
9 | |||
10 | class CPXSolution : public Solution | ||
11 | { | ||
12 | private: | ||
13 | CPXENVptr env; | ||
14 | CPXLPptr lp; | ||
15 | |||
16 | const LinearProgram &linprog; | ||
17 | const unsigned int num_cols; | ||
18 | const unsigned int num_rows; | ||
19 | unsigned int num_coeffs; | ||
20 | |||
21 | double *values; | ||
22 | bool solved; | ||
23 | |||
24 | void solve_model(double var_lb, double var_ub); | ||
25 | |||
26 | bool setup_objective(double lb, double ub); | ||
27 | bool add_rows(); | ||
28 | bool load_coeffs(); | ||
29 | |||
30 | public: | ||
31 | CPXSolution(const LinearProgram &lp, unsigned int max_num_vars, | ||
32 | double var_lb = 0.0, double var_ub = 1.0); | ||
33 | ~CPXSolution(); | ||
34 | |||
35 | double get_value(unsigned int var) const | ||
36 | { | ||
37 | return values[var]; | ||
38 | } | ||
39 | |||
40 | bool is_solved() const | ||
41 | { | ||
42 | return solved; | ||
43 | } | ||
44 | }; | ||
45 | |||
46 | CPXSolution::CPXSolution(const LinearProgram& lp, unsigned int max_num_vars, | ||
47 | double var_lb, double var_ub) | ||
48 | : env(0), | ||
49 | lp(0), | ||
50 | linprog(lp), | ||
51 | num_cols(max_num_vars), | ||
52 | num_rows(lp.get_equalities().size() + | ||
53 | lp.get_inequalities().size()), | ||
54 | num_coeffs(0), | ||
55 | values(0), | ||
56 | solved(false) | ||
57 | { | ||
58 | if (num_cols > 0) | ||
59 | { | ||
60 | values = new double[num_cols]; | ||
61 | solve_model(var_lb, var_ub); | ||
62 | } else | ||
63 | // Trivial case: no variables. | ||
64 | solved = true; | ||
65 | } | ||
66 | |||
67 | |||
68 | void CPXSolution::solve_model(double var_lb, double var_ub) | ||
69 | { | ||
70 | int err; | ||
71 | |||
72 | #if DEBUG_LP_OVERHEADS >= 3 | ||
73 | static DEFINE_CPU_CLOCK(model_costs); | ||
74 | static DEFINE_CPU_CLOCK(solver_costs); | ||
75 | static DEFINE_CPU_CLOCK(extract_costs); | ||
76 | |||
77 | model_costs.start(); | ||
78 | #endif | ||
79 | |||
80 | env = CPXopenCPLEX(&err); | ||
81 | |||
82 | if (!env) | ||
83 | return; | ||
84 | |||
85 | lp = CPXcreateprob(env, &err, "blocking"); | ||
86 | |||
87 | if (!lp) | ||
88 | return; | ||
89 | |||
90 | |||
91 | if (!setup_objective(var_lb, var_ub) || | ||
92 | !add_rows() || | ||
93 | !load_coeffs()) | ||
94 | return; | ||
95 | |||
96 | #if DEBUG_LP_OVERHEADS >= 3 | ||
97 | model_costs.stop(); | ||
98 | solver_costs.start(); | ||
99 | #endif | ||
100 | |||
101 | err = CPXlpopt(env, lp); | ||
102 | |||
103 | |||
104 | #if DEBUG_LP_OVERHEADS >= 3 | ||
105 | solver_costs.stop(); | ||
106 | extract_costs.start(); | ||
107 | #endif | ||
108 | |||
109 | err = CPXsolution(env, lp, NULL, NULL, values, NULL, NULL, NULL); | ||
110 | solved = err == 0; | ||
111 | |||
112 | #if DEBUG_LP_OVERHEADS >= 3 | ||
113 | extract_costs.stop(); | ||
114 | |||
115 | std::cout << model_costs << std::endl | ||
116 | << solver_costs << std::endl | ||
117 | << extract_costs << std::endl; | ||
118 | #endif | ||
119 | } | ||
120 | |||
121 | CPXSolution::~CPXSolution() | ||
122 | { | ||
123 | int status; | ||
124 | |||
125 | if (lp) { | ||
126 | status = CPXfreeprob(env, &lp); | ||
127 | assert(status == 0); | ||
128 | } | ||
129 | |||
130 | if (env) { | ||
131 | status = CPXcloseCPLEX(&env); | ||
132 | assert(status == 0); | ||
133 | } | ||
134 | |||
135 | delete [] values; | ||
136 | } | ||
137 | |||
138 | bool CPXSolution::setup_objective(double lb, double ub) | ||
139 | { | ||
140 | |||
141 | const LinearExpression *obj = linprog.get_objective(); | ||
142 | int err; | ||
143 | |||
144 | double *all = new double[num_cols * 3]; | ||
145 | double *vals = all; | ||
146 | double *lbs = all + num_cols; | ||
147 | double *ubs = all + 2 * num_cols; | ||
148 | |||
149 | assert(obj->get_terms().size() == num_cols); | ||
150 | |||
151 | foreach(obj->get_terms(), term) | ||
152 | vals[term->second] = term->first; | ||
153 | |||
154 | for (unsigned int i = 0; i < num_cols; i++) | ||
155 | { | ||
156 | lbs[i] = lb; | ||
157 | ubs[i] = ub; | ||
158 | } | ||
159 | |||
160 | CPXchgobjsen(env, lp, CPX_MAX); | ||
161 | err = CPXnewcols(env, lp, num_cols, vals, lbs, ubs, NULL, NULL); | ||
162 | |||
163 | delete [] all; | ||
164 | |||
165 | return err == 0; | ||
166 | } | ||
167 | |||
168 | bool CPXSolution::add_rows() | ||
169 | { | ||
170 | double *bounds = new double[num_rows]; | ||
171 | char *senses = new char[num_rows]; | ||
172 | int err; | ||
173 | |||
174 | unsigned int r = 0; | ||
175 | |||
176 | foreach(linprog.get_equalities(), equ) | ||
177 | { | ||
178 | bounds[r] = equ->second; | ||
179 | senses[r] = 'E'; // equality constraint | ||
180 | |||
181 | num_coeffs += equ->first->get_terms().size(); | ||
182 | r++; | ||
183 | } | ||
184 | |||
185 | foreach(linprog.get_inequalities(), inequ) | ||
186 | { | ||
187 | bounds[r] = inequ->second; | ||
188 | senses[r] = 'L'; // less-than-or-equal constraint | ||
189 | |||
190 | num_coeffs += inequ->first->get_terms().size(); | ||
191 | r++; | ||
192 | } | ||
193 | |||
194 | |||
195 | err = CPXnewrows(env, lp, num_rows, bounds, senses, NULL, NULL); | ||
196 | |||
197 | delete [] bounds; | ||
198 | delete [] senses; | ||
199 | |||
200 | return err == 0; | ||
201 | } | ||
202 | |||
203 | bool CPXSolution::load_coeffs() | ||
204 | { | ||
205 | unsigned int r = 0; | ||
206 | int err; | ||
207 | |||
208 | foreach(linprog.get_equalities(), equ) | ||
209 | { | ||
210 | foreach(equ->first->get_terms(), term) | ||
211 | { | ||
212 | err = CPXchgcoef(env, lp, r, term->second, term->first); | ||
213 | if (err != 0) | ||
214 | return false; | ||
215 | } | ||
216 | r++; | ||
217 | } | ||
218 | |||
219 | foreach(linprog.get_inequalities(), inequ) | ||
220 | { | ||
221 | foreach(inequ->first->get_terms(), term) | ||
222 | { | ||
223 | err = CPXchgcoef(env, lp, r, term->second, term->first); | ||
224 | if (err != 0) | ||
225 | return false; | ||
226 | } | ||
227 | r++; | ||
228 | } | ||
229 | |||
230 | return true; | ||
231 | } | ||
232 | |||
233 | Solution *cpx_solve(const LinearProgram& lp, unsigned int max_num_vars) | ||
234 | { | ||
235 | CPXSolution *sol = new CPXSolution(lp, max_num_vars); | ||
236 | if (sol->is_solved()) | ||
237 | return sol; | ||
238 | else | ||
239 | { | ||
240 | delete sol; | ||
241 | return NULL; | ||
242 | } | ||
243 | } | ||