这次的 Plaid 可以使用的就是 https://z3prover.github.io/papers/programmingz3.html#sec-optimization

这里需要反思一下了,并不是 Optimize 就一定慢。当约束的结果是一个可能的接近最大值的情况下,使用普通的约束求解可能因为少了这个信息(最大)而更加慢

如果可能,这类题目可以转化为 MaxSAT 求解(最小化违反软断言的数量),这就会好的多了

def tt(s, f): 
    return is_true(s.model().eval(f))
 
def get_mss(s, ps):
    if sat != s.check():
       return []
    mss = { q for q in ps if tt(s, q) }
    return get_mss(s, mss, ps)
 
def get_mss(s, mss, ps):
    ps = ps - mss
    backbones = set([])
    while len(ps) > 0:
       p = ps.pop()
       if sat == s.check(mss | backbones | { p }):
          mss = mss | { p } | { q for q in ps if tt(s, q) }
          ps  = ps - mss
       else:
          backbones = backbones | { Not(p) }
    return mss

计算最大满足子集的算法(好,可以出题了😋)

MaxSAT 问题求解:

a, b, c = Bools('a b c')
o = Optimize()
o.add(a == c)
o.add(Not(And(a, b)))
o.add_soft(Or(a, b), 2)
o.add_soft(b, 1)
o.add_soft(c, 1)
print(o.check())
print(o.model())

为了 debug 什么的,可以设置在最大值更新的时候输出当前最大的那个情况长啥样:

def on_model(m):
    print(m.eval(score), bytes(m[c].as_long() for c in flag))
solver = Optimize()
solver.set_on_model(on_model)

试着用 tactic 好像不怎么好使?没有 Optimize 这么好用的接口了