Похоже, у вас есть почти все части, но, возможно, не совсем правильный синтаксис. Вот полное кодирование с c = 18
:
(set-option :produce-models true)
(set-logic ALL)
;; Declaring all the variables
(declare-const a (_ BitVec 48))
(declare-const b (_ BitVec 48))
(declare-const c (_ BitVec 48))
(assert (= c #x000000000012)) ; 18 is 0x12 in hex
(assert (= c (bvmul a b)))
; don't allow overflow
(assert (bvumul_noovfl a b))
(assert (bvult #x000000000001 a))
(assert (bvult #x000000000001 b))
;; Soft constraints to limit reuse
(assert-soft (not (= a b)))
(check-sat)
(get-model)
Обратите внимание на использование ALL
logi c и функции bvumul_noovfl
, которая обнаруживает переполнение умножения на битовый вектор без знака. (Эта функция имеет спецификацию z3 c и доступна только в том случае, если для логики c выбрано значение ALL
.) Поскольку вы выполняете арифметику битовых векторов c, она может быть изменена, и я думаю, это то, что вы хотели бы избежать. Явно заявляя, что мы не хотим, чтобы умножение a
и b
переполнялось, мы достигаем этой цели.
Для этого ввода z3 говорит:
sat
(model
(define-fun b () (_ BitVec 48)
#x000000000009)
(define-fun a () (_ BitVec 48)
#x000000000002)
(define-fun c () (_ BitVec 48)
#x000000000012)
)
, что правильно подставляет число 18
(записанное здесь в шестнадцатеричном виде как 12
) в 2
и 9
.
Обратите внимание, что умножение является сложной проблемой. По мере того, как вы увеличиваете размер в битах (здесь вы выбрали 48, но может быть больше), или если число c
само становится больше, проблема будет становиться все труднее и сложнее для решения z3. Это, конечно, неудивительно: факторизация - это сложная проблема в общем, и здесь нет волхвов c, чтобы z3 правильно вычислил входное значение без решения огромного набора внутренних уравнений, которые экспоненциально увеличиваются в размерах как бит -пропуск увеличивается.
Но не бойтесь: битовая векторная логика c завершена: это означает, что z3 всегда будет способен вычислять, хотя и медленно, если вы сначала не исчерпаете память или терпение!