Is there a data type in Dafny like List<T> in java? - dafny

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

Related

Why does my shunting yard implementation mix operator order?

I have been trying to implement the shunting yard algorithm, but the output of my parser is incorrect.
let mut stack: Vec<String> = vec![];
let mut op_stack: Vec<String> = vec![];
for current in sub_tree {
if current.tok_type == TokenType::NUMBER || current.tok_type == TokenType::NEGNUMBER {
self.parse();
stack.push(current.content.clone());
}
if current.tok_type == TokenType::SUBBIN
|| current.tok_type == TokenType::PLUSBIN
|| current.tok_type == TokenType::DIVBIN
|| current.tok_type == TokenType::MULBIN
{
while op_stack.len() > 0 && op_stack.last().unwrap().to_string() != "(" {
if op_prec(&op_stack.last().unwrap().to_string()) > op_prec(&current.content)
|| (op_prec(&op_stack.last().unwrap().to_string()) == op_prec(&current.content)
&& op_asso(&current.content) == "left")
{
stack.push(op_stack.pop().unwrap().to_string());
} else {
break;
}
}
op_stack.push(current.content.to_string())
}
}
The original equation I am parsing: 1 + 2 * 3
I expected the following output: 1 2 3 * +
Instead I get this: 1 2 3 + *
I think I am going wrong somewhere in my while loop but I don't really know. I tried to follow the example on the Wikipedia article.
I forgot I had to pop from the operator stack back into the output stack at the end.
Comparing your code
if current.tok_type == TokenType::SUBBIN
|| current.tok_type == TokenType::PLUSBIN
|| current.tok_type == TokenType::DIVBIN
|| current.tok_type == TokenType::MULBIN
{
while op_stack.len() > 0 && op_stack.last().unwrap().to_string() != "(" {
if op_prec(&op_stack.last().unwrap().to_string()) > op_prec(&current.content)
|| (op_prec(&op_stack.last().unwrap().to_string()) == op_prec(&current.content)
&& op_asso(&current.content) == "left")
{
stack.push(op_stack.pop().unwrap().to_string());
} else {
break;
}
}
op_stack.push(current.content.to_string())
}
with the Wikipedia code https://en.wikipedia.org/wiki/Shunting-yard_algorithm
- an operator o1:
while (
there is an operator o2 other than the left parenthesis at the top
of the operator stack, and (o2 has greater precedence than o1
or they have the same precedence and o1 is left-associative)
):
pop o2 from the operator stack into the output queue
push o1 onto the operator stack
It looks like they are functionally identical.
So I suspect the problem is not with the code, but instead with the precedence table. If you have the precedence of + and * the wrong way round, then you would get this behaviour. It is easy to get this mixed up as some source have precedence going from tighter binding to loser one and some have the opposite. Compare Wikipedia order of operations and Operator Precedence in Java, use the former.

Can dafny assert cope with "! false"

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];
}
}

LHS of assignment must denote a mutable variable

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;

strange index out of range In Dafny

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.

Filtering IQueryable result set using parameters

I'm getting confused with this and I know there will be a more slick way of starting it off. The 'result' variable has many records and I want to check if IN_SiteId is > 0 and filter on it, same after that for LandownerId and PaymentCategoryId etc. If I can get the right approach for the first 2 I will be ok from there. This should be easier but having a brick wall day. Any comments appreciated
public IQueryable rptRentPaidMonthly(int IN_SiteId, int IN_LandownerId, int IN_PaymentCategoryId, int IN_PaymentTypeId, string IN_ShowRelevantProportion)
{
var result = this._lmsDb.rptRentPaidMonthly(IN_daysFrom, IN_daysTo, IN_SiteId, IN_LandownerId, IN_PaymentCategoryId, IN_PaymentTypeId, IN_ShowRelevantProportion);
if (IN_SiteId > 0)
{
var searchResults = (from s in result
where (s.SiteId == #IN_SiteId)
select s);
return searchResults.AsQueryable();
}
return result.AsQueryable();
}
I'm not a LINQ expert but I think you can do something like this:
public IQueryable rptRentPaidMonthly(int IN_SiteId, int IN_LandownerId, int IN_PaymentCategoryId, int IN_PaymentTypeId, string IN_ShowRelevantProportion)
{
var result = this._lmsDb.rptRentPaidMonthly(IN_daysFrom, IN_daysTo, IN_SiteId, IN_LandownerId, IN_PaymentCategoryId, IN_PaymentTypeId, IN_ShowRelevantProportion);
var searchResults = (from s in result
where (IN_SiteId <= 0 || s.SiteId == IN_SiteId)
&& (IN_LandownerId <= 0 || s.LandownerId == IN_LandownerId)
&& (IN_PaymentCategoryId <= 0 || s.PaymentCategoryId == IN_PaymentCategoryId)
&& (IN_PaymentTypeId <= 0 || s.PaymentTypeId == In_PaymentTypeId)
select s);
return searchResults.AsQueryable();
}
The where clause checks if each filter value is less than or equal to 0, if so then it will return true and will not evaluate the next bit which attempts to filter the actual field on the value provided.

Resources