我需要找到从初始位置穿过冰冻湖到目的地的所有可能路径。结冰的湖泊由一个矩阵表示,其中每个单元格由 1(安全单元格)或 0(不安全单元格)组成。我想使用 Z3 定理证明器编写代码来找到从初始位置到目的地的有效路径,而不使用任何不安全的单元格。
这是一个 e# 用法示例
在此矩阵中,单元格 D1 是起始位置,C3 是目标位置。单元格 A1、A2、A3、B1、B3、C1、C3 和 D1 是安全单元格(以橙色标记),而单元格 A4、B2、B4、C2、C4、D2、D3 和 D4 是不安全单元格(以橙色标记)红色的)。从初始位置到目标位置只有一条有效路径,由 D1 -> C1 -> B1 -> A1 -> A2 -> A3 -> B3 -> C3 给出。
为了解决这个问题,我使用Python中的Z3定理证明器。这是代码:
from z3 import *
def find_path(matrix, start, end):
# Define the dimensions of the matrix
rows = len(matrix)
cols = len(matrix[0])
# Create Z3 variables for each cell in the matrix
cells = [[Bool(f'cell_{i}_{j}') for j in range(cols)] for i in range(rows)]
# Create a Z3 solver
s = Solver()
# Add constraints for the starting and destination positions
s.add(cells[start[0]][start[1]]) # Starting position
s.add(cells[end[0]][end[1]]) # Destination position
# Add constraints for safe and unsafe cells
for i in range(rows):
for j in range(cols):
if matrix[i][j] == 0:
s.add(Not(cells[i][j])) # Unsafe cell
else:
s.add(cells[i][j]) # Safe cell
# Add constraints for adjacent cells
for i in range(rows):
for j in range(cols):
adjacent_cells = []
if i > 0:
adjacent_cells.append(cells[i-1][j]) # Cell above
if i < rows - 1:
adjacent_cells.append(cells[i+1][j]) # Cell below
if j > 0:
adjacent_cells.append(cells[i][j-1]) # Cell to the left
if j < cols - 1:
adjacent_cells.append(cells[i][j+1]) # Cell to the right
s.add(Implies(cells[i][j], Or(adjacent_cells))) # Only connect to adjacent safe cells
print(s)
# Check if there is a valid path from the starting position to the destination
if s.check() == sat:
model = s.model()
path = []
for i in range(rows):
for j in range(cols):
if model[cells[i][j]]:
path.append((i, j))
s.reset()
return path
else:
return None
# Example usage
matrix = [[1, 1, 1, 0],
[1, 0, 1, 0],
[1, 0, 1, 0],
[1, 0, 0, 0]]
start = (3, 0)
end = (2, 2)
path = find_path(matrix, start, end)
if path:
print("Valid path found:")
for cell in path:
print(f"({chr(ord('A') + cell[0])}{cell[1] + 1})")
else:
print("No valid path found.")
在此代码中,我首先定义矩阵的维度并为每个单元格创建 Z3 变量。然后,我添加对起始位置和目的地位置以及安全和不安全单元格的约束。最后,我添加了对相邻单元格的约束,以确保路径仅连接到相邻的安全单元格。我使用 Z3 解算器检查从起始位置到目的地是否存在有效路径,如果是,则检索该路径。
但是,当我运行此代码时,我没有得到预期的输出。约束条件或我对问题建模的方式似乎存在问题。
到底出了什么问题,如何解决?
您不需要为矩阵本身创建符号值:它是一个常量数组。相反,创建与路径相对应的变量,并告诉 z3 这应该是对该矩阵的有效遍历。然后 z3 会找到路径变量的赋值,为您解决迷宫问题。比如:
from z3 import *
def find_path(matrix, start, end):
# Define the dimensions of the matrix
rows = len(matrix)
cols = len(matrix[0])
# symbolic look-up into the matrix:
def lookup(x, y):
val = 0
for r in range(rows):
for c in range(cols):
val = If(And(x == r, y == c), matrix[r][c], val)
return val
# Create a path, there are at most rows*cols elements
path = []
for r in range(rows):
for c in range(cols):
path.append([FreshInt(), FreshInt()])
s = Solver()
# assert that the very first element of the path is the start position:
s.add(path[0][0] == start[0])
s.add(path[0][1] == start[1])
# for each remaining path-element, make sure either we reached the end, or it's a valid move
prev = path[0]
done = False
for p in path[1:]:
valid1 = And(p[0] >= 0, p[0] < rows, p[1] >= 0, p[1] < cols) # Valid coords
valid2 = Or( And(p[0] == prev[0]-1, p[1] == prev[1]) # Go up
, And(p[0] == prev[0]+1, p[1] == prev[1]) # or Go down
, And(p[0] == prev[0], p[1] == prev[1]+1) # or Go right
, And(p[0] == prev[0], p[1] == prev[1]-1)) # or Go left
valid3 = lookup(p[0], p[1]) == 1 # The cell is safe
# Either we're done, or all valid conditions must hold
s.add(Or(done, And(valid1, valid2, valid3)))
prev = p
# We're done if p is the end position:
done = Or(done, And(p[0] == end[0], p[1] == end[1]))
# Make sure the path is unique:
for i in range(len(path)):
for j in range(len(path)):
if j <= i:
continue
s.add(Or(path[i][0] != path[j][0], path[i][1] != path[j][1]))
# Compute the path:
if s.check() == sat:
model = s.model()
walk = []
for p in path:
cur = [model[p[0]].as_long(), model[p[1]].as_long()]
walk.append(cur)
if (cur[0] == end[0] and cur[1] == end[1]):
break
return walk
else:
return None
# Example usage
matrix = [[1, 1, 1, 0],
[1, 0, 1, 0],
[1, 0, 1, 0],
[1, 0, 0, 0]]
start = (3, 0)
end = (2, 2)
path = find_path(matrix, start, end)
if path:
print("Valid path found:")
for cell in path:
print(f"({chr(ord('A') + cell[0])}{cell[1] + 1})")
else:
print("No valid path found.")
运行时,将打印:
Valid path found:
(D1)
(C1)
(B1)
(A1)
(A2)
(A3)
(B3)
(C3)
这就是您正在寻找的解决方案。