GEKKO: считать вхождения в массиве как условие - PullRequest
4 голосов
/ 19 июня 2020

Я использую gekko для INLP, т.е. целочисленного нелинейного программирования. У меня есть массив целочисленных переменных; однако мое условие состоит в том, что никакое значение не должно появляться более одного раза, т.е.

enter image description here

Код:

from gekko import GEKKO

model = GEKKO()

model.options.SOLVER = 1

x = model.Array(model.Var, 2, lb=0, ub=10, integer=True)

for m in range(11):
    model.Equation(x.count(m) <= 1)

model.Obj(sum(x))

model.solve()

Выдает ошибку: TypeError: объект типа int не имеет len ()

Почему я не могу сделать это таким образом?

1 Ответ

2 голосов
/ 20 июня 2020

Функция Numpy count не предоставляет градиенты для решателей и, следовательно, не поддерживается в уравнениях gekko. Альтернативный способ решения проблемы - использовать двоичную переменную b, чтобы определить, какие 2 числа выбраны от 0 до 10.

from gekko import GEKKO
model = GEKKO()
model.options.SOLVER = 1

n = 10
b = model.Array(model.Var, 11, lb=0, ub=1, integer=True)
y = [model.Intermediate(b[i]*i) for i in range(11)]
model.Equation(model.sum(b)==2)
model.Minimize(model.sum(y))

model.solve()

print('b: ' + str(b))
print('y: ' + str(y))

Решение:

b: [[1.0] [1.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0]]
y: [[0.0], [1.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0]]

Это правильно, потому что 0 и 1 выбраны для минимизации суммирования. Если вы переключитесь на m.Maximize(model.sum(y)), тогда решающая программа выберет 9 и 10.

b: [[0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [0.0] [1.0] [1.0]]
y: [[0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [0.0], [9.0], [10.0]]

Это не дает решения для x в виде массива только из 2 чисел. Также возможно, что вы можете использовать y в своем приложении.

Вот способ сжать y до x:

from gekko import GEKKO
model = GEKKO()
model.options.SOLVER = 1

b = model.Array(model.Var, (11,2), lb=0, ub=1, integer=True)
x = [None]*2
for j in range(2):
    x[j] = model.sum([model.Intermediate(b[i,j]*i) for i in range(11)])

model.Equations([model.sum(b[:,j])==1 for j in range(2)])
model.Equations([model.sum(b[i,:])<=1 for i in range(11)])

model.Minimize(model.sum(x))

model.solve()

print('b: ' + str(b))
print('x: ' + str(x))

Это дает решение:

b: [[[0.0] [1.0]]
 [[1.0] [0.0]]
 [[0.0] [0.0]]
 [[0.0] [0.0]]
 [[0.0] [0.0]]
 [[0.0] [0.0]]
 [[0.0] [0.0]]
 [[0.0] [0.0]]
 [[0.0] [0.0]]
 [[0.0] [0.0]]
 [[0.0] [0.0]]]
x: [[1.0], [0.0]]

Этот метод требует большего количества двоичных переменных, но решение все равно быстрое.

...