在z3的河流交叉难题

时间:2014-10-25 12:07:16

标签: z3 z3py

我刚开始学习z3求解器。我见过一些由z3解决的难题,即数独和八皇后。我只是想知道是否有人解决了z3中的过河问题。 z3在解决问题方面看起来非常好。

此致

2 个答案:

答案 0 :(得分:4)

我试图对它进行建模,我想出了以下内容。你可以在中运行它 交互式rise4fun环境,看到答案:

(declare-datatypes () ((Object Human Fox Rabbit Cabbage)))
(declare-datatypes () ((Location Left Right OnBoat)))
(declare-const n Int)
(declare-fun objectLocation (Int Object) Location)

(assert (= n 14))

(assert (forall ((x Object) (t Int)) (=> (= t 0) (= (objectLocation t x) Left))))
(assert (forall ((x Object) (t Int)) (=> (= t n) (= (objectLocation t x) Right))))
(assert
  (forall
    ((t Int))
    (=>
      (and (>= t 0) (<= t n))
      (<=
        (+
          (ite (= (objectLocation t Human) OnBoat) 1 0)
          (ite (= (objectLocation t Fox) OnBoat) 1 0)
          (ite (= (objectLocation t Rabbit) OnBoat) 1 0)
          (ite (= (objectLocation t Cabbage) OnBoat) 1 0)
        )
        2
      )
    )
  )
)
(assert
  (forall
    ((x Object) (t Int))
    (=>
      (and (>= t 1) (<= t (- n 1)))
      (iff
        (= (objectLocation t x) OnBoat)
        (and
          (not (= (objectLocation (+ t 1) x) OnBoat))
          (not (= (objectLocation (- t 1) x) OnBoat))
          (not (= (objectLocation (+ t 1) x) (objectLocation (- t 1) x)))
        )
      )
    )
  )
)
(assert
  (forall
    ((x Object) (t Int))
    (=>
      (and (>= t 1) (<= t n))
      (=>
        (not (= (objectLocation t x) (objectLocation (- t 1) x)))
        (or
          (= (objectLocation t x) OnBoat)
          (= (objectLocation (- t 1) x) OnBoat)
        )
      )
    )
  )
)
(assert
  (forall
    ((x Object) (y Object) (t Int))
    (=>
      (and (>= t 1) (<= t n))
      (=>
        (and (= (objectLocation t x) OnBoat) (= (objectLocation t y) OnBoat))
        (= (objectLocation (- t 1) x) (objectLocation (- t 1) y))
      )
    )
  )
)
(assert
  (forall
    ((x Object) (t Int))
    (=>
      (and (>= t 0) (<= t n))
      (=>
        (= (objectLocation t x) OnBoat)
        (= (objectLocation t Human) OnBoat)
      )
    )
  )
)
(assert
  (forall
    ((t Int))
    (=>
      (and (>= t 0) (<= t n))
      (=>
        (= (objectLocation t Fox) (objectLocation t Rabbit))
        (= (objectLocation t Human) (objectLocation t Rabbit))
      )
    )
  )
)
(assert
  (forall
    ((t Int))
    (=>
      (and (>= t 0) (<= t n))
      (=>
        (= (objectLocation t Cabbage) (objectLocation t Rabbit))
        (= (objectLocation t Human) (objectLocation t Rabbit))
      )
    )
  )
)

(check-sat)

(echo "step 0")
(eval (objectLocation 0 Human))
(eval (objectLocation 0 Fox))
(eval (objectLocation 0 Rabbit))
(eval (objectLocation 0 Cabbage))

(echo "step 1")
(eval (objectLocation 1 Human))
(eval (objectLocation 1 Fox))
(eval (objectLocation 1 Rabbit))
(eval (objectLocation 1 Cabbage))

(echo "step 2")
(eval (objectLocation 2 Human))
(eval (objectLocation 2 Fox))
(eval (objectLocation 2 Rabbit))
(eval (objectLocation 2 Cabbage))

(echo "step 3")
(eval (objectLocation 3 Human))
(eval (objectLocation 3 Fox))
(eval (objectLocation 3 Rabbit))
(eval (objectLocation 3 Cabbage))

