-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathFiatHelpers.v
350 lines (313 loc) · 9.98 KB
/
FiatHelpers.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
Require Export
Fiat.ADT
Fiat.ADTNotation
Fiat.ADTRefinement
Fiat.ADTRefinement.BuildADTRefinements
Fiat.Computation.Core.
Definition _blocked_ret : { x: forall A, A -> Comp A | x = ret }.
Proof. exists Return; reflexivity. Qed.
Definition blocked_ret {A} := (proj1_sig _blocked_ret A).
Arguments blocked_ret [A] _ _.
Notation "x <<- a ; y" := (Bind (blocked_ret a%comp) (fun x => y%comp))
(at level 81, a at level 200, y at level 81).
Definition blocked_let {A B} (a: A) (f: A -> B) := let x := a in f x.
Arguments blocked_let : simpl never.
Notation "'blet' x := a 'in' y" :=
(blocked_let a (fun x => y))
(at level 81, a at level 200, y at level 81,
format "'[v' 'blet' x := a 'in' '/' y ']'").
Add Parametric Morphism {A B} : (@blocked_let A B)
with signature (eq ==> pointwise_relation _ eq ==> eq)
as blet_morphism.
Proof.
unfold pointwise_relation; simpl; intros * H.
unfold blocked_let; rewrite H; reflexivity.
Qed.
Lemma blet_ret_commute {A B} :
forall (a: A) (f: A -> B),
blocked_let a (fun x => ret (f x)) = ret (blocked_let a f).
Proof.
unfold blocked_let; reflexivity.
Qed.
Global Opaque blocked_let.
Lemma blocked_ret_is_ret :
blocked_ret = ret.
Proof. exact (proj2_sig _blocked_ret). Qed.
Ltac unblock :=
rewrite blocked_ret_is_ret at 1.
Lemma bound_blocked_ret_is_bound_ret {A B} (a: A) (f: A -> Comp B) :
Bind (blocked_ret a) f = Bind (ret a) f.
Proof. rewrite blocked_ret_is_ret; reflexivity. Qed.
Lemma unfold_blocked_ret X Y (f : X -> Comp Y) x y
: refine (f x) y
-> refine (Bind (blocked_ret x) f) y.
Proof. rewrite blocked_ret_is_ret; apply refine_bind_unit_helper. Qed.
Lemma blocked_ret_to_let {A B} :
forall aa (x y : A -> Comp B),
refine (x aa) (y aa) ->
refine (a <- blocked_ret aa; x a) (blet a := aa in y a).
Proof.
intros; apply unfold_blocked_ret; simpl; assumption.
Qed.
Ltac add_let_in_head term new_head expr :=
let rec aux head_and_args restore_args_fn :=
lazymatch head_and_args with
| ?term ?arg => aux term (fun term' => restore_args_fn (term' arg))
| ?head => constr:(blet x := expr in restore_args_fn (new_head x))
end in
let tt := type of term in
let term' := aux term (fun y: tt => y) in
let reduced := (eval cbv beta in term') in
constr:(reduced).
(** Example:
Axiom f : nat -> nat -> nat.
Axiom g : nat -> nat -> nat -> nat.
let tt := add_let_in_head (f 1 2) (g) (5) in
pose tt. (* blet x := 5 in g x 1 2 *) *)
Definition NoSubst (P: Prop) := P.
Ltac args term :=
match term with
| ?term ?a1 ?a2 => let all_but_last := args (term a1) in
constr:((all_but_last, a2))
| _ ?a => constr:(a)
| _ => constr:(tt)
end.
Ltac refine_blocked_ret_cleanup hd' const :=
cbv beta;
unfold hd' in *; clear hd';
let bvar := fresh "bvar" in
let bvar_eqn := fresh "bvar_eqn" in
set const as bvar;
assert (NoSubst (bvar = const)) as bvar_eqn by reflexivity;
clearbody bvar;
apply blocked_ret_to_let.
Tactic Notation "refine" "blocked" "ret" :=
lazymatch goal with
| [ |- refine (Bind (blocked_ret ?const) _) ?comp] =>
let old_evar := head comp in
let old_evar_type := type of old_evar in
let const_type := type of const in
let new_evar := fresh in
evar (new_evar: const_type -> old_evar_type);
let refined := add_let_in_head comp new_evar const in
first [ unify comp refined |
let aa := args comp in
fail 1 "Unification of" comp "and" refined
"failed. Make sure that" const
"can be written as a function of" aa ];
refine_blocked_ret_cleanup new_evar const
end.
Ltac expose_rets_hidden_under_blets :=
hone representation using eq;
subst; simpl; try simplify with monad laws;
repeat setoid_rewrite blet_ret_commute;
[ refine pick eq;
try simplify with monad laws;
try rewrite <- surjective_pairing;
try finish honing.. | ].
Ltac finish_SharpeningADT_WithoutDelegation ::=
eapply FullySharpened_Finish;
[ FullySharpenEachMethod
(@Vector.nil ADTSig)
(@Vector.nil Type)
(ilist.inil (B := fun nadt => ADT (delegateeSig nadt)));
try simplify with monad laws; simpl; try refine pick eq; try simplify with monad laws;
try first [ simpl]; try rewrite <- surjective_pairing;
(* Guard setoid rewriting with [refine_if_If] to only occur when there's
actually an [if] statement in the goal. This prevents [setoid_rewrite] from
uselessly descending into folded definitions. *)
repeat match goal with
| [ |- context [ if _ then _ else _ ] ] =>
setoid_rewrite refine_if_If at 1
end;
repeat first [
higher_order_reflexivity
| simplify with monad laws
| Implement_If_Then_Else
| Implement_If_Opt_Then_Else ]
| extract_delegate_free_impl
| simpl; higher_order_reflexivityT ].
(* ========================= *)
Require Import Fiat.Computation.Refinements.Tactics.
Lemma refine_smaller (A B: Type) (C: A) (f g: A -> Comp B):
(forall x, refineEquiv (f x) (g x))
-> refineEquiv (x <<- C; f x) (x <<- C; g x).
Proof.
intros.
assert (refineEquiv (f C) (g C)) by apply H.
rewrite blocked_ret_is_ret in *.
erewrite refineEquiv_bind_unit.
erewrite refineEquiv_bind_unit.
apply H.
Qed.
Lemma refine_trivial_bind {A B}:
forall (a: A) (b: Comp B),
refineEquiv (x <<- a; b) (b).
Proof.
intros.
rewrite blocked_ret_is_ret in *.
split.
- repeat intro.
computes_to_inv.
econstructor.
split.
+ econstructor.
+ assumption.
- repeat intro.
inversion H.
inversion H0.
assumption.
Qed.
Lemma refine_trivial_bind2 {A B}:
forall (a: A) (f: A -> Comp B) (g: Comp B),
(forall x: A, (f x) = g) -> refineEquiv (x <<- a; f x) (g).
Proof.
intros.
rewrite blocked_ret_is_ret in *.
split; repeat intro; computes_to_inv; repeat (econstructor; eauto).
- unfold Ensembles.In.
rewrite H. assumption.
- rewrite H in H0'. assumption.
Qed.
Lemma refine_substitute {A B}:
forall (a: A) (f: A -> Comp B),
refineEquiv (x <<- a; f x) (f a).
Proof.
intros.
rewrite blocked_ret_is_ret in *.
split.
- repeat intro.
computes_to_inv.
econstructor.
split.
+ econstructor.
+ assumption.
- repeat intro.
inversion H.
inversion H0.
inversion H1.
eauto.
Qed.
Lemma refine_substitute2:
forall A B, forall (a: A) (f: A -> B),
refineEquiv (ret (f a)) (x <<- a; ret (f x)) .
Proof.
intros.
rewrite refine_substitute.
higher_order_reflexivity.
Qed.
Lemma blet_equal_blocked_ret {A B}:
forall (a: A) (f: A -> Comp B),
refineEquiv (x <<- a; f x) (blet x := a in f x).
Proof.
intros.
rewrite blocked_ret_is_ret in *.
split.
- repeat intro.
computes_to_inv.
econstructor.
split.
+ econstructor.
+ assumption.
- repeat intro.
inversion H.
inversion H0.
inversion H1.
eauto.
Qed.
Lemma pick_change_condition:
forall (T D: Type) (com: T -> Comp D) (P Q: T -> Prop) ,
(forall X : T, P X -> Q X) -> refine (x <- {X : T | Q X}; com(x)) (x <- {X: T | P X}; com(x)).
Proof.
intros.
repeat intro.
computes_to_inv.
exists v0.
split.
- unfold Ensembles.In.
apply H in H0.
eauto.
- unfold Ensembles.In.
eauto.
Qed.
Theorem refine_change_type A B:
forall (a : Comp A) (f: A -> Comp B) (cast: A -> B) (cast_back: B -> A),
(forall x, refine (f x) (f (cast_back (cast x)))) ->
refine (x <- a; f x)
(x <- (y <- a; ret (cast y));
f (cast_back x)).
Proof.
intros.
rewrite <- refine_bind_bind'.
unfold refine.
Transparent computes_to.
unfold computes_to.
Transparent Bind.
unfold Bind.
intros. intros.
inversion H0; subst.
exists x.
split.
- apply H1.
- inversion H1; subst.
unfold Ensembles.In in H3.
inversion H3; subst; clear H3.
inversion H4; subst; clear H4.
rewrite H.
unfold Ensembles.In. inversion H3; subst.
assumption.
Qed.
Lemma decompose_if {B C}:
forall (a: bool) (b: B) (c: B) (com: B -> Comp C),
refineEquiv (y <<- if a then b else c; com(y)) (x <<- a; y <<- b; z <<- c; w <<- if x then y else z; com(w)) .
Proof.
intros; split.
- repeat intro. computes_to_inv. rewrite blocked_ret_is_ret in *.
repeat (econstructor; try eauto).
unfold Ensembles.In.
inversion H. inversion H'. inversion H''. inversion H'''.
reflexivity.
- repeat intro. computes_to_inv. rewrite blocked_ret_is_ret in *.
repeat (econstructor; try eauto).
Qed.
Lemma decompose_1 {A B C} :
forall (a : A) (op: A -> B) (com: B -> Comp C),
refineEquiv (x <<- op a; com(x)) (y <<- a; x <<- op y; com x).
Proof.
intros; split.
- repeat intro. computes_to_inv. rewrite blocked_ret_is_ret in *.
repeat (econstructor; try eauto).
unfold Ensembles.In.
inversion H. inversion H'.
reflexivity.
- repeat intro. computes_to_inv. rewrite blocked_ret_is_ret in *.
repeat (econstructor; try eauto).
Qed.
Lemma decompose_2 {A B C D} :
forall (a : A) (b: B) (op: A -> B -> C) (com: C -> Comp D),
refineEquiv (x <<- op a b; com(x)) (y <<- a; z <<- b; x <<- op y z; com x).
Proof.
intros; split.
- repeat intro. computes_to_inv. rewrite blocked_ret_is_ret in *.
repeat (econstructor; try eauto).
unfold Ensembles.In.
inversion H. inversion H'.
inversion H''.
reflexivity.
- repeat intro. computes_to_inv. rewrite blocked_ret_is_ret in *.
repeat (econstructor; try eauto).
Qed.
Lemma decompose_3 {A B C D E} :
forall (a : A) (b: B) (c: C) (op: A -> B -> C -> D) (com: D -> Comp E),
refineEquiv (x <<- op a b c; com(x)) (x0 <<- a; x1 <<- b; x2 <<- c; x <<- op x0 x1 x2; com x).
Proof.
intros; split.
- repeat intro. computes_to_inv. rewrite blocked_ret_is_ret in *.
repeat (econstructor; try eauto).
unfold Ensembles.In.
inversion H. inversion H'. inversion H''.
inversion H'''.
reflexivity.
- repeat intro. computes_to_inv. rewrite blocked_ret_is_ret in *.
repeat (econstructor; try eauto).
Qed.