如何改善合金模型的性能?

时间:2018-06-27 11:25:50

标签: performance alloy

我已经为“浇水难题”写了两种合金解决方案(假设有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

1 个答案:

答案 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

提供的反例的可视化

counter exemple visualization