(echo "step 4")
(eval (objectLocation 4 Human))
(eval (objectLocation 4 Fox))
(eval (objectLocation 4 Rabbit))
(eval (objectLocation 4 Cabbage))

(echo "step 5")
(eval (objectLocation 5 Human))
(eval (objectLocation 5 Fox))
(eval (objectLocation 5 Rabbit))
(eval (objectLocation 5 Cabbage))

(echo "step 6")
(eval (objectLocation 6 Human))
(eval (objectLocation 6 Fox))
(eval (objectLocation 6 Rabbit))
(eval (objectLocation 6 Cabbage))

(echo "step 7")
(eval (objectLocation 7 Human))
(eval (objectLocation 7 Fox))
(eval (objectLocation 7 Rabbit))
(eval (objectLocation 7 Cabbage))

(echo "step 8")
(eval (objectLocation 8 Human))
(eval (objectLocation 8 Fox))
(eval (objectLocation 8 Rabbit))
(eval (objectLocation 8 Cabbage))

(echo "step 9")
(eval (objectLocation 9 Human))
(eval (objectLocation 9 Fox))
(eval (objectLocation 9 Rabbit))
(eval (objectLocation 9 Cabbage))

(echo "step 10")
(eval (objectLocation 10 Human))
(eval (objectLocation 10 Fox))
(eval (objectLocation 10 Rabbit))
(eval (objectLocation 10 Cabbage))

(echo "step 11")
(eval (objectLocation 11 Human))
(eval (objectLocation 11 Fox))
(eval (objectLocation 11 Rabbit))
(eval (objectLocation 11 Cabbage))

(echo "step 12")
(eval (objectLocation 12 Human))
(eval (objectLocation 12 Fox))
(eval (objectLocation 12 Rabbit))
(eval (objectLocation 12 Cabbage))

(echo "step 13")
(eval (objectLocation 13 Human))
(eval (objectLocation 13 Fox))
(eval (objectLocation 13 Rabbit))
(eval (objectLocation 13 Cabbage))

(echo "step 14")
(eval (objectLocation 14 Human))
(eval (objectLocation 14 Fox))
(eval (objectLocation 14 Rabbit))
(eval (objectLocation 14 Cabbage))

您还可以运行“(get-model)”来查看函数的定义 “objectLocation”但我警告你,这将是非常难以理解的。

以下是对断言内容的简短描述:

  1. 最多可以有14个步骤。
  2. 在步骤0,所有对象都在左侧。
  3. 在步骤n,所有对象都应在右侧。
  4. 每一步,船上最多可以有两个物体。
  5. 如果且仅在不同的情况下,物体在步骤t在船上 在步骤t-1和t + 1河的两侧。
  6. 如果对象将位置从步骤t-1更改为步骤t,则更改位置 这些地方应该是船。
  7. 如果在步骤t中有两个物体在船上,它们应该是 在步骤t-1的河的同一侧。
  8. 如果船上有东西,那么人类也应该在船上 船。
  9. 如果狐狸和兔子在同一个地方,那么人类应该 也在那里。
  10. 如果兔子和卷心菜在同一个地方,那么人类就应该这样做 也在那里。

答案 1 :(得分:3)

感谢Shahab,这里是受Shahab代码启发的python版本。还添加了一些改进,例如,没有这样的步骤编号为14。 顺便说一句,我把这个人和船当作一个对象,而不是一个位置。

两个for循环只是输出结果的两个版本;随你选择。

'''
A man has a wolf, a goat and a cabbage.
On the way home he must cross a river.
His boat is small and won't fit more than one of his object.
He cannot leave the goat alone with the cabbage (because the goat would eat it),
nor he can leave the goat alone with the wolf (because the goat would be eaten).
How can the man get everything on the other side in this river crossing puzzle?
'''

from z3 import *
import timeit

s = Then('qe', 'smt').solver() # This strategy improves efficiency

Obj, (Man, Wolf, Goat, Cabbage) = EnumSort('Obj', ['Man', 'Wolf', 'Goat', 'Cabbage'])
Pos, (Left, Right) = EnumSort('Pos', ['Left', 'Right'])
f = Function('f', Obj, IntSort(), Pos) # f(obj, t) returns the position of the object obj at time t (from 0)

