предпочтение управления z3 для возвращаемых значений модели - PullRequest
0 голосов
/ 25 ноября 2018

Вопрос: Можно ли управлять каким-либо предпочтением возвращаемых значений модели в z3?

Пример: Учитывая следующую формулу логики высказываний,2 возможных модели.

  • a: True, b: True, c: False (предпочтительно)
  • a: True, b: False, c: True (все еще действует, просто «второй выбор»)

Я хотел бы контролировать с помощью самой логической формулы / утверждений, что модель, в которой a и b равны True, должна иметь преимущество перед моделью, в которой a и c являются True.Но с учетом того, что b не может быть True, поскольку добавляются дополнительные ограничения, должна быть возвращена модель с a и c, равными True.

SMT2 Формула: Вот пример формулы SMT2, который можно проверить с помощью rise4fun .

(declare-const a Bool)
(declare-const b Bool)
(declare-const c Bool)

(assert (= a true))
(assert (or
    (and (= b true) (not (= c true)))
    (and (= c true) (not (= b true)))
))

(check-sat)
(get-model)

Наблюдение: Я заметил, что этона самом деле представляется возможным контролировать, действительно ли b или c являются True в возвращаемой модели, фактически переключая порядок предложений and в предложении or.Является ли это в некотором роде надежным или просто происходит случайно для этого тривиального примера?

Ответы [ 3 ]

0 голосов
/ 26 ноября 2018

Это альтернативный ответ, который использует команду assert-soft.


Альтернативное кодирование # 1

Я предоставляю кодировку для Сначала OptiMathSAT , а затем объясните, как изменить эти формулы для достижения того же результата в z3 . По сравнению с другим подходом эта кодировка более подходит, когда имеется много логических переменных, имеющих один и тот же уровень приоритета , поскольку она позволяет решателю OMT использовать либо выделенный механизм MaxSAT для каждого шага лексикографического поиска.или Cardinality Networks для улучшения стандартного поиска на основе OMT.

Я соединил два игрушечных примера, которые я показал в другом ответе, в одной пошаговой формуле следующим образом:

(set-option :produce-models true)
(set-option :opt.priority lex)

(declare-const a Bool)
(declare-const b Bool)
(declare-const c Bool)

(assert (= a true))
(assert (or
    (and (= b true) (not (= c true)))
    (and (= c true) (not (= b true)))
))

(assert-soft a :weight 1 :id highest_priority)
(assert-soft b :weight 1 :id medium_priority)
(assert-soft c :weight 1 :id lowest_priority)

(minimize highest_priority)
(minimize medium_priority)
(minimize lowest_priority)

; First Solution

(check-sat)
(get-objectives)
(get-model)

; Second Solution

(push 1)
(assert (not (and a b)))

(check-sat)
(get-objectives)
(get-model)
(pop 1)

(exit)

Этовывод:

~$ optimathsat test.smt2 
sat

(objectives
 (highest_priority 0)
 (medium_priority 0)
 (lowest_priority 1)
)
( (a true)
  (b true)
  (c false)
  (highest_priority 0)
  (medium_priority 0)
  (lowest_priority 1) )
sat

(objectives
 (highest_priority 0)
 (medium_priority 1)
 (lowest_priority 0)
)
( (a true)
  (b false)
  (c true)
  (highest_priority 0)
  (medium_priority 1)
  (lowest_priority 0) )

Чтобы использовать эту кодировку с z3 , достаточно закомментировать следующие три строки:

;(minimize highest_priority)
;(minimize medium_priority)
;(minimize lowest_priority)

Причинапотому что это z3 неявно определяет цель команды assert-soft и неявно минимизирует ее.Его вывод:

~$ z3 test.smt2 
sat
(objectives
 (highest_priority 0)
 (medium_priority 0)
 (lowest_priority 1)
)
(model 
  (define-fun b () Bool
    true)
  (define-fun c () Bool
    false)
  (define-fun a () Bool
    true)
)
sat
(objectives
 (highest_priority 0)
 (medium_priority 1)
 (lowest_priority 0)
)
(model 
  (define-fun b () Bool
    false)
  (define-fun c () Bool
    true)
  (define-fun a () Bool
    true)
)

Обратите внимание, что, поскольку z3 неявно объявляет цели минимизации для вас, команды assert-soft должны отображаться в том же порядке приоритета, который вы хотели быназначить их связанной целевой функции.


Как я уже упоминал в начале статьи, эта кодировка намного лучше, чем в другом ответе в случае, когда некоторые переменные имеют одинаковый уровень приоритета.Чтобы разместить две переменные a1 и a2 на одном уровне приоритета, вы можете использовать одинаковые id для их команды assert-soft.

