/**************************************************************** Copyright (C) 1997-2001 Lucent Technologies All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that the copyright notice and this permission notice and warranty disclaimer appear in supporting documentation, and that the name of Lucent or any of its entities not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ /* Variant that duplicates columns for ranges when presenting the dual problem to CPLEX. (I thought this wasn't necessary, but CPLEX seems to botch the solve without it.) */ /* Compile with -DNO_CPLEX_MIP to disable MIP keywords. */ /* Compile with -DNO_BARRIER to disable barrier keywords. */ #ifndef NO_CPLEX_MIP #undef CPLEX_MIP #define CPLEX_MIP #endif #ifndef NO_BARRIER #undef BARRIER #define BARRIER #endif #include "limits.h" #define OBJ_ADJ #include "cplex.h" #define STDIO_H_included #include "nlp.h" #include "getstub.h" #include "avltree.h" #include "signal.h" /* {Modifications for CPLEX 7.1 */ #ifndef CPX_PARAM_WORKDIR #define CPX_PARAM_WORKDIR CPX_PARAM_NODEFILEDIR #endif #ifndef CPX_PARAM_PDSWITCH #define CPX_PARAM_PDSWITCH 1063 #endif /* End Modifications for CPLEX 7.1} */ /* {Modifications for CPLEX 8 */ #undef Const #undef BARRIER_FOR_QP #ifdef CPXERR_Q_NEG_ZERO_COMP /* CPLEX 7.1 */ #define CPX_STAT_INFEASIBLE CPX_INFEASIBLE #define CPX_STAT_UNBOUNDED CPX_UNBOUNDED #define CPXCENVptr CPXENVptr #define Const /*nothing*/ #define BARRIER_FOR_QP #else #define Const const #endif /* End Modifications for CPLEX 8} */ /* {Hidden params of CPLEX 6.5.1 */ #ifndef CPX_PARAM_OLDPRICING #define CPX_PARAM_OLDPRICING 1054 #endif #ifndef CPX_PARAM_EPSAGG #define CPX_PARAM_EPSAGG 1055 #endif /* End hidden params} */ #ifndef Sig_ret_type #define Sig_ret_type void #define SigRet /*nothing*/ #endif #ifndef SigRet #define SigRet /*nothing*/ #endif #ifndef Sig_func_type typedef void sig_func_type ANSI((int)); #endif #ifdef _WIN32 /* Win32 is too hard. */ #undef KEEP_BANNER #define KEEP_BANNER #else #ifndef KEEP_BANNER #include "fcntl.h" #include "unistd.h" #endif #endif static ASL *asl; typedef struct cpxlp cpxlp; typedef struct mint_values { int L; int U; int val; } mint_values; typedef struct mdbl_values { double L; double U; double val; } mdbl_values; enum { /* sf_mint f values */ set_crossover = 0, set_dualthresh = 1, set_netopt = 2, set_objno = 3, set_conpri = 4, set_objpri = 5, set_prestats = 6, set_sos2 = 7, set_timing = 8, set_iis = 9, set_mipststat = 10, set_mipstval = 11, set_namernd = 12, set_sos = 13, set_mipcuts = 14, set_round = 15, set_rays = 16, set_mipbasis = 17, set_basis_cond = 18, set_retmipgap = 19, set_feasopt = 20, set_feasoptobj = 21, set_lazy = 22, set_populate = 23 }; #ifdef CPX_PARAM_FEASOPTMODE /* >= 9.2b */ #define Uselazy #endif enum { /* sf_mdbl f values */ set_dual_ratio = 0 }; static mint_values mint_val[24] = { /* set_crossover */ 0, 2, 1, /* set_dualthresh */ -0x7fffffff, 0x7fffffff, 0, /* set_netopt */ 0, 2, 1, /* set_objno */ 0, 0/*n_obj*/, 1, /* set_conpri */ 0, 0x7fffffff, 1, /* set_objpri */ 0, 0x7fffffff, 2, /* set_prestats */ 0, 1, 0, /* set_sos2 */ 0, 1, 1, /* set_timing */ 0, 3, 0, /* set_iis */ 0, 3, 0, /* set_mipststat */ 0, 1, 1, /* set_mipstval */ 0, 1, 1, /* set_namernd */ 0, 1, 0, /* set_sos */ 0, 1, 1, /* set_mipcuts */ -1, 2, 0, /* set_round */ 0, 15, 1, /* set_rays */ 0, 3, 3, /* set_mipbasis */ 0, 1, 1, /* set_basis_cond */ 0, 1, 0, /* set_retmipgap */ 0, 7, 0, /* set_feasopt */ 0, 2, 0, /* set_feasoptobj */ 1, 3, 1, /* set_lazy */ 0, 3, 3, /* set_populate */ 0, 2, 0 }; static mdbl_values mdbl_val[] = { /* set_dual_ratio */ 1., 1e30, 3. }; #define crossover mint_val[0].val #define dual_thresh mint_val[1].val #define use_netopt mint_val[2].val #define objno mint_val[3].val #define conpri mint_val[4].val #define objpri mint_val[5].val #define prestats mint_val[6].val #define sos2 mint_val[7].val #define time_flag mint_val[8].val #define want_iis mint_val[9].val #define mipststat mint_val[10].val #define mipstval mint_val[11].val #define Nameround mint_val[12].val #define sos mint_val[13].val /* #define mipcuts mint_val[14].val */ /* only set_mipcuts is used */ #define Round mint_val[15].val #define rays mint_val[16].val #define mipbasis mint_val[17].val #define basis_cond mint_val[18].val #define retmipgap mint_val[19].val #define want_feasopt mint_val[20].val #define feasoptobj mint_val[21].val #define uselazy mint_val[22].val #define populate mint_val[23].val #define dual_ratio mdbl_val[0].val static int hybmethod = CPX_ALG_PRIMAL; static int netiters = -1; static CPXFILEptr Logf; static char cplex_version[] = "AMPL/CPLEX with bad license\0\nAMPL/CPLEX Driver Version 20080109\n"; static char *baralgname, *endbas, *endtree, *endvec, *logfname; static char *paramfile, *poolstub, *pretunefile, *pretunefileprm; static char *startbas, *starttree, *startvec, *tunefile, *tunefileprm; static char *tunefix, *tunefixfile, *workfiledir, *wrtfname; static int bestnode, breaking, costsens, dispzap, lpoptalg, mbas, method; static int nbas, netopting, objadj, objsen, relax, zap_lpcbf; static int aggtries, net_status, net_nodes, net_arcs; static double obj_adj; static char *algname = ""; static real intwarn_tol = 1e-9; typedef struct Cbfinfo { int agg, disp, m, mipdisp, n, n0[4], nx[2], nint, npr, pres; char *xkind; } Cbfinfo; static Cbfinfo cbi; /* Stuff to cope with current CPLEX political correctness... */ static CPXENVptr Env; #define disconnectchannel(a) CPXdisconnectchannel(Env,a) #define addfuncdest(a,b,c) CPXaddfuncdest(Env,a,b,c) typedef struct dims { double *c; double *x; double *y; int *cstat; int *rstat; SufDesc *csd; SufDesc *rsd; char *rtype; /* Stuff for netopt... */ int *cs; int *rs; /* for solution pools */ int npool; } dims; static char * strcpy1(char *t, const char *s) { while(*t = *s++) t++; return t; } static void badretfmt(int rc, char *fmt, ...) { va_list ap; char buf[4200], *s; int k; va_start(ap, fmt); k = vsprintf(buf, fmt, ap) + 1; if (rc) { solve_result_num = rc; memcpy(s = (char*)M1alloc(k), buf, k); asl->i.uinfo = s; } if (!rc) fprintf(Stderr, "%s\n", buf); } static void badret(char *what, int i, int rc) { badretfmt(rc, "%s failed; error code %d.", what, i); if (rc) exit(1); } #ifdef CPX_CON_INDICATOR /* >= 9.2b */ #define ALLOW_CLP ASL_allow_CLP #include "opcode.hd" static int Neg[6] = {2,3,0,1,5,4}; typedef struct LCADJ_Info { ASL *asl; int *z[2]; double LU[4], rhs, *x[2]; ograd *freeog, *ograd_block, **s; int b[2], nx[2]; int nlv[6]; int zerodiv; int ograd_ntogo; int vk, vnb; Char **M1state1, **M1state2; } LCADJ_Info; #ifndef LCADJ_GULP #define LCADJ_GULP 128 #endif enum { Gulp = LCADJ_GULP }; static int bincheck(ASL *asl, LCADJ_Info *lci, expr *e) { expr_n *en; expr_v *v; int j, k; switch(Intcast e->op) { case GT: k = 1; break; case GE: k = 2; break; case LE: k = 3; break; case LT: k = 4; break; case EQ: k = 5; break; case NE: k = 6; break; default: return 0; } v = (expr_v*)e->L.e; switch (Intcast v->op) { case OPVARVAL: en = (expr_n*) e->R.e; if ((Intcast en->op) == OPNUM) { hit: if ((j = v->a) < lci->nlv[0] || j >= lci->nlv[1] && j < lci->nlv[2] || j >= lci->nlv[3] && j < lci->nlv[4] || j >= lci->nlv[5]) return 0; lci->vk = j; lci->rhs = en->v; return k; } break; case OPNUM: en = (expr_n*)v; v = (expr_v*)e->R.e; if (k < 5) k = 5 - k; if ((Intcast v->op) == OPVARVAL) goto hit; } return 0; } static ograd * new_og(LCADJ_Info *lci, int varno, real coef) { ASL *asl; ograd *og; if (og = lci->freeog) lci->freeog = og->next; else { if (!lci->ograd_ntogo) { asl = lci->asl; lci->ograd_block = (ograd*)M1alloc(Gulp*sizeof(ograd)); lci->ograd_ntogo = Gulp; } og = lci->ograd_block + --lci->ograd_ntogo; } og->next = 0; og->varno = varno; og->coef = coef; return og; } static void free_og(LCADJ_Info *lci, ograd *og1, ograd *og1e) { og1e->next = lci->freeog; lci->freeog = og1; } static ograd * linform(LCADJ_Info *lci, expr *e, ograd **oglp) { ASL_fg *asl; cexp *ce; cexp1 *ce1; expr **ep, **epe; expr_n *en; int i; linpart *L, *Le; ograd *og, *og1, *og1e, *og2, *og2e, *og2x, **ogp; real t; switch(Intcast e->op) { case OPNUM: return *oglp = new_og(lci, -1, ((expr_n *)e)->v); case OPPLUS: if (!(og1 = linform(lci, e->L.e, &og1e))) return og1; if (!(og2 = linform(lci, e->R.e, &og2e))) { free_og(lci, og1, og1e); return og2; } finish_plus: if (og1->varno > og2->varno) { og = og1; og1 = og2; og2 = og; og = og1e; og1e = og2e; og2e = og; } else for(og = og1; og; og = og->next) { if (!og2) { og2e = og1e; break; } if (og2->varno != og->varno) break; og->coef += og2->coef; og2x = og2->next; og2->next = lci->freeog; lci->freeog = og2; og2 = og2x; } og1e->next = og2; *oglp = og2e; return og1; case OPMINUS: if (!(og1 = linform(lci, e->L.e, &og1e))) return og1; if (!(og2 = linform(lci, e->R.e, &og2e))) { free_og(lci, og1, og1e); return og2; } for(og = og2; og; og = og->next) og->coef = -og->coef; goto finish_plus; case OPUMINUS: if (og1 = linform(lci, e->L.e, oglp)) { do og1->coef = -og1->coef; while(og1 = og1->next); } return og1; case OPMULT: if (!(og1 = linform(lci, e->L.e, &og1e))) return og1; if (!(og2 = linform(lci, e->R.e, &og2e))) { free_og(lci, og1, og1e); return og2; } if (og1->varno < 0 && !og1->next) { t = og1->coef; free_og(lci, og1, og1e); } else if (og2->varno < 0 && !og2->next) { t = og2->coef; free_og(lci, og2, og2e); og2 = og1; og2e = og1e; } else { free_og(lci, og1, og1e); free_og(lci, og2, og2e); return 0; } for(og = og2; og; og = og->next) og->coef *= t; *oglp = og2e; return og2; case OPDIV: /* only allow division by a constant */ if (!(og1 = linform(lci, e->L.e, &og1e))) return og1; if (!(og2 = linform(lci, e->L.e, &og2e))) { free_og(lci, og1, og1e); return og2; } if (og2->varno < 0 && !og2->next) { t = og2->coef; free_og(lci, og2, og2e); } else { free_og(lci, og1, og1e); free_og(lci, og2, og2e); return 0; } for(og = og1; og; og = og->next) og->coef /= t; *oglp = og1e; return og1; case OPSUMLIST: ep = e->L.ep; epe = e->R.ep; if (!(og1 = linform(lci, *ep, &og1e))) return og1; while(++ep < epe) { if (!(og2 = linform(lci, *ep, &og2e))) { free_og(lci, og1, og1e); return og2; } if (og1->varno > og2->varno) { og = og1; og1 = og2; og2 = og; og = og1e; og1e = og2e; og2e = og; } else for(og = og1; og; og = og->next) { if (!og2) { og2e = og1e; break; } if (og2->varno != og->varno) break; og->coef += og2->coef; og2x = og2->next; og2->next = lci->freeog; lci->freeog = og2; og2 = og2x; } og1e->next = og2; og1e = og2e; } *oglp = og1e; return og1; case OPVARVAL: asl = (ASL_fg*)lci->asl; if ((i = (expr_v *)e - var_e) < n_var) return *oglp = new_og(lci, i, 1.); if ((i -= n_var) < ncom0) { ce = cexps + i; en = (expr_n*)ce->e; L = ce->L; Le = L + ce->nlin; } else { ce1 = cexps1 + (i - ncom0); en = (expr_n*)ce1->e; L = ce1->L; Le = L + ce1->nlin; } if ((Intcast en->op) != OPNUM) return 0; ogp = &og2; if (en->v != 0.) { og2 = new_og(lci, -1, en->v); ogp = &og2->next; } for(; L < Le; L++) { i = (expr_v*)((char*)L->v.rp - (char*)voffset_of(expr_v,v)) - var_e; og = *ogp = new_og(lci, i, L->fac); ogp = &og->next; } *ogp = 0; *oglp = og; return og2; } return 0; } static int intcomp(const void *a, const void *b, void *v) { return *(int*)a - *(int*)b; } static int lincheck(LCADJ_Info *lci, expr *e, double *LU, int *nx, double *x, int *z) { expr *e1, *e2; int i, j, k, m; ograd *freeog, *og, *og1, *og1e, *og2, **s; real rhs; switch(Intcast e->op) { case GE: k = 2; break; case LE: k = 3; break; case EQ: k = 5; break; default: return 1; } e1 = e->L.e; e2 = e->R.e; if ((Intcast e1->op) == OPNUM) { rhs = ((expr_n*)e1)->v; e1 = e2; if (k != 5) k = 5 - k; } else if ((Intcast e2->op) != OPNUM) return 1; else rhs = ((expr_n*)e2)->v; if (!(og1 = linform(lci,e1,&og1e))) return 1; s = lci->s; m = 0; freeog = lci->freeog; while(og = og1) { og1 = og->next; if ((i = og->varno) < 0) rhs -= og->coef; else if (!(og2 = s[i])) { s[i] = og; z[m++] = i; continue; } else og2->coef += og->coef; og->next = freeog; freeog = og; } *nx = m; if (m > 1) qsortv(z, m, sizeof(int), intcomp, 0); for(i = 0; i < m; i++) { j = z[i]; og = s[j]; s[j] = 0; x[i] = og->coef; og->next = freeog; freeog = og; } lci->freeog = freeog; LU[0] = LU[1] = rhs; switch(k) { case 2: LU[1] = Infinity; break; case 3: LU[0] = negInfinity; } return 0; } int lcadj(ASL *asl, LCADJ_Info **lcip, expr *e) { Char **Mbnext, **Mblast; LCADJ_Info *lci; double rhs, *x; expr *e1, *e2, *e3; expr_if *eif; int b1, b2, i, k, n, vk, *z; ograd **s; if (!(lci = *lcip)) { Mbnext = asl->i.Mbnext; Mblast = asl->i.Mblast; n = n_var; x = (double*)M1alloc(sizeof(LCADJ_Info) + Gulp*sizeof(ograd) + n*(2*(sizeof(double)+sizeof(int)) + sizeof(ograd*))); s = (ograd**)(x + 2*n); z = (int*)(s + n); *lcip = lci = (LCADJ_Info*)(z + 2*n); lci->x[0] = x; lci->x[1] = x + n; lci->s = s; lci->z[0] = z; lci->z[1] = z + n; lci->asl = asl; lci->freeog = 0; lci->ograd_block = (ograd*)(lci+1); lci->ograd_ntogo = Gulp; lci->zerodiv = 0; lci->M1state1 = Mbnext; lci->M1state2 = Mblast; memset(s, 0, n*sizeof(ograd*)); lci->nlv[1] = i = nlvb; lci->nlv[0] = i - nlvbi; lci->nlv[3] = i += nlvc; lci->nlv[2] = i - nlvci; lci->nlv[5] = i += nlvo; lci->nlv[4] = i - nlvoi; } switch(Intcast e->op) { case OPOR: e1 = e->L.e; e2 = e->R.e; if (b1 = bincheck(asl,lci,e1)) { vk = lci->vk; rhs = lci->rhs; } if (b2 = bincheck(asl,lci,e2)) { if (b1 && !lincheck(lci, e2, lci->LU, &lci->nx[0], lci->x[0], lci->z[0])) { lci->b[0] = Neg[b1 - 1]; lci->vk = vk; lci->rhs = rhs; return 1; } b1 = b2; e1 = e2; e2 = e->L.e; } else if (!b1) return 0; k = 1; break; case OPIMPELSE: eif = (expr_if*)e; e1 = eif->e; if (!(b1 = bincheck(asl,lci,eif->e))) return 0; k = 2; e2 = eif->F; e3 = eif->T; break; default: return 0; } b1 = Neg[b1 - 1]; for(i = 0; i < k; i++, e2 = e3) { /* must split e2 into const op elin, pass elin to xqpcheck */ if (lincheck(lci, e2, lci->LU + 2*i, &lci->nx[i], lci->x[i], lci->z[i])) return 0; lci->b[i] = b1; b1 = Neg[b1]; } return k; } static void add_indicator(ASL *asl, cpxlp *cpx, int ci, LCADJ_Info **lcip, expr *e) { LCADJ_Info *lci; double *LU, rhs; int compl, i, j, k, sense, vk; k = lcadj(asl, lcip, e); if (!k) { badretfmt(563, "logical constraint %s is not an indicator constraint.\n", lcon_name(ci)); exit(4); } lci = *lcip; vk = lci->vk; rhs = lci->rhs; compl = 0; switch(lci->b[0]) { case 0: /* > */ if (rhs < 0. || rhs >= 1.) { bad_cmpop: badretfmt(563, "logical constraint %s is not an indicator constraint\n\ due to bad comparison with %s.\n", lcon_name(ci), var_name(vk)); exit(4); } break; case 1: /* >= */ if (rhs <= 0. || rhs > 1.) goto bad_cmpop; break; case 2: /* <= */ if (rhs < 0. || rhs >= 1.) goto bad_cmpop; compl = 1; break; case 3: /* < */ if (rhs <= 0. || rhs > 1.) goto bad_cmpop; compl = 1; break; case 4: /* == */ if (rhs == 1.) break; if (rhs == 0.) { compl = 1; break; } goto bad_cmpop; case 5: /* != */ if (rhs == 0.) break; if (rhs == 1.) { compl = 1; break; } goto bad_cmpop; } LU = lci->LU; for(j = 0; j < k; j++, compl = 1 - compl, LU += 2) { if (LU[0] > negInfinity) { rhs = LU[0]; sense = LU[1] == rhs ? 'E': 'G'; } else { rhs = LU[1]; sense = 'L'; } if (i = CPXaddindconstr(Env, cpx, vk, compl, lci->nx[j], rhs, sense, lci->z[j], lci->x[j], 0)) badret("CPXaddindconstr", i, 531); } } #else /*CPX_CON_INDICATOR*/ #define ALLOW_CLP 0 #endif /*CPX_CON_INDICATOR*/ #ifdef DEBUG static void Basedebug(char *name, int *cs, int *rs) /*!!!!*/ { FILE *f; int i; if (!(f = fopen(name,"w"))) { fprintf(Stderr, "Basedebug: cannot open \"%s\".\n", name); return; } for(i = 0; i < nbas; i++) fprintf(f, "cs[%d] = %d\n", i, cs[i]); for(i = 0; i < mbas; i++) fprintf(f, "rs[%d] = %d\n", i, rs[i]); fclose(f); } #else #define Basedebug(a,b,c) #endif static void bascopy(CPXLPptr cpx, dims *d, int n, int m, int *cmap, int *ncs, int *nrs, int *rmap) { int *cs, i, j, *rs; if (cs = d->cs) rs = d->rs; else { cs = (int*)Malloc((mbas+nbas)*sizeof(int)); rs = cs + nbas; for (i = 0, j = nbas + mbas; i < j; i++) cs[i] = CPX_AT_LOWER;; } for(i = 0; i < n; i++) if ((j = cmap[i]) >= 0) cs[j] = ncs[i]; for(i = 0; i < m; i++) if ((j = rmap[i]) >= 0) rs[j] = nrs[i]; Basedebug("net.bas",cs,rs); CPXcopybase(Env, cpx, cs, rs); if (!d->cs) free(cs); } static int netopt(CPXLPptr cpx, dims *d, int *st, int *nodes, int *arcs, int *its) { CPXNETptr net; int i, j, k, m, n; int *cmap, *ncs, *nrs, *rmap, *s; k = 0; if (!(net = CPXNETcreateprob(Env,&k,"embedded")) || k) return 1; m = mbas + 1; n = mbas + nbas; cmap = (int*)Malloc(2*(m+n)*sizeof(int)); rmap = cmap + n; ncs = rmap + m; nrs = ncs + n; if (CPXNETextract(Env, net, cpx, cmap, rmap) || (*nodes = CPXNETgetnumnodes(Env,net)) <= 0) { free(cmap); return 1; } *arcs = CPXNETgetnumarcs(Env,net); CPXgetintparam(Env, CPX_PARAM_SIMDISPLAY, &k); if (!k) { netopting = 1; /* suppress netopt termination msg */ CPXsetintparam(Env, CPX_PARAM_SIMDISPLAY, 1); } if (s = d->cs) { n = *arcs; for(i = 0; i < n; i++) ncs[i] = (j = cmap[i]) >= 0 ? s[j] : CPX_BASIC; n = *nodes; s = d->rs; for(i = 0; i < n; i++) nrs[i] = (j = rmap[i]) >= 0 ? s[j] : CPX_BASIC; if (i = CPXNETcopybase(Env, net, ncs, nrs)) fprintf(Stderr, "Return %d from CPXNETcopybase.\n", i); } if (i = CPXNETprimopt(Env, net)) { fprintf(Stderr, "Return %d from CPXNETprimopt\n", i); *st = 11; #ifdef Student_Edition #ifndef CPXERR_RESTRICTED_VERSION #define CPXERR_RESTRICTED_VERSION CPXERR_PROMOTION_VERSION #endif if (i == CPXERR_RESTRICTED_VERSION) *st = 12; #endif } else { i = CPXNETgetstat(Env, net); if (i >= 1 && i <= 8) { *st = i; if (i == 4) goto bug; } else if (i >= 12 && i <= 13) *st = i - 3; else if (i == 19) *st = 4; else { bug: fprintf(Stderr, "Return %d from CPXNETgetstat\n", i); *st = 11; } *its = CPXNETgetitcnt(Env,net); #ifdef DEBUG CPXNETbasewrite(Env,net,"net.bw"); #endif if (!CPXNETgetbase(Env, net, ncs, nrs)) { bascopy(cpx, d, *arcs, *nodes, cmap, ncs, nrs, rmap); #ifdef DEBUG CPXmbasewrite(Env, cpx, "m.bw"); #endif } } netopting = 0; if (!k) CPXsetintparam(Env, CPX_PARAM_SIMDISPLAY, 0); free(cmap); CPXNETfreeprob(Env, &net); return 0; } typedef int (CPXPUBLIC *Optalg)(CPXCENVptr, cpxlp*); static Optalg Optimize; static jmp_buf Jb; #ifdef CPXERR_IN_INFOCALLBACK /* CPLEX 11 */ static int breaknow; #endif Sig_ret_type intcatch(int n) { printf("\n (cplex)\n", n); fflush(stdout); #ifdef CPXERR_IN_INFOCALLBACK breaknow = 1; #endif if (++breaking > 3) longjmp(Jb, 2); signal(SIGINT, intcatch); SigRet; } static int CPXPUBLIC breakcallback(CPXCENVptr e, void *c, int w, void *h) { Not_Used(e); Not_Used(c); Not_Used(w); Not_Used(h); return breaking > 1; } #ifdef BARRIER static int CPXPUBLIC Optimize2(CPXCENVptr e, cpxlp *c) { return CPXhybbaropt(e, c, hybmethod); } static int CPXPUBLIC Optimizebar(CPXCENVptr e, cpxlp *c) { int rv, s; if (!(rv = CPXbaropt(e, c)) && endvec && (s = CPXvecwrite(e, c, endvec))) printf("\n*** return %d from CPXvecwrite.\n", s); return rv; } static void set_baropt(VOID) { baralgname = ""; if (crossover) { Optimize = Optimize2; if (crossover == 1) { algname = "crossover primal "; hybmethod = CPX_ALG_PRIMAL; } else { algname = "crossover dual "; hybmethod = CPX_ALG_DUAL; } } else { Optimize = Optimizebar; algname = ""; } } static int startcomp(ASL *asl, int n0, int m, int nextra, int *ka, int *kal, int *ia, double *a, double *b, double *c, double **cdualp, double **cprimp, double **rdualp, double **rprimp) { double *r, t, *x, *y; int i, j, k; int n = n0 - objadj; /* Why can't CPXcopystart do this calculation? */ if (!X0 && !pi0) return 0; if (method > 0) { x = X0; y = pi0; } else { x = pi0; y = X0; } if (x) { if (method < 0 && (i = nextra + nranges) > 0) { r = (double *)M1alloc(n0*sizeof(double)); memcpy(r, x, (j = n - i)*sizeof(double)); memset(r+j, 0, i*sizeof(double)); /* Can we do better? */ x = r; if (objadj) x[n] = obj_adj; } else if (objadj) { r = (double *)M1alloc(n0*sizeof(double)); memcpy(r, x, n*sizeof(double)); x = r; x[n] = obj_adj; } *cprimp = x; *rprimp = r = (double *)M1alloc(m*sizeof(double)); memcpy(r, b, m*sizeof(double)); for(i = 0; i < n; i++) if (t = x[i]) { j = ka[i]; for(k = j + kal[i]; j < k; j++) r[ia[j]] -= t*a[j]; } } else *cprimp = *rprimp = 0; if (y) { if (method > 0 && objadj) { r = (double *)M1alloc(m*sizeof(double)); memcpy(r, y, (m-1)*sizeof(double)); r[m-1] = obj_adj; y = r; } *rdualp = y; *cdualp = r = (double*)M1alloc(n0*sizeof(double)); for(i = 0; i < n0; i++) { t = c[i]; j = ka[i]; for(k = j + kal[i]; j < k; j++) t -= y[ia[j]]*a[j]; r[i] = t; } } else *cdualp = *rdualp = 0; return 1; } #endif /*BARRIER*/ #ifdef CPX_PARAM_FEASOPTMODE /* >= 9.2b */ static int feasopt(CPXENVptr e, cpxlp *cpx) { char *grptype; double *L, *U, *lb, *rhs, *rng, *ub; int *grpbeg, *grpind, i, j, k, n, nqc; i = want_feasopt + 2*feasoptobj - 3; if (CPXsetintparam(e, CPX_PARAM_FEASOPTMODE, i)) printf("Could not set CPX_PARAM_FEASOPTMODE to %d\n", i); /* bug */ if (!(nqc = nlc)) { n = 2*(mbas + nbas); lb = (double*)Malloc(n*sizeof(double)); for(i = 0; i < n; i++) lb[i] = 1.; /* preferences */ ub = lb + nbas; rhs = ub + nbas; rng = rhs + mbas; i = CPXfeasopt(e, cpx, rhs, rng, lb, ub); } else { L = LUv; U = Uvx; k = nbas; n = mbas; for(i = 0; i < k; i++) { if (L[i] > negInfinity) n++; if (U[i] < Infinity) n++; } lb = (double*)Malloc(n*(sizeof(double)+2*sizeof(int)+1)); grpbeg = (int*)(lb + n); grpind = grpbeg + n; grptype = (char*)(grpind + n); for(i = 0; i < n; i++) { lb[i] = 1.; /* preferences */ grpbeg[i] = i; } for(i = j = 0; i < k; i++) { if (L[i] > negInfinity) { grpind[j] = i; grptype[j++] = CPX_CON_LOWER_BOUND; } if (U[i] < Infinity) { grpind[j] = i; grptype[j++] = CPX_CON_UPPER_BOUND; } } k = n_con - nqc; for(i = 0; i < k; i++) { grpind[j] = i; grptype[j++] = CPX_CON_LINEAR; } k = nqc; for(i = 0; i < k; i++) { grpind[j] = i; grptype[j++] = CPX_CON_QUADRATIC; } i = CPXfeasoptext(e, cpx, n, n, lb, grpbeg, grpind, grptype); } free(lb); return i; } #endif /*CPX_PARAM_FEASOPTMODE*/ #ifdef MSDOS #undef Stand_alone #endif #ifdef Student_Edition #undef Stand_alone #endif extern int cpxmain ANSI((int, char**)); typedef char *sfunc ANSI((char *, char *, int)); #ifdef CPLEX_MIP #ifdef CPX_PARAM_IISIND /* version < 9.2b */ typedef int (CPXPUBLIC *Treeio)(CPXCENVptr,CPXLPptr,Const char*); static void treeio(cpxlp *cpx, char *fname, char *what, Treeio tio) { if ((*tio)(Env,cpx,fname)) { printf("Could not %s tree file \"%s\".\n", what, fname); need_nl = 0; } } #endif #endif enum { /* sf_known f values */ set_barrier = 0, set_dual = 1, set_dualopt = 2, set_max = 3, set_min = 4, set_primal = 5, set_primalopt = 6, set_relax = 7, set_sens = 8, set_bestnode = 9, set_autoopt = 10, set_siftopt = 11, set_concurrentopt=12, set_bestbound = 13 }; static char * sf_known(Option_Info *oi, keyword *kw, char *v) { switch(Intcast kw->info) { #ifdef BARRIER case set_barrier: set_baropt(); break; #endif case set_dual: method = -1; break; case set_dualopt: Optimize = CPXdualopt; algname = "dual "; baralgname = ""; break; case set_max: objsen = -1; break; case set_min: objsen = 1; break; case set_primal: method = 1; break; case set_primalopt: Optimize = CPXprimopt; algname = baralgname = ""; break; case set_relax: relax = 1; break; case set_sens: costsens = 1; break; case set_bestbound: bestnode |= 1; break; case set_bestnode: bestnode |= 2; break; case set_autoopt: lpoptalg = CPX_ALG_AUTOMATIC; use_lpopt: Optimize = CPXlpopt; CPXsetintparam(Env, CPX_PARAM_LPMETHOD, lpoptalg); break; #ifdef CPX_STAT_OPTIMAL /* >= 8.0 */ case set_siftopt: lpoptalg = CPX_ALG_SIFTING; goto use_lpopt; case set_concurrentopt: lpoptalg = CPX_ALG_CONCURRENT; goto use_lpopt; #endif /*CPX_STAT_OPTIMAL*/ } return v; } static void baddval(Option_Info *oi, keyword *kw, double t, double L, double U) { printf("rejecting %s %g; must be between %g and %g\n", kw->name, t, L, U); badopt_ASL(oi); } static void badival(Option_Info *oi, keyword *kw, int t, int L, int U) { printf("rejecting %s %d; must be between %d and %d\n", kw->name, t, L, U); badopt_ASL(oi); } static char* sf_mdbl(Option_Info *oi, keyword *kw, char *v) { char *rv; double t; int i = Intcast kw->info; mdbl_values *m = mdbl_val + i; if (*v == '?' && v[1] <= ' ') { printf("%s=%g\n", kw->name, m->val); oi->option_echo &= ~ASL_OI_echothis; return v + 1; } t = strtod(v, &rv); if (rv == v) { printf("Expected a floating-point value for %s, not \"%s\"\n", kw->name, v); badopt_ASL(oi); return v; } if (t < m->L || t > m->U) { baddval(oi,kw,t,m->L,m->U); return rv; } m->val = t; return rv; } static char * sf_mint(Option_Info *oi, keyword *kw, char *v) { int t; char *rv; int i = Intcast kw->info; mint_values *m = mint_val + i; if (*v == '?' && v[1] <= ' ') { printf("%s=%d\n", kw->name, m->val); oi->option_echo &= ~ASL_OI_echothis; return v + 1; } t = (int)strtol(v, &rv, 10); if (rv == v) { printf("Expected an integer value for %s, not \"%s\"\n", kw->name, v); badopt_ASL(oi); return v; } if (t < m->L || t > m->U) { badival(oi,kw,t,m->L,m->U); return rv; } m->val = t; #ifdef BARRIER if (i == set_crossover) set_baropt(); #endif #ifdef CPLEX_MIP if (i == set_mipcuts) { static int op[9] = { CPX_PARAM_CLIQUES, CPX_PARAM_COVERS, CPX_PARAM_DISJCUTS, CPX_PARAM_FLOWCOVERS, CPX_PARAM_FLOWPATHS, CPX_PARAM_FRACCUTS, CPX_PARAM_GUBCOVERS, CPX_PARAM_IMPLBD, CPX_PARAM_MIRCUTS }; int f; for(f = 0; f < 9; f++) CPXsetintparam(Env, op[f], t); } #endif return rv; } static char * sf_int(Option_Info *oi, keyword *kw, char *v) { int f, t, z[3]; char *rv, *what = kw->name; f = Intcast kw->info; if (*v == '?' && v[1] <= ' ') { CPXgetintparam(Env, f, &t); printf("%s=%d\n", what, t); oi->option_echo &= ~ASL_OI_echothis; return v + 1; } t = (int)strtol(v, &rv, 10); if (rv == v) { printf("Expected an integer value for %s, not \"%s\"\n", what, v); badopt_ASL(oi); } else if (CPXsetintparam(Env, f, t)) { z[2] = 0; z[1] = 1; CPXinfointparam(Env, f, z, z+1, z+2); badival(oi, kw, t, z[1], z[2]); } return rv; } static char * sf_ipar(Option_Info *oi, keyword *kw, char *v) { int f, t, z[3]; char *rv, *v0 = v, *what = kw->name; f = (int)strtol(v, &rv, 10); if (rv == v) { printf("Expected an integer parameter number after %s%s, not \"%s\"\n", what, oi->eqsign, v); badopt_ASL(oi); } for(v = rv; *v <= ' '; v++) if (!*v) { printf("Expected an integer value after %s%s\n", what, oi->eqsign); badopt_ASL(oi); } if (*v == '=') while(*++v <= ' ') if (!*v) { printf("Expected an integer value after %s%s%s\n", what, oi->eqsign, v0); badopt_ASL(oi); } if (*v == '?' && v[1] <= ' ') { CPXgetintparam(Env, f, &t); printf("%s=%d=%d\n", what, f, t); oi->option_echo &= ~ASL_OI_echothis; return v + 1; } t = (int)strtol(v, &rv, 10); if (rv == v) { printf("Expected an integer value for %s %d, not \"%s\"\n", what, f, v); badopt_ASL(oi); } else if (CPXsetintparam(Env, f, t)) { z[2] = 0; z[1] = 1; CPXinfointparam(Env, f, z, z+1, z+2); printf("rejecting %s=%d=%d; assigned value must be between %d and %d\n", what, f, t, z[1], z[2]); badopt_ASL(oi); } return rv; } /* In case some reason surfaces to distinguish the old setzzzpar() */ /* calls from the old setzzzind calls (which had sfunc value sf_int and */ /* sf_int1, respectively, in the keywds table, we use the following */ /* #define and retain appearances of sf_int1 in the keywds table. */ #define sf_int1 sf_int static char * sf_dbl(Option_Info *oi, keyword *kw, char *v) { double t, z[3]; char *rv, *what = kw->name; int f = Intcast kw->info; if (*v == '?' && v[1] <= ' ') { CPXgetdblparam(Env, f, &t); printf("%s=%g\n", what, t); oi->option_echo &= ~ASL_OI_echothis; return v + 1; } t = strtod(v, &rv); if (rv == v) { printf("Expected a numeric value for %s, not \"%s\"\n", what, v); badopt_ASL(oi); } else if (CPXsetdblparam(Env, f, t)) { z[2] = 0; z[1] = 1; CPXinfodblparam(Env, f, z, z+1, z+2); printf("rejecting %s %g; must be between %g and %g\n", what, t, z[1], z[2]); badopt_ASL(oi); } return rv; } /* sf_int2 and sf_dbl2 are variants of sf_int and sf_dbl for */ /* synonyms, so getparinfo() will not deal with the synonyms. */ static char * sf_int2(Option_Info *oi, keyword *kw, char *v) { return sf_int(oi,kw,v); } static char * sf_dbl2(Option_Info *oi, keyword *kw, char *v) { return sf_dbl(oi,kw,v); } static char * sf_dpar(Option_Info *oi, keyword *kw, char *v) { double t, z[3]; int f; char *rv, *v0 = v, *what = kw->name; f = (int)strtol(v, &rv, 10); if (rv == v) { printf("Expected an integer parameter number after %s%s, not \"%s\"\n", what, oi->eqsign, v); badopt_ASL(oi); } for(v = rv; *v <= ' '; v++) if (!*v) { printf("Expected a floating-point value after %s%s\n", what, oi->eqsign); badopt_ASL(oi); } if (*v == '=') while(*++v <= ' ') if (!*v) { printf("Expected a floating-point value after %s%s%s\n", what, oi->eqsign, v0); badopt_ASL(oi); } if (*v == '?' && v[1] <= ' ') { CPXgetdblparam(Env, f, &t); printf("%s=%d=%g\n", what, f, t); oi->option_echo &= ~ASL_OI_echothis; return v + 1; } t = strtod(v, &rv); if (rv == v) { printf("Expected a floating-point value for %s %d, not \"%s\"\n", what, f, v); badopt_ASL(oi); } else if (CPXsetdblparam(Env, f, t)) { z[2] = 0; z[1] = 1; CPXinfodblparam(Env, f, z, z+1, z+2); printf("rejecting %s=%d=%g; assigned value must be between %g and %g\n", what, f, t, z[1], z[2]); badopt_ASL(oi); } return rv; } static char **file_name[17] = { &endbas, &endtree, &startbas, &starttree, &endvec, &startvec, &logfname, &wrtfname, &workfiledir, &poolstub, ¶mfile, &pretunefile, &pretunefileprm, &tunefile, &tunefileprm, &tunefix, &tunefixfile }; enum { /* sf_char f values */ set_endbas = 0, set_endtree = 1, set_startbas = 2, set_starttree = 3, set_endvector = 4, set_startvector = 5, set_logname = 6, set_wrtfname = 7, set_workfiledir = 8, set_poolstub = 9, set_paramfile = 10, set_pretunefile = 11, set_pretunefileprm = 12, set_tunefile = 13, set_tunefileprm = 14, set_tunefix = 15, set_tunefixfile = 16 }; static char * sf_char(Option_Info *oi, keyword *kw, char *v) { char *rv, *t; int f, q; size_t n; if (!*v) { printf("rejecting %s: no following file name\n", kw->name); badopt_ASL(oi); return v; } f = Intcast kw->info; if (*v == '?' && v[1] <= ' ') { if (!(t = *file_name[f])) t = ""; printf("%s=%s\n", kw->name, t); oi->option_echo &= ~ASL_OI_echothis; return v + 1; } q = 0; if (*v == '\'' || *v == '"') { q = *v++; for(rv = v; *rv != q; ++rv) { if (!*rv) { printf("Missing final %c in file name for %s.\n", q, kw->name); badname: badopt_ASL(oi); return rv+1; } } if (v == rv) { printf("Empty file name for %s.\n", kw->name); goto badname; } if (*++rv > ' ') { printf("Unexpected '%c' after closing $c of file name for %s.\n", *rv, q, kw->name); goto badname; } n = rv - v; } else { for(rv = v; *++rv > ' ';); n = rv - v + 1; } t = M1alloc(n); strncpy(t, v, --n); t[n] = 0; *file_name[f] = t; if (f == set_logname) { if (!(Logf = CPXfopen(t,"w"))) { printf("Cannot open logfile \"%s\"\n", t); badopt_ASL(oi); } else CPXsetlogfile(Env, Logf); } return rv; } static Option_Info Oinfo; static char * sf_par(Option_Info *oi, keyword *kw, char *v) { FILE *f; char buf[4096], *s; if (*v == '?' && v[1] <= ' ') { printf("# %s is processed when specified.\n", kw->name); return v + 1; } paramfile = 0; v = sf_char(oi, kw, v); if (!paramfile) return v; if (!(f = fopen(paramfile, "r"))) { printf("Cannot open %s \"%s\"\n", kw->name, paramfile); badopt_ASL(oi); return v; } while(fgets(buf, sizeof(buf), f)) for(s = buf; *s; s = get_opt_ASL(&Oinfo, s)); fclose(f); if (Oinfo.n_badopts) { if (amplflag) badretfmt(564, "Error reading paramfile \"%s\".", paramfile); exit(1); } return v; } #if CPX_VERSION >= 1000 /*{*/ static char * sf_parm(Option_Info *oi, keyword *kw, char *v) { if (*v == '?' && v[1] <= ' ') { printf("# %s is processed when specified.\n", kw->name); return v + 1; } paramfile = 0; v = sf_char(oi, kw, v); if (!paramfile) return v; if (CPXreadcopyparam(Env, paramfile)) { if (amplflag) badretfmt(564, "Error reading paramfileprm \"%s\".", paramfile); exit(1); } return v; } #endif /*}*/ #define VP (Char*) struct option_word { char *name; sfunc *sf; int ival; }; typedef struct option_word option_word; static keyword keywds[] = { /* must be in alphabetical order */ /* Undocumented keywords start with underscore... */ { "_aggsort", sf_int, VP 1061 /*CPX_PARAM_PREAGGSORT*/}, { "_aggtolerance", sf_dbl, VP 1055 /*CPX_PARAM_EPSAGG*/}, { "_cancel", sf_int, VP 1071 /*CPX_PARAM_PRECANCEL*/}, { "_clique", sf_int, VP 1072 /*CPX_PARAM_PRECLIQUE*/}, { "_cliquetablesize", sf_dbl, VP 2064 /*CPX_PARAM_CLIQUETABLESZ*/}, { "_domination", sf_int, VP 2038 /*CPX_PARAM_COLDOMIND*/}, { "_effslack", sf_int, VP 1042 /*CPX_PARAM_EFFSLACKIND*/}, { "_factormem", sf_dbl, VP 3021 /*CPX_PARAM_BARFACTMEM*/}, { "_flip", sf_int, VP 1051 /*CPX_PARAM_FLIPIND*/}, { "_hfeasibility", sf_dbl, VP 1050 /*CPX_PARAM_EPRHS_H*/}, { "_hoptimality", sf_dbl, VP 1049 /*CPX_PARAM_EPOPT_H*/}, { "_insubtree", sf_int, VP 2063 /*CPX_PARAM_INSUBTREE*/}, { "_kernel", sf_int, VP 3020 /*CPX_PARAM_BARKERNEL*/}, { "_knapcoeff", sf_int, VP 1059 /*CPX_PARAM_KNAPCOERED*/}, { "_localcovers", sf_int, VP 2061 /*CPX_PARAM_LOCALCOVERS*/}, { "_logparams", sf_int, VP 1075 /*CPX_PARAM_LOGPARAMS*/}, { "_memfact", sf_dbl, VP 1045 /*CPX_PARAM_PREMEMFACT*/}, { "_memsave", sf_int, VP 1060 /*CPX_PARAM_PREMEMSAVE*/}, { "_minstuck", sf_int, VP 3023 /*CPX_PARAM_BARMINSTUCK*/}, { "_oldpricing", sf_int, VP 1054 /*CPX_PARAM_OLDPRICING*/}, { "_oldqpfactor", sf_int, VP 3024 /*CPX_PARAM_OLDQPFACTOR*/}, { "_oldratio", sf_int, VP 1068 /*CPX_PARAM_OLDRATIO*/}, { "_orderthreads", sf_int, VP 3022 /*CPX_PARAM_BARORDERTHREADS*/}, { "_primalstart", sf_dbl, VP 3005 /*CPX_PARAM_BARPSTART*/}, { "_probe", sf_int, VP 1070 /*CPX_PARAM_PREPROBE*/}, { "_recurseheur", sf_int, VP 2062 /*CPX_PARAM_RECURSEHEUR*/}, #ifdef CPX_PARAM_IISIND /* version < 9.2b */ { "_rowsdense", sf_int, VP 3015 /*CPX_PARAM_BARROWSDEN*/}, #endif { "_splitrow", sf_int, VP 1079 /*CPX_PARAM_PRESPLITROW*/}, { "_svbound", sf_int, VP 1069 /*CPX_PARAM_SVBNDSTR*/}, /* Documented keywords... */ #ifdef CPLEX_MIP { "absmipgap", sf_dbl, VP CPX_PARAM_EPAGAP }, #endif { "advance", sf_int1, VP CPX_PARAM_ADVIND }, #ifdef CPLEX_MIP { "aggcutlim", sf_int, VP CPX_PARAM_AGGCUTLIM }, #endif { "aggfill", sf_int2, VP CPX_PARAM_AGGFILL }, { "agglim", sf_int, VP CPX_PARAM_AGGFILL }, { "aggregate", sf_int1, VP CPX_PARAM_AGGIND }, { "aggtol", sf_dbl, VP CPX_PARAM_EPSAGG }, { "autoopt", sf_known, VP set_autoopt }, { "autopt", sf_known, VP set_autoopt }, #ifdef CPLEX_MIP { "backtrack", sf_dbl, VP CPX_PARAM_BTTOL }, #endif #ifdef BARRIER { "baralg", sf_int, VP CPX_PARAM_BARALG }, { "barcorr", sf_int, VP CPX_PARAM_BARMAXCOR }, { "bardisplay", sf_int2, VP CPX_PARAM_BARDISPLAY }, { "bargrowth", sf_dbl, VP CPX_PARAM_BARGROWTH }, { "bariterlim", sf_int, VP CPX_PARAM_BARITLIM }, { "barobjrange", sf_dbl, VP CPX_PARAM_BAROBJRNG }, { "baropt", sf_known, VP set_barrier }, #ifdef CPX_PARAM_BAROOC { "baroutofcore",sf_int, VP CPX_PARAM_BAROOC }, #endif { "barstart", sf_int, VP CPX_PARAM_BARSTARTALG }, { "barstartalg",sf_int, VP CPX_PARAM_BARSTARTALG }, #ifdef CPX_PARAM_BARTHREADS { "barthreads", sf_int, VP CPX_PARAM_BARTHREADS }, #endif #ifdef CPX_PARAM_BARVARUP { "barvarup", sf_dbl, VP CPX_PARAM_BARVARUP }, #endif #endif /* BARRIER */ { "basis_cond", sf_mint, VP set_basis_cond }, { "basisinterval", sf_int, VP CPX_PARAM_BASINTERVAL }, #ifdef CPLEX_MIP { "bbinterval", sf_int, VP CPX_PARAM_BBINTERVAL }, { "bestbound", sf_known, VP set_bestbound }, { "bestnode", sf_known, VP set_bestnode }, { "boundstr", sf_int, VP CPX_PARAM_BNDSTRENIND }, { "branch", sf_int, VP CPX_PARAM_BRDIR }, { "branchdir", sf_int, VP CPX_PARAM_BRDIR }, { "cliquecuts", sf_int2, VP CPX_PARAM_CLIQUES }, { "cliques", sf_int, VP CPX_PARAM_CLIQUES }, #endif { "clocktype", sf_int, VP CPX_PARAM_CLOCKTYPE }, #ifdef CPLEX_MIP { "coeffreduce", sf_int1, VP CPX_PARAM_COEREDIND }, #endif #ifdef BARRIER { "comptol", sf_dbl, VP CPX_PARAM_BAREPCOMP }, #endif { "concurrent", sf_known, VP set_concurrentopt }, { "concurrentopt",sf_known, VP set_concurrentopt }, #ifdef CPX_PARAM_CONFLICTDISPLAY { "conflictdisplay", sf_int, VP CPX_PARAM_CONFLICTDISPLAY }, #endif #ifdef CPLEX_MIP { "covercuts", sf_int2, VP CPX_PARAM_COVERS }, { "covers", sf_int, VP CPX_PARAM_COVERS }, #endif { "crash", sf_int, VP CPX_PARAM_CRAIND }, #ifdef BARRIER { "crossover", sf_mint, VP set_crossover }, #endif #ifdef CPLEX_MIP { "cutpass", sf_int, VP CPX_PARAM_CUTPASS }, { "cutsfactor", sf_dbl, VP CPX_PARAM_CUTSFACTOR }, #endif #ifdef BARRIER { "dense", sf_int2, VP CPX_PARAM_BARCOLNZ }, { "densecol", sf_int, VP CPX_PARAM_BARCOLNZ }, #endif { "dependency", sf_int1, VP CPX_PARAM_DEPIND }, { "dgradient", sf_int, VP CPX_PARAM_DPRIIND }, #ifdef CPLEX_MIP { "disjcuts", sf_int, VP CPX_PARAM_DISJCUTS }, #endif { "display", sf_int2, VP CPX_PARAM_SIMDISPLAY }, { "doperturb", sf_int1, VP CPX_PARAM_PERIND }, { "dparam", sf_dpar, 0 }, { "dual", sf_known, VP set_dual }, { "dualopt", sf_known, VP set_dualopt }, { "dualratio", sf_mdbl, VP set_dual_ratio }, { "dualthresh", sf_mint, VP set_dualthresh }, #ifdef CPX_PARAM_EACHCUTLIM { "eachcutlim", sf_int, VP CPX_PARAM_EACHCUTLIM }, #endif { "endbasis", sf_char, VP set_endbas }, #ifdef CPLEX_MIP #ifdef CPX_PARAM_IISIND /* version < 9.2b */ { "endtree", sf_char, VP set_endtree }, #endif #endif #ifdef BARRIER { "endvector", sf_char, VP set_endvector }, #endif { "feasibility", sf_dbl, VP CPX_PARAM_EPRHS }, #ifdef CPX_PARAM_FEASOPTMODE /* >= 9.2b */ { "feasopt", sf_mint, VP set_feasopt }, { "feasoptobj", sf_mint, VP set_feasoptobj }, #endif { "file", sf_char, VP set_wrtfname }, #ifdef CPX_PARAM_FINALFACTOR { "finalfactor", sf_int, VP CPX_PARAM_FINALFACTOR }, #endif #ifdef CPLEX_MIP { "flowcuts", sf_int, VP CPX_PARAM_FLOWCOVERS }, { "flowpathcuts",sf_int, VP CPX_PARAM_FLOWPATHS }, #ifdef CPX_PARAM_FPHEUR { "fpheur", sf_int, VP CPX_PARAM_FPHEUR }, #endif #ifndef NO_CPLEX66 /* for versions prior to CPLEX 6.6 */ { "fraccand", sf_int, VP CPX_PARAM_FRACCAND }, { "fraccuts", sf_int, VP CPX_PARAM_FRACCUTS }, { "fracpass", sf_int, VP CPX_PARAM_FRACPASS }, { "fractionalcuts", sf_int, VP CPX_PARAM_FRACCUTS }, #endif #endif #ifdef BARRIER { "growth", sf_dbl, VP CPX_PARAM_BARGROWTH }, /*== bargrowth*/ #endif #ifdef CPLEX_MIP { "gubcuts", sf_int, VP CPX_PARAM_GUBCOVERS }, { "heurfreq", sf_int, VP CPX_PARAM_HEURFREQ }, #ifdef CPX_PARAM_HEURISTIC { "heuristic", sf_int, VP CPX_PARAM_HEURISTIC }, #endif { "heuristicfreq", sf_int, VP CPX_PARAM_HEURFREQ }, #endif { "iisfind", sf_mint, VP set_iis }, #ifdef CPLEX_MIP { "impliedcuts", sf_int, VP CPX_PARAM_IMPLBD }, { "integrality", sf_dbl, VP CPX_PARAM_EPINT }, { "intwarntol", D_val, VP &intwarn_tol }, #endif { "iparam", sf_ipar, 0 }, { "iterations", sf_int, VP CPX_PARAM_ITLIM }, { "iterlim", sf_int, VP CPX_PARAM_ITLIM }, #ifdef Uselazy { "lazy", sf_mint, VP set_lazy }, #endif #ifdef CPLEX_MIP #ifdef CPX_PARAM_LBHEUR { "lbheur", sf_int, VP CPX_PARAM_LBHEUR }, #endif #endif { "limitperturb",sf_int2, VP CPX_PARAM_PERLIM }, { "logfile", sf_char, VP set_logname }, #ifdef CPLEX_MIP { "lowercutoff", sf_dbl, VP CPX_PARAM_CUTLO }, #endif { "lowerobj", sf_dbl, VP CPX_PARAM_OBJLLIM }, { "lowerobjlim", sf_dbl, VP CPX_PARAM_OBJLLIM }, { "lpdisplay", sf_int2, VP CPX_PARAM_SIMDISPLAY }, { "lpiterlim", sf_int2, VP CPX_PARAM_ITLIM }, { "lptimelim", sf_dbl2, VP CPX_PARAM_TILIM }, { "markowitz", sf_dbl, VP CPX_PARAM_EPMRK }, { "maximize", sf_known, VP set_max }, #ifdef CPX_PARAM_MEMORYEMPHASIS { "memoryemphasis", sf_int, VP CPX_PARAM_MEMORYEMPHASIS }, #endif { "minimize", sf_known, VP set_min }, #ifdef CPLEX_MIP { "mipalg", sf_int, VP CPX_PARAM_SUBALG }, { "mipalgorithm", sf_int, VP CPX_PARAM_SUBALG }, { "mipbasis", sf_mint, VP set_mipbasis }, { "mipcrossover",sf_int, VP CPX_PARAM_BARCROSSALG }, { "mipcuts", sf_mint, VP set_mipcuts }, { "mipdisplay", sf_int2, VP CPX_PARAM_MIPDISPLAY }, { "mipemphasis",sf_int, VP CPX_PARAM_MIPEMPHASIS }, { "mipgap", sf_dbl, VP CPX_PARAM_EPGAP }, { "mipinterval", sf_int, VP CPX_PARAM_MIPINTERVAL }, { "mipordertype",sf_int2, VP CPX_PARAM_MIPORDTYPE }, #ifdef CPX_PARAM_MIPSEARCH { "mipsearch", sf_int, VP CPX_PARAM_MIPSEARCH }, #endif { "mipsolutions", sf_int, VP CPX_PARAM_INTSOLLIM }, { "mipstart", sf_mint, VP set_mipstval }, { "mipstartalg", sf_int, VP CPX_PARAM_STARTALG }, { "mipstartstatus", sf_mint, VP set_mipststat }, { "mipstartvalue", sf_mint, VP set_mipstval }, { "mipsubalg", sf_int, VP CPX_PARAM_SUBALG }, #ifdef CPX_PARAM_MIPTHREADS { "mipthreads", sf_int, VP CPX_PARAM_MIPTHREADS }, #endif #ifdef CPX_PARAM_MIQCPSTRAT { "miqcpstrat", sf_int, VP CPX_PARAM_MIQCPSTRAT }, #endif { "mircuts", sf_int, VP CPX_PARAM_MIRCUTS }, #endif { "nameround", sf_mint, VP set_namernd }, { "netdisplay", sf_int, VP CPX_PARAM_NETDISPLAY }, { "netfeasibility", sf_dbl, VP CPX_PARAM_NETEPRHS }, { "netfind", sf_int, VP CPX_PARAM_NETFIND }, { "netfinder", sf_int, VP CPX_PARAM_NETFIND }, { "netiterations", sf_int, VP CPX_PARAM_NETITLIM }, { "netopt", sf_mint, VP set_netopt }, { "netoptimality", sf_dbl, VP CPX_PARAM_NETEPOPT }, { "netpricing", sf_int, VP CPX_PARAM_NETPPRIIND }, #ifdef CPLEX_MIP { "node", sf_int2, VP CPX_PARAM_NODELIM }, { "nodefile", sf_int, VP CPX_PARAM_NODEFILEIND }, { "nodefiledir",sf_char, VP set_workfiledir }, #ifdef CPX_PARAM_NODEFILELIM { "nodefilelim", sf_dbl, VP CPX_PARAM_NODEFILELIM }, { "nodefilesize",sf_dbl, VP CPX_PARAM_NODEFILELIM }, #endif { "nodelim", sf_int2, VP CPX_PARAM_NODELIM }, { "nodes", sf_int, VP CPX_PARAM_NODELIM }, { "nodesel", sf_int, VP CPX_PARAM_NODESEL }, { "nodeselect", sf_int, VP CPX_PARAM_NODESEL }, #endif #ifdef CPX_PARAM_NUMERICALEMPHASIS { "numericalemphasis", sf_int, VP CPX_PARAM_NUMERICALEMPHASIS }, #endif #ifdef CPLEX_MIP { "objdifference", sf_dbl, VP CPX_PARAM_OBJDIF }, #endif { "objno", sf_mint, VP set_objno }, { "oldpricing", sf_int, VP CPX_PARAM_OLDPRICING }, { "optimality", sf_dbl, VP CPX_PARAM_EPOPT }, { "optimize", sf_known, VP set_primalopt }, #ifdef BARRIER { "ordering", sf_int, VP CPX_PARAM_BARORDER }, #endif #ifdef CPLEX_MIP { "ordertype", sf_int, VP CPX_PARAM_MIPORDTYPE }, #endif { "outlev", sf_int2, VP CPX_PARAM_SIMDISPLAY }, #ifdef CPX_PARAM_PARALLELMODE { "parallelmode", sf_int, VP CPX_PARAM_PARALLELMODE }, #endif { "paramfile", sf_par, VP set_paramfile }, #if CPX_VERSION >= 1000 { "paramfileprm", sf_parm, VP set_paramfile }, #endif { "pdswitch", sf_int, VP CPX_PARAM_PDSWITCH }, { "perturb", sf_int1, VP CPX_PARAM_PERIND }, { "perturbation", sf_dbl, VP CPX_PARAM_EPPER }, { "perturbconst", sf_dbl, VP CPX_PARAM_EPPER }, { "perturblim", sf_int, VP CPX_PARAM_PERLIM }, { "perturblimit", sf_int, VP CPX_PARAM_PERLIM }, { "pgradient", sf_int, VP CPX_PARAM_PPRIIND }, #ifdef CPLEX_MIP { "plconpri", sf_mint, VP set_conpri }, { "plobjpri", sf_mint, VP set_objpri }, #ifdef CPX_PARAM_POLISHTIME { "polishtime", sf_dbl, VP CPX_PARAM_POLISHTIME }, #endif #ifdef CPX_PARAM_POPULATELIM { "poolagap", sf_dbl, VP CPX_PARAM_SOLNPOOLAGAP }, { "poolcapacity", sf_int2, VP CPX_PARAM_SOLNPOOLCAPACITY }, { "poolgap", sf_dbl, VP CPX_PARAM_SOLNPOOLGAP }, { "poolintensity", sf_int, VP CPX_PARAM_SOLNPOOLINTENSITY }, { "poolreplace", sf_int, VP CPX_PARAM_SOLNPOOLREPLACE }, { "poolstub", sf_char, VP set_poolstub }, { "populate", sf_mint, VP set_populate }, { "populatelim", sf_int, VP CPX_PARAM_POPULATELIM }, #endif #endif /*CPLEX_MIP*/ #ifdef CPX_PARAM_PRECOMPRESS { "precompress", sf_int, VP CPX_PARAM_PRECOMPRESS }, #endif { "predual", sf_int, VP CPX_PARAM_PREDUAL }, { "prelinear", sf_int, VP CPX_PARAM_PRELINEAR }, #ifdef CPX_PARAM_PREPASS { "prepass", sf_int, VP CPX_PARAM_PREPASS }, #endif { "prereduce", sf_int, VP CPX_PARAM_REDUCE }, #ifdef CPLEX_MIP { "prerelax", sf_int1, VP CPX_PARAM_RELAXPREIND }, #endif { "presolve", sf_int1, VP CPX_PARAM_PREIND }, { "presolvedual",sf_int, VP CPX_PARAM_PREDUAL }, #ifdef CPLEX_MIP { "presolvenode",sf_int, VP CPX_PARAM_PRESLVND }, #endif { "prestats", sf_mint, VP set_prestats }, #ifdef CPX_TUNE_TILIM { "pretunefile", sf_char, VP set_pretunefile }, { "pretunefileprm", sf_char, VP set_pretunefileprm }, #endif { "pricing", sf_int, VP CPX_PARAM_PRICELIM }, { "primal", sf_known, VP set_primal }, { "primalopt", sf_known, VP set_primalopt }, #ifdef CPLEX_MIP { "priorities", sf_int1, VP CPX_PARAM_MIPORDIND }, { "probe", sf_int, VP CPX_PARAM_PROBE }, #ifdef CPX_PARAM_PROBETIME { "probetime", sf_dbl, VP CPX_PARAM_PROBETIME }, #endif #endif /*CPLEX_MIP*/ #ifdef CPX_PARAM_BARQCPEPCOMP { "qcpconvergetol", sf_dbl, VP CPX_PARAM_BARQCPEPCOMP }, #endif { "rays", sf_mint, VP set_rays }, { "readbasis", sf_char, VP set_startbas }, #ifdef BARRIER { "readvector", sf_char, VP set_startvector }, #endif { "refactor", sf_int, VP CPX_PARAM_REINV }, #ifdef CPLEX_MIP { "relax", sf_known, VP set_relax }, { "relaxpresolve", sf_int, VP CPX_PARAM_RELAXPREIND }, { "relobjdif", sf_dbl2, VP CPX_PARAM_RELOBJDIF }, { "relobjdiff", sf_dbl, VP CPX_PARAM_RELOBJDIF }, { "relpresolve", sf_int, VP CPX_PARAM_RELAXPREIND }, #ifdef CPX_PARAM_REPAIRTRIES { "repairtries", sf_int, VP CPX_PARAM_REPAIRTRIES }, #endif #ifdef CPX_PARAM_REPEATPRESOLVE { "repeatpresolve", sf_int, VP CPX_PARAM_REPEATPRESOLVE }, #endif { "return_mipgap", sf_mint, VP set_retmipgap }, #ifdef CPX_PARAM_RINSHEUR { "rinsheur", sf_int, VP CPX_PARAM_RINSHEUR }, #endif #ifdef CPX_PARAM_HEURISTIC { "rootheuristic", sf_int, VP CPX_PARAM_HEURISTIC }, #endif { "round", sf_mint, VP set_round }, #endif /*CPLEX_MIP*/ { "scale", sf_int, VP CPX_PARAM_SCAIND }, { "sensitivity", sf_known, VP set_sens }, { "siftingopt", sf_known, VP set_siftopt }, { "siftopt", sf_known, VP set_siftopt }, #ifdef CPX_PARAM_SIMTHREADS { "simthreads", sf_int, VP CPX_PARAM_SIMTHREADS }, #endif { "singular", sf_int, VP CPX_PARAM_SINGLIM }, { "singularlim", sf_int, VP CPX_PARAM_SINGLIM }, #ifdef CPLEX_MIP { "solutionlim", sf_int, VP CPX_PARAM_INTSOLLIM }, { "sos", sf_mint, VP set_sos }, { "sos2", sf_mint, VP set_sos2 }, { "startalg", sf_int, VP CPX_PARAM_STARTALG }, { "startalgorithm", sf_int, VP CPX_PARAM_STARTALG }, { "startbasis", sf_char, VP set_startbas }, #ifdef CPX_PARAM_IISIND /* version < 9.2b */ { "starttree", sf_char, VP set_starttree }, #endif #ifdef BARRIER { "startvector", sf_char, VP set_startvector }, #endif #ifdef CPLEX_MIP { "strongcand", sf_int, VP CPX_PARAM_STRONGCANDLIM}, { "strongit", sf_int, VP CPX_PARAM_STRONGITLIM}, #ifdef CPX_PARAM_STRONGTHREADLIM { "strongthreads", sf_int, VP CPX_PARAM_STRONGTHREADLIM}, #endif #endif { "subalg", sf_int, VP CPX_PARAM_SUBALG }, { "subalgorithm", sf_int, VP CPX_PARAM_SUBALG }, #endif #ifdef CPX_PARAM_SUBMIPNODELIM { "submipnodelim", sf_int, VP CPX_PARAM_SUBMIPNODELIM }, #endif #ifdef CPLEX_MIP #ifdef CPX_PARAM_SYMMETRY { "symmetry", sf_int, VP CPX_PARAM_SYMMETRY }, #endif #endif #ifdef CPX_PARAM_THREADS { "threads", sf_int, VP CPX_PARAM_THREADS }, #endif { "time", sf_dbl, VP CPX_PARAM_TILIM }, { "timelimit", sf_dbl, VP CPX_PARAM_TILIM }, { "timing", sf_mint, VP set_timing }, { "tranopt", sf_known, VP set_dualopt }, #ifdef CPLEX_MIP { "treelimit", sf_dbl2, VP CPX_PARAM_TRELIM }, { "treememlim", sf_dbl2, VP CPX_PARAM_TRELIM }, { "treememory", sf_dbl, VP CPX_PARAM_TRELIM }, #endif #ifdef CPX_TUNE_TILIM { "tunedisplay",sf_int, VP CPX_PARAM_TUNINGDISPLAY }, { "tunefile", sf_char, VP set_tunefile }, { "tunefileprm",sf_char, VP set_tunefileprm }, { "tunefix", sf_char, VP set_tunefix }, { "tunefixfile",sf_char, VP set_tunefixfile }, { "tunerepeat", sf_int, VP CPX_PARAM_TUNINGREPEAT }, { "tunetime", sf_dbl, VP CPX_PARAM_TUNINGTILIM }, #endif #ifdef CPLEX_MIP { "uppercutoff", sf_dbl, VP CPX_PARAM_CUTUP }, #endif { "upperobj", sf_dbl, VP CPX_PARAM_OBJULIM }, { "upperobjlim",sf_dbl, VP CPX_PARAM_OBJULIM }, #ifdef CPLEX_MIP { "varsel", sf_int, VP CPX_PARAM_VARSEL }, { "varselect", sf_int, VP CPX_PARAM_VARSEL }, #endif { "version", Ver_val, 0 }, { "wantsol", WS_val, 0 }, { "workfiledir",sf_char, VP set_workfiledir }, #ifdef CPX_PARAM_WORKMEM { "workfilelim",sf_dbl, VP CPX_PARAM_WORKMEM }, #endif { "writebasis", sf_char, VP set_endbas }, { "writeprob", sf_char, VP set_wrtfname }, #ifdef BARRIER { "writevector", sf_char, VP set_endvector }, #endif { "xxxstart", sf_int, VP CPX_PARAM_XXXIND } #ifdef CPX_PARAM_ZEROHALFCUTS ,{ "zerohalfcuts", sf_int, VP CPX_PARAM_ZEROHALFCUTS } #endif }; static Option_Info Oinfo = { "cplex", 0, "cplex_options", keywds, nkeywds, 0, cplex_version, 0,0,0,0,0, 20080109 }; static void badlic(int rc, int status) { char buf[4096]; if (!CPXgeterrorstring(Env, status, buf)) Sprintf(buf, "CPLEX licensing problem: error code %d from CPXopenCPLEX.", status); badretfmt(rc, "%s", buf); } static void nonlin(int n, int rc, char *what) { if (n) { badretfmt(rc, "%s contains %s.\n", filename, what); exit(4); } } static unsigned namemem(int n) { int k, L; unsigned int rv; L = 3; k = 9; rv = 0; while(n > k) { rv += k*L++; n -= k; k *= 10; } return rv + n*L; } static char * namegen(char *stub, char **name, char *s, int n) { int i, j, k, k0, L; k0 = 10; for(i = 1; i <= n; i++) { if (k0 <= i) k0 *= 10; *name++ = s; *s++ = *stub; for(j = i, k = k0; k /= 10; ) { L = j / k; j -= L * k; *s++ = '0' + L; } *s++ = 0; } return s; } static unsigned int brlen(char **name, int n) { char *s, *s0; unsigned int x = 0; top: while(n > 0) for(s = s0 = name[--n];;) switch(*s++) { case 0: goto top; case '[': case ']': x += strlen(s0) + 1; goto top; } return x; } static char* br_round(char **name, int n, char *s) { char *t, *t0; top: while(n > 0) for(t = t0 = name[--n];;) switch(*t++) { case 0: goto top; case '[': case ']': name[n] = s; for(;;) switch(*s++ = *t0++) { case 0: goto top; case '[': s[-1] = '('; break; case ']': s[-1] = ')'; } } return s; } static void make_names(char ***cnamep, char ***rnamep) { char buf[24], **cname, **rname, *s; int cnlen, i, j, n, rnlen; unsigned int cstorsz, rstorsz, rsz; cnlen = rnlen = 0; if (method > 0) { cnlen = maxcolnamelen; rnlen = maxrownamelen; } cstorsz = cnlen > 0 ? 0 : namemem(nbas); rstorsz = rnlen > 0 ? 0 : namemem(mbas); *cnamep = cname = (char **)Malloc((mbas+nbas)*sizeof(char *) + cstorsz + rstorsz); *rnamep = rname = cname + nbas; s = (char*)(rname + mbas); if (cnlen > 0) { for(i = 0, n = n_var; i < n; i++) cname[i] = var_name(i); while(i < nbas) { j = sprintf(buf, "_svar[%d]", i+1) + 1; memcpy(cname[i++] = (char*)mem(j), buf, j); } } else s = namegen("x", cname, s, nbas); if (rnlen > 0) { for(i = 0, n = n_con; i < n; i++) rname[i] = con_name(i); while(i < mbas) { j = sprintf(buf, "_scon[%d]", i+1) + 1; memcpy(rname[i++] = (char*)mem(j), buf, j); } } else namegen("c", rname, s, mbas); if (Nameround) { /* This would be better done by running "tr" separately. */ rsz = 0; if (cnlen > 0) rsz = brlen(cname, nbas); if (rnlen > 0) rsz += brlen(rname, mbas); if (!rsz) return; s = (char*)M1alloc(rsz); if (cnlen > 0) s = br_round(cname, nbas, s); if (rnlen > 0) br_round(rname, mbas, s); } } #ifdef CPLEX_MIP static int nzeros(int *p, int n) { int *pe = p + n; n = 0; while(p < pe) if (*p++) n++; return n; } static void mip_priorities(ASL *asl, cpxlp *cpx) { int baddir, badpri, i, j, k, listsize, nnames, pvk, sk; int *ci, *colindex, *dir, *direction, *p, *priority; int *start, *num, *pri; SufDesc *dp, *dd; baddir = badpri = i = listsize = 0; dd = suf_get("direction", ASL_Sufkind_var); dir = dd->u.i; dp = suf_get("priority", ASL_Sufkind_var); direction = 0; if ((p = dp->u.i) || dir) { nnames = n_var; k = 2; if (p && dir) { k = 3; for(; i < nnames; i++) if (p[i] || dir[i]) listsize++; } else if (p) listsize = nzeros(p, nnames); else listsize = nzeros(dir, nnames); if (!listsize) return; priority = 0; colindex = (int*)Malloc(k*listsize*sizeof(int)); i = k = 0; if (dir && p) { priority = colindex + listsize; direction = priority + listsize; for(; i < nnames; i++) if (p[i] || dir[i]) { colindex[k] = i; if ((j = p[i]) < 0) { badpri++; j = 0; } priority[k] = j; switch(dir[i]) { case -1: j = CPX_BRANCH_DOWN; break; case 1: j= CPX_BRANCH_UP; break; default: baddir++; /* no break */ case 0: j = CPX_BRANCH_GLOBAL; } direction[k++] = j; } } else if (p) { priority = colindex + listsize; for(; i < nnames; i++) if (p[i]) { colindex[k] = i; if ((j = p[i]) < 0) { badpri++; j = 0; } priority[k++] = j; } } else { direction = colindex + listsize; for(; i < nnames; i++) if (dir[i]) { switch(dir[i]) { case -1: j = CPX_BRANCH_DOWN; break; case 1: j= CPX_BRANCH_UP; break; default: baddir++; /* no break */ case 0: j = CPX_BRANCH_GLOBAL; } direction[k] = j; colindex[k++] = i; } } listsize = k; if (baddir) fprintf(Stderr, "Treating %d .direction values outside [-1, 1] as 0.\n", baddir); if (badpri) fprintf(Stderr, "Treating %d negative .priority values as 0\n", badpri); } else if (nnames = mip_pri(&start, &num, &pri, 2147483647)) { for(; i < nnames; i++) listsize += num[i]; ci = colindex = (int *)Malloc(listsize*(2*sizeof(int))); priority = p = ci + listsize; for(k = 0; k < nnames; k++) { i = num[k]; pvk = pri[k]; sk = start[k]; while(--i >= 0) { *ci++ = sk++; *p++ = pvk; } } listsize = ci - colindex; } else return; if (CPXcopyorder(Env,cpx,listsize,colindex,priority,direction)) printf("error in CPXcopyorder!\n"); free(colindex); } static void mipinit_loop(ASL *asl, int **rp, int *np, real **xp, int j, int k) { int i, *r; real *L, *U, t, *v, *x; v = X0 + j; L = LUv + j; U = Uvx + j; r = *rp; x = *xp; for(i = 0; i < k; ++i) { *r++ = i + j; if ((t = v[i]) < L[i]) t = L[i]; else if (t > U[i]) t = U[i]; *x++ = t; } *rp = r; *xp = x; *np -= k; } static void set_mipinit(ASL *asl, cpxlp *cpx, int nint) { int i, k, m, m0, n1, *r, *r1; real *x, *x1; x = x1 = (real*)Malloc(nint*(sizeof(real) + sizeof(int))); r = r1 = (int*)(x + nint); n1 = nint; if (k = nlvbi) mipinit_loop(asl, &r1, &n1, &x1, nlvb - k, k); m0 = nlvb; m = nlvc - nlvb; if (k = nlvci) mipinit_loop(asl, &r1, &n1, &x1, m0 + m - k, k); m0 += m; if (k = nlvoi) mipinit_loop(asl, &r1, &n1, &x1, m0 + nlvo - nlvb - k, k); if (n1) mipinit_loop(asl, &r1, &n1, &x1, n_var - (niv + nbv), n1); if (i = CPXcopymipstart(Env, cpx, nint, r, x)) badret("CPXcopymipstart", i, 0); #ifdef CPX_PARAM_MIPSTART else if (i = CPXsetintparam(Env, CPX_PARAM_MIPSTART, 1)) badret("CPXsetintparam(CPX_PARAM_MIPSTART)", i, 0); #endif free(x); } #endif static int parval(int par) { int rv; CPXgetintparam(Env, par, &rv); return rv; } static int CPXPUBLIC lpcbf(CPXCENVptr env, void *lp, int wf, void *cbh) { int i; static int n[4]; static int wi[8] = { CPX_CALLBACK_INFO_PRESOLVE_ROWSGONE, CPX_CALLBACK_INFO_PRESOLVE_COLSGONE, CPX_CALLBACK_INFO_PRESOLVE_AGGSUBST, CPX_CALLBACK_INFO_PRESOLVE_COEFFS, CPX_CALLBACK_INFO_CROSSOVER_PPUSH, CPX_CALLBACK_INFO_CROSSOVER_PEXCH, CPX_CALLBACK_INFO_CROSSOVER_DPUSH, CPX_CALLBACK_INFO_CROSSOVER_DEXCH }; static char pfmt[] = "%sLP Presolve eliminated %d rows and %d columns.\n"; static int wf0; char *pfx, *prob; Not_Used(cbh); switch(wf) { case CPX_CALLBACK_PRESOLVE: if (!prestats || !dispzap) goto done; for(i = 0; i < 4; i++) CPXgetcallbackinfo(env, lp, wf, wi[i], &n[i]); wf0 = wf; goto done; case CPX_CALLBACK_PRIMAL_CROSSOVER: cbi.xkind = "primal"; for(i = 0; i < 2; i++) CPXgetcallbackinfo(env, lp, wf, wi[i+4], &cbi.nx[i]); goto done; case CPX_CALLBACK_DUAL_CROSSOVER: cbi.xkind = "dual"; for(i = 0; i < 2; i++) CPXgetcallbackinfo(env, lp, wf, wi[i+6], &cbi.nx[i]); goto done; } if (wf == wf0 || !prestats || !dispzap) goto done; wf0 = wf; if (cbi.npr++ && !memcmp(n, cbi.n0, 4*sizeof(int))) goto done; memcpy(cbi.n0, n, 4*sizeof(int)); if (cbi.nint) { pfx = "MIP "; prob = "MIP"; } else { pfx = ""; prob = "LP"; } if (!(n[0] + n[1] + n[2])) { printf("No %s presolve or aggregator reductions.\n", prob); goto done; } if (cbi.pres) printf(pfmt, pfx, n[0], n[1]); if (n[2]) printf("Aggregator did %d substitutions.\n", n[2]); if (n[3]) printf("%d coefficients modified.\n", n[3]); done: return breaking > 1; } static void stat_map(int *stat, int n, int *map, int mx, char *what) { int bad, i, i1, j, j1; static char badfmt[] = "cplex driver: %s[%d] = %d\n"; for(i = bad = 0; i < n; i++) { if ((j = stat[i]) >= 0 && j <= mx) stat[i] = map[j]; else { stat[i] = 0; i1 = i; j1 = j; if (!bad++) fprintf(Stderr, badfmt, what, i, j); } } if (bad > 1) { if (bad == 2) fprintf(Stderr, badfmt, what, i1, j1); else fprintf(Stderr, "cplex driver: %d messages about bad %s values suppressed.\n", bad-1, what); } } static void get_statuses(ASL *asl, cpxlp *cpx, dims *d) { SufDesc *sd; int *cs, *cstat, havestats, i, j, m, n, *rs, *rstat; real *L, *U; static int map[] = {0, 1, 3, 0, 2, 3, 3}; havestats = 0; sd = d->csd; n = n_var; if (sd->kind & ASL_Sufkind_input) havestats = 1; sd = d->rsd; m = n_con; if (sd->kind & ASL_Sufkind_input) havestats = 1; d->cs = d->rs = 0; if (!havestats || !mipststat && niv + nbv) return; if (method > 0) { stat_map(d->cs = d->cstat, n, map, 6, "incoming cstat"); stat_map(d->rs = d->rstat, m, map, 6, "incoming rstat"); if (objadj) { d->cstat[n] = CPX_BASIC; d->rstat[m] = CPX_FREE_SUPER; } if (i = CPXcopybase(Env, cpx, d->cstat, d->rstat)) { bad_copybase: badret("CPXcopybase", i, 0); } return; } cs = (int*)(use_netopt ? M1alloc((mbas + nbas)*sizeof(int)) : Malloc((mbas + nbas)*sizeof(int))); rs = cs + nbas; m = n_con; n = n_var; L = LUrhs; U = Urhsx; cstat = d->cstat; rstat = d->rstat; for(i = 0; i < m; i++) { if (L[i] <= negInfinity) cs[i] = rstat[i] == 1 ? CPX_AT_UPPER : CPX_BASIC; else cs[i] = rstat[i] == 1 ? CPX_AT_LOWER : CPX_BASIC; } if (nranges) { for(j = 0; j < m; j++) if (L[j] < U[j] && L[j] > negInfinity && U[j] < Infinity) cs[i++] = rstat[j] == 4 ? CPX_BASIC : CPX_AT_UPPER; } L = LUv; U = Uvx; for(j = 0; j < n; j++) { rs[j] = CPX_AT_LOWER; if (L[j] > negInfinity) { if (L[j]) cs[i++] = cstat[j] == 3 ? CPX_BASIC : CPX_AT_LOWER; else rs[j] = cstat[j] == 3 ? CPX_BASIC : CPX_AT_UPPER; if (U[j] < Infinity) goto finite_ub; } else if (U[j] < Infinity) { finite_ub: if (U[j]) cs[i++] = cstat[j] == 4 ? CPX_BASIC : CPX_AT_LOWER; else rs[j] = cstat[j] == 4 ? CPX_BASIC : CPX_AT_LOWER; } else if (cstat[j] != 1) rs[j] = CPX_BASIC; } if (objadj) cs[i] = 1; i = CPXcopybase(Env, cpx, cs, rs); if (use_netopt) { d->cs = cs; d->rs = rs; } else free(cs); if (i) goto bad_copybase; } static int qmatadj(int k, int nr, int os, int *colq, int *colqcnt, double **qmatp) { double badd[3], *oqmat, osd, *qmat, t; int badk[3], i, nbad = 0, nb, w, w1; oqmat = *qmatp; *qmatp = qmat = (double *)Malloc(nr*sizeof(double)); while(nr > k) qmat[--nr] = 0.; osd = os; while(--k >= 0) { t = 0.; if (colqcnt[k]) { t = oqmat[colq[k]]; if (t*osd < 0.) { if (nbad < 3) { badd[nbad] = t; badk[nbad] = k; } nbad++; } } qmat[k] = t; } free(oqmat); if (!nbad) return 0; fprintf(Stderr, "%d diagonal QP coefficients of the wrong sign:\n", nbad); if ((nb = nbad) > 3) nb = 3; w = 8; for(i = 0; i < nb; i++) { w1 = strlen(var_name(badk[i])); if (w < w1) w = w1; } fprintf(Stderr, "Variable%.*s Diagonal\n", w-8, ""); for(i = 0; i < nb; i++) fprintf(Stderr, "%-*s %g\n", w, var_name(badk[i]), 0.5*badd[i]); solve_result_num = 540; asl->i.uinfo = "Diagonal QP Hessian has elements of the wrong sign."; return 1; } static void sos_kludge(int nsos, int *sosbeg, double *sosref) { /* Adjust sosref if necessary to accommodate CPLEX's */ /* undocumented requirement that sosref values differ */ /* by at least 1e-10. */ int i, j, k; double t, t1; for(i = j = 0; i++ < nsos; ) { k = sosbeg[i]; t = sosref[j]; while(++j < k) { t1 = sosref[j]; t += 1e-10; if (t1 <= t) sosref[j] = t1 = t + 1e-10; t = t1; } } } #ifdef CPXERR_QCP_SENSE static void Surprise(ASL *asl, int n, char *who) { char msgbuf[64]; sprintf(msgbuf, "Surprise return %d from %s.", n, who); nonlin(1, 561, msgbuf); } static Char** linadj(ASL *asl, int *ka, int *ia, double *a, int **kaqp, int **kalqp, int **iaqp, double **aqp, int **nelqcp, int ***rowqcp, int ***colqcp, double ***qcmatp) { /* Move linear parts of nqc quadratic constraints from ka, ia, a */ /* to kaq, kalq, iaq, aq and corresponding Cgrad pointers and return a */ /* pointer to the relevant allocation. */ cgrad **cgp, *cg, *cga, *cg0; double *aq, **qcmat, *x, *y; fint *colqf, *cqf, *rowqf; int i, i1, i2, j, k, nl, nqc, m, m0, n, nelq, nqcnl; int **colqc, *iaq, *kalq, *kaq, *kaq0, *nelqc, **rowqc, *z, *z1; size_t L; n = n_var; nqc = nlc; j = nzc; for(i = nl = 0; i < j; i++) if (ia[i] < nqc) nl++; cg = cga = (cgrad*)Malloc(nqc*(sizeof(int)+sizeof(cgrad*)) + nl*sizeof(cgrad)); Cgrad = cgp = (cgrad**)(cga + nl); kaq0 = (int*)(cgp + nqc); L = (char*)kaq0 - (char*)cga; memset(kaq0, 0, nqc*sizeof(int)); memset(cgp, 0, nqc*sizeof(cgrad*)); for(i = j = 0; i < n; i++) { for(k = ka[i+1]; j < k; j++) if ((i1 = ia[j]) < nqc) { kaq0[i1]++; cg->varno = i; cg->coef = a[j]; cg->next = cgp[i1]; cgp[i1] = cg++; } } x = LUrhs; y = Urhsx; for(i = nl = nqcnl = 0; i < nqc; i++) { if (x[i] > negInfinity && y[i] < Infinity) { badretfmt(562, "Constraint %s is not convex quadratic since it is %s constraint.", con_name(i), x[i] == y[i] ? "an equality" : "a two-sided"); exit(4); } k = nl; nl += kaq0[i]; kaq0[i] = k; j = mqpcheck(-(i+1), 0, 0, 0); if (j < 0) { nonlin(j == -2, 558, "a quadratic constraint involving division by 0"); nonlin(1, 550, "a nonquadratic nonlinear constraint"); } nonlin(j == 0, 559, "CPLEX driver bug: no quadratic terms in \"nonlinear\" constraint"); nqcnl += j; } *aqp = aq = (double*)Realloc(cga, nl*sizeof(cgrad) + nqc*sizeof(cgrad*) + nqc*(sizeof(double*) + 2*sizeof(int*)) + (3*nqc + 2*nqcnl + nl)*sizeof(int) + (nl+nqcnl)*sizeof(double)); x = aq + nl; cga = (cgrad*)(x + nqcnl); Cgrad = cgp = (cgrad**)(cga + nl); *qcmatp = qcmat = (double**)(cgp + nqc); *rowqcp = rowqc = (int**)(qcmat + nqc); *colqcp = colqc = rowqc + nqc; *kaqp = kaq = (int*)(colqc + nqc); *kalqp = kalq = kaq + nqc; *nelqcp = nelqc = kalq + nqc; z = nelqc + nqc; *iaqp = iaq = z + 2*nqcnl; kaq0 = (int*)((char*)aq + L); if (kaq0 < kaq) for(i = nqc; i-- > 0; ) kaq[i] = kaq0[i]; else for(i = 0; i < nqc; i++) kaq[i] = kaq0[i]; memset(cgp, 0, nqc*sizeof(cgrad*)); for(i = j = m = 0; j < n; j++) { ka[j] = m0 = m; for(k = ka[j+1]; i < k; i++) if ((i1 = ia[i]) < nqc) { iaq[i2 = kaq[i1]++] = j; aq[i2] = a[i]; } else { ia[m] = i1 - nqc; a[m++] = a[i]; } } nzc = ka[n] = m; for(i = nqc; --i > 0; ) kaq[i] = kaq[i-1]; kaq[0] = 0; j = nl; for(i = nqc; i > 0; ) { k = kaq[--i]; cg0 = 0; while(j > k) { cg = cga++; cg->next = cg0; cg0 = cg; cg->coef = aq[--j]; cg->varno = iaq[j]; } cgp[i] = cg0; } for(i = m = 0; i < nqc; i++) { nelqc[i] = nelq = mqpcheck(-(i+1), &rowqf, &colqf, &y); qcmat[i] = x; for(j = 0; j < nelq; j++) *x++ = 0.5*y[j]; rowqc[i] = z1 = z; colqc[i] = z += nelq; cqf = colqf; i1 = *++cqf; for(j = k = 0; j < nelq; j++) { while (j >= i1) { k++; i1 = *++cqf; } *z1++ = rowqf[j]; *z++ = k; } free(colqf); free(rowqf); free(y); kaq[i] = m0 = m; for(cg = cgp[i]; cg; cg = cg->next) if (cg->coef) { iaq[m] = cg->varno; aq[m++] = cg->coef; } kalq[i] = m - m0; } return M1record((Char*)aq); } #endif /*CPXERR_QCP_SENSE*/ #ifdef Uselazy typedef struct LazyInfo { char *sense[2], **rowname[2]; int *colno[2], nz[2], *rowbeg[2], rows[2]; double *matval[2], *rhs[2]; } LazyInfo; Char ** lazyadj(ASL *asl, LazyInfo *LI, int n, int nint, int *mp, double *b, char *senx, int *ka, int *kal, int *ia, double *a, double *rngvec, char **rname) { Char *rv; SufDesc *lp; char *nn, *nn1, *sense, **rowname; double *matval, *rhs; int *colno, i, i1, i2, j, j0, j1, k, m, nr[3], nrt, nt[2], nz, *rl, *rowbeg, *z; size_t Lnn, Lrl; nr[0] = nr[1] = nr[2] = 0; rv = 0; if (!(uselazy & 3) || !nint) goto done; lp = suf_get("lazy", ASL_Sufkind_con); if (!(z = lp->u.i)) goto done; m = *mp; /* Expect .lazy values, i.e., values in z, to be 0, 1, or 2 */ /* with 1 ==> lazy constraint, 2 ==> user cut. */ /* For simplicity, we treat 3 as 1 and ignore bits beyond the first two. */ for(i = 0; i < m; i++) { if ((j = z[i] & uselazy) && j <= 2) { ++nr[j = 1 - (j&1)]; if (senx[i] == 'R') { ++nr[j]; ++nr[2]; } } } /* nr[0] = number of lazy constraints */ /* nr[1] = number of user cuts */ /* nr[2] = number of range constraints among above */ if (!(nrt = nr[0] + nr[1])) goto done; *mp = m - (nrt - nr[2]); nt[1] = 0; nt[0] = nr[0]; /* nt[0] = for user cuts, nt[1] for lazy constraints */ if (nr[2]) for(i = 0; i < m; i++) { if (j = (z[i]&3)) { z[i] = ++nt[j &= 1]; if (senx[i] == 'R') ++nt[j]; } else z[i] = 0; } else for(i = 0; i < m; i++) z[i] = (j = (z[i]&3)) ? ++nt[j&1] : 0; for(i = nz = 0; i < n; i++) { for(j = ka[i], k = j + kal[i]; j < k; j++) if (z[ia[j]]) nz++; } Lnn = Lrl = 0; if (rname) Lnn = nrt*sizeof(char*); if (nr[2]) { /* ranges */ Lrl = nrt; for(i = 0; i < n; i++) { for(j = ka[i], k = j + kal[i]; j < k; j++) if (z[j1 = ia[j]] && senx[j1] == 'R') nz++; } if (rname) for(i = 0; i < m; i++) if (senx[i] == 'R') Lnn += strlen(rname[i]) + 3; } matval = (double*)Malloc((nz+nrt)*(sizeof(double)+sizeof(int)) + (Lrl+2)*sizeof(int) + nrt + Lnn); rv = (Char*)matval; rhs = matval + nz; if (rname) { rowname = (char**)(rhs + nrt); rowbeg = (int*)(rowname + nrt); } else { rowname = 0; rowbeg = (int*)(rhs + nrt); } colno = rowbeg + nrt + 2; rl = colno + nz; sense = (char*)(rl + Lrl); nn = sense + nrt; memset(rowbeg, 0, nrt*sizeof(int)); if (Lrl) memset(rl, 0, Lrl*sizeof(int)); for(i = 0; i < n; i++) { for(j = ka[i], k = j + kal[i]; j < k; j++) if (j1 = z[ia[j]]) ++rowbeg[j1-1]; } if (nr[2]) { for(i = 0; i < m; i++) if ((j = z[i]) && senx[i] == 'R') rl[j] = rowbeg[j] = rowbeg[j-1]; } for(i = k = 0; i < nrt; i++) { j = rowbeg[i]; rowbeg[i] = k; k += j; } for(i = k = 0; i < m; i++) if (!z[i]) z[i] = k--; for(i = j1 = 0; i < n; i++) { j = ka[i]; ka[i] = j0 = j1; for(k = j + kal[i]; j < k; j++) if ((i1 = z[ia[j]]) > 0) { i2 = rowbeg[i1-1]++; colno[i2] = i; matval[i2] = a[j]; } else { ia[j1] = -i1; a[j1++] = a[j]; } kal[i] = j1 - j0; } if (nr[2]) { for(i = 0; i < nrt; i++) if (j = rl[i]) { k = rowbeg[i]; rowbeg[i] = k + j; memcpy(colno + k, colno - j + k, j*sizeof(int)); memcpy(matval + k, matval - j + k, j*sizeof(double)); } } for(i = k = 0; i < nr[0]; i++) { j = rowbeg[i]; rowbeg[i] = k; k = j; } LI->nz[0] = k; LI->nz[1] = nz - k; for(j1 = 0; i < nrt; i++) { j = rowbeg[i]; rowbeg[i] = j1; j1 = j - k; } rowbeg[i+1] = j1; for(; i > nr[0]; --i) rowbeg[i] = rowbeg[i-1]; rowbeg[i] = k; LI->sense[0] = sense; LI->sense[1] = sense + nr[0]; for(i = 0; i < m; i++) { if ((j = z[i]) > 0) { rhs[--j] = b[i]; if ((sense[j] = senx[i]) == 'R') { sense[j] = 'G'; sense[++j] = 'L'; rhs[j] = b[i] + rngvec[i]; if (rname) { nn1 = strcpy1(rowname[j] = nn, rname[i]); nn = strcpy(nn1, ".u"); } } } else { b[j = -j] = b[i]; rngvec[j] = rngvec[i]; senx[j] = senx[i]; } } if (rname) { LI->rowname[0] = rowname; LI->rowname[1] = rowname + nr[0]; for(i = 0; i < m; i++) if ((j = z[i]) > 0) rowname[j-1] = rname[i]; else rname[-j] = rname[i]; } else LI->rowname[0] = LI->rowname[1] = 0; LI->colno[0] = colno; LI->colno[1] = colno + k; LI->rowbeg[0] = rowbeg; LI->rowbeg[1] = rowbeg + k + 1; LI->matval[0] = matval; LI->matval[1] = matval + k; LI->rhs[0] = rhs; LI->rhs[1] = rhs + nr[0]; done: LI->rows[0] = nr[0]; LI->rows[1] = nr[1]; return M1record(rv); } #endif /*Uselazy*/ static void amplin(ASL *asl, cpxlp **pcpx, FILE **nl, dims *d, int *nelqp, int *nintp, char **av) { int *ia, *ia1, *ia2, *ja, *ka, *ka1, *ka2, *kal, *kal1, *kal2; double *a, *a1, *b, *b1, *c, *c1, *l, *l1, *le, *lrhs, *lx, *rngvec, *rv1, *u, *u1, *urhs, *ux; double nos, os; ograd *og, *og1; int i, j, k, m, m0, mq, n, n0, nbv1, nextra, nint, nint1, nqc, nr, nsos, nz, nz1, nzc0, nzextra, nzr; char **cname, **rname, *s, *senx; Char **zap[6]; #ifdef BARRIER fint nelqf, *colqf, *rowqf; int havestart, nelq, *colq, *colqcnt, *rowq; double *cdual, *cprim, *qmat, *rdual, *rprim; #undef Want_mqpcheck #ifdef BARRIER_FOR_QP #ifdef BARRIER #define Want_mqpcheck #endif #else /*!BARRIER_FOR_QP, i.e., >= 8.0*/ #define Want_mqpcheck #endif #ifndef Want_mqpcheck #undef CPXERR_QCP_SENSE #endif #ifdef CPXERR_QCP_SENSE /* CPLEX version >= 9.0 */ double *aq, **qcmat; int **colqc, *iaq, *kaq, *kalq, *nelqc, **rowqc; #endif /*CPXERR_QCP_SENSE*/ #endif /*BARRIER*/ char probname[48]; cpxlp *cpx; #ifdef CPLEX_MIP char *ctype; char *sostype; int nsosnz, *sosbeg, *sosind; double *sosref; #ifdef CPX_PARAM_IISIND /* version < 9.2b */ int copri[2], **p_sospri, *sospri; #else #define copri 0 #define p_sospri 0 #endif #endif #ifdef CPX_CON_INDICATOR LCADJ_Info *lci; cde *logc; int nlogc; #else #define nlogc 0 #endif /*CPX_CON_INDICATOR*/ #ifdef Uselazy LazyInfo LI; #endif /*Uselazy*/ /* change default display to 0 */ CPXsetintparam(Env, CPX_PARAM_SIMDISPLAY, 0); #ifdef CPLEX_MIP /* change default mipdisplay to 0 */ CPXsetintparam(Env, CPX_PARAM_MIPDISPLAY, 0); #endif #ifdef BARRIER /* change default bardisplay to 0 */ CPXsetintparam(Env, CPX_PARAM_BARDISPLAY, 0); #endif aggtries = 0; if (!(mint_val[set_objno].U = n_obj)) objno = 0; #ifndef CPXERR_QCP_SENSE /* if CPLEX version >= 9.0 */ nonlin(nlc, 550, "nonlinear constraints"); #endif nonlin(plterms, 554, "piecewise-linear terms"); if (getopts(av, &Oinfo)) { if (amplflag) badretfmt(560, "Error in $cplex_options."); exit(1); } obj_no = objno - 1; #ifndef CPX_PARAM_FEASOPTMODE /* < 9.2b */ if (want_iis #ifdef CPXERR_QCP_SENSE /* if CPLEX version >= 9.0 */ && !nlc #endif ) { if (want_iis == 3) want_iis = 2; /* The IIS finder requires use of primal or dual simplex. */ if (Optimize && Optimize != CPXprimopt #ifdef CPXERR_QCP_SENSE /* if CPLEX version >= 9.0 */ && Optimize != CPXdualopt #endif ) { printf("Assuming primalopt so iisfind will work.\n"); Optimize = CPXprimopt; algname = baralgname = ""; } } #endif /*CPX_PARAM_FEASOPTMODE*/ if (!Optimize) { Optimize = #ifdef CPXERR_QCP_SENSE nlc | nlo ? CPXqpopt : #endif CPXlpopt; lpoptalg = CPX_ALG_AUTOMATIC; algname = baralgname = ""; } m = n_con + 1; /* allow elbow room for obj_adj */ n = n_var + 1; nzr = nzc + 1; #ifdef CPX_CON_INDICATOR /* >= 9.2b */ nlogc = n_lcon; #endif d->cstat = (int*)M1zapalloc((m+n+2+nlogc)*sizeof(int)); d->rstat = d->cstat + n + 1; d->csd = suf_iput("sstatus", ASL_Sufkind_var, d->cstat); d->rsd = suf_iput("sstatus", ASL_Sufkind_con, d->rstat); b = LUrhs = (double *)M1alloc(2*Sizeof(double)*(m+n)); Urhsx = b + m; LUv = Urhsx + m; Uvx = LUv + n; a = A_vals = (double *)Malloc(nzr*Sizeof(double) + ((fint)nzr + n + 1)*sizeof(int)); zap[0] = M1record((Char*)a); zap[1] = zap[2] = zap[3] = zap[4] = zap[5] = 0; ia = A_rownos = (int *)(a + nzr); ka = A_colstarts = ia + nzr; #ifdef Want_mqpcheck nint = nbv + niv + nlvbi + nlvci + nlvoi; if (Optimize == Optimize2 || Optimize == Optimizebar || nlo || nlc || nint && mipstval) want_xpi0 = 3; want_deriv = 0; qp_read(*nl,ALLOW_CLP); *nl = 0; /* Indicate closed file -- in case we're */ /* subsequently interrupted. */ nelqf = 0; if (obj_no >= 0 && obj_no < n_obj && (nelqf = mqpcheck(obj_no, &rowqf, &colqf, &qmat))) { if (nelqf < 0) { nonlin(nelqf == -2, 555, "a quadratic objective involving division by 0"); nonlin(1, 551, "a nonlinear objective"); } #ifdef BARRIER_FOR_QP nonlin(nint, 553, "integer variables and a quadratic objective"); #endif crossover = 0; #ifndef BARRIER_FOR_QP if (Optimize == Optimize2) #endif set_baropt(); method = 1; } #ifdef BARRIER_FOR_QP else nonlin(nlvoi, 552, "nonlinear integer variables"); #endif nqc = nlc; #ifdef CPXERR_QCP_SENSE /* if CPLEX version >= 9.0 */ if (nqc > 0) zap[4] = linadj(asl, ka, ia, a, &kaq, &kalq, &iaq, &aq, &nelqc, &rowqc, &colqc, &qcmat); #endif /*CPXERR_QCP_SENSE*/ #else /*Want_mqpcheck*/ nonlin(nlvoi, 552, "nonlinear integer variables"); f_read(*nl, 0); *nl = 0; #endif/*Want_mqpcheck*/ nsos = 0; #ifdef CPLEX_MIP if (!relax) { #ifdef CPX_PARAM_IISIND /* version < 9.2b */ copri[0] = objpri; copri[1] = conpri; p_sospri = &sospri; #endif i = ASL_suf_sos_explict_free; if (!sos) i |= ASL_suf_sos_ignore_sosno; if (!sos2) i |= ASL_suf_sos_ignore_amplsos; nsos = suf_sos(i, &nsosnz, &sostype, p_sospri, copri, &sosbeg, &sosind, &sosref); } #endif m = m0 = n_con; n = n0 = nr = n_var; nzc0 = nzc; nint = nbv + niv + nlvoi + nlvci + nlvbi; if (nint #ifdef CPLEX_MIP && relax #endif ) { if (nint) { printf("Ignoring integrality of %d variable%s.\n", nint, nint > 1 ? "s" : ""); need_nl = nint = 0; } } *nelqp = nelqf; *nintp = nint1 = nint + nsos; if (use_netopt == 1 && !lnc) use_netopt = 0; if (nint1 || m <= 0 || nlc > 0) { method = 1; use_netopt = 0; } else if (!method) method = use_netopt ? 1 : dual_thresh > 0 && m - n > dual_thresh || m > dual_ratio*n ? -1 : 1; nbv1 = nbv; if (method < 0 && use_netopt == 1) use_netopt = 0; if (!nint) niv = nbv = nbv1 = 0; og = 0; if (obj_no >= 0 && obj_no < n_obj) { og = Ograd[obj_no]; if (!objsen) objsen = objtype[obj_no] ? -1 : 1; obj_adj = objconst(obj_no); } else if (!objsen) objsen = 1; #ifndef BARRIER nonlin(nl_obj(obj_no), 556, "nonlinear objective terms"); #endif *stub_end = 0; for(i = 0, og1 = og; og1; i++) og1 = og1->next; sprintf(probname, "c%dv%di%do%d", n_var, n_con, niv, i); if (!(cpx = CPXcreateprob(Env, &i, probname))) badret("CPXcreateprob", i, 531); *pcpx = cpx; n = n0; m = m0; nextra = 0; if (method < 0) { /* solve dual */ l = LUv; u = Uvx; for(le = l + n0; l < le; l++, u++) { if (*l > negInfinity && *l) nextra++; if (*u < Infinity && *u) nextra++; } nzextra = 0; if (nranges) { ja = (int *)Malloc(m0*sizeof(int)); memset((char *)ja, 0, m0*sizeof(int)); ia1 = ia + nzc0; while(ia1 > ia) ja[*--ia1]++; l = LUrhs; u = Urhsx; for(le = l + m0; l < le; l++, u++) if (*l < *u && *l > negInfinity && *u < Infinity) nzextra += ja[l - LUrhs]; free(ja); } m = n0; n = m0 + nranges + nextra; } #ifdef OBJ_ADJ if (obj_adj || m <= 0) { objadj = 1; n++; nextra++; } #endif nz = nzc0 + nextra; if (method < 0) /* dual */ { nz1 = nz += nzextra; a = (double *)Malloc((nz1+2L*n+m)*sizeof(double) + (nz1+1L+n)*sizeof(int)); *zap[0] = (Char*)a; l = a + nz1; u = l + n; b = u + n; ia = (int *)(b + m); ka = ia + nz1; nr = n; } else { m += objadj; #ifdef Student_Edition if (n > 300 || m > 300) { fflush(stdout); fprintf(Stderr, "\nSorry, the student edition is limited to 300 variables and 300\n\ constraints. After adjustments to handle the constant term in\n\ the objective, you have %d variables and %d constraints.\n", n, m); exit(1); } #endif nr += objadj; nz1 = nz; l = LUv; u = Uvx; if (nint1) { #ifdef CPLEX_MIP ctype = M1alloc(nr); if (i = n - nbv1 - niv - nextra) memset(ctype, 'C', i); if (nbv1) memset(ctype+i, 'B', nbv1); if (niv) memset(ctype+i+nbv1, 'I', niv); if (nextra) memset(ctype+i+nbv1+niv, 'C', nextra); #ifndef BARRIER_FOR_QP if (nlvbi) for(j = nlvb, i = j - nlvbi; i < j; i++) ctype[i] = l[i] == 0. & u[i] == 1. ? 'B' : 'I'; if (nlvci) for(j = nlvc, i = j - nlvci; i < j; i++) ctype[i] = l[i] == 0. & u[i] == 1. ? 'B' : 'I'; if (nlvoi) for(j = nlvo, i = j - nlvoi; i < j; i++) ctype[i] = l[i] == 0. & u[i] == 1. ? 'B' : 'I'; #endif #else badretfmt(557, "CPLEX's MIP option is needed to solve problems with\n%s.\n", "nonconvex (nonconcave) piecewise-linear terms"); exit(1); #endif } } d->x = (double *)M1zapalloc((m+nlogc+2L*nr)*sizeof(double) + m); d->y = d->x + nr; d->c = c = d->y + m + nlogc; d->rtype = senx = (char*)(c + nr); rngvec = (double *)Malloc(m*Sizeof(double) + nr*Sizeof(int)); zap[1] = M1record((Char*)rngvec); kal = (int *)(rngvec + m); #ifdef CPLEX_MIP if (nint1) { Optimize = CPXmipopt; baralgname = ""; } #endif if (method > 0) { b = (double*)Malloc(m*Sizeof(double)); zap[2] = M1record((Char*)b); } b1 = b + m; s = senx + m; rv1 = rngvec + m; ia1 = ia + nz; a1 = a + nz; l1 = l + n; u1 = u + n; kal1 = kal + n; ka1 = ka + n; lrhs = LUrhs + m0; urhs = Urhsx + m0; if (method < 0) { /* dual */ os = objsen; nos = -os; objsen = -objsen; memset(b, 0, m*sizeof(double)); c1 = c + (m0 + nranges + nextra); #ifdef OBJ_ADJ if (objadj) { *--l1 = *--u1 = 1; *--kal1 = 0; *--ka1 = nz1; *--c1 = obj_adj; } #endif j = n0; lx = LUv + n0; ux = Uvx + n0; do { *--rv1 = 0; *--s = 'E'; --j; if (*--ux < Infinity) if (*ux) { *--kal1 = 1; *--ka1 = --nz1; *--ia1 = j; *--a1 = -1; *--c1 = nos * *ux; *--l1 = 0; *--u1 = Infinity; } else *s = 'G'; if (*--lx > negInfinity) if (*lx) { *--kal1 = 1; *--ka1 = --nz1; *--ia1 = j; *--a1 = 1; *--c1 = os * *lx; *--l1 = 0; *--u1 = Infinity; } else *s = 'L'; } while(lx > LUv); for(; og; og = og->next) b[og->varno] = os * og->coef; memset((char *)kal, 0, m0*sizeof(int)); ia1 = A_rownos; ia2 = ia1 + nzc0; while(ia1 < ia2) kal[*ia1++]++; for(i = j = 0; i < m0; i++) ka[i] = j += kal[i]; a1 = A_vals + nzc0; j = n0; while(--j >= 0) { ia1 = A_rownos + A_colstarts[j]; while(ia2 > ia1) { ia[i = --ka[*--ia2]] = j; a[i] = *--a1; } } if (nranges) { /* This could be merged with the following while * loop but for cplex's undocumented assumption * that elements of ka are in ascending order! */ kal2 = kal + m0; ka2 = ka + m0; for(i = m0; --i >= 0; ) { --ka2; --kal2; if (*--lrhs < *--urhs && *lrhs > negInfinity && *urhs < Infinity) { *--kal1 = j = *kal2; *--ka1 = nz1 -= j; memcpy((char *)(a+nz1), (char *)(a+*ka2), j*sizeof(double)); memcpy((char *)(ia+nz1), (char *)(ia+*ka2), j*sizeof(int)); *--c1 = os * *urhs; *--l1 = negInfinity; *--u1 = 0; } } lrhs = LUrhs + m0; urhs = Urhsx + m0; } i = m0; while(--i >= 0) { --c1; --l1; --u1; --urhs; if (*--lrhs <= negInfinity) { *c1 = os * *urhs; *l1 = negInfinity; *u1 = 0.; } else { *u1 = Infinity; *c1 = os * *lrhs; *l1 = *urhs == *lrhs ? negInfinity : 0.; } } free(A_vals); } else { /* primal */ memset(c, 0, n0*sizeof(double)); #ifdef OBJ_ADJ if (objadj) { c[n0] = obj_adj; /* fixed adjustment to objective */ *--l1 = 0; *--u1 = 2; *--ia1 = m0-nqc; *--a1 = *--b1 = 1; *--kal1 = 1; *--ka1 = --nz1; *--s = 'E'; *--rv1 = 0; } #endif for(; og; og = og->next) c[og->varno] = og->coef; i = m0; while(--i >= 0) { --b1; *--rv1 = 0; --s; --urhs; if ((*b1 = *--lrhs) <= negInfinity) { *s = 'L'; *b1 = *urhs; } else if (*urhs >= Infinity) *s = 'G'; else if (*lrhs < *urhs) { *s = 'R'; *rv1 = *urhs - *lrhs; } else *s = 'E'; } ka2 = ka + n0; *ka2 = nz1; while(ka2 > ka) { --ka2; *--kal1 = ka2[1] - ka2[0]; } } mbas = m; nbas = n; cname = rname = 0; if (startbas || endbas || startvec || endvec || wrtfname || Optimize == CPXprimopt || Optimize == CPXdualopt || Optimize == CPXlpopt || Optimize == CPXqpopt || parval(CPX_PARAM_XXXIND)) { make_names(&cname, &rname); zap[3] = M1record((Char*)cname); } mq = m - nqc; #ifdef Uselazy i = mq; zap[5] = lazyadj(asl, &LI, n, nint, &mq, b+nqc, senx+nqc, ka, kal, ia, a, rngvec+nqc, rname ? rname+nqc : 0); if ((j = LI.rows[0] + LI.rows[1] - (i - mq)) > 0) { /* unlikely; allocate extra space... */ j += mq + nqc + nlogc; d->y = (double*)M1zapalloc(j*(sizeof(double) + sizeof(int))); ia1 = (int*)(d->y + j); memcpy(ia1, d->rstat, n_con * sizeof(int)); d->rsd->u.i = d->rstat = ia1; } #endif /*Uselazy*/ i = CPXcopylpwnames(Env, cpx, n, mq, objsen, c, b+nqc, senx+nqc, ka, kal, ia, a, l, u, rngvec+nqc, cname, rname ? rname+nqc : 0); if (i) badret("CPXcopylpwnames", i, 531); #ifdef CPXERR_QCP_SENSE /* if CPLEX version >= 9.0 */ lrhs = LUrhs; urhs = Urhsx; for(i = 0; i < nqc; i++) { j = CPXaddqconstr(Env, cpx, kalq[i], nelqc[i], b[i], senx[i], iaq+kaq[i], aq+kaq[i], rowqc[i], colqc[i], qcmat[i], rname ? rname[i] : 0); if (j) Surprise(asl, j, "CPXaddqconstr"); } mbas += nqc; #endif /*CPXERR_QCP_SENSE*/ #ifdef CPLEX_MIP if (nint1) { if (i = CPXcopyctype(Env, cpx, ctype)) badret("CPXcopyctype", i, 531); if (nsos) { sos_kludge(nsos, sosbeg, sosref); #ifdef CPX_PARAM_IISIND /* version < 9.2b */ i = CPXcopysos(Env,cpx,nsos,nsosnz,sostype,sospri, sosbeg,sosind,sosref); #else i = CPXcopysos(Env,cpx,nsos,nsosnz,sostype, sosbeg,sosind,sosref,0); #endif free(sosref); if (i) badret("CPXcopysos", i, 531); } if (nint) { mip_priorities(asl, cpx); if (mipstval && X0 && (i = nbv1 + niv + nlvbi + nlvci + nlvoi)) set_mipinit(asl, cpx, i); } if (workfiledir) CPXsetstrparam(Env, CPX_PARAM_WORKDIR, workfiledir); } #endif #ifdef Uselazy if (LI.rows[0]) { CPXgetintparam(Env, CPX_PARAM_REDUCE, &i); if (i & ~1) { i &= 1; fprintf(Stderr, "Assuming prereduce = %d for lazy constraints.\n", i); if (j = CPXsetintparam(Env, CPX_PARAM_REDUCE, i)) badret("CPXsetintparam(CPX_PARAM_REDUCE)", j, 531); } if (i = CPXaddlazyconstraints(Env, cpx, LI.rows[0], LI.nz[0], LI.rhs[0], LI.sense[0], LI.rowbeg[0], LI.colno[0], LI.matval[0], LI.rowname[0])) badret("CPXaddlazyconstraints", i, 531); } if (LI.rows[1]) { CPXgetintparam(Env, CPX_PARAM_PRELINEAR, &i); if (i) { fprintf(Stderr, "Assuming prelinear = 0 for user cuts.\n"); if (j = CPXsetintparam(Env, CPX_PARAM_PRELINEAR, 0)) badret("CPXsetintparam(CPX_PARAM_PRELINEAR)", j, 531); } if (i = CPXaddusercuts(Env, cpx, LI.rows[1], LI.nz[1], LI.rhs[1], LI.sense[1], LI.rowbeg[1], LI.colno[1], LI.matval[1], LI.rowname[1])) badret("CPXaddusercuts", i, 531); } #endif #ifdef BARRIER havestart = 0; if (Optimize == Optimize2 || Optimize == Optimizebar) havestart = startcomp(asl, n, m, nextra, ka, kal, ia, a, b, c, &cdual, &cprim, &rdual, &rprim); #endif if (nelqf) { nelq = (int)nelqf; colq = (int*)Malloc(2*sizeof(int)*nr); colqcnt = colq + nr; if (sizeof(fint) != sizeof(int)) { /* should not happen */ rowq = (int*)Malloc(nelq*sizeof(int)); for(i = 0; i < nelq; i++) rowq[i] = (int)rowqf[i]; free(rowqf); } else rowq = (int*)rowqf; k = n_var; for(i = 0; i < k; i++) { colq[i] = (int)colqf[i]; colqcnt[i] = (int)(colqf[i+1] - colqf[i]); } for(j = colqf[k]; i < nr; i++) { colq[i] = j; colqcnt[i] = 0; } free(colqf); for(i = 0; ; i++) { if (i == k) { i = qmatadj(k, nr, objsen, colq, colqcnt, &qmat); if (!i) { for(i = k; i < nr; i++) qmat[i++] = 0.; i = CPXcopyqpsep(Env,cpx,qmat); if (i) badret("CPXcopyqpsep", i,531); } free(rowq); free(qmat); free(colq); if (i) exit(1); baralgname = "separable QP "; break; } if (!(j = colqcnt[i])) continue; if (j > 1 || rowq[colq[i]] != i) { i = CPXcopyquad(Env,cpx,colq, colqcnt,rowq,qmat); free(rowq); free(qmat); free(colq); if (i) badret("CPXcopyquad", i, 531); baralgname = "QP "; break; } } } #ifdef CPX_CON_INDICATOR if (nlogc) { lci = 0; logc = ((ASL_fg*)asl)->I.lcon_de_; for(i = 0; i < nlogc; i++) add_indicator(asl, cpx, i, &lci, logc[i].e); M1free_ASL(&asl->i, lci->M1state1, lci->M1state2); } #endif /*CPX_CON_INDICATOR*/ #ifdef BARRIER if (havestart) { if (i = CPXcopystart(Env,cpx,0,0,cprim,rprim,cdual,rdual)) badret("CPXcopystart", i, 0); } #endif for(i = 6; i > 0; ) if (zap[--i]) { free(*zap[i]); *zap[i] = 0; } get_statuses(asl, cpx, d); cbi.disp = parval(CPX_PARAM_SIMDISPLAY); #ifdef CPLEX_MIP cbi.mipdisp = parval(CPX_PARAM_MIPDISPLAY); #endif if (prestats && (dispzap = !cbi.disp || nint && !cbi.mipdisp) #ifndef NO_BARRIER || Optimize == Optimize2 #endif ) { zap_lpcbf = 1; cbi.agg = parval(CPX_PARAM_AGGIND); cbi.m = m; cbi.n = n; cbi.nint = nint; cbi.pres = parval(CPX_PARAM_PREIND); #ifdef CPXERR_IN_INFOCALLBACK CPXsetinfocallbackfunc(Env, lpcbf, 0); #else CPXsetlpcallbackfunc(Env, lpcbf, 0); CPXsetmipcallbackfunc(Env, lpcbf, 0); #endif } else { #ifdef CPXERR_IN_INFOCALLBACK #else CPXsetlpcallbackfunc(Env, breakcallback, 0); CPXsetmipcallbackfunc(Env, breakcallback, 0); #endif } breaking = 1; } /* The following routine was named "round", but HPUX 11 reportedly */ /* could not cope with this name. */ static int xround(double *x, fint n, int assign, double *w) { double d, dx, *xe, y; int m = 0; dx = *w; for(xe = x + n; x < xe; x++) { y = floor(*x + 0.5); if ((d = *x - y) != 0.) { if (d < 0) d = -d; if (dx < d) dx = d; m++; if (assign) *x = y; } } *w = dx; return m; } static char * failstat(int j) { static char buf[32]; switch(j) { /* cases and text provided by Ed Klotz */ case CPXERR_NO_MEMORY: return "insufficient memory"; case CPXERR_NO_PROBLEM: return "no problem"; case CPXERR_SINGULAR: return "singular basis"; case CPXERR_PRIIND: return "invalid pricing setting"; #ifdef CPXERR_BOUNDS_INFEAS case CPXERR_BOUNDS_INFEAS: return "contradictory bounds"; #endif case CPXERR_PRESLV_INForUNBD: return "presolve: infeasible or unbounded problem"; case CPXERR_INDEX_RANGE: return "illegal list length"; #ifdef CPXERR_NET_IMBALANCE case CPXERR_NET_IMBALANCE: return "an infeasible or unbounded network"; #endif case CPXERR_BAD_METHOD: return "unknown method after network optimization"; #ifdef CPXERR_PRESLV_TIME_LIM /* CPLEX 11 */ case CPXERR_PRESLV_TIME_LIM: return "time limit exceeded in CPLEX's presolve"; case CPXERR_THREAD_FAILED: return "thread creation failed"; #endif } sprintf(buf, "CPLEX error # %d.", j); return buf; } static int statadjust(cpxlp *cpx, int stat) { #ifdef CPX_STAT_OPTIMAL /* >= 8.0 */ static int statmap[23] = { 1, 3, 2, 31, 11, 9, -1, -1, -1, 5, 7, 4, 12, 56, 57, 58, 59, 60, 61, 24, 22, 23, 31 }; int adj, dfeas, pfeas, solmeth, soltype; if (stat >= 101 && stat <= 119) return stat + (35 - 101); if (stat > 22 || stat <= 0) { #ifndef CPXERR_ALGNOTLICENSED #define CPXERR_ALGNOTLICENSED 32024 #endif if (stat == CPXERR_ALGNOTLICENSED) return obj_no >= 0 && obj_no < nlo || nlc ? 34 : 32; #ifdef CPXMIP_POPULATESOL_LIM if (stat == CPXMIP_POPULATESOL_LIM) stat = 35; else #endif stat = 0; } else { adj = 0; pfeas = dfeas = 1; switch(stat) { case CPX_STAT_INFEASIBLE: CPXsolninfo(Env, cpx, &solmeth, &soltype, &pfeas, &dfeas); if (solmeth == CPX_ALG_BARRIER && (!pfeas || !dfeas)) { adj = pfeas ? 16 : 17; if (!dfeas) adj += 2; } /* no break */ case CPX_STAT_UNBOUNDED: if (method < 0) stat = CPX_STAT_INFEASIBLE + CPX_STAT_UNBOUNDED - stat; break; case CPX_STAT_NUM_BEST: CPXsolninfo(Env, cpx, &solmeth, &soltype, &pfeas, &dfeas); if (solmeth == CPX_ALG_BARRIER) { adj = 16; if (!pfeas) adj++; if (!dfeas) adj += 2; } break; case CPX_STAT_ABORT_IT_LIM: case CPX_STAT_ABORT_TIME_LIM: CPXsolninfo(Env, cpx, &solmeth, &soltype, &pfeas, &dfeas); if (!dfeas) adj = 1; break; case CPX_STAT_ABORT_USER: CPXsolninfo(Env, cpx, &solmeth, &soltype, &pfeas, &dfeas); if (solmeth == CPX_ALG_BARRIER) { if (pfeas && dfeas) adj = 5; else { adj = dfeas ? 1 : 2; if (!pfeas) adj += 2; } } } stat = statmap[stat-1] + adj; } #else if (stat > 100 && stat < 120) stat -= 66; else if (stat > 18 && stat < 44) stat -= 13; else if (stat == 1101) stat = 31; /* should not happen */ else if (stat < 0 || stat > 18) stat = 0; else if (stat >= 2 && stat <= 3 && Optimize == CPXdualopt) stat = 5 - stat; #endif return stat; } static void write_basis(cpxlp *cpx) { if (CPXmbasewrite(Env, cpx, endbas)) { printf("Could not write ending basis to \"%s\"\n", endbas); need_nl = 0; } } static void cud_cadjust(ASL *asl) { int i, m; real *L, *U; m = n_con; L = LUrhs; U = Urhsx; for(i = 0; i < m; i++) if (L[i] <= negInfinity) L[i] = U[i]; } static void Kludge_getbase(dims *d, int *rstat) { /* Kludge around CPLEX bug in rstat values for <= constraints... */ int i, m = mbas; char *rt = d->rtype; for(i = 0; i < m; i++) if (rt[i] == 'L' && rstat[i] == 0) rstat[i] = 2; } static int send_statuses(ASL *asl, cpxlp *cpx, dims *d) { int i, j, m, n; int *cs, *cstat, *rs, *rstat; real *L, *U; static int map[] = {3, 1, 4, 6, 0}; if (!(Oinfo.wantsol & 1) && !amplflag) return 0; cstat = d->cstat; rstat = d->rstat; memset(cstat, 0, n_var*sizeof(int)); memset(rstat, 0, n_con*sizeof(int)); if (method > 0) { if (i = CPXgetbase(Env, cpx, cstat, rstat)) { no_basis: if (i != CPXERR_NO_BASIS) badret("CPXgetbase", i, 0); d->csd->kind &= ~ASL_Sufkind_output; d->rsd->kind &= ~ASL_Sufkind_output; return 1; } Basedebug("spx.bas",cstat,rstat); Kludge_getbase(d, rstat); stat_map(cstat, n_var, map, 4, "outgoing cstat"); stat_map(rstat, n_con, map, 4, "outgoing rstat"); equ_adjust(cstat, rstat); if (costsens) { L = (real*)M1alloc(2*sizeof(real)*(nbas + mbas)); U = L + nbas; if (i = CPXobjsa(Env, cpx, 0, nbas-1, L, U)) badret("CPXobjsa", i, 0); else { suf_rput("down", ASL_Sufkind_var, L); suf_rput("up", ASL_Sufkind_var, U); suf_rput("current", ASL_Sufkind_var, d->c); } L = U + nbas; U = L + mbas; if (i = CPXrhssa(Env, cpx, 0, mbas-1, L, U)) badret("CPXrhssa", i, 0); else { cud_cadjust(asl); suf_rput("down", ASL_Sufkind_con, L); suf_rput("up", ASL_Sufkind_con, U); suf_rput("current", ASL_Sufkind_con, LUrhs); } } return 0; } cs = (int*)M1alloc((mbas + nbas)*sizeof(int)); rs = cs + nbas; if (i = CPXgetbase(Env, cpx, cs, rs)) goto no_basis; m = n_con; n = n_var; Kludge_getbase(d, rs); L = LUrhs; U = Urhsx; for(i = 0; i < m; i++) { if (L[i] <= negInfinity) rstat[i] = cs[i] == CPX_AT_UPPER ? 1 : 4; else rstat[i] = L[i] == U[i] || cs[i] == CPX_BASIC ? 3 : 1; } if (nranges) { for(j = 0; j < m; j++) if (L[j] < U[j] && L[j] > negInfinity && U[j] < Infinity && cs[i++] == CPX_BASIC) rstat[j] = 4; } L = LUv; U = Uvx; for(j = 0; j < n; j++) { if (L[j] > negInfinity) { if (L[j]) cstat[j] = cs[i++] == CPX_BASIC ? 3 : 1; else cstat[j] = rs[j] == CPX_BASIC ? 3 : 1; if (U[j] < Infinity) if ((U[j] ? cs[i++] : rs[j]) == CPX_BASIC) cstat[j] = 4; } else if (U[j] < Infinity) { if (U[j]) cstat[j] = cs[i++] == CPX_BASIC ? 4 : 1; else cstat[j] = rs[j] == CPX_BASIC ? 4 : 1; } else cstat[j] = rs[j] == CPX_BASIC ? 2 : 1; } equ_adjust(cstat, rstat); return 0; } static int send_dray(ASL *asl, cpxlp *cpx, int nelqf) { real proof, *y; if (nelqf) { /* CPLEX 8.0 faulted in this case; */ /* CPLEX 8.1 would issue a message. */ return 2; } y = (real*)M1zapalloc(mbas*sizeof(real)); if (CPXdualfarkas(Env, cpx, y, &proof)) return 1; suf_rput("dunbdd", ASL_Sufkind_con, y); return 0; } static int send_ray(ASL *asl, cpxlp *cpx) { int i, j, n, rc; real *r; if (CPXgetijdiv(Env, cpx, &i, &j)) return 1; if ((n = n_var) < nbas) n = nbas; r = (real*)M1zapalloc(n*sizeof(real)); if (!(rc = CPXgetray(Env, cpx, r))) suf_rput("unbdd", ASL_Sufkind_var, r); return rc; } #ifdef CPX_PARAM_IISIND static void iis_put(ASL *asl, int kind, int n, int *ind, int *stat) { int i, *x; x = (int*)M1zapalloc((&asl->i.n_var_)[kind]*sizeof(int)); suf_iput("iis", kind, x); for(i = 0; i < n; i++) x[ind[i]] = stat[i] + 1; } #endif /*CPX_PARAM_IISIND*/ static int retfrom(char *hbuf, int k, const char *what) { return Sprintf(hbuf, "\nReturn %d from %s.", k, what); } #ifdef CPX_PARAM_FEASOPTMODE /* >= 9.2b */ /* use conflict finder to determine IIS */ static int confiis_put(ASL *asl, int kind, int n, int *ind, int *stat) { int i, j, k, *x; static int stmap[7] = {0, 5, 6, 7, 4, 1, 3 }; x = (int*)M1zapalloc((&asl->i.n_var_)[kind]*sizeof(int)); suf_iput("iis", kind, x); for(i = k = 0; i < n; i++) { if ((j = stat[i] + 1) < 0 || j > 6) j = 8; else j = stmap[j]; if (x[ind[i]] = j) k++; } return k; } static int send_confiis_ext(ASL *asl, cpxlp *cpx, char *hbuf) { char *grptype; double *L, *U, *gp; int *ci, *grpbeg, *grpind, *gs, i, i1, j, j1, k, n, nc, nv, rv, *vi; static int lbmap[4] = {0, 6, 1, 8}, ubmap[4] = {0, 7, 3, 8}, cmap[4] = {0, 5, 4, 8}; L = LUv; U = Uvx; k = n_var; n = n_con; for(i = 0; i < k; i++) { if (L[i] > negInfinity) n++; if (U[i] < Infinity) n++; } gp = (double*)Malloc(n*(sizeof(double)+3*sizeof(int)+1)); grpbeg = (int*)(gp + n); grpind = grpbeg + n; gs = grpind + n; grptype = (char*)(gs + n); for(i = 0; i < n; i++) { grpbeg[i] = i; gp[i] = 1.; } for(i = j = 0; i < k; i++) { if (L[i] > negInfinity) { grpind[j] = i; grptype[j++] = CPX_CON_LOWER_BOUND; } if (U[i] < Infinity) { grpind[j] = i; grptype[j++] = CPX_CON_UPPER_BOUND; } } for(i = 0, k += n_con - nlc; j < k; j++) { grpind[j] = i++; grptype[j] = CPX_CON_LINEAR; } for(i = 0, k += nlc; j < k; j++) { grpind[j] = i++; grptype[j] = CPX_CON_QUADRATIC; } if (i = CPXrefineconflictext(Env, cpx, n, n, gp, grpbeg, grpind, grptype)) { rv = retfrom(hbuf, i, "CPXrefineconflictext"); goto ret; } if (i = CPXgetconflictext(Env, cpx, gs, 0, n-1)) { rv = retfrom(hbuf, i, "CPXgetconflictext"); goto ret; } for(i = 0; i < n; i++) if ((j = ++gs[i]) < 0 || j > 1) gs[i] = j == CPX_CONFLICT_MEMBER ? 2 : 3; vi = (int*)M1zapalloc((n_var+n_con)*sizeof(int)); ci = vi + n_var; k = n_var; for(i = j = nv = 0; i < k; i++) { i1 = 0; if (L[i] > negInfinity) { vi[i] = lbmap[gs[j++]]; i1 = 1; } if (U[i] < Infinity) { i1 = 1; j1 = ubmap[gs[j++]]; if (vi[i] && L[i] == U[i]) j1 = 2; vi[i] = j1; } nv += i1; } for(i = nc = 0, k = n_con; i < k; i++) if (ci[i] = cmap[gs[j++]]) nc++; suf_iput("iis", ASL_Sufkind_var, vi); suf_iput("iis", ASL_Sufkind_con, ci); rv = Sprintf(hbuf, "\nReturning an IIS involving %d variables and %d constraints.", nv, nc); ret: free(gp); return rv; } static int send_confiis(ASL *asl, cpxlp *cpx, char *hbuf) { int cs, k, mc, mc1, nc, nc1, rv; int *colind, *colst, *rowind, *rowst; static char *abort_reason[7] = { "contradiction", "time limit", "iteration limit", "node limit", "objective limit", "memory limit", "user request" }; if (k = CPXrefineconflict(Env, cpx, &mc, &nc)) return retfrom(hbuf, k, "CPXrefineconflict"); k = mc + nc; if (mc < 0 || nc < 0 || k == 0) return Sprintf(hbuf, "\nSurprise values mc = %d, nc = %d from CPXrefineconflict.", mc, nc); colind = (int*)Malloc(2*sizeof(int)*k); colst = colind + nc; rowind = colst + nc; rowst = rowind + mc; if (k = CPXgetconflict(Env, cpx, &cs, rowind, rowst, &mc1, colind, colst, &nc1)) { rv = retfrom(hbuf, k, "CPXgetconflict"); goto ret; } if (cs == CPX_STAT_CONFLICT_FEASIBLE) { rv = Sprintf(hbuf, "\nNo IIS after all: problem is feasible!"); goto ret; } if (cs != CPX_STAT_CONFLICT_MINIMAL) { if ((cs < CPX_STAT_CONFLICT_ABORT_CONTRADICTION) < 0 || cs > CPX_STAT_CONFLICT_ABORT_CONTRADICTION + 6) rv = Sprintf(hbuf, "\nSurprise conflict status = %d from CPXgetconflict\n", cs); else rv = Sprintf(hbuf, "\nSearch for conflicts aborted because of %s\n", abort_reason[cs - CPX_STAT_CONFLICT_ABORT_CONTRADICTION]); goto ret; } if (mc1 > mc || nc1 > nc) { rv = Sprintf(hbuf, "\nSurprise confnumrows = %d (should be <= %d)," "\nconfnumcols = %d (should be <= %d) from CPXgetconflict.", mc1, mc, nc1, nc); goto ret; } nc = confiis_put(asl, ASL_Sufkind_var, nc1, colind, colst); mc = confiis_put(asl, ASL_Sufkind_con, mc1, rowind, rowst); return Sprintf(hbuf, "\nReturning an IIS of %d variables and %d constraints.", nc, mc); ret: free(colind); return rv; } #endif /*CPX_PARAM_FEASOPTMODE*/ static int send_iis(ASL *asl, cpxlp *cpx, char *hbuf) { char *ckind; int i, j, m, m1, n, n1; int *ci, *cs, *ri, *rs; if (!want_iis) return 0; #ifdef CPX_PARAM_FEASOPTMODE /* >= 9.2b */ if (nlc) return send_confiis_ext(asl, cpx, hbuf); if (want_iis > 2 || nbv + niv + nlvoi + nlvci + nlvbi > 0 && !relax || (Optimize != CPXprimopt && Optimize != CPXdualopt)) return send_confiis(asl, cpx, hbuf); #endif if (nlc) { printf("Ignoring iisfind request because of nonlinearities.\n"); return 0; } #ifdef CPX_PARAM_IISIND CPXsetintparam(Env, CPX_PARAM_IISIND, want_iis-1); if (i = CPXfindiis(Env, cpx, &m, &n)) return retfrom(hbuf, i, "CPXfindiis"); #else if (i = CPXrefineconflict(Env, cpx, &m, &n)) return retfrom(hbuf, i, "CPXrefineconflict"); #endif ci = (int*)M1alloc((2*(m+n))*sizeof(int)); cs = ci + n; ri = cs + n; rs = ri + m; ckind = ""; #ifdef CPX_PARAM_IISIND if (i = CPXgetiis(Env, cpx, &j, ri, rs, &m1, ci, cs, &n1)) return retfrom(hbuf, i, "CPXgetiis"); iis_put(asl, ASL_Sufkind_var, n, ci, cs); iis_put(asl, ASL_Sufkind_con, m, ri, rs); if (j != 1) ckind = "partial "; #else if (i = CPXgetconflict(Env, cpx, &j, ri, rs, &m1, ci, cs, &n1)) return retfrom(hbuf, i, "CPXgetconflict"); switch(j) { case CPX_STAT_CONFLICT_MINIMAL: confiis_put(asl, ASL_Sufkind_var, n, ci, cs); confiis_put(asl, ASL_Sufkind_con, m, ri, rs); break; case CPX_STAT_CONFLICT_FEASIBLE: return Sprintf(hbuf, "\nCPXgetconflict claims the problem is feasible."); default: return Sprintf(hbuf, "\nSurprise conflict status %d from CPXgetconflict.", j); } #endif return Sprintf(hbuf, "\nReturning %siis of %d variables and %d constraints.", ckind, n, m); } static int wantray(int dual, cpxlp *cpx, int *itcp, int *itcip, int nelqf) { Optalg Rayalg; static Optalg PDalg[2] = { CPXprimopt, CPXdualopt }; *itcp = 0; if (want_iis || !(rays & (1 << dual))) return 0; Rayalg = PDalg[dual]; if (Optimize == Rayalg || nelqf && (Optimize == CPXdualopt || Optimize == CPXprimopt)) { *itcip = 0; return 1; } if (Optimize == CPXmipopt || Optimize == Optimizebar) return 0; (*Rayalg)(Env, cpx); *itcp = CPXgetitcnt(Env, cpx); *itcip = CPXgetphase1cnt(Env, cpx); algname = dual ? "dual " : ""; return 1; } #ifdef CPX_PARAM_POPULATELIM /*{*/ static void poolwrite(ASL *asl, cpxlp *cpx, dims *d, char *hb, int *hbi, size_t hblen) { char buf[32], buf1[120], *fname, *s; const char *whence; int i, j, k, n, nm1, nsols; real obj, *x; size_t L; i = *hbi; j = 0; if (populate == 1) { if (k = CPXpopulate(Env, cpx)) { i += snprintf(hb+i, hblen-i, "\nReturn %d from CPXpopulate.", k); goto done; } } nsols = CPXgetsolnpoolnumsolns(Env,cpx); if (nsols <= 0) { i += snprintf(hb+i, hblen-i, "\n%d solutions in solution pool.", nsols); goto done; } n = n_var; L = strlen(poolstub); x = (real*)Malloc(n*sizeof(real) + L + 32); fname = (char*)(x + n); strcpy(fname, poolstub); nm1 = n - 1; whence = 0; for(j = k = 0; j < nsols; j++) { if (k = CPXgetsolnpoolx(Env, cpx, j, x, 0, nm1)) { whence = "CPXgetsolnpoolx"; break; } if (k = CPXgetsolnpoolobjval(Env, cpx, j, &obj)) { whence = "CPXgetsolnpoolobjval"; break; } g_fmtop(buf, obj); snprintf(buf1, sizeof(buf1), "Solution pool member %d (of %d); objective %s", j+1, nsols, buf); sprintf(fname+L, "%d.sol", j+1); if (write_solf_ASL(asl, buf1, x, 0, 0, fname)) { whence = ""; break; } } i += snprintf(hb+i,hblen-i,"\nWrote %d solution%s in solution pool", j, "s" + (j == 1)); s = L > 32 ? "\n" : " "; if (j > 0) switch(j) { case 1: i += snprintf(hb+i,hblen-i,"\nto file %s1.sol", poolstub); break; case 2: i += snprintf(hb+i,hblen-i,"\nto files %s1.sol%sand %s2.sol", poolstub, s, poolstub); break; default: i += snprintf(hb+i,hblen-i,"\nto files %s1.sol%s... %s%d.sol", poolstub, s, poolstub, j); } i += snprintf(hb+i,hblen-i,"."); if (whence) { if (k) i += snprintf(hb+i,hblen-i, "\nSolution pool writing stopped by return %d from %s.", k, whence); else i += snprintf(hb+i,hblen-i, "\nCould not open \"%s\"", fname); } free(x); done: d->npool = j; suf_iput("npool", ASL_Sufkind_prob, &d->npool); *hbi = i; } struct Element { keyword *kw; union { double dval; int ival; } u; }; typedef struct ParInfo { double align; Element *nd; AVL_Tree *tree; int n_dbl, n_int; } ParInfo; static int int_elcmp(void *v, const Element *L, const Element *R) { return (Intcast L->kw->info) - (Intcast R->kw->info); } static ParInfo * getparinfo(void) { AVL_Tree *at; Element *e; ParInfo *PI; double w[4]; int k, z[4]; keyword *kw, *kwe; size_t L, n; /* Use of AVL stuff here is only needed if the choice between */ /* (sf_int and sf_int2) or (sf_dbl and sf_dbl2) is wrong in keywds. */ n = nkeywds; L = n*sizeof(Element) + sizeof(ParInfo); /* overkill */ PI = (ParInfo*)Malloc(L); PI->nd = e = (Element*)(PI + 1); PI->tree = at = AVL_Tree_alloc(0, int_elcmp, mymalloc_ASL); PI->n_dbl = PI->n_int = 0; kw = keywds; for(kwe = kw + nkeywds; kw < kwe; ++kw) { k = Intcast kw->info; if (kw->kf == sf_int) { CPXinfointparam(Env, k, z, z+1, z+2); CPXgetintparam(Env, k, z+3); if (z[0] != z[3]) { e->kw = kw; if (!AVL_insert(e,at)) { e->u.ival = z[3]; ++e; PI->n_int++; } } } else if (kw->kf == sf_dbl) { CPXinfodblparam(Env, k, w, w+1, w+2); CPXgetdblparam(Env, k, w+3); if (w[0] != w[3]) { e->kw = kw; if (!AVL_insert(e,at)) { e->u.dval = w[3]; ++e; PI->n_dbl++; } } } } return PI; } static void tunewrite(char *fname, const char *fkeywd, char *hb, int *hbi, size_t hblen) { Element *e, *ee; FILE *f; ParInfo *PI; int i, n; keyword *kw; i = *hbi; if (!(f = fopen(fname, "w"))) { *hbi = i += snprintf(hb+i, hblen-i, "\nCould not open %s file \"%s\"", fkeywd, fname);; solve_result_num = 565; return; } PI = getparinfo(); n = 0; e = PI->nd; n = AVL_Tree_size(PI->tree); ee = e + n; for(; e < ee; ++e) { kw = e->kw; if (kw->kf == sf_int) fprintf(f, "%s = %d\n", kw->name, e->u.ival); else fprintf(f, "%s = %.g\n", kw->name, e->u.dval); } fclose(f); *hbi = i += snprintf(hb+i, hblen-i, "\n%d settings written to %s file \"%s\"", n, fkeywd, fname); AVL_Tree_free(&PI->tree); free(PI); } #endif /*}*/ #if CPX_VERSION >= 1000 /*{*/ static void tunewriteprm(char *fname, const char *fkeywd, char *hb, int *hbi, size_t hblen) { char *fmt; int i = *hbi; if (CPXEwriteparam(Env, fname)) { fmt = "\nError writing %s file \"%s\""; solve_result_num = 565; } else fmt = "\n%s file \"%s\" written"; *hbi = i += snprintf(hb+i, hblen-i, fmt, fkeywd, fname); } #endif /*}*/ #if CPX_VERSION >= 1100 /*{*/ typedef struct Tunefix { AVL_Tree *avi, *avr; Element *e; int *num0, *nume, *numi, *numr; } Tunefix; static void tunefixname(Tunefix *Tf, char *s, const char *what) { AVL_Tree *T; Element *e; Kwfunc *f; char *peq; int L; keyword *kw; if (kw = (keyword *)b_search_ASL(keywds, (int)sizeof(keyword), nkeywds, &s, &peq)) { f = kw->kf; e = Tf->e; e->kw = kw; if (f == sf_int || f == sf_int2) { if (!(T = Tf->avi)) Tf->avi = T = AVL_Tree_alloc(0, int_elcmp, mymalloc_ASL); if (!AVL_insert(e,T)) { *Tf->numi++ = Intcast kw->info; ++Tf->e; } } else if (f == sf_dbl || f == sf_dbl2) { if (!(T = Tf->avr)) Tf->avr = T = AVL_Tree_alloc(0, int_elcmp, mymalloc_ASL); if (!AVL_insert(e,T)) { *--Tf->numr = Intcast kw->info; ++Tf->e; } } } else { for(L = 0; s[L] > ' '; ++L); badretfmt(566, "unrecognized keyword \"%.*s\" in %s", L, s, what); } } static void tunefix_proc(Tunefix *Tf, char *s) { char buf[64], *s1; size_t inc, L; for(;;) { while(*s <= ' ') if (!*s++) return; for(L = inc = 0; s[L] > 0; ++L) { if (s[L] == ',') { inc = 1; break; } } if (L && L < sizeof(buf)) { s1 = s; if (inc) { memcpy(s1 = buf, s, L); s1[L] = 0; } tunefixname(Tf, s1, "tunefix"); } s += L + inc; } } static void tunefixfile_proc(Tunefix *Tf) { FILE *f; char buf[4096], *b, *b1, *be; if (!(f = fopen(tunefixfile, "rb"))) badretfmt(566, "Could not open tunefixfile \"%s\"", tunefixfile); top: while(fgets(buf, sizeof(buf), f)) { b = buf; be = b + strlen(b); if (be > b && be[-1] == '\n') *--be = 0; for(;;) { while(*b <= ' ') if (!*b++) goto top; b1 = b; while(*++b > ' '); tunefixname(Tf, b1, "tunefixfile"); } } fclose(f); } static void tunerun(cpxlp *cpx, char *hb, int *hbi, size_t hblen) { Element *E; Tunefix TF; char *what, whatbuf[64]; double *dblval; int *intval; int i, j, k, n_dbl, n_int; dblval = 0; intval = 0; TF.avi = TF.avr = 0; TF.e = E = (Element *)Malloc((nkeywds)*(sizeof(Element) + sizeof(int))); TF.num0 = TF.numi = (int*)(E + nkeywds); TF.nume = TF.numr = TF.num0 + nkeywds; if (tunefix) tunefix_proc(&TF, tunefix); if (tunefixfile) tunefixfile_proc(&TF); n_dbl = TF.nume - TF.numr; n_int = TF.numi - TF.num0; if (n_dbl + n_int) { dblval = (double*)Malloc(n_dbl*sizeof(double) + n_int*sizeof(int)); intval = (int*)(dblval + n_dbl); for(i = 0; i < n_int; ++i) CPXgetintparam(Env, TF.num0[i], intval + i); for(i = 0; i < n_dbl; ++i) CPXgetdblparam(Env, TF.numr[i], dblval + i); } k = CPXtuneparam(Env, cpx, n_int, TF.num0, intval, n_dbl, TF.numr, dblval, 0, 0, 0, &j); i = *hbi; if (k) i += snprintf(hb + i, hblen - i, "\nSurprise return %d from CPXtuneparam.", k); else { switch(j) { case 0: what = "finished"; break; case CPX_TUNE_ABORT: what = "aborted"; break; case CPX_TUNE_TILIM: what = "time limit reached"; break; default: what = whatbuf; snprintf(whatbuf, sizeof(whatbuf), "got surprise tunestat = %d", j); } i += snprintf(hb + i, hblen - i, "\nTuning %s.", what); } *hbi = i; if (dblval) { free(dblval); if (TF.avi) AVL_Tree_free(&TF.avi); if (TF.avr) AVL_Tree_free(&TF.avr); } free(E); } #endif /*}*/ static void amplout(ASL *asl, cpxlp *cpx, dims *d, int status, int nelqf, int nint1, int *nosp) { char buf[32], hbuf[1100], *wb; int bitc, i, ii, itc, itci, j, m, mipstat, n, nint, npt; int nodecnt, nodelim, nos, nround, opt, stat, stat0, stat1, stat10; real *bb, *bn, *l, *le, *u, w[4], *x, *x2, *y, *z, *z1; real absmipgap, bbound, bcond, bobj, bobj0, feastol, inttol; real relmipgap, obj, t; typedef struct { char *msg; int code; int wantobj; } Sol_info; Sol_info *SI; static Sol_info solinfo[] = { { "unrecoverable failure or licensing problem", 500, 0 }, { "optimal solution", 000, 1 }, { "infeasible problem", 200, 0 }, /* 2 */ { "unbounded problem", 300, 0 }, { "phase II objective limit exceeded", 400, 1 }, /* 4 */ { "iteration limit in phase II", 401, 1 }, { "iteration limit in phase I", 402, 1 }, /* 6 */ { "time limit in phase II", 403, 1 }, { "time limit in phase I", 404, 1 }, /* 8 */ { "infeasible with phase II singularities", 201, 0 }, { "infeasible with phase I singularities", 202, 0 }, { "optimal with unscaled infeasibilities", 110, 1 }, /* 11 */ { "aborted in phase II", 501, 1 }, { "aborted in phase I", 502, 0 }, { "aborted in barrier, dual infeasible", 503, 0 }, /* 14* */ { "aborted in barrier, primal infeasible", 504, 0 }, { "aborted in barrier, primal and dual infeasible", 505, 0 }, { "aborted in barrier, primal and dual feasible", 506, 0 }, { "aborted in crossover", 507, 0 }, /* 18 */ { "converged, dual feasible, primal infeasible", 204, 1 }, /*32 --> 19*/ { "converged, primal feasible, dual infeasible", 301, 1 }, { "converged, primal and dual infeasible", 205, 1 }, { "primal objective limit reached", 405, 1 }, /* 35 --> 22 */ { "dual objective limit reached", 406, 1 }, { "primal has unbounded optimal face", 001, 1 }, { "best solution found, primal-dual feasible", 100, 1 },/* 38 --> 25*/ { "best solution found, primal infeasible", 206, 1 }, { "best solution found, dual infeasible", 302, 1 }, { "best solution found, primal-dual infeasible", 207, 1 }, /* 41 --> 28 */ { "solution found, numerical difficulties", 508, 1}, { "solution found, inconsistent equations", 509, 1}, /* 43 --> 30*/ { "infeasible or unbounded in presolve", 208, 0 }, /*1101*/ { "not licensed to solve MIP problems", 571, 0}, /* 32 */ { "not licensed to use the barrier algorithm", 572, 0 }, { "not licensed to solve MIQP or QCP problems", 573, 0 } #ifdef CPLEX_MIP ,{ "optimal integer solution", 002, 1 }, /* 101 --> 35 */ { "optimal integer solution within mipgap or absmipgap", 003, 1 }, { "integer infeasible", 220, 0 }, /* 103 */ { "mixed-integer solutions limit", 420, 1 }, { "node limit with integer solution", 421, 1 }, /* 105 */ { "node limit with no integer solution", 410, 0 }, { "time limit with integer solution", 422, 1 }, { "time limit with no integer solution", 411, 0 }, /* 108 */ { "unrecoverable failure with integer solution", 520, 1 }, { "unrecoverable failure with no integer solution", 510, 0 }, { "treememory limit with integer solution", 423, 1 }, { "treememory limit with no integer solution", 412, 0 },/* 112 */ { "aborted, integer solution exists", 521, 1 }, { "aborted, no integer solution", 511, 0 }, /* 114 */ { "integer optimal with unscaled infeasibilities", 111, 1 }, { "out of memory, no tree; solution may exist", 523, 1 },/* 116 */ { "out of memory, no tree; no integer solution", 512, 1 }, #ifdef CPX_STAT_OPTIMAL /* >= 8.0 */ { "integer unbounded ray", 320, 1}, /* 118 */ { "integer infeasible or unbounded in presolve", 209, 0 }, /* 119 --> 53 */ #else { "node file limit with integer solution", 424, 1 }, { "node file limit with no integer solution", 413, 1 }, /* 119 --> 53 */ #endif /*CPX_STAT_OPTIMAL*/ { "optimal (non-)integer solution", 102, 1 }, { "optimal (non-)integer solution within mipgap or absmipgap", 103, 1 }, { "feasible relaxed sum in feasopt", 121, 1}, /* --> 56 */ { "optimal relaxed sum in feasopt", 122, 1}, { "feasible relaxed infeasibility count in feasopt", 123, 1}, { "optimal relaxed infeasibility count in feasopt", 124, 1}, { "feasible relaxed quadratic penalty in feasopt", 125, 1}, { "optimal relaxed quadratic penalty in feasopt", 126, 1} /* --> 61 */ #endif /*CPLEX_MIP*/ }; static Sol_info solinfo1[] = { { "QP Hessian is not positive semi-definite", 542, 0 }, { "primal optimal (no dual solution available)", 004, 1 }, { "ran out of memory", 522, 0 } #ifdef CPXERR_Q_NEG_ZERO_COMP /* CPLEX 7.1 */ ,{ "QP Hessian has diag. elements of the wrong sign", 541, 0 } #endif }; static char *netmsg[] = { "no network", /*"an optimal network solution"*/ "", "an infeasible network", "an unbounded network", "an infeasible or unbounded network", "iteration limit with a feasible network solution", "iteration limit with an infeasible network solution", "time limit with a feasible network solution", "time limit with an infeasible network solution", "a feasible aborted network solution", "an infeasible aborted network solution", "a bug" #ifdef Student_Edition ,"the adjusted problem too large" #endif }; static char *dray_msg[4] = { "\nconstraint.dunbdd returned", "\nfailed to compute variable.dunbdd", "\nQP simplex cannot compute variable.dunbdd" }; #if CPX_VERSION < 1100 int cl0, cl, cov, ccpr = 0; #else typedef struct CutInfo { const char *cutname; int cuttype; } CutInfo; CutInfo *CI; static CutInfo Cut_Info[] = { { "cover", CPX_CUT_COVER }, { "GUB-cover", CPX_CUT_GUBCOVER }, { "flow-cover", CPX_CUT_FLOWCOVER }, { "clique", CPX_CUT_CLIQUE }, { "Gomory", CPX_CUT_FRAC }, { "flow-path", CPX_CUT_FLOWPATH }, { "disjunctive", CPX_CUT_DISJ }, { "implied-bound", CPX_CUT_IMPLBD }, { "zero-half", CPX_CUT_ZEROHALF }, { "mixed-integer rounding", CPX_CUT_MIR }, #if 0 { "", CPX_CUT_LOCALCOVER }, { "", CPX_CUT_TIGHTEN }, { "", CPX_CUT_OBJDISJ }, { "", CPX_CUT_USER }, { "", CPX_CUT_TABLE }, { "", CPX_CUT_SOLNPOOL } #endif { 0, 0}}; #endif absmipgap = obj = relmipgap = Infinity; stat1 = 1; ii = mipstat = nodecnt = npt = nround = opt = 0; m = n_con; n = n_var; x = d->x; y = d->y; if (Logf) CPXsetlogfile(Env, NULL); /* suppress idiotic Error 1217 */ #ifdef BARRIER bitc = CPXgetbaritcnt(Env, cpx); #else bitc = 0; #endif itc = CPXgetitcnt(Env, cpx); itci = CPXgetphase1cnt(Env, cpx); if (Logf) CPXsetlogfile(Env, Logf); nos = nosp ? *nosp : 0; switch (status) { case 0: break; case CPXERR_NO_MEMORY: SI = solinfo1 + 2; stat = -1; goto have_SI; case CPXERR_Q_NOT_POS_DEF: SI = solinfo1; stat = -1; goto have_SI; #ifdef CPXERR_Q_NEG_ZERO_COMP case CPXERR_Q_NEG_ZERO_COMP: SI = solinfo1 + 3; stat = -1; goto have_SI; #endif case CPXERR_PRESLV_INForUNBD: SI = solinfo + 31; goto have_SI; case 32024: stat = 33; goto more_default; default: stat = 0; more_default: stat0 = status; x = y = 0; goto have_stat; } if (Optimize == CPXlpopt #ifndef BARRIER_FOR_QP || Optimize == CPXqpopt #endif /* BARRIER_FOR_QP */ ) { if (lpoptalg == CPX_ALG_AUTOMATIC) switch(i = CPXgetmethod(Env,cpx)) { case CPX_ALG_DUAL: Optimize = CPXdualopt; algname = "dual "; break; case CPX_ALG_PRIMAL: Optimize = CPXprimopt; break; #ifdef CPX_STAT_OPTIMAL /* >= 8.0 */ case CPX_ALG_SIFTING: case CPX_ALG_BARRIER: #ifdef CPX_ALG_FEASOPT /* >= 9.2b */ case CPX_ALG_FEASOPT: #endif Optimize = CPXlpopt; lpoptalg = i; #endif /* CPX_STAT_OPTIMAL */ } } #ifdef CPLEX_MIP else if (Optimize == CPXmipopt) { #if CPX_VERSION < 1100 /*{*/ if (prestats && nint1 && (parval(CPX_PARAM_CLIQUES) || parval(CPX_PARAM_COVERS))) { cl0 = CPXgetgenclqcnt(Env, cpx); cl = CPXgetclqcnt(Env, cpx); cov = CPXgetcovcnt(Env, cpx); ccpr = 1; } #endif if (status > 0) { mipstat = statadjust(cpx, stat0 = status); status = 0; } } #endif #ifdef CPLEX_MIP bobj = bobj0 = objsen * Infinity; if (nint1) { if (mipstat) { stat = mipstat; if (mipstat < 4 || mipstat > 8) goto have_ii; switch(mipstat) { /* Increase limits to permit recovering best sol'n */ case 5: case 6: CPXsetintparam(Env, CPX_PARAM_ITLIM, 2*parval(CPX_PARAM_ITLIM)); break; case 7: case 8: { double tl = 1e75; CPXgetdblparam(Env, CPX_PARAM_TILIM, &tl); CPXsetdblparam(Env, CPX_PARAM_TILIM, 2.*tl); } } } else stat = statadjust(cpx, stat0 = CPXgetstat(Env, cpx)); ii = CPXgetmipitcnt(Env, cpx); nodecnt = CPXgetnodecnt(Env, cpx); have_ii: if (CPXgetbestobjval(Env, cpx, &bobj)) bobj = bobj0; if (!solinfo[stat].wantobj) x = y = 0; if (solinfo[stat].wantobj || endbas) { if (zap_lpcbf) { zap_lpcbf = 0; #ifdef CPXERR_IN_INFOCALLBACK CPXsetinfocallbackfunc(Env, breakcallback, 0); #else CPXsetlpcallbackfunc(Env, breakcallback, 0); CPXsetmipcallbackfunc(Env, breakcallback, 0); #endif } if (!CPXgetmipobjval(Env, cpx, &obj) && bobj != bobj0) { if ((absmipgap = obj - bobj) < 0.) absmipgap = -absmipgap; if ((t = obj) < 0.) t = -t; relmipgap = absmipgap / (1e-10 + t); } if (endbas) mipbasis = 1; if (!nlc && mipbasis) { opt = CPXgetprobtype(Env, cpx); npt = nelqf ? 8 : 3; if (npt != opt) CPXchgprobtype(Env, cpx, npt); if (i = !CPXgetdblparam(Env,CPX_PARAM_EPRHS,&feastol) && !CPXgetdblparam(Env,CPX_PARAM_EPINT,&inttol) && inttol > feastol) CPXsetdblparam(Env, CPX_PARAM_EPRHS, inttol); status = CPXprimopt(Env, cpx); stat1 = CPXgetstat(Env, cpx); if (i) /*restore "feasibility" tolerance*/ CPXsetdblparam(Env, CPX_PARAM_EPRHS, feastol); if (status || stat1 != 1) fprintf(Stderr, "CPLEX solution status %d with fixed integers:\n\t%s\n", stat1, solinfo[statadjust(cpx,stat1)].msg); if (endbas && !nelqf) write_basis(cpx); } if (!solinfo[stat].wantobj) goto have_stat; if (nlc || !mipbasis) { if (i = CPXgetmipx(Env, cpx, x, 0, n-1)) { fprintf(Stderr, "Surprise return %d from CPXgetmipx\n", i); x = 0; } } else { if (CPXsolution(Env, cpx, &stat1, &obj, x, y, 0, 0)) stat1 = CPXgetstat(Env, cpx); stat1 = statadjust(cpx, stat10 = stat1); } /* round to integer */ if (!relax && Round >= 0 && x) { w[0] = 0; if (nint = niv + nbv) { x2 = x + n_var - nint; nround = xround(x2, nint, Round & 1, w); } if (nint = nlvbi) { x2 = x + (nlvb - nint); nround += xround(x2, nint, Round & 1, w); } if (nint = nlvci) { x2 = x + (nlvc - nint); nround += xround(x2, nint, Round & 1, w); } if (nint = nlvoi) { x2 = x + (nlvo - nint); nround += xround(x2, nint, Round & 1, w); } if (nround) { CPXinfodblparam(Env, CPX_PARAM_EPINT, w+1, w+2, w+3); if (w[0] <= intwarn_tol && !(Round & 8)) nround = 0; else CPXgetdblparam(Env, CPX_PARAM_EPINT, w+1); } if (nround) { if ((solinfo[stat].code & ~1) == 2 && !(Round & 2)) stat += 19; if (Round & 4) nround = 0; else if (!(Round & 1)) nround = -nround; } } } } else #endif { switch(CPXsolution(Env, cpx, &stat, &obj, x, y, 0, 0)) { case 0: break; #ifdef CPXERR_NO_DUAL_SOLN case CPXERR_NO_DUAL_SOLN: y = 0; if (!CPXsolution(Env, cpx, &stat, &obj, x, y, 0, 0)) { if (method > 0 && stat == 1) { SI = solinfo1 + 1; goto have_SI; } break; } #endif /*CPXERR_NO_DUAL_SOLN*/ default: stat = CPXgetstat(Env, cpx); } stat = nos == 2 ? 2 : statadjust(cpx, stat0 = stat); } if (method < 0) { /* dual */ z = x; x = y; y = z; z1 = z + m; l = LUrhs; u = Urhsx; /* fix dual variables */ for(le = l + m; l < le; l++, u++, z++) if (*u > *l && *l > negInfinity && *u < Infinity) { if (*z < -*z1) *z = *z1; z1++; } if (objsen > 0) { for(z = y, z1 = y + m; z < z1; z++) *z = -*z; for(z = x, z1 = x + n; z < z1; z++) *z = -*z; } } have_stat: SI = solinfo + stat; have_SI: i = Sprintf(hbuf, "%s: %s", Oinfo.bsname, SI->msg); if (!stat) i += Sprintf(hbuf+i, ": %s", failstat(stat0)); #ifdef CPLEX_MIP else if (stat == 16 || stat == 17) { CPXgetintparam(Env, CPX_PARAM_NODELIM, &nodelim); i += Sprintf(hbuf+i, ".\nCurrent node limit = %d", nodelim); } #endif else if (!SI->wantobj) i += Sprintf(hbuf+i, "."); if (SI->wantobj) { if (obj == Infinity) CPXgetobjval(Env, cpx, &obj); g_fmtop(buf, obj); i += Sprintf(hbuf+i, "; objective %s", buf); } solve_result_num = SI->code; if (nosp) { if (nos < 0 || nos > 12) nos = 11; if (nos != 1) i += Sprintf(hbuf+i, "\nnetopt found %s.", netmsg[nos]); if (net_nodes != lnc || net_arcs != nwv) i += Sprintf(hbuf+i, "\nNetwork extractor found %d nodes and %d arcs.", net_nodes, net_arcs); i += Sprintf(hbuf+i, "\n%d network simplex iterations.", netiters); } if (nint1 && !mipstat) i += Sprintf(hbuf+i, "\n%d MIP simplex iterations\n%d branch-and-bound nodes", ii, nodecnt); if (itc > 0 || itci > 0 || Optimize == CPXprimopt || Optimize == CPXdualopt) { i += Sprintf(hbuf+i, "\n%d %s%ssimplex iterations (%d in phase I)%s", itc, nelqf ? "QP " : "", algname, itci, method > 0 ? "" : " on the dual problem"); if (itc == 0 && itci == 0 && netiters <= 0 && solve_result_num == 0) solve_result_num = 4; } #ifdef CPX_STAT_OPTIMAL /* >= 8.0 */ else if (Optimize == CPXlpopt && lpoptalg == CPX_ALG_SIFTING) { itc = CPXgetsiftitcnt(Env, cpx); itci = CPXgetsiftphase1cnt(Env, cpx); i += Sprintf(hbuf+i, "\n%d sifting subproblems solved (%d in phase I)", itc, itci); } #endif if (bitc > 0) { i += Sprintf(hbuf+i, "\n%d %sbarrier iterations", bitc, baralgname); if (cbi.nx[0] | cbi.nx[1]) i += Sprintf(hbuf+i, "\n%d push, %d exchange %s crossover iterations", cbi.nx[0], cbi.nx[1], cbi.xkind); } #ifdef CPLEX_MIP if (bestnode) { bbound = bobj0; if ((j = SI->code) < 200) { if (objsen*(bbound = bobj) > objsen*obj) bbound = obj; } else if (j < 400) { if (j >= 300) bbound = -bbound; } else if (j < 500 && objsen*bobj <= objsen*obj) bbound = bobj; if (n_obj > 0) { if ((bestnode & 3) == 3) { bb = (real*)M1zapalloc(2*sizeof(real)*n_obj); bn = bb + n_obj; } else bn = bb = (real*)M1zapalloc(n_obj*sizeof(real)); if (bestnode & 1) { if (obj_no >= 0) bb[obj_no] = bbound; suf_rput("bestbound", ASL_Sufkind_obj, bb); } if (bestnode & 2) { if (obj_no >= 0) bn[obj_no] = bobj; suf_rput("bestnode", ASL_Sufkind_obj, bn); } } if (bestnode & 1) suf_rput("bestbound", ASL_Sufkind_prob, &bbound); if (bestnode & 2) suf_rput("bestnode", ASL_Sufkind_prob, &bobj); } #if CPX_VERSION < 1100 if (ccpr) { if (cl0 | cl | cov) { if (cl0) i += Sprintf(hbuf+i, "\n%d of %d clique inequalities used", cl, cl0); if (cov) i += Sprintf(hbuf+i, "\n%d cover cuts added", cov); } else i += Sprintf(hbuf+i, "\nNo clique or cover cuts used."); } #endif if (absmipgap > 0. && absmipgap < Infinity && !(retmipgap & 4)) i += Sprintf(hbuf+i, "\nabsmipgap = %g, relmipgap = %g", absmipgap, relmipgap); if (retmipgap & 1) { suf_rput("relmipgap", ASL_Sufkind_obj, &relmipgap); suf_rput("relmipgap", ASL_Sufkind_prob, &relmipgap); } if (retmipgap & 2) { suf_rput("absmipgap", ASL_Sufkind_obj, &absmipgap); suf_rput("absmipgap", ASL_Sufkind_prob, &absmipgap); } #endif if (stat1 != 1) { SI = solinfo + stat1; i += Sprintf(hbuf+i, "\nStatus recovering solution: %s", SI->msg); if (!stat1) i += Sprintf(hbuf+i, ": stat = %d", stat10); if (solve_result_num < SI->code) solve_result_num = SI->code; } if (aggtries > 1) i += Sprintf(hbuf+i, "\nTried aggregator %d times", aggtries); if (solve_result_num >= 200 && solve_result_num < 300) { i += send_iis(asl, cpx, hbuf+i); } if (send_statuses(asl, cpx, d)) i += Sprintf(hbuf+i, "\nNo basis."); else if (asl->i.flags & 1 && method > 0) switch(stat) { /* Note: stat values have been adjusted to accord with */ /* earlier CPLEX versions -- don't use CPX_STAT_INFEASIBLE */ /* or CPX_STAT_UNBOUNDED here... */ case 2: /*infeasible*/ if (wantray(1,cpx,&itc,&itci,nelqf)) { j = send_dray(asl,cpx,nelqf); i += Sprintf(hbuf+i, dray_msg[j]); } goto j_check; case 3: /*unbounded*/ if (wantray(0,cpx,&itc,&itci,0)) i += Sprintf(hbuf+i, (j = send_ray(asl,cpx)) ? "\nfailed to compute variable.unbdd" : "\nvariable.unbdd returned"); j_check: if (itc) { i += Sprintf(hbuf+i, "\n%d extra %ssimplex iterations for ray", itc, algname); if (itci) i += Sprintf(hbuf+i," (%d in phase I)",itci); } if (!j) solve_result_num += 10; } if (basis_cond) { if (CPXgetdblquality(Env, cpx, &bcond, CPX_KAPPA)) { i += Sprintf(hbuf+i, "\nBasis condition is unavailable."); bcond = 0; } else i += Sprintf(hbuf+i, "\nBasis condition = %g", bcond); if (n_obj > 0) suf_rput("basis_cond", ASL_Sufkind_obj, &bcond); suf_rput("basis_cond", ASL_Sufkind_prob, &bcond); } if (nround) { wb = ""; if (nround < 0) { nround = -nround; wb = "would be "; } i += Sprintf(hbuf+i, "\n%d integer variables %srounded (maxerr = %g).", nround, wb, w[0]); if (w[0] > intwarn_tol && 0.5*w[0] > w[2]) { i += Sprintf(hbuf+i, "\nAssigning integrality = %.1g might help.", 0.5*w[0]); i += Sprintf(hbuf+i, "\nCurrently integrality = %g.", w[1]); } } #if CPX_VERSION >= 1100 if (npt != opt) CPXchgprobtype(Env, cpx, opt); for(CI = Cut_Info; CI->cutname; ++CI) if (!CPXgetnumcuts(Env, cpx, CI->cuttype, &j) && j > 0) i += Sprintf(hbuf+i, "\n%d %s cut%s", j, CI->cutname, "s" + (j == 1)); #endif #ifdef CPX_PARAM_POPULATELIM if (Optimize == CPXmipopt && poolstub && x) poolwrite(asl, cpx, d, hbuf, &i, sizeof(hbuf)); #endif if (pretunefile) tunewrite(pretunefile, "pretunefile", hbuf, &i, sizeof(hbuf)); #if CPX_VERSION >= 1000 /*{*/ if (pretunefileprm) tunewriteprm(pretunefileprm, "pretunefileprm", hbuf, &i, sizeof(hbuf)); #ifdef CPX_TUNE_TILIM /* CPLEX 11 */ if (tunefile || tunefileprm) { tunerun(cpx, hbuf, &i, sizeof(hbuf)); if (tunefile) tunewrite(tunefile, "tunefile", hbuf, &i, sizeof(hbuf)); if (tunefileprm) tunewriteprm(tunefileprm, "tunefileprm", hbuf, &i, sizeof(hbuf)); } #endif #endif /*}*/ write_sol(hbuf, x, y, &Oinfo); if (Logf) { CPXsetlogfile(Env, NULL); CPXfclose(Logf); Logf = 0; } } static double Times[4]; static void show_times(void) { int i; Times[3] = xectim_(); for(i = 1; i <= 2