# variables for quantifier
i, j, k, x = Ints('i j k x')
a, b = Consts('a b', Obj)

# At time 0, all the objects are at left side
s.add(ForAll([a],
             f(a, 0) == Left))

# At time x (x >= 0), all objects are at right side
# And before that, the duplicated cases are not allowed
s.add(And(x >= 0,
          ForAll([a], f(a, x) == Right),
          ForAll([j, k],
                 Implies(And(j >= 0, j <= x, k >= 0, k <= x, j != k),
                         Exists([b],
                                f(b, j) != f(b, k))))))

# Man will come over and again between two sides until all objects are at right
s.add(ForAll([i],
             Implies(And(i >= 0, i < x),
                     f(Man, i) != f(Man, i + 1))))

# Man is at the same side with the goat, or goat is at a different side with wolf and cabbage
s.add(ForAll([i],
             Implies(And(i >= 0, i <= x),
                     Or(f(Man, i) == f(Goat, i),
                        And(f(Wolf, i) != f(Goat, i),
                            f(Cabbage, i) != f(Goat, i))))))

# All objects except man remain at the same side,
# or only one object moves the same with man while others remain the same side
s.add(ForAll([i],
             Implies(And(i >= 0, i < x),
                     Or(ForAll([a],  # all objects except man remain the same
                               Implies(a != Man,
                                       f(a, i) == f(a, i + 1))),
                        Exists([b],  # or there must one moves the same with man
                               And(b != Man,
                                   f(b, i) == f(Man, i),
                                   f(b, i + 1) == f(Man, i + 1),
                                   ForAll([a],  # and except that one must remain the same
                                          Implies(And(a != b, a != Man),
                                                  f(a, i) == f(a, i + 1)))))))))

print "Time eclipsed:", timeit.timeit(s.check, number=1)
print

if s.check() != sat:
    print "No result!"
    exit()

m = s.model()
total = m[x].as_long() + 1

for t in range(total):
    print "Step:", t
    print "Man", m.eval(f(Man, t)), "\t",
    print "Wolf", m.eval(f(Wolf, t)), "\t",
    print "Goat", m.eval(f(Goat, t)), "\t",
    print "Cabbage", m.eval(f(Cabbage, t))

print

for t in range(total):
    print "Step:", t
    if m.eval(f(Man, t)).eq(Left):
        print "Man",
    if m.eval(f(Wolf, t)).eq(Left):
        print "Wolf",
    if m.eval(f(Goat, t)).eq(Left):
        print "Goat",
    if m.eval(f(Cabbage, t)).eq(Left):
        print "Cabbage",
    print "~~~>",
    if m.eval(f(Man, t)).eq(Right):
        print "Man",
    if m.eval(f(Wolf, t)).eq(Right):
        print "Wolf",
    if m.eval(f(Goat, t)).eq(Right):
        print "Goat",
    if m.eval(f(Cabbage, t)).eq(Right):
        print "Cabbage",
    print

print "finished"

这是输出:

Time eclipsed: 0.169998884201

Step: 0
Man Left    Wolf Left   Goat Left   Cabbage Left
Step: 1
Man Right   Wolf Left   Goat Right  Cabbage Left
Step: 2
Man Left    Wolf Left   Goat Right  Cabbage Left
Step: 3
Man Right   Wolf Left   Goat Right  Cabbage Right
Step: 4
Man Left    Wolf Left   Goat Left   Cabbage Right
Step: 5
Man Right   Wolf Right  Goat Left   Cabbage Right
Step: 6
Man Left    Wolf Right  Goat Left   Cabbage Right
Step: 7
Man Right   Wolf Right  Goat Right  Cabbage Right

Step: 0
Man Wolf Goat Cabbage ~~~>
Step: 1
Wolf Cabbage ~~~> Man Goat
Step: 2
Man Wolf Cabbage ~~~> Goat
Step: 3
Wolf ~~~> Man Goat Cabbage
Step: 4
Man Wolf Goat ~~~> Cabbage
Step: 5
Goat ~~~> Man Wolf Cabbage
Step: 6
Man Goat ~~~> Wolf Cabbage
Step: 7
~~~> Man Wolf Goat Cabbage
finished