Например:

(set-option :produce-models true)
(set-option :opt.priority lex)

(declare-const a1 Bool)
(declare-const a2 Bool)
(declare-const a3 Bool)
(declare-const b1 Bool)
(declare-const b2 Bool)
(declare-const c Bool)

(assert (= a1 true))
(assert (or
    (and (= b1 true) (not (= c true)))
    (and (= c true) (not (= b1 true)))
))

(assert (or (not a1) (not a2) (not a3) ))
(assert (or (not b1) (not b2) ))

(assert-soft a1 :weight 1 :id highest_priority)
(assert-soft a2 :weight 1 :id highest_priority)
(assert-soft a3 :weight 1 :id highest_priority)

(assert-soft b1 :weight 1 :id medium_priority)
(assert-soft b2 :weight 1 :id medium_priority)

(assert-soft c :weight 1 :id lowest_priority)

(minimize highest_priority)
(minimize medium_priority)
(minimize lowest_priority)

; First Solution

(check-sat)
(get-objectives)
(get-model)

; Second Solution

(push 1)
(assert (not (and a1 b1)))

(check-sat)
(get-objectives)
(get-model)
(pop 1)

(exit)

с выводом

~$ optimathsat test.smt2 
sat

(objectives
 (highest_priority 1)
 (medium_priority 1)
 (lowest_priority 0)
)
( (a1 true)
  (a2 true)
  (a3 false)
  (b1 false)
  (b2 true)
  (c true)
  (highest_priority 1)
  (medium_priority 1)
  (lowest_priority 0) )
sat

(objectives
 (highest_priority 1)
 (medium_priority 1)
 (lowest_priority 0)
)
( (a1 true)
  (a2 true)
  (a3 false)
  (b1 false)
  (b2 true)
  (c true)
  (highest_priority 1)
  (medium_priority 1)
  (lowest_priority 0) )

Альтернативное кодирование # 2

Интересный факт о assert-soft заключается в том, что его можно использовать для решения лексикографическая оптимизация проблем без какого-либо лексикографического механизма оптимизации: для достижения того же результата достаточно немного поиграть с весами.Это то, что традиционно делается в случае решения SAT / MaxSAT.Единственное предостережение - нужно аккуратно расставлять гири.Помимо этого, этот подход может быть даже более эффективным, чем приведенное выше кодирование, поскольку вся проблема оптимизации решается с помощью одного вызова внутреннего одноцелевого механизма.

(set-option :produce-models true)
(set-option :opt.priority lex)

(declare-const a Bool)
(declare-const b Bool)
(declare-const c Bool)

(assert (= a true))
(assert (or
    (and (= b true) (not (= c true)))
    (and (= c true) (not (= b true)))
))

(assert-soft a :weight 4 :id obj) ; highest priority
(assert-soft b :weight 2 :id obj)
(assert-soft c :weight 1 :id obj) ; lowest priority

(minimize obj)

; First Solution

(check-sat)
(get-objectives)
(get-model)

; Second Solution

(push 1)
(assert (not (and a b)))

(check-sat)
(get-objectives)
(get-model)
(pop 1)

(exit)

Это вывод:

~$ optimathsat test.smt2 
sat

(objectives
 (obj 1)
)
( (a true)
  (b true)
  (c false)
  (obj 1) )
sat

(objectives
 (obj 2)
)
( (a true)
  (b false)
  (c true)
  (obj 2) )

Я упоминал об этом в комментарии к другому ответу, но другое потенциально интересное решение могло бы заключаться в том, чтобы попытаться использовать бит-векторную кодировку формулы, а затем использовать OBVBS * 1069.* (см. «Оптимизация по битовому вектору» Наделя и др. ) механизм оптимизации BV по вектору, в котором самый значимый бит представляет переменную с наивысшим приоритетом, а наименее значимый бит представляет наименьшийпеременная приоритета.

Если вы хотите попробовать, некоторое время назад мы представили в OptiMathSAT повторную реализацию механизма OBVBS, описанного в статье.Z3 также поддерживает оптимизацию Bit-Vector.

0 голосов
/ 26 ноября 2018

Патрик дал хороший список вариантов для этого, и я думаю, что решение assert-soft является самым простым в использовании.Но так как вы спросили в комментариях и упомянули, что вы также хотите кодировать с использованием z3py, вот решение, которое создает битовый вектор для хранения переменных и максимизирует это как одну цель:

from z3 import *

noOfVars = 3
goal = BitVec('goal', noOfVars)
a, b, c = variables = Bools('a b c')

