在 Z3Py 中编码可接受的集合
Encode admissible sets in Z3Py
基于论证框架理论,我正在尝试使用 Z3Py 证明器对可接受集进行编码。但是,我 运行 遇到了一些问题,如果能提供有关如何改进它的任何指示,我将不胜感激。
根据 Wikipedia 的定义,一组参数 E 是可接受的,当且仅当它没有冲突并且它的所有参数都可以接受至 E.
基于以下带参数的有向图:a、b、c、d、e 和关系:(a, d)、(a, b)、(b, c)、(c, b)、 (c, d), (e, a) 可容集的正确解是:[], [e], [c], [c, e], [b, e], [b, d, e]
我开始玩 Z3Py 但在编码时遇到问题。
到目前为止我有这个:
from z3 import *
a, b, c, d, e = Bools('a b c d e')
arguments = [a, b, c, d, e]
solver = Solver()
relations = [(a, d), (a, b), (b, c), (c, b), (c, d), (e, a)]
# ensure there are no conflicting arguments
for relation in relations:
solver.append(Implies(relation[0], Not(relation[1])))
for argument in arguments:
# if not attacked then removed any arguments attacked by this argument
if len([item for item in relations if item[1] == argument]) == 0:
solver.append([Not(attacked[1]) for attacked in relations if attacked[0] == argument])
# if self attacking remove the argument
if len([item for item in relations if item[1] == argument and item[0] == argument]) > 0:
solver.append(Not(argument))
# get all attackers
attackers = [item[0] for item in relations if item[1] == argument]
for attacker in attackers:
# get defenders of the initial argument (arguments attacking the attacker)
defenders = [item[0] for item in relations if item[1] == attacker]
defending_z3 = []
if len(defenders) > 0:
for defender in defenders:
if defender not in attackers:
defending_z3.append(defender)
if len(defending_z3) > 0:
solver.append(Implies(Or([defend for defend in defending_z3]), argument))
else:
solver.append(Not(argument))
# get solutions
solutions = []
while solver.check() == sat:
model = solver.model()
block = []
solution = []
for var in arguments:
v = model.eval(var, model_completion=True)
block.append(var != v)
if is_true(v):
solution.append(var)
solver.add(Or(block))
solutions.append(solution)
for solution in solutions:
print(solution)
执行时,它给出了以下解决方案:[]、[c]、[d]、[b, d]、[b, d, e],其中只有 3 个是正确的:
- [b, d] 是不正确的,因为 d 不能保护自己(e 是 d 的防御者)
- [d] 又是错误的,因为 d 无法保护自己
- 缺少[e]
- 缺少[c, e]
- [b, e] 缺失
如有任何帮助,我们将不胜感激。
对于 SMT 解决来说,这是一个非常好的问题,z3 将能够相对轻松地处理此类问题,即使您的数据集非常大。
您的编码思路是正确的,但您混淆了相等性:在测试一个变量是否与另一个变量相同时,您应该小心。为此,请使用 Python 的 eq
方法。 (如果您使用 ==
,那么您将得到一个符号相等性测试,这不是您在这里要找的。)
鉴于此,我倾向于将您的问题编码如下:
from z3 import *
a, b, c, d, e = Bools('a b c d e')
arguments = [a, b, c, d, e]
solver = Solver()
relations = [(a, d), (a, b), (b, c), (c, b), (c, d), (e, a)]
# No conflicting arguments
for relation in relations:
solver.add(Not(And(relation[0], relation[1])))
# For each element, if it is attacked, then another element that
# attacks the attacker must be present:
for argument in arguments:
# Find the attackers for this argument:
attackers = [relation[0] for relation in relations if argument.eq(relation[1])]
# We must defend against each attacker:
for attacker in attackers:
defenders = [relation[0] for relation in relations if relation[1].eq(attacker)]
# One of the defenders must be included:
solver.add(Implies(argument, Or(defenders)))
# Collect the solutions:
while solver.check() == sat:
model = solver.model()
block = []
solution = []
for var in arguments:
v = model.eval(var, model_completion=True)
block.append(var != v)
if is_true(v):
solution.append(str(var))
solver.add(Or(block))
solution.sort()
print(solution)
希望代码应该易于理解。如果没有,请随时提出具体问题。
当我 运行 它时,我得到:
[]
['c']
['c', 'e']
['e']
['b', 'e']
['b', 'd', 'e']
这似乎与您预测的解决方案相符。
基于论证框架理论,我正在尝试使用 Z3Py 证明器对可接受集进行编码。但是,我 运行 遇到了一些问题,如果能提供有关如何改进它的任何指示,我将不胜感激。
根据 Wikipedia 的定义,一组参数 E 是可接受的,当且仅当它没有冲突并且它的所有参数都可以接受至 E.
基于以下带参数的有向图:a、b、c、d、e 和关系:(a, d)、(a, b)、(b, c)、(c, b)、 (c, d), (e, a) 可容集的正确解是:[], [e], [c], [c, e], [b, e], [b, d, e]
我开始玩 Z3Py 但在编码时遇到问题。
到目前为止我有这个:
from z3 import *
a, b, c, d, e = Bools('a b c d e')
arguments = [a, b, c, d, e]
solver = Solver()
relations = [(a, d), (a, b), (b, c), (c, b), (c, d), (e, a)]
# ensure there are no conflicting arguments
for relation in relations:
solver.append(Implies(relation[0], Not(relation[1])))
for argument in arguments:
# if not attacked then removed any arguments attacked by this argument
if len([item for item in relations if item[1] == argument]) == 0:
solver.append([Not(attacked[1]) for attacked in relations if attacked[0] == argument])
# if self attacking remove the argument
if len([item for item in relations if item[1] == argument and item[0] == argument]) > 0:
solver.append(Not(argument))
# get all attackers
attackers = [item[0] for item in relations if item[1] == argument]
for attacker in attackers:
# get defenders of the initial argument (arguments attacking the attacker)
defenders = [item[0] for item in relations if item[1] == attacker]
defending_z3 = []
if len(defenders) > 0:
for defender in defenders:
if defender not in attackers:
defending_z3.append(defender)
if len(defending_z3) > 0:
solver.append(Implies(Or([defend for defend in defending_z3]), argument))
else:
solver.append(Not(argument))
# get solutions
solutions = []
while solver.check() == sat:
model = solver.model()
block = []
solution = []
for var in arguments:
v = model.eval(var, model_completion=True)
block.append(var != v)
if is_true(v):
solution.append(var)
solver.add(Or(block))
solutions.append(solution)
for solution in solutions:
print(solution)
执行时,它给出了以下解决方案:[]、[c]、[d]、[b, d]、[b, d, e],其中只有 3 个是正确的:
- [b, d] 是不正确的,因为 d 不能保护自己(e 是 d 的防御者)
- [d] 又是错误的,因为 d 无法保护自己
- 缺少[e]
- 缺少[c, e]
- [b, e] 缺失
如有任何帮助,我们将不胜感激。
对于 SMT 解决来说,这是一个非常好的问题,z3 将能够相对轻松地处理此类问题,即使您的数据集非常大。
您的编码思路是正确的,但您混淆了相等性:在测试一个变量是否与另一个变量相同时,您应该小心。为此,请使用 Python 的 eq
方法。 (如果您使用 ==
,那么您将得到一个符号相等性测试,这不是您在这里要找的。)
鉴于此,我倾向于将您的问题编码如下:
from z3 import *
a, b, c, d, e = Bools('a b c d e')
arguments = [a, b, c, d, e]
solver = Solver()
relations = [(a, d), (a, b), (b, c), (c, b), (c, d), (e, a)]
# No conflicting arguments
for relation in relations:
solver.add(Not(And(relation[0], relation[1])))
# For each element, if it is attacked, then another element that
# attacks the attacker must be present:
for argument in arguments:
# Find the attackers for this argument:
attackers = [relation[0] for relation in relations if argument.eq(relation[1])]
# We must defend against each attacker:
for attacker in attackers:
defenders = [relation[0] for relation in relations if relation[1].eq(attacker)]
# One of the defenders must be included:
solver.add(Implies(argument, Or(defenders)))
# Collect the solutions:
while solver.check() == sat:
model = solver.model()
block = []
solution = []
for var in arguments:
v = model.eval(var, model_completion=True)
block.append(var != v)
if is_true(v):
solution.append(str(var))
solver.add(Or(block))
solution.sort()
print(solution)
希望代码应该易于理解。如果没有,请随时提出具体问题。
当我 运行 它时,我得到:
[]
['c']
['c', 'e']
['e']
['b', 'e']
['b', 'd', 'e']
这似乎与您预测的解决方案相符。