Cplex C++,求和 IloNumVarArray 并创建 SOS2

Cplex C++, Sum IloNumVarArray and create SOS2

我正在尝试实现本书第 179 页的示例 9.8:link

我正在使用带有 C++ 接口的 Cplex。

我无法正确初始化 SOS2。这是我初始化 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

我收到以下错误:

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];
            ^

这当然很清楚了。该类型未实现运算符“+=”。但是,我想不出任何其他方法,我很确定这确实是我想做的。

任何人都可以帮助我或指出正确的方向吗?

提前致谢!

编辑:

这是我正在尝试做的事情:

我正在尝试逼近两个变量 z = f(x,y) 的非线性函数。我已经定义了一个值网格 (x,y) 和每个点的相关非负权重(即 lamda[s][k])。那么如果将网格点处的(x,y)的值记为(X[s], Y[s]),则函数可以近似为如下关系:

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

然后为了使用紧密相关的点,我们需要强制最多四个相邻的lamda[s][k]可以是非零的。这可以通过以下约束施加:

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

其中 C {C_1, C_2, .. C_s} 和 B {B_1, B_2, .. B_k } 被视为 SOS2。这规定最多两个相邻的行和两个相邻的列可以是非零的。

我提供的代码是针对最后两个约束的,我想做的是例如将 C[s](C 的第 s 个实例)设置为等于 s 上的 lamda 之和和 k(行和列)。或者换句话说,对于网格的每一行,第 1 行中变量的总和应该进入 C[1],第 2 行中变量的总和应该进入 C[2] 等。对于每一列,第 1 列中变量的总和,应进入 B[1] 等

所以在 CPLEX 术语中。我想总结一组 IloNumVars 并将其设置为等于 IloNumVarArray 中的位置,然后将该 IloNumVarArray 用作 SOS2

我希望这能澄清一点。

我认为 lamda 的每一行和每一列都需要一个 SOS2 约束,如下所示:

  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]));
  }

例如,对于 4x4 矩阵,这将产生以下 LP 格式的 SOS2 约束:

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

因此,如果 "x_0_0" 不为零,那么至多 "x_0_1"、"x_1_0" 和 "x_1_1" 也为非零。可以看到权重是自动生成的

我找到了一个解决方案,感谢@rkersh,他让我朝着正确的方向思考。有兴趣的reader,我是这样解决的:

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

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