FICO
FICO Xpress Optimization Examples Repository
FICO Optimization Community FICO Xpress Optimization Home
Back to examples browserPrevious exampleNext example

Basic LP/MIP solver interface for Xpress Optimizer

Description
Language extensions provided by this module:
  • type: extension of mpproblem
  • subroutines: procedures and functions
  • implementation of a callback function
  • services: reset, unload, accessing and enumerating parameters
  • parameters: real, integer, boolean
  • constants: integer


Source Files
By clicking on a file name, a preview is opened at the bottom of this page.
myxprs.c[download]

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;
}

Back to examples browserPrevious exampleNext example