M.frank M.frank - 11 months ago 78
C++ Question

Cplex C++, Sum IloNumVarArray and create SOS2

I am trying to implement the example 9.8 on page 179 of this book: link

I am using Cplex with the C++ interface.

I have troubles with initializing the SOS2 correctly. Here is the piece of my code for initializing the SOS2:

IloNumArray Cval(env, S);
IloNumVarArray C(env,S);
for (int s = 0; s < S; s++)
for (int k = 0; k < K; k++)
C[s] = IloNumVar(env, 0, 1);
C[s] += lamda[s][k];
Cval[s] = s;
model.add(IloSOS2(env, C, Cvals));

IloNumArray Bval(env, K);
IloNumVarArray B(env,K);
for (int k = 0; k < K; k++)
for (int s = 0; s < S; s++)
B[s] = IloNumVar(env, 0, 1);
B[k] += lamda[s][k];
Bval[k] = k;
model.add(IloSOS2(env, B, Bval));enter code here

I get the following error:

SOS2Test.cpp: In function ‘int main()’:
SOS2Test.cpp:74:16: error: no match for ‘operator+=’ (operand types
are ‘IloNumVar’ and ‘IloNumVar’)
sosvars[s] += lamda[s][k];
SOS2Test.cpp:87:16: error: no match for ‘operator+=’ (operand types
are ‘IloNumVar’ and ‘IloNumVar’)
sosvark[k] += lamda[s][k];

which of course if very clear. The operator '+=' is not implemented for that type. However, I cannot think of any other way of doing it and I am pretty sure that is indeed what I want to do.

Can anybody help me out or point me in the right direction?

Thanks in advance!


Here is what I am trying to do:

I am trying to approximate a non-linear function of two variables z = f(x,y). I have defined a grid of values (x,y) and associated non-negative weight to each point (i.e. the lamda[s][k]). Then if the values of (x,y) at the grid points are denoted (X[s], Y[s]), then the function can be approximated by the following relations:

x = Sum_s Sum_k X[s] * lamda[s][k]
y = Sum_s Sum_k Y[k] * lamda[s][k]
z = Sum_s Sum_k Z[s][k] * lamda[s][k]
1 = Sum_s Sum_k Z[s][k] lamda[s][k]


s = rows
k = columns

Then in order to use points that are closely related, we need to impose that at most four neighbouring lamda[s][k] can be non-zero. That can be imposed by the following constraints:

C[s] = sum_k lamda[s][k] for all s
B[k] = sum_k lamda[s][k] for all k

where C {C_1, C_2, .. C_s} and B {B_1, B_2, .. B_k} are taken as SOS2. Which imposes that at most two neighboring rows and two neighboring columns can be non-zero.

The code I have provided is for the last two constraints and what I am trying to do is for instance setting the C[s] (the s'th instance of C) equal to the sum of the lamda over s and k (row and column). Or in other words, for each row of the grid, the sum of the variables in row 1, should go into C[1], the sum of the variables in row 2 should go into C[2] etc. And for each column, the sum of the variables in column 1, should go into B[1] etc.

So in CPLEX term. I want to sum up a set of IloNumVars and set that equal to a position in a IloNumVarArray and then use that IloNumVarArray as a SOS2

I hope this clarifies it a bit.

Answer Source

I think you'll need an SOS2 constraint for every row and column of lamda, like so:

  for (int s = 0; s < S; s++) {
     model.add(IloSOS2(env, lamda[s]));

  IloNumVarArray B[K];
  for (int k = 0; k < K; k++) {
     B[k] = IloNumVarArray(env, S);
     for (int s = 0; s < S; s++) {
        B[k][s] = lamda[s][k];
     model.add(IloSOS2(env, B[k]));

That would produce, for example with a 4x4 matrix, the following SOS2 constraints in LP format:

 s1: S2 ::  x_0_0 : 1  x_0_1 : 2  x_0_2 : 3  x_0_3 : 4
 s2: S2 ::  x_1_0 : 1  x_1_1 : 2  x_1_2 : 3  x_1_3 : 4
 s3: S2 ::  x_2_0 : 1  x_2_1 : 2  x_2_2 : 3  x_2_3 : 4
 s4: S2 ::  x_3_0 : 1  x_3_1 : 2  x_3_2 : 3  x_3_3 : 4
 s5: S2 ::  x_0_0 : 1  x_1_0 : 2  x_2_0 : 3  x_3_0 : 4
 s6: S2 ::  x_0_1 : 1  x_1_1 : 2  x_2_1 : 3  x_3_1 : 4
 s7: S2 ::  x_0_2 : 1  x_1_2 : 2  x_2_2 : 3  x_3_2 : 4
 s8: S2 ::  x_0_3 : 1  x_1_3 : 2  x_2_3 : 3  x_3_3 : 4

So, if "x_0_0" is nonzero, then at most, "x_0_1", "x_1_0" and "x_1_1" would also be nonzero. You can see that the weights are auto-generated.