不重复布尔表达式用Z3解SAT问题

不重复布尔表达式用Z3解SAT问题,z3,smt,sat,Z3,Smt,Sat,让我们看看下面的问题:f(a,b,c,x,y,z)是一个布尔函数,其中a,b,c,x,y和z是布尔值,f的输出是布尔值。f的定义由许多and/or/nor运算符组成。我想找到一组三个布尔值x0、y0和z0,这样: f(0, 0, 0, x0, y0, z0) = 0 AND f(0, 0, 1, x0, y0, z0) = 1 AND f(0, 1, 0, x0, y0, z0) = 1 AND f(0, 1, 1, x0, y0, z0) = 0 AND ... f(1, 1, 1, x0,

让我们看看下面的问题:
f(a,b,c,x,y,z)
是一个布尔函数,其中a,b,c,x,y和z是布尔值,f的输出是布尔值。f的定义由许多and/or/nor运算符组成。我想找到一组三个布尔值x0、y0和z0,这样:

f(0, 0, 0, x0, y0, z0) = 0 AND
f(0, 0, 1, x0, y0, z0) = 1 AND
f(0, 1, 0, x0, y0, z0) = 1 AND
f(0, 1, 1, x0, y0, z0) = 0 AND
...
f(1, 1, 1, x0, y0, z0) = 1 # A total of 8 constrains. Each of them is from an entry in the truth table.
一种简单的方法是定义3个布尔变量x、y、z,并重复定义函数
f
8次。但是f由复杂的布尔表达式组成。定义8次可能会破坏模型。此外,事实上,我有7个变量:a,b,c,d,e,f,g。真值表有128个条目

有没有办法定义不属于解决方案的“占位符”变量a、b、c?然后我可以在a,b,c,x,y,z上定义f一次,然后以某种方式将a,b,c“赋值”给布尔常数


我是SMT解决方案的新手,占位符的想法可能完全不相关。其他解决方案也很受欢迎。

我不清楚您需要模型做什么以及需要多大的灵活性,但这里有一个想法:如果可以通过一个else案例将函数约束在所有参数值上,那么以下可能会起作用:

(declare-fun f (Bool Bool Bool Bool) Bool)

(assert (forall ((x Bool) (y Bool) (z Bool) (p Bool)) (!
  (=
    (f x y z p)
    (ite
      (and (not x) y) true (ite         ; 1. case
      (and (not x) (not y) z) true (ite ; 2. case
      (and x (not y) z) true            ; 3. case
      false))))                         ; else-case
  :pattern ((f x y z p)))))
至少在这个简单的例子中,Z3的模型有效地忽略了函数
f
的不相关的第四个参数:

(check-sat) ;; SAT --> good
(get-model)  
; NOTE: 4th parameter x!3 is declared, but not used
; (model 
;   (define-fun p () Bool
;     false)
;   (define-fun f ((x!0 Bool) (x!1 Bool) (x!2 Bool) (x!3 Bool)) Bool
;     (or (not (or x!0 (not x!1)))
;         (not (or x!1 (not x!2) (not x!0)))
;         (not (or x!1 x!0 (not x!2)))))
; )

很难准确地理解你想做什么。但在我看来,您关心的是如何轻松地编写代码,而不是其他任何事情。如果是这样,我建议使用一种比SMTLib提供更高级别API的语言进行编程。可以使用许多Z3支持的接口:C、C++、java等,以简化编程任务。 例如,下面是如何使用Python接口编写问题实例的代码:

从z3导入*
原始(a、b、c、x、y、z)的定义:
返回或([a,b^c,x,y,z])
x0,y0,z0=Bools(“x0-y0-z0”)
def f(a、b、c):
返回原始值(a==1,b==1,c==1,x0,y0,z0)
s=解算器()
s、 加(f(0,0,0)=False)
s、 加(f(0,0,1)=真)
s、 加(f(0,1,0)=真)
s、 加(f(0,1,1)=假)
s、 加(f(1,1,1)=真)
打印(s.check())
打印(s.model())
运行时,此选项将打印:

sat
[y0 = False, z0 = False, x0 = False]
当您试图查找时,给您分配到
x0
y0
z0

这里的想法是使用z3的接口将
f
编码为常规函数。我在python代码中调用了这个函数
fororiginal
。然后我们为原始定义了一个版本的
,我在代码中称之为
f
,它传递最后三个参数的符号值,但前三个参数需要常数

然后,我们只需为每个案例添加约束。按照你的例子,我只添加了上面的5个;当然,你可以加上全部8个


我希望这能让你开始

关键的一点是,必须使用量词(有各种编码都略有不同)。这样做的问题是,解算器的行为不太可预测,并且通常比无量词编码中的少量
f
副本花费更多的时间。在某些情况下,如果没有“明显”的简化,解算器还将生成所有可能的值组合,您可以手动列出这些值(例如,通过MBQI)。谢谢。我关心的是模型的复杂性,而不是干净的编码。布尔表达式定义了5(或8)次。这正是我所担心的。我不认为模型的复杂性会成为这种规模的问题。如果你使用量词,那么无论如何解决问题肯定会更复杂。我建议您尝试一下,如果您观察到复杂性,请仅处理复杂性。我正在尝试使用最少数量的NOR门构建一个7段显示解码器电路。给定一个4位到7位的布尔函数,它基本上搜索一个等效电路。代码位于。对于
num_gates=13
,它在2分钟后给出unsat。有了更多的门,它运行的时间太长了。