2 * Copyright (C) 2005-2011 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
6 * This file may be distributed and/or modified under the terms of the
7 * GNU General Public License version 2 as published by the Free Software
8 * Foundation and appearing in the file LICENSE.GPL included in the
9 * packaging of this file.
11 * Licensees holding valid libFirm Professional Edition licenses may use
12 * this file in accordance with the libFirm Commercial License.
13 * Agreement provided with the Software.
15 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * @author Daniel Grund
27 #include "lpp_cplex.h"
32 #include <ilcplex/cplex.h>
35 #include "stat_timing.h"
36 #include "sp_matrix.h"
38 static char cpx_cst_encoding[4] = "?ELG";
39 static char cpx_var_encoding[4] = "??CB";
41 typedef struct _cpx_t {
49 static void chk_cpx_err(cpx_t *cpx)
52 if (CPXgeterrorstring(cpx->env, cpx->status, cpx->buf))
53 printf("%s", cpx->buf);
55 printf("Unknown CPLEX error\n");
60 static cpx_t *new_cpx(lpp_t *lpp)
62 cpx_t *cpx = XMALLOCZ(cpx_t);
64 cpx->env = CPXopenCPLEX(&cpx->status);
66 cpx->prob = CPXcreateprob(cpx->env, &cpx->status, lpp->name);
68 CPXchgobjsen(cpx->env, cpx->prob, (lpp->opt_type == lpp_minimize)?1:-1);
70 if (lpp->log && CPXsetlogfile(cpx->env, lpp->log))
75 static void free_cpx(cpx_t *cpx)
77 CPXfreeprob(cpx->env, &cpx->prob);
78 CPXcloseCPLEX(&cpx->env);
83 * Build CPLEX data structure from LPP matrix.
84 * @note: The LPP matrix is freed after this step, to save memory.
86 static void cpx_construct(cpx_t *cpx)
88 const matrix_elem_t *elem;
90 int numcols, numrows, numentries;
91 int objsen, *matbeg, *matcnt, *matind, *indices;
92 double *obj, *rhs, *matval, *lb, *ub, *startv;
93 char *sense, *vartype;
94 char **colname, **rowname;
96 lpp_t *lpp = cpx->lpp;
98 numcols = lpp->var_next-1;
99 numrows = lpp->cst_next-1;
100 numentries = matrix_get_entries(lpp->m);
101 objsen = lpp->opt_type == lpp_minimize ? 1 : -1;
104 obj = obstack_alloc(&obst, numcols * sizeof(*obj));
105 lb = obstack_alloc(&obst, numcols * sizeof(*lb));
106 ub = obstack_alloc(&obst, numcols * sizeof(*ub));
107 colname = obstack_alloc(&obst, numcols * sizeof(*colname));
108 rowname = obstack_alloc(&obst, numrows * sizeof(*rowname));
109 vartype = obstack_alloc(&obst, numcols * sizeof(*vartype));
110 indices = obstack_alloc(&obst, numcols * sizeof(*indices));
111 startv = obstack_alloc(&obst, numcols * sizeof(*startv));
112 matbeg = obstack_alloc(&obst, numcols * sizeof(*matbeg));
113 matcnt = obstack_alloc(&obst, numcols * sizeof(*matcnt));
114 matind = obstack_alloc(&obst, numentries * sizeof(*matind));
115 matval = obstack_alloc(&obst, numentries * sizeof(*matval));
116 rhs = obstack_alloc(&obst, numrows * sizeof(*rhs));
117 sense = obstack_alloc(&obst, numrows * sizeof(*sense));
121 /* fill the CPLEX matrix*/
122 for (i = 0; i < numcols; ++i) {
123 lpp_name_t *curr_var = lpp->vars[1+i];
125 obj[i] = matrix_get(lpp->m, 0, 1+i);
127 ub[i] = CPX_INFBOUND;
129 colname[i] = (char*) curr_var->name;
130 vartype[i] = cpx_var_encoding[curr_var->type.var_type];
132 if (curr_var->value_kind == lpp_value_start) {
134 startv[sv_cnt++] = curr_var->value;
139 matrix_foreach_in_col(lpp->m, 1 + i, elem) {
142 matind[o] = elem->row-1;
143 matval[o] = elem->val;
149 /* get constraint stuff (right hand side, type, name) */
150 for (i = 0; i < numrows; ++i) {
151 lpp_name_t *curr_cst = lpp->csts[1 + i];
153 rhs[i] = matrix_get(lpp->m, 1 + i, 0);
154 sense[i] = cpx_cst_encoding[curr_cst->type.cst_type];
155 rowname[i] = (char*) curr_cst->name;
158 cpx->status = CPXcopylpwnames(cpx->env, cpx->prob,
159 numcols, numrows, objsen,
161 matbeg, matcnt, matind, matval,
166 cpx->status = CPXcopyctype(cpx->env, cpx->prob, vartype);
168 cpx->status = CPXcopymipstart(cpx->env, cpx->prob, sv_cnt, indices, startv);
171 obstack_free(&obst, NULL);
172 lpp_free_matrix(lpp);
175 static void cpx_solve(cpx_t *cpx)
177 int i, CPX_state, numcols;
182 lpp_t *lpp = cpx->lpp;
183 numcols = CPXgetnumcols(cpx->env, cpx->prob);
186 /* set performance parameters */
187 // CPXsetintparam(cpx->env, CPX_PARAM_MIPSTART, CPX_ON);
188 CPXsetintparam(cpx->env, CPX_PARAM_MIPORDTYPE, CPX_MIPORDER_COST);
189 /* output every search tree node */
190 // CPXsetintparam(cpx->env, CPX_PARAM_MIPINTERVAL, 1);
192 /* experimental switches */
193 // CPXsetintparam(cpx->env, CPX_PARAM_VARSEL, CPX_VARSEL_STRONG);
194 // CPXsetdblparam(cpx->env, CPX_PARAM_BTTOL, 1.0);
195 // CPXsetintparam(cpx->env, CPX_PARAM_BRDIR, CPX_BRDIR_UP);
198 /* Set the time limit appropriately */
199 if(lpp->time_limit_secs > 0.0)
200 CPXsetdblparam(cpx->env, CPX_PARAM_TILIM, lpp->time_limit_secs);
203 * If we have enough time, we instruct cplex to imply some
204 * of its higher order magic to pursue the best solution
207 CPXsetintparam(cpx->env, CPX_PARAM_MIPEMPHASIS, lpp->emphasis);
211 * If a bound of the objective function is supplied,
212 * set it accordingly, dependign on minimization or maximization.
215 CPXsetdblparam(cpx->env, (lpp->opt_type == lpp_minimize
216 ? CPX_PARAM_OBJLLIM : CPX_PARAM_OBJULIM), lpp->bound);
219 /* turn on the fancy messages :) */
220 // CPXsetintparam (cpx->env, CPX_PARAM_SCRIND, CPX_ON);
224 cpx->status = CPXmipopt(cpx->env, cpx->prob);
228 /* get solution status */
229 CPX_state = CPXgetstat(cpx->env, cpx->prob);
232 CPXgetstatstring(cpx->env, CPX_state, buf);
233 fprintf(stderr, "%s\n", buf);
236 case CPXMIP_INFEASIBLE:
237 case CPX_STAT_INFEASIBLE: lpp->sol_state = lpp_infeasible; break;
238 case CPXMIP_INForUNBD:
239 case CPX_STAT_INForUNBD: lpp->sol_state = lpp_inforunb; break;
240 case CPXMIP_UNBOUNDED:
241 case CPX_STAT_UNBOUNDED: lpp->sol_state = lpp_unbounded; break;
242 case CPXMIP_ABORT_FEAS:
243 case CPXMIP_FAIL_FEAS:
244 case CPXMIP_MEM_LIM_FEAS:
245 case CPXMIP_NODE_LIM_FEAS:
246 case CPXMIP_TIME_LIM_FEAS: lpp->sol_state = lpp_feasible; break;
248 case CPXMIP_OPTIMAL_TOL: /* TODO: Is this ok? Read the docu more closely */
249 case CPX_STAT_OPTIMAL: lpp->sol_state = lpp_optimal; break;
250 default: lpp->sol_state = lpp_unknown;
253 /* get variable solution values */
254 values = alloca(numcols * sizeof(*values));
255 CPXgetmipx(cpx->env, cpx->prob, values, 0, numcols-1);
257 for(i=0; i<numcols; ++i) {
258 lpp->vars[1+i]->value = values[i];
259 lpp->vars[1+i]->value_kind = lpp_value_solution;
262 /* Get the value of the objective function. */
263 CPXgetmipobjval(cpx->env, cpx->prob, &lpp->objval);
264 CPXgetbestobjval(cpx->env, cpx->prob, &lpp->best_bound);
266 /* get some statistics */
267 timing_ticks_sub(tva, tvb);
268 lpp->sol_time = timing_ticks_dbl(tva);
269 lpp->iterations = CPXgetmipitcnt(cpx->env, cpx->prob);
272 void lpp_solve_cplex(lpp_t *lpp)
274 cpx_t *cpx = new_cpx(lpp);