M.frank - 9 months ago 72

C++ Question

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!

EDIT:

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]

where

`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

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:

```
SOS
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.

Source (Stackoverflow)