【问题标题】:Path hunting with Z3 solver使用 Z3 求解器寻路
【发布时间】:2022-11-27 06:45:38
【问题描述】:

我在 Z3 中对以下问题进行建模。目的是找到代理人避开障碍物到达硬币的路径。

Initial_grid =[['T' 'T' 'T' 'T' 'T' 'T' 'T']
              ['T' ' ' ' ' ' ' ' ' ' ' 'T']
              ['T' ' ' 'A' 'O' ' ' 'O' 'T']
              ['T' 'O' ' ' ' ' ' ' ' ' 'T']
              ['T' ' ' ' ' 'O' 'O' 'C' 'T']
              ['T' ' ' ' ' ' ' ' ' ' ' 'T']
              ['T' 'T' 'T' 'T' 'T' 'T' 'T']]

x, y = Ints('x y')
x = agent_loc[0]
y = agent_loc[1]

xc, yc = Ints('xc yc')
xc = coin_loc[0]
yc = coin_loc[1]

s = Solver()
s.add(x,y = (Or(move_right(),move_left(),move_top(),move_bottom())))
solve(And (x = xc) (y = yc))
if s.check() == unsat:
      print('Problem not solvable')
else:
    m = s.model()

我为运动函数添加了约束,如果运动有效(没有障碍物且在边界内),该函数返回 x,y 坐标,否则返回 false。我如何建模运动约束,因为代码中的那个会给出错误:add() 得到了一个意外的关键字参数 'y'.

【问题讨论】:

  • 您需要发布 MRE。没有上下文的小代码段不可能在堆栈溢出时得到回答。见:stackoverflow.com/help/minimal-reproducible-example
  • 当您发布适当的 MRE 时,还请尝试解释您的代码的每个部分打算做什么。您发布的代码遗漏、奇怪或错误的地方太多了,因此无法按原样弄清楚。比如你定义的Initial_grid是无效的,以后你再也不用了;您将几个变量分配为 Z3 整数变量只是为了随后将它们重新分配给其他东西;你没有向我们展示你对agent_loccoin_locmove_rightmove_left等的定义; ...
  • ...您为不接受任何函数的关键字参数提供关键字参数,并使用 And 就好像它返回了一个函数;并且不清楚您在添加约束时实际试图表达的约束是什么。

标签: python z3 z3py


【解决方案1】:

使用像 z3 这样的 SMT 求解器确实可以进行这种搜索,尽管看起来您的方法并不合适。 (正如 cmets 中所指出的,就此而言,您的代码甚至不是有效的 Python 或 z3Py。)

考虑这个问题的最佳方法是双管齐下:

  • 我可以找到 1 步的路径吗?如果没有,请尝试 2​​ 步、3 步等,直到达到上限,或者您决定停止尝试。

  • 与其“搜索”,不如想象给你一条路径;您将如何检查它是否是一条好路? SMT 解决方案的神奇之处在于,如果您可以编写一个程序来验证“声称的”解决方案确实不错,它就会为您找到一个确实不错的解决方案。

以下是按照这些思路解决您的问题的方法。我放在这里是为了让你更深入地学习和理解。如果这是你的家庭作业或学校项目或其他东西,提交它不会让你走得太远!除了我上面所说的,我特意不放置任何 cmet,希望您能研究它并在处理它时提出具体问题。

from z3 import *

Grid = [ ['T', 'T', 'T', 'T', 'T', 'T', 'T']
       , ['T', ' ', ' ', ' ', ' ', ' ', 'T']
       , ['T', ' ', 'A', 'O', ' ', 'O', 'T']
       , ['T', 'O', ' ', ' ', ' ', ' ', 'T']
       , ['T', ' ', ' ', 'O', 'O', 'C', 'T']
       , ['T', ' ', ' ', ' ', ' ', ' ', 'T']
       , ['T', 'T', 'T', 'T', 'T', 'T', 'T']
       ]

Cell, (Wall, Empty, Agent, Obstacle, Coin) = EnumSort('Cell', ('Wall', 'Empty', 'Agent', 'Obstacle', 'Coin'))

def mkCell(c):
    if c == 'T':
        return Wall
    elif c == ' ':
        return Empty
    elif c == 'A':
        return Agent
    elif c == 'O':
        return Obstacle
    else:
        return Coin

def grid(x, y):
    result = Wall
    for i in range (len(Grid)):
        for j in range (len(Grid[0])):
            result = If(And(x == IntVal(i), y == IntVal(j)), mkCell(Grid[i][j]), result)
    return result

def validStart(x, y):
    return grid(x, y) == Agent

def validEnd(x, y):
    return grid(x, y) == Coin

def canMoveTo(x, y):
    n = grid(x, y)
    return Or(n == Empty, n == Coin, n == Agent)

def moveLeft(x, y):
    return [x, If(canMoveTo(x, y-1), y-1, y)]

def moveRight(x, y):
    return [x, If(canMoveTo(x, y+1), y+1, y)]

def moveUp(x, y):
    return [If(canMoveTo(x-1, y), x-1, x), y]

def moveDown(x, y):
    return [If(canMoveTo(x+1, y), x+1, x), y]

Dir, (Left, Right, Up, Down) = EnumSort('Dir', ('Left', 'Right', 'Up', 'Down'))

def move(d, x, y):
    xL, yL = moveLeft (x, y)
    xR, yR = moveRight(x, y)
    xU, yU = moveUp   (x, y)
    xD, yD = moveDown (x, y)
    xN     = If(d == Left, xL, If (d == Right, xR, If (d == Up, xU, xD)))
    yN     = If(d == Left, yL, If (d == Right, yR, If (d == Up, yU, yD)))
    return [xN, yN]

def solves(seq, x, y):
    def walk(moves, curX, curY):
        if moves:
            nX, nY = move(moves[0], curX, curY)
            return walk(moves[1:], nX, nY)
        else:
            return [curX, curY]

    xL, yL = walk(seq, x, y)
    return And(validStart(x, y), validEnd(xL, yL))

pathLength = 0

while(pathLength != 20):
    print("Trying to find a path of length:", pathLength)

    s    = Solver()
    seq  = [Const('m' + str(i), Dir)  for i in range(pathLength)]
    x, y = Ints('x, y')
    s.add(solves(seq, x, y))

    if s.check() == sat:
        print("Found solution with length:", pathLength)
        m = s.model()
        print("    Start x:", m[x])
        print("    Start y:", m[y])
        for move in seq:
             print("    Move", m[move])
        break;
    else:
        pathLength += 1

运行时,打印:

Trying to find a path of length: 0
Trying to find a path of length: 1
Trying to find a path of length: 2
Trying to find a path of length: 3
Trying to find a path of length: 4
Trying to find a path of length: 5
Found solution with length: 5
    Start x: 2
    Start y: 2
    Move Down
    Move Right
    Move Right
    Move Right
    Move Down

因此,它找到了 5 步的解决方案;你可以在你的网格中追逐它,看看它确实是正确的。 (编号从左上角的 0,0 开始;随着向右和向下移动而增加。)

希望这可以帮助您在学习时取得进步并创建自己的版本。随时提出澄清问题;但请记住,如果这是家庭作业,那么按原样提交无疑会让您陷入困境,除非您真正理解此处提供的解决方案。

【讨论】:

    猜你喜欢
    • 2012-12-04
    • 2016-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多