int CPLEXAddConstraint(LinEquation* InEquation) { int Status = 0; if (InEquation->ConstraintType != QUADRATIC && InEquation->ConstraintType != LINEAR) { FErrorFile() << "This constraint type is not supported in CPLEX: " << InEquation->ConstraintType << endl; FlushErrorFile(); return FAIL; } //First I check the number of rows. If it's larger than the index, then this constraint already exists and is only being changed int NumberRows = CPXgetnumrows (CPLEXenv, CPLEXModel); if (NumberRows <= InEquation->Index) { char* Sense = new char[1]; if (InEquation->EqualityType == EQUAL) { if (InEquation->QuadOne.size() > 0) { delete [] Sense; FErrorFile() << "Quadratic constraints cannot be equivalent constraints in CPLEX." << endl; FlushErrorFile(); return FAIL; } else { Sense[0] = 'E'; } } else if (InEquation->EqualityType == LESS) { Sense[0] = 'L'; } else if (InEquation->EqualityType == GREATER) { Sense[0] = 'G'; } else { delete [] Sense; FErrorFile() << "Unrecognized constraint type: " << InEquation->ConstraintType << endl; FlushErrorFile(); return FAIL; } double* Rhs = new double[1]; Rhs[0] = InEquation->RightHandSide; int* ColInd = NULL; int* RowInd = NULL; double* Coeff = NULL; if (InEquation->Variables.size() > 0) { ColInd = new int[int(InEquation->Variables.size())]; RowInd = new int[int(InEquation->Variables.size())]; Coeff = new double[int(InEquation->Variables.size())]; for (int i=0; i < int(InEquation->Variables.size()); i++) { Coeff[i] = InEquation->Coefficient[i]; RowInd[i] = 0; ColInd[i] = InEquation->Variables[i]->Index; } } if (InEquation->QuadOne.size() > 0) { if (CPXgetprobtype(CPLEXenv, CPLEXModel) == CPXPROB_LP) { Status = CPXchgprobtype(CPLEXenv, CPLEXModel, CPXPROB_QP); } else if (CPXgetprobtype(CPLEXenv, CPLEXModel) == CPXPROB_MILP) { Status = CPXchgprobtype(CPLEXenv, CPLEXModel, CPXPROB_MIQP); } int *QuadCol = new int[int(InEquation->QuadOne.size())]; int *QuadRow = new int[int(InEquation->QuadTwo.size())]; double *QuadCoeff = new double[int(InEquation->QuadCoeff.size())]; for (int i=0; i < int(InEquation->QuadOne.size()); i++) { QuadCol[i] = InEquation->QuadOne[i]->Index; QuadRow[i] = InEquation->QuadTwo[i]->Index; QuadCoeff[i] = InEquation->QuadCoeff[i]; } Status = CPXaddqconstr(CPLEXenv, CPLEXModel, int(InEquation->Variables.size()), int(InEquation->QuadOne.size()), Rhs[0], int(Sense[0]), ColInd, Coeff, QuadRow, QuadCol, QuadCoeff, NULL); delete [] QuadCol; delete [] QuadRow; delete [] QuadCoeff; } else if (InEquation->Variables.size() > 0) { string StrName = GetConstraintName(InEquation); char** Name = new char*; Name[0] = new char[StrName.length()+1]; strcpy(Name[0],StrName.data()); if ((InEquation->ConstraintMeaning.compare("chemical potential constraint") == 0) && (InEquation->Loaded == false) && (GetParameter("Check potential constraints feasibility").compare("1") == 0)) { Rhs[0] = InEquation->LoadedRightHandSide; Sense[0] = 'L'; } else if ((InEquation->ConstraintMeaning.compare("chemical potential constraint") == 0) && (InEquation->Loaded == false) && (InEquation->RightHandSide > 0.9*FLAG)){ Rhs[0] = FLAG; Sense[0] = 'L'; } Status = CPXaddrows(CPLEXenv, CPLEXModel, 0, 1, int(InEquation->Variables.size()), Rhs, Sense, RowInd, ColInd, Coeff, NULL, Name); delete [] Name[0]; delete [] Name; delete [] ColInd; delete [] RowInd; delete [] Coeff; } delete [] Rhs; delete [] Sense; if (Status) { FErrorFile() << "Failed to add constraint: " << InEquation->Index << endl; FlushErrorFile(); return FAIL; } } else { if (InEquation->QuadOne.size() > 0) { FErrorFile() << "Cannot change a quadratic constraint." << endl; FlushErrorFile(); return FAIL; } else { int NumberOfColumns = CPXgetnumcols(CPLEXenv, CPLEXModel); //First I reset all of the coefficients to zero for (int i=0; i < NumberOfColumns; i++) { Status = CPXchgcoef (CPLEXenv, CPLEXModel, InEquation->Index, i, 0); if (Status) { FErrorFile() << "Failed to change constraint: " << InEquation->Index << endl; FlushErrorFile(); return FAIL; } } //Next I set all of the nonzero coefficients according to the input equation for (int i=0; i < int(InEquation->Variables.size()); i++) { Status = CPXchgcoef (CPLEXenv, CPLEXModel, InEquation->Index, InEquation->Variables[i]->Index, InEquation->Coefficient[i]); if (Status) { FErrorFile() << "Failed to change constraint: " << InEquation->Index << endl; FlushErrorFile(); return FAIL; } } char* Sense = new char[1]; if (InEquation->ConstraintMeaning.compare("chemical potential constraint") == 0 && InEquation->Loaded == false) { Sense[0] = 'L'; Status = CPXchgcoef (CPLEXenv, CPLEXModel, InEquation->Index, -1, InEquation->LoadedRightHandSide); Status = CPXchgsense (CPLEXenv, CPLEXModel, 1, &(InEquation->Index), Sense); } else { //Now I change the RHS of the constraint Status = CPXchgcoef (CPLEXenv, CPLEXModel, InEquation->Index, -1, InEquation->RightHandSide); //Also change the sense of the constraint if nec if (InEquation->EqualityType == EQUAL) { if (InEquation->QuadOne.size() > 0) { delete [] Sense; FErrorFile() << "Quadratic constraints cannot be equivalent constraints in CPLEX." << endl; FlushErrorFile(); return FAIL; } else { Sense[0] = 'E'; } } else if (InEquation->EqualityType == LESS) { Sense[0] = 'L'; } else if (InEquation->EqualityType == GREATER) { Sense[0] = 'G'; } else { delete [] Sense; FErrorFile() << "Unrecognized constraint type: " << InEquation->ConstraintType << endl; FlushErrorFile(); return FAIL; } Status = CPXchgsense (CPLEXenv, CPLEXModel, 1, &(InEquation->Index), Sense); if (Status) { FErrorFile() << "Failed to change constraint: " << InEquation->Index << endl; FlushErrorFile(); return FAIL; } } } } return SUCCESS; }
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; int numcols; int numrows; int objsen; double *obj = NULL; double *rhs = NULL; char *sense = NULL; int *matbeg = NULL; int *matcnt = NULL; int *matind = NULL; double *matval = NULL; double *lb = NULL; double *ub = NULL; int *qmatbeg = NULL; int *qmatcnt = NULL; int *qmatind = NULL; double *qmatval = NULL; /* Declare pointers for the variables that will contain the data for the constraint that cuts off certain local optima. */ int numrows_extra; int numnnz_extra; double *rhs_extra = NULL; char *sense_extra = NULL; int *rmatbeg = NULL; int *rmatind = NULL; double *rmatval = NULL; int 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 = CPXopenCPLEX (&status); /* If an error occurs, the status value indicates the reason for failure. A call to CPXgeterrorstring will produce the text of the error message. Note that CPXopenCPLEX produces no output, so the only way to see the cause of the error is to use CPXgeterrorstring. 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"); CPXgeterrorstring (env, status, errmsg); fprintf (stderr, "%s", errmsg); goto TERMINATE; } /* Turn on output to the screen */ status = CPXsetintparam (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 = CPXcreateprob (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 = CPXcopylp (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 = CPXcopyquad (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_OptimalityTarget is set to accept first-order optimal solutions. */ status = CPXsetintparam (env, CPXPARAM_OptimalityTarget, CPX_OPTIMALITYTARGET_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 = CPXaddrows (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] = CPXgetnumrows (env, lp) - 1; status = CPXchgsense (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 = CPXwriteprob (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 CPXcreateprob, if necessary */ if ( lp != NULL ) { status = CPXfreeprob (env, &lp); if ( status ) { fprintf (stderr, "CPXfreeprob failed, error code %d.\n", status); } } /* Free up the CPLEX environment, if necessary */ if ( env != NULL ) { status = CPXcloseCPLEX (&env); /* Note that CPXcloseCPLEX produces no output, so the only way to see the cause of the error is to use CPXgeterrorstring. 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"); CPXgeterrorstring (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 */