## Monday, August 16, 2010

### Iterating over a CPLEX Model: the Sequel

In a previous post is showed methods for iterating over the constraints of a CPLEX model.  One can also iterate over the model as a whole, but it turns out there are some quirks.  I'll enumerate a couple here. Whether they are also quirks in the C++ API I'm not sure.

The example model is the same small LP I used before, so I won't repeat it here. I will repeat the Java code to generate the model, though, so that I can tweak it later.

IloCplex cplex = new IloCplex();
IloNumVar[] vars = new IloNumVar[3];
vars[0] = cplex.numVar(0, Double.MAX_VALUE, "x");
vars[1] = cplex.numVar(0, Double.MAX_VALUE, "y");
vars[2] = cplex.numVar(0, Double.MAX_VALUE, "z");
cplex.scalProd(new double[]{1., 2., 3.}, vars),
"Obj")
);
// first constraint: x + y + z <= 5
// second constraint: y + 2z <= 3
cplex.scalProd(new double[]{0., 1., 2.}, vars),
3., "Con2");
// third constraint: x = z


This is pretty vanilla stuff.  If we print cplex.toString(), we get a nice, readable representation of the model:

IloModel  {
IloMaximize  : 1.0*x + 2.0*y + 3.0*z
IloRange Con1 : -infinity <= 1.0*x + 1.0*y + 1.0*z <= 5.0
IloRange Con2 : -infinity <= 1.0*y + 2.0*z <= 3.0
IloRange Con3 : 0.0 <= 1.0*x - 1.0*z <= 0.0
}


One (minor?) surprise so far: the objective function's somewhat unimaginative name ("Obj") did not print out. Now suppose that, for some reason, I want to disassemble the model into its components.  CPLEX will give me an iterator (an instance of java.util.Iterator) that I can use to iterate over the model.  Here comes the first surprise. Consider the following code, which should iterate over the model and print object names along with some context information:

Iterator it = cplex.iterator();
while (it.hasNext()) {
Object thing = it.next();
if (thing instanceof IloNumVar) {
System.out.print("Variable ");
}
else if (thing instanceof IloRange) {
System.out.print("Constraint ");
}
else if (thing instanceof IloObjective) {
System.out.print("Objective ");
}
System.out.println("named " +
}


Here's the output:

Objective named null
Variable named Con1
Variable named Con2
Variable named Con3


Notice anything funny?  Besides being consistent about denying that the objective function has a name, the iterator identifies the three constraints as variables (and does not identify any of the variables as anything). I'm told by an insider that listing the constraints as variables turns out to be a "feature" of CPLEX: for somewhat arcane reasons associated with using IloConstraint instances as arguments to the ifThen() method, IloRange implements the IloNumVar interface. At any rate, to use the current cliche, it is what it is.

So I have three things to fix: get CPLEX to acknowledge the name of the objective function; get CPLEX to distinguish constraints from variables; and get CPLEX to list the variables. There is an easy workaround for the first issue (objective name): I change the statement introducing the objective function to

cplex.addMaximize(
cplex.scalProd(new double[]{1., 2., 3.}, vars)
).setName("Obj");


Applying the setName method to the instance of IloObjective returned by addMaximize gets the name installed correctly. Fixing the third issue (finding the variables) is also simple: I can just add them explicitly into the model. It's redundant, given that they already occur in the model, but seems harmless and gets them listed. I'll insert the following line at the end of model construction:

cplex.add(vars);


The model output changes to

The model:
IloModel  {
IloMaximize Obj : 1.0*x + 2.0*y + 3.0*z
IloRange Con1 : -infinity <= 1.0*x + 1.0*y + 1.0*z <= 5.0
IloRange Con2 : -infinity <= 1.0*y + 2.0*z <= 3.0
IloRange Con3 : 0.0 <= 1.0*x - 1.0*z <= 0.0
x
y
z
}


(note that the variables are now listed at the end of the model). An alternative is to iterate over the expressions in the objective and constraint, using an  IloLinearNumExprIterator, and pick out the variables. It's less efficient, and it will find every variable multiple times, but if someone else generated the model and did not explicitly (and redundantly) add the variables, it may be the only viable approach. (And, let's face it, if you wrote the model yourself, you probably don't need to iterate over it looking for variables.)

Finally, the middle issue (distinguishing variables from constraints) is also fairly easy to solve. I can use some sort of naming convention to let me tell them apart by names, but there's an even easier method.  A constraint will appear as an instance of both IloNumVar and IloRange, so I can use the latter fact to screen out constraints.  I'll change the first if statement to

if (thing instanceof IloNumVar &&
!(thing instanceof IloRange)) {


which skips over the constraints. With those changes, the output finally looks right:

Objective named Obj
Constraint named Con1
Constraint named Con2
Constraint named Con3
Variable named x
Variable named y
Variable named z


1. Hi Paul,
I am looking for a way to list all variable names and their values. I defined my CplexModel in a function, and trying to print the values after solving in another function. I looked over and over again to C++ API but couldn't find a way to do it. I'm afraid even your solution (cplex.iterator()) is not available in C++.

Actually I don't understand why this is so difficult. When i call cplex.writeSolutions("file.sol") a nice solution file with variable names and values are printed. But somehow I cannot reach these values with a function.

There are still some tricks that I can apply, but I really want to use an easy function for this task. Do you know any function for this operation? (it could be for Java, maybe I can find the equivalent one for C++)

1. Sertalp,

First, just to be clear, iterating over a model is potentially useful when the model is imported from an external source (such as a file). If you construct the model in your own code, you should never need to iterate over it (because you know what it contains).

Second, the C++ API has a model iterator class (IloModel::Iterator) that should work about the same way my Java solution works.

I don't think CPLEX provides a method for printing a solution, because every user is going to want to format the output differently. If the model builder assigns names to the variables in their constructors (a practice I always recommend), printing the solution should be easy. When you call IloCplex::getValues to get the solution, you pass it an IloNumVarArray (call that 'vars') and an IloNumArray (call that 'vals'). In the print statement, you just need to pair each vals[i] with vars[i].getName().

If the variables are not named, you'll need to create names for them somewhere (in a string array, say 'names') and pair vals[i] with names[i].

2. Actually I know that I should use getValues to get values :) I have a question about it. For my code, I have
IloModel model
which is my basic model. Later, I want to add some cuts to this model and get another one, hence I'm creating a clone of it as
IloModel localCopy(env);
IloCplex cplex(localCopy);
So, what I wonder is if I solve "cplex" then does it also change the original values of the IloNumVar objects? As far as I understand, variables are special to the models, so I wonder what happens when I clone them.

3. Ah, I solved my problem. As you said, I used the iterator class.
Here is my solution for future reference

typedef IloIterator IloNumVarIterator; // Defines an iterator for IloNumVar
...
for (IloNumVarIterator it(env); it.ok(); ++it) {
try {
IloNumVar ext = *it;
cout << ext.getName() << ": " << cplex.getValue(ext) << endl;
} catch (IloException &e){
cerr << "Exception for variable " << ext.getName() << endl;
}
}

As you mentioned, usage of the IloNumVar itself as a parameter is the proper way. I just coded this way, because after cloning a model, the IloNumVar objects are also cloned (I guess).