This section reminders me "Related location 1. This is the postcondition that might not hold."
datatype CACHE_STATE = I| S| E
datatype MSG_CMD = Empty| ReqS| ReqE| Inv| InvAck| GntS| GntE
type NODE=nat
type DATA=nat
type boolean=bool
method n_RecvGntSinv__2_0(Cache_Data:array<DATA>, Cache_State:array<CACHE_STATE>, Chan2_Cmd:array<MSG_CMD>, Chan2_Data:array<DATA>,i:nat, N0:nat,p__Inv0:nat,p__Inv2:nat)
requires Cache_Data.Length==N0
requires Cache_State.Length==N0
requires Chan2_Cmd.Length==N0
requires Chan2_Data.Length==N0
requires 0<= i<N0
requires p__Inv0!=p__Inv2&&p__Inv2<N0&& p__Inv0<N0
requires i==p__Inv2
requires (!((Cache_State[p__Inv0] == E) && (Chan2_Cmd[p__Inv2] == GntS)))//3
//guard condition
requires (Chan2_Cmd[i] == GntS)
ensures !((Cache_State[p__Inv2] == S) && (!(Cache_State[p__Inv0] == I)) && (!(Cache_State[p__Inv0] == S)))
modifies Cache_Data
modifies Cache_State
modifies Chan2_Cmd
modifies Chan2_Data
{
Cache_State[i] := S;
Cache_Data[i] := Chan2_Data[i];
Chan2_Cmd[i] := Empty;
}
When i change the condition of ensure,like the below fragment
datatype CACHE_STATE = I| S| E
datatype MSG_CMD = Empty| ReqS| ReqE| Inv| InvAck| GntS| GntE
type NODE=nat
type DATA=nat
type boolean=bool
method n_RecvGntSinv__2_0(Cache_Data:array<DATA>, Cache_State:array<CACHE_STATE>, Chan2_Cmd:array<MSG_CMD>, Chan2_Data:array<DATA>,i:nat, N0:nat,p__Inv0:nat,p__Inv2:nat)
requires Cache_Data.Length==N0
requires Cache_State.Length==N0
requires Chan2_Cmd.Length==N0
requires Chan2_Data.Length==N0
requires 0<= i<N0
requires p__Inv0!=p__Inv2&&p__Inv2<N0&& p__Inv0<N0
requires i==p__Inv2
requires (!((Cache_State[p__Inv0] == E) && (Chan2_Cmd[p__Inv2] == GntS)))//3
//guard condition
requires (Chan2_Cmd[i] == GntS)
ensures !((Cache_State[p__Inv2] == S) && (Cache_State[p__Inv0] == E ))modifies Cache_Data
modifies Cache_State
modifies Chan2_Cmd
modifies Chan2_Data
{
Cache_State[i] := S;
Cache_Data[i] := Chan2_Data[i];
Chan2_Cmd[i] := Empty;
}
This compiles success.Whether there are some place i don't understand Dafny?
I think Dafny is no longer maintained by people, it is dead! No need to use it!
Related
Is there a built-in data type in Dafny like List in Java (or any type for dynamic list)?
I've looked for it in Dafny Reference Manual, but nothing found.
It seems that a self-defined class must be defined for it.
If it is the fact, then how can the performance be assured for the generated java program and how can the gernerality of Dafny as a programming language be assured?
Not criticism, just curious.
Dafny's first collection is undoubtedly seq, which is an immutable list.
function sum(s: seq<int>): int {
if |s| == 0 then 0 else s[0] + sum(s[1..])
}
For anything else, the Dafny team is working on a standard library, but you might be interestest by the first example given in the Dafny documentation that also explain why lists are non trivial objects to verify:
https://dafny.org/dafny/DafnyRef/DafnyRef#sec-example
In short, to define a list, you want to write a class and store a ghost model of all the elements to ensure there is no cycle, and possibly write this node into another data structure. But the proofs are not obvious. Here is what I got so far.
class ListNode<T> {
var head: T
var tail: ListNode?<T>
ghost var Repr: seq<ListNode<T>>
constructor(h: T, t: ListNode?<T>) requires t != null ==> t.Valid() ensures Valid()
{
head:= h;
tail := t;
Repr := [this] + (if t == null then [] else t.Repr);
}
predicate Valid() reads this, Repr decreases |Repr|
{
&& |Repr| > 0
&& Repr[0] == this
&& (if tail == null then |Repr| == 1 else
&& |Repr| > 1
&& tail == Repr[1]
&& tail.Repr == Repr[1..]
&& tail.Valid())
}
lemma ReprAreDecreasing(i: int)
requires Valid()
requires 0 <= i < |Repr|
ensures Repr[i].Repr == Repr[i..]
ensures Repr[i].Valid()
{
if i == 0 {
} else {
tail.ReprAreDecreasing(i-1);
}
}
}
class List<T> {
var head: ListNode?<T>
var last: ListNode?<T>
ghost var Repr: seq<ListNode<T>>
constructor() ensures Valid() {
head := null;
last := null;
Repr := [];
}
lemma ValidImpliesAllNodesValid(n: ListNode<T>)
requires Valid()
requires n in Repr
ensures n.Valid() {
if n == head {
assert n.Valid();
} else {
var i :| 0 <= i < |Repr| && Repr[i] == n;
head.ReprAreDecreasing(i);
}
}
method Append(node: ListNode<T>)
{
...
}
predicate Valid() reads this, Repr
{
(if head != null then
&& last != null
&& head in Repr
&& head.Repr == Repr
&& head.Valid()
&& last == head.Repr[|head.Repr|-1]
&& assert last.Repr == head.Repr[|head.Repr|-1..] by {
head.ReprAreDecreasing(|head.Repr|-1);
} last.Valid()
else
&& last == null
&& |Repr| == 0)
}
}
References:
https://dafny.org/dafny/DafnyRef/DafnyRef#sec-seq-comprehension
The final commented out assert will not validate but when run the if statement above will prints.
OUTPUT
ohb= true
ohx= false
palin(xe) == false
ohx ==false
function method palin(a:seq<int>) :bool {
forall i:int :: (0<=i && i<(|a|/2)) ==> a[i]==a[|a|-i -1]
}
method Main() {
var xe:seq<int> := [0,1,2,3,0];
var se:seq<int> := [0,1,2,1,0];
var ohb := palin(se);
var ohx :bool := palin(xe);
print "ohb= ",ohb,"\n";
print "ohx= ",ohx,"\n";
assert palin(se);
if (palin(xe) == false) {print "palin(xe) == false\n";}
if (!ohx) {print "ohx ==false\n";}
//assert !ohx;
}
A failing assert means the verifier cannot automatically find a proof. If you think the property holds, you need to write the proof (or part of the proof).
For your program, proving that something is not a palindrome comes down to showing a position that violates the palindrome property. In terms of logic, you're trying to prove the negation of a forall, which is an exists, and to prove an exists you'll need to supply the witness for the bound variable i.
In your example, the following suffices:
predicate method palin(a: seq<int>) {
forall i :: 0 <= i < |a| / 2 ==> a[i] == a[|a| - i - 1]
}
method Main() {
var xe := [0,1,2,3,0];
var se := [0,1,2,1,0];
var ohb := palin(se);
var ohx := palin(xe);
print "ohb= ", ohb, "\n";
print "ohx= ", ohx, "\n";
assert palin(se);
if palin(xe) == false { print "palin(xe) == false\n"; }
if !ohx { print "ohx == false\n"; }
assert !ohx by {
assert xe[1] != xe[3];
}
}
datatype CACHE_STATE = I| S| E
datatype MSG_CMD = Empty| ReqS| ReqE| Inv| InvAck| GntS| GntE
type NODE=nat
type DATA=nat
type boolean=bool
class class_0 {
var
Data : DATA,
Cmd : MSG_CMD
}
class class_1 {
var
Data : DATA,
State : CACHE_STATE
}
method n_SendGntEinv__5_0(Cache_State:array<CACHE_STATE>, Chan2_Cmd:array<MSG_CMD>, Chan2_Data:array<DATA>, CurCmd:MSG_CMD, CurPtr:NODE, ExGntd:boolean, MemData:DATA, ShrSet:array<boolean>,
i:nat,N0:nat,p__Inv0:nat,p__Inv2:nat)
requires 0<= i < N0
requires Chan2_Cmd.Length==N0
requires Chan2_Data.Length==N0
requires ShrSet.Length==N0
requires p__Inv0!=p__Inv2&&p__Inv2<N0&& p__Inv0<N0
requires i==p__Inv2
//1
//guard condition
requires ((Chan2_Cmd[i] == Empty) && (CurCmd == ReqE) && (CurPtr == i) && (ExGntd == false) && (forall j |0<= j<N0 :: (ShrSet[j] == false) ))
ensures (!((Cache_State[p__Inv0] == E) && (Chan2_Cmd[p__Inv2] == GntS)))
modifies Chan2_Cmd
modifies Chan2_Data
modifies ShrSet
{
Chan2_Cmd[i] := GntE;
Chan2_Data[i] := MemData;
ShrSet[i] := true;
ExGntd := true;
CurCmd := Empty;
}
I try to compile this code, however tip mentions me
LHS of assignment must denote a mutable variable
and I don't know how to solve the problem. Does the CurCMD and the EXGntd need to be array value, or there has other solution to this problem?
In-parameters are immutable. The error message points out that you're trying to assign to them.
You can introduce (mutable) local variables, if you want. In your example, that would look like:
var ExGntd', CurCmd' := ExGntd, CurCmd;
...
ExGntd' := true;
CurCmd' := Empty;
When I run my code, I get an index out of range error. The same problem also occurs at the ensures statement.
My code:
datatype CACHE_STATE = I| S| E
datatype MSG_CMD = Empty| ReqS| ReqE| Inv| InvAck| GntS| GntE
type NODE=nat
type DATA=nat
type boolean=bool
class class_0 {
var
Data : DATA,
Cmd : MSG_CMD
}
class class_1 {
var
Data : DATA,
State : CACHE_STATE
}
class TopC{
var
AuxData : DATA,
MemData : DATA,
CurPtr : NODE,
CurCmd : MSG_CMD,
ExGntd : boolean,
ShrSet : array<boolean>,
InvSet : array<boolean>,
Chan3 : array<class_0 > ,
Chan2 : array<class_0 > ,
Chan1 : array<class_0 > ,
Cache : array<class_1 > }
method n_RecvInvAck(top:TopC,i:nat, N0:nat,p1:nat,p2:nat )
requires 0<= i<N0
requires top.Chan3.Length ==N0
requires top.ShrSet.Length ==N0
requires N0>0
requires 0<= p1 <top.Chan3.Length
requires 0<= p2 <top.Chan3.Length
requires p1
requires N0>0
requires (i==p2)
requires ((top.Chan3[i].Cmd == InvAck) && (!(top.CurCmd == Empty)))
modifies top.Chan3[i]
modifies top.ShrSet
modifies top
ensures (!((top.ShrSet[p1] == true) && (top.ExGntd == true) &&
(top.ShrSet[p2] == true)))
{
top.Chan3[i].Cmd := Empty;
top.ShrSet[i] := false;
if (top.ExGntd == true) {
top.ExGntd := false;
top.MemData := top.Chan3[i].Data;
}
}
The problem is that the method modifies top, which means it might allocated a totally different array for top.ShrSet, which might have a different length.
You can add the line
ensures top.ShrSet == old(top.ShrSet)
before the other ensures clause to fix this problem.
I am trying to match a variable (a string) to one of my defined tokens in JAVACC. The pseudocode for what I am trying to do is...
String x;
if (x matches <FUNCTIONNAME>) {...}
How would I go about achieving this?
Thank you
Here is one way to do it. Use the STATIC==false option. The following code should do what you need
public boolean matches( String str, int k ) {
// Precondition: k should be one of the integers
// given a name in XXXConstants
// Postcondition: result is true if and only if str would be lexed by
// the lexer as a single token of kind k possibly
// preceeded and followed by any number of skipped and special tokens.
StringReader sr = new StringReader( str ) ;
SimpleCharStream scs = new SimpleCharStream( sr ) ;
XXXTokenManager lexer = new XXXTokenManager( scs );
boolean matches = false ;
try {
Token a = lexer.getNextToken() ;
Token b = lexer.getNextToken() ;
matches = a.kind == k && b.kind == 0 ; }
catch( Throwable t ) {}
return matches ;
}
One problem with this is that it will skip tokens declared as SKIP or SPECIAL_TOKEN. E.g. if I use a Java lexer then "/*hello*/\tworld // \n" will still match JavaParserConstants.ID. If you don't want this, you need to do two things. First go into the .jj file and convert any SKIP tokens to SPECIAL_TOKENS. Second add checks that there no special tokens were found
matches = a.kind == k && b.kind == 0 && a.specialToken == null && b.specialToken == null ;