Как оптимизировать кусок кода в Z3? (Связано с PI_NON_NESTED_ARITH_WEIGHT) - PullRequest
1 голос
/ 15 декабря 2011

У меня есть код в z3, который призван решить задачу оптимизации для логической формулы

(set-option :PI_NON_NESTED_ARITH_WEIGHT 1000000000)

(declare-const a0 Int) (assert (= a0 2))
(declare-const b0 Int) (assert (= b0 2))
(declare-const c0 Int) (assert (= c0 (- 99999)))
(declare-const d0 Int) (assert (= d0 99999))
(declare-const e0 Int) (assert (= e0 49))
(declare-const f0 Int) (assert (= f0 49))

(declare-const a1 Int) (assert (= a1 3))
(declare-const b1 Int) (assert (= b1 3))
(declare-const c1 Int) (assert (= c1 (- 99999)))
(declare-const d1 Int) (assert (= d1 99999))
(declare-const e1 Int) (assert (= e1 48))
(declare-const f1 Int) (assert (= f1 49))

(declare-const c Int)
(declare-const d Int)
(declare-const e Int)
(declare-const f Int)

(define-fun max ((x Int) (y Int)) Int
  (ite (>= x y) x y))

(define-fun min ((x Int) (y Int)) Int
  (ite (< x y) x y))

(define-fun goal ((c Int) (d Int) (e Int) (f Int)) Int
  (* (- d c) (- f e)))

(define-fun sat ((c Int) (d Int) (e Int) (f Int)) Bool
   (and (and  (>= d c) (>= f e))
        (forall ((x Int)) (=> (and (<= a0 x) (<= x b0))
                              (> (max c (+ x e)) (min d (+ x f)))))))

(assert (and (sat c d e f)
             (forall ((cp Int) (dp Int) (ep Int) (fp Int)) (=> (sat cp dp ep fp)
                                                               (>= (goal c d e f) (goal cp dp ep fp))))))

(check-sat)

Я полагаю, что из-за квантификаторов и следствия этот код стоит дорого. Когда я тестировал его в режиме онлайн, он дал мне 2 предупреждения, и окончательный результат - unknown:

failed to find a pattern for quantifier (quantifier id: k!33)
using non nested arith. pattern (quantifier id: k!48), the weight was increased to 1000000000 (this value can be modified using PI_NON_NESTED_ARITH_WEIGHT=<val>). timeout`. 

Может ли кто-нибудь сказать мне, если эти два предупреждения не дают хорошего результата? Есть ли способ оптимизировать этот кусок кода, чтобы он работал?

Ответы [ 2 ]

3 голосов
/ 16 декабря 2011

SoftTimur: Поскольку ваша задача связана с нелинейной арифметикой (в целевой функции) над целыми числами, Z3, скорее всего, ответит «неизвестно» на вашу проблему, даже если вы можете решить другие проблемы, с которыми вы столкнулись.Нелинейная целочисленная арифметика неразрешима, и маловероятно, что текущий решатель в Z3 может эффективно решить вашу проблему при наличии квантификаторов.(Конечно, удивительные люди Z3 могут настроить свой решатель просто «правильно» для решения этой конкретной проблемы, но проблема неразрешимости остается в целом.) Даже если у вас не было нелинейных конструкций, квантификаторы - это мягкое место дляРешатели SMT, и вам вряд ли удастся далеко продвинуться с количественным подходом.

Итак, вы по сути остались с идеей Филиппа об использовании итерации.Я хочу подчеркнуть, однако, что эти два метода (итерация против количественного определения) не эквивалентны!Теоретически, количественный подход является более мощным.Например, если вы попросите Z3 дать вам наибольшее целочисленное значение (простая задача максимизации, где стоимость - это значение самого целого числа), он правильно скажет вам, что такого целого числа не существует.Однако, если вы будете следовать итеративному подходу, вы будете работать бесконечно.В общем, итеративный подход потерпит неудачу в тех случаях, когда для задачи оптимизации не существует глобального максимума / минимума.В идеале, подход, основанный на квантификаторе, может иметь дело с такими случаями, но тогда он подвержен и другим ограничениям, как вы уже сами наблюдали.Lib немного болит.Вот почему многие люди создают более простые в использовании интерфейсы.Если вы открыты для использования Haskell, например, вы можете попробовать привязки SBV, которые позволят вам написать скрипт Z3 из Haskell.Фактически, я закодировал вашу проблему в Haskell: http://gist.github.com/1485092. (Имейте в виду, что, возможно, я неправильно понял ваш код SMTLib или, возможно, допустил ошибку кодирования, поэтому, пожалуйста, проверьте еще раз.)

Библиотека SBV Haskell допускает количественные и итеративные подходы к оптимизации.Когда я пробую z3 с квантификаторами, Z3 действительно возвращает «неизвестно», что означает, что проблема не решаема.(См. Функцию «test1» в программе.) Когда я попробовал итеративную версию (см. Функцию «test2»), она все время находила все более и более лучшие решения, я убил ее примерно через 10 минут, найдя следующее решение:

*** Round 3128 ****************************
*** Solution: [4,42399,-1,0]
*** Value   : 42395 :: SInteger

Вы случайно не знаете, имеет ли данный конкретный случай вашей проблемы оптимальное решение?Если это так, вы можете позволить программе работать дольше, и она в конечном итоге найдет ее, в противном случае она будет работать вечно.

Дайте мне знать, если вы решите исследовать путь Haskell и если у вас есть какие-либопроблемы с этим.

3 голосов
/ 15 декабря 2011

Я решил задачи оптимизации в Z3 следующим итеративным способом, по сути, циклом, который ищет решение, используя несколько вызовов Z3.

  1. Find one решение (в вашем случае решение для (sat c d e f)

  2. Вычислить значение этого решения (если ваше решение c0, d0, e0, f0, оцените (goal c0 d0 e0 f0). Назовите это значение v0.

  3. Найдите решение новой проблемы (and (sat c1 d1 e1 f1) (> (goal c1 d1 e1 f1) v0)).

  4. Если точка 3. возвращает UNSAT, v0 - ваш максимум. Если нет, используйте новое решение как v0 и вернитесь к пункту 3.

Иногда вы можете ускоритьсначала определите верхнюю границу (т. е. значения cu, du, eu, fu, такие что (and (sat c d e f) (<= (goal cu du eu fu)) является UNSAT), а затем перейдите к дихотомии.итеративный способ намного быстрее, чем использование квантификаторов для задач оптимизации.

...