-
Notifications
You must be signed in to change notification settings - Fork 1
/
BottomUpCheerios.v
471 lines (401 loc) · 12.5 KB
/
BottomUpCheerios.v
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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
Require Import List Arith PArith ZArith Ascii Omega Integers.
Import ListNotations.
Set Implicit Arguments.
Inductive step_result S A :=
| Error
| Success (a : A)
| More (s : S).
Arguments Error {_} {_}.
Arguments Success {_} {_} _.
Arguments More {_} {_} _.
Module dmachine.
Record t (E A : Type) : Type := Make {
state : Type;
init : state;
step : state -> E -> step_result state A
}.
Definition run {E S A} (step : S -> E -> step_result S A) : S -> list E -> option (A * list E) :=
fix go (s : S) (l : list E) {struct l} : option (A * list E) :=
match l with
| [] => None
| e :: l =>
match step s e with
| Error => None
| Success a => Some (a, l)
| More s => go s l
end
end.
End dmachine.
Module serializer.
Class t (E A : Type) : Type := Make {
serialize : A -> list E;
dmachine : dmachine.t E A;
spec : forall a l, dmachine.run (dmachine.step dmachine)
(dmachine.init dmachine)
(serialize a ++ l)
= Some (a, l)
}.
Section lemmas.
Variables (E A : Type).
Context {sA : t E A}.
Lemma spec' : forall a,
dmachine.run (dmachine.step dmachine)
(dmachine.init dmachine)
(serialize a)
= Some (a, []).
Proof.
intros.
rewrite <- app_nil_r with (l := serialize a) at 1.
now rewrite serializer.spec.
Qed.
End lemmas.
Module exports.
Definition serialize {E A t} := @serialize E A t.
End exports.
End serializer.
Import serializer.exports.
Definition bool_serialize (b : bool) := [b].
Definition bool_dmachine : dmachine.t bool bool :=
dmachine.Make tt (fun _ b => Success b).
Instance bool_serializer : serializer.t bool bool :=
serializer.Make bool_serialize bool_dmachine _.
Proof.
now destruct a; simpl; intros.
Defined.
Fixpoint positive_serialize (p : positive) : list bool :=
match p with
| xI p => serialize true ++ serialize true ++ positive_serialize p
| xO p => serialize true ++ serialize false ++ positive_serialize p
| xH => serialize false
end.
Module positive_dmachine.
Inductive state :=
| Start (k : positive -> positive)
| OneMoreElt (k : positive -> positive).
Definition step (s : state) (b : bool) : step_result _ _ :=
match s with
| Start k => if b then More (OneMoreElt k) else Success (k xH)
| OneMoreElt k => More (Start (fun p => k ((if b then xI else xO) p)))
end.
Definition init := (Start (fun x => x)).
Definition m := dmachine.Make init step .
End positive_dmachine.
Lemma positive_run_k :
forall p k l,
dmachine.run positive_dmachine.step
(positive_dmachine.Start k)
(positive_serialize p ++ l)
= Some (k p, l).
Proof.
induction p; simpl; intros.
- apply IHp.
- apply IHp.
- reflexivity.
Qed.
Lemma positive_run : forall p l,
dmachine.run positive_dmachine.step (positive_dmachine.Start (fun x => x))
(positive_serialize p ++ l) = Some (p, l).
Proof.
intros.
apply positive_run_k.
Qed.
Instance positive_serializer : serializer.t bool positive :=
serializer.Make positive_serialize positive_dmachine.m positive_run.
Section convert.
Variable E A B : Type.
Context {sA : serializer.t E A}.
Variable A_to_B : A -> B.
Variable B_to_A : B -> A.
Hypothesis AB_inv : forall b, A_to_B (B_to_A b) = b.
Notation machine s := (@serializer.dmachine _ _ s).
Notation state m := (dmachine.state m).
Notation step m := (dmachine.step m).
Notation init m := (dmachine.init m).
Definition convert_serialize (b : B) : list E :=
serialize (B_to_A b).
Definition convert_step (s : state (machine sA)) (e : E) : step_result (state (machine sA)) B :=
match step (machine sA) s e with
| Error => Error
| Success a => Success (A_to_B a)
| More s => More s
end.
Definition convert_dmachine : dmachine.t E B :=
dmachine.Make (init (machine sA)) convert_step.
Lemma convert_run :
forall l s,
dmachine.run convert_step s l =
match dmachine.run (step (machine sA)) s l with
| None => None
| Some (a, l) => Some (A_to_B a, l)
end.
Proof.
unfold convert_step.
induction l; simpl; intros; auto.
destruct (step _); auto.
Qed.
Instance convert_serializer : serializer.t E B :=
serializer.Make convert_serialize convert_dmachine _.
Proof.
intros b l.
simpl.
unfold convert_serialize.
now rewrite convert_run, serializer.spec, AB_inv.
Defined.
End convert.
Definition N_serialize (n : N) : list bool :=
match n with
| N0 => serialize false
| Npos p => serialize true ++ serialize p
end.
Module N_dmachine.
Inductive state : Type :=
| Start
| Pos : positive_dmachine.state -> state.
Definition step (s : state) (b : bool) : step_result state N :=
match s with
| Start =>
if b
then More (Pos positive_dmachine.init)
else Success N0
| Pos s =>
match positive_dmachine.step s b with
| Error => Error
| Success p => Success (Npos p)
| More s => More (Pos s)
end
end.
Definition init := Start.
Definition m := dmachine.Make init step.
End N_dmachine.
Lemma N_run_pos :
forall l s,
dmachine.run N_dmachine.step (N_dmachine.Pos s) l =
match dmachine.run positive_dmachine.step s l with
| None => None
| Some (p, l) => Some (Npos p, l)
end.
Proof.
induction l; simpl; intros.
- auto.
- destruct positive_dmachine.step; auto.
Qed.
Instance N_serializer : serializer.t bool N :=
serializer.Make N_serialize N_dmachine.m _.
intros n l.
destruct n; simpl.
- auto.
- now rewrite N_run_pos, (serializer.spec(t := positive_serializer)).
Defined.
Instance nat_serializer : serializer.t bool nat :=
convert_serializer N.to_nat N.of_nat Nnat.Nat2N.id.
Section dmachine_combinators.
Variable A B : Type.
Context {sA : serializer.t bool A}.
Context {sB : serializer.t bool B}.
Definition pair_serialize (p : A * B) : list bool :=
let (a, b) := p
in serialize a ++ serialize b.
Notation machine s := (@serializer.dmachine _ _ s).
Notation state m := (dmachine.state m).
Notation step m := (dmachine.step m).
Notation init m := (dmachine.init m).
Inductive pair_state : Type :=
| PS_A : state (machine sA) -> pair_state
| PS_B : A -> state (machine sB) -> pair_state.
Definition pair_init : pair_state := PS_A (init (machine sA)).
Definition pair_step (s : pair_state) (b : bool) : step_result pair_state (A * B) :=
match s with
| PS_A sa =>
match step (machine sA) sa b with
| Error => Error
| Success a => More (PS_B a (init (machine sB)))
| More sa => More (PS_A sa)
end
| PS_B a sb =>
match step (machine sB) sb b with
| Error => Error
| Success b => Success (a, b)
| More sb => More (PS_B a sb)
end
end.
Definition pair_dmachine : dmachine.t bool (A * B) :=
dmachine.Make pair_init pair_step.
Lemma run_pair_B :
forall l a sb,
dmachine.run pair_step (PS_B a sb) l =
match dmachine.run (step (machine sB)) sb l with
| None => None
| Some (b, l) => Some ((a, b), l)
end.
Proof.
induction l; simpl; intros; auto.
destruct (step _); auto.
Qed.
Lemma run_pair :
forall l sa,
dmachine.run pair_step (PS_A sa) l =
match dmachine.run (step (machine sA)) sa l with
| None => None
| Some (a, l) =>
match dmachine.run (step (machine sB)) (init (machine sB)) l with
| None => None
| Some (b, l) => Some ((a, b), l)
end
end.
Proof.
induction l; simpl; intros; auto.
destruct (step _); auto using run_pair_B.
Qed.
Instance pair_serializer : serializer.t bool (A * B) :=
serializer.Make pair_serialize pair_dmachine _.
destruct a as [a b].
intros.
simpl.
unfold pair_init.
now rewrite run_pair, app_assoc_reverse, !serializer.spec.
Defined.
Fixpoint list_serialize_rec (l : list A) : list bool :=
match l with
| [] => []
| a :: l => serialize a ++ list_serialize_rec l
end.
Definition list_serialize (l : list A) : list bool :=
serialize (length l) ++ list_serialize_rec l.
Inductive list_state :=
| LS_length (s : state (machine nat_serializer))
| LS_elts (n : nat) (l : list A) (s : state (machine sA)).
Definition list_init := LS_length (init (machine nat_serializer)).
Definition list_step (s : list_state) (b : bool) : step_result list_state (list A) :=
match s with
| LS_length s =>
match step (machine nat_serializer) s b with
| Error => Error
| Success n =>
match n with
| 0 => Success []
| S n => More (LS_elts n [] (init (machine sA)))
end
| More s => More (LS_length s)
end
| LS_elts n l s =>
match step (machine sA) s b with
| Error => Error
| Success a =>
match n with
| 0 => Success (List.rev (a :: l))
| S n => More (LS_elts n (a :: l) (init (machine sA)))
end
| More s => More (LS_elts n l s)
end
end.
Definition list_dmachine :=
dmachine.Make list_init list_step.
Lemma list_step_length :
forall l s,
dmachine.run list_step (LS_length s) l =
match dmachine.run (step (machine nat_serializer)) s l with
| None => None
| Some (n, l) =>
match n with
| 0 => Some ([], l)
| S n =>
dmachine.run list_step (LS_elts n [] (init (machine sA))) l
end
end.
Proof.
induction l; simpl; intros; auto.
destruct convert_step; auto.
destruct a0; auto.
Qed.
Lemma list_step_elts :
forall l n acc s,
dmachine.run list_step (LS_elts n acc s) l =
match dmachine.run (step (machine sA)) s l with
| None => None
| Some (a, l) =>
match n with
| 0 => Some (List.rev (a :: acc), l)
| S n => dmachine.run list_step (LS_elts n (a :: acc) (init (machine sA))) l
end
end.
Proof.
induction l; simpl; intros; auto.
destruct (step _); eauto.
destruct n; auto.
Qed.
Lemma list_serialize_rec_spec :
forall l bin n acc,
S n = length l ->
dmachine.run (step list_dmachine) (LS_elts n acc (init (machine sA)))
(list_serialize_rec l ++ bin) =
Some (rev_append acc l, bin)%list.
Proof.
induction l; simpl; intros.
- congruence.
- rewrite list_step_elts, app_assoc_reverse, serializer.spec.
destruct n.
+ destruct l.
* now rewrite rev_append_rev.
* simpl in *. congruence.
+ now rewrite IHl by congruence.
Qed.
Instance list_serializer : serializer.t bool (list A) :=
serializer.Make list_serialize list_dmachine _.
Proof.
intros l bin.
cbn [init list_dmachine].
unfold list_init, list_serialize.
rewrite list_step_length, app_assoc_reverse, serializer.spec.
destruct l; auto.
cbn [length].
now rewrite list_serialize_rec_spec.
Defined.
End dmachine_combinators.
Section pair_elements.
Variable E A : Type.
Context {sA : serializer.t (E * E) A}.
Notation m := (serializer.dmachine(t:=sA)).
Definition concat_pairs l :=
concat (map (fun (p : E * E) => let (x, y) := p in [x; y]) l).
Definition pair_element_serialize (a : A) : list E :=
concat_pairs (serializer.serialize a).
Inductive pair_element_state : Type :=
| PE_even (s : dmachine.state m)
| PE_odd (e : E) (s : dmachine.state m).
Definition pair_element_init := PE_even (dmachine.init m).
Definition pair_element_step (s : pair_element_state) (e : E)
: step_result pair_element_state A :=
match s with
| PE_even s => More (PE_odd e s)
| PE_odd e1 s =>
match dmachine.step m s (e1, e) with
| Error => Error
| Success a => Success a
| More s => More (PE_even s)
end
end.
Definition pair_element_dmachine :=
dmachine.Make pair_element_init pair_element_step.
Lemma pair_element_step_even :
forall l s bin,
dmachine.run pair_element_step (PE_even s) (concat_pairs l ++ bin) =
match dmachine.run (dmachine.step m) s l with
| None => dmachine.run pair_element_step (PE_even s) (concat_pairs l ++ bin)
| Some (a, l) =>
Some (a, concat_pairs l ++ bin)%list
end.
Proof.
induction l; simpl; intros.
- auto.
- destruct a as [e1 e2]. simpl.
destruct dmachine.step; auto.
Qed.
Instance pair_element_serializer : serializer.t E A :=
serializer.Make pair_element_serialize pair_element_dmachine _.
Proof.
intros.
simpl.
unfold pair_element_serialize, pair_element_init.
now rewrite pair_element_step_even, serializer.spec'.
Defined.
End pair_elements.