我有一个网状网络,如图所示。 现在,我正在为这个sat网络中的所有边缘分配值。我想在我的程序中提出,我的分配中没有闭环。例如,左上角最大正方形的约束可以写为 -
E0 = 0 or E3 = 0 or E4 = 0 or E7 = 0
,因此任何一个链接都必须处于非活动状态才能形成循环。但是,在这种网络中,有许多可能的循环。
例如由边缘形成的循环 - E0, E3, E7, E11, E15, E12, E5, E1
。
现在我的问题是我必须描述在这个网络中可能出现的每个可能的循环组合。我尝试在一个可能的公式中编写约束,但是我无法成功。
如果有可能的方法来编码这种情况,任何人都可以抛出任何指针吗? 仅供参考,我使用的是Z3 Sat Solver。
答案 0 :(得分:1)
以下编码可用于包含N
个节点和M
边的任何图形。它使用(N+1)*M
变量和2*M*M
3-SAT子句。 This ipython notebook通过比较SAT求解器结果(当存在循环时为UNSAT,否则为SAT)和直接循环查找算法的结果来演示编码。
免责声明:此编码是我对此问题的临时解决方案。我非常确定它是正确的,但我不知道它如何将性能与其他编码方式进行比较。由于我的解决方案适用于任何图形,因此可以预期存在更好的解决方案,它使用OP感兴趣的图形类的一些属性。
<强>变量:强>
每个边都有一个变量。边缘是活跃的&#34;或&#34;使用&#34;如果设置了相应的变量。在我的参考实现中,边缘具有索引0..(M-1)
,并且此变量具有索引1..M
:
def edge_state_var(edge_idx):
assert 0 <= edge_idx < M
return 1 + edge_idx
然后我为每个边缘都有一个M
位宽的状态变量,或者总共N*M
个状态位(节点和位也使用从零开始的索引):
def node_state_var(node_idx, bit_idx):
assert 0 <= node_idx < N
assert 0 <= bit_idx < M
return 1 + M + node_idx*M + bit_idx
<强>条款:强>
当边缘处于活动状态时,它会链接它连接在一起的两个节点的状态变量。具有与节点相同索引的状态位在两侧必须不同,并且其他状态位必须等于其在另一节点上的对应伙伴。在python代码中:
# which edge connects which nodes
connectivity = [
( 0, 1), # edge E0
( 1, 2), # edge E1
( 2, 3), # edge E2
( 0, 4), # edge E3
...
]
cnf = list()
for i in range(M):
eb = edge_state_var(i)
p, q = connectivity[i]
for k in range(M):
pb = node_state_var(p, k)
qb = node_state_var(q, k)
if k == i:
# eb -> (pb != qb)
cnf.append([-eb, -pb, -qb])
cnf.append([-eb, +pb, +qb])
else:
# eb -> (pb == qb)
cnf.append([-eb, -pb, +qb])
cnf.append([-eb, +pb, -qb])
所以基本上每个边都试图将它所分割的图形分割为边缘一侧的一半,并且所有状态位对应于边缘设置为1,另一半位于另一边。边缘并且具有对应于边缘设置为0的状态位。对于循环中的所有节点都可以从循环中每个边的两侧到达的循环,这是不可能的。