static int optimize_and_report (CPXENVptr env, CPXLPptr lp, int *solstat_p, double *objval_p) { int status = 0; double x[NUMCOLS]; double pi[TOTROWS]; double slack[TOTROWS]; double dj[NUMCOLS]; int i, j; int cur_numrows, cur_numcols; status = CPXXqpopt (env, lp); if ( status ) { fprintf (stderr, "Failed to optimize QP.\n"); goto TERMINATE; } status = CPXXsolution (env, lp, solstat_p, objval_p, x, pi, slack, dj); if ( status ) { fprintf (stderr, "Failed to obtain solution.\n"); goto TERMINATE; } /* Write the output to the screen. */ printf ("\nSolution status = %d\n", *solstat_p); printf ("Solution value = %f\n\n", *objval_p); /* The size of the problem should be obtained by asking CPLEX what the actual size is, rather than using what was passed to CPXXcopylp. cur_numrows and cur_numcols store the current number of rows and columns, respectively. */ cur_numrows = CPXXgetnumrows (env, lp); cur_numcols = CPXXgetnumcols (env, lp); for (i = 0; i < cur_numrows; i++) { printf ("Row %d: Slack = %10f Pi = %10f\n", i, slack[i], pi[i]); } for (j = 0; j < cur_numcols; j++) { printf ("Column %d: Value = %10f Reduced cost = %10f\n", j, x[j], dj[j]); } TERMINATE: return (status); } /* END optimize_and_report */
int main (void) { /* Declare pointers for the variables and arrays that will contain the data which define the LP problem. The setproblemdata() routine allocates space for the problem data. */ char *probname = NULL; CPXDIM numcols; CPXDIM numrows; int objsen; double *obj = NULL; double *rhs = NULL; char *sense = NULL; CPXNNZ *matbeg = NULL; CPXDIM *matcnt = NULL; CPXDIM *matind = NULL; double *matval = NULL; double *lb = NULL; double *ub = NULL; CPXNNZ *qmatbeg = NULL; CPXDIM *qmatcnt = NULL; CPXDIM *qmatind = NULL; double *qmatval = NULL; /* Declare and allocate space for the variables and arrays where we will store the optimization results including the status, objective value, variable values, dual values, row slacks and variable reduced costs. */ int solstat; double objval; double x[NUMCOLS]; double pi[NUMROWS]; double slack[NUMROWS]; double dj[NUMCOLS]; CPXENVptr env = NULL; CPXLPptr lp = NULL; int status; CPXDIM i, j; CPXDIM cur_numrows, cur_numcols; /* Initialize the CPLEX environment */ env = CPXXopenCPLEX (&status); /* If an error occurs, the status value indicates the reason for failure. A call to CPXXgeterrorstring will produce the text of the error message. Note that CPXXopenCPLEX produces no output, so the only way to see the cause of the error is to use CPXXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */ if ( env == NULL ) { char errmsg[CPXMESSAGEBUFSIZE]; fprintf (stderr, "Could not open CPLEX environment.\n"); CPXXgeterrorstring (env, status, errmsg); fprintf (stderr, "%s", errmsg); goto TERMINATE; } /* Turn on output to the screen */ status = CPXXsetintparam (env, CPXPARAM_ScreenOutput, CPX_ON); if ( status ) { fprintf (stderr, "Failure to turn on screen indicator, error %d.\n", status); goto TERMINATE; } /* Fill in the data for the problem. */ status = setproblemdata (&probname, &numcols, &numrows, &objsen, &obj, &rhs, &sense, &matbeg, &matcnt, &matind, &matval, &lb, &ub, &qmatbeg, &qmatcnt, &qmatind, &qmatval); if ( status ) { fprintf (stderr, "Failed to build problem data arrays.\n"); goto TERMINATE; } /* Create the problem. */ lp = CPXXcreateprob (env, &status, probname); /* A returned pointer of NULL may mean that not enough memory was available or there was some other problem. In the case of failure, an error message will have been written to the error channel from inside CPLEX. In this example, the setting of the parameter CPXPARAM_ScreenOutput causes the error message to appear on stdout. */ if ( lp == NULL ) { fprintf (stderr, "Failed to create problem.\n"); goto TERMINATE; } /* Now copy the LP part of the problem data into the lp */ status = CPXXcopylp (env, lp, numcols, numrows, objsen, obj, rhs, sense, matbeg, matcnt, matind, matval, lb, ub, NULL); if ( status ) { fprintf (stderr, "Failed to copy problem data.\n"); goto TERMINATE; } status = CPXXcopyquad (env, lp, qmatbeg, qmatcnt, qmatind, qmatval); if ( status ) { fprintf (stderr, "Failed to copy quadratic matrix.\n"); goto TERMINATE; } /* Optimize the problem and obtain solution. */ status = CPXXqpopt (env, lp); if ( status ) { fprintf (stderr, "Failed to optimize QP.\n"); goto TERMINATE; } status = CPXXsolution (env, lp, &solstat, &objval, x, pi, slack, dj); if ( status ) { fprintf (stderr, "Failed to obtain solution.\n"); goto TERMINATE; } /* Write the output to the screen. */ printf ("\nSolution status = %d\n", solstat); printf ("Solution value = %f\n\n", objval); /* The size of the problem should be obtained by asking CPLEX what the actual size is, rather than using what was passed to CPXXcopylp. cur_numrows and cur_numcols store the current number of rows and columns, respectively. */ cur_numrows = CPXXgetnumrows (env, lp); cur_numcols = CPXXgetnumcols (env, lp); for (i = 0; i < cur_numrows; i++) { printf ("Row %d: Slack = %10f Pi = %10f\n", i, slack[i], pi[i]); } for (j = 0; j < cur_numcols; j++) { printf ("Column %d: Value = %10f Reduced cost = %10f\n", j, x[j], dj[j]); } /* Finally, write a copy of the problem to a file. */ status = CPXXwriteprob (env, lp, "qpex1.lp", NULL); if ( status ) { fprintf (stderr, "Failed to write LP to disk.\n"); goto TERMINATE; } TERMINATE: /* Free up the problem as allocated by CPXXcreateprob, if necessary */ if ( lp != NULL ) { status = CPXXfreeprob (env, &lp); if ( status ) { fprintf (stderr, "CPXXfreeprob failed, error code %d.\n", status); } } /* Free up the CPLEX environment, if necessary */ if ( env != NULL ) { status = CPXXcloseCPLEX (&env); /* Note that CPXXcloseCPLEX produces no output, so the only way to see the cause of the error is to use CPXXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */ if ( status ) { char errmsg[CPXMESSAGEBUFSIZE]; fprintf (stderr, "Could not close CPLEX environment.\n"); CPXXgeterrorstring (env, status, errmsg); fprintf (stderr, "%s", errmsg); } } /* Free up the problem data arrays, if necessary. */ free_and_null ((char **) &probname); free_and_null ((char **) &obj); free_and_null ((char **) &rhs); free_and_null ((char **) &sense); free_and_null ((char **) &matbeg); free_and_null ((char **) &matcnt); free_and_null ((char **) &matind); free_and_null ((char **) &matval); free_and_null ((char **) &lb); free_and_null ((char **) &ub); free_and_null ((char **) &qmatbeg); free_and_null ((char **) &qmatcnt); free_and_null ((char **) &qmatind); free_and_null ((char **) &qmatval); return (status); } /* END main */
int main (void) { char probname[16]; /* Problem name is max 16 characters */ /* Declare and allocate space for the variables and arrays where we will store the optimization results including the status, objective value, variable values, dual values, row slacks and variable reduced costs. */ int solstat; double objval; double x[NUMCOLS]; double pi[NUMROWS]; double slack[NUMROWS]; double dj[NUMCOLS]; CPXENVptr env = NULL; CPXLPptr lp = NULL; int status; CPXDIM i, j; CPXDIM cur_numrows, cur_numcols; char errmsg[CPXMESSAGEBUFSIZE]; CPXCHANNELptr cpxerror = NULL; CPXCHANNELptr cpxwarning = NULL; CPXCHANNELptr cpxresults = NULL; CPXCHANNELptr ourchannel = NULL; char *errorlabel = "cpxerror"; char *warnlabel = "cpxwarning"; char *reslabel = "cpxresults"; char *ourlabel = "Our Channel"; CPXFILEptr fpout = NULL; /* Initialize the CPLEX environment */ env = CPXXopenCPLEX (&status); /* If an error occurs, the status value indicates the reason for failure. A call to CPXXgeterrorstring will produce the text of the error message. Note that CPXXopenCPLEX produces no output, so the only way to see the cause of the error is to use CPXXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */ /* Since the message handler is yet to be set up, we'll call our messaging function directly to print out any errors */ if ( env == NULL ) { ourmsgfunc ("Our Message", "Could not open CPLEX environment.\n"); goto TERMINATE; } /* Now get the standard channels. If an error, just call our message function directly. */ status = CPXXgetchannels (env, &cpxresults, &cpxwarning, &cpxerror, NULL); if ( status ) { ourmsgfunc ("Our Message", "Could not get standard channels.\n"); CPXXgeterrorstring (env, status, errmsg); ourmsgfunc ("Our Message", errmsg); goto TERMINATE; } /* Now set up the error channel first. The label will be "cpxerror" */ status = CPXXaddfuncdest (env, cpxerror, errorlabel, ourmsgfunc); if ( status ) { ourmsgfunc ("Our Message", "Could not set up error message handler.\n"); CPXXgeterrorstring (env, status, errmsg); ourmsgfunc ("Our Message", errmsg); } /* Now that we have the error message handler set up, all CPLEX generated errors will go through ourmsgfunc. So we don't have to use CPXXgeterrorstring to determine the text of the message. We can also use CPXXmsg to do any other printing. */ status = CPXXaddfuncdest (env, cpxwarning, warnlabel, ourmsgfunc); if ( status ) { CPXXmsg (cpxerror, "Failed to set up handler for cpxwarning.\n"); goto TERMINATE; } status = CPXXaddfuncdest (env, cpxresults, reslabel, ourmsgfunc); if ( status ) { CPXXmsg (cpxerror, "Failed to set up handler for cpxresults.\n"); goto TERMINATE; } /* Now turn on the iteration display. */ status = CPXXsetintparam (env, CPXPARAM_Simplex_Display, 2); if ( status ) { CPXXmsg (cpxerror, "Failed to turn on simplex display level.\n"); goto TERMINATE; } /* Create the problem. */ strcpy (probname, "example"); lp = CPXXcreateprob (env, &status, probname); /* A returned pointer of NULL may mean that not enough memory was available or there was some other problem. In the case of failure, an error message will have been written to the error channel from inside CPLEX. In this example, the setting of the parameter CPXPARAM_ScreenOutput causes the error message to appear on stdout. */ if ( lp == NULL ) { CPXXmsg (cpxerror, "Failed to create LP.\n"); goto TERMINATE; } /* Now populate the problem with the data. */ status = populatebycolumn (env, lp); if ( status ) { CPXXmsg (cpxerror, "Failed to populate problem data.\n"); goto TERMINATE; } /* Optimize the problem and obtain solution. */ status = CPXXlpopt (env, lp); if ( status ) { CPXXmsg (cpxerror, "Failed to optimize LP.\n"); goto TERMINATE; } status = CPXXsolution (env, lp, &solstat, &objval, x, pi, slack, dj); if ( status ) { CPXXmsg (cpxerror, "Failed to obtain solution.\n"); goto TERMINATE; } /* Write the output to the screen. We will also write it to a file as well by setting up a file destination and a function destination. */ ourchannel = CPXXaddchannel (env); if ( ourchannel == NULL ) { CPXXmsg (cpxerror, "Failed to set up our private channel.\n"); goto TERMINATE; } fpout = CPXXfopen ("lpex5.msg", "w"); if ( fpout == NULL ) { CPXXmsg (cpxerror, "Failed to open lpex5.msg file for output.\n"); goto TERMINATE; } status = CPXXaddfpdest (env, ourchannel, fpout); if ( status ) { CPXXmsg (cpxerror, "Failed to set up output file destination.\n"); goto TERMINATE; } status = CPXXaddfuncdest (env, ourchannel, ourlabel, ourmsgfunc); if ( status ) { CPXXmsg (cpxerror, "Failed to set up our output function.\n"); goto TERMINATE; } /* Now any message to channel ourchannel will go into the file and into the file opened above. */ CPXXmsg (ourchannel, "\nSolution status = %d\n", solstat); CPXXmsg (ourchannel, "Solution value = %f\n\n", objval); /* The size of the problem should be obtained by asking CPLEX what the actual size is, rather than using sizes from when the problem was built. cur_numrows and cur_numcols store the current number of rows and columns, respectively. */ cur_numrows = CPXXgetnumrows (env, lp); cur_numcols = CPXXgetnumcols (env, lp); for (i = 0; i < cur_numrows; i++) { CPXXmsg (ourchannel, "Row %d: Slack = %10f Pi = %10f\n", i, slack[i], pi[i]); } for (j = 0; j < cur_numcols; j++) { CPXXmsg (ourchannel, "Column %d: Value = %10f Reduced cost = %10f\n", j, x[j], dj[j]); } /* Finally, write a copy of the problem to a file. */ status = CPXXwriteprob (env, lp, "lpex5.lp", NULL); if ( status ) { CPXXmsg (cpxerror, "Failed to write LP to disk.\n"); goto TERMINATE; } TERMINATE: /* First check if ourchannel is open */ if ( ourchannel != NULL ) { int chanstat; chanstat = CPXXdelfuncdest (env, ourchannel, ourlabel, ourmsgfunc); if ( chanstat ) { strcpy (errmsg, "CPXXdelfuncdest failed.\n"); ourmsgfunc ("Our Message", errmsg); if (!status) status = chanstat; } if ( fpout != NULL ) { chanstat = CPXXdelfpdest (env, ourchannel, fpout); if ( chanstat ) { strcpy (errmsg, "CPXXdelfpdest failed.\n"); ourmsgfunc ("Our Message", errmsg); if (!status) status = chanstat; } CPXXfclose (fpout); } chanstat = CPXXdelchannel (env, &ourchannel); if ( chanstat ) { strcpy (errmsg, "CPXXdelchannel failed.\n"); ourmsgfunc ("Our Message", errmsg); if (!status) status = chanstat; } } /* Free up the problem as allocated by CPXXcreateprob, if necessary */ if ( lp != NULL ) { status = CPXXfreeprob (env, &lp); if ( status ) { strcpy (errmsg, "CPXXfreeprob failed.\n"); ourmsgfunc ("Our Message", errmsg); } } /* Now delete our function destinations from the 3 CPLEX channels. */ if ( cpxresults != NULL ) { int chanstat; chanstat = CPXXdelfuncdest (env, cpxresults, reslabel, ourmsgfunc); if ( chanstat && !status ) { status = chanstat; strcpy (errmsg, "Failed to delete cpxresults function.\n"); ourmsgfunc ("Our Message", errmsg); } } if ( cpxwarning != NULL ) { int chanstat; chanstat = CPXXdelfuncdest (env, cpxwarning, warnlabel, ourmsgfunc); if ( chanstat && !status ) { status = chanstat; strcpy (errmsg, "Failed to delete cpxwarning function.\n"); ourmsgfunc ("Our Message", errmsg); } } if ( cpxerror != NULL ) { int chanstat; chanstat = CPXXdelfuncdest (env, cpxerror, errorlabel, ourmsgfunc); if ( chanstat && !status ) { status = chanstat; strcpy (errmsg, "Failed to delete cpxerror function.\n"); ourmsgfunc ("Our Message", errmsg); } } /* Free up the CPLEX environment, if necessary */ if ( env != NULL ) { status = CPXXcloseCPLEX (&env); /* Note that CPXXcloseCPLEX produces no output, so the only way to see the cause of the error is to use CPXXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */ if ( status ) { strcpy (errmsg, "Could not close CPLEX environment.\n"); ourmsgfunc ("Our Message", errmsg); CPXXgeterrorstring (env, status, errmsg); ourmsgfunc ("Our Message", errmsg); } } return (status); } /* END main */
int main (void) { /* Declare pointers for the variables and arrays that will contain the data which define the LP problem. The setproblemdata() routine allocates space for the problem data. */ char *probname = NULL; CPXDIM numcols; CPXDIM numrows; int objsen; double *obj = NULL; double *rhs = NULL; char *sense = NULL; CPXNNZ *matbeg = NULL; CPXDIM *matcnt = NULL; CPXDIM *matind = NULL; double *matval = NULL; double *lb = NULL; double *ub = NULL; CPXNNZ *qmatbeg = NULL; CPXDIM *qmatcnt = NULL; CPXDIM *qmatind = NULL; double *qmatval = NULL; /* Declare pointers for the variables that will contain the data for the constraint that cuts off certain local optima. */ CPXDIM numrows_extra; CPXNNZ numnnz_extra; double *rhs_extra = NULL; char *sense_extra = NULL; CPXNNZ *rmatbeg = NULL; CPXDIM *rmatind = NULL; double *rmatval = NULL; CPXDIM rowind[1]; /* Declare and allocate space for the variables and arrays where we will store the optimization results including the status, objective value, variable values, dual values, row slacks and variable reduced costs. */ int solstat; double objval; CPXENVptr env = NULL; CPXLPptr lp = NULL; int status; /* Initialize the CPLEX environment */ env = CPXXopenCPLEX (&status); /* If an error occurs, the status value indicates the reason for failure. A call to CPXXgeterrorstring will produce the text of the error message. Note that CPXXopenCPLEX produces no output, so the only way to see the cause of the error is to use CPXXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */ if ( env == NULL ) { char errmsg[CPXMESSAGEBUFSIZE]; fprintf (stderr, "Could not open CPLEX environment.\n"); CPXXgeterrorstring (env, status, errmsg); fprintf (stderr, "%s", errmsg); goto TERMINATE; } /* Turn on output to the screen */ status = CPXXsetintparam (env, CPXPARAM_ScreenOutput, CPX_ON); if ( status ) { fprintf (stderr, "Failure to turn on screen indicator, error %d.\n", status); goto TERMINATE; } /* Fill in the data for the problem. */ status = setproblemdata (&probname, &numcols, &numrows, &objsen, &obj, &rhs, &sense, &matbeg, &matcnt, &matind, &matval, &lb, &ub, &qmatbeg, &qmatcnt, &qmatind, &qmatval, &numrows_extra, &numnnz_extra, &rhs_extra, &sense_extra, &rmatbeg, &rmatind, &rmatval); if ( status ) { fprintf (stderr, "Failed to build problem data arrays.\n"); goto TERMINATE; } /* Create the problem. */ lp = CPXXcreateprob (env, &status, probname); /* A returned pointer of NULL may mean that not enough memory was available or there was some other problem. In the case of failure, an error message will have been written to the error channel from inside CPLEX. In this example, the setting of the parameter CPXPARAM_ScreenOutput causes the error message to appear on stdout. */ if ( lp == NULL ) { fprintf (stderr, "Failed to create problem.\n"); goto TERMINATE; } /* Now copy the LP part of the problem data into the lp */ status = CPXXcopylp (env, lp, numcols, numrows, objsen, obj, rhs, sense, matbeg, matcnt, matind, matval, lb, ub, NULL); if ( status ) { fprintf (stderr, "Failed to copy problem data.\n"); goto TERMINATE; } status = CPXXcopyquad (env, lp, qmatbeg, qmatcnt, qmatind, qmatval); if ( status ) { fprintf (stderr, "Failed to copy quadratic matrix.\n"); goto TERMINATE; } /* When a non-convex objective function is present, CPLEX will return error CPXERR_Q_NOT_POS_DEF unless the parameter CPXPARAM_SolutionTarget is set to accept first-order optimal solutions. */ status = CPXXsetintparam (env, CPXPARAM_SolutionTarget, CPX_SOLUTIONTARGET_FIRSTORDER); if ( status ) goto TERMINATE; /* Optimize the problem and obtain solution. */ status = optimize_and_report(env, lp, &solstat, &objval); if ( status ) goto TERMINATE; /* Add a constraint to cut off the solution at (-1, 1) */ status = CPXXaddrows (env, lp, 0, numrows_extra, numnnz_extra, rhs_extra, sense_extra, rmatbeg, rmatind, rmatval, NULL, NULL); if ( status ) goto TERMINATE; status = optimize_and_report(env, lp, &solstat, &objval); if ( status ) goto TERMINATE; /* Reverse the sense of the new constraint to cut off the solution at (1, 1) */ rowind[0] = CPXXgetnumrows (env, lp) - 1; status = CPXXchgsense (env, lp, 1, rowind, "L"); if ( status ) goto TERMINATE; status = optimize_and_report(env, lp, &solstat, &objval); if ( status ) goto TERMINATE; /* Finally, write a copy of the problem to a file. */ status = CPXXwriteprob (env, lp, "indefqpex1.lp", NULL); if ( status ) { fprintf (stderr, "Failed to write LP to disk.\n"); goto TERMINATE; } TERMINATE: /* Free up the problem as allocated by CPXXcreateprob, if necessary */ if ( lp != NULL ) { status = CPXXfreeprob (env, &lp); if ( status ) { fprintf (stderr, "CPXXfreeprob failed, error code %d.\n", status); } } /* Free up the CPLEX environment, if necessary */ if ( env != NULL ) { status = CPXXcloseCPLEX (&env); /* Note that CPXXcloseCPLEX produces no output, so the only way to see the cause of the error is to use CPXXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */ if ( status ) { char errmsg[CPXMESSAGEBUFSIZE]; fprintf (stderr, "Could not close CPLEX environment.\n"); CPXXgeterrorstring (env, status, errmsg); fprintf (stderr, "%s", errmsg); } } /* Free up the problem data arrays, if necessary. */ free_and_null ((char **) &probname); free_and_null ((char **) &obj); free_and_null ((char **) &rhs); free_and_null ((char **) &sense); free_and_null ((char **) &matbeg); free_and_null ((char **) &matcnt); free_and_null ((char **) &matind); free_and_null ((char **) &matval); free_and_null ((char **) &lb); free_and_null ((char **) &ub); free_and_null ((char **) &qmatbeg); free_and_null ((char **) &qmatcnt); free_and_null ((char **) &qmatind); free_and_null ((char **) &qmatval); free_and_null ((char **) &rhs_extra); free_and_null ((char **) &sense_extra); free_and_null ((char **) &rmatbeg); free_and_null ((char **) &rmatind); free_and_null ((char **) &rmatval); return (status); } /* END main */
int main (int argc, char *argv[]) { /* Declare and allocate space for the variables and arrays where we will store the optimization results including the status, objective value, maximum bound violation, variable values, and basis. */ int solnstat, solnmethod, solntype; double objval, maxviol; double *x = NULL; int *cstat = NULL; int *rstat = NULL; CPXENVptr env = NULL; CPXLPptr lp = NULL; int status = 0; CPXDIM j; CPXDIM cur_numrows, cur_numcols; int method; char *basismsg; /* Check the command line arguments */ if (( argc != 3 ) || ( strchr ("podbn", argv[2][0]) == NULL ) ) { usage (argv[0]); goto TERMINATE; } /* Initialize the CPLEX environment */ env = CPXXopenCPLEX (&status); /* If an error occurs, the status value indicates the reason for failure. A call to CPXXgeterrorstring will produce the text of the error message. Note that CPXXopenCPLEX produces no output, so the only way to see the cause of the error is to use CPXXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */ if ( env == NULL ) { char errmsg[CPXMESSAGEBUFSIZE]; fprintf (stderr, "Could not open CPLEX environment.\n"); CPXXgeterrorstring (env, status, errmsg); fprintf (stderr, "%s", errmsg); goto TERMINATE; } /* Turn on output to the screen */ status = CPXXsetintparam (env, CPXPARAM_ScreenOutput, CPX_ON); if ( status ) { fprintf (stderr, "Failure to turn on screen indicator, error %d.\n", status); goto TERMINATE; } /* Create the problem, using the filename as the problem name */ lp = CPXXcreateprob (env, &status, argv[1]); /* A returned pointer of NULL may mean that not enough memory was available or there was some other problem. In the case of failure, an error message will have been written to the error channel from inside CPLEX. In this example, the setting of the parameter CPXPARAM_ScreenOutput causes the error message to appear on stdout. Note that most CPLEX routines return an error code to indicate the reason for failure. */ if ( lp == NULL ) { fprintf (stderr, "Failed to create LP.\n"); goto TERMINATE; } /* Now read the file, and copy the data into the created lp */ status = CPXXreadcopyprob (env, lp, argv[1], NULL); if ( status ) { fprintf (stderr, "Failed to read and copy the problem data.\n"); goto TERMINATE; } if ( CPXXgetprobtype (env, lp) != CPXPROB_QP ) { fprintf (stderr, "Input file is not a QP. Exiting.\n"); goto TERMINATE; } /* Optimize the problem and obtain solution. */ switch (argv[2][0]) { case 'o': method = CPX_ALG_AUTOMATIC; break; case 'p': method = CPX_ALG_PRIMAL; break; case 'd': method = CPX_ALG_DUAL; break; case 'n': method = CPX_ALG_NET; break; case 'b': method = CPX_ALG_BARRIER; break; default: method = CPX_ALG_NONE; break; } status = CPXXsetintparam (env, CPXPARAM_QPMethod, method); if ( status ) { fprintf (stderr, "Failed to set the optimization method, error %d.\n", status); goto TERMINATE; } status = CPXXqpopt (env, lp); if ( status ) { fprintf (stderr, "Failed to optimize QP.\n"); goto TERMINATE; } solnstat = CPXXgetstat (env, lp); if ( solnstat == CPX_STAT_UNBOUNDED ) { printf ("Model is unbounded\n"); goto TERMINATE; } else if ( solnstat == CPX_STAT_INFEASIBLE ) { printf ("Model is infeasible\n"); goto TERMINATE; } else if ( solnstat == CPX_STAT_INForUNBD ) { printf ("Model is infeasible or unbounded\n"); goto TERMINATE; } status = CPXXsolninfo (env, lp, &solnmethod, &solntype, NULL, NULL); if ( status ) { fprintf (stderr, "Failed to obtain solution info.\n"); goto TERMINATE; } printf ("Solution status %d, solution method %d\n", solnstat, solnmethod); if ( solntype == CPX_NO_SOLN ) { fprintf (stderr, "Solution not available.\n"); goto TERMINATE; } status = CPXXgetobjval (env, lp, &objval); if ( status ) { fprintf (stderr, "Failed to obtain objective value.\n"); goto TERMINATE; } printf ("Objective value %.10g.\n", objval); /* The size of the problem should be obtained by asking CPLEX what the actual size is. cur_numrows and cur_numcols store the current number of rows and columns, respectively. */ cur_numcols = CPXXgetnumcols (env, lp); cur_numrows = CPXXgetnumrows (env, lp); /* Retrieve basis, if one is available */ if ( solntype == CPX_BASIC_SOLN ) { cstat = malloc (cur_numcols*sizeof(*cstat)); rstat = malloc (cur_numrows*sizeof(*rstat)); if ( cstat == NULL || rstat == NULL ) { fprintf (stderr, "No memory for basis statuses.\n"); goto TERMINATE; } status = CPXXgetbase (env, lp, cstat, rstat); if ( status ) { fprintf (stderr, "Failed to get basis; error %d.\n", status); goto TERMINATE; } } else { printf ("No basis available\n"); } /* Retrieve solution vector */ x = malloc (cur_numcols*sizeof(*x)); if ( x == NULL ) { fprintf (stderr, "No memory for solution.\n"); goto TERMINATE; } status = CPXXgetx (env, lp, x, 0, cur_numcols-1); if ( status ) { fprintf (stderr, "Failed to obtain primal solution.\n"); goto TERMINATE; } /* Write out the solution */ for (j = 0; j < cur_numcols; j++) { printf ( "Column %d: Value = %17.10g", j, x[j]); if ( cstat != NULL ) { switch (cstat[j]) { case CPX_AT_LOWER: basismsg = "Nonbasic at lower bound"; break; case CPX_BASIC: basismsg = "Basic"; break; case CPX_AT_UPPER: basismsg = "Nonbasic at upper bound"; break; case CPX_FREE_SUPER: basismsg = "Superbasic, or free variable at zero"; break; default: basismsg = "Bad basis status"; break; } printf (" %s",basismsg); } printf ("\n"); } /* Display the maximum bound violation. */ status = CPXXgetdblquality (env, lp, &maxviol, CPX_MAX_PRIMAL_INFEAS); if ( status ) { fprintf (stderr, "Failed to obtain bound violation.\n"); goto TERMINATE; } printf ("Maximum bound violation = %17.10g\n", maxviol); TERMINATE: /* Free up the basis and solution */ free_and_null ((char **) &cstat); free_and_null ((char **) &rstat); free_and_null ((char **) &x); /* Free up the problem, if necessary */ if ( lp != NULL ) { status = CPXXfreeprob (env, &lp); if ( status ) { fprintf (stderr, "CPXXfreeprob failed, error code %d.\n", status); } } /* Free up the CPLEX environment, if necessary */ if ( env != NULL ) { status = CPXXcloseCPLEX (&env); /* Note that CPXXcloseCPLEX produces no output, so the only way to see the cause of the error is to use CPXXgeterrorstring. For other CPLEX routines, the errors will be seen if the CPXPARAM_ScreenOutput indicator is set to CPX_ON. */ if ( status ) { char errmsg[CPXMESSAGEBUFSIZE]; fprintf (stderr, "Could not close CPLEX environment.\n"); CPXXgeterrorstring (env, status, errmsg); fprintf (stderr, "%s", errmsg); } } return (status); } /* END main */
/* * The function returns a true value if the tested KKT conditions are * satisfied and false otherwise. */ static int checkkkt (CPXCENVptr env, CPXLPptr lp, CPXDIM const *cone, double tol) { CPXDIM cols = CPXXgetnumcols (env, lp); CPXDIM rows = CPXXgetnumrows (env, lp); CPXDIM qcons = CPXXgetnumqconstrs (env, lp); double *dslack = NULL, *pi = NULL, *socppi = NULL; double *val = NULL, *rhs = NULL; CPXDIM *ind = NULL; char *sense = NULL; double *x = NULL, *slack = NULL, *qslack = NULL; double *sum = NULL; qbuf_type qbuf; CPXCHANNELptr resc, warnc, errc, logc; int ok = 0, skip = 0; int status; CPXDIM i, j, q; qbuf_init (&qbuf); /* Get the channels on which we may report. */ if ( (status = CPXXgetchannels (env, &resc, &warnc, &errc, &logc)) != 0 ) goto TERMINATE; /* Fetch results and problem data that we need to check the KKT * conditions. */ CPXXmsg (logc, "Fetching results ... "); if ( (cols > 0 && (dslack = malloc (cols * sizeof (*dslack))) == NULL) || (rows > 0 && (pi = malloc (rows * sizeof (*pi))) == NULL) || (qcons > 0 && (socppi = malloc (qcons * sizeof (*socppi))) == NULL) || (cols > 0 && (x = malloc (cols * sizeof (*x))) == NULL) || (rows > 0 && (sense = malloc (rows * sizeof (*sense))) == NULL ) || (rows > 0 && (slack = malloc (rows * sizeof (*slack))) == NULL ) || (qcons > 0 && (qslack = malloc (qcons * sizeof (*qslack))) == NULL) || (cols > 0 && (sum = malloc (cols * sizeof (*sum))) == NULL) || (cols > 0 && (val = malloc (cols * sizeof (*val))) == NULL) || (cols > 0 && (ind = malloc (cols * sizeof (*ind))) == NULL) || (rows > 0 && (rhs = malloc (rows * sizeof (*rhs))) == NULL) ) { CPXXmsg (errc, "Out of memory!\n"); goto TERMINATE; } /* Fetch problem data. */ if ( (status = CPXXgetsense (env, lp, sense, 0, rows - 1)) != 0 ) goto TERMINATE; if ( (status = CPXXgetrhs (env, lp, rhs, 0, rows - 1)) != 0 ) goto TERMINATE; /* Fetch solution information. */ if ( (status = CPXXgetx (env, lp, x, 0, cols - 1)) != 0 ) goto TERMINATE; if ( (status = CPXXgetpi (env, lp, pi, 0, rows - 1)) != 0 ) goto TERMINATE; if ( (status = getsocpconstrmultipliers (env, lp, dslack, socppi)) != 0 ) goto TERMINATE; if ( (status = CPXXgetslack (env, lp, slack, 0, rows - 1)) != 0 ) goto TERMINATE; if ( (status = CPXXgetqconstrslack (env, lp, qslack, 0, qcons - 1)) != 0 ) goto TERMINATE; CPXXmsg (logc, "ok.\n"); /* Print out the solution data we just fetched. */ CPXXmsg (resc, "x = ["); for (j = 0; j < cols; ++j) CPXXmsg (resc, " %+7.3f", x[j]); CPXXmsg (resc, " ]\n"); CPXXmsg (resc, "dslack = ["); for (j = 0; j < cols; ++j) CPXXmsg (resc, " %+7.3f", dslack[j]); CPXXmsg (resc, " ]\n"); CPXXmsg (resc, "pi = ["); for (i = 0; i < rows; ++i) CPXXmsg (resc, " %+7.3f", pi[i]); CPXXmsg (resc, " ]\n"); CPXXmsg (resc, "slack = ["); for (i = 0; i < rows; ++i) CPXXmsg (resc, " %+7.3f", slack[i]); CPXXmsg (resc, " ]\n"); CPXXmsg (resc, "socppi = ["); for (q = 0; q < qcons; ++q) CPXXmsg (resc, " %+7.3f", socppi[q]); CPXXmsg (resc, " ]\n"); CPXXmsg (resc, "qslack = ["); for (q = 0; q < qcons; ++q) CPXXmsg (resc, " %+7.3f", qslack[q]); CPXXmsg (resc, " ]\n"); /* Test primal feasibility. */ CPXXmsg (logc, "Testing primal feasibility ... "); /* This example illustrates the use of dual vectors returned by CPLEX * to verify dual feasibility, so we do not test primal feasibility * here. */ CPXXmsg (logc, "ok.\n"); /* Test dual feasibility. * We must have * - for all <= constraints the respective pi value is non-negative, * - for all >= constraints the respective pi value is non-positive, * - since all quadratic constraints are <= constraints the socppi * value must be non-negative for all quadratic constraints, * - the dslack value for all non-cone variables must be non-negative. * Note that we do not support ranged constraints here. */ CPXXmsg (logc, "Testing dual feasibility ... "); for (i = 0; i < rows; ++i) { switch (sense[i]) { case 'L': if ( pi[i] < -tol ) { CPXXmsg (errc, "<= row %d has invalid dual multiplier %f.\n", i, pi[i]); goto TERMINATE; } break; case 'G': if ( pi[i] > tol ) { CPXXmsg (errc, ">= row %d has invalid dual multiplier %f.\n", i, pi[i]); goto TERMINATE; } break; case 'E': /* Nothing to check here. */ break; } } for (q = 0; q < qcons; ++q) { if ( socppi[q] < -tol ) { CPXXmsg (errc, "Quadratic constraint %d has invalid dual multiplier %f.\n", q, socppi[q]); goto TERMINATE; } } for (j = 0; j < cols; ++j) { if ( cone[j] == NOT_IN_CONE && dslack[j] < -tol ) { CPXXmsg (errc, "dslack value for column %d is invalid: %f\n", j, dslack[j]); goto TERMINATE; } } CPXXmsg (logc, "ok.\n"); /* Test complementary slackness. * For each constraint either the constraint must have zero slack or * the dual multiplier for the constraint must be 0. Again, we must * consider the special case in which a variable is not explicitly * contained in a second order cone constraint (conestat[j] == 0). */ CPXXmsg (logc, "Testing complementary slackness ... "); for (i = 0; i < rows; ++i) { if ( fabs (slack[i]) > tol && fabs (pi[i]) > tol ) { CPXXmsg (errc, "Complementary slackness not satisfied for row %d (%f, %f)\n", i, slack[i], pi[i]); goto TERMINATE; } } for (q = 0; q < qcons; ++q) { if ( fabs (qslack[q]) > tol && fabs (socppi[q]) > tol ) { CPXXmsg (errc, "Complementary slackness not satisfied for cone %d (%f, %f).\n", q, qslack[q], socppi[q]); goto TERMINATE; } } for (j = 0; j < cols; ++j) { if ( cone[j] == NOT_IN_CONE ) { if ( fabs (x[j]) > tol && fabs (dslack[j]) > tol ) { CPXXmsg (errc, "Complementary slackness not satisfied for non-cone variable %f (%f, %f).\n", j, x[j], dslack[j]); goto TERMINATE; } } } CPXXmsg (logc, "ok.\n"); /* Test stationarity. * We must have * c - g[i]'(X)*pi[i] = 0 * where c is the objective function, g[i] is the i-th constraint of the * problem, g[i]'(x) is the derivate of g[i] with respect to x and X is the * optimal solution. * We need to distinguish the following cases: * - linear constraints g(x) = ax - b. The derivative of such a * constraint is g'(x) = a. * - second order constraints g(x[1],...,x[n]) = -x[1] + |(x[2],...,x[n])| * the derivative of such a constraint is * g'(x) = (-1, x[2]/|(x[2],...,x[n])|, ..., x[n]/|(x[2],...,x[n])| * (here |.| denotes the Euclidean norm). * - bound constraints g(x) = -x for variables that are not explicitly * contained in any second order cone constraint. The derivative for * such a constraint is g'(x) = -1. * Note that it may happen that the derivative of a second order cone * constraint is not defined at the optimal solution X (this happens if * X=0). In this case we just skip the stationarity test. */ CPXXmsg (logc, "Testing stationarity ... "); /* Initialize sum = c. */ if ( (status = CPXXgetobj (env, lp, sum, 0, cols - 1)) != 0 ) goto TERMINATE; /* Handle linear constraints. */ for (i = 0; i < rows; ++i) { CPXNNZ nz, surplus, beg; CPXNNZ n; status = CPXXgetrows (env, lp, &nz, &beg, ind, val, cols, &surplus, i, i); if ( status != 0 ) goto TERMINATE; for (n = 0; n < nz; ++n) { sum[ind[n]] -= pi[i] * val[n]; } } /* Handle second order cone constraints. */ for (q = 0; q < qcons; ++q) { double norm = 0.0; CPXNNZ n; if ( !getqconstr (env, lp, q, &qbuf) ) goto TERMINATE; for (n = 0; n < qbuf.qnz; ++n) { if ( qbuf.qval[n] > 0 ) norm += x[qbuf.qcol[n]] * x[qbuf.qcol[n]]; } norm = sqrt (norm); if ( fabs (norm) <= tol ) { CPXXmsg (warnc, "WARNING: Cannot test stationarity at non-differentiable point.\n"); skip = 1; break; } for (n = 0; n < qbuf.qnz; ++n) { if ( qbuf.qval[n] < 0 ) sum[qbuf.qcol[n]] -= socppi[q]; else sum[qbuf.qcol[n]] += socppi[q] * x[qbuf.qcol[n]] / norm; } } /* Handle variables that do not appear in any second order cone constraint. */ for (j = 0; !skip && j < cols; ++j) { if ( cone[j] == NOT_IN_CONE ) { sum[j] -= dslack[j]; } } /* Now test that all the entries in sum[] are 0. */ for (j = 0; !skip && j < cols; ++j) { if ( fabs (sum[j]) > tol ) { CPXXmsg (errc, "Stationarity not satisfied at index %d: %f\n", j, sum[j]); goto TERMINATE; } } CPXXmsg (logc, "ok.\n"); CPXXmsg (logc, "KKT conditions are satisfied.\n"); ok = 1; TERMINATE: if ( !ok ) CPXXmsg (logc, "failed.\n"); qbuf_clear (&qbuf); free (rhs); free (ind); free (val); free (sum); free (qslack); free (slack); free (sense); free (x); free (socppi); free (pi); free (dslack); return ok; }