【问题标题】:How to get z3 to return multiple unsat cores, multiple satisfying assignments如何让 z3 返回多个 unsat 核心,多个令人满意的分配
【发布时间】:2015-11-16 10:05:13
【问题描述】:

我正在研究研究工具的一个组件; 我有兴趣检索(用于 QF_LRA)

-多个(最小或其他)UNSAT核心和
- 多项 SAT 作业

我查看了论坛上有关此主题的早期讨论,例如, How to get different unsat cores when using z3 on logic QF_LRA

他们参考了 z3 Python 教程 例如,http://rise4fun.com/Z3Py/tutorial/musmss

目前似乎处于离线状态。我已经尝试了 github 等的其他建议来找到提到的教程,但没有运气。

我正在使用 z3 Java API;但乐于改用其他替代品。

【问题讨论】:

    标签: z3 smt sat


    【解决方案1】:

    这里是教程。您可以找到更多关于 MARCO 的信息 来自 Mark Liffiton 的网页。

    枚举最小不可满足核心和最大满足子集

    本教程说明如何使用 Z3 提取所有最小不可满足核心 连同所有最大满足子集。

    产地

    我们接下来描述的算法 代表 Liffiton 和 Malik 的核心提取程序的本质,并且独立地 由 Previti 和 Marques-Silva 撰写:

    枚举不可行性:快速找到多个 MUS
    Mark H. Liffiton 和 Ammar Malik
    过程中。第十届人工集成国际会议 约束编程中的智能 (AI) 和运筹学 (OR) 技术 (CPAIOR-2013),160-175,2013 年 5 月。

    部分 MUS 枚举
    亚历山德罗·普雷维蒂,若昂·马克斯-席尔瓦 在过程中。 AAAI-2013 2013 年 7 月

    Z3py 功能

    此实现不包含任何调整。 它是由 Mark Liffiton 贡献的,它是对其中一个可用版本的简化 他的马可波罗网站。 eMUS 的代码也可用。 该示例说明了 Z3 基于 Python 的 API 的以下特性:

    1. 使用假设来跟踪无法满足的核心。
    2. 使用多个求解器并在它们之间传递约束。
    3. 从 Python 调用基于 C 的 API。 Python 并不支持所有 API 函数 包装纸。此示例显示如何获取 AST 的唯一整数标识符, 它可以用作哈希表中的键。

    算法思路

    算法的主要思想是保持两个 逻辑上下文并在它们之间交换信息:

    1. MapSolver 用于枚举尚未出现的子句集 现有不可满足核心的超集,而不是最大满足分配的子集。 MapSolver 每个 soft 子句使用一个唯一的原子谓词,因此它枚举 原子谓词集。对于每个最小不可满足核心,比如说,由谓词表示 p1、p2、p5MapSolver 包含 子句 - p1 ∨ - p2 ∨ - p5。 对于每个最大可满足子集,例如,由谓词表示 p2、p3、p5MapSolver 包含对应于所有文字析取的子句 不在最大可满足子集中,p1 ∨ p4 ∨ p6
    2. SubsetSolver 包含一个集合 软子句(带有唯一指示原子的子句被否定)。 MapSolver 为其提供一组子句(指示原子)。 回想一下,这些还不是现有最小值的超集 不可满足的核心,或最大满足分配的子集。 如果断言这些原子使 SubsetSolver 上下文不可行, 然后它找到对应于这些原子的最小不可满足子集。 如果断言原子与 SubsetSolver 一致,则 它将这组原子最大限度地扩展为一个令人满意的集合。
    from Z3 import *
    
    def main():
        x, y = Reals('x y')
        constraints = [x > 2, x < 1, x < 0, Or(x + y > 0, y < 0), Or(y >= 0, x >= 0), Or(y < 0, x < 0), Or(y > 0, x < 0)]
        csolver = SubsetSolver(constraints)
        msolver = MapSolver(n=csolver.n)
        for orig, lits in enumerate_sets(csolver, msolver):
            output = "%s %s" % (orig, lits)
            print(output)
    
    
    
    def get_id(x):
        return Z3_get_ast_id(x.ctx.ref(),x.as_ast())
    
    def MkOr(clause):
        if clause == []:
           return False
        else:
           return Or(clause)
    

    子集求解器:

    class SubsetSolver:
       constraints = []
       n = 0
       s = Solver()
       varcache = {}
       idcache = {}
    
       def __init__(self, constraints):
           self.constraints = constraints
           self.n = len(constraints)
           for i in range(self.n):
               self.s.add(Implies(self.c_var(i), constraints[i]))
    
       def c_var(self, i):
           if i not in self.varcache:
              v = Bool(str(self.constraints[abs(i)]))
              self.idcache[get_id(v)] = abs(i)
              if i >= 0:
                 self.varcache[i] = v
              else:
                 self.varcache[i] = Not(v)
           return self.varcache[i]
    
       def check_subset(self, seed):
           assumptions = self.to_c_lits(seed)
           return (self.s.check(assumptions) == sat)
    
       def to_c_lits(self, seed):
           return [self.c_var(i) for i in seed]
    
       def complement(self, aset):
           return set(range(self.n)).difference(aset)
    
       def seed_from_core(self):
           core = self.s.unsat_core()
           return [self.idcache[get_id(x)] for x in core]
    
       def shrink(self, seed):       
           current = set(seed)
           for i in seed:
              if i not in current:
                 continue
              current.remove(i)
              if not self.check_subset(current):
                 current = set(self.seed_from_core())
              else:
                 current.add(i)
           return current
    
       def grow(self, seed):
           current = seed
           for i in self.complement(current):
               current.append(i)
               if not self.check_subset(current):
                  current.pop()
           return current
    

    地图解算器:

    class MapSolver:
        def __init__(self, n):
            """Initialization.
               Args:
                n: The number of constraints to map.
            """
           self.solver = Solver()
           self.n = n
           self.all_n = set(range(n))  # used in complement fairly frequently
    
       def next_seed(self):
           """Get the seed from the current model, if there is one. 
                Returns:
                A seed as an array of 0-based constraint indexes.
           """
           if self.solver.check() == unsat:
                return None
           seed = self.all_n.copy()  # default to all True for "high bias"
           model = self.solver.model()
           for x in model:
               if is_false(model[x]):
                  seed.remove(int(x.name()))
           return list(seed)
    
       def complement(self, aset):
           """Return the complement of a given set w.r.t. the set of mapped constraints."""
           return self.all_n.difference(aset)
    
       def block_down(self, frompoint):
           """Block down from a given set."""
           comp = self.complement(frompoint)
           self.solver.add( MkOr( [Bool(str(i)) for i in comp] ) )
    
       def block_up(self, frompoint):
           """Block up from a given set."""
           self.solver.add( MkOr( [Not(Bool(str(i))) for i in frompoint] ) )
    
    
    
      def enumerate_sets(csolver, map):
          """Basic MUS/MCS enumeration, as a simple example."""
          while True:
            seed = map.next_seed()
            if seed is None:
               return
            if csolver.check_subset(seed):
               MSS = csolver.grow(seed)
               yield ("MSS", csolver.to_c_lits(MSS))
               map.block_down(MSS)
            else:
               MUS = csolver.shrink(seed)
               yield ("MUS", csolver.to_c_lits(MUS))
               map.block_up(MUS)
    
       main()
    

    【讨论】:

    • 非常感谢您的详细回复和指向 Mark Liffiton 网页的指针。
    • 抱歉,上面代码片段的第 3,4 行是否缺少某些内容?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-10
    相关资源
    最近更新 更多