NuSMV 模型检查:创建一个简单的游戏模型
NuSMV model checking: create a simple game model
我是 NuSMV 的新手,尝试为这个简单的回合制游戏建模。一堆有 10 块砖,每个玩家每回合可以拿取 1-3 块砖,谁拿走最后一块砖就赢了。假设玩家 A 先走,这是我的尝试。我想表达 "eventually there is a winner",但我的代码不起作用,因为它不会阻止玩家在 brick=0 之后拿砖,所以最终玩家 a、b 都会成为赢家。
这是我的代码:
MODULE main
VAR
bricks : 0..10;
i : 1..3;
j : 1..3;
turn : boolean;
winner : {none, a, b};
ASSIGN
init(winner) := none;
init(bricks) := 10;
init(turn) := TRUE;
next(turn) := case
turn : FALSE;
!turn: TRUE;
esac;
next(bricks) :=
case
bricks - j >= 0 : bricks - j;
bricks - j < 0 : 0;
TRUE:bricks;
esac;
next(winner) := case
turn=TRUE & bricks = 0: a;
turn=FALSE & bricks = 0: b;
TRUE:winner;
esac;
SPEC AF (winner = a | winner = b)
这是我在 SPEC AF 上的输出(获胜者 = a | 获胜者 = none)来说明我的观点。
i = 1
j = 1
turn = TRUE
winner = none
State: 1.2 <-
bricks = 9
j = 3
turn = FALSE
State: 1.3 <-
bricks = 6
turn = TRUE
State: 1.4 <-
bricks = 3
turn = FALSE
State: 1.5 <-
bricks = 0
j = 1
turn = TRUE
State: 1.6 <-
turn = FALSE
winner = a
State: 1.7 <-
turn = TRUE
winner = b
如您所见,模型仍然提供了一个反例,即玩家 a 已经获胜后玩家 b 赢得了游戏。
我不确定您如何提供 反例,因为您指定的 属性 是 验证的型号:
-- specification AF (winner = a | winner = b) is true
也许您模拟了该程序并简单地观察到它以意想不到的方式运行。您似乎真正要验证的 属性 是 AF (AG winner = a | AG winner = b)
。事实上,使用此 属性 会导致 反例 类似于您自己的:
-- specification AF (AG winner = a | AG winner = b) is false
-- as demonstrated by the following execution sequence
Trace Description: CTL Counterexample
Trace Type: Counterexample
-> State: 1.1 <-
bricks = 10
i = 1
j = 1
turn = TRUE
winner = none
-> State: 1.2 <-
bricks = 9
turn = FALSE
-> State: 1.3 <-
bricks = 8
turn = TRUE
-> State: 1.4 <-
bricks = 7
turn = FALSE
-> State: 1.5 <-
bricks = 6
turn = TRUE
-> State: 1.6 <-
bricks = 5
turn = FALSE
-> State: 1.7 <-
bricks = 4
turn = TRUE
-> State: 1.8 <-
bricks = 3
turn = FALSE
-> State: 1.9 <-
bricks = 2
turn = TRUE
-> State: 1.10 <-
bricks = 1
turn = FALSE
-> State: 1.11 <-
bricks = 0
turn = TRUE
-- Loop starts here
-> State: 1.12 <-
turn = FALSE
winner = a
-> State: 1.13 <-
turn = TRUE
winner = b
-> State: 1.14 <-
turn = FALSE
winner = a
问题是游戏结束了还要翻牌,结果就是A和B不断翻牌。
我重新编写了您的解决方案以更好的方式:
MODULE main
VAR
bricks : 0..10;
q : 0..3;
turn : {A_TURN , B_TURN};
DEFINE
game_won := next(bricks) = 0;
a_won := game_won & turn = A_TURN;
b_won := game_won & turn = B_TURN;
ASSIGN
init(bricks) := 10;
init(turn) := A_TURN;
next(bricks) := case
bricks - q >= 0 : bricks - q;
TRUE : 0;
esac;
next(turn) := case
turn = A_TURN & !game_won: B_TURN;
turn = B_TURN & !game_won: A_TURN;
TRUE : turn;
esac;
-- forbid q values from being both larger than the remaining number of
-- bricks, and equal to zero when there are still bricks to take.
INVAR (q <= bricks)
INVAR (bricks > 0) -> (q > 0)
INVAR (bricks <= 0) -> (q = 0)
-- Sooner or later the number of bricks will always be
-- zero for every possible state in every possible path,
-- that is, someone won the game
CTLSPEC
AF AG (bricks = 0)
我认为代码是不言自明的。
您可以 运行 它与 NuSMV 和 nuXmv 使用以下命令:
> read_model -i game.smv
> go
> check_property
-- specification AF (AG bricks = 0) is true
如果您想找到可能的解决方案,只需翻转 属性:
> check_ctlspec -p "AF AG (bricks != 0)"
-- specification AF (AG bricks != 0) is false
-- as demonstrated by the following execution sequence
Trace Description: CTL Counterexample
Trace Type: Counterexample
-> State: 1.1 <-
bricks = 10
q = 1
turn = A_TURN
game_won = FALSE
b_won = FALSE
a_won = FALSE
-> State: 1.2 <-
bricks = 9
turn = B_TURN
-> State: 1.3 <-
bricks = 8
turn = A_TURN
-> State: 1.4 <-
bricks = 7
turn = B_TURN
-> State: 1.5 <-
bricks = 6
turn = A_TURN
-> State: 1.6 <-
bricks = 5
turn = B_TURN
-> State: 1.7 <-
bricks = 4
turn = A_TURN
-> State: 1.8 <-
bricks = 3
turn = B_TURN
-> State: 1.9 <-
bricks = 2
turn = A_TURN
-> State: 1.10 <-
bricks = 1
turn = B_TURN
game_won = TRUE
b_won = TRUE
-- Loop starts here
-> State: 1.11 <-
bricks = 0
q = 0
-> State: 1.12 <-
希望此回答对您有所帮助。
我是 NuSMV 的新手,尝试为这个简单的回合制游戏建模。一堆有 10 块砖,每个玩家每回合可以拿取 1-3 块砖,谁拿走最后一块砖就赢了。假设玩家 A 先走,这是我的尝试。我想表达 "eventually there is a winner",但我的代码不起作用,因为它不会阻止玩家在 brick=0 之后拿砖,所以最终玩家 a、b 都会成为赢家。
这是我的代码:
MODULE main
VAR
bricks : 0..10;
i : 1..3;
j : 1..3;
turn : boolean;
winner : {none, a, b};
ASSIGN
init(winner) := none;
init(bricks) := 10;
init(turn) := TRUE;
next(turn) := case
turn : FALSE;
!turn: TRUE;
esac;
next(bricks) :=
case
bricks - j >= 0 : bricks - j;
bricks - j < 0 : 0;
TRUE:bricks;
esac;
next(winner) := case
turn=TRUE & bricks = 0: a;
turn=FALSE & bricks = 0: b;
TRUE:winner;
esac;
SPEC AF (winner = a | winner = b)
这是我在 SPEC AF 上的输出(获胜者 = a | 获胜者 = none)来说明我的观点。
i = 1
j = 1
turn = TRUE
winner = none
State: 1.2 <-
bricks = 9
j = 3
turn = FALSE
State: 1.3 <-
bricks = 6
turn = TRUE
State: 1.4 <-
bricks = 3
turn = FALSE
State: 1.5 <-
bricks = 0
j = 1
turn = TRUE
State: 1.6 <-
turn = FALSE
winner = a
State: 1.7 <-
turn = TRUE
winner = b
如您所见,模型仍然提供了一个反例,即玩家 a 已经获胜后玩家 b 赢得了游戏。
我不确定您如何提供 反例,因为您指定的 属性 是 验证的型号:
-- specification AF (winner = a | winner = b) is true
也许您模拟了该程序并简单地观察到它以意想不到的方式运行。您似乎真正要验证的 属性 是 AF (AG winner = a | AG winner = b)
。事实上,使用此 属性 会导致 反例 类似于您自己的:
-- specification AF (AG winner = a | AG winner = b) is false
-- as demonstrated by the following execution sequence
Trace Description: CTL Counterexample
Trace Type: Counterexample
-> State: 1.1 <-
bricks = 10
i = 1
j = 1
turn = TRUE
winner = none
-> State: 1.2 <-
bricks = 9
turn = FALSE
-> State: 1.3 <-
bricks = 8
turn = TRUE
-> State: 1.4 <-
bricks = 7
turn = FALSE
-> State: 1.5 <-
bricks = 6
turn = TRUE
-> State: 1.6 <-
bricks = 5
turn = FALSE
-> State: 1.7 <-
bricks = 4
turn = TRUE
-> State: 1.8 <-
bricks = 3
turn = FALSE
-> State: 1.9 <-
bricks = 2
turn = TRUE
-> State: 1.10 <-
bricks = 1
turn = FALSE
-> State: 1.11 <-
bricks = 0
turn = TRUE
-- Loop starts here
-> State: 1.12 <-
turn = FALSE
winner = a
-> State: 1.13 <-
turn = TRUE
winner = b
-> State: 1.14 <-
turn = FALSE
winner = a
问题是游戏结束了还要翻牌,结果就是A和B不断翻牌。
我重新编写了您的解决方案以更好的方式:
MODULE main
VAR
bricks : 0..10;
q : 0..3;
turn : {A_TURN , B_TURN};
DEFINE
game_won := next(bricks) = 0;
a_won := game_won & turn = A_TURN;
b_won := game_won & turn = B_TURN;
ASSIGN
init(bricks) := 10;
init(turn) := A_TURN;
next(bricks) := case
bricks - q >= 0 : bricks - q;
TRUE : 0;
esac;
next(turn) := case
turn = A_TURN & !game_won: B_TURN;
turn = B_TURN & !game_won: A_TURN;
TRUE : turn;
esac;
-- forbid q values from being both larger than the remaining number of
-- bricks, and equal to zero when there are still bricks to take.
INVAR (q <= bricks)
INVAR (bricks > 0) -> (q > 0)
INVAR (bricks <= 0) -> (q = 0)
-- Sooner or later the number of bricks will always be
-- zero for every possible state in every possible path,
-- that is, someone won the game
CTLSPEC
AF AG (bricks = 0)
我认为代码是不言自明的。
您可以 运行 它与 NuSMV 和 nuXmv 使用以下命令:
> read_model -i game.smv
> go
> check_property
-- specification AF (AG bricks = 0) is true
如果您想找到可能的解决方案,只需翻转 属性:
> check_ctlspec -p "AF AG (bricks != 0)"
-- specification AF (AG bricks != 0) is false
-- as demonstrated by the following execution sequence
Trace Description: CTL Counterexample
Trace Type: Counterexample
-> State: 1.1 <-
bricks = 10
q = 1
turn = A_TURN
game_won = FALSE
b_won = FALSE
a_won = FALSE
-> State: 1.2 <-
bricks = 9
turn = B_TURN
-> State: 1.3 <-
bricks = 8
turn = A_TURN
-> State: 1.4 <-
bricks = 7
turn = B_TURN
-> State: 1.5 <-
bricks = 6
turn = A_TURN
-> State: 1.6 <-
bricks = 5
turn = B_TURN
-> State: 1.7 <-
bricks = 4
turn = A_TURN
-> State: 1.8 <-
bricks = 3
turn = B_TURN
-> State: 1.9 <-
bricks = 2
turn = A_TURN
-> State: 1.10 <-
bricks = 1
turn = B_TURN
game_won = TRUE
b_won = TRUE
-- Loop starts here
-> State: 1.11 <-
bricks = 0
q = 0
-> State: 1.12 <-
希望此回答对您有所帮助。