0

我尝试将以下约束添加到我的模型中。我的问题:函数 g() 期望 x 作为二进制 numpy 数组。所以结果 arr_a 取决于优化的每一步中 x 的当前值!之后,我希望这个数组乘以 x 的最大值小于 50。

如何动态添加此约束,以便在每次迭代时始终使用 x 的值正确计算 arr_a ,同时告诉模型保持约束 arr_a * x <= 50 ?目前我在向模型添加约束时遇到错误,因为 g() 期望 x 作为 numpy 数组来计算 arr_a、arr_b、arr_c ( g 在其计算中使用 np.where(x == 1) )。

#Init model
from ortools.sat.python import cp_model
model = cp_model.CpModel()
# Declare the variables
x = []
for i in range(self.ds.n_banks):
   x.append(model.NewIntVar(0, 1, "x[%i]" % (i)))   
#add bool vars
a = model.NewBoolVar('a')    
arr_a, arr_b, arr_c = g(df1,df2,df3,x)        
model.Add((arr_a.astype('int32') * x).max() <= 50).OnlyEnforceIf(a)
model.Add((arr_a.astype('int32') * x).max() > 50).OnlyEnforceIf(a.Not())

之后我添加了自然也依赖于 x 的目标函数。

model.Minimize(target(x))

def target(x):
   arr_a, arr_b, arr_c = g(df1,df2,df3,x)
   return  (3 * arr_b * x + 2 * arr_c * x).sum()

编辑

我的问题发生了一些变化,我设法让它毫无问题地工作。然而,我体验到约束从未真正得到满足!自定义函数是一个高度非线性函数,它需要 x==1 和 x == 0 的索引,并返回一个 numpy 数组。此外,无法使用 sat.solver 的预定义函数重新构建它。

#Init model
model = cp_model.CpModel()

# Declare the variables
x = [model.NewIntVar(0, 1, "x[%i]" % (i)) for i in range(66)]
# add hints
[model.AddHint(x[i],np.random.choice(2, 1, p=[0.4, 0.6])[0]) for i in range(66)]

open_elements = [model.NewBoolVar("open_elements[%i]" % (i)) for i in range(66)]
closed_elements = [model.NewBoolVar("closed_elements[%i]" % (i)) for i in range(6)]
        

# open indices as bool vars
for i in range(66):
     model.Add(x[i] == 1).OnlyEnforceIf(open_elements[i])
     model.Add(x[i] != 1).OnlyEnforceIf(open_elements[i].Not())
     model.Add(x[i] != 1).OnlyEnforceIf(closed_elements[i])
     model.Add(x[i] == 1).OnlyEnforceIf(closed_elements[i].Not())

model.Add((self-defined-function(np.where(open_elements), np.where(closed_elements), some_array).astype('int32') * x - some_vector).all() <= 0)

即使我应用了更简单的功能,它也无法正常工作。

model.Add((self-defined-function(x, some_array).astype('int32') * x - some_vector).all() <= 0)

我还尝试了以下方法:

arr_indices_open = []
arr_indices_closed = []
for i in range(66):
  if open_elements[i] == True:
     arr_indices_open.append(i)
  else:
     arr_indices_closed.append(i)

# final Constraint
arr_ = self-defined-function(arr_indices_open, arr_indices_closed, some_array)[0].astype('int32')
        
for i in range(66):
     model.Add(arr_[i] * x[i] <= some_other_vector[i])

自定义函数的一些最小示例,我只是尝试说 n_closed 应小于 10。即使求解器不满足该条件:

def self_defined_function(arr_indices_closed)
     return len(arr_indices_closed)

arr_ = self-defined-function(arr_indices_closed)
            
for i in range(66):
   model.Add(arr_ < 10)
4

1 回答 1

1

我不确定我是否完全理解这个问题,但一般来说,如果你想优化一个函数 g(x),你必须使用求解器的原语 ( docs ) 来实现它。

当您的计算与现有的求解器函数一致时,这样做会更容易,例如:如果您尝试计算线性表达式;但在尝试计算更复杂的东西时可能会变得更难。但是,我相信这是唯一的方法。

于 2021-05-02T13:01:54.010 回答