| |||||||||||
Basic LP/MIP solver interface for Xpress Optimizer Description Language extensions provided by this module:
Source Files By clicking on a file name, a preview is opened at the bottom of this page.
Data Files myxprs.c /********************************************** Mosel NI Examples ================= File myxprs.c ````````````` Example module interfacing to a MIP solver using the Mosel NI * matrix generation and solver call * retrieving solution values * access to sample solver parameters * implementation of a solver (integer solution) callback * routine for matrix output by the solver (c) 2022 Fair Isaac Corporation author: Y. Colombani, S. Heipcke, 2017 ***********************************************/ /* gcc -Wall -g -o myxprs.dso -shared -I${XPRESSDIR}/include myxprs.c -L${XPRESSDIR}/lib -lxprs -lxprnls cl /LD /MD /Femyxprs.dso -I%XPRESSDIR%\include myxprs.c %XPRESSDIR%\lib\xprs.lib %XPRESSDIR%\lib\xprnls.lib */ #include <stdlib.h> #include <stdio.h> #include <string.h> #define XPRM_NICOMPAT 6000000 /* Compatibility level: Mosel 6.0.0 */ #include "xprm_ni.h" /* Mosel NI header file */ #include "xprnls.h" /* Character encoding conversion routines */ #include "xprs.h" /* Solver library header file */ /**** Function prototypes ****/ struct SlvCtx; struct SlvPb; /* Module services */ static void *slv_reset(XPRMcontext ctx,void *libctx); static void slv_quitlib(void); static int slv_findparam(const char *name, int *type, int why, XPRMcontext ctx, void *libctx); static void *slv_nextparam(void *ref, const char **name, const char **desc, int *type); /* Solver library function calls */ static int slv_lc_getpar(XPRMcontext ctx,void *libctx); static int slv_lc_setpar(XPRMcontext ctx,void *libctx); static int slv_lc_getpstat(XPRMcontext ctx,void *libctx); static int slv_lc_maxim(XPRMcontext ctx,void *libctx); static int slv_lc_minim(XPRMcontext ctx,void *libctx); static int slv_lc_setcbintsol(XPRMcontext ctx,void *libctx); static int slv_lc_setcbintsol_pr(XPRMcontext ctx,void *libctx); static int slv_lc_writepb(XPRMcontext ctx,void *libctx); /* Optimization problem handling */ static void *slv_pb_create(XPRMcontext ctx,void *libctx,void *toref,int type); static void slv_pb_delete(XPRMcontext ctx,void *libctx,void *todel,int type); static int slv_pb_copy(XPRMcontext ctx,void *libctx,void *toinit,void *src, int ust); /**** Structures for passing info to Mosel ****/ /* Constants */ static XPRMdsoconst tabconst[]= { XPRM_CST_INT("MYXP_INF", XPRM_PBINF), /* Mosel status codes */ XPRM_CST_INT("MYXP_OPT", XPRM_PBOPT), XPRM_CST_INT("MYXP_OTH", XPRM_PBOTH), XPRM_CST_INT("MYXP_UNF", XPRM_PBUNF), XPRM_CST_INT("MYXP_UNB", XPRM_PBUNB), XPRM_CST_INT("MYXP_LP_OPTIMAL", XPRS_LP_OPTIMAL), /* Solver status codes */ XPRM_CST_INT("MYXP_LP_INFEAS", XPRS_LP_INFEAS), XPRM_CST_INT("MYXP_LP_CUTOFF", XPRS_LP_CUTOFF), XPRM_CST_INT("MYXP_MIP_NOT_LOADED", XPRS_MIP_NOT_LOADED), XPRM_CST_INT("MYXP_MIP_SOLUTION", XPRS_MIP_SOLUTION), XPRM_CST_INT("MYXP_MIP_INFEAS", XPRS_MIP_INFEAS) }; /* Subroutines */ static XPRMdsofct tabfct[]= { {"", XPRM_FCT_GETPAR, XPRM_TYP_NOT,0,NULL, slv_lc_getpar}, {"", XPRM_FCT_SETPAR, XPRM_TYP_NOT,0,NULL, slv_lc_setpar}, {"getprobstat", 2000, XPRM_TYP_INT,0,NULL, slv_lc_getpstat}, {"minimise", 2100, XPRM_TYP_NOT,1,"c", slv_lc_minim}, {"minimize", 2100, XPRM_TYP_NOT,1,"c", slv_lc_minim}, {"maximise", 2101, XPRM_TYP_NOT,1,"c", slv_lc_maxim}, {"maximize", 2101, XPRM_TYP_NOT,1,"c", slv_lc_maxim}, {"setcbintsol", 2102, XPRM_TYP_NOT,1,"s", slv_lc_setcbintsol}, {"setcbintsol", 2103, XPRM_TYP_NOT,1,"F()", slv_lc_setcbintsol_pr}, {"writeprob", 2104, XPRM_TYP_NOT,2,"ss", slv_lc_writepb} }; /* Types */ static XPRMdsotyp tabtyp[]= { {"mpproblem.mxp", 1, XPRM_DTYP_PROB|XPRM_DTYP_APPND, slv_pb_create, slv_pb_delete, NULL, NULL, slv_pb_copy} }; /* Services */ static XPRMdsoserv tabserv[]= { {XPRM_SRV_PARAM, (void *)slv_findparam}, {XPRM_SRV_PARLST, (void *)slv_nextparam}, {XPRM_SRV_RESET, (void *)slv_reset}, {XPRM_SRV_UNLOAD, (void *)slv_quitlib} }; /* Interface structure */ static XPRMdsointer dsointer= { sizeof(tabconst)/sizeof(XPRMdsoconst), tabconst, sizeof(tabfct)/sizeof(XPRMdsofct), tabfct, sizeof(tabtyp)/sizeof(XPRMdsotyp), tabtyp, sizeof(tabserv)/sizeof(XPRMdsoserv), tabserv }; /**** Structures used by this module ****/ static XPRMnifct mm; /* For storing the Mosel NI function table */ /* The "problem" type is used to record solution information and solver ref */ /* Mosel will maintain 1 instance of this type for each mpproblem object */ typedef struct SlvPb { struct SlvCtx *slctx; XPRSprob xpb; /* Solver problem */ int have; int is_mip; double *solval; /* Structures for storing solution values */ double *dualval; double *rcostval; double *slackval; XPRMproc cb_intsol; /* Solver callback (INTSOL) */ XPRMcontext saved_ctx; /* Mosel context (used by callbacks) */ struct SlvPb *prev,*next; } s_slvpb; typedef struct SlvCtx /* A context for this module */ { int pbid; /* ID of type "mpproblem.mxp" */ int options; /* Runtime options */ s_slvpb *probs; /* List of created problems */ } s_slvctx; static struct /* Parameters published by this module */ { char *name; int type; } myxprsparams[]= { {"myxp_verbose",XPRM_TYP_BOOL|XPRM_CPAR_READ|XPRM_CPAR_WRITE}, {"myxp_timelimit", XPRM_TYP_REAL|XPRM_CPAR_READ|XPRM_CPAR_WRITE}, {"myxp_lpstatus",XPRM_TYP_INT|XPRM_CPAR_READ}, {"myxp_mipstatus",XPRM_TYP_INT|XPRM_CPAR_READ}, {"myxp_lpobjval",XPRM_TYP_REAL|XPRM_CPAR_READ}, {"myxp_loadnames",XPRM_TYP_BOOL|XPRM_CPAR_READ|XPRM_CPAR_WRITE} }; #define SLV_NBPARAM (sizeof(myxprsparams)/sizeof(myxprsparams[0])) /* 'have' in 'slvpb': available solution info */ #define HAVESOL 1 #define HAVERCS 2 #define HAVEDUA 4 #define HAVESLK 8 #define HAVEMIPSOL 16 /* For decoding 'options' in the module context 'slvctx' */ #define OPT_VERBOSE 1 #define OPT_LOADNAMES 2 #define OBJ_MINIMIZE 0 #define OBJ_MAXIMIZE 1 /* Get problem pointer from module context */ #define SLVCTX2PB(o) ((s_slvpb*)(ctx->pbctx[(o)->pbid])) /* Prototypes of module-internal functions */ static int slv_optim(XPRMcontext ctx, struct SlvCtx *slctx, int objsense, XPRMlinctr obj); /* MIP solver interface */ static int slv_loadmat(XPRMcontext ctx, void *mipctx,mm_matrix *m); static double slv_getsol_v(XPRMcontext ctx, void *mipctx,int what, int col); static double slv_getsol_c(XPRMcontext ctx, void *mipctx,int what, int row); static void slv_clearsol(XPRMcontext ctx, void *mipctx); /* Solver callback funtions */ static int XPRS_CC slv_cb_stopxprs(XPRSprob prob, s_slvpb *slpb); static void XPRS_CC slv_cb_output(XPRSprob prob, void *p, const char *ch, int n, int errtype); static void XPRS_CC slv_cb_intsol(XPRSprob opt_prob, s_slvpb *slpb); /* Memory management */ static void Free(void *ad); /* MIP solver interface structure for NI library function 'loadmat' */ static mm_mipsolver xpress= {{'N','G','L','E','R','1','2'}, {'+','I','B','P','S','R'}, slv_loadmat, slv_clearsol, slv_getsol_v, slv_getsol_c}; /************************************************/ /* Initialize the library just after loading it */ /************************************************/ DSO_INIT myxprs_init(XPRMnifct nifct, int *interver, int *libver, XPRMdsointer **interf) { int r; *interver=XPRM_NIVERS; /* The interface version we are using */ *libver=XPRM_MKVER(0,0,1); /* The version of the module: 0.0.1 */ *interf=&dsointer; /* Our module interface structure */ r=XPRSinit(NULL); /* Initialize the solver */ if((r!=0)&&(r!=32)) { nifct->dispmsg(NULL, "myxprs: I cannot initialize Xpress Optimizer.\n"); return 1; } mm=nifct; /* Retrieve the Mosel NI function table */ return 0; } /********************/ /***** Services *****/ /********************/ /****************************************/ /* Reset the myxprs interface for a run */ /****************************************/ static void *slv_reset(XPRMcontext ctx,void *libctx) { s_slvctx *slctx; /* End of execution: release context */ if(libctx!=NULL) { slctx=libctx; /* Release all remaining problems */ while(slctx->probs!=NULL) { slv_pb_delete(ctx,slctx,slctx->probs,-1); } free(slctx); return NULL; } else { /* Begin of execution: create context */ if((slctx=malloc(sizeof(s_slvctx)))==NULL) { mm->dispmsg(ctx,"myxprs: Out of memory error.\n"); return NULL; } memset(slctx,0,sizeof(s_slvctx)); /* Record the problem ID of our problem type */ mm->gettypeprop(ctx,mm->findtypecode(ctx,"mpproblem.mxp"),XPRM_TPROP_PBID, (XPRMalltypes*)&(slctx->pbid)); return (void *)slctx; } } /*************************************/ /* Called when unloading the library */ /*************************************/ static void slv_quitlib(void) { if(mm!=NULL) { XPRSfree(); mm=NULL; } } /****************************/ /* Find a control parameter */ /****************************/ static int slv_findparam(const char *name,int *type,int why,XPRMcontext ctx, void *libctx) { int n; for(n=0;n<SLV_NBPARAM;n++) { if(strcmp(name,myxprsparams[n].name)==0) { *type=myxprsparams[n].type; return n; } } return -1; } /*********************************************/ /* Return the next parameter for enumeration */ /*********************************************/ static void *slv_nextparam(void *ref,const char **name,const char **desc, int *type) { size_t cst; cst=(size_t)ref; if(cst>=SLV_NBPARAM) return NULL; else { *name=myxprsparams[cst].name; *type=myxprsparams[cst].type; *desc=NULL; return (void *)(cst+1); } } /*************************************/ /***** Subroutines of the module *****/ /*************************************/ /*******************************/ /* Getting a control parameter */ /*******************************/ static int slv_lc_getpar(XPRMcontext ctx,void *libctx) { s_slvctx *slctx; int n; double r; slctx=libctx; n=XPRM_POP_INT(ctx); switch(n) { case 0: XPRM_PUSH_INT(ctx,(slctx->options&OPT_VERBOSE)?1:0); break; case 1: XPRSgetdblcontrol(SLVCTX2PB(slctx)->xpb,XPRS_TIMELIMIT,&r); XPRM_PUSH_REAL(ctx,r); break; case 2: XPRSgetintattrib(SLVCTX2PB(slctx)->xpb,XPRS_LPSTATUS,&n); XPRM_PUSH_INT(ctx,n); break; case 3: XPRSgetintattrib(SLVCTX2PB(slctx)->xpb,XPRS_MIPSTATUS,&n); XPRM_PUSH_INT(ctx,n); break; case 4: XPRSgetdblattrib(SLVCTX2PB(slctx)->xpb,XPRS_LPOBJVAL,&r); XPRM_PUSH_REAL(ctx,r); break; case 5: XPRM_PUSH_INT(ctx,(slctx->options&OPT_LOADNAMES)?1:0); break; default: mm->dispmsg(ctx,"myxprs: Wrong control parameter number.\n"); return XPRM_RT_ERROR; } return XPRM_RT_OK; } /*******************************/ /* Setting a control parameter */ /*******************************/ static int slv_lc_setpar(XPRMcontext ctx,void *libctx) { s_slvctx *slctx; int n; slctx=libctx; n=XPRM_POP_INT(ctx); switch(n) { case 0: slctx->options=XPRM_POP_INT(ctx)?(slctx->options|OPT_VERBOSE):(slctx->options&~OPT_VERBOSE); break; case 1: XPRSsetdblcontrol(SLVCTX2PB(slctx)->xpb,XPRS_TIMELIMIT,XPRM_POP_REAL(ctx)); break; case 5: slctx->options=XPRM_POP_INT(ctx)?(slctx->options|OPT_LOADNAMES):(slctx->options&~OPT_LOADNAMES); break; default: mm->dispmsg(ctx,"myxprs: Wrong control parameter number.\n"); return XPRM_RT_ERROR; } return XPRM_RT_OK; } /*****************************/ /* Return the problem status */ /*****************************/ static int slv_lc_getpstat(XPRMcontext ctx,void *libctx) { XPRM_PUSH_INT(ctx,mm->getprobstat(ctx)&XPRM_PBRES); return XPRM_RT_OK; } /**********************/ /* Maximise a problem */ /**********************/ static int slv_lc_maxim(XPRMcontext ctx,void *libctx) { XPRMlinctr obj; obj=XPRM_POP_REF(ctx); return slv_optim(ctx,(s_slvctx *)libctx,OBJ_MAXIMIZE,obj); } /**********************/ /* Minimise a problem */ /**********************/ static int slv_lc_minim(XPRMcontext ctx,void *libctx) { XPRMlinctr obj; obj=XPRM_POP_REF(ctx); return slv_optim(ctx,(s_slvctx *)libctx,OBJ_MINIMIZE,obj); } /********************************************/ /* Define integer callback (procedure name) */ /********************************************/ static int slv_lc_setcbintsol(XPRMcontext ctx,void *libctx) { s_slvctx *slctx; s_slvpb *slpb; XPRMalltypes result; const char *procname,*partyp; int nbpar,type; slctx=libctx; slpb=SLVCTX2PB(slctx); procname=XPRM_POP_REF(ctx); if(slpb->cb_intsol!=NULL) { mm->delref(ctx,XPRM_STR_PROC,slpb->cb_intsol); slpb->cb_intsol=NULL; } if(procname!=NULL) { /* The specified entity must be a procedure */ if(XPRM_STR(mm->findident(ctx,procname,&result,XPRM_FID_NOLOC))!=XPRM_STR_PROC) { mm->dispmsg(ctx,"myxprs: Wrong subroutine type for callback `intsol'.\n"); return XPRM_RT_ERROR; } do { /* The specified procedure must not have any arguments */ mm->getprocinfo(result.proc,&partyp,&nbpar,&type); type=XPRM_TYP(type); if((type==XPRM_TYP_NOT)&&(nbpar==0)) break; result.proc=mm->getnextproc(result.proc); } while(result.proc!=NULL); if(result.proc==NULL) { mm->dispmsg(ctx,"myxprs: Wrong procedure type for callback `intsol'.\n"); return XPRM_RT_ERROR; } else slpb->cb_intsol=mm->newref(ctx,XPRM_STR_PROC,result.proc); } return XPRM_RT_OK; } /*************************************************/ /* Define integer callback (procedure reference) */ /*************************************************/ static int slv_lc_setcbintsol_pr(XPRMcontext ctx,void *libctx) { s_slvctx *slctx; s_slvpb *slpb; mm_proc proc; slctx=libctx; slpb=SLVCTX2PB(slctx); proc=XPRM_POP_REF(ctx); if(proc==NULL) { mm->dispmsg(ctx,"myxprs: NULL reference.\n"); return XPRM_RT_ERROR; } else { if(slpb->cb_intsol!=NULL) mm->delref(ctx,XPRM_STR_PROC,slpb->cb_intsol); slpb->cb_intsol=mm->newref(ctx,XPRM_STR_PROC,proc); } return XPRM_RT_OK; } /******************/ /* Call writeprob */ /******************/ static int slv_lc_writepb(XPRMcontext ctx,void *libctx) { s_slvpb *slpb; int rts; char *dname,*options; char ename[MM_MAXPATHLEN]; slpb=SLVCTX2PB((s_slvctx*)libctx); dname=MM_POP_REF(ctx); options=MM_POP_REF(ctx); if((dname!=NULL)&& /* Make sure that the file can be created */ (mm->pathcheck(ctx,dname,ename,MM_MAXPATHLEN,MM_RCHK_WRITE|MM_RCHK_IODRV)==0)) { slpb->saved_ctx=ctx; /* Save current context for callbacks */ rts=XPRSwriteprob(slpb->xpb,XNLSconvstrto(XNLS_ENC_FNAME,ename,-1,NULL),options); slpb->saved_ctx=NULL; if(rts) { mm->dispmsg(ctx,"myxprs: Error when executing `writeprob'.\n"); return XPRM_RT_IOERR; } else return XPRM_RT_OK; } else { mm->dispmsg(ctx,"myxprs: Cannot write to '%s'.\n",dname!=NULL?dname:""); return XPRM_RT_IOERR; } } /******************************/ /***** Problem management *****/ /******************************/ /**************************/ /* Create a new "problem" */ /**************************/ static void *slv_pb_create(XPRMcontext ctx,void *libctx,void *toref,int type) { s_slvctx *slctx; s_slvpb *slpb; int i; slctx=libctx; if((slpb=malloc(sizeof(s_slvpb)))==NULL) { mm->dispmsg(ctx,"myxprs: Out of memory error.\n"); return NULL; } memset(slpb,0,sizeof(s_slvpb)); i=XPRScreateprob(&(slpb->xpb)); if((i!=0)&&(i!=32)) { mm->dispmsg(ctx,"myxprs: I cannot create the problem.\n"); free(slpb); return NULL; } slpb->slctx=slctx; /* Redirect solver messages to the Mosel streams */ XPRSaddcbmessage(slpb->xpb,slv_cb_output,slpb,0); XPRSsetintcontrol(slpb->xpb,XPRS_OUTPUTLOG,1); /* Define intsol callback */ XPRSaddcbintsol(slpb->xpb,(void*)slv_cb_intsol,slpb,0); /* Define log callbacks to report program interruption */ XPRSaddcblplog(slpb->xpb,(void*)slv_cb_stopxprs,slpb,0); XPRSaddcbcutlog(slpb->xpb,(void*)slv_cb_stopxprs,slpb,0); XPRSaddcbmiplog(slpb->xpb,(void*)slv_cb_stopxprs,slpb,0); XPRSaddcbbarlog(slpb->xpb,(void*)slv_cb_stopxprs,slpb,0); if(slctx->probs!=NULL) { slpb->next=slctx->probs; slctx->probs->prev=slpb; } /* else we are creating the main problem */ slctx->probs=slpb; return slpb; } /**********************/ /* Delete a "problem" */ /**********************/ static void slv_pb_delete(XPRMcontext ctx,void *libctx,void *todel,int type) { s_slvctx *slctx; s_slvpb *slpb; slctx=libctx; slpb=todel; slv_clearsol(ctx,slpb); XPRSdestroyprob(slpb->xpb); if(slpb->next!=NULL) /* Last in list */ slpb->next->prev=slpb->prev; if(slpb->prev==NULL) /* First in list */ slctx->probs=slpb->next; else slpb->prev->next=slpb->next; free(slpb); } /***********************************************************/ /* copy/reset/append: simply clear data of the destination */ /***********************************************************/ static int slv_pb_copy(XPRMcontext ctx,void *libctx,void *toinit,void *src,int ust) { s_slvpb *slpb; slpb=toinit; if(XPRM_CPY(ust)<XPRM_CPY_APPEND) slv_clearsol(ctx,slpb); return 0; } /**************************************/ /**** Solver & solution management ****/ /**************************************/ /****************************************************/ /* Optimise a problem: load it then call the solver */ /****************************************************/ static int slv_optim(XPRMcontext ctx,s_slvctx *slctx, int objsense,XPRMlinctr obj) { int c,i; s_slvpb *slpb; int result; double objval; slpb=SLVCTX2PB(slctx); slpb->saved_ctx=ctx; /* Save current context for callbacks */ slv_clearsol(ctx,slpb); /* Call function 'loadmat' to generate and load the matrix */ if(mm->loadmat(ctx,obj,NULL,MM_MAT_FORCE,&xpress,slpb)!=0) { mm->dispmsg(ctx,"myxprs: loadprob failed.\n"); slpb->saved_ctx=NULL; return XPRM_RT_ERROR; } /* Set optimisation direction */ XPRSchgobjsense(slpb->xpb,(objsense==OBJ_MINIMIZE)?XPRS_OBJ_MINIMIZE:XPRS_OBJ_MAXIMIZE); mm->setprobstat(ctx,XPRM_PBSOL,0); /* solution available for callbacks */ if(!slpb->is_mip) { /* Solve an LP problem */ c=XPRSlpoptimize(slpb->xpb,""); if(c!=0) { mm->dispmsg(ctx,"myxprs: optimisation failed.\n"); slpb->saved_ctx=NULL; return XPRM_RT_ERROR; } /* Retrieve solution status */ XPRSgetintattrib(slpb->xpb,XPRS_PRESOLVESTATE,&i); if(i&128) { XPRSgetdblattrib(slpb->xpb,XPRS_LPOBJVAL,&objval); result=XPRM_PBSOL; } else { objval=0; result=0; } XPRSgetintattrib(slpb->xpb,XPRS_LPSTATUS,&i); switch(i) { case XPRS_LP_OPTIMAL: result|=XPRM_PBOPT; break; case XPRS_LP_INFEAS: result|=XPRM_PBINF; break; case XPRS_LP_CUTOFF: result|=XPRM_PBOTH; break; case XPRS_LP_UNFINISHED: result|=XPRM_PBUNF; break; case XPRS_LP_UNBOUNDED: result|=XPRM_PBUNB; break; case XPRS_LP_CUTOFF_IN_DUAL: result|=XPRM_PBOTH; break; case XPRS_LP_UNSOLVED: result|=XPRM_PBOTH; break; } } else { /* Solve an MIP problem */ c=XPRSmipoptimize(slpb->xpb,""); if(c!=0) { mm->dispmsg(ctx,"myxprs: optimisation failed.\n"); slpb->saved_ctx=NULL; return XPRM_RT_ERROR; } /* Retrieve solution status */ XPRSgetintattrib(slpb->xpb,XPRS_MIPSTATUS,&i); switch(i) { case XPRS_MIP_LP_NOT_OPTIMAL: objval=0; result=XPRM_PBUNF; break; case XPRS_MIP_LP_OPTIMAL: objval=0; result=XPRM_PBUNF; break; case XPRS_MIP_NO_SOL_FOUND: /* Search incomplete: no solution */ objval=0; result=XPRM_PBUNF; break; case XPRS_MIP_SOLUTION: /* Search incomplete: there is a solution */ XPRSgetdblattrib(slpb->xpb,XPRS_MIPOBJVAL,&objval); result=XPRM_PBUNF|XPRM_PBSOL; slpb->have|=HAVEMIPSOL; break; case XPRS_MIP_INFEAS: /* Search complete: no solution */ objval=0; result=XPRM_PBINF; break; case XPRS_MIP_OPTIMAL: /* Search complete: best solution available */ XPRSgetdblattrib(slpb->xpb,XPRS_MIPOBJVAL,&objval); result=XPRM_PBSOL|XPRM_PBOPT; slpb->have|=HAVEMIPSOL; break; case XPRS_MIP_UNBOUNDED: objval=0; result=XPRM_PBUNB; break; default: result=XPRM_PBOTH; } if(!(result&XPRM_PBSOL)) { /* If no MIP solution try to get an LP solution */ XPRSgetintattrib(slpb->xpb,XPRS_PRESOLVESTATE,&i); if(i&128) { XPRSgetdblattrib(slpb->xpb,XPRS_LPOBJVAL,&objval); result|=XPRM_PBSOL; } } } /* Record solution status and objective value */ mm->setprobstat(ctx,result,objval); slpb->saved_ctx=NULL; return 0; } /**************************************/ /* Load the matrix into the optimiser */ /**************************************/ static int slv_loadmat(XPRMcontext ctx,void *mipctx,mm_matrix *m) { s_slvpb *slpb; s_slvctx *slctx; char pbname[80]; int c,r; slpb=mipctx; slctx=slpb->slctx; slv_clearsol(ctx,slpb); slpb->is_mip=(m->ngents>0) || (m->nsos>0); if(slctx->options&OPT_LOADNAMES) mm->genmpnames(ctx,MM_KEEPOBJ,NULL,0); sprintf(pbname,"xpb%p",slpb); if(slpb->is_mip) r=XPRSloadmip(slpb->xpb,pbname,m->ncol,m->nrow, m->qrtype,m->rhs,m->range,m->obj, m->mstart,NULL,m->mrwind,m->dmatval,m->dlb,m->dub, m->ngents,m->nsos,m->qgtype,m->mgcols,m->mplim,m->qstype, m->msstart,m->mscols,m->dref); else r=XPRSloadlp(slpb->xpb,pbname,m->ncol,m->nrow, m->qrtype,m->rhs,m->range,m->obj, m->mstart,NULL,m->mrwind,m->dmatval,m->dlb,m->dub); /* Objective constant term */ if(!r) { c=-1;r=XPRSchgobj(slpb->xpb,1, &c, &(m->fixobj)); } /* Load names if requested */ if(!r && (slctx->options&OPT_LOADNAMES)) { char *names,*n; size_t totlen,totlen2; size_t l; totlen=0; for(c=0;c<m->ncol;c++) { l=strlen(mm->getmpname(ctx,MM_MPNAM_COL,c)); totlen+=l+1; } totlen2=0; for(c=0;c<m->nrow;c++) { l=strlen(mm->getmpname(ctx,MM_MPNAM_ROW,c)); totlen2+=l+1; } if(totlen<totlen2) totlen=totlen2; totlen2=0; for(c=0;c<m->nsos;c++) { l=strlen(mm->getmpname(ctx,MM_MPNAM_SOS,c)); totlen2+=l+1; } if(totlen<totlen2) totlen=totlen2; if((names=malloc(totlen))==NULL) mm->dispmsg(ctx,"myxprs: Not enough memory for loading the names.\n"); else { n=names; for(c=0;c<m->ncol;c++) n+=strlen(strcpy(n,mm->getmpname(ctx,MM_MPNAM_COL,c)))+1; if((r=XPRSaddnames(slpb->xpb,2,names,0,m->ncol-1))!=0) mm->dispmsg(ctx,"myxprs: Error when executing `addnames'.\n"); if(!r && (m->nrow>0)) { n=names; for(c=0;c<m->nrow;c++) n+=strlen(strcpy(n,mm->getmpname(ctx,MM_MPNAM_ROW,c)))+1; if((r=XPRSaddnames(slpb->xpb,1,names,0,m->nrow-1))!=0) mm->dispmsg(ctx,"myxprs: Error when executing `addnames'.\n"); } if(!r && (m->nsos>0)) { n=names; for(c=0;c<m->nsos;c++) n+=strlen(strcpy(n,mm->getmpname(ctx,MM_MPNAM_SOS,c)))+1; if((r=XPRSaddnames(slpb->xpb,3,names,0,m->nsos-1))!=0) mm->dispmsg(ctx,"myxprs: Error when executing `addnames'.\n"); } free(names); } } return r; } /**********************************/ /* Get a solution (variable part) */ /**********************************/ static double slv_getsol_v(XPRMcontext ctx,void *mipctx,int what, int col) { s_slvpb *slpb; slpb=mipctx; if(what) { if(!(slpb->have&HAVERCS)) { if(slpb->rcostval==NULL) { int ncol; XPRSgetintattrib(slpb->xpb,XPRS_ORIGINALCOLS,&ncol); if((slpb->rcostval=malloc(ncol*sizeof(double)))==NULL) { mm->dispmsg(ctx,"myxprs: Out of memory error.\n"); return 0; } } if(slpb->have&HAVEMIPSOL) /* No rcost for a MIP => 0 */ { int ncol; XPRSgetintattrib(slpb->xpb,XPRS_ORIGINALCOLS,&ncol); memset(slpb->rcostval,0,ncol*sizeof(double)); } else XPRSgetlpsol(slpb->xpb,NULL,NULL,NULL,slpb->rcostval); slpb->have|=HAVERCS; } return slpb->rcostval[col]; } else { if(!(slpb->have&HAVESOL)) { if(slpb->solval==NULL) { int ncol; XPRSgetintattrib(slpb->xpb,XPRS_ORIGINALCOLS,&ncol); if((slpb->solval=malloc(ncol*sizeof(double)))==NULL) { mm->dispmsg(ctx,"myxprs: Out of memory error.\n"); return 0; } } if(slpb->have&HAVEMIPSOL) XPRSgetmipsol(slpb->xpb,slpb->solval,NULL); else XPRSgetlpsol(slpb->xpb,slpb->solval,NULL,NULL,NULL); slpb->have|=HAVESOL; } return slpb->solval[col]; } } /************************************/ /* Get a solution (constraint part) */ /************************************/ static double slv_getsol_c(XPRMcontext ctx,void *mipctx,int what, int row) { s_slvpb *slpb; slpb=mipctx; if(what) { if(!(slpb->have&HAVEDUA)) { if(slpb->dualval==NULL) { int nrow; XPRSgetintattrib(slpb->xpb,XPRS_ORIGINALROWS,&nrow); if((slpb->dualval=malloc(nrow*sizeof(double)))==NULL) { mm->dispmsg(ctx,"myxprs: Out of memory error.\n"); return 0; } } if(slpb->have&HAVEMIPSOL) /* No dual for a MIP => 0 */ { int nrow; XPRSgetintattrib(slpb->xpb,XPRS_ORIGINALROWS,&nrow); memset(slpb->dualval,0,nrow*sizeof(double)); } else XPRSgetlpsol(slpb->xpb,NULL,NULL,slpb->dualval,NULL); slpb->have|=HAVEDUA; } return slpb->dualval[row]; } else { if(!(slpb->have&HAVESLK)) { if(slpb->slackval==NULL) { int nrow; XPRSgetintattrib(slpb->xpb,XPRS_ORIGINALROWS,&nrow); if((slpb->slackval=malloc(nrow*sizeof(double)))==NULL) { mm->dispmsg(ctx,"myxprs: Out of memory error.\n"); return 0; } } if(slpb->have&HAVEMIPSOL) XPRSgetmipsol(slpb->xpb,NULL,slpb->slackval); else XPRSgetlpsol(slpb->xpb,NULL,slpb->slackval,NULL,NULL); slpb->have|=HAVESLK; } return slpb->slackval[row]; } } /*******************************/ /* Delete solution information */ /*******************************/ static void slv_clearsol(XPRMcontext ctx,void *mipctx) { s_slvpb *slpb; slpb=mipctx; Free(&(slpb->solval)); Free(&(slpb->dualval)); Free(&(slpb->rcostval)); Free(&(slpb->slackval)); slpb->have=0; } /*****************************************/ /* XPRS callback: log (for interruption) */ /*****************************************/ static int XPRS_CC slv_cb_stopxprs(XPRSprob prob,s_slvpb *slpb) { return mm->chkinterrupt(slpb->saved_ctx); } /*************************/ /* XPRS callback: Output */ /*************************/ static void XPRS_CC slv_cb_output(XPRSprob prob, void *p, const char *ch, int n, int errtype) { s_slvpb *slpb; slpb=(s_slvpb *)p; switch(errtype) { case 1: case 2: case 3: if(slpb->slctx->options&OPT_VERBOSE) { if(slpb->saved_ctx!=NULL) mm->printf(slpb->saved_ctx,"%.*s\n",n,ch); else mm->dispmsg(NULL,"%.*s\n",n,ch); } break; case 4: mm->dispmsg(slpb->saved_ctx,"%.*s\n",n,ch); break; default: if((slpb->slctx->options&OPT_VERBOSE) && (slpb->saved_ctx!=NULL)) mm->fflush(slpb->saved_ctx); } } /*************************/ /* XPRS callback: IntSol */ /*************************/ static void XPRS_CC slv_cb_intsol(XPRSprob opt_prob,s_slvpb *slpb) { XPRMalltypes result; XPRSprob xpb_save; if(slpb->cb_intsol!=NULL) { xpb_save=slpb->xpb; slpb->xpb=opt_prob; slpb->have=0; if(mm->callproc(slpb->saved_ctx,slpb->cb_intsol,&result)!=0) { mm->stoprun(slpb->saved_ctx); XPRSinterrupt(opt_prob,XPRS_STOP_CTRLC); } slpb->xpb=xpb_save; } } /****************/ /* Free + reset */ /****************/ static void Free(void *ad) { free(*(void **)ad); *(void **)ad=NULL; } | |||||||||||
© Copyright 2024 Fair Isaac Corporation. |