我已经为“浇水难题”写了两种合金解决方案(假设有5夸脱的水罐,3夸脱的水罐,您能精确测量4夸脱的水吗?)
我的第一次尝试(specific.als)将两个水罐硬编码为命名关系:
sig State {
threeJug: one Int,
fiveJug: one Int
}
它可以在大约500毫秒内解决难题(找到反例)。
我的第二次尝试(generic.als)被编码为允许任意数量的水罐和不同的大小:
sig State {
jugAmounts: Jug -> one Int
}
它可以在大约2000毫秒内解决难题。
通用代码能否与特定代码一样快地运行? 需要更改什么?
open util/ordering[State]
sig State {
threeJug: one Int,
fiveJug: one Int
}
fact {
all s: State {
s.threeJug >= 0
s.threeJug <= 3
s.fiveJug >= 0
s.fiveJug <= 5
}
first.threeJug = 0
first.fiveJug = 0
}
pred Fill(s, s': State){
(s'.threeJug = 3 and s'.fiveJug = s.fiveJug)
or (s'.fiveJug = 5 and s'.threeJug = s.threeJug)
}
pred Empty(s, s': State){
(s.threeJug > 0 and s'.threeJug = 0 and s'.fiveJug = s.fiveJug)
or (s.fiveJug > 0 and s'.fiveJug = 0 and s'.threeJug = s.threeJug)
}
pred Pour3To5(s, s': State){
some x: Int {
s'.fiveJug = plus[s.fiveJug, x]
and s'.threeJug = minus[s.threeJug, x]
and (s'.fiveJug = 5 or s'.threeJug = 0)
}
}
pred Pour5To3(s, s': State){
some x: Int {
s'.threeJug = plus[s.threeJug, x]
and s'.fiveJug = minus[s.fiveJug, x]
and (s'.threeJug = 3 or s'.fiveJug = 0)
}
}
fact Next {
all s: State, s': s.next {
Fill[s, s']
or Pour3To5[s, s']
or Pour5To3[s, s']
or Empty[s, s']
}
}
assert notOne {
no s: State | s.fiveJug = 4
}
check notOne for 7
open util/ordering[State]
sig Jug {
max: Int
}
sig State {
jugAmounts: Jug -> one Int
}
fact jugCapacity {
all s: State {
all j: s.jugAmounts.univ {
j.(s.jugAmounts) >= 0
and j.(s.jugAmounts) <= j.max
}
}
-- jugs start empty
first.jugAmounts = Jug -> 0
}
pred fill(s, s': State){
one j: Jug {
j.(s'.jugAmounts) = j.max
all r: Jug - j | r.(s'.jugAmounts) = r.(s.jugAmounts)
}
}
pred empty(s, s': State){
one j: Jug {
j.(s'.jugAmounts) = 0
all r: Jug - j | r.(s'.jugAmounts) = r.(s.jugAmounts)
}
}
pred pour(s, s': State){
some x: Int {
some from, to: Jug {
from.(s'.jugAmounts) = 0 or to.(s'.jugAmounts) = to.max
from.(s'.jugAmounts) = minus[from.(s.jugAmounts), x]
to.(s'.jugAmounts) = plus[to.(s.jugAmounts), x]
all r: Jug - from - to | r.(s'.jugAmounts) = r.(s.jugAmounts)
}
}
}
fact next {
all s: State, s': s.next {
fill[s, s']
or empty[s, s']
or pour[s, s']
}
}
fact SpecifyPuzzle{
all s: State | #s.jugAmounts = 2
one j: Jug | j.max = 5
one j: Jug | j.max = 3
}
assert no4 {
no s: State | 4 in univ.(s.jugAmounts)
}
check no4 for 7
答案 0 :(得分:0)
根据经验,可以通过以下方法获得更好的性能:
no s: State | 4 in univ.(s.jugAmounts)
在逻辑上等效于4 not in univ.(State.jugAmounts)
。仅在模型中进行此微小更改,就已经使子句的处理速度提高了200毫秒。编辑
我有空的时候回到了你的问题。
这是我用来得出此结论的模型
module WaterJugs/AbstractSyntax/ASM
open util/ordering[State]
open util/integer
//===== HARDCODE 2 jugs of volume 3 and 5 resp. comment those lines for generic approach ====
one sig JugA extends Jug{}{
volume=3
water[first]=0
}
one sig JugB extends Jug{}{
volume=5
water[first]=0
}
//==================================================================
abstract sig Jug{
volume: Int,
water: State ->one Int
}{
all s:State| water[s]<=volume and water[s]>=0
volume >0
}
pred Fill(s1,s2:State){
one disj j1,j2:Jug{j1.water[s1]!=j1.volume and j1.water[s2]=j1.volume and j2.water[s2]=j2.water[s1] }
}
pred Empty(s1,s2:State){
one disj j1,j2:Jug{ j1.water[s1]!=0 and j1.water[s2]=0 and j2.water[s2]= j2.water[s1] }
}
pred Pour(s1,s2:State){
one disj j1,j2: Jug{
add[j1.water[s1],j2.water[s1]] >j1.volume implies {
( j1.water[s2]=j1.volume and j2.water[s2]=sub[j2.water[s1],sub[j1.volume,j1.water[s1]]])}
else{
( j1.water[s2]=add[j1.water[s1],j2.water[s1]] and j2.water[s2]=0)
}
}
}
fact Next {
all s: State-last{
Fill[s, s.next]
or Pour[s, s.next]
or Empty[s, s.next]
}
}
sig State{
}
assert no4 {
4 not in Jug.water[State]
}
check no4 for 7
此外,这是Lightning
提供的反例的可视化