s = Optimize()
for (v, val) in zip(variables, [Extract(i, i, goal) for i in list(reversed(range(noOfVars)))]):
    s.add(v == (val == BitVecVal(1, 1)))

s.add(a)
s.add(Or(And(b, Not(c)), And(c, Not(b))))

s.maximize(goal)

print s.sexpr()
print s.check()
print s.model()

Это печатает:

$ python b.py
(declare-fun goal () (_ BitVec 3))
(declare-fun a () Bool)
(declare-fun b () Bool)
(declare-fun c () Bool)
(assert (= a (= ((_ extract 2 2) goal) #b1)))
(assert (= b (= ((_ extract 1 1) goal) #b1)))
(assert (= c (= ((_ extract 0 0) goal) #b1)))
(assert a)
(assert (or (and b (not c)) (and c (not b))))
(maximize goal)
(check-sat)

sat
[b = True, c = False, goal = 6, a = True]

Надеюсь, это поможет!

0 голосов
/ 25 ноября 2018

С учетом порядка a, b, c, ... возможной идеей является кодирование вашей игрушки-примера в Оптимизация по модулю теории и использование лексикографической оптимизации engine:

(set-option :produce-models true)
(set-option :opt.priority lex)

(declare-const a Bool)
(declare-const b Bool)
(declare-const c Bool)

(assert (= a true))
(assert (or
    (and (= b true) (not (= c true)))
    (and (= c true) (not (= b true)))
))

(maximize (ite a 1 0)) ; highest priority
(maximize (ite b 1 0))
(maximize (ite c 1 0)) ; lowest priority

(check-sat)
(get-objectives)
(get-model)

Вы можете решить это с помощью z3 или OptiMathSAT , так как они принимают тот же синтаксис:

~$ optimathsat test.smt2 
sat

(objectives
 ((ite a 1 0) 1)
 ((ite b 1 0) 1)
 ((ite c 1 0) 0)
)
( (a true)
  (b true)
  (c false) )

~$ z3 test.smt2 
sat
(objectives
 ((ite a 1 0) 1)
 ((ite b 1 0) 1)
 ((ite c 1 0) 0)
)
(model 
  (define-fun b () Bool
    true)
  (define-fun c () Bool
    false)
  (define-fun a () Bool
    true)
)

Если вы добавите ограничения, запрещающие комбинацию a /\ b, следующим образом:

(set-option :produce-models true)
(set-option :opt.priority lex)

(declare-const a Bool)
(declare-const b Bool)
(declare-const c Bool)

(assert (= a true))
(assert (or
    (and (= b true) (not (= c true)))
    (and (= c true) (not (= b true)))
))
(assert (not (and a b)))

(maximize (ite a 1 0))
(maximize (ite b 1 0))
(maximize (ite c 1 0))

(check-sat)
(get-objectives)
(get-model)

Тогда решатель (и) найдет другое решение:

~$ optimathsat test.smt2 
sat

(objectives
 ((ite a 1 0) 1)
 ((ite b 1 0) 0)
 ((ite c 1 0) 1)
)
( (a true)
  (b false)
  (c true) )

~$ z3 test.smt2 
sat
(objectives
 ((ite a 1 0) 1)
 ((ite b 1 0) 0)
 ((ite c 1 0) 1)
)
(model 
  (define-fun b () Bool
    false)
  (define-fun c () Bool
    true)
  (define-fun a () Bool
    true)
)

Примечание 1. Обратите внимание, что я закодировал цель самым простым способом, но это не обязательно лучший способ достижения желаемой цели.В зависимости от того, сколько переменных содержит проблема, и от структуры самой проблемы, следует рассмотреть другие возможные кодировки (например, использовать другую формулировку для целевой функции, использовать функции только для API, такие как установка предпочтения ветвления над некоторымипеременные, кодирующие проблему с бит-векторами) .Кроме того, если вам не нужна особая SMT-функция, вам может потребоваться найти решатель SAT / MaxSAT с возможностями лексикографической оптимизации.

Примечание 2. В случае, если ваше представление о предпочтении болеемодели являются более общими, чем «лексикографическое предпочтение» , которое я вывел из вашего примера с игрушкой, тогда вы все еще можете использовать теории оптимизации по модулю с определением функции альтернативной стоимости которая лучше соответствует вашим потребностям.

Примечание 3. (из комментариев) Если две переменные a1 и a2 должны иметь одинаковый уровень приоритета, то они должны бытьв той же директиве minimize/maximize, например, (maximize (+ (ite a1 1 0) (ite a2 1 0))).

...