Гекко не может найти решение небольшой проблемы

Я делаю несколько тестов с библиотекой Gekko из python, и у меня есть небольшая проблема, решение которой я знаю. Полный код выглядит следующим образом:

from gekko import GEKKO

P = [[3.0,3.55,5.18,7.9,5.98],
    [1.56,1.56,2.48,3.15,2.38],
    [1.49,4.96,6.4,9.4,6.5]]

M = [[1,2,3,4,5],
     [6,7,8,9,10],
     [11,12,13,14,15]]

mm = M
pp = P
c1 = [300,200,150,250,180]
qtde = [10,10,10]
flex = [0.2,0.2,0.2]

m = GEKKO(remote=False)
ni = 3
nj = 5
x = [[m.Var(lb=0,integer=True) for j in range(nj)] for i in range(ni)]

s = 0
expr = []
for i in range(ni):
    for j in range(nj):
        s += x[i][j]*pp[i][j]
    expr.append(s)
    s = 0

for i in range(ni):
    for j in range(nj):
        if mm[i][j] == 0:
            m.Equation(x[i][j] == 0)


for i in range(len(flex)):
    if flex[i] == 0:
        m.Equation(sum([x[i][j] for j in range(nj)]) >= qtde[i])
    else:
        m.Equation(sum([x[i][j] for j in range(nj)]) >= qtde[i])
        m.Equation(sum([x[i][j] for j in range(nj)]) <= (1+flex[i])*qtde[i])


b = m.Array(m.Var,nj,integer=True,lb=0,ub=1)
iv = [None]*nj



for j in range(nj):
   iv[j] = m.sum([pp[i][j]*x[i][j] for i in range(ni)])
   m.Equation(iv[j] >= b[j]*c1[j])


m.Obj(m.sum(expr))

m.options.SOLVER=1 # switch to APOPT
m.solver_options = ['minlp_gap_tol 1.0e-2',\
                    'minlp_maximum_iterations 50000',\
                    'minlp_max_iter_with_int_sol 50000',\
                    'minlp_branch_method 1',\
                    'minlp_integer_leaves 2']


m.solve()    

for j in range(nj):
    m.Equation((1 - b[j])*iv[j] == 0)

m.options.SOLVER=1
m.solve()


Код завершается с ошибкой: Exception: @error: Solution Not Found. Что странно, ведь есть однозначное решение:

x = [[0,0,12,0,0],
     [0,0,12,0,0],
     [0,0,12,0,0]]

Еще более странным является тот факт, что даже если я сильно увеличу значение переменной qtde (например, qtde = [40,40,40]), алгоритм не сможет найти решение. Есть ли ошибка в том, как я пишу ограничения?


person donut    schedule 27.04.2020    source источник


Ответы (1)


Иногда решателям требуется помощь с более точным начальным предположением или выборочными границами, чтобы избежать проблемных решений. Вот кое-что, что помогает решить проблему с помощью только одного вызова решателя.

lower = [0,0,4,0,0]
for i in range(ni):
    for j in range(nj):
        x[i][j].value = 5
        x[i][j].lower = lower[j]
        x[i][j].upper = 20

Я всегда получаю сообщение infeasible solution, если устанавливаю нижнюю границу равной нулю для всех генераторов. Похоже, что решатель застревает на пробном решении всех нулей или когда все они ниже определенного порога. В этом случае мне пришлось ограничить средний блок выше 4, чтобы получить успешное решение, в то время как остальные равны нулю. Вот полный код:

from gekko import GEKKO

P = [[3.0,3.55,5.18,7.9,5.98],
    [1.56,1.56,2.48,3.15,2.38],
    [1.49,4.96,6.4,9.4,6.5]]

M = [[1,2,3,4,5],
     [6,7,8,9,10],
     [11,12,13,14,15]]

mm = M
pp = P
c1 = [300,200,150,250,180]
qtde = [10,10,10]
flex = [0.2,0.2,0.2]

m = GEKKO(remote=False)
ni = 3
nj = 5
x = [[m.Var(integer=True) for j in range(nj)] for i in range(ni)]

# Fix x at values to check the feasibility of the initial guess
#x = [[m.Param() for j in range(nj)] for i in range(ni)]

lower = [0,0,4,0,0]
for i in range(ni):
    for j in range(nj):
        x[i][j].value = 5
        x[i][j].lower = lower[j]
        x[i][j].upper = 20

s = 0
expr = []
for i in range(ni):
    for j in range(nj):
        s += x[i][j]*pp[i][j]
    expr.append(s)
    s = 0

for i in range(ni):
    for j in range(nj):
        if mm[i][j] == 0:
            m.Equation(x[i][j] == 0)


for i in range(len(flex)):
    if flex[i] == 0:
        m.Equation(sum([x[i][j] for j in range(nj)]) >= qtde[i])
    else:
        m.Equation(sum([x[i][j] for j in range(nj)]) >= qtde[i])
        m.Equation(sum([x[i][j] for j in range(nj)]) <= (1+flex[i])*qtde[i])


b = m.Array(m.Var,nj,value=0.5,integer=True,lb=0,ub=1)
iv = [None]*nj



for j in range(nj):
   iv[j] = m.sum([pp[i][j]*x[i][j] for i in range(ni)])
   m.Equation(iv[j] >= b[j]*c1[j])


m.Obj(m.sum(expr))

for j in range(nj):
    m.Equation((1 - b[j])*iv[j] <= 1e-5)

print('Initial guess: ' + str(x))

# solve as NLP first to see iterations
#m.solver_options = ['minlp_as_nlp 1']
#m.options.SOLVER = 1
#m.solve(debug=0)



# solve as MINLP
m.options.SOLVER=1 # switch to APOPT
m.solver_options = ['minlp_gap_tol 1.0e-2',\
                    'minlp_maximum_iterations 50000',\
                    'minlp_max_iter_with_int_sol 50000',\
                    'minlp_branch_method 1',\
                    'minlp_integer_leaves 2']

m.options.SOLVER=1
m.solve(disp=False)

print('Final solution: ' + str(x))

При идеальном решателе первоначальное предположение не требовалось бы, и можно было бы установить границы от 0 до infinity. Некоторые проблемы решить сложнее, например проблемы со смешанными целочисленными переменными и при использовании условий дополнительности. У вашей проблемы есть и то, и другое, поэтому я не удивлен, что решатель борется без первоначального предположения или соответствующих границ.

person John Hedengren    schedule 28.04.2020
comment
Есть ли способ программно проверить, нужны ли решателю настройки нижней границы, чтобы действительно работать? Я пытаюсь понять, как я могу решить эту проблему с помощью библиотеки или попробовать другой алгоритм. Я не думаю, что смогу узнать, какая нижняя граница будет больше нуля, прежде чем решатель запустится, может, мне стоит попробовать несколько инициализаций, допускающих несколько итераций? Я думаю, что я могу получить неоптимальные решения также с этими случайными инициализациями. - person donut; 28.04.2020
comment
Похоже, что когда все значения x равны нулю, он застревает. Может потребоваться, чтобы хотя бы один из генераторов был включен. Трудно сказать, что подойдет для проблемы. Вы также можете попробовать другие решатели MINLP, перечисленные здесь: en.wikipedia.org/wiki/List_of_optimization_software, но только APOPT есть в Gekko как опция MINLP. - person John Hedengren; 29.04.2020