英文:
TLA+ spec stalls as CHOOSE does not select a previous selected value
问题
现在我开始逐渐习惯TLA+,我首先对骑士任务问题建模,其中骑士最终必须到达棋盘上的每个可能的方格。为此,我使用了2个不同的变量:当前位置和占用位置的集合。
首先,我开始定义Init和Next动作谓词,以及我的规范和公平规范(在WF中我只使用了current,因为由于返回到某个位置,占用可能在某些情况下停滞; 但是,如果我将WF设置为两者,问题仍然存在)。
常量 N
变量 occupied, current
vars == <<occupied, current>>
Possible == 0..N-1
Inv == /\ Cardinality(occupied) ≤ N^2
/\ IsFiniteSet(occupied)
/\ occupied ⊆ (Possible \X Possible)
Jumps(pair) == LET x == pair[1]
y == pair[2]
IN
({<<x+2, y-1>>, <<x+2, y+1>>, <<x-2,y+1>>, <<x-2,y-1>>}
\cup
{<<x+1, y-2>>, <<x+1, y+2>>, <<x-1,y+2>>, <<x-1,y-2>>}
)
\cap
(Possible \X Possible)
Init == \E x \in Possible : \E y \in Possible : /\ occupied = {<<x,y>>}
/\ current = <<x,y>>
Next == LET S == Jumps(current)
Chosen == CHOOSE s \in S: TRUE
IN
/\ current' = Chosen
/\ occupied' = occupied \cup {Chosen}
Spec == Init /\ [][Next]_vars
FairSpec == Spec /\ WF_occupied(Next)
然后我设置了一个不变式NotSolved,所以TLC给我返回了不变式的收缩:在其中,占用达到了(= (N-1)^2)的基数,这意味着每个位置都曾经被占用过。
NotSolved == Cardinality(occupied) < (N-1)^2
然而,一旦它到达当前位置,其中CHOOSE必须选择曾经被选择过的位置(返回到相同的位置,然后选择另一个),规范就会停滞。这意味着occupied的基数永远不会与棋盘相同。
我猜测CHOOSE是真正的问题,但我不确定如何解决这个问题。
英文:
As I am starting to get used to TLA+, I started by modelling the Knight Quest problem, in which a knight must eventually reach every possible square of the chess board. For that, I've used 2 different variables: the current position and occupied set of positions.
First, I started to define my Init and Next action predicates, along with my specification and fair specification (in the WF I've only used current, as occupied may in some cases stall due to the returning to a certain position; however, if I set the WF to both, the issue is the same).
CONSTANT N
VARIABLE occupied, current
vars == << occupied, current >>
Possible == 0..N-1
Inv == /\ Cardinality(occupied) \leq N^2
/\ IsFiniteSet(occupied)
/\ occupied \subseteq (Possible \X Possible)
Jumps(pair) == LET x == pair[1]
y == pair[2]
IN
({<<x+2, y-1>>, <<x+2, y+1>>, <<x-2,y+1>>, <<x-2,y-1>>}
\cup
{<<x+1, y-2>>, <<x+1, y+2>>, <<x-1,y+2>>, <<x-1,y-2>>}
)
\cap
(Possible \X Possible)
Init == \E x \in Possible : \E y \in Possible : /\ occupied = {<<x,y>>}
/\ current = <<x,y>>
Next == LET S == Jumps(current)
Chosen == CHOOSE s \in S: TRUE
IN
/\ current' = Chosen
/\ occupied' = occupied \cup {Chosen}
Spec == Init /\ [][Next]_vars
FairSpec == Spec /\ WF_occupied(Next)
Then I've set a invariant NotSolved, so TLC returns me the contraction of the invariant: in which, the occupied reaches the cardinality of (= (N-1)^2), meaning that every position was once occupied.
NotSolved == Cardinality(occupied) < (N-1)^2
However, as soon as it reaches a current position, where the CHOOSE has to select a position that once was chosen (return to the same position, to then select another), the spec stalls. Which means, that the cardinality of occupied is never the same as the chess board.
I am guessing CHOOSE is the actual problem, but I am not sure how to fix this.
答案1
得分: 1
You are right, CHOOSE does something else than you expect. It is a function that returns an arbitrary value fulfilling the specified criteria. But because it's a function it always returns the same value for the same expression. After all you want
(CHOOSE s \in S : P(s)) = (CHOOSE s \in S : P(s))
to hold. Alternatives are usually expressed with logical disjunction (for example Action(0) \/ Action(1)) or the existential quantifier (for example \E s \in S: P(s) /\ Action(s)). In your case you need to change Next to:
Next == LET S == Jumps(current) IN \E Chosen \in S:
/\ current' = Chosen
/\ occupied' = occupied \cup {Chosen}
When you check for NotSolved as an invariant you will get a trace that really exceeds your size limits.
Nevertheless, the current description does allow for a path where the same element of S is chosen over and over again. You can prevent that by adding /\ ~(Chosen \in occupied) as a conjunct. But that also means at some point you will have exhausted S and your algorithm will stall, which you need to take into account.
英文:
You are right, CHOOSE does something else than you expect. It is a function that returns an arbitrary value fulfilling the specified criteria. But because it's a function it always returns the same value for the same expression. After all you want
(CHOOSE s \in S : P(s)) = (CHOOSE s \in S : P(s))
to hold. Alternatives are usually expressed with logical disjunction ( for example Action(0) \/ Action(1) ) or the existential quantifier (for example \E s \in S: P(s) /\ Action(s) ). In your case you need to change Next to:
Next == LET S == Jumps(current)
IN \E Chosen \in S:
/\ current' = Chosen
/\ occupied' = occupied \cup {Chosen}
When you check for NotSolved as an invariant you will get a trace that really exceeds your size limits.
Nevertheless, the current description does allow for a path where the same element of S is chosen over and over again. You can prevent that by adding /\ ~(Chosen \in occupied) as a conjunct. But that also means at some point you will have exhausted S and your algorithm will stall which you need to take into account.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论