-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1114 from utwente-fmt/veymont-reinstate-old-tests
VeyMont: reinstate old tests & case studies
- Loading branch information
Showing
148 changed files
with
5,543 additions
and
2,542 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
199 changes: 199 additions & 0 deletions
199
...hive/known-problems/no-issue/2023/VeyMontToolPaper/paper-examples/veymont-tictactoemn.pvl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
/* | ||
Requires to pass: --assumeInjectivityOnInhale. | ||
|
||
TODO: This file verifies slowly because the generated permissions are too coarse. This can be fixed in two ways. | ||
First, when VeyMont has permission support, we can manually specify the permissions. Second, the permissions that | ||
VeyMont generates can be tightened, though it is unclear if that speeds up this file. | ||
*/ | ||
|
||
class Move { | ||
int x; | ||
int y; | ||
int t; | ||
|
||
ensures this.x == x; | ||
ensures this.y == y; | ||
ensures this.t == t; | ||
constructor(int x, int y, int t); | ||
|
||
ensures \old(x) == x && x == \result.x; | ||
ensures \old(y) == y && y == \result.y; | ||
ensures \old(t) == t && t == \result.t; | ||
Move clone() { | ||
return new Move(x, y, t); | ||
} | ||
} | ||
|
||
class Player { | ||
int width, height, myToken, yourToken; | ||
int[][] board; | ||
Move temp; | ||
Move move; | ||
boolean goOn; | ||
|
||
inline resource constants() = | ||
\old(width) == width && | ||
\old(height) == height && | ||
\old(myToken) == myToken && | ||
\old(yourToken) == yourToken && | ||
\old(temp) == temp && | ||
\old(move) == move && | ||
\old(board) == board && | ||
(\forall int i = 0 .. board.length; \old(board[i]) == board[i]); | ||
|
||
ensures width == m && height == n && myToken == t1 && yourToken == t2; | ||
ensures matrix(board, width, height); | ||
ensures (\forall int i = 0..width, int j = 0..height; {: board[i][j] :} == 0); | ||
ensures goOn == false; | ||
constructor(int m, int n, int t1, int t2); | ||
|
||
context matrix(board, width, height); | ||
ensures constants(); | ||
ensures (\forall int i = 0..width, int j = 0..height; \old(board[i][j]) == {: board[i][j] :}); | ||
ensures \old(goOn) == goOn; | ||
ensures 2 <= move.x && move.x < width - 2; | ||
ensures 2 <= move.y && move.y < height - 2; | ||
ensures move.t == myToken; | ||
ensures board[move.x][move.y] == 0; | ||
void think(); | ||
|
||
requires matrix(board, width, height); | ||
requires 2 <= x && x < width - 2; | ||
requires 2 <= y && y < height - 2; | ||
pure boolean twoTokensAroundMove(int x, int y) = ( | ||
(board[x-2][y] == move.t && board[x-1][y] == move.t) || | ||
(board[x-1][y] == move.t && board[x+1][y] == move.t) || | ||
(board[x+1][y] == move.t && board[x+2][y] == move.t) || | ||
(board[x][y-2] == move.t && board[x][y-1] == move.t) || | ||
(board[x][y-1] == move.t && board[x][y+1] == move.t) || | ||
(board[x][y+1] == move.t && board[x][y+2] == move.t) || | ||
(board[x-2][y-2] == move.t && board[x-1][y-1] == move.t) || | ||
(board[x-1][y-1] == move.t && board[x+1][y+1] == move.t) || | ||
(board[x+1][y+1] == move.t && board[x+2][y+2] == move.t) || | ||
(board[x+2][y-2] == move.t && board[x+1][y-1] == move.t) || | ||
(board[x+1][y-1] == move.t && board[x-1][y+1] == move.t) || | ||
(board[x-1][y+1] == move.t && board[x-2][y+2] == move.t)); | ||
|
||
context matrix(board, width, height); | ||
context 2 <= move.x && move.x < width - 2; | ||
context 2 <= move.y && move.y < height - 2; | ||
context 1 <= move.t && move.t <= 2; | ||
requires board[move.x][move.y] == 0; | ||
ensures constants(); | ||
ensures \old(move.x) == move.x; | ||
ensures \old(move.y) == move.y; | ||
ensures \old(move.t) == move.t; | ||
ensures (\forall int i = 0..width, int j = 0..height; | ||
(i != move.x || j != move.y) ==> \old({: board[i][j] :}) == board[i][j]); | ||
ensures board[move.x][move.y] == move.t; | ||
ensures \old(goOn) == false ==> goOn == false; | ||
/*ensures (\let int[] bx = board[move.x]; | ||
\old(goOn) == true ==> ((board[move.x-2][move.y] == move.t && board[move.x-1][move.y] == move.t) || | ||
(board[move.x-1][move.y] == move.t && board[move.x+1][move.y] == move.t) || | ||
(board[move.x+1][move.y] == move.t && board[move.x+2][move.y] == move.t) || | ||
(bx[move.y-2] == move.t && bx[move.y-1] == move.t) || | ||
(bx[move.y-1] == move.t && bx[move.y+1] == move.t) || | ||
(bx[move.y+1] == move.t && bx[move.y+2] == move.t) || | ||
(board[move.x-2][move.y-2] == move.t && board[move.x-1][move.y-1] == move.t) || | ||
(board[move.x-1][move.y-1] == move.t && board[move.x+1][move.y+1] == move.t) || | ||
(board[move.x+1][move.y+1] == move.t && board[move.x+2][move.y+2] == move.t) || | ||
(board[move.x+2][move.y-2] == move.t && board[move.x+1][move.y-1] == move.t) || | ||
(board[move.x+1][move.y-1] == move.t && board[move.x-1][move.y+1] == move.t) || | ||
(board[move.x-1][move.y+1] == move.t && board[move.x-2][move.y+2] == move.t)) == !goOn | ||
); */ | ||
ensures \old(goOn) == true ==> twoTokensAroundMove(move.x, move.y) == !goOn; | ||
void play(); | ||
} | ||
|
||
requires matrix(p1.board, p1.width, p1.height) ** matrix(p2.board, p2.width, p2.height); | ||
requires p1.width == p2.width && p1.height == p2.height; | ||
requires (\forall int i = 0..p1.width, int j = 0..p1.height; {: p1.board[i][j] :} == {: p2.board[i][j] :}); | ||
requires p1.move.x == p2.move.x && p1.move.y == p2.move.y && p1.move.t == p2.move.t; | ||
requires 2 <= p1.move.x && p1.move.x < p1.width - 2; | ||
requires 2 <= p1.move.y && p1.move.y < p1.height - 2; | ||
requires !p1.goOn == p1.twoTokensAroundMove(p1.move.x, p1.move.y); | ||
requires !p2.goOn == p2.twoTokensAroundMove(p2.move.x, p2.move.y); | ||
ensures p1.constants() ** p2.constants(); | ||
ensures p1.goOn == p2.goOn; | ||
ensures (\forall int i = 0..p1.width, int j = 0..p1.height; \old({: p1.board[i][j] :}) == p1.board[i][j]); | ||
ensures (\forall int i = 0..p2.width, int j = 0..p2.height; \old({: p2.board[i][j] :}) == p2.board[i][j]); | ||
void lemma(Player p1, Player p2) { | ||
// Automatic | ||
} | ||
|
||
requires matrix(p.board, p.width, p.height); | ||
requires 2 <= p.move.x && p.move.x < p.width - 2; | ||
requires 2 <= p.move.y && p.move.y < p.height - 2; | ||
ensures !p.goOn == p.twoTokensAroundMove(p.move.x, p.move.y); | ||
pure boolean twoTokensLemma(Player p); | ||
|
||
inline resource matrix(int[][] mat, int w, int h) = | ||
mat != null && mat.length == w && (\forall int i = 0 .. w; {: mat[i] :} != null && {: mat[i] :}.length == h); | ||
|
||
inline resource consistency(Player p1, Player p2) = | ||
p1.myToken == 1 ** p2.myToken == 2 ** | ||
p1.myToken == p2.yourToken ** p1.yourToken == p2.myToken ** | ||
p1.width == p2.width ** p1.height == p2.height ** | ||
matrix(p1.board, p1.width, p1.height) ** | ||
matrix(p2.board, p2.width, p2.height) ** | ||
(\forall int i = 0..p1.width, int j = 0..p1.height; {: p1.board[i][j] :} == {: p2.board[i][j] :}) ** | ||
p1.goOn == p2.goOn; | ||
|
||
seq_program tic_tac_toe(int m, int n) { | ||
endpoint p1 = Player(m, n, 1, 2); | ||
endpoint p2 = Player(m, n, 2, 1); | ||
|
||
// context consistency(p1, p2); | ||
requires p1.goOn ** p2.goOn; | ||
context | ||
p1.myToken == 1 ** p2.myToken == 2 ** | ||
p1.myToken == p2.yourToken ** p1.yourToken == p2.myToken ** | ||
p1.width == p2.width ** p1.height == p2.height ** | ||
matrix(p1.board, p1.width, p1.height) ** | ||
matrix(p2.board, p2.width, p2.height) ** | ||
(\forall int i = 0..p1.width, int j = 0..p1.height; {: p1.board[i][j] :} == {: p2.board[i][j] :}) ** | ||
p1.goOn == p2.goOn; | ||
void turn1() { | ||
p1.think(); | ||
p1.play(); | ||
p2.think(); // in the background | ||
p1.temp := p1.move.clone(); | ||
communicate p2.move <- p1.temp; | ||
p1.temp := p1.move.clone(); // Workaround - shouldn't be necessary... | ||
p2.play(); // to update | ||
|
||
// The assume goal below is slow to prove. Basically because of the next two proof goals: | ||
// assume !p1.goOn == p1.twoTokensAroundMove(p1.move.x, p1.move.y); | ||
// assume !p2.goOn == p2.twoTokensAroundMove(p2.move.x, p2.move.y); | ||
// I would expect them to be quick to verify, as they are in the postcondition of play(). | ||
// But the state changes above apparently cause this fact to be deleted everytime... Somehow. | ||
// The program also verifies without the assume, but to keep the test suite quick we encode it like this | ||
assume p1.goOn == p2.goOn; | ||
} | ||
|
||
requires p1.goOn ** p2.goOn; | ||
context consistency(p1, p2); | ||
void turn2() { | ||
p2.think(); | ||
p2.play(); | ||
p1.think(); // in the background | ||
p2.temp := p2.move.clone(); | ||
communicate p1.move <- p2.temp; | ||
p2.temp := p2.move.clone(); // Workaround - shouldn't be necessary... | ||
p1.play(); // to update | ||
|
||
// See long comment above | ||
assume p1.goOn == p2.goOn; | ||
} | ||
|
||
context consistency(p1, p2); | ||
seq_run { | ||
loop_invariant consistency(p1, p2); | ||
while(p1.goOn && p2.goOn){ | ||
turn1(); | ||
if (p1.goOn && p2.goOn) { | ||
turn2(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
class Move { | ||
int i, j, token; | ||
|
||
ensures i == mi ** j == mj ** token == mt; | ||
constructor(int mi, int mj, int mt) { | ||
i = mi; | ||
j = mj; | ||
token = mt; | ||
} | ||
|
||
ensures \result.i == i ** \result.j == j ** \result.token == token; | ||
ensures i == \old(i) ** j == \old(j) ** token == \old(token); | ||
Move clone() { | ||
return new Move(i,j,token); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
class Player { | ||
int c00, c01, c02, c10, c11, c12, c20, c21, c22; | ||
int myToken; | ||
Move move, temp; | ||
boolean turn; | ||
|
||
|
||
requires tok == 0 || tok == 1; | ||
ensures c00 == -1 && c01 == -1 && c02 == -1 && | ||
c10 == -1 && c11 == -1 && c12 == -1 && | ||
c20 == -1 && c21 == -1 && c22 == -1; | ||
ensures myToken == tok; | ||
ensures myToken == 0 || myToken == 1; | ||
ensures turn == t; | ||
constructor(int tok, boolean t) { | ||
c00 = -1; | ||
c01 = -1; | ||
c02 = -1; | ||
c10 = -1; | ||
c11 = -1; | ||
c12 = -1; | ||
c20 = -1; | ||
c21 = -1; | ||
c22 = -1; | ||
myToken = tok; | ||
turn = t; | ||
move = new Move(0, 0, tok); | ||
temp = new Move(-1, -1, -1); | ||
} | ||
|
||
|
||
context 0 <= move.i && move.i <= 2; | ||
context 0 <= move.j && move.j <= 2; | ||
requires move.token == 0 || move.token == 1; | ||
ensures myToken == \old(myToken); | ||
requires readMoveCell() == -1; | ||
ensures readMoveCell() == move.token; | ||
ensures move.i == \old(move.i); | ||
ensures move.j == \old(move.j); | ||
ensures move.token == \old(move.token); | ||
ensures turn == \old(turn); | ||
ensures move.i != 0 || move.j != 0 ==> \old(c00) == c00; | ||
ensures move.i != 0 || move.j != 1 ==> \old(c01) == c01; | ||
ensures move.i != 0 || move.j != 2 ==> \old(c02) == c02; | ||
ensures move.i != 1 || move.j != 0 ==> \old(c10) == c10; | ||
ensures move.i != 1 || move.j != 1 ==> \old(c11) == c11; | ||
ensures move.i != 1 || move.j != 2 ==> \old(c12) == c12; | ||
ensures move.i != 2 || move.j != 0 ==> \old(c20) == c20; | ||
ensures move.i != 2 || move.j != 1 ==> \old(c21) == c21; | ||
ensures move.i != 2 || move.j != 2 ==> \old(c22) == c22; | ||
void doMove() { | ||
if(move.i == 0 && move.j == 0) { | ||
c00 = move.token; | ||
} else if(move.i == 0 && move.j == 1) { | ||
c01 = move.token; | ||
} else if(move.i == 0 && move.j == 2) { | ||
c02 = move.token; | ||
} else if(move.i == 1 && move.j == 0) { | ||
c10 = move.token; | ||
} else if(move.i == 1 && move.j == 1) { | ||
c11 = move.token; | ||
} else if(move.i == 1 && move.j == 2) { | ||
c12 = move.token; | ||
} else if(move.i == 2 && move.j == 0) { | ||
c20 = move.token; | ||
} else if(move.i == 2 && move.j == 1) { | ||
c21 = move.token; | ||
} else if(move.i == 2 && move.j == 2) { | ||
c22 = move.token; | ||
} | ||
} | ||
|
||
requires 0 <= move.i && move.i <= 2; | ||
requires 0 <= move.j && move.j <= 2; | ||
pure int readMoveCell() = | ||
(move.i == 0 && move.j == 0) ? c00 | ||
: (move.i == 0 && move.j == 1) ? c01 | ||
: (move.i == 0 && move.j == 2) ? c02 | ||
: (move.i == 1 && move.j == 0) ? c10 | ||
: (move.i == 1 && move.j == 1) ? c11 | ||
: (move.i == 1 && move.j == 2) ? c12 | ||
: (move.i == 2 && move.j == 0) ? c20 | ||
: (move.i == 2 && move.j == 1) ? c21 | ||
: c22; | ||
|
||
pure boolean gridFull() = | ||
c00 != -1 && c01 != -1 && c02 != -1 && | ||
c10 != -1 && c11 != -1 && c12 != -1 && | ||
c20 != -1 && c21 != -1 && c22 != -1; | ||
|
||
pure boolean gridWin() = | ||
c00 != -1 && c00 == c01 && c01 == c02 || | ||
c10 != -1 && c10 == c11 && c11 == c12 || | ||
c20 != -1 && c20 == c21 && c21 == c22 || | ||
c00 != -1 && c00 == c10 && c10 == c20 || | ||
c01 != -1 && c01 == c11 && c11 == c21 || | ||
c02 != -1 && c02 == c12 && c12 == c22 || | ||
c00 != -1 && c00 == c11 && c11 == c22 || | ||
c02 != -1 && c02 == c11 && c11 == c20; | ||
|
||
pure boolean gameFinished() = gridFull() || gridWin(); | ||
|
||
pure boolean equalGrid(Player other) = | ||
c00 == other.c00 && c01 == other.c01 && c02 == other.c02 && | ||
c10 == other.c10 && c11 == other.c11 && c12 == other.c12 && | ||
c20 == other.c20 && c21 == other.c21 && c22 == other.c22; | ||
|
||
ensures 0 <= move.i && move.i <= 2; | ||
ensures 0 <= move.j && move.j <= 2; | ||
requires myToken == 0 || myToken == 1; | ||
ensures move.token == myToken; | ||
ensures move.token == 0 || move.token == 1; | ||
ensures myToken == \old(myToken); | ||
ensures turn == \old(turn); | ||
requires !gridFull(); | ||
ensures readMoveCell() == -1; | ||
ensures c00 == \old(c00) && c01 == \old(c01) && c02 == \old(c02) && | ||
c10 == \old(c10) && c11 == \old(c11) && c12 == \old(c12) && | ||
c20 == \old(c20) && c21 == \old(c21) && c22 == \old(c22); | ||
void createNewMove(); | ||
|
||
} |
Oops, something went wrong.