当检查满足性时,如何防止Z3求解器绑定(=解释)某些变量(=常量)?

时间:2017-03-17 12:53:39

标签: c# z3

当检查满足性时,有没有办法阻止Z3求解器绑定(=解释)某些变量(=常量)?

例如,在下面的C#程序中,可能有两种不同的解释:

  1. switch1 = true且CONST1 = 16,或
  2. switch2 = true且RAX!0 = 16
  3. `

    Dictionary<string, string> settings = new Dictionary<string, string> {
        { "unsat-core", "true" },    // enable generation of unsat cores
        { "model", "true" },         // enable model generation
        { "proof", "false" }         // enable proof generation
    };
    Context ctx = new Context(settings);
    Solver solver = ctx.MkSolver();
    
    BitVecExpr rax0 = ctx.MkBVConst("RAX!0", 64); // register values
    BitVecExpr rax1 = ctx.MkBVConst("RAX!1", 64);
    BoolExpr switch1 = ctx.MkBoolConst("switch_1_on"); // switch on/off instruction 1
    BoolExpr switch2 = ctx.MkBoolConst("switch_2_on"); // switch on/off instruction 2
    BitVecExpr immConst = ctx.MkBVConst("CONST1", 64); // imm const
    
    //making rax0 inconsistent does not work
    //solver.Assert(ctx.MkEq(rax0, ctx.MkBVAND(ctx.MkBV(0, 64), ctx.MkBV(0xFFFFFFFFFFFFFFFF, 64))));
    
    // instruction 1: MOV RAX, immConst
    solver.Assert(ctx.MkIff(switch1, ctx.MkEq(rax1, immConst)));
    
    // instruction 2: NOP
    solver.Assert(ctx.MkIff(switch2, ctx.MkEq(rax1, rax0)));
    
    // atleast and atmost one instruction must be executed
    solver.Assert(ctx.MkAtMost(new BoolExpr[] { switch1, switch2 }, 1));
    solver.Assert(ctx.MkOr(new BoolExpr[] { switch1, switch2 }));
    
    // after executing the ASM we want rax to be 0
    solver.Assert(ctx.MkEq(rax1, ctx.MkBV(0, 64)));
    

    `

    问题:是否有一种自然的方法可以使第二种解释(switch2 = true)无效,以便在迭代所有解释时不会显示。

    我试图通过断言ctx.MkEq(rax0, ctx.MkBVAND(ctx.MkBV(0, 64), ctx.MkBV(0xFFFFFFFFFFFFFFFF, 64))来使rax0不一致,但这并没有帮助。

    我可以检查解释是否以某种方式使用rax0,但我不知道如何测试。我想这样的解释无效会更好。

1 个答案:

答案 0 :(得分:1)

模型/解释通常被定义为从符号到值的总映射;因此,如果可以告诉求解器在作业中不包含某些符号,那么这似乎有点令人惊讶。

虽然这是一个想法:我解释你的目标是找到“忽略”某些符号的模型,因为找到的模型仍然是模型,无论哪个(其他)值分配给感兴趣的符号。也就是说,适用于这些符号的所有值的模型。因此,您可以对这些符号进行普遍量化,然后要求求解器具有可满足性。

考虑这个例子:

(declare-const b1 Bool)
(declare-const b2 Bool)
(declare-const i1 Int)
(declare-const i2 Int)

(assert
  (or ; Admits several models
    (not b1)
    (< 0 i1)
    (and b2 (= i1 i2))))

(check-sat)
(get-model)

它承认了几种型号,例如: i1 = 0, i2 = 0, !b1, !b2。如果您要强制执行“忽略”i1的模型,即无论i1的值是哪个模型,那么只需量化i1

(assert
    (forall ((i1 Int)) 
      (or
        (not b1)
        (< 0 i1)
        (and b2 (= i1 i2)))))

满足这些约束的唯一方法是满足第一个析取,i1的值与此无关。实际上,将(assert b1)添加到上述程序会使其不可满足:没有可以忽略i1的模型。

另一方面,

i2进行量化会使解算器有更多可能的模型选择:i1无关紧要(因为!b1)和i1 { {1}}是积极的。