Как правило, @ alias прав, когда заявляет, что решатель OMT не дает никаких гарантий того, что решение будет доступно в конце поиска оптимизации, когда оно прерывается сигналом timeout
. .
Решатель OMT может искать оптимальное решение одним из двух способов:
, начиная с начальной модели формулы и пытаясь улучшить значение целевая функция; Это случай стандартного подхода OMT, который перечисляет ряд частично оптимизированных решений, пока не находит оптимальное.
, начиная с более чем оптимального, неудовлетворительного, назначения и постепенно смягчать такое назначение, пока оно не даст оптимального решения; AFAIK, это только случай механизма Maximum Resolution для решения проблем MaxSMT.
Когда решатель OMT использует метод оптимизации, относящийся к первой категории затем можно получить наиболее известное решение, когда оно истекло, при условии, что решатель OMT хранит его в безопасном месте во время поиска оптимизации. Это не относится ко второму движку MaxRes (см. это Q / A ).
Возможный обходной путь. (CAVEAT: у меня нет проверил это) z3
отслеживает границы целевой функции lower
и upper
в поисковой оптимизации. При минимизации граница upper
соответствует значению целевой функции в самом последнем частичном решении, найденном решателем OMT (двойное для максимизации). После того, как произошел сигнал тайм-аута при минимизации (соответственно максимизации) экземпляра obj
, полученного из minimize()
(соответственно maximize()
), необходимо иметь возможность получить последнее приближение v
оптимального значения obj
позвонив по номеру obj.upper()
(соответственно obj.lower()
). Предполагая, что такое значение v
отличается от +oo
(соответственно -oo
), можно постепенно узнать ограничение вида cost = v
и выполнить дополнительную проверку SMT на соответствие, чтобы реконструировать модель, соответствующую субпространству. Оптимальное решение для z3
.
OptiMathSAT
- это один из решателей OMT, хранящий в безопасном месте последнее решение, с которым он столкнулся при поиске оптимизации. Это облегчает достижение того, что вы хотите сделать.
Существует два типа timeout
сигналов в OptiMathSAT
:
hard timeout : как только срабатывает timeout
, поиск оптимизации немедленно останавливается; если решатель OMT нашел какое-либо решение, результат поиска оптимизации (доступный через msat_objective_result(env, obj)
) равен MSAT_OPT_SAT_PARTIAL
, и модель, соответствующую последнему неоптимальному решению, может быть извлечена и распечатана; если вместо этого решатель OMT не нашел решения, результат поиска по оптимизации равен MSAT_UNKNOWN
, а модель недоступна.
soft timeout : если timeout
срабатывает после того, как решатель OMT нашел какое-либо решение, затем поиск немедленно останавливается, как в случае hard timeout . В противном случае timeout
будет игнорироваться , пока решатель OMT не найдет one решение.
Тип сигнала timeout
можно установить с помощью опции opt.soft_timeout=[true|false]
.
Пример: Следующий пример - timeout.py unit-test, содержащийся в моем omt_python_examples github-репозитории, в котором есть несколько примеров использования Python API-интерфейса OptiMathSAT
.
"""
timeout unit-test.
"""
###
### SETUP PATHS
###
import os
import sys
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
INCLUDE_DIR = os.path.join(BASE_DIR, '..', 'include')
LIB_DIR = os.path.join(BASE_DIR, '..', 'lib')
sys.path.append(INCLUDE_DIR)
sys.path.append(LIB_DIR)
from wrapper import * # pylint: disable=unused-wildcard-import,wildcard-import
###
### DATA
###
OPTIONS = {
"model_generation" : "true", # !IMPORTANT!
"opt.soft_timeout" : "false",
"opt.verbose" : "true",
}
###
### TIMEOUT UNIT-TEST
###
with create_config(OPTIONS) as cfg:
with create_env(cfg) as env:
# Load Hard Problem from file
with open(os.path.join(BASE_DIR, 'smt2', 'bacp-19.smt2'), 'r') as f:
TERM = msat_from_smtlib2(env, f.read())
assert not MSAT_ERROR_TERM(TERM)
msat_assert_formula(env, TERM)
# Impose a timeout of 3.0 seconds
CALLBACK = Timer(3.0)
msat_set_termination_test(env, CALLBACK)
with create_minimize(env, "objective", lower="23", upper="100") as obj:
assert_objective(env, obj)
solve(env) # optimization search until timeout
get_objectives_pretty(env) # print latest range of optimization search
load_model(env, obj) # retrieve sub-optimal model
dump_model(env) # print sub-optimal model
Это подробный вывод поискового запроса:
# obj(.cost_0) := objective
# obj(.cost_0) - search start: [ 23, 100 ]
# obj(.cost_0) - linear step: 1
# obj(.cost_0) - new: 46
# obj(.cost_0) - update upper: [ 23, 46 ]
# obj(.cost_0) - linear step: 2
# obj(.cost_0) - new: 130/3
# obj(.cost_0) - update upper: [ 23, 130/3 ]
# obj(.cost_0) - linear step: 3
# obj(.cost_0) - new: 40
# obj(.cost_0) - update upper: [ 23, 40 ]
# obj(.cost_0) - linear step: 4
# obj(.cost_0) - new: 119/3
# obj(.cost_0) - update upper: [ 23, 119/3 ]
# obj(.cost_0) - linear step: 5
# obj(.cost_0) - new: 112/3
# obj(.cost_0) - update upper: [ 23, 112/3 ]
# obj(.cost_0) - linear step: 6
# obj(.cost_0) - new: 104/3
# obj(.cost_0) - update upper: [ 23, 104/3 ]
# obj(.cost_0) - linear step: 7
# obj(.cost_0) - new: 34
# obj(.cost_0) - update upper: [ 23, 34 ]
# obj(.cost_0) - linear step: 8
# obj(.cost_0) - new: 133/4
# obj(.cost_0) - update upper: [ 23, 133/4 ]
# obj(.cost_0) - linear step: 9
# obj(.cost_0) - new: 161/5
# obj(.cost_0) - update upper: [ 23, 161/5 ]
# obj(.cost_0) - linear step: 10
# obj(.cost_0) - new: 32
# obj(.cost_0) - update upper: [ 23, 32 ]
# obj(.cost_0) - linear step: 11
# obj(.cost_0) - new: 158/5
# obj(.cost_0) - update upper: [ 23, 158/5 ]
# obj(.cost_0) - linear step: 12
# obj(.cost_0) - new: 247/8
# obj(.cost_0) - update upper: [ 23, 247/8 ]
# obj(.cost_0) - linear step: 13
# obj(.cost_0) - new: 123/4
# obj(.cost_0) - update upper: [ 23, 123/4 ]
# obj(.cost_0) - linear step: 14
# obj(.cost_0) - new: 61/2
# obj(.cost_0) - update upper: [ 23, 61/2 ]
# obj(.cost_0) - linear step: 15
unknown ;; <== Timeout!
(objectives
(objective 61/2), partial search, range: [ 23, 61/2 ]
) ;; sub-optimal value, latest search interval
course_load__ARRAY__1 : 9 ;; and the corresponding sub-optimal model
course_load__ARRAY__2 : 1
course_load__ARRAY__3 : 2
course_load__ARRAY__4 : 10
course_load__ARRAY__5 : 3
course_load__ARRAY__6 : 4
course_load__ARRAY__7 : 1
course_load__ARRAY__8 : 10
course_load__ARRAY__9 : 4
course_load__ARRAY__10 : 1
course_load__ARRAY__11 : 1
course_load__ARRAY__12 : 5
course_load__ARRAY__13 : 10
course_load__ARRAY__14 : 9
course_load__ARRAY__15 : 1
...
;; the sub-optimal model is pretty long, it has been cut to fit this answer!
...