1/* BEGIN LICENSE BLOCK
2 * Version: CMPL 1.1
3 *
4 * The contents of this file are subject to the Cisco-style Mozilla Public
5 * License Version 1.1 (the "License"); you may not use this file except
6 * in compliance with the License.  You may obtain a copy of the License
7 * at www.eclipse-clp.org/license.
8 *
9 * Software distributed under the License is distributed on an "AS IS"
10 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See
11 * the License for the specific language governing rights and limitations
12 * under the License.
13 *
14 * The Original Code is  The ECLiPSe/Gurobi Interface
15 * The Initial Developer of the Original Code is Joachim Schimpf
16 * Portions created by the Initial Developer are
17 * Copyright (C) 2012 Joachim Schimpf
18 *
19 * Contributor(s): Joachim Schimpf, Coninfer Ltd
20 *
21 * END LICENSE BLOCK */
22
23/*
24 * ECLiPSe/Gurobi interface (for inclusion in eplex.c)
25 */
26
27#ifdef GUROBI
28
29/*
30 * Notes on Gurobi
31 *
32 * Parameters
33 *	Parameters are part of the "environment". When a model is created,
34 *	it gets a copy of the specified environment.
35 * Strangely uses strings for attribute/param identifiers
36 * Methods
37 *	auto
38 *	primal
39 *	dual
40 *	barrier
41 *	barrier(auto|none|1|2|3|4)
42 *	concurrent
43 *	concurrent_det
44 *	sift(auto|primal|dual|barrier)
45 * Node_methods
46 *	primal
47 *	dual
48 *	barrier
49 * Need to "flush" model modifications with GRBupdatemodel()
50 *	between adding columns and rows with these columns,
51 *	and on many other occasions after the model changed.
52 * No notion of different message streams (log,warning,error,result)
53 *	we send everything to Log
54 *
55 * Licence
56 *	license file gurobi.lic in HOME, C:\gurobiVV or /opt/gurobiVV
57 *	alternatively GRB_LICENSE_FILE contains path name of license file
58 */
59
60static int
61grb_getintattr(GRBmodel* lp, const char* attr)
62{
63    int value = 0;
64    GRBgetintattr(lp, attr, &value);
65    return value;
66}
67
68
69static int
70grb_chgbds(GRBmodel* lp, int cnt, int* idxs, char* lu, double* bd)
71{
72    int err, i, nvars;
73    if (GRBgetintattr(lp, GRB_INT_ATTR_NUMVARS, &nvars))
74	goto _return_err_;
75    for (i=0; i<cnt; i++)
76    {
77	int j=idxs[i];
78	if (j < 0 || j >= nvars) return -1;
79	switch(lu[i])
80	{
81	    case 'L': err = GRBsetdblattrelement(lp,GRB_DBL_ATTR_LB,j,bd[i]);
82	    	break;
83	    case 'B': err = GRBsetdblattrelement(lp,GRB_DBL_ATTR_LB,j,bd[i]);
84	    	/*fall through*/
85	    case 'U': err = GRBsetdblattrelement(lp,GRB_DBL_ATTR_UB,j,bd[i]);
86	    	break;
87	    default:
88		return -1;
89	}
90	if (err) goto _return_err_;
91    }
92    return 0;
93_return_err_:
94    Report_Solver_Error(cpx_env);
95    return -1;
96}
97
98
99/* caution: this function assumes that the arrays are the right size */
100static int
101grb_loadbasis(GRBmodel* lp, int* cbase, int* rbase)
102{
103    int nvars, ncstr;
104    if (GRBgetintattr(lp, GRB_INT_ATTR_NUMVARS, &nvars))
105	goto _return_err_;
106    if (GRBgetintattr(lp, GRB_INT_ATTR_NUMCONSTRS, &ncstr))
107	goto _return_err_;
108    if (GRBsetintattrarray(lp,GRB_INT_ATTR_CBASIS,0,ncstr,cbase))
109	goto _return_err_;
110    if (GRBsetintattrarray(lp,GRB_INT_ATTR_VBASIS,0,nvars,rbase))
111	goto _return_err_;
112    return 0;
113_return_err_:
114    Report_Solver_Error(cpx_env);
115    return -1;
116}
117
118
119static int
120cpx_loadstart(lp_desc* lpd, int option, double *sols, int sz)
121{
122    int nvars, i;
123
124    if (GRBgetintattr(lpd->lp, GRB_INT_ATTR_NUMVARS, &nvars))
125	goto _return_err_;
126    if (sz == 0) option = MIPSTART_NONE;
127    if (sz > nvars) sz = nvars;
128
129    switch(option)
130    {
131    case MIPSTART_NONE:
132	if (lpd->mipstart_dirty)
133	{
134	    for (i=0; i<nvars; ++i)
135	    {
136		if (GRBsetdblattrelement(lpd->lp,GRB_DBL_ATTR_START,i,GRB_UNDEFINED))
137		    goto _return_err_;
138	    }
139	    lpd->mipstart_dirty = 0;
140	}
141	break;
142
143    case MIPSTART_ALL:
144	if (GRBsetdblattrarray(lpd->lp,GRB_DBL_ATTR_START,0,sz,sols))
145	    goto _return_err_;
146	for (i=sz; i<nvars; ++i)
147	{
148	    if (GRBsetdblattrelement(lpd->lp,GRB_DBL_ATTR_START,i,GRB_UNDEFINED))
149		goto _return_err_;
150	}
151	lpd->mipstart_dirty = 1;
152	break;
153
154    case MIPSTART_INT:
155	{
156	    char *vtype = (char*) Malloc(nvars*sizeof(char));
157	    if (GRBgetcharattrarray(lpd->lp,GRB_CHAR_ATTR_VTYPE,0,nvars,vtype))
158	    {
159		Free(vtype);
160		goto _return_err_;
161	    }
162	    for (i=0; i<sz; ++i)
163	    {
164		if (GRBsetdblattrelement(lpd->lp,GRB_DBL_ATTR_START,i,
165			vtype[i]=='C' ? GRB_UNDEFINED : sols[i]))
166		{
167		    Free(vtype);
168		    goto _return_err_;
169		}
170	    }
171	    Free(vtype);
172	    for (i=sz; i<nvars; ++i)
173	    {
174		if (GRBsetdblattrelement(lpd->lp,GRB_DBL_ATTR_START,i,GRB_UNDEFINED))
175		    goto _return_err_;
176	    }
177	    lpd->mipstart_dirty = 1;
178	}
179	break;
180    }
181    return 0;
182
183_return_err_:
184    Report_Solver_Error(cpx_env);
185    return -1;
186}
187
188
189/* caution: this function assumes that the arrays are the right size */
190static int
191grb_getbasis(GRBmodel* lp, int* cbase, int* rbase)
192{
193    int nvars, ncstr;
194    if (GRBgetintattr(lp, GRB_INT_ATTR_NUMVARS, &nvars))
195	goto _return_err_;
196    if (GRBgetintattr(lp, GRB_INT_ATTR_NUMCONSTRS, &ncstr))
197	goto _return_err_;
198    if (GRBgetintattrarray(lp,GRB_INT_ATTR_CBASIS,0,ncstr,cbase))
199	goto _return_err_;
200    if (GRBgetintattrarray(lp,GRB_INT_ATTR_VBASIS,0,nvars,rbase))
201	goto _return_err_;
202    return 0;
203_return_err_:
204    Report_Solver_Error(cpx_env);
205    return -1;
206}
207
208
209static int
210grb_setname(GRBmodel* lp, char ntype, int idx, char * name)
211{
212    switch(ntype)
213    {
214    case 'c':
215	if (GRBsetstrattrelement(lp,GRB_STR_ATTR_VARNAME,idx,name))
216	    goto _return_err_;
217	break;
218    case 'r':
219	if (GRBsetstrattrelement(lp,GRB_STR_ATTR_CONSTRNAME,idx,name))
220	    goto _return_err_;
221	break;
222    default:
223    	return -1;
224    }
225    return 0;
226_return_err_:
227    Report_Solver_Error(cpx_env);
228    return -1;
229}
230
231
232/*
233 * Set parameters for methods and timeout
234 */
235static int
236cpx_prepare_solve(lp_desc* lpd, struct lp_meth *meth, double timeout)
237{
238    int method, val, min, max;
239    GRBenv* grb_env = GRBgetenv(lpd->lp);
240
241    if (timeout <= 0.0)
242    	timeout = HUGE_VAL;
243    if (GRBsetdblparam(grb_env, GRB_DBL_PAR_TIMELIMIT, timeout))
244	goto _return_err_;
245
246    if (meth->meth != METHOD_DEFAULT)
247    {
248	switch(meth->meth)
249	{
250	    case METHOD_AUTO:	method = GRB_METHOD_AUTO; break;
251	    case METHOD_PRIMAL:	method = GRB_METHOD_PRIMAL; break;
252	    case METHOD_DUAL:	method = GRB_METHOD_DUAL; break;
253	    case METHOD_CONCURRENT:	method = GRB_METHOD_CONCURRENT; break;
254	    case METHOD_CONCURRENTDET:	method = GRB_METHOD_DETERMINISTIC_CONCURRENT; break;
255	    case METHOD_BAR:
256		if (meth->auxmeth != METHOD_DEFAULT)
257		{
258		    switch(meth->auxmeth)
259		    {
260			case METHOD_AUTO:	method = -1; break;
261			case METHOD_NONE:	method = 0; break;
262			case METHOD_PRIMAL:	method = 3; break;
263			case METHOD_DUAL:	method = 2; break;
264			default:		goto _illegal_method_;
265		    }
266		    if (GRBsetintparam(grb_env, GRB_INT_PAR_CROSSOVER, method))
267			goto _return_err_;
268		}
269		method = GRB_METHOD_BARRIER;
270		break;
271	    case METHOD_SIFT:
272		if (meth->auxmeth != METHOD_DEFAULT)
273		{
274		    switch(meth->auxmeth)
275		    {
276			case METHOD_AUTO:	method = -1; break;
277			case METHOD_PRIMAL:	method = 0; break;
278			case METHOD_DUAL:	method = 1; break;
279			case METHOD_BAR:	method = 2; break;
280			default:		goto _illegal_method_;
281		    }
282		    if (GRBsetintparam(grb_env, GRB_INT_PAR_SIFTMETHOD, method))
283			goto _return_err_;
284		}
285		/* We leave the SIFTING parameter untouched! */
286		method = GRB_METHOD_DUAL;
287		break;
288	    default:	goto _illegal_method_;
289	}
290	if (GRBsetintparam(grb_env, GRB_INT_PAR_METHOD, method))
291	    goto _return_err_;
292    }
293
294    if (meth->node_meth != METHOD_DEFAULT)
295    {
296	switch(meth->node_meth)
297	{
298	    case METHOD_PRIMAL:	method = GRB_METHOD_PRIMAL; break;
299	    case METHOD_DUAL:	method = GRB_METHOD_DUAL; break;
300	    case METHOD_BAR:
301		if (meth->meth != METHOD_BAR && meth->node_auxmeth != METHOD_DEFAULT)
302		{
303		    switch(meth->node_auxmeth)
304		    {
305			case METHOD_AUTO:	method = -1; break;
306			case METHOD_NONE:	method = 0; break;
307			case METHOD_PRIMAL:	method = 3; break;
308			case METHOD_DUAL:	method = 2; break;
309			default:		goto _illegal_method_;
310		    }
311		    if (GRBsetintparam(grb_env, GRB_INT_PAR_CROSSOVER, method))
312			goto _return_err_;
313		}
314		method = GRB_METHOD_BARRIER;
315		break;
316	    case METHOD_SIFT:
317		if (meth->meth != METHOD_SIFT && meth->node_auxmeth != METHOD_DEFAULT)
318		{
319		    switch(meth->node_auxmeth)
320		    {
321			case METHOD_AUTO:	method = -1; break;
322			case METHOD_PRIMAL:	method = 0; break;
323			case METHOD_DUAL:	method = 1; break;
324			case METHOD_BAR:	method = 2; break;
325			default:		goto _illegal_method_;
326		    }
327		    if (GRBsetintparam(grb_env, GRB_INT_PAR_SIFTMETHOD, method))
328			goto _return_err_;
329		}
330		/* We leave the SIFTING parameter untouched! */
331		method = GRB_METHOD_DUAL;
332		break;
333	    default:	goto _illegal_method_;
334	}
335	if (GRBsetintparam(grb_env, GRB_INT_PAR_NODEMETHOD, method))
336	    goto _return_err_;
337    }
338
339    return 0;
340
341_illegal_method_:
342    Report_Error("Unsupported solver method");
343    return -1;
344_return_err_:
345    Report_Solver_Error(cpx_env);
346    return -1;
347}
348
349
350static int
351cpx_solve(lp_desc* lpd, struct lp_meth *meth, struct lp_sol *sol, double* bestbound, double* worstbound)
352{
353    int sol_count;
354    int rev_state = GRB_LOADED;
355
356    if (cpx_loadstart(lpd, meth->option_mipstart, sol->oldsols, sol->oldmac))
357	return -1;
358
359_retry_:
360    if (GRBoptimize(lpd->lp))
361    	goto _return_err_;
362
363    if (GRBgetintattr(lpd->lp, GRB_INT_ATTR_STATUS, &lpd->sol_state))
364    	goto _return_err_;
365
366    switch(lpd->sol_state)
367    {
368    case GRB_OPTIMAL:			/* SuccessState */
369	    lpd->descr_state = DESCR_SOLVED_SOL;
370	    lpd->optimum_ctr++;
371	    if (GRBgetdblattr(lpd->lp, GRB_DBL_ATTR_OBJVAL, &lpd->objval))
372		goto _return_err_;
373	    *worstbound = *bestbound = lpd->objval;
374	    break;
375
376    case GRB_INFEASIBLE:		/* FailState */
377_grb_infeasible_:
378	    lpd->descr_state = DESCR_SOLVED_NOSOL;
379	    lpd->infeas_ctr++;
380	    lpd->objval = 0.0;
381	    *worstbound = (lpd->sense == SENSE_MIN ? -HUGE_VAL :  HUGE_VAL);
382	    *bestbound = (lpd->sense ==  SENSE_MIN ?  HUGE_VAL : -HUGE_VAL);
383	    break;
384
385    case GRB_CUTOFF:			/* FailState */
386	    lpd->descr_state = DESCR_SOLVED_NOSOL;
387	    lpd->infeas_ctr++;
388	    lpd->objval = 0.0;
389	    *worstbound = (lpd->sense == SENSE_MIN ? -HUGE_VAL :  HUGE_VAL);
390	    if (GRBgetdblparam(GRBgetenv(lpd->lp), GRB_DBL_PAR_CUTOFF, bestbound))
391		goto _return_err_;
392	    break;
393
394    case GRB_INF_OR_UNBD:		/* MaybeFailState */
395#ifdef TRY_RESOLVE_UNCERTAIN_RESULT
396	    /* try to check for infeasibility by reversing the sense */
397	    switch(rev_state)
398	    {
399	    case GRB_LOADED:
400		{
401		    int sense, res;
402		    GRBgetintattr(lpd->lp, GRB_INT_ATTR_MODELSENSE, &sense);
403		    GRBsetintattr(lpd->lp, GRB_INT_ATTR_MODELSENSE, -sense);
404		    res = GRBoptimize(lpd->lp);
405		    GRBsetintattr(lpd->lp, GRB_INT_ATTR_MODELSENSE, sense);
406		    GRBgetintattr(lpd->lp, GRB_INT_ATTR_STATUS, &rev_state);
407		    if (res == 0)
408			goto _retry_;
409		}
410		break;
411	    case GRB_INFEASIBLE:
412		goto _grb_infeasible_;
413	    case GRB_OPTIMAL:
414	    case GRB_SUBOPTIMAL:
415	    case GRB_CUTOFF:
416	    case GRB_UNBOUNDED:
417		goto _grb_unbounded_;
418	    }
419#endif
420
421	    /* can't get a more precise result */
422	    lpd->descr_state = DESCR_UNKNOWN_NOSOL;
423	    lpd->infeas_ctr++;
424	    lpd->objval = 0.0;
425	    *worstbound = (lpd->sense == SENSE_MIN ?  HUGE_VAL : -HUGE_VAL);
426	    *bestbound = (lpd->sense ==  SENSE_MIN ? -HUGE_VAL :  HUGE_VAL);
427	    break;
428
429    case GRB_UNBOUNDED:			/* UnboundedState */
430_grb_unbounded_:
431	    /* From Gurobi manual: an unbounded status indicates the presence
432	     * of an unbounded ray that allows the objective to improve
433	     * without limit. It says nothing about whether the model has a
434	     * feasible solution. If you require information on feasibility,
435	     * you should set the objective to zero and reoptimize.
436	     */
437	    lpd->descr_state = DESCR_UNBOUNDED_NOSOL;
438	    lpd->abort_ctr++;
439	    *bestbound = (lpd->sense == SENSE_MIN ? -HUGE_VAL : HUGE_VAL);
440	    /* try to obtain a better worstbound */
441	    if (GRBgetintattr(lpd->lp, GRB_INT_ATTR_SOLCOUNT, &sol_count))
442		goto _return_err_;
443	    if (sol_count > 0) {
444		if (GRBgetdblattr(lpd->lp, GRB_DBL_ATTR_OBJVAL, worstbound))
445		    goto _return_err_;
446		*worstbound = lpd->objval;
447	    } else {
448		lpd->objval = 0.0;
449		*worstbound = (lpd->sense == SENSE_MIN ?  HUGE_VAL : -HUGE_VAL);
450	    }
451	    break;
452
453    case GRB_ITERATION_LIMIT:
454    case GRB_NODE_LIMIT:
455    case GRB_TIME_LIMIT:
456    case GRB_SOLUTION_LIMIT:
457    case GRB_INTERRUPTED:
458    case GRB_NUMERIC:
459	    lpd->abort_ctr++;
460	    if (GRBgetintattr(lpd->lp, GRB_INT_ATTR_SOLCOUNT, &sol_count))
461		goto _return_err_;
462	    if (sol_count > 0) {
463		lpd->descr_state = DESCR_ABORTED_SOL;
464		if (GRBgetdblattr(lpd->lp, GRB_DBL_ATTR_OBJVAL, &lpd->objval))
465		    goto _return_err_;
466		*worstbound = lpd->objval;
467	    } else {
468		lpd->descr_state = DESCR_ABORTED_NOSOL;
469		/* KISH: what worstbound value? */
470		*worstbound = (lpd->sense == SENSE_MIN ? HUGE_VAL : -HUGE_VAL);
471		lpd->objval = 0.0;
472	    }
473	    if (GRBgetdblattr(lpd->lp, GRB_DBL_ATTR_OBJBOUND, bestbound))
474		goto _return_err_;
475	    break;
476
477    case GRB_SUBOPTIMAL:
478	    lpd->descr_state = DESCR_ABORTED_SOL;
479	    lpd->abort_ctr++;
480	    if (GRBgetdblattr(lpd->lp, GRB_DBL_ATTR_OBJVAL, &lpd->objval))
481		goto _return_err_;
482	    *worstbound = lpd->objval;
483	    if (GRBgetdblattr(lpd->lp, GRB_DBL_ATTR_OBJBOUND, bestbound))
484		goto _return_err_;
485	    break;
486
487    default:
488	    return -1;
489    }
490    return 0;
491_return_err_:
492    Report_Solver_Error(cpx_env);
493    return -1;
494}
495
496
497static int
498cpx_get_soln_state(lp_desc* lpd, struct lp_sol *sol)
499{
500    if (lpd->mac > 0)	/* columns/variables */
501    {
502	if (sol->sols && GRBgetdblattrarray(lpd->lp, GRB_DBL_ATTR_X, 0, lpd->mac, sol->sols))
503	    goto _return_err_;
504	if (sol->djs && GRBgetdblattrarray(lpd->lp, GRB_DBL_ATTR_RC, 0, lpd->mac, sol->djs))
505	    goto _return_err_;
506	if (sol->cbase && GRBgetintattrarray(lpd->lp, GRB_INT_ATTR_VBASIS, 0, lpd->mac, sol->cbase))
507	    goto _return_err_;
508    }
509    if (lpd->mar > 0)	/* rows/constraints */
510    {
511	if (sol->slacks && GRBgetdblattrarray(lpd->lp, GRB_DBL_ATTR_SLACK, 0, lpd->mar, sol->slacks))
512	    goto _return_err_;
513	if (sol->pis && GRBgetdblattrarray(lpd->lp, GRB_DBL_ATTR_PI, 0, lpd->mar, sol->pis))
514	    goto _return_err_;
515	if (sol->rbase && GRBgetintattrarray(lpd->lp, GRB_INT_ATTR_CBASIS, 0, lpd->mar, sol->rbase))
516	    goto _return_err_;
517   }
518   return 0;
519_return_err_:
520    Report_Solver_Error(cpx_env);
521    return -1;
522}
523
524
525/* Model callback function, currently only for messages */
526static int
527_grb_callback(GRBmodel *model, void *cbdata, int where, void *usrdata)
528{
529    switch(where)
530    {
531	case GRB_CB_MESSAGE:
532	{
533	    char *msg;
534	    if (solver_streams[LogType] == Current_Null)
535		return 0;
536	    if (GRBcbget(cbdata, where, GRB_CB_MSG_STRING, &msg))
537	    	return 0;
538	    (void) ec_outfs(solver_streams[LogType], msg);
539	    (void) ec_flush(solver_streams[LogType]);
540	    break;
541	}
542    }
543    return 0;
544}
545
546
547/* Extra initialisation for new models, if needed */
548static int
549cpx_newmodel(GRBmodel *lp)
550{
551    int grb_output;
552    /* install messaging callback */
553    if (GRBsetcallbackfunc(lp, _grb_callback, NULL))
554	return -1;
555    return 0;
556}
557
558
559static int
560cpx_loadprob(lp_desc *lpd)
561{
562    if (GRBloadmodel(cpx_env, &lpd->lp, "eclipse",
563    		lpd->mac, lpd->mar, lpd->sense,
564		0.0,		/*objcon*/
565		lpd->objx, lpd->senx, lpd->rhsx,
566		lpd->matbeg, lpd->matcnt, lpd->matind, lpd->matval,
567		lpd->bdl, lpd->bdu, lpd->ctype,
568		NULL,		/*varnames*/
569		NULL		/*cstrnames*/
570		))
571	goto _return_err_;
572
573    if (lpd->nsos && GRBaddsos(lpd->lp, lpd->nsos, lpd->nsosnz,
574		lpd->sostype, lpd->sosbeg, lpd->sosind, lpd->sosref))
575	goto _return_err_;
576
577    /* Switch presolve off if requested, otherwise leave cpx_env's defaults */
578    if (lpd->presolve == 0)
579	GRBsetintparam(GRBgetenv(lpd->lp), GRB_INT_PAR_PRESOLVE, GRB_PRESOLVE_OFF);
580
581    return cpx_newmodel(lpd->lp);
582_return_err_:
583    Report_Solver_Error(cpx_env);
584    return -1;
585}
586
587
588static int
589cpx_delsos(lp_desc *lpd, int from, int to)
590{
591    _grow_numbers_array(lpd, to);	/* if necessary */
592    return GRBdelsos(lpd->lp, to-from, &lpd->numbers[from]);
593}
594
595
596static int
597cpx_write(lp_desc *lpd, char *file, char *fmt)
598{
599    char buf[1000];
600    int suflen;
601    int flen = strlen(file);
602    suflen = strlen(fmt);
603    /* append the correct suffix, unless already there */
604    if (!(flen>suflen && file[flen-suflen-1] == '.' && !strcmp(file+flen-suflen,fmt)))
605	file = strcat(strcat(strcpy(buf,file),"."),fmt);
606    CPXupdatemodel(lpd->lp);
607    if (GRBwrite(lpd->lp, file))
608	goto _return_err_;
609    return 0;
610_return_err_:
611    Report_Solver_Error(cpx_env);
612    return -1;
613}
614
615
616static int
617cpx_read(lp_desc *lpd, char *file, char *fmt)
618{
619    int sen, pre, mip, qp;
620    char buf[1000];
621    char *suf;
622
623    /* append correct suffix, if not already there */
624    suf = strrchr(file, '.');
625    if (!suf || strcmp(suf+1, fmt))
626	file = strcat(strcat(strcpy(buf,file),"."),fmt);
627
628    if (GRBreadmodel(cpx_env, file, &lpd->lp))
629	goto _return_err_;
630
631    /* initialize non-zero fields in lp_desc */
632    CallN(lpd->lpcopy = lpd->lp);  /* no need for a copy */
633    GRBgetintattr(lpd->lp, GRB_INT_ATTR_MODELSENSE, &sen);
634    lpd->sense = sen == GRB_MINIMIZE ? SENSE_MIN : SENSE_MAX;
635    GRBgetintattr(lpd->lp, GRB_INT_ATTR_NUMVARS, &lpd->mac);
636    GRBgetintattr(lpd->lp, GRB_INT_ATTR_NUMCONSTRS, &lpd->mar);
637    GRBgetintattr(lpd->lp, GRB_INT_ATTR_IS_MIP, &mip);
638    GRBgetintattr(lpd->lp, GRB_INT_ATTR_IS_QP, &qp);
639    lpd->prob_type = mip ? ( qp ? PROBLEM_MIQP : PROBLEM_MIP )
640			 : ( qp ? PROBLEM_QP   : PROBLEM_LP );
641
642    return cpx_newmodel(lpd->lp);
643_return_err_:
644    Report_Solver_Error(cpx_env);
645    return -1;
646}
647
648
649/*
650 * Parameter Table
651 *
652 * Extract #define GRB_xxx_PAR_ lines from gurobi_c.h and substitute as follows:
653 * s/^#define[	 ]GRB_INT_PAR_\([^ ]*\).*$/{"\L\1\E", GRB_INT_PAR_\1, 0},/
654 * s/^#define[	 ]GRB_DBL_PAR_\([^ ]*\).*$/{"\L\1\E", GRB_DBL_PAR_\1, 1},/
655 * s/^#define[	 ]GRB_STR_PAR_\([^ ]*\).*$/{"\L\1\E", GRB_STR_PAR_\1, 2},/
656 */
657
658#define NUMPARAMS 83
659#define NUMALIASES 10
660static struct param_desc params[NUMPARAMS+NUMALIASES] = {
661{"bariterlimit", GRB_INT_PAR_BARITERLIMIT, 0},
662{"cutoff", GRB_DBL_PAR_CUTOFF, 1},
663{"iterationlimit", GRB_DBL_PAR_ITERATIONLIMIT, 1},
664{"nodelimit", GRB_DBL_PAR_NODELIMIT, 1},
665{"solutionlimit", GRB_INT_PAR_SOLUTIONLIMIT, 0},
666{"timelimit", GRB_DBL_PAR_TIMELIMIT, 1},
667{"feasibilitytol", GRB_DBL_PAR_FEASIBILITYTOL, 1},
668{"intfeastol", GRB_DBL_PAR_INTFEASTOL, 1},
669{"markowitztol", GRB_DBL_PAR_MARKOWITZTOL, 1},
670{"mipgap", GRB_DBL_PAR_MIPGAP, 1},
671{"mipgapabs", GRB_DBL_PAR_MIPGAPABS, 1},
672{"optimalitytol", GRB_DBL_PAR_OPTIMALITYTOL, 1},
673{"psdtol", GRB_DBL_PAR_PSDTOL, 1},
674{"method", GRB_INT_PAR_METHOD, 0},
675{"perturbvalue", GRB_DBL_PAR_PERTURBVALUE, 1},
676{"objscale", GRB_DBL_PAR_OBJSCALE, 1},
677{"scaleflag", GRB_INT_PAR_SCALEFLAG, 0},
678{"simplexpricing", GRB_INT_PAR_SIMPLEXPRICING, 0},
679{"quad", GRB_INT_PAR_QUAD, 0},
680{"normadjust", GRB_INT_PAR_NORMADJUST, 0},
681{"sifting", GRB_INT_PAR_SIFTING, 0},
682{"siftmethod", GRB_INT_PAR_SIFTMETHOD, 0},
683{"barconvtol", GRB_DBL_PAR_BARCONVTOL, 1},
684{"barcorrectors", GRB_INT_PAR_BARCORRECTORS, 0},
685{"barhomogeneous", GRB_INT_PAR_BARHOMOGENEOUS, 0},
686{"barorder", GRB_INT_PAR_BARORDER, 0},
687{"barqcpconvtol", GRB_DBL_PAR_BARQCPCONVTOL, 1},
688{"crossover", GRB_INT_PAR_CROSSOVER, 0},
689{"crossoverbasis", GRB_INT_PAR_CROSSOVERBASIS, 0},
690{"branchdir", GRB_INT_PAR_BRANCHDIR, 0},
691{"heuristics", GRB_DBL_PAR_HEURISTICS, 1},
692{"improvestartgap", GRB_DBL_PAR_IMPROVESTARTGAP, 1},
693{"improvestarttime", GRB_DBL_PAR_IMPROVESTARTTIME, 1},
694{"minrelnodes", GRB_INT_PAR_MINRELNODES, 0},
695{"mipfocus", GRB_INT_PAR_MIPFOCUS, 0},
696{"nodefiledir", GRB_STR_PAR_NODEFILEDIR, 2},
697{"nodefilestart", GRB_DBL_PAR_NODEFILESTART, 1},
698{"nodemethod", GRB_INT_PAR_NODEMETHOD, 0},
699{"pumppasses", GRB_INT_PAR_PUMPPASSES, 0},
700{"rins", GRB_INT_PAR_RINS, 0},
701{"submipnodes", GRB_INT_PAR_SUBMIPNODES, 0},
702{"symmetry", GRB_INT_PAR_SYMMETRY, 0},
703{"varbranch", GRB_INT_PAR_VARBRANCH, 0},
704{"solutionnumber", GRB_INT_PAR_SOLUTIONNUMBER, 0},
705{"zeroobjnodes", GRB_INT_PAR_ZEROOBJNODES, 0},
706{"cuts", GRB_INT_PAR_CUTS, 0},
707{"cliquecuts", GRB_INT_PAR_CLIQUECUTS, 0},
708{"covercuts", GRB_INT_PAR_COVERCUTS, 0},
709{"flowcovercuts", GRB_INT_PAR_FLOWCOVERCUTS, 0},
710{"flowpathcuts", GRB_INT_PAR_FLOWPATHCUTS, 0},
711{"gubcovercuts", GRB_INT_PAR_GUBCOVERCUTS, 0},
712{"impliedcuts", GRB_INT_PAR_IMPLIEDCUTS, 0},
713{"mipsepcuts", GRB_INT_PAR_MIPSEPCUTS, 0},
714{"mircuts", GRB_INT_PAR_MIRCUTS, 0},
715{"modkcuts", GRB_INT_PAR_MODKCUTS, 0},
716{"zerohalfcuts", GRB_INT_PAR_ZEROHALFCUTS, 0},
717{"networkcuts", GRB_INT_PAR_NETWORKCUTS, 0},
718{"submipcuts", GRB_INT_PAR_SUBMIPCUTS, 0},
719{"cutaggpasses", GRB_INT_PAR_CUTAGGPASSES, 0},
720{"cutpasses", GRB_INT_PAR_CUTPASSES, 0},
721{"gomorypasses", GRB_INT_PAR_GOMORYPASSES, 0},
722{"aggregate", GRB_INT_PAR_AGGREGATE, 0},
723{"aggfill", GRB_INT_PAR_AGGFILL, 0},
724{"displayinterval", GRB_INT_PAR_DISPLAYINTERVAL, 0},
725{"dualreductions", GRB_INT_PAR_DUALREDUCTIONS, 0},
726{"iismethod", GRB_INT_PAR_IISMETHOD, 0},
727{"infunbdinfo", GRB_INT_PAR_INFUNBDINFO, 0},
728{"logfile", GRB_STR_PAR_LOGFILE, 2},
729{"logtoconsole", GRB_INT_PAR_LOGTOCONSOLE, 0},
730{"miqcpmethod", GRB_INT_PAR_MIQCPMETHOD, 0},
731{"outputflag", GRB_INT_PAR_OUTPUTFLAG, 0},
732{"precrush", GRB_INT_PAR_PRECRUSH, 0},
733{"predeprow", GRB_INT_PAR_PREDEPROW, 0},
734{"predual", GRB_INT_PAR_PREDUAL, 0},
735{"prepasses", GRB_INT_PAR_PREPASSES, 0},
736{"preqlinearize", GRB_INT_PAR_PREQLINEARIZE, 0},
737{"presolve", GRB_INT_PAR_PRESOLVE, 0},
738{"presparsify", GRB_INT_PAR_PRESPARSIFY, 0},
739{"qcpdual", GRB_INT_PAR_QCPDUAL, 0},
740{"resultfile", GRB_STR_PAR_RESULTFILE, 2},
741{"threads", GRB_INT_PAR_THREADS, 0},
742{"feasrelaxbigm", GRB_DBL_PAR_FEASRELAXBIGM, 1},
743{"dummy", GRB_STR_PAR_DUMMY, 2},
744
745/* NUMALIASES lines follow */
746{"time_limit", GRB_DBL_PAR_TIMELIMIT, 1},
747{"perturbation_const", GRB_DBL_PAR_PERTURBVALUE, 1},
748{"feasibility_tol", GRB_DBL_PAR_FEASIBILITYTOL, 1},
749{"markowitz_tol", GRB_DBL_PAR_MARKOWITZTOL, 1},
750{"absmipgap", GRB_DBL_PAR_MIPGAPABS, 1},
751{"optimality_tol", GRB_DBL_PAR_OPTIMALITYTOL, 1},
752{"integrality", GRB_DBL_PAR_INTFEASTOL, 1},
753{"iteration_limit", GRB_DBL_PAR_ITERATIONLIMIT, 1},
754{"solution_limit", GRB_INT_PAR_SOLUTIONLIMIT, 0},
755{"node_limit", GRB_DBL_PAR_NODELIMIT, 1},
756
757};
758
759#endif
760