Example: Using the Network Optimizer with the Callable Library

In the standard distribution of ILOG CPLEX, the file netex1.c contains code that creates, solves, and displays the solution of the network-flow problem illustrated in Figure 6.1.

Briefly, the main() function initializes the ILOG CPLEX environment and creates the problem object; it also calls the optimizer to solve the problem and retrieves the solution.

In detail, main() first calls the Callable Library routine CPXopenCPLEX(). As we explain in Initialize the ILOG CPLEX Environment, CPXopenCPLEX() must always be the first ILOG CPLEX routine called in a ILOG CPLEX Callable Library application. Those routines create the ILOG CPLEX environment and return a pointer (called env) to it. This pointer will be passed to every Callable Library routine. If this initialization routine fails, env will be NULL and the error code indicating the reason for the failure will be written to status. That error code can be transformed into a string by the Callable Library routine CPXgeterrorstring().

After main() initializes the ILOG CPLEX environment, it uses the Callable Library routine CPXsetintparam() to turn on the ILOG CPLEX screen indicator parameter CPX_PARAM_SCRIND so that ILOG CPLEX output appears on screen. If this parameter is turned off, ILOG CPLEX does not produce viewable output, neither on screen, nor in a log file. We recommend turning this parameter on when you are debugging your application.

The Callable Library routine CPXNETcreateprob() creates an empty problem object, that is, a minimum-cost network-flow problem with no arcs and no nodes.

The function buildNetwork() populates the problem object; that is, it loads the problem data into the problem object. Pointer variables in the example are initialized as NULL so that you can check whether they point to valid data-a good programming practice. The most important calls in this function are to the Callable Library routines, CPXNETaddnodes(), which adds nodes with the specified supply values to the network problem, and CPXNETaddarcs(), which adds the arcs connecting the nodes with the specified objective values and bounds. In this example, both routines are called with their last argument NULL indicating that no names are assigned to the network nodes and arcs. If you want to name arcs and nodes in your problem, pass an array of strings instead.

The function buildNetwork() also includes a few routines that are not strictly necessary to this example, but illustrate concepts you may find useful in other applications. To delete a node and all arcs dependent on that node, it uses the Callable Library routine CPXNETdelnodes(). To change the objective sense to minimization, it uses the Callable Library routine CPXNETchgobjsen().

Also buildNetwork() sets the row growth and column growth parameters CPX_PARAM_ROWGROWTH and CPX_PARAM_COLGROWTH. These parameters specify the amount that internal arrays are extended if more nodes or arcs are added than currently fit in allocated memory. If you build up a problem by adding nodes and arcs one by one, and if these parameters are set to a low value, then internal arrays will be frequently reallocated; frequent reallocation may negatively impact performance. Ideally, these parameters are set to the maximum number of nodes and arcs that the problem will ever have. This setting will avoid all reallocation and therefore provide best performance. The parameter CPX_PARAM_ROWGROWTH pertains to adding nodes to a network problem (and rows to an LP, QP, or MIP problem) whereas CPX_PARAM_COLGROWTH pertains to adding arcs to a network problem (or columns to an LP, QP, or MIP problem).

Let's return to main(), where it actually calls the network optimizer with the Callable Library routine, CPXNETprimopt(). If CPXNETprimopt() returns a nonzero value an error has occurred, otherwise, the optimization was successful. Before retrieving that solution, we allocate arrays to hold it. Then we use CPXNETsolution() to copy the solution into those arrays. After we display the solution on screen, we write the network problem into a file, netex1.net in the NET file format.

The TERMINATE: label is used as a place for the program to exit if any type of error occurs. Therefore, code following this label cleans up: it frees the memory that has been allocated for the solution data; it frees the network object by calling CPXNETfreeprob(); and it frees the ILOG CPLEX environment by calling CPXcloseCPLEX(). All freeing should be done only if the data is actually available. The Callable Library routine CPXcloseCPLEX() should always be the last ILOG CPLEX routine called in a ILOG CPLEX Callable Library application. In other words, all ILOG CPLEX objects that have been allocated should be freed before the call to CPXcloseCPLEX().


Previous Page: Preprocessing and the Network Optimizer  Return to Top Next Page: Complete Program: netex1.c