summaryrefslogtreecommitdiff
path: root/Test/VSI-Benchmarks/b3.dfy
blob: 91044397d7f54376f4011ef63da73ec23b26d1e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// RUN: %dafny /compile:0 "%s" > "%t"
// RUN: %diff "%s.expect" "%t"

// Note:  We used integers instead of a generic Comparable type, because
// Dafny has no way of saying that the Comparable type's AtMost function
// is total and transitive.

// Note:  We couldn't get things to work out if we used the Get method.
// Instead, we used .contents.

// Note:  Due to infelicities of the Dafny sequence treatment, we
// needed to supply two lemmas, do a complicated assignment of 
// pperm, had to write invariants over p and perm rather than pperm and we couldn't use 
// "x in p".

class Queue<T> {
  var contents: seq<T>;
  method Init()
    modifies this;
    ensures |contents| == 0;
  method Enqueue(x: T)
    modifies this;
    ensures contents == old(contents) + [x];
  method Dequeue() returns (x: T)
    requires 0 < |contents|;
    modifies this;
    ensures contents == old(contents)[1..] && x == old(contents)[0];
  function method Head(): T
    requires 0 < |contents|;
    reads this;
  { contents[0] }
  function method Get(i: int): T
    requires 0 <= i < |contents|;
    reads this;
  { contents[i] }
}

class Comparable {
  function AtMost(c: Comparable): bool
    reads this, c;
}


class Benchmark3 {

  method Sort(q: Queue<int>) returns (r: Queue<int>)
    requires q != null;
    modifies q;
    ensures r != null && fresh(r);
    ensures |r.contents| == |old(q.contents)|;
    ensures forall i, j :: 0 <= i < j < |r.contents| ==> r.Get(i) <= r.Get(j);
    // the final Queue is a permutation of the input Queue
    ensures multiset(r.contents) == multiset(old(q.contents));
  {
    r := new Queue<int>.Init();
    while (|q.contents| != 0)
      invariant |r.contents| + |q.contents| == |old(q.contents)|;
      invariant forall i, j :: 0 <= i < j < |r.contents| ==> r.contents[i] <= r.contents[j];
      invariant forall i, j ::
                    0 <= i < |r.contents| &&
                    0 <= j < |q.contents|
                    ==> r.contents[i] <= q.contents[j];
      // the current array is that permutation of the input array
      invariant multiset(r.contents + q.contents) == multiset(old(q.contents));
    {
      ghost var qc := q.contents;
      var m,k := RemoveMin(q);
      assert qc == qc[..k] + [m] + qc[k+1..];
      r.Enqueue(m);
    }
  }
  
  
  method RemoveMin(q: Queue<int>) returns (m: int, k: int) //m is the min, k is m's index in q
    requires q != null && |q.contents| != 0;
    modifies q;
    ensures |old(q.contents)| == |q.contents| + 1;
    ensures 0 <= k < |old(q.contents)| && old(q.contents[k]) == m;
    ensures forall i :: 0 <= i < |q.contents| ==> m <= q.contents[i];
    ensures q.contents == old(q.contents)[k+1..] + old(q.contents)[..k];  
  {
    var n := |q.contents|;
    k := 0;
    m := q.Head(); 
    var j := 0;
   
    while (j < n)
      invariant j <= n;
      invariant q.contents == old(q.contents)[j..] + old(q.contents)[..j]; //i.e. rotated
      invariant 0 <= k < |old(q.contents)| && old(q.contents)[k] == m;
      invariant forall i :: 0 <= i < j ==> m <= old(q.contents)[i]; //m is min so far
    {
      var x := q.Dequeue();
      q.Enqueue(x);
      if (x < m) { k := j; m := x; }
      j := j+1;
    }
    
    j := 0;
    while (j < k)
      invariant j <= k;
      invariant q.contents == old(q.contents)[j..] + old(q.contents)[..j]; 
    {
      var x := q.Dequeue();
      q.Enqueue(x);
      j := j+1;
      assert q.contents == old(q.contents)[j..] + old(q.contents)[..j];
    }

    m := q.Dequeue();
  }
}