summaryrefslogtreecommitdiff
path: root/Chalice/tests/refinements/Celebrity.chalice
blob: b0d398e054d4fad55f46f859661b62ddb71681f0 (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
// Celebrity example, inspired by the Rodin tutorial
class Person {
  function knows(other: Person): bool
    requires this != other;
}

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

  method Find(people: seq<Person>, /*ghost*/ c: Person) returns (r: Person)
    requires null !in people && IsCelebrity(c, people);
  {
    var r [r == c];
  }
}

/** Without theory of sets, hard to describe: "remove an element from a sequence" */
class Celebrity1 refines Celebrity0 {
  refines Find(people: seq<Person>, c: Person) returns (r: Person)
  {
    var q:seq<Person> := people;

    // pick and remove a
    var a:Person := q[0]; q := q[1..]; assert people == [a] ++ q;
      
    while (|q| > 0)   
      invariant forall p in q :: p in people;
      invariant a in people;
      invariant IsCelebrity(c,[a] ++ q);  
    {      
      // pick and remove b
      var oldq:seq<Person> := q;
      var b:Person := q[0]; q := q[1..]; 
      assert oldq == [b] ++ q;

      if (a != b && a.knows(b)) {
        a := b;
      }      
    }         

    r := a;
  }
}