4 * Copyright: (c) Universitaet Karlsruhe
5 * Licence: This file protected by GPL - GNU GENERAL PUBLIC LICENSE.
18 #include <ilcplex/cplex.h>
21 #include "sp_matrix.h"
23 static char cpx_cst_encoding[4] = "?ELG";
24 static char cpx_var_encoding[4] = "??CB";
26 #define my_timersub(tvp, uvp, vvp) \
28 (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
29 (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
30 if ((vvp)->tv_usec < 0) { \
32 (vvp)->tv_usec += 1000000; \
36 typedef struct _cpx_t {
44 static void chk_cpx_err(cpx_t *cpx)
47 if (CPXgeterrorstring(cpx->env, cpx->status, cpx->buf))
48 printf("%s", cpx->buf);
50 printf("Unknown CPLEX error\n");
55 static cpx_t *new_cpx(lpp_t *lpp)
57 cpx_t *cpx = XMALLOCZ(cpx_t);
59 cpx->env = CPXopenCPLEX(&cpx->status);
61 cpx->prob = CPXcreateprob(cpx->env, &cpx->status, lpp->name);
63 CPXchgobjsen(cpx->env, cpx->prob, (lpp->opt_type == lpp_minimize)?1:-1);
65 if (lpp->log && CPXsetlogfile(cpx->env, lpp->log))
70 static void free_cpx(cpx_t *cpx)
72 CPXfreeprob(cpx->env, &cpx->prob);
73 CPXcloseCPLEX(&cpx->env);
78 * Build CPLEX data structure from LPP matrix.
79 * @note: The LPP matrix is freed after this step, to save memory.
81 static void cpx_construct(cpx_t *cpx)
83 const matrix_elem_t *elem;
85 int numcols, numrows, numentries;
86 int objsen, *matbeg, *matcnt, *matind, *indices;
87 double *obj, *rhs, *matval, *lb, *ub, *startv;
88 char *sense, *vartype;
89 char **colname, **rowname;
91 lpp_t *lpp = cpx->lpp;
93 numcols = lpp->var_next-1;
94 numrows = lpp->cst_next-1;
95 numentries = matrix_get_entries(lpp->m);
96 objsen = lpp->opt_type == lpp_minimize ? 1 : -1;
99 obj = obstack_alloc(&obst, numcols * sizeof(*obj));
100 lb = obstack_alloc(&obst, numcols * sizeof(*lb));
101 ub = obstack_alloc(&obst, numcols * sizeof(*ub));
102 colname = obstack_alloc(&obst, numcols * sizeof(*colname));
103 rowname = obstack_alloc(&obst, numrows * sizeof(*rowname));
104 vartype = obstack_alloc(&obst, numcols * sizeof(*vartype));
105 indices = obstack_alloc(&obst, numcols * sizeof(*indices));
106 startv = obstack_alloc(&obst, numcols * sizeof(*startv));
107 matbeg = obstack_alloc(&obst, numcols * sizeof(*matbeg));
108 matcnt = obstack_alloc(&obst, numcols * sizeof(*matcnt));
109 matind = obstack_alloc(&obst, numentries * sizeof(*matind));
110 matval = obstack_alloc(&obst, numentries * sizeof(*matval));
111 rhs = obstack_alloc(&obst, numrows * sizeof(*rhs));
112 sense = obstack_alloc(&obst, numrows * sizeof(*sense));
116 /* fill the CPLEX matrix*/
117 for (i = 0; i < numcols; ++i) {
118 lpp_name_t *curr_var = lpp->vars[1+i];
120 obj[i] = matrix_get(lpp->m, 0, 1+i);
122 ub[i] = CPX_INFBOUND;
124 colname[i] = (char*) curr_var->name;
125 vartype[i] = cpx_var_encoding[curr_var->type.var_type];
127 if (curr_var->value_kind == lpp_value_start) {
129 startv[sv_cnt++] = curr_var->value;
134 matrix_foreach_in_col(lpp->m, 1 + i, elem) {
137 matind[o] = elem->row-1;
138 matval[o] = elem->val;
144 /* get constraint stuff (right hand side, type, name) */
145 for (i = 0; i < numrows; ++i) {
146 lpp_name_t *curr_cst = lpp->csts[1 + i];
148 rhs[i] = matrix_get(lpp->m, 1 + i, 0);
149 sense[i] = cpx_cst_encoding[curr_cst->type.cst_type];
150 rowname[i] = (char*) curr_cst->name;
153 cpx->status = CPXcopylpwnames(cpx->env, cpx->prob,
154 numcols, numrows, objsen,
156 matbeg, matcnt, matind, matval,
161 cpx->status = CPXcopyctype(cpx->env, cpx->prob, vartype);
163 cpx->status = CPXcopymipstart(cpx->env, cpx->prob, sv_cnt, indices, startv);
166 obstack_free(&obst, NULL);
167 free_lpp_matrix(lpp);
170 static void cpx_solve(cpx_t *cpx)
172 int i, CPX_state, numcols;
174 struct timeval tvb, tva, tvdiff;
176 lpp_t *lpp = cpx->lpp;
177 numcols = CPXgetnumcols(cpx->env, cpx->prob);
180 /* set performance parameters */
181 // CPXsetintparam(cpx->env, CPX_PARAM_MIPSTART, CPX_ON);
182 CPXsetintparam(cpx->env, CPX_PARAM_MIPORDTYPE, CPX_MIPORDER_COST);
183 /* output every search tree node */
184 // CPXsetintparam(cpx->env, CPX_PARAM_MIPINTERVAL, 1);
186 /* experimental switches */
187 // CPXsetintparam(cpx->env, CPX_PARAM_VARSEL, CPX_VARSEL_STRONG);
188 // CPXsetdblparam(cpx->env, CPX_PARAM_BTTOL, 1.0);
189 // CPXsetintparam(cpx->env, CPX_PARAM_BRDIR, CPX_BRDIR_UP);
192 /* Set the time limit appropriately */
193 if(lpp->time_limit_secs > 0.0)
194 CPXsetdblparam(cpx->env, CPX_PARAM_TILIM, lpp->time_limit_secs);
197 * If we have enough time, we instruct cplex to imply some
198 * of its higher order magic to pursue the best solution
201 CPXsetintparam(cpx->env, CPX_PARAM_MIPEMPHASIS, lpp->emphasis);
205 * If a bound of the objective function is supplied,
206 * set it accordingly, dependign on minimization or maximization.
209 CPXsetdblparam(cpx->env, (lpp->opt_type == lpp_minimize
210 ? CPX_PARAM_OBJLLIM : CPX_PARAM_OBJULIM), lpp->bound);
213 /* turn on the fancy messages :) */
214 // CPXsetintparam (cpx->env, CPX_PARAM_SCRIND, CPX_ON);
217 gettimeofday(&tvb, NULL);
218 cpx->status = CPXmipopt(cpx->env, cpx->prob);
219 gettimeofday(&tva, NULL);
222 /* get solution status */
223 CPX_state = CPXgetstat(cpx->env, cpx->prob);
226 CPXgetstatstring(cpx->env, CPX_state, buf);
227 fprintf(stderr, "%s\n", buf);
230 case CPXMIP_INFEASIBLE:
231 case CPX_STAT_INFEASIBLE: lpp->sol_state = lpp_infeasible; break;
232 case CPXMIP_INForUNBD:
233 case CPX_STAT_INForUNBD: lpp->sol_state = lpp_inforunb; break;
234 case CPXMIP_UNBOUNDED:
235 case CPX_STAT_UNBOUNDED: lpp->sol_state = lpp_unbounded; break;
236 case CPXMIP_ABORT_FEAS:
237 case CPXMIP_FAIL_FEAS:
238 case CPXMIP_MEM_LIM_FEAS:
239 case CPXMIP_NODE_LIM_FEAS:
240 case CPXMIP_TIME_LIM_FEAS: lpp->sol_state = lpp_feasible; break;
242 case CPXMIP_OPTIMAL_TOL: /* TODO: Is this ok? Read the docu more closely */
243 case CPX_STAT_OPTIMAL: lpp->sol_state = lpp_optimal; break;
244 default: lpp->sol_state = lpp_unknown;
247 /* get variable solution values */
248 values = alloca(numcols * sizeof(*values));
249 CPXgetmipx(cpx->env, cpx->prob, values, 0, numcols-1);
251 for(i=0; i<numcols; ++i) {
252 lpp->vars[1+i]->value = values[i];
253 lpp->vars[1+i]->value_kind = lpp_value_solution;
256 /* Get the value of the objective function. */
257 CPXgetmipobjval(cpx->env, cpx->prob, &lpp->objval);
258 CPXgetbestobjval(cpx->env, cpx->prob, &lpp->best_bound);
260 /* get some statistics */
261 my_timersub(&tva, &tvb, &tvdiff);
262 lpp->sol_time = tvdiff.tv_sec + tvdiff.tv_usec / 1e6;
263 lpp->iterations = CPXgetmipitcnt(cpx->env, cpx->prob);
266 void lpp_solve_cplex(lpp_t *lpp)
268 cpx_t *cpx = new_cpx(lpp);