static int populatebycolumn (CPXENVptr env, CPXLPptr lp) { int status = 0; double obj[NUMCOLS]; double lb[NUMCOLS]; double ub[NUMCOLS]; char const *colname[NUMCOLS]; CPXNNZ matbeg[NUMCOLS]; CPXDIM matind[NUMNZ]; double matval[NUMNZ]; double rhs[NUMROWS]; char sense[NUMROWS]; char const *rowname[NUMROWS]; /* To build the problem by column, create the rows, and then add the columns. */ status = CPXXchgobjsen (env, lp, CPX_MAX); /* Problem is maximization */ if ( status ) goto TERMINATE; /* Now create the new rows. First, populate the arrays. */ rowname[0] = "c1"; sense[0] = 'L'; rhs[0] = 20.0; rowname[1] = "c2"; sense[1] = 'L'; rhs[1] = 30.0; status = CPXXnewrows (env, lp, NUMROWS, rhs, sense, NULL, rowname); if ( status ) goto TERMINATE; /* Now add the new columns. First, populate the arrays. */ obj[0] = 1.0; obj[1] = 2.0; obj[2] = 3.0; matbeg[0] = 0; matbeg[1] = 2; matbeg[2] = 4; matind[0] = 0; matind[2] = 0; matind[4] = 0; matval[0] = -1.0; matval[2] = 1.0; matval[4] = 1.0; matind[1] = 1; matind[3] = 1; matind[5] = 1; matval[1] = 1.0; matval[3] = -3.0; matval[5] = 1.0; lb[0] = 0.0; lb[1] = 0.0; lb[2] = 0.0; ub[0] = 40.0; ub[1] = CPX_INFBOUND; ub[2] = CPX_INFBOUND; colname[0] = "x1"; colname[1] = "x2"; colname[2] = "x3"; status = CPXXaddcols (env, lp, NUMCOLS, NUMNZ, obj, matbeg, matind, matval, lb, ub, colname); if ( status ) goto TERMINATE; TERMINATE: return (status); } /* END populatebycolumn */
static int buildnetwork (CPXENVptr env, CPXLPptr lp) { char sense[NUMNODES]; double rhs[NUMNODES]; CPXDIM ind[2]; double val[2]; char const *name[1]; char buffer[100]; int i, j; CPXDIM varindex; CPXNNZ zero = 0; double dblzero = 0.0; double dblone = 1.0; char binary = 'B'; int status = 0; /* Create constraint placeholders --- One constraint for each node (flow constraints) */ for (i = 0; i < NUMNODES; i++) { rhs[i] = demand[i]; sense[i] = 'G'; } status = CPXXnewrows (env, lp, NUMNODES, rhs, sense, NULL, NULL); if ( status ) { fprintf (stderr, "Could not create new rows.\n"); goto TERMINATE; } /* Add flow variables */ for (j = 0; j < NUMEDGES; j++) { ind[0] = orig[j]; /* Flow leaves origin */ val[0] = -1.0; ind[1] = dest[j]; /* Flow arrives at destination */ val[1] = 1.0; name[0] = buffer; sprintf(buffer, "x%d%d", orig[j], dest[j]); status = CPXXaddcols (env, lp, 1, 2, &unitcost[j], &zero, ind, val, NULL, NULL, name); if ( status ) { fprintf (stderr, "Failed to add flow edge.\n"); goto TERMINATE; } } /* Add fixed charge variables */ for (j = 0; j < NUMEDGES; j++) { name[0] = buffer; sprintf(buffer, "f%d%d", orig[j], dest[j]); status = CPXXaddcols (env, lp, 1, 0, &fixedcost[j], &zero, ind, val, &dblzero, &dblone, name); if ( status ) { fprintf (stderr, "Failed to add fixed charge variable.\n"); goto TERMINATE; } varindex = NUMEDGES+j; status = CPXXchgctype (env, lp, 1, &varindex, &binary); if ( status ) { fprintf (stderr, "Failed to change variable type.\n"); goto TERMINATE; } } /* Add indicator constraints -- f = 0 -> x <= 0 */ for (j = 0; j < NUMEDGES; j++) { varindex = j; sprintf(buffer, "indicator%d", j); status = CPXXaddindconstr (env, lp, NUMEDGES+j, 1, 1, 0.0, 'L', &varindex, &dblone, buffer); if ( status ) { fprintf (stderr, "Failed to add indicator constraint."); goto TERMINATE; } } TERMINATE: return (status); } /* END buildnetwork */
static int colsteel (int numprod, int tweeks, double const *rate, double const *inv0, double const *avail, double const *flatmarket, double const *prodcost, double const *invcost, double const *flatrevenue, CPXENVptr env, CPXLPptr lp) { double *obj = NULL; char *sense = NULL; CPXNNZ *cmatbeg = NULL; CPXDIM *cmatind = NULL; double *cmatval = NULL; double *lb = NULL; double *ub = NULL; CPXCHANNELptr cpxerror = NULL; int t,p; /* Various loop counters */ CPXNNZ k; int status = 0; printf ("Building model by column.\n"); status = CPXXgetchannels (env, NULL, NULL, &cpxerror, NULL); if ( status ) goto TERMINATE; /* Set the objective sense to be maximize */ status = CPXXchgobjsen (env, lp, CPX_MAX); if ( status ) { CPXXmsg (cpxerror, "Could not change objective sense. Error %d\n", status); goto TERMINATE; } /* Set up the constraints for the problem */ /* First do the time constraints. Allocate space for a sense array. */ sense = malloc (tweeks*sizeof(*sense)); if ( sense == NULL ) { status = -2; goto TERMINATE; } for (t = 0; t < tweeks; t++) { sense[t] = 'L'; } status = CPXXnewrows (env, lp, tweeks, avail, sense, NULL, NULL); if ( status ) { CPXXmsg (cpxerror, "CPXXnewrows failed to add time constraints. Error %d\n", status); goto TERMINATE; } /* Free up the temporary sense array */ free (sense); sense = NULL; /* Now do the balance constraints. Can do this without temporary arrays, because the only nonzero is the negative of the inventory levels. */ for (p = 0; p < numprod; p++) { double temprhs = -inv0[p]; /* Fill in the initial inventory level */ status = CPXXnewrows (env, lp, 1, &temprhs, NULL, NULL, NULL); if ( status ) { CPXXmsg (cpxerror, "%sfor product %d. Error %d.\n", "CPXXnewrows failed to add initial inventory constraint\n", p, status); goto TERMINATE; } /* The remaining balance constraints have 0.0 as the rhs value, and are equality constraints. No need to specify the arrays */ status = CPXXnewrows (env, lp, tweeks-1, NULL, NULL, NULL, NULL); if ( status ) { CPXXmsg (cpxerror, "%sfor product %d. Error %d.\n", "CPXXnewrows failed to add other inventory constraints\n", p, status); goto TERMINATE; } } /* Now, add the variables. For each set of variables, we allocate * arrays to hold the data for the CPXXaddcols() calls, and then free * them up, so that each set of variables is maintained in a "local" * piece of code. */ /* First, do the Make variables. Each Make[p][t] variable has * objective coefficient -prodcost[p], and bounds of (0, +infinity). * Each Make[p][t] variable appears in the constraints * time(t) and balance(p,t). * Create temporary arrays to hold the objective coefficients, * lower and upper bounds, and matrix coefficients for one product. */ obj = malloc (tweeks*sizeof(*obj)); cmatbeg = malloc (tweeks*sizeof(*cmatbeg)); cmatind = malloc (2*tweeks*sizeof(*cmatind)); cmatval = malloc (2*tweeks*sizeof(*cmatval)); if ( obj == NULL || cmatbeg == NULL || cmatind == NULL || cmatval == NULL ) { status = -2; goto TERMINATE; } for (p = 0; p < numprod; p++) { k = 0; /* Reset the nonzero count for each product */ for (t = 0; t < tweeks; t++) { cmatbeg[t] = k; obj[t] = -prodcost[p]; cmatind[k] = t; cmatval[k] = 1.0/rate[p]; k++; cmatind[k] = (p + 1)*tweeks + t; cmatval[k] = 1.0; k++; } status = CPXXaddcols (env, lp, tweeks, k, obj, cmatbeg, cmatind, cmatval, NULL, NULL, NULL); if ( status ) { CPXXmsg (cpxerror, "%sfor product %d. Error %d.\n", "CPXXaddcols failed to add Make variables\n", p, status); goto TERMINATE; } } /* Free up allocated memory used to add Make variables */ free (obj); obj = NULL; free (cmatbeg); cmatbeg = NULL; free (cmatind); cmatind = NULL; free (cmatval); cmatval = NULL; /* Now do the Inv variables in (p,t) order. Each Inv[p][t] variable * has objective coefficient -invcost[p], and bounds of (0, +infinity). * If t is not tweeks-1, then Inv[p][t] appears in constraints * balance(p,t) and balance(p,t+1). * If t is tweeks-1, then Inv[p][t] appears only in * constraint balance(p,t). * Create temporary arrays to hold the objective coefficients, * lower and upper bounds, and matrix coefficients for one product. */ obj = malloc (tweeks*sizeof(*obj)); cmatbeg = malloc (tweeks*sizeof(*cmatbeg)); cmatind = malloc (2*tweeks*sizeof(*cmatind)); cmatval = malloc (2*tweeks*sizeof(*cmatval)); if ( obj == NULL || cmatbeg == NULL || cmatind == NULL || cmatval == NULL ) { status = -2; goto TERMINATE; } for (p = 0; p < numprod; p++) { k = 0; /* Reset the nonzero count for each product */ for (t = 0; t < tweeks; t++) { obj[t] = -invcost[p]; cmatbeg[t] = k; cmatind[k] = (p+1)*tweeks + t; cmatval[k] = -1.0; k++; cmatind[k] = (p+1)*tweeks + t+1; cmatval[k] = 1.0; k++; } /* Now repair the coefficient for t=tweeks-1 by passing k-1 as * the number of nonzeros, so that the last coefficient is * ignored. */ status = CPXXaddcols (env, lp, tweeks, k-1, obj, cmatbeg, cmatind, cmatval, NULL, NULL, NULL); if ( status ) { CPXXmsg (cpxerror, "%sfor product %d. Error %d.\n", "CPXXaddcols failed to add Inv variables\n", p, status); goto TERMINATE; } } /* Free up allocated memory used to add Inv variables */ free (obj); obj = NULL; free (cmatbeg); cmatbeg = NULL; free (cmatind); cmatind = NULL; free (cmatval); cmatval = NULL; /* Now do the Sell[p][t] variables. The objective coefficients of * Sell[p][t] is flatrevenue[p*tweeks+t], which means that * we can pull the objective coefficients from the slice of that * array. The lower bounds are 0.0, and the upper bounds are * flatmarket[p*tweeks+t], which means that we can pull the * upper bounds from the slice of that array. Each Sell variable * appears only in the balance(p,t) constraint. * Create temporary arrays to hold the bounds, and matrix * coefficients for one product. */ cmatbeg = malloc (tweeks*sizeof(*cmatbeg)); cmatind = malloc (tweeks*sizeof(*cmatind)); cmatval = malloc (tweeks*sizeof(*cmatval)); if ( cmatbeg == NULL || cmatind == NULL || cmatval == NULL ) { status = -2; goto TERMINATE; } for (p = 0; p < numprod; p++) { k = 0; /* Reset the nonzero count for each product */ for (t = 0; t < tweeks; t++) { cmatbeg[t] = k; cmatind[k] = (p+1)*tweeks + t; cmatval[k] = -1.0; k++; } status = CPXXaddcols (env, lp, tweeks, k, &flatrevenue[p*tweeks], cmatbeg, cmatind, cmatval, NULL, &flatmarket[p*tweeks], NULL); if ( status ) { CPXXmsg (cpxerror, "%sfor product %d. Error %d.\n", "CPXXaddcols failed to add Sell variables\n", p, status); goto TERMINATE; } } /* Free up allocated memory used to add Sell variables */ free (lb); lb = NULL; free (cmatbeg); cmatbeg = NULL; free (cmatind); cmatind = NULL; free (cmatval); cmatval = NULL; TERMINATE: if ( obj != NULL ) free ( obj ); if ( sense != NULL ) free ( sense ); if ( cmatbeg != NULL ) free ( cmatbeg ); if ( cmatind != NULL ) free ( cmatind ); if ( cmatval != NULL ) free ( cmatval ); if ( lb != NULL ) free ( lb ); if ( ub != NULL ) free ( ub ); return (status); } /* END colsteel */