User error handling
In this section we use a small, infeasible problem to demonstrate how the error handling and all printed messages produced by BCL can be intercepted by the user's program. This is done by defining the corresponding BCL callback functions and changing the error handling flag. If error handling by BCL is disabled, then the definition of the error callback replaces the necessity to check for the return values of the BCL functions called by a program.
User error handling may be required if a BCL program is embedded in some larger application or if the program is run under Windows from an application with windows. In all other cases it will usually be sufficient to use the error handling provided by BCL.
#include <stdio.h> #include <setjmp.h> #include <string.h> #include "xprb.h" jmp_buf model_failed; /* Marker for the longjump */ void modinf(XPRBprob prob) { XPRBvar x[3]; XPRBctr ctr[2], cobj; int i; for(i=0;i<2;i++) /* Create two integer variables */ x[i]=XPRBnewvar(prob, XPRB_UI, XPRBnewname("x_%d",i),0,100); /* Create the constraints: C1: 2x0 + 3x1 >= 41 C2: x0 + 2x1 = 13 */ ctr[0]=XPRBnewctr(prob,"C1",XPRB_G); XPRBaddterm(ctr[0],x[0],2); XPRBaddterm(ctr[0],x[1],3); XPRBaddterm(ctr[0],NULL,41); ctr[1]=XPRBnewctr(prob,"C2",XPRB_E); XPRBaddterm(ctr[1],x[0],1); XPRBaddterm(ctr[1],x[1],2); XPRBaddterm(ctr[1],NULL,13); /* Uncomment the following line to cause an error in the model that triggers the user error handling: */ /* x[2]=XPRBnewvar(prob, XPRB_UI, "x_2", 10, 1); */ /* Objective: minimize x0+x1 */ cobj = XPRBnewctr(prob,"OBJ",XPRB_N); for(i=0;i<2;i++) XPRBaddterm(cobj, x[i], 1); XPRBsetobj(prob,cobj); /* Select objective function */ XPRBsetsense(prob,XPRB_MINIM); /* Obj. sense: minimization */ XPRBprintprob(prob); /* Print current problem */ XPRBlpoptimize(prob,""); /* Solve the LP */ XPRBprintf(prob, "problem status: %d LP status: %d MIP status: %d\n", XPRBgetprobstat(prob), XPRBgetlpstat(prob), XPRBgetmipstat(prob)); /* This problem is infeasible, that means the following command will fail. It prints a warning if the message level is at least 2 */ XPRBprintf(prob, "Objective: %g\n", XPRBgetobjval(prob)); for(i=0;i<2;i++) /* Print solution values */ XPRBprintf(prob, "%s:%g, ", XPRBgetvarname(x[i]), XPRBgetsol(x[i])); XPRBprintf(prob, "\n"); } /**** User error handling function ****/ void XPRB_CC usererror(XPRBprob prob, void *vp, int num, int type, const char *t) { printf("BCL error %d: %s\n", num, t); if(type==XPRB_ERR) longjmp(model_failed,1); } /**** User printing function ****/ void XPRB_CC userprint(XPRBprob prob, void *vp, const char *msg) { static int rtsbefore=1; /* Print 'BCL output' whenever a new output line starts, otherwise continue to print the current line. */ if(rtsbefore) printf("BCL output: %s", msg); else printf("%s",msg); rtsbefore=(msg[strlen(msg)-1]=='\n'); } int main(int argc, char **argv) { XPRBprob prob; XPRBseterrctrl(0); /* Switch to error handling by the user's program */ XPRBsetmsglevel(NULL,2); /* Set the printing flag to printing errors and warnings */ XPRBdefcbmsg(NULL, userprint, NULL); /* Define the printing callback func. */ if((prob=XPRBnewprob("ExplInf"))==NULL) { /* Initialize a new problem in BCL */ fprintf(stderr,"I cannot create the problem\n"); return 1; } else if(setjmp(model_failed)) /* Set a marker at this point */ { fprintf(stderr,"I cannot build the problem\n"); XPRBdelprob(prob); /* Delete the part of the problem that has been created */ XPRBdefcberr(prob, NULL, NULL); /* Reset the error callback */ return 1; } else { XPRBdefcberr(prob, usererror, NULL); /* Define the error handling callback */ modinf(prob); /* Formulate and solve the problem */ XPRBdefcberr(prob, NULL, NULL); /* Reset the error callback */ return 0; } }
Since this example defines the printing level and the printing callback function before creating the problem (that is, before BCL is initialized), we pass NULL as first argument.