summaryrefslogtreecommitdiff
path: root/Test/dafny4/FlyingRobots.dfy
blob: c80d310daf3542cbf0ff35db090907304e6f068f (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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
// RUN: %dafny /compile:3 /dprint:"%t.dprint" /autoTriggers:1 "%s" > "%t"
// RUN: %diff "%s.expect" "%t"

// The flying robots examples from an F* tutorial.  It demonstrates how to specify
// mutable data structures in the heap.

class Cell {
  var val:int
  constructor (v:int)
    modifies this
    ensures val == v
  {
    val := v;
  }
}

class Point {
  ghost var Value: (int, int, int)

  ghost var Repr: set<object>
  predicate Valid()
    reads this, Repr
  {
    this in Repr && null !in Repr &&
    {x,y,z} <= Repr &&
    x != y && y != z && z != x &&
    Value == (x.val, y.val, z.val)
  }
  
  var x:Cell, y:Cell, z:Cell

  constructor (a:int, b:int, c:int)
    modifies this
    ensures Valid() && fresh(Repr - {this})
    ensures Value == (a, b, c)
  {
    x := new Cell(a);
    y := new Cell(b);
    z := new Cell(c);
    Repr := {this};
    Repr := Repr + {x, y, z};
    Value := (a, b, c);
  }

  method Mutate(a:int, b:int, c:int)
    requires Valid()
    modifies Repr
    ensures Valid() && fresh(Repr - old(Repr))
    ensures Value == (a, b, c)
  {
    x.val, y.val, z.val := a, b, c;
    Value := (a, b, c);
  }
}

class Arm {
  ghost var Value: (int, int)

  ghost var Repr: set<object>
  predicate Valid()
    reads this, Repr
  {
    this in Repr && null !in Repr &&
    {polar, azim} <= Repr &&
    polar != azim &&
    Value == (polar.val, azim.val)
  }

  var polar:Cell
  var azim:Cell

  constructor (polar_in:int, azim_in:int)
    modifies this
    ensures Valid() && fresh(Repr - {this})
    ensures Value == (polar_in, azim_in)
  {
    polar := new Cell(polar_in);
    azim := new Cell(azim_in);
    Repr := {this};
    Repr := Repr + {polar, azim};
    Value := (polar_in, azim_in);
  }

  method Mutate(polar_in:int, azim_in:int)
    requires Valid()
    modifies Repr
    ensures Valid() && fresh(Repr - old(Repr))
    ensures Value == (polar_in, azim_in)
  {
    polar.val, azim.val := polar_in, azim_in;
    Value := (polar_in, azim_in);
  }
}

class Bot {
  ghost var Repr: set<object>
  predicate {:opaque} Valid()
    reads this, Repr
    ensures Valid() ==> this in Repr && null !in Repr
  {
    this in Repr && null !in Repr &&
    pos in Repr && {left, right} <= Repr &&
    left != right &&
    pos.Repr <= Repr && left.Repr <= Repr && right.Repr <= Repr &&
    pos.Repr !! left.Repr !! right.Repr &&
    pos.Valid() && left.Valid() && right.Valid()
  }

  var pos:Point
  var left:Arm
  var right:Arm

  constructor ()
    modifies this
    ensures Valid() && fresh(Repr - {this})
  {
    pos := new Point(0, 0, 0);
    left := new Arm(0, 0);
    right := new Arm(0, 0);
    Repr := {this};
    Repr := Repr + pos.Repr + left.Repr + right.Repr;
    reveal_Valid();
  }

  predicate flying()
    requires (reveal_Valid(); Valid())
    reads Repr
  {
    pos.z.val > 0
  }
  
  predicate arms_up()
    requires (reveal_Valid(); Valid())
    reads Repr
  {
    left.polar.val == right.polar.val == 0
  }

  predicate robot_inv()
    requires (reveal_Valid(); Valid())
    reads Repr
  {
    flying() ==> arms_up()
  }

  method Fly()
    requires Valid()
    modifies Repr
    ensures Valid() && fresh(Repr - old(Repr))
    ensures robot_inv() && flying()
  {
    reveal_Valid();
    left.polar.val, right.polar.val := 0, 0;
    pos.z.val := 100;
    right.azim.val := 17;
    pos.Value := (pos.Value.0, pos.Value.1, 100);
    left.Value, right.Value := (0, left.Value.1), (0, 17);
    reveal_Valid();
  }
}

// This method tests that Fly operates independently on disjoint robots
method FlyRobots(b0:Bot, b1:Bot)
  requires b0 != null && b0.Valid()
  requires b1 != null && b1.Valid()
  requires b0 != b1 ==> b0.Repr !! b1.Repr
  modifies b0.Repr, b1.Repr
  ensures b0.Valid() && fresh(b0.Repr - old(b0.Repr))
  ensures b1.Valid() && fresh(b1.Repr - old(b1.Repr))
  ensures b0 != b1 ==> b0.Repr !! b1.Repr
  ensures  b0.robot_inv() && b1.robot_inv()
  ensures  b0.flying() && b1.flying()
{
  b0.Fly();
  b1.Fly();
}

// ----- robot armies ----------

// The union of .Repr for the robots in "bots"
function ArmyRepr(bots:seq<Bot>) : set<object>
  reads set b | b in bots 
{
  set b,o | b in bots && b != null && o in b.Repr :: o
}

// An army is a sequence of disjoint, valid robots
predicate ValidArmy(bots:seq<Bot>)
  reads set b | b in bots 
  reads ArmyRepr(bots)     
{
      (forall i :: 0 <= i < |bots| ==> bots[i] != null && bots[i].Valid())
  &&  (forall i,j :: 0 <= i < j < |bots| ==> bots[i].Repr !! bots[j].Repr)
}

method FlyRobotArmy(bots:seq<Bot>)
  requires ValidArmy(bots)
  modifies ArmyRepr(bots)
  ensures ValidArmy(bots) && fresh(ArmyRepr(bots) - old(ArmyRepr(bots)))
  ensures forall b :: b in bots ==> b.Valid() && b.robot_inv() && b.flying()
{
  if * {
    // fly recursively
    FlyRobotArmy_Recursively(bots);
  } else {
    // fly iteratively
    var n := 0;
    while n < |bots|
      invariant 0 <= n <= |bots|
      invariant ValidArmy(bots)
      invariant forall j :: 0 <= j < n ==> bots[j].Valid() && bots[j].robot_inv() && bots[j].flying()
      invariant forall i :: 0 <= i < |bots| ==> fresh(bots[i].Repr - old(bots[i].Repr))
    {
      FlyOne(bots, n);
      n := n + 1;
    }
  }
}

method FlyRobotArmy_Recursively(bots:seq<Bot>)
  requires ValidArmy(bots)
  modifies ArmyRepr(bots)
  ensures ValidArmy(bots)
  ensures forall i :: 0 <= i < |bots| ==> fresh(bots[i].Repr - old(bots[i].Repr))
  ensures forall b :: b in bots ==> b.robot_inv() && b.flying()
{
  if bots != [] {
    FlyOne(bots, 0);
    FlyRobotArmy_Recursively(bots[1..]);
  }
}

// This method is intended to be called in each loop iteration of FlyRobotArmy
method FlyOne(bots:seq<Bot>, n:int)
  requires 0 <= n < |bots|
  requires forall j :: 0 <= j < |bots| ==> bots[j] != null && bots[j].Valid()
  requires forall i,j :: 0 <= i < j < |bots| ==> bots[i].Repr !! bots[j].Repr
  requires forall j :: 0 <= j < n ==>  bots[j].robot_inv() && bots[j].flying()
  modifies bots[n].Repr
  ensures forall j :: 0 <= j < |bots| ==> bots[j].Valid()
  ensures fresh(bots[n].Repr - old(bots[n].Repr))
  ensures bots[n].robot_inv() && bots[n].flying()
  ensures forall j :: 0 <= j < |bots| && j != n ==> bots[j].Repr == old(bots[j].Repr)
  ensures forall j :: 0 <= j < n ==> bots[j].robot_inv() && bots[j].flying()
{
  bots[n].Fly();
}

// This method makes sure FlyRobotArmy is callable and callable again
method FormArmy(b0:Bot, b1:Bot, b2:Bot)
  requires null !in {b0, b1, b2}
  requires b0.Valid() && b1.Valid() && b2.Valid()
  requires b0.Repr !! b1.Repr !! b2.Repr
  modifies b0.Repr, b1.Repr, b2.Repr
  ensures b0.Valid() && b1.Valid() && b2.Valid()
  ensures b0.Repr !! b1.Repr !! b2.Repr
  ensures fresh(b0.Repr + b1.Repr + b2.Repr - old(b0.Repr + b1.Repr + b2.Repr))
{
  var army := [b0, b1, b2];
  ArmyRepr3(army);
  FlyRobotArmy(army);
  FlyRobotArmy(army);  // do it again
  ArmyRepr3(army);
}

lemma ArmyRepr3(army:seq<Bot>)
  requires null !in army && |army| == 3
  ensures ArmyRepr(army) == army[0].Repr + army[1].Repr + army[2].Repr
{
}

// ----- Make sure everything is callable ----------

method Main()
{
  var b0 := new Bot();
  var b1 := new Bot();
  FlyRobots(b0, b1);
  FlyRobots(b0, b1);
  FlyRobots(b1, b0);

  var b2 := new Bot();
  FormArmy(b0, b1, b2);
  FormArmy(b2, b0, b1);
}