2025, Dec 09 09:01
Как настроить Mosek Fusion для получения допустимого решения после тайм-аута
Почему после тайм-аута Mosek Fusion не отдает level() и как вернуть лучшую допустимую точку: AccSolutionStatus.Feasible, acceptedSolutionStatus для MIP
Работа с крупными задачами целочисленной оптимизации при ограничении по времени — обычная практика, но часто возникает проблема, когда нужно получить лучшую найденную на данный момент точку. В Mosek-Fusion запрос уровней переменных после истечения тайм-аута может завершиться ошибкой даже при наличии допустимого инкумбента. Ниже — как настроить Fusion так, чтобы он возвращал лучшую допустимую точку, если оптимизатор остановился раньше.
Воспроизведение проблемы
Ниже приведён фрагмент, который задаёт жёсткий лимит времени и затем пытается прочитать значения переменных. Решение прекращается по тайм-ауту, а попытка получить уровни приводит к исключению.
from mosek.fusion import *
import mosek.fusion.pythonic
import numpy as np
import sys
if __name__ == '__main__':
mdl = Model()
matA = np.array(np.random.randint(-1, 2, size=(128, 256)), dtype=np.float64)
dv = mdl.variable("x_bin", 256, Domain.binary())
vecb = np.array(np.random.randint(0, 20, size=(128)), dtype=np.float64)
coeffs = np.random.random(size=256)
mdl.constraint(matA @ dv <= vecb)
mdl.objective(ObjectiveSense.Maximize, dv.T @ coeffs)
mdl.setSolverParam("optimizerMaxTime", 1)
mdl.setLogHandler(sys.stdout)
mdl.solve()
print(dv.level())
Когда лимит времени исчерпан, Fusion сообщает статус «допустимо», но не «оптимально», и возникает ошибка:
SolutionError: Solution status is Feasible but Optimal is expected. Reason: Accessing integer solution whose problem status is PrimalFeasible.
Что происходит
По умолчанию Fusion ожидает оптимальное решение, когда вы запрашиваете значения методами вроде level(). После тайм-аута лучшим доступным результатом для целочисленной задачи может быть лишь допустимое, но не оптимальное решение. В таком состоянии Fusion отказывается возвращать уровни, если вы явно не разрешите получать не оптимальные, а просто допустимые решения.
Решение
Сообщите Fusion, что допустимое решение подходит для чтения значений. В API есть способ указать, какие статусы решения вы готовы принимать. Ключевая строка:
mdl.acceptedSolutionStatus(AccSolutionStatus.Feasible)
С этой настройкой Fusion позволит запрашивать значения даже если решатель завершился раньше, оставив допустимого инкумбента.
Исправленный пример
from mosek.fusion import *
import mosek.fusion.pythonic
import numpy as np
import sys
if __name__ == '__main__':
mdl = Model()
matA = np.array(np.random.randint(-1, 2, size=(128, 256)), dtype=np.float64)
dv = mdl.variable("x_bin", 256, Domain.binary())
vecb = np.array(np.random.randint(0, 20, size=(128)), dtype=np.float64)
coeffs = np.random.random(size=256)
mdl.constraint(matA @ dv <= vecb)
mdl.objective(ObjectiveSense.Maximize, dv.T @ coeffs)
mdl.acceptedSolutionStatus(AccSolutionStatus.Feasible)
mdl.setSolverParam("optimizerMaxTime", 1)
mdl.setLogHandler(sys.stdout)
mdl.solve()
print(dv.level())
Поведение модели и процесса решения остаётся прежним. Единственное отличие — мы указываем Fusion принимать допустимое решение для чтения значений после истечения лимита времени. Этот подход задокументирован здесь: https://docs.mosek.com/latest/pythonfusion/accessing-solution.html#retrieving-solution-values.
Зачем это нужно
Лимиты времени — практичные «ограждения» в целочисленной оптимизации. Если решатель останавливается по времени, а не по оптимальности, лучшая допустимая точка всё ещё может быть полезной. Разрешив Fusion принимать статус «допустимо», вы сразу получаете доступ к этим значениям — особенно удобно, если собираетесь продолжить работу с этим состоянием модели или донастроить её.
Выводы
Если решение завершилось по тайм-ауту и вам нужна лучшая допустимая точка, заранее укажите в Fusion, что её можно принимать, — до вызова level(). Это поможет работать без сбоев при ограниченных временных бюджетах и избавит от неожиданных исключений, когда достаточно допустимого, пусть и не оптимального, результата.