summaryrefslogtreecommitdiff
path: root/Chalice/examples/refinement/Celebrity.chalice
blob: 266ebb1bc7fe16c26f1967f49ac5087b1e376024 (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
// Celebrity example, inspired by the Rodin tutorial
class Person {
  var knows: seq<Person>;
}

class Celebrity {
  function IsCelebrity(c: Person, people: seq<Person>): bool
    requires forall p in people :: p != null;
    requires c in people && rd(people[*].knows);
  {
    forall p in people :: p != c ==> (c in p.knows) && (p !in c.knows)
  }

  method FindCelebrity0(people: seq<Person>) returns (r: Person)
    requires null !in people && rd(people[*].knows); 
    requires exists c in people :: IsCelebrity(c, people);
    ensures rd(people[*].knows);
    ensures r in people && IsCelebrity(r, people);
  {
    var cc:Person; 
    assume cc in people && IsCelebrity(cc, people);
    r := cc;
  }

  method FindCelebrity1(people: seq<Person>) returns (r: Person)
    requires null !in people && rd(people[*].knows);
    requires exists c in people :: IsCelebrity(c, people);
    ensures rd(people[*].knows);
    ensures r in people && IsCelebrity(r, people);
  {
    call r := Eliminate0(people, people);
  }
  
  method Eliminate0(Q: seq<Person>, people: seq<Person>) returns (r: Person)
    requires null !in people && rd(people[*].knows);
    requires forall c in Q :: c != null && c in people;
    requires exists c in Q :: IsCelebrity(c, people);  
    ensures rd(people[*].knows);
    ensures r in people && IsCelebrity(r, people);
  {
    if (|Q| == 1) {
      r := Q[0];
    } else {
      var x:Person := Q[0];
      var y:Person := Q[1];
      var W:seq<Person>;
      assume x != y;
      if (y in x.knows) {
        W := Q[1..];
        assert !IsCelebrity(x, people);          
        assert Q == [x] ++ W; 
      } else {
        W := [x] ++ Q[2..];
        assert !IsCelebrity(y, people);
        assert W[0] == x;
        assert W[1..] == Q[2..];

        assert exists c in W :: IsCelebrity(c, people);
      }
      call r := Eliminate0(W, people);
    }
  }
}