Question

(Note: this question relates to IBM's ILOG CPLEX C++ API, documentation for which circa 2007 is in a pdf via HTTP here, and current materials for "version 12" available via IBM's FTP)

I have a matrix variable and I want to transfer their values to a matrix parameter. This is what I did:

typedef IloArray<IloNumArray> NumMatrix;
typedef IloArray<IloBoolVarArray> BoolVarMatrix;

NumMatrix ystar(env,I);
for(IloInt i = 0; i < I; i++){
    ystar[i] = IloNumArray(env, T);
}

BoolVarMatrix y(env,I);
for(IloInt i = 0; i < I; i++){
    y[i] = IloBoolVarArray(env, T);
}

for(IloInt i = 0; i < I; i++)
    cplex_master.getValues(ystar[i],y[i]);

But apparently getValues() only works with IloNumVarArray. How can I fix this?

Was it helpful?

Solution

IloCplex::getValue can be used for any IloNumVar. The return value is just a double, so you aren't restricted to the Concert data structures. The expression y[i][t] gives you an IloNumVar.

   for(IloInt i = 0; i < I; i++)
        for (IloInt t = 0; t < T; ++t)
        ystar[i][t] = cplex_master.getValue(y[i][t]);

OTHER TIPS

Guessing game time! :-) I'm going to just guess that cplex_master is of type IloCplex.

You have two freshly initialized 2-dimensional matrices, one of "boolean variables" and the other of "non-variable floating point numbers". It would appear you want to solve the boolean variables in y and have the results represented as floating point numbers in ystar.

  1. I'm not sure what solving blank matrices into each other accomplishes, so I'll just pretend they're not blank in your actual code

  2. I don't know what your scenario is transforming boolean matrices row-wise into floats, but maybe that's legitimate somehow

Anyway, IloCplex offers four variants of getValues(), all of which seem to operate on the two parameters which it names var and val:

public void getValues(const IloIntVarArray var, IloNumArray val) const
public void getValues(IloNumArray val, const IloIntVarArray var) const
public void getValues(const IloNumVarArray var, IloNumArray val) const
public void getValues(IloNumArray val, const IloNumVarArray var) const

They all have similar documentation which is to the effect of:

This method puts the solution values of the integer variables specified by the array var into the array val. Array val is resized to the same size as array var, and val[i] will contain the solution value for variable var[i].

There's an unusual design choice, in that val is being modified despite the fact that it is being passed by value. This is very non-C++ style. If you were dealing with integers, say, and wrote code like:

void myCopy(const int source, int destination) {
    /* what could go here? */
}

void someFunction() {
   int a = 10;
   int b;
   myCopy(a, b);
}

...there is no way to write the myCopy() routine with that prototype. The destination was passed by value so myCopy() can't reach back and change the value of b in the caller. Proper C++ would do it by using pointers or references (via &):

void myCopy(const int source, int& destination) {
    destination = source;
}

So this CPLEX C++ thing uses some kind of trick under the hood, I'd assume through that mysterious env parameter...to do things another way. It suffers from the typical case of what happens when people write weird language wrappers and don't know the idioms. Another post has been very critical here:

Is it just me or could the Cplex Concert API use some improvements?

Your question might be why the IloCplex doesn't take IloBoolVarArray as a var and an IloNumArray val, when it would be happy to take a IloIntVarArray as a var and an IloNumArray val. After all, IloBoolVarArray inherits from IloIntVarArray...shouldn't it be able to be used in the same slot?

But these pass-by-value semantics of the getValue() method inhibits the natural inheritance that might otherwise have worked. You can only pass derived classes in lieu of a base class when passing by pointer or reference. So no go on this.

If you really want to use an IloBoolVarArray instead of an IloIntVarArray, then I'd guess you'd have to go through an intermediate:

typedef IloArray<IloNumArray> NumMatrix;
typedef IloArray<IloBoolVarArray> BoolVarMatrix;
typedef IloArray<IloIntVarArray> IntVarMatrix;

NumMatrix ystar(env,I);
for(IloInt i = 0; i < I; i++){
    ystar[i] = IloNumArray(env, T);
}

BoolVarMatrix y(env,I);
for(IloInt i = 0; i < I; i++){
    y[i] = IloBoolVarArray(env, T);
}

IntVarMatrix yint(env,I);
for(IloInt i = 0; i < I; i++){
    for(IloInt t = 0; t < T; t++) {
        yint[i][t] = y[i][t];
    }
}

for(IloInt i = 0; i < I; i++)
    cplex_master.getValues(ystar[i],yint[i]);

The real question might be if using IloBool vs. IloInt is really worth it. It looks like an afterthought:

This type definition represents Boolean values in Concert Technology. Those values are IloTrue and IloFalse. Booleans are, in fact, integers of type IloInt. IloFalse is 0 (zero), and IloTrue is 1 (one). This type anticipates the built-in bool type proposed for standard C++. By using this type, you can be sure that the Concert Technology components of your application will port in this respect without source changes across different hardware platforms.

The arrays don't seem to have first-class treatment in solvers, but individual variables do:

An instance of IloBoolVar is extracted by IloSolver (documented in the ILOG Solver Reference Manual) as an instance of the class IlcBoolVar (also documented in the ILOG Solver Reference Manual).

An instance of IloBoolVar is extracted by IloCplex (documented in the ILOG CPLEX Reference Manual) as a column representing a numeric variable of type Bool with bounds as specified by IloBoolVar

I'd imagine avoiding it entirely is the best answer.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top