Я работал над проблемой комбинаторной оптимизации, которую можно смоделировать как целочисленное линейное программирование. Я реализовал его как проект на c ++ в Visual Studio 2017 и CPLEX1271. Поскольку существует экспоненциально много ограничений, я реализовал ленивые ограничения с помощью IloCplex :: LazyConstraintCallbackI. На мой взгляд, следующая процедура представляет собой создание оптимального решения: каждый раз, когда определяется целочисленное решение, LazyConstraintCallbackI будет проверять его и добавлять некоторые нарушенные ограничения в модель, пока не будет получено оптимальное целочисленное решение.
Однако объективные значения, данные моей реализацией для разных входов, не всегда верны. После почти годичной периодической отладки и тестирования я наконец выяснил причину, которая очень связана с проблемами, но может быть объяснена (надеюсь) следующим крошечным примером: целочисленное линейное программирование с использованием четырех переменных типа bool x1, x2, x3 и x4
minimize x1
subject to:
x1 ≥ x2
x1 ≥ x3
x1 ≥ x4
x2 + x3 ≥ 1
x1, x2, x3 and x4 ∈ {0, 1}
Результат, выдаваемый cplex:
Solution status = Optimal
Objective value = 1
x1 = 1
x2 = 1
x3 = 1
x4 = 1
Несомненно, объективное значение верное. Странно то, что cplex устанавливает x4 = 1. Несмотря на то, что x4 равно 1 или 0 не влияет на объективную ценность этого программирования. Но когда используется ленивый обратный вызов ограничений, это может привести к проблеме, добавив некорректного ограничения, а целочисленное программирование решается путем итеративного добавления нарушенных ограничений. Я хотел бы знать:
- почему cplex устанавливает "несвязанную" переменную x4 равной 1, а не 0?
- Что мне делать, чтобы сообщить CPLEX, что я хочу оставить такую "несвязанную" переменную равной 0?