You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

451 lines
15 KiB

From stdpp Require Import gmap base relations.
From iris Require Import prelude.
From semantics.ts.systemf_mu_state Require Import lang notation.
(* TODO: everywhere replace the metavar σ for heaps with h *)
(** ** Deterministic reduction *)
Record det_step (e1 : expr) (e2 : expr) := {
det_step_safe h : reducible e1 h;
det_step_det e2' h h' :
contextual_step (e1, h) (e2', h') e2' = e2 h' = h
}.
Record det_base_step (e1 e2 : expr) := {
det_base_step_safe h : base_reducible e1 h;
det_base_step_det e2' h h' :
base_step (e1, h) (e2', h') e2' = e2 h' = h
}.
Lemma det_base_step_det_step e1 e2 : det_base_step e1 e2 det_step e1 e2.
Proof.
intros [Hp1 Hp2]. split.
- intros h. destruct (Hp1 h) as (e2' & h' & ?).
eexists e2', h'. by apply base_contextual_step.
- intros e2' h h' ?%base_reducible_contextual_step; [ | done]. by eapply Hp2.
Qed.
(** *** Pure execution lemmas *)
Local Ltac inv_step :=
repeat match goal with
| H : to_val _ = Some _ |- _ => apply of_to_val in H
| H : base_step (?e, ?σ) (?e2, ?σ2) |- _ =>
try (is_var e; fail 1); (* inversion yields many goals if [e] is a variable
and should thus better be avoided. *)
inversion H; subst; clear H
end.
Local Ltac solve_exec_safe := intros; subst; eexists _, _; econstructor; eauto.
Local Ltac solve_exec_detdet := simpl; intros; inv_step; try done.
Local Ltac solve_det_exec :=
subst; intros; apply det_base_step_det_step;
constructor; [solve_exec_safe | solve_exec_detdet].
Lemma det_step_beta x e e2 :
is_val e2
det_step (App (@Lam x e) e2) (subst' x e2 e).
Proof. solve_det_exec. Qed.
Lemma det_step_tbeta e :
det_step ((Λ, e) <>) e.
Proof. solve_det_exec. Qed.
Lemma det_step_unpack e1 e2 x :
is_val e1
det_step (unpack (pack e1) as x in e2) (subst' x e1 e2).
Proof. solve_det_exec. Qed.
Lemma det_step_unop op e v v' :
to_val e = Some v
un_op_eval op v = Some v'
det_step (UnOp op e) v'.
Proof. solve_det_exec. by simplify_eq. Qed.
Lemma det_step_binop op e1 v1 e2 v2 v' :
to_val e1 = Some v1
to_val e2 = Some v2
bin_op_eval op v1 v2 = Some v'
det_step (BinOp op e1 e2) v'.
Proof. solve_det_exec. by simplify_eq. Qed.
Lemma det_step_if_true e1 e2 :
det_step (if: #true then e1 else e2) e1.
Proof. solve_det_exec. Qed.
Lemma det_step_if_false e1 e2 :
det_step (if: #false then e1 else e2) e2.
Proof. solve_det_exec. Qed.
Lemma det_step_fst e1 e2 :
is_val e1
is_val e2
det_step (Fst (e1, e2)) e1.
Proof. solve_det_exec. Qed.
Lemma det_step_snd e1 e2 :
is_val e1
is_val e2
det_step (Snd (e1, e2)) e2.
Proof. solve_det_exec. Qed.
Lemma det_step_casel e e1 e2 :
is_val e
det_step (Case (InjL e) e1 e2) (e1 e).
Proof. solve_det_exec. Qed.
Lemma det_step_caser e e1 e2 :
is_val e
det_step (Case (InjR e) e1 e2) (e2 e).
Proof. solve_det_exec. Qed.
Lemma det_step_unroll e :
is_val e
det_step (unroll (roll e)) e.
Proof. solve_det_exec. Qed.
(** ** n-step reduction *)
(** Reduce in n steps to an irreducible expression.
(this is ^n from the lecture notes)
*)
Definition red_nsteps (n : nat) e h e' h' := nsteps contextual_step n (e, h) (e', h') irreducible e' h'.
Lemma det_step_red e e' e'' h h'' n :
det_step e e'
red_nsteps n e h e'' h''
1 n red_nsteps (n - 1) e' h e'' h''.
Proof.
intros [Hprog Hstep] Hred.
specialize (Hprog h).
destruct Hred as [Hred Hirred].
destruct n as [ | n].
{ inversion Hred; subst.
exfalso; eapply not_reducible; done.
}
inversion Hred as [ | ??[e1 h1]? Hstep0]; subst. simpl.
apply Hstep in Hstep0 as [<- <-].
split; first lia.
replace (n - 0) with n by lia. done.
Qed.
Lemma contextual_step_red_nsteps n e e' e'' h h' h'':
contextual_step (e, h) (e', h')
red_nsteps n e' h' e'' h''
red_nsteps (S n) e h e'' h''.
Proof.
intros Hstep [Hsteps Hirred].
split; last done.
by econstructor.
Qed.
Lemma nsteps_val_inv n v e' h h' :
red_nsteps n (of_val v) h e' h' n = 0 e' = of_val v h' = h.
Proof.
intros [Hred Hirred]; cbn in *.
destruct n as [ | n].
- inversion Hred; subst. done.
- inversion Hred as [ | ??[e1 h1]]; subst. exfalso. eapply val_irreducible; last done.
rewrite to_of_val. eauto.
Qed.
Lemma nsteps_val_inv' n v e e' h h' :
to_val e = Some v
red_nsteps n e h e' h' n = 0 e' = of_val v h' = h.
Proof. intros Ht. rewrite -(of_to_val _ _ Ht). apply nsteps_val_inv. Qed.
Lemma red_nsteps_fill K k e e' h h' :
red_nsteps k (fill K e) h e' h'
j e'' h'', j k
red_nsteps j e h e'' h''
red_nsteps (k - j) (fill K e'') h'' e' h'.
Proof.
intros [Hsteps Hirred].
induction k as [ | k IH] in e, e', h, h', Hsteps, Hirred |-*.
- inversion Hsteps; subst.
exists 0, e, h'. split_and!; [done | split | ].
+ constructor.
+ by eapply irreducible_fill.
+ done.
- inversion Hsteps as [ | n [e1 h1] [e2 h2] [e3 h3] Hstep Hsteps' Heq1 Heq2 Heq3]. subst.
destruct (contextual_ectx_step_case _ _ _ _ _ Hstep) as [(e'' & -> & Hstep') | Hv].
+ apply IH in Hsteps' as (j & e3 & h3 & ? & Hsteps' & Hsteps''); last done.
eexists (S j), _, _. split_and!; [lia | | done ].
eapply contextual_step_red_nsteps; done.
+ exists 0, e, h. split_and!; [ lia | | ].
* split; [constructor | ].
apply val_irreducible. by apply is_val_spec.
* simpl. by eapply contextual_step_red_nsteps.
Qed.
(** * Heap execution lemmas *)
Lemma new_step_inv v e e' σ σ' :
to_val e = Some v
base_step (New e, σ) (e', σ')
l, e' = (Lit $ LitLoc l) σ' = init_heap l 1 v σ σ !! l = None.
Proof.
intros <-%of_to_val.
inversion 1; subst.
rewrite to_of_val in H5. injection H5 as [= ->].
eauto.
Qed.
Lemma new_nsteps_inv n v e e' σ σ' :
to_val e = Some v
red_nsteps n (New e) σ e' σ'
(n = 1 base_step (New e, σ) (e', σ')).
Proof.
intros <-%of_to_val [Hsteps Hirred%not_reducible].
inversion Hsteps; subst.
- exfalso; apply Hirred. eapply base_reducible_reducible. eexists _, _. eapply new_fresh.
- destruct y.
eapply base_reducible_contextual_step in H.
2: { eexists _, _. apply new_fresh. }
inversion H0; subst.
{ eauto. }
eapply new_step_inv in H; last apply to_of_val.
destruct H as (l & -> & -> & ?).
destruct y. apply val_stuck in H1. done.
Qed.
Lemma load_step_inv e v σ e' σ' :
to_val e = Some v
base_step (Load e, σ) (e', σ')
(l : loc) v', v = #l σ !! l = Some v' e' = of_val v' σ' = σ.
Proof.
intros <-%of_to_val.
inversion 1; subst.
symmetry in H0. apply of_val_lit in H0 as ->.
eauto 8.
Qed.
Definition sub_redexes_are_values (e : expr) :=
K e', e = fill K e' to_val e' = None K = empty_ectx.
Lemma contextual_base_reducible e σ :
reducible e σ sub_redexes_are_values e base_reducible e σ.
Proof.
intros (e' & σ' & Hstep) ?. inversion Hstep; subst.
assert (K = empty_ectx) as -> by eauto 10 using val_base_stuck.
rewrite fill_empty /base_reducible; eauto.
Qed.
Ltac solve_sub_redexes_are_values :=
let K := fresh "K" in
let e' := fresh "e'" in
let Heq := fresh "Heq" in
let Hv := fresh "Hv" in
let IH := fresh "IH" in
let Ki := fresh "Ki" in
let Ki' := fresh "Ki'" in
intros K e' Heq Hv;
destruct K as [ | Ki K]; first (done);
exfalso; induction K as [ | Ki' K IH] in e', Ki, Hv, Heq |-*;
[destruct Ki; inversion Heq; subst; simplify_val; cbn in *; congruence
| eapply IH; first (by rewrite Heq);
apply fill_item_no_val; done].
Lemma load_nsteps_inv n v e e' σ σ' :
to_val e = Some v
red_nsteps n (Load e) σ e' σ'
(n = 0 σ' = σ e' = Load e ¬ reducible (Load e) σ)
(n = 1 base_step (Load e, σ) (e', σ')).
Proof.
intros <-%of_to_val [Hsteps Hirred%not_reducible].
inversion Hsteps; subst.
- by left.
- right. destruct y.
eapply base_reducible_contextual_step in H.
2: { eapply contextual_base_reducible; [eexists _, _; done | solve_sub_redexes_are_values]. }
inversion H0; subst.
{ eauto. }
eapply load_step_inv in H as (l & ? & -> & ? & -> & ->); last apply to_of_val.
destruct y. apply val_stuck in H1. simplify_val. done.
Qed.
(** useful derived lemma when we know upfront that l satisfies some invariant [P] *)
Lemma load_nsteps_inv' n l e e' σ σ' (P : val Prop) :
to_val e = Some (LitV $ LitLoc l)
( v', σ !! l = Some v' P v')
red_nsteps n (Load e) σ e' σ'
v' : val, n = 1 e' = v' σ' = σ σ !! l = Some v' P v'.
Proof.
intros <-%of_to_val (v' & Hlook & HP) Hred.
eapply load_nsteps_inv in Hred; last done.
destruct Hred as [(-> & -> & -> & Hnred) | (-> & Hstep)].
- exfalso; eapply Hnred. eexists v', _.
eapply base_contextual_step. econstructor. done.
- exists v'. split; first done.
eapply load_step_inv in Hstep; last done.
destruct Hstep as (l' & v'' & [= <-] & ? & -> & ->).
split; first by simplify_option_eq.
split; last done. econstructor; done.
Qed.
Lemma store_step_inv v1 v2 σ e' σ' :
base_step (Store (of_val v1) (of_val v2), σ) (e', σ')
(l : loc) v', v1 = #l σ !! l = Some v' e' = Lit LitUnit σ' = <[l := v2]> σ.
Proof.
inversion 1; subst.
symmetry in H0. apply of_val_lit in H0 as ->.
simplify_val. simplify_option_eq.
eauto 8.
Qed.
Lemma store_nsteps_inv n v1 v2 e' σ σ' :
red_nsteps n (Store (of_val v1) (of_val v2)) σ e' σ'
(n = 0 σ' = σ e' = Store (of_val v1) (of_val v2) ¬ reducible (Store (of_val v1) (of_val v2)) σ)
(n = 1 base_step (Store (of_val v1) (of_val v2), σ) (e', σ')).
Proof.
intros [Hsteps Hirred%not_reducible].
inversion Hsteps; subst.
- by left.
- right. destruct y.
eapply base_reducible_contextual_step in H.
2: { eapply contextual_base_reducible; [eexists _, _; done | solve_sub_redexes_are_values]. }
inversion H0; subst.
{ eauto. }
apply store_step_inv in H as (l & ? & -> & ? & -> & ->).
destruct y. apply val_stuck in H1. simplify_val. done.
Qed.
Lemma store_nsteps_inv' n e1 e2 v0 v l e' σ σ' :
to_val e1 = Some (LitV $ LitLoc l)
to_val e2 = Some v
σ !! l = Some v0
red_nsteps n (Store e1 e2) σ e' σ'
n = 1 e' = Lit $ LitUnit σ' = <[l := v ]> σ.
Proof.
intros <-%of_to_val <-%of_to_val Hlook Hred%store_nsteps_inv.
destruct Hred as [(-> & -> & -> & Hnred) | (-> & Hb)].
- exfalso; eapply Hnred.
eexists #(), _.
eapply base_contextual_step. econstructor; [done | apply to_of_val ].
- eapply store_step_inv in Hb. destruct Hb as (l' & v' & [= <-] & Hlook' & -> & ->).
simplify_option_eq. done.
Qed.
(** Additionally useful stepping lemmas *)
Lemma app_step_r (e1 e2 e2': expr) h h' :
contextual_step (e2, h) (e2', h') contextual_step (e1 e2, h) (e1 e2', h').
Proof. by apply (fill_contextual_step [AppRCtx _]). Qed.
Lemma app_step_l (e1 e1' e2: expr) h h' :
contextual_step (e1, h) (e1', h') is_val e2 contextual_step (e1 e2, h) (e1' e2, h').
Proof.
intros ? (v & Hv)%is_val_spec.
rewrite <-(of_to_val _ _ Hv).
by apply (fill_contextual_step [AppLCtx _]).
Qed.
Lemma app_step_beta (x: string) (e e': expr) h :
is_val e' is_closed [x] e contextual_step ((λ: x, e)%E e', h) (lang.subst x e' e, h).
Proof.
intros Hval Hclosed. eapply base_contextual_step, BetaS; eauto.
Qed.
Lemma unroll_roll_step (e: expr) h :
is_val e contextual_step ((unroll (roll e))%E, h) (e, h).
Proof.
intros ?; by eapply base_contextual_step, UnrollS.
Qed.
Lemma fill_reducible K e h :
reducible e h reducible (fill K e) h.
Proof.
intros (e' & h' & Hstep).
exists (fill K e'), h'. eapply fill_contextual_step. done.
Qed.
Lemma reducible_contextual_step_case K e e' h1 h2 :
contextual_step (fill K e, h1) (e', h2)
reducible e h1
e'', e' = fill K e'' contextual_step (e, h1) (e'', h2).
Proof.
intros [ | Hval]%contextual_ectx_step_case Hred; first done.
exfalso. apply is_val_spec in Hval as (v & Hval).
apply reducible_not_val in Hred. congruence.
Qed.
(** Contextual lifting lemmas for deterministic reduction *)
Tactic Notation "lift_det" uconstr(ctx) :=
intros;
let Hs := fresh in
match goal with
| H : det_step _ _ |- _ => destruct H as [? Hs]
end;
simplify_val; econstructor;
[intros; by eapply (fill_reducible ctx) |
intros ? ? ? (? & -> & [-> ->]%Hs)%(reducible_contextual_step_case ctx); done ].
Lemma det_step_pair_r e1 e2 e2' :
det_step e2 e2'
det_step (e1, e2)%E (e1, e2')%E.
Proof. lift_det [PairRCtx _]. Qed.
Lemma det_step_pair_l e1 e1' e2 :
is_val e2
det_step e1 e1'
det_step (e1, e2)%E (e1', e2)%E.
Proof. lift_det [PairLCtx _]. Qed.
Lemma det_step_binop_r e1 e2 e2' op :
det_step e2 e2'
det_step (BinOp op e1 e2)%E (BinOp op e1 e2')%E.
Proof. lift_det [BinOpRCtx _ _]. Qed.
Lemma det_step_binop_l e1 e1' e2 op :
is_val e2
det_step e1 e1'
det_step (BinOp op e1 e2)%E (BinOp op e1' e2)%E.
Proof. lift_det [BinOpLCtx _ _]. Qed.
Lemma det_step_if e e' e1 e2 :
det_step e e'
det_step (If e e1 e2)%E (If e' e1 e2)%E.
Proof. lift_det [IfCtx _ _]. Qed.
Lemma det_step_app_r e1 e2 e2' :
det_step e2 e2'
det_step (App e1 e2)%E (App e1 e2')%E.
Proof. lift_det [AppRCtx _]. Qed.
Lemma det_step_app_l e1 e1' e2 :
is_val e2
det_step e1 e1'
det_step (App e1 e2)%E (App e1' e2)%E.
Proof. lift_det [AppLCtx _]. Qed.
Lemma det_step_snd_lift e e' :
det_step e e'
det_step (Snd e)%E (Snd e')%E.
Proof. lift_det [SndCtx]. Qed.
Lemma det_step_fst_lift e e' :
det_step e e'
det_step (Fst e)%E (Fst e')%E.
Proof. lift_det [FstCtx]. Qed.
Lemma det_step_store_r e1 e2 e2' :
det_step e2 e2'
det_step (Store e1 e2)%E (Store e1 e2')%E.
Proof. lift_det [StoreRCtx _]. Qed.
Lemma det_step_store_l e1 e1' e2 :
is_val e2
det_step e1 e1'
det_step (Store e1 e2)%E (Store e1' e2)%E.
Proof. lift_det [StoreLCtx _]. Qed.
#[global]
Hint Resolve app_step_r app_step_l app_step_beta unroll_roll_step : core.
#[global]
Hint Extern 1 (is_val _) => (simpl; fast_done) : core.
#[global]
Hint Immediate is_val_of_val : core.
#[global]
Hint Resolve det_step_beta det_step_tbeta det_step_unpack det_step_unop det_step_binop det_step_if_true det_step_if_false det_step_fst det_step_snd det_step_casel det_step_caser det_step_unroll : core.
#[global]
Hint Resolve det_step_pair_r det_step_pair_l det_step_binop_r det_step_binop_l det_step_if det_step_app_r det_step_app_l det_step_snd_lift det_step_fst_lift det_step_store_l det_step_store_r : core.
#[global]
Hint Constructors nsteps : core.
#[global]
Hint Extern 1 (is_val _) => simpl : core.
Ltac do_det_step :=
match goal with
| |- nsteps det_step _ _ _ => econstructor 2; first do_det_step
| |- det_step _ _ => simpl; solve[eauto 10]
end.