aboutsummaryrefslogtreecommitdiff
path: root/src/Compilers/WfReflectiveGen.v
diff options
context:
space:
mode:
Diffstat (limited to 'src/Compilers/WfReflectiveGen.v')
-rw-r--r--src/Compilers/WfReflectiveGen.v334
1 files changed, 0 insertions, 334 deletions
diff --git a/src/Compilers/WfReflectiveGen.v b/src/Compilers/WfReflectiveGen.v
deleted file mode 100644
index 4de378451..000000000
--- a/src/Compilers/WfReflectiveGen.v
+++ /dev/null
@@ -1,334 +0,0 @@
-(** * A reflective version of [Wf]/[WfRel] proofs *)
-(** Because every constructor of [Syntax.wff] stores the syntax tree
- being proven well-formed, a proof that a syntax tree is
- well-formed is quadratic in the size of the syntax tree. (Tacking
- an extra term on to the head of the syntax tree requires an extra
- constructor of [Syntax.wff], and that constructor stores the
- entirety of the new syntax tree.)
-
- In practice, this makes proving well-formedness of large trees
- very slow. To remedy this, we provide an alternative type
- ([reflect_wffT]) that implies [Syntax.wff], but is only linear in
- the size of the syntax tree, with a coefficient less than 1.
-
- The idea is that, since we already know the syntax-tree arguments
- to the constructors (and, moreover, already fully know the shape
- of the [Syntax.wff] proof, because it will exactly match the shape
- of the syntax tree), the proof doesn't have to store any of that
- information. It only has to store the genuinely new information
- in [Syntax.wff], namely, that the constants don't depend on the
- [var] argument (i.e., that the constants in the same location in
- the two expressions are equal), and that there are no free nor
- mismatched variables (i.e., that the variables in the same
- location in the two expressions are in the relevant list of
- binders). We can make the further optimization of storing the
- location in the list of each binder, so that all that's left to
- verify is that the locations line up correctly.
-
- Since there is no way to assign list locations (De Bruijn indices)
- after the fact (that is, once we have an [exprf var t] rather than
- an [Expr t]), we instead start from an expression where [var] is
- enriched with De Bruijn indices, and talk about [Syntax.wff] of
- that expression stripped of its De Bruijn indices. Since this
- procedure is only expected to work on concrete syntax trees, we
- will be able to simply check by unification to check that
- stripping the indices results in the term that we started with.
-
- The interface of this file is that, to prove a [Syntax.Wf] goal,
- you invoke the tactic [reflect_Wf base_type_eq_semidec_is_dec
- op_beq_bl], where:
-
- - [base_type_eq_semidec_is_dec : forall t1 t2,
- base_type_eq_semidec_transparent t1 t2 = None -> t1 <> t2] for
- some [base_type_eq_semidec_transparent : forall t1 t2 :
- base_type_code, option (t1 = t2)], and
-
- - [op_beq_bl : forall t1 tR x y, prop_of_option (op_beq t1 tR x y)
- -> x = y] for some [op_beq : forall t1 tR, op t1 tR -> op t1 tR
- -> option pointed_Prop] *)
-
-Require Import Coq.Arith.Arith Coq.Logic.Eqdep_dec.
-Require Import Crypto.Compilers.Syntax.
-Require Import Crypto.Util.Notations Crypto.Util.Option Crypto.Util.Sigma Crypto.Util.Prod Crypto.Util.Decidable Crypto.Util.ListUtil.
-Require Import Crypto.Util.Tactics.RewriteHyp.
-Require Import Crypto.Compilers.Wf.
-Require Export Crypto.Util.PartiallyReifiedProp. (* export for the [bool >-> reified_Prop] coercion *)
-Require Export Crypto.Util.FixCoqMistakes.
-
-
-Section language.
- (** To be able to optimize away so much of the [Syntax.wff] proof,
- we must be able to decide a few things: equality of base types,
- and equality of operator codes. Since we will be casting across
- the equality proofs of base types, we require that this
- semi-decider give transparent proofs. (This requirement is not
- enforced, but it will block [vm_compute] when trying to use the
- lemma in this file.) *)
- Context (base_type_code : Type)
- (base_type_eq_semidec_transparent : forall t1 t2 : base_type_code, option (t1 = t2))
- (base_type_eq_semidec_is_dec : forall t1 t2, base_type_eq_semidec_transparent t1 t2 = None -> t1 <> t2)
- (op : flat_type base_type_code -> flat_type base_type_code -> Type).
- (** In practice, semi-deciding equality of operators should either
- return [Some trivial] or [None], and not make use of the
- generality of [pointed_Prop]. However, we need to use
- [pointed_Prop] internally because we need to talk about equality
- of things of type [var t], for [var : base_type_code -> Type].
- It does not hurt to allow extra generality in [op_beq]. *)
- Context (op_beq : forall t1 tR, op t1 tR -> op t1 tR -> reified_Prop).
- Context (op_beq_bl : forall t1 tR x y, to_prop (op_beq t1 tR x y) -> x = y).
- Context {var1 var2 : base_type_code -> Type}.
-
- Local Notation eP := (fun t => var1 (fst t) * var2 (snd t))%type (only parsing).
-
- (* convenience notations that fill in some arguments used across the section *)
- Local Notation flat_type := (flat_type base_type_code).
- Local Notation type := (type base_type_code).
- Local Notation exprf := (@exprf base_type_code op).
- Local Notation expr := (@expr base_type_code op).
-
- Local Ltac inversion_base_type_code_step :=
- match goal with
- | [ H : ?x = ?x :> base_type_code |- _ ]
- => assert (H = eq_refl) by eapply UIP_dec, dec_rel_of_semidec_rel, base_type_eq_semidec_is_dec; subst H
- | [ H : ?x = ?y :> base_type_code |- _ ] => subst x || subst y
- end.
- Local Ltac inversion_base_type_code := repeat inversion_base_type_code_step.
-
- (* lift [base_type_eq_semidec_transparent] across [flat_type] *)
- Fixpoint flat_type_eq_semidec_transparent (t1 t2 : flat_type) : option (t1 = t2)
- := match t1, t2 return option (t1 = t2) with
- | Tbase t1, Tbase t2
- => option_map (@f_equal _ _ Tbase _ _)
- (base_type_eq_semidec_transparent t1 t2)
- | Tbase _, _ => None
- | Unit, Unit => Some eq_refl
- | Unit, _ => None
- | Prod A B, Prod A' B'
- => match flat_type_eq_semidec_transparent A A', flat_type_eq_semidec_transparent B B' with
- | Some p, Some q => Some (f_equal2 Prod p q)
- | _, _ => None
- end
- | Prod _ _, _ => None
- end.
- Definition type_eq_semidec_transparent (t1 t2 : type) : option (t1 = t2)
- := match t1, t2 return option (t1 = t2) with
- | Arrow A B, Arrow A' B'
- => match flat_type_eq_semidec_transparent A A', flat_type_eq_semidec_transparent B B' with
- | Some p, Some q => Some (f_equal2 (@Arrow base_type_code) p q)
- | _, _ => None
- end
- end.
- Lemma base_type_eq_semidec_transparent_refl t : base_type_eq_semidec_transparent t t = Some eq_refl.
- Proof using base_type_eq_semidec_is_dec.
- clear -base_type_eq_semidec_is_dec.
- pose proof (base_type_eq_semidec_is_dec t t).
- destruct (base_type_eq_semidec_transparent t t); intros; try intuition congruence.
- inversion_base_type_code; reflexivity.
- Qed.
- Lemma flat_type_eq_semidec_transparent_refl t : flat_type_eq_semidec_transparent t t = Some eq_refl.
- Proof using base_type_eq_semidec_is_dec.
- clear -base_type_eq_semidec_is_dec.
- induction t as [t | | A B IHt]; simpl; try reflexivity.
- { rewrite base_type_eq_semidec_transparent_refl; reflexivity. }
- { rewrite_hyp !*; reflexivity. }
- Qed.
- Lemma type_eq_semidec_transparent_refl t : type_eq_semidec_transparent t t = Some eq_refl.
- Proof using base_type_eq_semidec_is_dec.
- clear -base_type_eq_semidec_is_dec.
- destruct t; simpl; rewrite !flat_type_eq_semidec_transparent_refl; reflexivity.
- Qed.
-
-
- Definition op_beq' t1 tR t1' tR' (x : op t1 tR) (y : op t1' tR') : reified_Prop
- := match flat_type_eq_semidec_transparent t1 t1', flat_type_eq_semidec_transparent tR tR' with
- | Some p, Some q
- => match p in (_ = t1'), q in (_ = tR') return op t1' tR' -> _ with
- | eq_refl, eq_refl => fun y => op_beq _ _ x y
- end y
- | _, _ => rFalse
- end.
-
- (** While [Syntax.wff] is parameterized over a list of [sigT (fun t
- => var1 t * var2 t)], it is simpler here to make everything
- heterogenous, rather than trying to mix homogenous and
- heterogenous things.† Thus we parameterize our [reflect_wffT]
- over a list of [sigT (fun t => var1 (fst t) * var2 (snd t))],
- and write a function ([duplicate_type]) that turns the former
- into the latter.
-
- † This is an instance of the general theme that abstraction
- barriers are important. Here we enforce the abstraction
- barrier that our input decision procedures are homogenous, but
- all of our internal code is strictly heterogenous. This
- allows us to contain the conversions between homogenous and
- heterogenous code to a few functions: [op_beq'],
- [eq_type_and_var], [eq_type_and_const], and to the statement
- about [Syntax.wff] itself. *)
-
- Definition eq_semidec_and_gen {T} (semidec : forall x y : T, option (x = y))
- (t t' : T) (f g : T -> Type) (R : forall t, f t -> g t -> reified_Prop)
- (x : f t) (x' : g t')
- : reified_Prop
- := match semidec t t' with
- | Some p
- => R _ (eq_rect _ f x _ p) x'
- | None => rFalse
- end.
-
- (* Here is where we use the generality of [pointed_Prop], to say
- that two things of type [var1] are equal, and two things of type
- [var2] are equal. *)
- Definition eq_type_and_var : sigT eP -> sigT eP -> reified_Prop
- := fun x y => (eq_semidec_and_gen
- base_type_eq_semidec_transparent _ _ var1 var1 (fun _ => rEq) (fst (projT2 x)) (fst (projT2 y))
- /\ eq_semidec_and_gen
- base_type_eq_semidec_transparent _ _ var2 var2 (fun _ => rEq) (snd (projT2 x)) (snd (projT2 y)))%reified_prop.
-
- Definition duplicate_type (ls : list (sigT (fun t => var1 t * var2 t)%type)) : list (sigT eP)
- := List.map (fun v => existT eP (projT1 v, projT1 v) (projT2 v)) ls.
-
- Lemma duplicate_type_app ls ls'
- : (duplicate_type (ls ++ ls') = duplicate_type ls ++ duplicate_type ls')%list.
- Proof using Type. apply List.map_app. Qed.
- Lemma duplicate_type_length ls
- : List.length (duplicate_type ls) = List.length ls.
- Proof using Type. apply List.map_length. Qed.
- Lemma duplicate_type_in t v ls
- : List.In (existT _ (t, t) v) (duplicate_type ls) -> List.In (existT _ t v) ls.
- Proof using base_type_eq_semidec_is_dec.
- unfold duplicate_type; rewrite List.in_map_iff.
- intros [ [? ?] [? ?] ].
- inversion_sigma; inversion_prod; inversion_base_type_code; subst; simpl.
- assumption.
- Qed.
- Lemma duplicate_type_not_in G t t0 v (H : base_type_eq_semidec_transparent t t0 = None)
- : ~List.In (existT _ (t, t0) v) (duplicate_type G).
- Proof using base_type_eq_semidec_is_dec.
- apply base_type_eq_semidec_is_dec in H.
- clear -H; intro H'.
- induction G as [|? ? IHG]; simpl in *; destruct H';
- intuition; congruence.
- Qed.
-
- Definition preflatten_binding_list2 t1 t2 : option (forall (x : interp_flat_type var1 t1) (y : interp_flat_type var2 t2), list (sigT (fun t => var1 t * var2 t)%type))
- := match flat_type_eq_semidec_transparent t1 t2 with
- | Some p
- => Some (fun x y
- => let x := eq_rect _ (interp_flat_type var1) x _ p in
- flatten_binding_list x y)
- | None => None
- end.
- Definition flatten_binding_list2 t1 t2 : option (forall (x : interp_flat_type var1 t1) (y : interp_flat_type var2 t2), list (sigT eP))
- := option_map (fun f x y => duplicate_type (f x y)) (preflatten_binding_list2 t1 t2).
- (** This function adds De Bruijn indices to variables *)
- Fixpoint natize_interp_flat_type var t (base : nat) (v : interp_flat_type var t) {struct t}
- : nat * interp_flat_type (fun t : base_type_code => nat * var t)%type t
- := match t return interp_flat_type var t -> nat * interp_flat_type _ t with
- | Prod A B => fun v => let ret := @natize_interp_flat_type _ A base (fst v) in
- let base := fst ret in
- let a := snd ret in
- let ret := @natize_interp_flat_type _ B base (snd v) in
- let base := fst ret in
- let b := snd ret in
- (base, (a, b))
- | Unit => fun v => (base, v)
- | Tbase t => fun v => (S base, (base, v))
- end v.
- Arguments natize_interp_flat_type {var t} _ _.
- Lemma length_natize_interp_flat_type1 {t} (base : nat) (v1 : interp_flat_type var1 t) (v2 : interp_flat_type var2 t)
- : fst (natize_interp_flat_type base v1) = length (flatten_binding_list v1 v2) + base.
- Proof using Type.
- revert base; induction t; simpl; [ reflexivity | reflexivity | ].
- intros; rewrite List.app_length, <- plus_assoc.
- rewrite_hyp <- ?*; reflexivity.
- Qed.
- Lemma length_natize_interp_flat_type2 {t} (base : nat) (v1 : interp_flat_type var1 t) (v2 : interp_flat_type var2 t)
- : fst (natize_interp_flat_type base v2) = length (flatten_binding_list v1 v2) + base.
- Proof using Type.
- revert base; induction t; simpl; [ reflexivity | reflexivity | ].
- intros; rewrite List.app_length, <- plus_assoc.
- rewrite_hyp <- ?*; reflexivity.
- Qed.
-
- (* This function strips De Bruijn indices from expressions *)
- Fixpoint unnatize_exprf {var t} (base : nat)
- (e : @Syntax.exprf base_type_code op (fun t => nat * var t)%type t)
- : @Syntax.exprf base_type_code op var t
- := match e in @Syntax.exprf _ _ _ t return Syntax.exprf _ _ t with
- | TT => TT
- | Var _ x => Var (snd x)
- | Op _ _ op args => Op op (@unnatize_exprf _ _ base args)
- | LetIn _ ex _ eC
- => LetIn (@unnatize_exprf _ _ base ex)
- (fun x => let v := natize_interp_flat_type base x in
- @unnatize_exprf _ _ (fst v) (eC (snd v)))
- | Pair _ x _ y
- => Pair (@unnatize_exprf _ _ base x) (@unnatize_exprf _ _ base y)
- end.
- Definition unnatize_expr {var t} (base : nat)
- (e : @Syntax.expr base_type_code op (fun t => nat * var t)%type t)
- : @Syntax.expr base_type_code op var t
- := match e in @Syntax.expr _ _ _ t return Syntax.expr _ _ t with
- | Abs tx tR f => Abs (fun x : interp_flat_type var tx =>
- let v := natize_interp_flat_type (t:=tx) base x in
- @unnatize_exprf _ _ (fst v) (f (snd v)))
- end.
-
- Fixpoint reflect_wffT (G : list (sigT (fun t => var1 (fst t) * var2 (snd t))%type))
- {t1 t2 : flat_type}
- (e1 : @exprf (fun t => nat * var1 t)%type t1)
- (e2 : @exprf (fun t => nat * var2 t)%type t2)
- {struct e1}
- : reified_Prop
- := match e1, e2 with
- | TT, TT => rTrue
- | TT, _ => rFalse
- | Var t0 x, Var t1 y
- => match beq_nat (fst x) (fst y), List.nth_error G (List.length G - S (fst x)) with
- | true, Some v => eq_type_and_var v (existT _ (t0, t1) (snd x, snd y))
- | _, _ => rFalse
- end
- | Var _ _, _ => rFalse
- | Op t1 tR op args, Op t1' tR' op' args'
- => (@reflect_wffT G t1 t1' args args' /\ op_beq' t1 tR t1' tR' op op')%reified_prop
- | Op _ _ _ _, _ => rFalse
- | LetIn tx ex tC eC, LetIn tx' ex' tC' eC'
- => let p := @reflect_wffT G tx tx' ex ex' in
- match @flatten_binding_list2 tx tx', flat_type_eq_semidec_transparent tC tC' with
- | Some G0, Some _
- => p
- /\ (∀ (x : interp_flat_type var1 tx) (x' : interp_flat_type var2 tx'),
- @reflect_wffT (G0 x x' ++ G)%list _ _
- (eC (snd (natize_interp_flat_type (List.length G) x)))
- (eC' (snd (natize_interp_flat_type (List.length G) x'))))
- | _, _ => rFalse
- end
- | LetIn _ _ _ _, _ => rFalse
- | Pair tx ex ty ey, Pair tx' ex' ty' ey'
- => @reflect_wffT G tx tx' ex ex' /\ @reflect_wffT G ty ty' ey ey'
- | Pair _ _ _ _, _ => rFalse
- end%reified_prop.
-
- Definition reflect_wfT (G : list (sigT (fun t => var1 (fst t) * var2 (snd t))%type))
- {t1 t2 : type}
- (e1 : @expr (fun t => nat * var1 t)%type t1)
- (e2 : @expr (fun t => nat * var2 t)%type t2)
- : reified_Prop
- := match e1, e2 with
- | Abs tx tR f, Abs tx' tR' f'
- => match @flatten_binding_list2 tx tx', flat_type_eq_semidec_transparent tR tR' with
- | Some G0, Some _
- => ∀ (x : interp_flat_type var1 tx) (x' : interp_flat_type var2 tx'),
- @reflect_wffT (G0 x x' ++ G)%list _ _
- (f (snd (natize_interp_flat_type (List.length G) x)))
- (f' (snd (natize_interp_flat_type (List.length G) x')))
- | _, _ => rFalse
- end
- end%reified_prop.
-End language.
-
-Global Arguments reflect_wffT {_} _ {op} op_beq {var1 var2} G {t1 t2} _ _.
-Global Arguments reflect_wfT {_} _ {op} op_beq {var1 var2} G {t1 t2} _ _.
-Global Arguments unnatize_exprf {_ _ _ _} _ _.
-Global Arguments unnatize_expr {_ _ _ _} _ _.
-Global Arguments natize_interp_flat_type {_ _ t} _ _.