Minuska.substitution_parallel_properties
From Minuska Require Import
prelude
spec
substitution_parallel
basic_properties
termoverbov_subst
termoverbov_subst_properties
.
From Coq Require Import Logic.Classical_Prop.
Definition subtmm_closed {Σ : StaticModel} (s : SubP) :=
forall k v, s !! k = Some v -> vars_of v = ∅
.
Lemma subp_app_empty
{Σ : StaticModel}
(φ : TermOver BuiltinOrVar)
:
subp_app ∅ φ = φ
.
Proof.
induction φ; simpl.
{
destruct a; simpl.
{ reflexivity. }
{
ltac1:(case_match).
{ ltac1:(rewrite lookup_empty in H). inversion H. }
{
reflexivity.
}
}
}
{
apply f_equal.
revert H.
induction l; intros H; simpl in *.
{
reflexivity.
}
{
rewrite Forall_cons_iff in H.
destruct H as [H1 H2].
specialize (IHl H2).
clear H2.
rewrite H1.
rewrite IHl.
reflexivity.
}
}
Qed.
Lemma subp_app_closed
{Σ : StaticModel}
(sub_mm : SubP)
(φ : TermOver BuiltinOrVar)
:
vars_of φ = ∅ ->
subp_app sub_mm φ = φ
.
Proof.
induction φ; intros HH; simpl in *.
{
destruct a; simpl in *.
{ reflexivity. }
{
unfold vars_of in HH; simpl in HH.
unfold vars_of in HH; simpl in HH.
ltac1:(set_solver).
}
}
{
apply f_equal.
revert HH H.
induction l; intros HH H; simpl in *.
{ reflexivity. }
{
rewrite Forall_cons_iff in H.
destruct H as [H1 H2].
rewrite vars_of_t_term in HH.
rewrite fmap_cons in HH.
rewrite union_list_cons in HH.
specialize (IHl ltac:(set_solver)).
specialize (H1 ltac:(set_solver)).
rewrite H1.
rewrite (IHl H2).
reflexivity.
}
}
Qed.
Lemma subp_app_almost_closed
{Σ : StaticModel}
(s : SubP)
(φ : TermOver BuiltinOrVar)
:
vars_of φ ## subp_dom s ->
subp_app s φ = φ
.
Proof.
unfold SubP in *.
revert s.
induction φ; intros ss HH; simpl in *.
{
destruct a; simpl in *.
{ reflexivity. }
{
unfold vars_of in HH; simpl in HH.
unfold vars_of in HH; simpl in HH.
rewrite disjoint_singleton_l in HH.
unfold subp_dom in HH.
destruct (ss !! x) eqn:Heq.
{
apply elem_of_dom_2 in Heq.
ltac1:(contradiction HH).
}
{
ltac1:(rewrite Heq).
reflexivity.
}
}
}
{
apply f_equal.
revert HH H.
induction l; intros HH H; simpl in *.
{ reflexivity. }
{
rewrite Forall_cons_iff in H.
destruct H as [H1 H2].
rewrite vars_of_t_term in HH.
rewrite fmap_cons in HH.
rewrite union_list_cons in HH.
specialize (IHl ltac:(set_solver)).
specialize (H1 ltac:(set_solver)).
rewrite H1.
rewrite (IHl H2).
reflexivity.
ltac1:(set_solver).
}
}
Qed.
Lemma subp_app_empty'
{Σ : StaticModel}
:
subp_app ∅ = id
.
Proof.
apply functional_extensionality.
apply subp_app_empty.
Qed.
Lemma subp_app_insert0
{Σ : StaticModel}
(s : SubP)
(x : variable)
(v : TermOver BuiltinOrVar)
:
vars_of v ## subp_dom s ->
subp_app (<[x:=v]>s)
= (subp_app s) ∘ (fun φ => TermOverBoV_subst φ x v)
.
Proof.
unfold SubP in *.
intros HH.
apply functional_extensionality.
intros φ.
revert s x v HH.
induction φ; intros ss x v HH; simpl.
{
destruct a; simpl.
{
reflexivity.
}
{
destruct (decide (x = x0)).
{
subst.
ltac1:(rewrite lookup_insert).
symmetry.
apply subp_app_almost_closed.
exact HH.
}
{
ltac1:(rewrite lookup_insert_ne).
{
ltac1:(congruence).
}
{
ltac1:(case_match).
{
simpl.
ltac1:(rewrite H).
reflexivity.
}
{
rewrite subp_app_almost_closed.
reflexivity.
unfold vars_of; simpl.
unfold vars_of; simpl.
unfold subp_dom.
apply not_elem_of_dom_2 in H.
ltac1:(set_solver).
}
}
}
}
}
{
apply f_equal.
revert H.
induction l; intros H; simpl in *.
{ reflexivity. }
{
rewrite Forall_cons_iff in H.
destruct H as [H1 H2].
rewrite (IHl H2).
rewrite H1.
reflexivity.
assumption.
}
}
Qed.
Lemma subp_normalize_normalize
{Σ : StaticModel}
:
subp_normalize ∘ subp_normalize
= subp_normalize
.
Proof.
apply functional_extensionality.
unfold compose.
intros s.
unfold subp_normalize.
rewrite map_filter_filter.
simpl.
apply map_filter_ext.
intros i x Hsix.
split.
{
intros [H1 H2].
simpl.
exact H2.
}
{
intros H.
split; exact H.
}
Qed.
Lemma subp_normalize_normal
{Σ : StaticModel}
(s : SubP)
:
subp_is_normal s ->
subp_normalize s = s
.
Proof.
intros H.
unfold subp_is_normal in H.
exact H.
Qed.
Lemma subp_id_compose
{Σ : StaticModel}
(s : SubP)
:
subp_is_normal s ->
subp_compose subp_id s = s .
Proof.
intros Hnormal.
unfold subp_id.
unfold subp_compose.
rewrite map_filter_empty.
rewrite (left_id empty union).
ltac1:(rewrite subp_app_empty').
rewrite map_fmap_id.
rewrite subp_normalize_normal.
{ reflexivity. }
{ exact Hnormal. }
Qed.
Lemma subp_compose_id
{Σ : StaticModel}
(s : SubP)
:
subp_is_normal s ->
subp_compose s subp_id = s .
Proof.
intros Hnormal.
unfold subp_id.
unfold subp_compose.
rewrite fmap_empty.
rewrite (right_id empty union).
unfold subp_dom.
unfold SubP in *.
rewrite map_filter_id.
{
rewrite subp_normalize_normal.
{ reflexivity. }
{ exact Hnormal. }
}
{
intros i x Hsix.
rewrite dom_empty.
apply not_elem_of_empty.
}
Qed.
Lemma subp_app_singleton
{Σ : StaticModel}
x p
:
subp_app {[x:=p]} = (fun q => TermOverBoV_subst q x p)
.
Proof.
ltac1:(rewrite - insert_empty).
ltac1:(rewrite subp_app_insert0).
unfold subp_dom.
ltac1:(rewrite dom_empty_L).
ltac1:(set_solver).
ltac1:(rewrite subp_app_empty').
unfold compose.
apply functional_extensionality.
intros y.
reflexivity.
Qed.
Lemma subp_app_union_comm
{Σ : StaticModel}
(a b : gmap variable (TermOver BuiltinOrVar))
:
subp_dom a ## subp_dom b ->
subp_app (a ∪ b) = subp_app (b ∪ a)
.
Proof.
intros HH0.
apply functional_extensionality.
intros phi.
revert a b HH0.
induction phi; intros aa bb HH0; simpl in *.
{
destruct a.
{ reflexivity. }
{
ltac1:(repeat case_match).
{
ltac1:(rewrite lookup_union in H).
ltac1:(rewrite lookup_union in H0).
destruct (aa !! x) eqn:Hax,
(bb !! x) eqn:Hbx.
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
ltac1:(apply elem_of_dom_2 in Hax).
ltac1:(apply elem_of_dom_2 in Hbx).
unfold subp_dom in *.
unfold subp_codom in *.
ltac1:(set_solver).
}
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
ltac1:(apply elem_of_dom_2 in Hax).
unfold subp_dom in *.
unfold subp_codom in *.
ltac1:(set_solver).
}
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
ltac1:(apply elem_of_dom_2 in Hbx).
unfold subp_dom in *.
unfold subp_codom in *.
ltac1:(set_solver).
}
{
inversion H.
}
}
{
ltac1:(rewrite lookup_union in H).
ltac1:(rewrite lookup_union in H0).
destruct (aa !! x) eqn:Hax,
(bb !! x) eqn:Hbx.
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
}
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
}
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
}
{
inversion H.
}
}
{
ltac1:(rewrite lookup_union in H).
ltac1:(rewrite lookup_union in H0).
destruct (aa !! x) eqn:Hax,
(bb !! x) eqn:Hbx.
{
inversion H; subst; clear H.
}
{
inversion H; subst; clear H.
}
{
inversion H; subst; clear H.
}
{
inversion H0.
}
}
{
reflexivity.
}
}
}
{
apply f_equal.
apply map_ext_Forall.
rewrite Forall_forall in H.
rewrite Forall_forall.
intros x Hx.
specialize (H x Hx).
apply H.
apply HH0.
}
Qed.
Lemma subp_compose_helper_1
{Σ : StaticModel}
(b c : SubP)
:
subp_codom b ## subp_dom c ->
subp_app c <$> b = b
.
Proof.
intros Hdisj.
apply map_eq_iff.
intros i.
destruct (b !! i) eqn:Hbi.
{
rewrite lookup_fmap.
ltac1:(rewrite Hbi).
simpl.
apply f_equal.
apply subp_app_almost_closed.
unfold SubP in *.
ltac1:(assert(vars_of t ⊆ subp_codom b)).
{
unfold subp_codom.
rewrite elem_of_subseteq.
intros x Hx.
rewrite elem_of_union_list.
exists (vars_of t).
split>[|exact Hx].
rewrite elem_of_list_fmap.
exists t.
split>[reflexivity|].
rewrite elem_of_elements.
ltac1:(rewrite elem_of_map_img).
exists i.
exact Hbi.
}
ltac1:(set_solver).
}
{
rewrite lookup_fmap.
ltac1:(rewrite Hbi).
reflexivity.
}
Qed.
Lemma subp_app_union
{Σ : StaticModel}
(b c : gmap variable (TermOver BuiltinOrVar))
:
subp_codom b ## subp_dom c ->
subp_app (b ∪ c) = (subp_app c) ∘ (subp_app b)
.
Proof.
intros HH.
apply functional_extensionality.
intros phi.
revert b c HH.
induction phi; intros b c HH.
{
simpl.
ltac1:(repeat case_match; simplify_eq/=; try reflexivity).
{
unfold SubP in *.
ltac1:(erewrite lookup_union_Some_l in H0)>[|apply H1].
apply (inj Some) in H0.
subst.
symmetry.
apply subp_app_almost_closed.
(* ltac1:(eapply lookup_union_Some_l in H1). *)
ltac1:(assert(vars_of t ⊆ subp_codom b)).
{
unfold subp_codom.
rewrite elem_of_subseteq.
intros y Hy.
rewrite elem_of_union_list.
exists (vars_of t).
split>[|exact Hy].
rewrite elem_of_list_fmap.
exists t.
split>[reflexivity|].
rewrite elem_of_elements.
ltac1:(rewrite elem_of_map_img).
exists x.
exact H1.
}
ltac1:(set_solver).
}
{
ltac1:(rewrite lookup_union_r in H0).
exact H1.
ltac1:(rewrite H0).
reflexivity.
}
{
ltac1:(exfalso).
unfold SubP in *.
rewrite lookup_union in H0.
rewrite H1 in H0.
unfold union,option_union,union_with,option_union_with in H0.
ltac1:(case_match; simplify_eq/=).
}
{
unfold SubP in *.
rewrite lookup_union in H0.
rewrite H1 in H0.
unfold union,option_union,union_with,option_union_with in H0.
ltac1:(case_match; simplify_eq/=).
reflexivity.
}
}
{
simpl.
f_equal.
clear s.
ltac1:(replace (map) with (@fmap list list_fmap) by reflexivity).
rewrite <- list_fmap_compose.
apply list_fmap_ext.
intros i x Hix.
rewrite Forall_forall in H.
specialize (H x).
ltac1:(ospecialize (H _)).
{
rewrite elem_of_list_lookup.
exists i.
exact Hix.
}
specialize (H _ _ HH).
exact H.
}
Qed.
Lemma subp_union_is_compose__sometimes_1
{Σ : StaticModel}
(a b : gmap variable (TermOver BuiltinOrVar))
:
(subp_app a <$> b) = b ->
subp_is_normal a ->
subp_is_normal b ->
b ∪ a = subp_compose a b
.
Proof.
intros HH1 Hna Hnb.
unfold subp_compose.
ltac1:(rewrite -> HH1 at 1).
unfold subp_dom.
apply map_eq.
intros i.
unfold SubP in *.
rewrite lookup_union.
unfold subp_normalize.
rewrite map_lookup_filter.
simpl.
rewrite lookup_union.
rewrite map_lookup_filter.
destruct
(b !! i) eqn:Hbi,
(a !! i) eqn:Hai.
{
simpl.
rewrite option_guard_False.
{
simpl.
rewrite option_guard_decide.
ltac1:(case_match).
{
clear H.
reflexivity.
}
{
ltac1:(exfalso).
clear H.
apply dec_stable in n.
subst t.
unfold subp_is_normal in Hnb.
rewrite <- Hnb in Hbi.
unfold subp_normalize in Hbi.
rewrite map_lookup_filter in Hbi.
rewrite bind_Some in Hbi.
destruct Hbi as [v [H1v H2v]].
simpl in *.
rewrite option_guard_decide in H2v.
ltac1:(case_match; simplify_eq/=).
}
}
{
rewrite elem_of_dom.
rewrite Hbi.
intros Ht. apply Ht. clear Ht.
exists t. reflexivity.
}
}
{
simpl.
rewrite (right_id None union).
rewrite option_guard_True.
{ reflexivity. }
{
intros HContra.
subst t.
assert (Hbi' := Hbi).
unfold subp_is_normal in Hnb.
rewrite <- Hnb in Hbi.
unfold subp_normalize in Hbi.
rewrite map_lookup_filter in Hbi.
rewrite Hbi' in Hbi.
simpl in Hbi.
rewrite bind_Some in Hbi.
destruct Hbi as [HContra [_ ?]].
ltac1:(congruence).
}
}
{
rewrite (right_id None union).
rewrite (left_id None union).
simpl.
rewrite option_guard_True.
{
simpl.
rewrite option_guard_decide.
ltac1:(case_match).
{
reflexivity.
}
{
ltac1:(contradiction n).
clear n H.
intros Hc.
subst t.
assert (Hai' := Hai).
unfold subp_is_normal in Hna.
rewrite <- Hna in Hai.
unfold subp_normalize in Hai.
rewrite map_lookup_filter in Hai.
rewrite Hai' in Hai.
simpl in Hai.
rewrite bind_Some in Hai.
destruct Hai as [HContra [_ ?]].
ltac1:(congruence).
}
}
{
rewrite elem_of_dom.
rewrite Hbi.
intros [? HContra].
inversion HContra.
}
}
{
simpl.
reflexivity.
}
Qed.
Lemma subp_compose_correct
{Σ : StaticModel}
(a b : SubP)
:
subp_app (subp_compose a b) = (subp_app a) ∘ (subp_app b)
.
Proof.
unfold subp_compose.
unfold compose.
apply functional_extensionality.
intros p.
revert a b.
induction p; intros aa bb; simpl.
{
destruct a; simpl in *.
{ reflexivity. }
{
unfold subp_normalize.
rewrite map_filter_union.
{
ltac1:(rewrite lookup_union).
ltac1:(rewrite map_lookup_filter).
unfold SubP in *.
ltac1:(rewrite map_lookup_filter).
ltac1:(rewrite map_lookup_filter).
ltac1:(rewrite lookup_fmap).
destruct (bb!!x) eqn:Hbx.
{
simpl.
destruct (aa !! x) eqn:Hax.
{
simpl.
rewrite option_guard_False.
{ simpl.
destruct (decide (t_over (bov_variable x) = subp_app aa t)).
{
rewrite option_guard_False.
{ simpl. ltac1:(congruence). }
{ simpl. ltac1:(congruence). }
}
{ rewrite option_guard_True.
simpl. reflexivity.
ltac1:(congruence).
}
}
{
intros HContra.
apply HContra.
unfold subp_dom.
ltac1:(rewrite elem_of_dom).
rewrite Hbx.
eexists.
reflexivity.
}
}
{
simpl.
destruct (decide (t_over (bov_variable x) = subp_app aa t)).
{
rewrite option_guard_False.
{ simpl. ltac1:(congruence). }
{ simpl. ltac1:(congruence). }
}
{
rewrite option_guard_True.
{ simpl. reflexivity. }
{ ltac1:(congruence). }
}
}
}
{
simpl.
destruct (aa!!x) eqn:Hax.
{
ltac1:(rewrite Hax).
simpl.
rewrite option_guard_True.
{
simpl.
destruct (decide (t = t_over (bov_variable x))).
{
subst.
rewrite option_guard_False.
{ simpl. reflexivity. }
{ ltac1:(congruence). }
}
{
rewrite option_guard_True.
{ simpl. reflexivity. }
{ ltac1:(congruence). }
}
}
{
unfold subp_dom.
ltac1:(rewrite elem_of_dom).
rewrite Hbx.
intros [? H].
inversion H.
}
}
{
simpl.
ltac1:(rewrite Hax).
reflexivity.
}
}
}
{
apply map_disjoint_spec.
intros i x' y' Hx' Hy'.
rewrite map_lookup_filter in Hx'.
rewrite lookup_fmap in Hy'.
destruct (aa !! i) eqn:Hai.
{
simpl in *.
destruct (bb !! i) eqn:Hbi.
{
simpl in *.
ltac1:(rewrite Hai in Hx').
simpl in *.
ltac1:(rewrite Hbi in Hy').
simpl in *.
ltac1:(simplify_eq/=).
ltac1:(simplify_option_eq).
unfold subp_dom in *.
apply H.
ltac1:(rewrite elem_of_dom).
ltac1:(rewrite Hbi).
eexists.
reflexivity.
}
{
ltac1:(rewrite Hai in Hx').
simpl in Hx'.
ltac1:(rewrite Hbi in Hy').
simpl in Hy'.
inversion Hy'.
}
}
{
ltac1:(rewrite Hai in Hx').
simpl in Hx'.
inversion Hx'.
}
}
}
}
{
apply f_equal.
ltac1:(replace (map) with (@fmap list list_fmap) by reflexivity).
rewrite Forall_forall in H.
rewrite <- list_fmap_compose.
apply list_fmap_ext.
intros i x Hix.
apply H.
rewrite elem_of_list_lookup.
exists i.
exact Hix.
}
Qed.
Lemma helper_lemma {Σ : StaticModel}:
forall x m t, t_over (bov_variable x) = subp_app m t -> exists y, t = t_over (bov_variable y)
.
Proof.
{
intros x' m' t' HH.
destruct t'; simpl in HH.
{ destruct a; simpl in HH.
inversion HH.
exists x. reflexivity.
}
{ inversion HH. }
}
Qed.
Lemma subp_compose_assoc
{Σ : StaticModel}
(a b c : SubP)
:
(*
subp_is_normal a -> *)
subp_is_normal b ->
(* subp_is_normal c ->*)
subp_compose (subp_compose a b) c = subp_compose a (subp_compose b c)
.
Proof.
(* intros Hnormala. *)
intros Hnormalb.
(* intros Hnormalc.*)
unfold SubP in *.
unfold subp_compose.
unfold subp_dom.
unfold SubP in *.
unfold subp_normalize.
apply map_eq.
{
intros i.
lazy_match! goal with
| [|- ?l = _] =>
destruct ($l) eqn:Heql
end.
{
symmetry.
ltac1:(rewrite map_lookup_filter in Heql).
rewrite bind_Some in Heql.
destruct Heql as [t' [H1t' H2t']].
simpl in *.
rewrite map_lookup_filter.
rewrite bind_Some.
simpl in *.
ltac1:(simplify_option_eq).
exists t.
split.
{
rewrite lookup_union in H1t'.
rewrite union_Some in H1t'.
rewrite lookup_union.
rewrite union_Some.
rewrite map_lookup_filter in H1t'.
rewrite map_lookup_filter.
rewrite bind_Some in H1t'.
rewrite bind_Some.
simpl in *.
destruct H1t' as [H1t|H1t].
{
destruct H1t as [x [H1x H2x]].
rewrite map_lookup_filter in H1x.
rewrite bind_Some in H1x.
destruct H1x as [y [H1y H2y]].
rewrite bind_Some in H2y.
destruct H2y as [pf [_ ?]].
simpl in *.
apply (inj Some) in H1.
subst y.
rewrite lookup_union in H1y.
rewrite map_lookup_filter in H1y.
rewrite lookup_fmap in H1y.
rewrite union_Some in H1y.
simpl in *.
destruct (a !! i) eqn:Hai.
{
rewrite bind_Some in H2x.
destruct H2x as [? [_ Hxt]].
apply (inj Some) in Hxt.
subst x.
simpl.
setoid_rewrite bind_Some.
lazy_match! Constr.type (Control.hyp @H1y) with
| (_ \/ ?rr) => destruct (classic $rr) as [Hyes|Hno]
end.
{
destruct H1y as [H1y|H1y].
{
rewrite bind_Some in H1y.
destruct H1y as [? [_ Htmp]].
rewrite bind_Some in Htmp.
destruct Htmp as [? [_ Htmp]].
apply (inj Some) in Htmp.
subst t.
apply not_elem_of_dom_1 in x1 as Hb.
apply not_elem_of_dom_1 in x0 as Hc.
rewrite lookup_fmap.
rewrite map_lookup_filter.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
simpl.
setoid_rewrite lookup_union.
setoid_rewrite map_lookup_filter.
rewrite Hb.
simpl.
setoid_rewrite lookup_fmap.
rewrite Hc.
simpl.
destruct Hyes as [H1y H2y].
simpl in *.
clear H1y.
rewrite Hb in H2y.
simpl in H2y.
inversion H2y.
}
{
destruct H1y as [H1 Htmp].
simpl in H1.
clear H1.
ltac1:(setoid_rewrite bind_None).
destruct (b !! i) eqn:Hbi.
{
simpl in *.
ltac1:(simplify_eq/=).
destruct Hyes as [H1 H2].
clear H1 H2.
apply not_elem_of_dom_1 in x0 as Hci.
setoid_rewrite lookup_fmap.
setoid_rewrite map_lookup_filter.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite lookup_union.
setoid_rewrite lookup_fmap.
setoid_rewrite Hci.
simpl.
setoid_rewrite (right_id None union).
setoid_rewrite map_lookup_filter.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite Hbi.
simpl.
right.
split.
left.
unfold guard_or.
ltac1:(case_match; try reflexivity).
ltac1:(exfalso; clear H1; rename n into H1).
rewrite elem_of_dom in H1.
rewrite map_lookup_filter in H1.
rewrite lookup_union in H1.
rewrite lookup_fmap in H1.
rewrite Hci in H1.
simpl in H1.
rewrite map_lookup_filter in H1.
rewrite Hbi in H1.
simpl in H1.
apply H1.
eexists.
rewrite bind_Some.
eexists.
rewrite bind_Some.
rewrite (right_id None union).
split.
{
erewrite option_guard_True_pi.
{ reflexivity. }
{ intros pfa pfb. apply proof_irrelevance. }
}
{
ltac1:(unshelve(eexists)).
{
unfold subp_is_normal in Hnormalb.
rewrite <- Hnormalb in Hbi.
unfold subp_normalize in Hbi.
rewrite map_lookup_filter in Hbi.
rewrite bind_Some in Hbi.
destruct Hbi as [bv [H1bv H2bv]].
rewrite bind_Some in H2bv.
simpl in H2bv.
destruct H2bv as [? [_ ?]].
ltac1:(congruence).
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
{
exists t1.
split>[|reflexivity].
exists t1.
(repeat split); try reflexivity.
{
exists t1.
split>[reflexivity|].
exists x0.
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
{
ltac1:(unshelve(eexists)).
{
intros HContra.
subst t1.
unfold subp_is_normal in Hnormalb.
rewrite <- Hnormalb in Hbi.
unfold subp_normalize in Hbi.
rewrite map_lookup_filter in Hbi.
rewrite bind_Some in Hbi.
destruct Hbi as [p [H1p H2p]].
rewrite bind_Some in H2p.
simpl in H2p.
destruct H2p as [? [_ ?]].
ltac1:(simplify_eq/=).
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
}
}
{
destruct Hyes as [H1 H2].
inversion H2.
}
}
}
{
apply not_and_or in Hno.
destruct (b !! i) eqn:Hbi.
{
simpl in *.
destruct H1y as [H1y|H1y].
{
rewrite bind_Some in H1y.
destruct H1y as [? [_ ?]].
apply not_elem_of_dom_1 in x.
ltac1:(congruence).
}
{
destruct H1y as [H1y Heq].
ltac1:(simplify_eq/=).
clear H1y.
destruct Hno as [Hno|Hno].
{
apply not_eq_None_Some in Hno.
destruct Hno as [q Hq].
rewrite bind_Some in Hq.
destruct Hq as [? [_ Htmp]].
ltac1:(simplify_eq/=).
apply not_elem_of_dom_1 in x.
ltac1:(congruence).
}
{
ltac1:(contradiction Hno).
reflexivity.
}
}
}
{
simpl in *.
destruct H1y as [H1y|H1y],
Hno as [Hno|Hno].
{
rewrite bind_Some in H1y.
destruct H1y as [? [_ Htmp]].
ltac1:(simplify_eq/=).
apply not_eq_None_Some in Hno.
destruct Hno as [q Hq].
rewrite bind_Some in Hq.
destruct Hq as [? [_ ?]].
ltac1:(simplify_eq/=).
apply not_elem_of_dom_1 in x0 as Hci.
setoid_rewrite lookup_fmap.
setoid_rewrite map_lookup_filter.
simpl.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite lookup_union.
setoid_rewrite lookup_fmap.
rewrite Hci.
simpl.
left.
exists q.
split>[reflexivity|].
ltac1:(unshelve(eexists)).
{
rewrite elem_of_dom.
rewrite map_lookup_filter.
intros [p Hp].
rewrite bind_Some in Hp.
destruct Hp as [o Ho].
rewrite lookup_union in Ho.
rewrite lookup_fmap in Ho.
destruct Ho as [H1o H2o].
rewrite map_lookup_filter in H1o.
rewrite Hci in H1o.
simpl in *.
rewrite Hbi in H1o.
simpl in H1o.
inversion H1o.
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
{
rewrite bind_Some in H1y.
clear Hno.
destruct H1y as [? [_ ?]].
ltac1:(simplify_eq/=).
apply not_elem_of_dom_1 in x0 as Hci.
setoid_rewrite lookup_fmap.
setoid_rewrite map_lookup_filter.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite bind_None.
setoid_rewrite lookup_union.
setoid_rewrite lookup_fmap.
rewrite Hci.
simpl.
setoid_rewrite map_lookup_filter.
rewrite Hbi.
simpl.
left.
exists t.
split>[reflexivity|].
ltac1:(unshelve(eexists)).
{
apply not_elem_of_dom_2.
rewrite map_lookup_filter_None.
rewrite lookup_union.
rewrite lookup_fmap.
rewrite Hci.
simpl.
rewrite (right_id None union).
setoid_rewrite (right_id None union).
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
left.
reflexivity.
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
{
destruct H1y as [? H1y].
inversion H1y.
}
{
destruct H1y as [? H1y].
inversion H1y.
}
}
}
}
{
simpl in *.
right.
split>[reflexivity|].
destruct H1y as [H1y|[H1y H2y]].
{
inversion H1y.
}
{
destruct (b !! i) eqn:Hbi.
{
simpl in *.
apply (inj Some) in H2y.
subst x.
simpl in *.
rewrite lookup_fmap.
rewrite map_lookup_filter.
simpl.
rewrite fmap_Some.
rewrite bind_Some in H2x.
destruct H2x as [pf1 [_ H1]].
apply (inj Some) in H1.
subst t.
exists t0.
split>[|reflexivity].
rewrite bind_Some.
setoid_rewrite lookup_union.
setoid_rewrite lookup_fmap.
apply not_elem_of_dom_1 in pf1 as pf1'.
rewrite pf1'.
simpl.
setoid_rewrite (right_id None union).
setoid_rewrite map_lookup_filter.
simpl.
rewrite Hbi.
simpl.
exists t0.
split.
{
rewrite bind_Some.
exists pf1.
split>[|reflexivity].
apply option_guard_True_pi.
intros pf8 pf9.
apply proof_irrelevance.
}
{
rewrite bind_Some.
ltac1:(unshelve(eexists)).
{
intros HContra.
subst t0.
simpl in *.
ltac1:(rewrite Hai in H).
ltac1:(contradiction H).
reflexivity.
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
}
{
simpl in H2y.
inversion H2y.
}
}
}
}
{
destruct H1t as [H1t H2t].
rewrite bind_None in H1t.
rewrite map_lookup_filter in H1t.
rewrite bind_None in H1t.
rewrite lookup_union in H1t.
rewrite lookup_fmap in H1t.
rewrite map_lookup_filter in H1t.
setoid_rewrite lookup_fmap.
setoid_rewrite bind_None.
destruct (a !! i) eqn:Hai.
{
rewrite map_lookup_filter.
simpl.
rewrite lookup_union.
rewrite lookup_fmap.
rewrite map_lookup_filter.
rewrite fmap_Some.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
destruct (b !! i) eqn:Hbi.
{
simpl.
destruct (c !! i) eqn:Hci.
{
simpl.
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
ltac1:(simplify_eq/=).
rewrite union_None in H1t.
destruct H1t as [[H1t|H1t]|H1t].
{
destruct H1t as [? H1t].
inversion H1t.
}
{
destruct H1t as [p [H1p H2p]].
rewrite union_Some in H1p.
rewrite bind_Some in H1p.
destruct H1p as [H1p|H1p].
{
destruct H1p as [H1p [_ ?]].
apply not_elem_of_dom_1 in H1p.
ltac1:(congruence).
}
{
destruct H1p as [_ H1p].
ltac1:(simplify_eq/=).
destruct (decide (subp_app b t2 = t_over (bov_variable i))).
{
left.
exists t0.
split>[reflexivity|].
remember (subp_compose a b) as ab.
assert(Heqab' := Heqab).
unfold subp_compose in Heqab'.
unfold subp_normalize in Heqab'.
setoid_rewrite <- Heqab.
clear Heqab'.
subst ab.
rewrite subp_compose_correct.
unfold compose.
rewrite e.
simpl.
ltac1:(rewrite Hai).
ltac1:(unshelve(eexists)).
{
rewrite elem_of_dom.
rewrite map_lookup_filter.
simpl.
rewrite lookup_union.
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
rewrite option_guard_False.
{ simpl. rewrite lookup_fmap. rewrite Hci. simpl.
rewrite option_guard_False.
{ intros [u Hu].
simpl in Hu.
inversion Hu.
}
{ ltac1:(congruence). }
}
rewrite elem_of_dom.
rewrite Hci.
intros Hu. apply Hu. exists t2. reflexivity.
}
{
split.
{
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
{ reflexivity. }
}
}
{
right.
split.
{ right.
exists t0.
split>[reflexivity|].
rewrite option_guard_False.
{ simpl. reflexivity. }
{
intros HC. apply HC. clear HC.
rewrite elem_of_dom.
rewrite map_lookup_filter.
rewrite lookup_union.
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
rewrite lookup_fmap.
rewrite Hci.
simpl.
rewrite option_guard_False.
{ simpl. rewrite option_guard_True.
eexists. reflexivity.
ltac1:(congruence).
}
{
rewrite elem_of_dom.
intros HH. apply HH. clear HH.
rewrite Hci.
eexists. reflexivity.
}
}
}
{
exists (subp_app b t2).
split.
{
exists (subp_app b t2).
repeat split.
{
rewrite option_guard_False.
{ simpl. reflexivity. }
{
rewrite elem_of_dom.
rewrite Hci.
intros HContra. apply HContra.
exists t2.
reflexivity.
}
}
{
apply nesym in n.
exists n.
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb. apply proof_irrelevance.
}
}
{
ltac1:(replace (subp_app a (subp_app b t2))
with (((subp_app a) ∘ (subp_app b)) t2)
by reflexivity).
rewrite <- subp_compose_correct.
reflexivity.
}
}
}
}
} {
destruct H1t as [p [H1p H2p]].
rewrite bind_Some in H1p.
destruct H1p as [q [H1q H2q]].
rewrite bind_Some in H2q.
destruct H2q as [Hq [_ ?]].
ltac1:(simplify_eq/=).
rewrite union_Some in H1q.
destruct H1q as [H1q|H1q].
{
rewrite bind_Some in H1q.
destruct H1q as [Hib' [_ ?]].
apply not_elem_of_dom_1 in Hib'.
ltac1:(congruence).
}
{
destruct H1q as [_ H1q].
ltac1:(simplify_eq/=).
(* I think that H is just a tautology.
*)
clear H.
destruct (decide (i ∈ dom (filter (λ kv : variable * TermOver' BuiltinOrVar, t_over (bov_variable kv.1) ≠ kv.2)
(filter (λ kv : variable * TermOver BuiltinOrVar, kv.1 ∉ dom c) b ∪ (subp_app b <$> c))))) as [Hin|Hnotin].
{
rewrite elem_of_dom in Hin.
destruct Hin as [p Hp].
rewrite map_lookup_filter in Hp.
rewrite bind_Some in Hp.
destruct Hp as [q [H1q H2q]].
rewrite lookup_union in H1q.
rewrite map_lookup_filter in H1q.
rewrite lookup_fmap in H1q.
rewrite Hbi in H1q.
simpl in H1q.
rewrite union_Some in H1q.
destruct H1q as [H1q|H1q].
{
rewrite bind_Some in H1q.
destruct H1q as [? [_ ?]].
ltac1:(simplify_eq/=).
apply elem_of_dom_2 in Hci.
ltac1:(contradiction).
}
{
destruct H1q as [_ H1q].
rewrite Hci in H1q.
simpl in H1q.
ltac1:(simplify_eq/=).
clear H2p.
rewrite bind_Some in H2q.
destruct H2q as [? [_ ?]].
ltac1:(simplify_eq/=).
right.
split.
{
right.
exists t0.
split>[reflexivity|].
rewrite bind_None.
left.
Search guard None.
rewrite option_guard_False.
{ reflexivity. }
rewrite elem_of_dom.
intros HContra.
apply HContra.
rewrite map_lookup_filter.
rewrite lookup_union.
rewrite map_lookup_filter.
rewrite lookup_fmap.
rewrite Hbi.
simpl.
rewrite Hci.
simpl.
rewrite option_guard_False.
{ simpl. rewrite option_guard_True. eexists. reflexivity.
assumption.
}
rewrite elem_of_dom.
rewrite Hci.
intros HH. apply HH. eexists. reflexivity.
}
{
exists (subp_app b t2).
ltac1:(replace (subp_app a (subp_app b t2)) with ((compose (subp_app a) (subp_app b)) t2) by reflexivity).
rewrite <- subp_compose_correct.
unfold subp_compose.
unfold subp_normalize.
split>[|reflexivity].
exists (subp_app b t2).
split.
{
rewrite option_guard_False.
simpl.
reflexivity.
intros HC. apply HC. clear HC.
rewrite elem_of_dom.
rewrite Hci.
exists t2. reflexivity.
}
{
exists x.
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
}
}
{
destruct (decide (t_over (bov_variable i) = subp_app b t2)).
{
left.
exists t0.
split>[reflexivity|].
exists Hnotin.
split.
{
apply option_guard_True_pi.
intros pfa pfb. apply proof_irrelevance.
}
{
apply f_equal.
lazy_match! goal with
| [|- _ = ?r] =>
assert(Hr: $r = (subp_app (subp_compose a b) t2))
end.
{
reflexivity.
}
rewrite Hr. clear Hr.
rewrite subp_compose_correct.
unfold compose.
rewrite <- e.
simpl.
ltac1:(rewrite Hai).
reflexivity.
}
}
{
ltac1:(exfalso).
apply Hnotin. clear Hnotin.
rewrite elem_of_dom.
rewrite map_lookup_filter.
rewrite lookup_union.
rewrite lookup_fmap.
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
rewrite Hci.
rewrite option_guard_False.
{
simpl.
rewrite option_guard_True.
eexists. reflexivity.
ltac1:(congruence).
}
{
intros HH. apply HH. clear HH.
rewrite elem_of_dom.
rewrite Hci. eexists. reflexivity.
}
}
}
}
}
}
{
simpl in *.
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
inversion H2t.
}
}
{
simpl in *.
rewrite lookup_fmap in H2t.
destruct (c !! i) eqn:Hci.
{
simpl in H2t.
ltac1:(simplify_eq/=).
destruct (decide (subp_app b t1 = t_over (bov_variable i))) as [Hiyes|Hino].
{
left.
exists t0.
split>[reflexivity|].
simpl.
remember (subp_compose a b) as ab.
assert(Hnice := Heqab).
unfold subp_compose in Heqab.
unfold subp_normalize in Heqab.
setoid_rewrite <- Heqab.
setoid_rewrite Hnice.
rewrite subp_compose_correct.
unfold compose.
rewrite Hiyes.
simpl.
ltac1:(rewrite Hai).
ltac1:(unshelve(eexists)).
{
rewrite elem_of_dom.
intros [p Hp].
rewrite map_lookup_filter in Hp.
rewrite lookup_union in Hp.
rewrite lookup_fmap in Hp.
simpl in *.
rewrite Hci in Hp.
rewrite map_lookup_filter in Hp.
rewrite Hbi in Hp.
simpl in Hp.
rewrite bind_Some in Hp.
destruct Hp as [? [_ ?]].
ltac1:(simplify_eq/=).
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros ? ?.
apply proof_irrelevance.
}
}
{
right.
split.
{
right.
exists t0.
split>[reflexivity|].
rewrite option_guard_False.
{ reflexivity. }
intros HH. apply HH. clear HH.
rewrite elem_of_dom.
rewrite map_lookup_filter.
simpl.
rewrite lookup_union.
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
rewrite lookup_fmap.
rewrite Hci.
simpl.
rewrite option_guard_True.
{ eexists. reflexivity. }
{
ltac1:(congruence).
}
}
{
exists (subp_app b t1).
ltac1:(replace(subp_app a (subp_app b t1)) with (((subp_app a) ∘ (subp_app b)) t1) by reflexivity).
rewrite <- subp_compose_correct.
split>[|reflexivity].
eexists.
split>[reflexivity|].
apply nesym in Hino.
exists Hino.
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
}
{
simpl in H2t.
inversion H2t.
}
}
}
{
destruct (b !! i) eqn:Hbi.
{
simpl in *.
destruct (c !! i) eqn:Hci.
{
simpl in H2t.
ltac1:(simplify_eq/=).
destruct (decide (t_over (bov_variable i) = subp_app b t1)).
{
right.
split.
{
left. reflexivity.
}
{
destruct H1t as [[H1t|H1t]|H1t].
{ inversion H1t. }
{ destruct H1t as [? [H1t ?]].
{ rewrite (left_id None union) in H1t. ltac1:(simplify_eq/=).
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
ltac1:(simplify_eq/=).
rewrite bind_None in H1.
remember (subp_compose a b) as ab.
assert (Hab := Heqab).
unfold subp_compose,subp_normalize in Hab.
ltac1:(setoid_rewrite <- Hab in H).
rewrite Heqab in H.
rewrite subp_compose_correct in H.
unfold compose in H.
rewrite <- e in H.
simpl in H.
ltac1:(rewrite Hai in H).
ltac1:(contradiction).
}
}
{
destruct H1t as [? [_ H1t]].
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
ltac1:(simplify_eq/=).
remember (subp_compose a b) as ab.
assert (Hab := Heqab).
unfold subp_compose,subp_normalize in Hab.
ltac1:(setoid_rewrite <- Hab in H).
rewrite Heqab in H.
rewrite subp_compose_correct in H.
unfold compose in H.
rewrite <- e in H.
simpl in H.
ltac1:(rewrite Hai in H).
ltac1:(contradiction).
}
}
}
{
right. split. left. reflexivity.
rewrite map_lookup_filter.
simpl.
rewrite fmap_Some.
setoid_rewrite lookup_union.
setoid_rewrite lookup_fmap.
setoid_rewrite map_lookup_filter.
exists (subp_app b t1).
split.
{
simpl.
rewrite Hbi.
simpl.
rewrite Hci.
rewrite option_guard_False.
{ simpl. rewrite option_guard_True. reflexivity.
ltac1:(congruence).
}
{
intros L. apply L. clear L.
rewrite elem_of_dom.
rewrite Hci.
exists t1. reflexivity.
}
}
{
fold (compose (subp_app a) (subp_app b) t1).
rewrite <- subp_compose_correct.
symmetry.
unfold subp_compose.
unfold subp_normalize.
simpl in *.
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
ltac1:(simplify_eq/=).
reflexivity.
}
}
}
{ simpl in H2t.
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
inversion H2t.
}
}
{
simpl in H2t.
rewrite lookup_fmap in H2t.
destruct (c !! i) eqn:Hci.
{
simpl in *.
ltac1:(simplify_eq/=).
destruct (decide (t_over (bov_variable i) = subp_app b t0)).
{
remember (subp_app (subp_compose a b) t0) as nice.
assert (Hnice := Heqnice).
unfold subp_compose in Hnice.
unfold subp_normalize in Hnice.
ltac1:(setoid_rewrite <- Hnice in H0).
rewrite Heqnice in H0.
rewrite subp_compose_correct in H0.
unfold compose in H0. simpl in H0.
rewrite <- e in H0.
simpl in H0.
ltac1:(rewrite Hai in H0).
simpl in H0.
ltac1:(contradiction H0).
reflexivity.
}
{
right.
split. left. reflexivity.
rewrite map_lookup_filter.
rewrite fmap_Some.
simpl.
setoid_rewrite bind_Some.
exists (subp_app b t0).
split.
{
exists (subp_app b t0).
split.
{
rewrite lookup_union.
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
rewrite lookup_fmap.
rewrite Hci.
simpl.
reflexivity.
}
{
rewrite option_guard_True.
reflexivity.
ltac1:(congruence).
}
}
{
fold (compose (subp_app a) (subp_app b) t0).
rewrite <- subp_compose_correct.
reflexivity.
}
}
}
{
simpl in *.
inversion H2t.
}
}
}
}
}
{
rewrite option_guard_True.
reflexivity.
ltac1:(congruence).
}
}
{
(* UFF, now the second inclusion *)
symmetry.
rewrite map_lookup_filter in Heql.
rewrite lookup_union in Heql.
rewrite map_lookup_filter in Heql.
rewrite lookup_fmap in Heql.
rewrite map_lookup_filter in Heql.
rewrite lookup_union in Heql.
simpl in Heql.
rewrite lookup_fmap in Heql.
rewrite map_lookup_filter in Heql.
simpl in Heql.
ltac1:(rewrite !(map_lookup_filter,lookup_union,lookup_fmap)).
destruct (a !! i) eqn:Hai, (b !! i) eqn:Hbi, (c !! i) eqn:Hci;
simpl in *;
assert(Hai' := Hai);
assert(Hbi' := Hbi);
assert(Hci' := Hci);
try (apply elem_of_dom_2 in Hai');
try (apply elem_of_dom_2 in Hbi');
try (apply elem_of_dom_2 in Hci');
try (apply not_elem_of_dom_1 in Hai');
try (apply not_elem_of_dom_1 in Hbi');
try (apply not_elem_of_dom_1 in Hci');
(repeat ((repeat (rewrite option_guard_decide));(repeat (rewrite option_guard_decide in Heql));ltac1:((repeat case_match); simplify_eq/=; simpl in *; try reflexivity)); try (solve [ltac1:(contradiction)]));
try reflexivity;
repeat (match! goal with
| [h: decide _ = _ |- _] => clear $h
end).
(* The above worked *)
Ltac2 just_specialize () :=
match! goal with
| [h: (?p -> ?q) |- _] =>
let f1 := ltac1:(P |- match goal with
| H : P |- _ => fail 1
| _ => idtac
end) in
(f1 (Ltac1.of_constr q));
let h := Control.hyp h in assert ($q) by (apply $h; ltac1:(tauto))
end.
Ltac2 mytac () := ((*try (just_specialize ());*) try (match! goal with
| [x : (TermOver BuiltinOrVar), h : (forall (_ : TermOver BuiltinOrVar), _) |- _] => let y := Control.hyp x in let h2 := Control.hyp h in let my := (Fresh.in_goal ident:(y)) in remember (t_over (bov_variable $y)) as $my;
apply $h2 in $h as $my
| [h: _ ∉ (dom _) |- _] => apply not_elem_of_dom_1 in $h
| [h: context [guard _] |- _] => rewrite option_guard_decide in $h
| [h1: (?m !! ?k = Some _), h2: context [?m !! ?k] |- _ ] => let h := Control.hyp h1 in rewrite $h in $h2
| [h1: (?m !! ?k = None), h2: context [?m !! ?k] |- _ ] => let h := Control.hyp h1 in rewrite $h in $h2
| [h: context [(union _ _) !! _ = _] |- _] => setoid_rewrite lookup_union in $h
| [h: context [(union _ _) = None] |- _] => setoid_rewrite union_None in $h
| [h: context [(union _ _) = Some _] |- _] => setoid_rewrite union_Some in $h
| [h: context[(filter _ _) !! _ = Some _] |- _] => setoid_rewrite map_lookup_filter in $h
| [h: context[(filter _ _) !! _ = None] |- _] => setoid_rewrite map_lookup_filter_None in $h
| [h: context[(_ <$> _) !! _ = _] |- _] => setoid_rewrite lookup_fmap in $h
| [h: decide _ = _ |- _] => clear $h
| [h: ~ (~ _) |- _] => apply dec_stable in $h
| [h: union _ _ = None |- _] => apply union_None in $h
| [h: _ <$> _ = None |- _] => apply fmap_None in $h
| [h: (ex _) |- _] => Std.destruct false [({Std.indcl_arg:=Std.ElimOnIdent(h); Std.indcl_eqn:=None; Std.indcl_as:=None; Std.indcl_in:=None})] None
| [h: (right _ = right _) |- _] => ltac1:(simplify_eq/=); clear $h
| [x : variable, h : (forall (_ : TermOver BuiltinOrVar), _) |- _] => let y := Control.hyp x in let h2 := Control.hyp h in
let myf := (Fresh.in_goal ident:(h)) in
let n := constr:($h2 (t_over (bov_variable $y))) in
let f1 := ltac1:(t |- learn_hyp (t)) in
f1 (Ltac1.of_constr n)
| [h: (forall _, _), a:_ |- _] => let f := ltac1:(ra rb|- learn_hyp (ra rb)) in f (Ltac1.of_constr (Control.hyp h)) (Ltac1.of_constr (Control.hyp a))
end); ltac1:(destruct_and?; (*destruct_or?; *)try congruence; (repeat case_match); simplify_eq/=); simpl in *;ltac1:(try tauto))
.
(* This loses information *)
Ltac2 apply_helper_lemma () :=
match! goal with
| [h: (t_over (bov_variable _) = subp_app _ _) |- _] => apply helper_lemma in $h
end
.
{ repeat (mytac ()); repeat (apply_helper_lemma ());
ltac1:(destruct_or!); (repeat (mytac ())).
}
{
apply dec_stable in n3.
repeat (mytac ()).
ltac1:(destruct_or!); (repeat (just_specialize ())); repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n6.
rewrite Heqab in n6.
rewrite subp_compose_correct in n6.
unfold compose in n6.
rewrite <- n3 in n6.
simpl in *.
ltac1:(rewrite Hai in n6).
repeat (mytac ()).
}
{
repeat (mytac ()).
ltac1:(destruct_or!); (repeat (just_specialize ())); repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
unfold compose in n4.
specialize (n0 (subp_app b t1) ltac:(tauto)).
apply dec_stable in n0.
ltac1:(contradiction n3).
}
{
apply dec_stable in n2.
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
remember ((subp_compose b c)) as bc.
assert (Hbc := Heqbc).
unfold subp_compose in Hbc.
unfold subp_normalize in Hbc.
ltac1:(setoid_rewrite <- Hbc in n0).
rewrite Heqbc in n0.
unfold compose in n4.
apply dec_stable in n3.
rewrite <- n3 in n4.
simpl in n4.
ltac1:(rewrite Hai in n4).
apply dec_stable in n4.
subst t.
ltac1:(contradiction n5).
reflexivity.
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n6.
rewrite Heqab in n6.
rewrite subp_compose_correct in n6.
unfold compose in n6.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
remember ((subp_compose b c)) as bc.
assert (Hbc := Heqbc).
unfold subp_compose in Hbc.
unfold subp_normalize in Hbc.
ltac1:(setoid_rewrite <- Hbc in n0).
rewrite Heqbc in n0.
unfold compose in n4.
ltac1:(contradiction).
}
{
remember ((subp_compose b c)) as bc.
assert (Hbc := Heqbc).
unfold subp_compose in Hbc.
unfold subp_normalize in Hbc.
setoid_rewrite <- Hbc in n0.
rewrite Heqbc in n0.
apply not_elem_of_dom_1 in n0.
remember (subp_app (subp_compose b c) (t_over (bov_variable i))).
assert(Htmp := Heqt1).
rewrite subp_compose_correct in Heqt1.
unfold compose in Heqt1.
simpl in Heqt1.
ltac1:(rewrite Hci' in Heqt1).
simpl in Heqt1.
ltac1:(rewrite Hbi in Heqt1).
simpl in Htmp.
ltac1:(rewrite n0 in Htmp).
ltac1:(simplify_eq/=).
}
{
remember ((subp_compose b c)) as bc.
assert (Hbc := Heqbc).
unfold subp_compose in Hbc.
unfold subp_normalize in Hbc.
setoid_rewrite <- Hbc in n0.
rewrite Heqbc in n0.
apply not_elem_of_dom_1 in n0.
apply dec_stable in n3.
subst t0.
apply dec_stable in n2.
simpl in *.
ltac1:(rewrite Hai in n2).
subst t.
ltac1:(contradiction).
}
{
repeat (mytac ()).
apply not_elem_of_dom_2 in Hci.
ltac1:(contradiction).
}
{
repeat (mytac ()).
clear n0.
apply not_elem_of_dom_2 in Hci.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
unfold compose in n4.
destruct t0; simpl in *.
{
destruct a0; simpl in *.
{ ltac1:(simplify_eq/=). }
{
destruct (b !! x) eqn:Hbx.
{
ltac1:(rewrite Hbx in n1).
ltac1:(rewrite Hbx in n0).
ltac1:(destruct_or!).
{ repeat (mytac ()). }
{
specialize (n0 t0 ltac:(tauto)).
ltac1:(contradiction).
}
}
{
ltac1:(rewrite Hbx in n1).
ltac1:(rewrite Hbx in n0).
ltac1:(destruct_or!)>[repeat (mytac ())|].
specialize (n0 (t_over (bov_variable x)) ltac:(tauto)).
ltac1:(contradiction).
}
}
}
{
ltac1:(destruct_or!)>[repeat (mytac ())|].
specialize (n0 (t_term s (map (subp_app b) l)) ltac:(tauto)).
ltac1:(contradiction).
}
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
unfold compose in n4.
ltac1:(destruct_or!)>[repeat (mytac ())|].
rewrite <- n1 in n4.
simpl in n4.
ltac1:(rewrite Hai in n4).
ltac1:(simplify_eq/=).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n5.
rewrite Heqab in n5.
rewrite subp_compose_correct in n5.
unfold compose in n5.
remember ((subp_compose b c)) as bc.
assert (Hbc := Heqbc).
unfold subp_compose in Hbc.
unfold subp_normalize in Hbc.
setoid_rewrite <- Hbc in n0.
rewrite Heqbc in n0.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
unfold compose in n4.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n2.
rewrite Heqab in n2.
rewrite subp_compose_correct in n2.
unfold compose in n2.
ltac1:(destruct_or!)>[repeat (mytac ())|].
specialize (n0 (subp_app b t0) ltac:(tauto)).
apply dec_stable in n0.
rewrite <- n0 in n2.
simpl in *.
ltac1:(rewrite Hai in n2).
subst t.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n2.
rewrite Heqab in n2.
rewrite subp_compose_correct in n2.
ltac1:(destruct_or!)>[repeat (mytac ())|].
specialize (n0 (subp_app b t0) ltac:(tauto)).
apply dec_stable in n0.
unfold compose in n2.
rewrite <- n0 in n2.
simpl in *.
ltac1:(rewrite Hai in n2).
subst t.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n2.
rewrite Heqab in n2.
rewrite subp_compose_correct in n2.
unfold compose in n2.
ltac1:(contradiction).
}
{
repeat (mytac ()).
apply not_elem_of_dom_2 in Hci.
ltac1:(contradiction).
}
{
apply not_elem_of_dom_2 in Hbi.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n3.
rewrite Heqab in n3.
rewrite subp_compose_correct in n3.
unfold compose in n3.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n1.
rewrite Heqab in n1.
rewrite subp_compose_correct in n1.
unfold compose in n1.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n.
rewrite Heqab in n.
rewrite subp_compose_correct in n.
unfold compose in n.
ltac1:(contradiction).
}
}
}
Unshelve.
{
repeat (mytac ()).
apply not_elem_of_dom_2 in x0.
ltac1:(contradiction).
}
Qed.
prelude
spec
substitution_parallel
basic_properties
termoverbov_subst
termoverbov_subst_properties
.
From Coq Require Import Logic.Classical_Prop.
Definition subtmm_closed {Σ : StaticModel} (s : SubP) :=
forall k v, s !! k = Some v -> vars_of v = ∅
.
Lemma subp_app_empty
{Σ : StaticModel}
(φ : TermOver BuiltinOrVar)
:
subp_app ∅ φ = φ
.
Proof.
induction φ; simpl.
{
destruct a; simpl.
{ reflexivity. }
{
ltac1:(case_match).
{ ltac1:(rewrite lookup_empty in H). inversion H. }
{
reflexivity.
}
}
}
{
apply f_equal.
revert H.
induction l; intros H; simpl in *.
{
reflexivity.
}
{
rewrite Forall_cons_iff in H.
destruct H as [H1 H2].
specialize (IHl H2).
clear H2.
rewrite H1.
rewrite IHl.
reflexivity.
}
}
Qed.
Lemma subp_app_closed
{Σ : StaticModel}
(sub_mm : SubP)
(φ : TermOver BuiltinOrVar)
:
vars_of φ = ∅ ->
subp_app sub_mm φ = φ
.
Proof.
induction φ; intros HH; simpl in *.
{
destruct a; simpl in *.
{ reflexivity. }
{
unfold vars_of in HH; simpl in HH.
unfold vars_of in HH; simpl in HH.
ltac1:(set_solver).
}
}
{
apply f_equal.
revert HH H.
induction l; intros HH H; simpl in *.
{ reflexivity. }
{
rewrite Forall_cons_iff in H.
destruct H as [H1 H2].
rewrite vars_of_t_term in HH.
rewrite fmap_cons in HH.
rewrite union_list_cons in HH.
specialize (IHl ltac:(set_solver)).
specialize (H1 ltac:(set_solver)).
rewrite H1.
rewrite (IHl H2).
reflexivity.
}
}
Qed.
Lemma subp_app_almost_closed
{Σ : StaticModel}
(s : SubP)
(φ : TermOver BuiltinOrVar)
:
vars_of φ ## subp_dom s ->
subp_app s φ = φ
.
Proof.
unfold SubP in *.
revert s.
induction φ; intros ss HH; simpl in *.
{
destruct a; simpl in *.
{ reflexivity. }
{
unfold vars_of in HH; simpl in HH.
unfold vars_of in HH; simpl in HH.
rewrite disjoint_singleton_l in HH.
unfold subp_dom in HH.
destruct (ss !! x) eqn:Heq.
{
apply elem_of_dom_2 in Heq.
ltac1:(contradiction HH).
}
{
ltac1:(rewrite Heq).
reflexivity.
}
}
}
{
apply f_equal.
revert HH H.
induction l; intros HH H; simpl in *.
{ reflexivity. }
{
rewrite Forall_cons_iff in H.
destruct H as [H1 H2].
rewrite vars_of_t_term in HH.
rewrite fmap_cons in HH.
rewrite union_list_cons in HH.
specialize (IHl ltac:(set_solver)).
specialize (H1 ltac:(set_solver)).
rewrite H1.
rewrite (IHl H2).
reflexivity.
ltac1:(set_solver).
}
}
Qed.
Lemma subp_app_empty'
{Σ : StaticModel}
:
subp_app ∅ = id
.
Proof.
apply functional_extensionality.
apply subp_app_empty.
Qed.
Lemma subp_app_insert0
{Σ : StaticModel}
(s : SubP)
(x : variable)
(v : TermOver BuiltinOrVar)
:
vars_of v ## subp_dom s ->
subp_app (<[x:=v]>s)
= (subp_app s) ∘ (fun φ => TermOverBoV_subst φ x v)
.
Proof.
unfold SubP in *.
intros HH.
apply functional_extensionality.
intros φ.
revert s x v HH.
induction φ; intros ss x v HH; simpl.
{
destruct a; simpl.
{
reflexivity.
}
{
destruct (decide (x = x0)).
{
subst.
ltac1:(rewrite lookup_insert).
symmetry.
apply subp_app_almost_closed.
exact HH.
}
{
ltac1:(rewrite lookup_insert_ne).
{
ltac1:(congruence).
}
{
ltac1:(case_match).
{
simpl.
ltac1:(rewrite H).
reflexivity.
}
{
rewrite subp_app_almost_closed.
reflexivity.
unfold vars_of; simpl.
unfold vars_of; simpl.
unfold subp_dom.
apply not_elem_of_dom_2 in H.
ltac1:(set_solver).
}
}
}
}
}
{
apply f_equal.
revert H.
induction l; intros H; simpl in *.
{ reflexivity. }
{
rewrite Forall_cons_iff in H.
destruct H as [H1 H2].
rewrite (IHl H2).
rewrite H1.
reflexivity.
assumption.
}
}
Qed.
Lemma subp_normalize_normalize
{Σ : StaticModel}
:
subp_normalize ∘ subp_normalize
= subp_normalize
.
Proof.
apply functional_extensionality.
unfold compose.
intros s.
unfold subp_normalize.
rewrite map_filter_filter.
simpl.
apply map_filter_ext.
intros i x Hsix.
split.
{
intros [H1 H2].
simpl.
exact H2.
}
{
intros H.
split; exact H.
}
Qed.
Lemma subp_normalize_normal
{Σ : StaticModel}
(s : SubP)
:
subp_is_normal s ->
subp_normalize s = s
.
Proof.
intros H.
unfold subp_is_normal in H.
exact H.
Qed.
Lemma subp_id_compose
{Σ : StaticModel}
(s : SubP)
:
subp_is_normal s ->
subp_compose subp_id s = s .
Proof.
intros Hnormal.
unfold subp_id.
unfold subp_compose.
rewrite map_filter_empty.
rewrite (left_id empty union).
ltac1:(rewrite subp_app_empty').
rewrite map_fmap_id.
rewrite subp_normalize_normal.
{ reflexivity. }
{ exact Hnormal. }
Qed.
Lemma subp_compose_id
{Σ : StaticModel}
(s : SubP)
:
subp_is_normal s ->
subp_compose s subp_id = s .
Proof.
intros Hnormal.
unfold subp_id.
unfold subp_compose.
rewrite fmap_empty.
rewrite (right_id empty union).
unfold subp_dom.
unfold SubP in *.
rewrite map_filter_id.
{
rewrite subp_normalize_normal.
{ reflexivity. }
{ exact Hnormal. }
}
{
intros i x Hsix.
rewrite dom_empty.
apply not_elem_of_empty.
}
Qed.
Lemma subp_app_singleton
{Σ : StaticModel}
x p
:
subp_app {[x:=p]} = (fun q => TermOverBoV_subst q x p)
.
Proof.
ltac1:(rewrite - insert_empty).
ltac1:(rewrite subp_app_insert0).
unfold subp_dom.
ltac1:(rewrite dom_empty_L).
ltac1:(set_solver).
ltac1:(rewrite subp_app_empty').
unfold compose.
apply functional_extensionality.
intros y.
reflexivity.
Qed.
Lemma subp_app_union_comm
{Σ : StaticModel}
(a b : gmap variable (TermOver BuiltinOrVar))
:
subp_dom a ## subp_dom b ->
subp_app (a ∪ b) = subp_app (b ∪ a)
.
Proof.
intros HH0.
apply functional_extensionality.
intros phi.
revert a b HH0.
induction phi; intros aa bb HH0; simpl in *.
{
destruct a.
{ reflexivity. }
{
ltac1:(repeat case_match).
{
ltac1:(rewrite lookup_union in H).
ltac1:(rewrite lookup_union in H0).
destruct (aa !! x) eqn:Hax,
(bb !! x) eqn:Hbx.
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
ltac1:(apply elem_of_dom_2 in Hax).
ltac1:(apply elem_of_dom_2 in Hbx).
unfold subp_dom in *.
unfold subp_codom in *.
ltac1:(set_solver).
}
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
ltac1:(apply elem_of_dom_2 in Hax).
unfold subp_dom in *.
unfold subp_codom in *.
ltac1:(set_solver).
}
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
ltac1:(apply elem_of_dom_2 in Hbx).
unfold subp_dom in *.
unfold subp_codom in *.
ltac1:(set_solver).
}
{
inversion H.
}
}
{
ltac1:(rewrite lookup_union in H).
ltac1:(rewrite lookup_union in H0).
destruct (aa !! x) eqn:Hax,
(bb !! x) eqn:Hbx.
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
}
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
}
{
inversion H; subst; clear H.
inversion H0; subst; clear H0.
}
{
inversion H.
}
}
{
ltac1:(rewrite lookup_union in H).
ltac1:(rewrite lookup_union in H0).
destruct (aa !! x) eqn:Hax,
(bb !! x) eqn:Hbx.
{
inversion H; subst; clear H.
}
{
inversion H; subst; clear H.
}
{
inversion H; subst; clear H.
}
{
inversion H0.
}
}
{
reflexivity.
}
}
}
{
apply f_equal.
apply map_ext_Forall.
rewrite Forall_forall in H.
rewrite Forall_forall.
intros x Hx.
specialize (H x Hx).
apply H.
apply HH0.
}
Qed.
Lemma subp_compose_helper_1
{Σ : StaticModel}
(b c : SubP)
:
subp_codom b ## subp_dom c ->
subp_app c <$> b = b
.
Proof.
intros Hdisj.
apply map_eq_iff.
intros i.
destruct (b !! i) eqn:Hbi.
{
rewrite lookup_fmap.
ltac1:(rewrite Hbi).
simpl.
apply f_equal.
apply subp_app_almost_closed.
unfold SubP in *.
ltac1:(assert(vars_of t ⊆ subp_codom b)).
{
unfold subp_codom.
rewrite elem_of_subseteq.
intros x Hx.
rewrite elem_of_union_list.
exists (vars_of t).
split>[|exact Hx].
rewrite elem_of_list_fmap.
exists t.
split>[reflexivity|].
rewrite elem_of_elements.
ltac1:(rewrite elem_of_map_img).
exists i.
exact Hbi.
}
ltac1:(set_solver).
}
{
rewrite lookup_fmap.
ltac1:(rewrite Hbi).
reflexivity.
}
Qed.
Lemma subp_app_union
{Σ : StaticModel}
(b c : gmap variable (TermOver BuiltinOrVar))
:
subp_codom b ## subp_dom c ->
subp_app (b ∪ c) = (subp_app c) ∘ (subp_app b)
.
Proof.
intros HH.
apply functional_extensionality.
intros phi.
revert b c HH.
induction phi; intros b c HH.
{
simpl.
ltac1:(repeat case_match; simplify_eq/=; try reflexivity).
{
unfold SubP in *.
ltac1:(erewrite lookup_union_Some_l in H0)>[|apply H1].
apply (inj Some) in H0.
subst.
symmetry.
apply subp_app_almost_closed.
(* ltac1:(eapply lookup_union_Some_l in H1). *)
ltac1:(assert(vars_of t ⊆ subp_codom b)).
{
unfold subp_codom.
rewrite elem_of_subseteq.
intros y Hy.
rewrite elem_of_union_list.
exists (vars_of t).
split>[|exact Hy].
rewrite elem_of_list_fmap.
exists t.
split>[reflexivity|].
rewrite elem_of_elements.
ltac1:(rewrite elem_of_map_img).
exists x.
exact H1.
}
ltac1:(set_solver).
}
{
ltac1:(rewrite lookup_union_r in H0).
exact H1.
ltac1:(rewrite H0).
reflexivity.
}
{
ltac1:(exfalso).
unfold SubP in *.
rewrite lookup_union in H0.
rewrite H1 in H0.
unfold union,option_union,union_with,option_union_with in H0.
ltac1:(case_match; simplify_eq/=).
}
{
unfold SubP in *.
rewrite lookup_union in H0.
rewrite H1 in H0.
unfold union,option_union,union_with,option_union_with in H0.
ltac1:(case_match; simplify_eq/=).
reflexivity.
}
}
{
simpl.
f_equal.
clear s.
ltac1:(replace (map) with (@fmap list list_fmap) by reflexivity).
rewrite <- list_fmap_compose.
apply list_fmap_ext.
intros i x Hix.
rewrite Forall_forall in H.
specialize (H x).
ltac1:(ospecialize (H _)).
{
rewrite elem_of_list_lookup.
exists i.
exact Hix.
}
specialize (H _ _ HH).
exact H.
}
Qed.
Lemma subp_union_is_compose__sometimes_1
{Σ : StaticModel}
(a b : gmap variable (TermOver BuiltinOrVar))
:
(subp_app a <$> b) = b ->
subp_is_normal a ->
subp_is_normal b ->
b ∪ a = subp_compose a b
.
Proof.
intros HH1 Hna Hnb.
unfold subp_compose.
ltac1:(rewrite -> HH1 at 1).
unfold subp_dom.
apply map_eq.
intros i.
unfold SubP in *.
rewrite lookup_union.
unfold subp_normalize.
rewrite map_lookup_filter.
simpl.
rewrite lookup_union.
rewrite map_lookup_filter.
destruct
(b !! i) eqn:Hbi,
(a !! i) eqn:Hai.
{
simpl.
rewrite option_guard_False.
{
simpl.
rewrite option_guard_decide.
ltac1:(case_match).
{
clear H.
reflexivity.
}
{
ltac1:(exfalso).
clear H.
apply dec_stable in n.
subst t.
unfold subp_is_normal in Hnb.
rewrite <- Hnb in Hbi.
unfold subp_normalize in Hbi.
rewrite map_lookup_filter in Hbi.
rewrite bind_Some in Hbi.
destruct Hbi as [v [H1v H2v]].
simpl in *.
rewrite option_guard_decide in H2v.
ltac1:(case_match; simplify_eq/=).
}
}
{
rewrite elem_of_dom.
rewrite Hbi.
intros Ht. apply Ht. clear Ht.
exists t. reflexivity.
}
}
{
simpl.
rewrite (right_id None union).
rewrite option_guard_True.
{ reflexivity. }
{
intros HContra.
subst t.
assert (Hbi' := Hbi).
unfold subp_is_normal in Hnb.
rewrite <- Hnb in Hbi.
unfold subp_normalize in Hbi.
rewrite map_lookup_filter in Hbi.
rewrite Hbi' in Hbi.
simpl in Hbi.
rewrite bind_Some in Hbi.
destruct Hbi as [HContra [_ ?]].
ltac1:(congruence).
}
}
{
rewrite (right_id None union).
rewrite (left_id None union).
simpl.
rewrite option_guard_True.
{
simpl.
rewrite option_guard_decide.
ltac1:(case_match).
{
reflexivity.
}
{
ltac1:(contradiction n).
clear n H.
intros Hc.
subst t.
assert (Hai' := Hai).
unfold subp_is_normal in Hna.
rewrite <- Hna in Hai.
unfold subp_normalize in Hai.
rewrite map_lookup_filter in Hai.
rewrite Hai' in Hai.
simpl in Hai.
rewrite bind_Some in Hai.
destruct Hai as [HContra [_ ?]].
ltac1:(congruence).
}
}
{
rewrite elem_of_dom.
rewrite Hbi.
intros [? HContra].
inversion HContra.
}
}
{
simpl.
reflexivity.
}
Qed.
Lemma subp_compose_correct
{Σ : StaticModel}
(a b : SubP)
:
subp_app (subp_compose a b) = (subp_app a) ∘ (subp_app b)
.
Proof.
unfold subp_compose.
unfold compose.
apply functional_extensionality.
intros p.
revert a b.
induction p; intros aa bb; simpl.
{
destruct a; simpl in *.
{ reflexivity. }
{
unfold subp_normalize.
rewrite map_filter_union.
{
ltac1:(rewrite lookup_union).
ltac1:(rewrite map_lookup_filter).
unfold SubP in *.
ltac1:(rewrite map_lookup_filter).
ltac1:(rewrite map_lookup_filter).
ltac1:(rewrite lookup_fmap).
destruct (bb!!x) eqn:Hbx.
{
simpl.
destruct (aa !! x) eqn:Hax.
{
simpl.
rewrite option_guard_False.
{ simpl.
destruct (decide (t_over (bov_variable x) = subp_app aa t)).
{
rewrite option_guard_False.
{ simpl. ltac1:(congruence). }
{ simpl. ltac1:(congruence). }
}
{ rewrite option_guard_True.
simpl. reflexivity.
ltac1:(congruence).
}
}
{
intros HContra.
apply HContra.
unfold subp_dom.
ltac1:(rewrite elem_of_dom).
rewrite Hbx.
eexists.
reflexivity.
}
}
{
simpl.
destruct (decide (t_over (bov_variable x) = subp_app aa t)).
{
rewrite option_guard_False.
{ simpl. ltac1:(congruence). }
{ simpl. ltac1:(congruence). }
}
{
rewrite option_guard_True.
{ simpl. reflexivity. }
{ ltac1:(congruence). }
}
}
}
{
simpl.
destruct (aa!!x) eqn:Hax.
{
ltac1:(rewrite Hax).
simpl.
rewrite option_guard_True.
{
simpl.
destruct (decide (t = t_over (bov_variable x))).
{
subst.
rewrite option_guard_False.
{ simpl. reflexivity. }
{ ltac1:(congruence). }
}
{
rewrite option_guard_True.
{ simpl. reflexivity. }
{ ltac1:(congruence). }
}
}
{
unfold subp_dom.
ltac1:(rewrite elem_of_dom).
rewrite Hbx.
intros [? H].
inversion H.
}
}
{
simpl.
ltac1:(rewrite Hax).
reflexivity.
}
}
}
{
apply map_disjoint_spec.
intros i x' y' Hx' Hy'.
rewrite map_lookup_filter in Hx'.
rewrite lookup_fmap in Hy'.
destruct (aa !! i) eqn:Hai.
{
simpl in *.
destruct (bb !! i) eqn:Hbi.
{
simpl in *.
ltac1:(rewrite Hai in Hx').
simpl in *.
ltac1:(rewrite Hbi in Hy').
simpl in *.
ltac1:(simplify_eq/=).
ltac1:(simplify_option_eq).
unfold subp_dom in *.
apply H.
ltac1:(rewrite elem_of_dom).
ltac1:(rewrite Hbi).
eexists.
reflexivity.
}
{
ltac1:(rewrite Hai in Hx').
simpl in Hx'.
ltac1:(rewrite Hbi in Hy').
simpl in Hy'.
inversion Hy'.
}
}
{
ltac1:(rewrite Hai in Hx').
simpl in Hx'.
inversion Hx'.
}
}
}
}
{
apply f_equal.
ltac1:(replace (map) with (@fmap list list_fmap) by reflexivity).
rewrite Forall_forall in H.
rewrite <- list_fmap_compose.
apply list_fmap_ext.
intros i x Hix.
apply H.
rewrite elem_of_list_lookup.
exists i.
exact Hix.
}
Qed.
Lemma helper_lemma {Σ : StaticModel}:
forall x m t, t_over (bov_variable x) = subp_app m t -> exists y, t = t_over (bov_variable y)
.
Proof.
{
intros x' m' t' HH.
destruct t'; simpl in HH.
{ destruct a; simpl in HH.
inversion HH.
exists x. reflexivity.
}
{ inversion HH. }
}
Qed.
Lemma subp_compose_assoc
{Σ : StaticModel}
(a b c : SubP)
:
(*
subp_is_normal a -> *)
subp_is_normal b ->
(* subp_is_normal c ->*)
subp_compose (subp_compose a b) c = subp_compose a (subp_compose b c)
.
Proof.
(* intros Hnormala. *)
intros Hnormalb.
(* intros Hnormalc.*)
unfold SubP in *.
unfold subp_compose.
unfold subp_dom.
unfold SubP in *.
unfold subp_normalize.
apply map_eq.
{
intros i.
lazy_match! goal with
| [|- ?l = _] =>
destruct ($l) eqn:Heql
end.
{
symmetry.
ltac1:(rewrite map_lookup_filter in Heql).
rewrite bind_Some in Heql.
destruct Heql as [t' [H1t' H2t']].
simpl in *.
rewrite map_lookup_filter.
rewrite bind_Some.
simpl in *.
ltac1:(simplify_option_eq).
exists t.
split.
{
rewrite lookup_union in H1t'.
rewrite union_Some in H1t'.
rewrite lookup_union.
rewrite union_Some.
rewrite map_lookup_filter in H1t'.
rewrite map_lookup_filter.
rewrite bind_Some in H1t'.
rewrite bind_Some.
simpl in *.
destruct H1t' as [H1t|H1t].
{
destruct H1t as [x [H1x H2x]].
rewrite map_lookup_filter in H1x.
rewrite bind_Some in H1x.
destruct H1x as [y [H1y H2y]].
rewrite bind_Some in H2y.
destruct H2y as [pf [_ ?]].
simpl in *.
apply (inj Some) in H1.
subst y.
rewrite lookup_union in H1y.
rewrite map_lookup_filter in H1y.
rewrite lookup_fmap in H1y.
rewrite union_Some in H1y.
simpl in *.
destruct (a !! i) eqn:Hai.
{
rewrite bind_Some in H2x.
destruct H2x as [? [_ Hxt]].
apply (inj Some) in Hxt.
subst x.
simpl.
setoid_rewrite bind_Some.
lazy_match! Constr.type (Control.hyp @H1y) with
| (_ \/ ?rr) => destruct (classic $rr) as [Hyes|Hno]
end.
{
destruct H1y as [H1y|H1y].
{
rewrite bind_Some in H1y.
destruct H1y as [? [_ Htmp]].
rewrite bind_Some in Htmp.
destruct Htmp as [? [_ Htmp]].
apply (inj Some) in Htmp.
subst t.
apply not_elem_of_dom_1 in x1 as Hb.
apply not_elem_of_dom_1 in x0 as Hc.
rewrite lookup_fmap.
rewrite map_lookup_filter.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
simpl.
setoid_rewrite lookup_union.
setoid_rewrite map_lookup_filter.
rewrite Hb.
simpl.
setoid_rewrite lookup_fmap.
rewrite Hc.
simpl.
destruct Hyes as [H1y H2y].
simpl in *.
clear H1y.
rewrite Hb in H2y.
simpl in H2y.
inversion H2y.
}
{
destruct H1y as [H1 Htmp].
simpl in H1.
clear H1.
ltac1:(setoid_rewrite bind_None).
destruct (b !! i) eqn:Hbi.
{
simpl in *.
ltac1:(simplify_eq/=).
destruct Hyes as [H1 H2].
clear H1 H2.
apply not_elem_of_dom_1 in x0 as Hci.
setoid_rewrite lookup_fmap.
setoid_rewrite map_lookup_filter.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite lookup_union.
setoid_rewrite lookup_fmap.
setoid_rewrite Hci.
simpl.
setoid_rewrite (right_id None union).
setoid_rewrite map_lookup_filter.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite Hbi.
simpl.
right.
split.
left.
unfold guard_or.
ltac1:(case_match; try reflexivity).
ltac1:(exfalso; clear H1; rename n into H1).
rewrite elem_of_dom in H1.
rewrite map_lookup_filter in H1.
rewrite lookup_union in H1.
rewrite lookup_fmap in H1.
rewrite Hci in H1.
simpl in H1.
rewrite map_lookup_filter in H1.
rewrite Hbi in H1.
simpl in H1.
apply H1.
eexists.
rewrite bind_Some.
eexists.
rewrite bind_Some.
rewrite (right_id None union).
split.
{
erewrite option_guard_True_pi.
{ reflexivity. }
{ intros pfa pfb. apply proof_irrelevance. }
}
{
ltac1:(unshelve(eexists)).
{
unfold subp_is_normal in Hnormalb.
rewrite <- Hnormalb in Hbi.
unfold subp_normalize in Hbi.
rewrite map_lookup_filter in Hbi.
rewrite bind_Some in Hbi.
destruct Hbi as [bv [H1bv H2bv]].
rewrite bind_Some in H2bv.
simpl in H2bv.
destruct H2bv as [? [_ ?]].
ltac1:(congruence).
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
{
exists t1.
split>[|reflexivity].
exists t1.
(repeat split); try reflexivity.
{
exists t1.
split>[reflexivity|].
exists x0.
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
{
ltac1:(unshelve(eexists)).
{
intros HContra.
subst t1.
unfold subp_is_normal in Hnormalb.
rewrite <- Hnormalb in Hbi.
unfold subp_normalize in Hbi.
rewrite map_lookup_filter in Hbi.
rewrite bind_Some in Hbi.
destruct Hbi as [p [H1p H2p]].
rewrite bind_Some in H2p.
simpl in H2p.
destruct H2p as [? [_ ?]].
ltac1:(simplify_eq/=).
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
}
}
{
destruct Hyes as [H1 H2].
inversion H2.
}
}
}
{
apply not_and_or in Hno.
destruct (b !! i) eqn:Hbi.
{
simpl in *.
destruct H1y as [H1y|H1y].
{
rewrite bind_Some in H1y.
destruct H1y as [? [_ ?]].
apply not_elem_of_dom_1 in x.
ltac1:(congruence).
}
{
destruct H1y as [H1y Heq].
ltac1:(simplify_eq/=).
clear H1y.
destruct Hno as [Hno|Hno].
{
apply not_eq_None_Some in Hno.
destruct Hno as [q Hq].
rewrite bind_Some in Hq.
destruct Hq as [? [_ Htmp]].
ltac1:(simplify_eq/=).
apply not_elem_of_dom_1 in x.
ltac1:(congruence).
}
{
ltac1:(contradiction Hno).
reflexivity.
}
}
}
{
simpl in *.
destruct H1y as [H1y|H1y],
Hno as [Hno|Hno].
{
rewrite bind_Some in H1y.
destruct H1y as [? [_ Htmp]].
ltac1:(simplify_eq/=).
apply not_eq_None_Some in Hno.
destruct Hno as [q Hq].
rewrite bind_Some in Hq.
destruct Hq as [? [_ ?]].
ltac1:(simplify_eq/=).
apply not_elem_of_dom_1 in x0 as Hci.
setoid_rewrite lookup_fmap.
setoid_rewrite map_lookup_filter.
simpl.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite lookup_union.
setoid_rewrite lookup_fmap.
rewrite Hci.
simpl.
left.
exists q.
split>[reflexivity|].
ltac1:(unshelve(eexists)).
{
rewrite elem_of_dom.
rewrite map_lookup_filter.
intros [p Hp].
rewrite bind_Some in Hp.
destruct Hp as [o Ho].
rewrite lookup_union in Ho.
rewrite lookup_fmap in Ho.
destruct Ho as [H1o H2o].
rewrite map_lookup_filter in H1o.
rewrite Hci in H1o.
simpl in *.
rewrite Hbi in H1o.
simpl in H1o.
inversion H1o.
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
{
rewrite bind_Some in H1y.
clear Hno.
destruct H1y as [? [_ ?]].
ltac1:(simplify_eq/=).
apply not_elem_of_dom_1 in x0 as Hci.
setoid_rewrite lookup_fmap.
setoid_rewrite map_lookup_filter.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
setoid_rewrite bind_None.
setoid_rewrite lookup_union.
setoid_rewrite lookup_fmap.
rewrite Hci.
simpl.
setoid_rewrite map_lookup_filter.
rewrite Hbi.
simpl.
left.
exists t.
split>[reflexivity|].
ltac1:(unshelve(eexists)).
{
apply not_elem_of_dom_2.
rewrite map_lookup_filter_None.
rewrite lookup_union.
rewrite lookup_fmap.
rewrite Hci.
simpl.
rewrite (right_id None union).
setoid_rewrite (right_id None union).
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
left.
reflexivity.
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
{
destruct H1y as [? H1y].
inversion H1y.
}
{
destruct H1y as [? H1y].
inversion H1y.
}
}
}
}
{
simpl in *.
right.
split>[reflexivity|].
destruct H1y as [H1y|[H1y H2y]].
{
inversion H1y.
}
{
destruct (b !! i) eqn:Hbi.
{
simpl in *.
apply (inj Some) in H2y.
subst x.
simpl in *.
rewrite lookup_fmap.
rewrite map_lookup_filter.
simpl.
rewrite fmap_Some.
rewrite bind_Some in H2x.
destruct H2x as [pf1 [_ H1]].
apply (inj Some) in H1.
subst t.
exists t0.
split>[|reflexivity].
rewrite bind_Some.
setoid_rewrite lookup_union.
setoid_rewrite lookup_fmap.
apply not_elem_of_dom_1 in pf1 as pf1'.
rewrite pf1'.
simpl.
setoid_rewrite (right_id None union).
setoid_rewrite map_lookup_filter.
simpl.
rewrite Hbi.
simpl.
exists t0.
split.
{
rewrite bind_Some.
exists pf1.
split>[|reflexivity].
apply option_guard_True_pi.
intros pf8 pf9.
apply proof_irrelevance.
}
{
rewrite bind_Some.
ltac1:(unshelve(eexists)).
{
intros HContra.
subst t0.
simpl in *.
ltac1:(rewrite Hai in H).
ltac1:(contradiction H).
reflexivity.
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
}
{
simpl in H2y.
inversion H2y.
}
}
}
}
{
destruct H1t as [H1t H2t].
rewrite bind_None in H1t.
rewrite map_lookup_filter in H1t.
rewrite bind_None in H1t.
rewrite lookup_union in H1t.
rewrite lookup_fmap in H1t.
rewrite map_lookup_filter in H1t.
setoid_rewrite lookup_fmap.
setoid_rewrite bind_None.
destruct (a !! i) eqn:Hai.
{
rewrite map_lookup_filter.
simpl.
rewrite lookup_union.
rewrite lookup_fmap.
rewrite map_lookup_filter.
rewrite fmap_Some.
setoid_rewrite bind_Some.
setoid_rewrite bind_Some.
destruct (b !! i) eqn:Hbi.
{
simpl.
destruct (c !! i) eqn:Hci.
{
simpl.
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
ltac1:(simplify_eq/=).
rewrite union_None in H1t.
destruct H1t as [[H1t|H1t]|H1t].
{
destruct H1t as [? H1t].
inversion H1t.
}
{
destruct H1t as [p [H1p H2p]].
rewrite union_Some in H1p.
rewrite bind_Some in H1p.
destruct H1p as [H1p|H1p].
{
destruct H1p as [H1p [_ ?]].
apply not_elem_of_dom_1 in H1p.
ltac1:(congruence).
}
{
destruct H1p as [_ H1p].
ltac1:(simplify_eq/=).
destruct (decide (subp_app b t2 = t_over (bov_variable i))).
{
left.
exists t0.
split>[reflexivity|].
remember (subp_compose a b) as ab.
assert(Heqab' := Heqab).
unfold subp_compose in Heqab'.
unfold subp_normalize in Heqab'.
setoid_rewrite <- Heqab.
clear Heqab'.
subst ab.
rewrite subp_compose_correct.
unfold compose.
rewrite e.
simpl.
ltac1:(rewrite Hai).
ltac1:(unshelve(eexists)).
{
rewrite elem_of_dom.
rewrite map_lookup_filter.
simpl.
rewrite lookup_union.
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
rewrite option_guard_False.
{ simpl. rewrite lookup_fmap. rewrite Hci. simpl.
rewrite option_guard_False.
{ intros [u Hu].
simpl in Hu.
inversion Hu.
}
{ ltac1:(congruence). }
}
rewrite elem_of_dom.
rewrite Hci.
intros Hu. apply Hu. exists t2. reflexivity.
}
{
split.
{
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
{ reflexivity. }
}
}
{
right.
split.
{ right.
exists t0.
split>[reflexivity|].
rewrite option_guard_False.
{ simpl. reflexivity. }
{
intros HC. apply HC. clear HC.
rewrite elem_of_dom.
rewrite map_lookup_filter.
rewrite lookup_union.
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
rewrite lookup_fmap.
rewrite Hci.
simpl.
rewrite option_guard_False.
{ simpl. rewrite option_guard_True.
eexists. reflexivity.
ltac1:(congruence).
}
{
rewrite elem_of_dom.
intros HH. apply HH. clear HH.
rewrite Hci.
eexists. reflexivity.
}
}
}
{
exists (subp_app b t2).
split.
{
exists (subp_app b t2).
repeat split.
{
rewrite option_guard_False.
{ simpl. reflexivity. }
{
rewrite elem_of_dom.
rewrite Hci.
intros HContra. apply HContra.
exists t2.
reflexivity.
}
}
{
apply nesym in n.
exists n.
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb. apply proof_irrelevance.
}
}
{
ltac1:(replace (subp_app a (subp_app b t2))
with (((subp_app a) ∘ (subp_app b)) t2)
by reflexivity).
rewrite <- subp_compose_correct.
reflexivity.
}
}
}
}
} {
destruct H1t as [p [H1p H2p]].
rewrite bind_Some in H1p.
destruct H1p as [q [H1q H2q]].
rewrite bind_Some in H2q.
destruct H2q as [Hq [_ ?]].
ltac1:(simplify_eq/=).
rewrite union_Some in H1q.
destruct H1q as [H1q|H1q].
{
rewrite bind_Some in H1q.
destruct H1q as [Hib' [_ ?]].
apply not_elem_of_dom_1 in Hib'.
ltac1:(congruence).
}
{
destruct H1q as [_ H1q].
ltac1:(simplify_eq/=).
(* I think that H is just a tautology.
*)
clear H.
destruct (decide (i ∈ dom (filter (λ kv : variable * TermOver' BuiltinOrVar, t_over (bov_variable kv.1) ≠ kv.2)
(filter (λ kv : variable * TermOver BuiltinOrVar, kv.1 ∉ dom c) b ∪ (subp_app b <$> c))))) as [Hin|Hnotin].
{
rewrite elem_of_dom in Hin.
destruct Hin as [p Hp].
rewrite map_lookup_filter in Hp.
rewrite bind_Some in Hp.
destruct Hp as [q [H1q H2q]].
rewrite lookup_union in H1q.
rewrite map_lookup_filter in H1q.
rewrite lookup_fmap in H1q.
rewrite Hbi in H1q.
simpl in H1q.
rewrite union_Some in H1q.
destruct H1q as [H1q|H1q].
{
rewrite bind_Some in H1q.
destruct H1q as [? [_ ?]].
ltac1:(simplify_eq/=).
apply elem_of_dom_2 in Hci.
ltac1:(contradiction).
}
{
destruct H1q as [_ H1q].
rewrite Hci in H1q.
simpl in H1q.
ltac1:(simplify_eq/=).
clear H2p.
rewrite bind_Some in H2q.
destruct H2q as [? [_ ?]].
ltac1:(simplify_eq/=).
right.
split.
{
right.
exists t0.
split>[reflexivity|].
rewrite bind_None.
left.
Search guard None.
rewrite option_guard_False.
{ reflexivity. }
rewrite elem_of_dom.
intros HContra.
apply HContra.
rewrite map_lookup_filter.
rewrite lookup_union.
rewrite map_lookup_filter.
rewrite lookup_fmap.
rewrite Hbi.
simpl.
rewrite Hci.
simpl.
rewrite option_guard_False.
{ simpl. rewrite option_guard_True. eexists. reflexivity.
assumption.
}
rewrite elem_of_dom.
rewrite Hci.
intros HH. apply HH. eexists. reflexivity.
}
{
exists (subp_app b t2).
ltac1:(replace (subp_app a (subp_app b t2)) with ((compose (subp_app a) (subp_app b)) t2) by reflexivity).
rewrite <- subp_compose_correct.
unfold subp_compose.
unfold subp_normalize.
split>[|reflexivity].
exists (subp_app b t2).
split.
{
rewrite option_guard_False.
simpl.
reflexivity.
intros HC. apply HC. clear HC.
rewrite elem_of_dom.
rewrite Hci.
exists t2. reflexivity.
}
{
exists x.
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
}
}
{
destruct (decide (t_over (bov_variable i) = subp_app b t2)).
{
left.
exists t0.
split>[reflexivity|].
exists Hnotin.
split.
{
apply option_guard_True_pi.
intros pfa pfb. apply proof_irrelevance.
}
{
apply f_equal.
lazy_match! goal with
| [|- _ = ?r] =>
assert(Hr: $r = (subp_app (subp_compose a b) t2))
end.
{
reflexivity.
}
rewrite Hr. clear Hr.
rewrite subp_compose_correct.
unfold compose.
rewrite <- e.
simpl.
ltac1:(rewrite Hai).
reflexivity.
}
}
{
ltac1:(exfalso).
apply Hnotin. clear Hnotin.
rewrite elem_of_dom.
rewrite map_lookup_filter.
rewrite lookup_union.
rewrite lookup_fmap.
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
rewrite Hci.
rewrite option_guard_False.
{
simpl.
rewrite option_guard_True.
eexists. reflexivity.
ltac1:(congruence).
}
{
intros HH. apply HH. clear HH.
rewrite elem_of_dom.
rewrite Hci. eexists. reflexivity.
}
}
}
}
}
}
{
simpl in *.
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
inversion H2t.
}
}
{
simpl in *.
rewrite lookup_fmap in H2t.
destruct (c !! i) eqn:Hci.
{
simpl in H2t.
ltac1:(simplify_eq/=).
destruct (decide (subp_app b t1 = t_over (bov_variable i))) as [Hiyes|Hino].
{
left.
exists t0.
split>[reflexivity|].
simpl.
remember (subp_compose a b) as ab.
assert(Hnice := Heqab).
unfold subp_compose in Heqab.
unfold subp_normalize in Heqab.
setoid_rewrite <- Heqab.
setoid_rewrite Hnice.
rewrite subp_compose_correct.
unfold compose.
rewrite Hiyes.
simpl.
ltac1:(rewrite Hai).
ltac1:(unshelve(eexists)).
{
rewrite elem_of_dom.
intros [p Hp].
rewrite map_lookup_filter in Hp.
rewrite lookup_union in Hp.
rewrite lookup_fmap in Hp.
simpl in *.
rewrite Hci in Hp.
rewrite map_lookup_filter in Hp.
rewrite Hbi in Hp.
simpl in Hp.
rewrite bind_Some in Hp.
destruct Hp as [? [_ ?]].
ltac1:(simplify_eq/=).
}
{
split>[|reflexivity].
apply option_guard_True_pi.
intros ? ?.
apply proof_irrelevance.
}
}
{
right.
split.
{
right.
exists t0.
split>[reflexivity|].
rewrite option_guard_False.
{ reflexivity. }
intros HH. apply HH. clear HH.
rewrite elem_of_dom.
rewrite map_lookup_filter.
simpl.
rewrite lookup_union.
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
rewrite lookup_fmap.
rewrite Hci.
simpl.
rewrite option_guard_True.
{ eexists. reflexivity. }
{
ltac1:(congruence).
}
}
{
exists (subp_app b t1).
ltac1:(replace(subp_app a (subp_app b t1)) with (((subp_app a) ∘ (subp_app b)) t1) by reflexivity).
rewrite <- subp_compose_correct.
split>[|reflexivity].
eexists.
split>[reflexivity|].
apply nesym in Hino.
exists Hino.
split>[|reflexivity].
apply option_guard_True_pi.
intros pfa pfb.
apply proof_irrelevance.
}
}
}
{
simpl in H2t.
inversion H2t.
}
}
}
{
destruct (b !! i) eqn:Hbi.
{
simpl in *.
destruct (c !! i) eqn:Hci.
{
simpl in H2t.
ltac1:(simplify_eq/=).
destruct (decide (t_over (bov_variable i) = subp_app b t1)).
{
right.
split.
{
left. reflexivity.
}
{
destruct H1t as [[H1t|H1t]|H1t].
{ inversion H1t. }
{ destruct H1t as [? [H1t ?]].
{ rewrite (left_id None union) in H1t. ltac1:(simplify_eq/=).
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
ltac1:(simplify_eq/=).
rewrite bind_None in H1.
remember (subp_compose a b) as ab.
assert (Hab := Heqab).
unfold subp_compose,subp_normalize in Hab.
ltac1:(setoid_rewrite <- Hab in H).
rewrite Heqab in H.
rewrite subp_compose_correct in H.
unfold compose in H.
rewrite <- e in H.
simpl in H.
ltac1:(rewrite Hai in H).
ltac1:(contradiction).
}
}
{
destruct H1t as [? [_ H1t]].
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
ltac1:(simplify_eq/=).
remember (subp_compose a b) as ab.
assert (Hab := Heqab).
unfold subp_compose,subp_normalize in Hab.
ltac1:(setoid_rewrite <- Hab in H).
rewrite Heqab in H.
rewrite subp_compose_correct in H.
unfold compose in H.
rewrite <- e in H.
simpl in H.
ltac1:(rewrite Hai in H).
ltac1:(contradiction).
}
}
}
{
right. split. left. reflexivity.
rewrite map_lookup_filter.
simpl.
rewrite fmap_Some.
setoid_rewrite lookup_union.
setoid_rewrite lookup_fmap.
setoid_rewrite map_lookup_filter.
exists (subp_app b t1).
split.
{
simpl.
rewrite Hbi.
simpl.
rewrite Hci.
rewrite option_guard_False.
{ simpl. rewrite option_guard_True. reflexivity.
ltac1:(congruence).
}
{
intros L. apply L. clear L.
rewrite elem_of_dom.
rewrite Hci.
exists t1. reflexivity.
}
}
{
fold (compose (subp_app a) (subp_app b) t1).
rewrite <- subp_compose_correct.
symmetry.
unfold subp_compose.
unfold subp_normalize.
simpl in *.
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
ltac1:(simplify_eq/=).
reflexivity.
}
}
}
{ simpl in H2t.
rewrite lookup_fmap in H2t.
rewrite Hci in H2t.
simpl in H2t.
inversion H2t.
}
}
{
simpl in H2t.
rewrite lookup_fmap in H2t.
destruct (c !! i) eqn:Hci.
{
simpl in *.
ltac1:(simplify_eq/=).
destruct (decide (t_over (bov_variable i) = subp_app b t0)).
{
remember (subp_app (subp_compose a b) t0) as nice.
assert (Hnice := Heqnice).
unfold subp_compose in Hnice.
unfold subp_normalize in Hnice.
ltac1:(setoid_rewrite <- Hnice in H0).
rewrite Heqnice in H0.
rewrite subp_compose_correct in H0.
unfold compose in H0. simpl in H0.
rewrite <- e in H0.
simpl in H0.
ltac1:(rewrite Hai in H0).
simpl in H0.
ltac1:(contradiction H0).
reflexivity.
}
{
right.
split. left. reflexivity.
rewrite map_lookup_filter.
rewrite fmap_Some.
simpl.
setoid_rewrite bind_Some.
exists (subp_app b t0).
split.
{
exists (subp_app b t0).
split.
{
rewrite lookup_union.
rewrite map_lookup_filter.
rewrite Hbi.
simpl.
rewrite lookup_fmap.
rewrite Hci.
simpl.
reflexivity.
}
{
rewrite option_guard_True.
reflexivity.
ltac1:(congruence).
}
}
{
fold (compose (subp_app a) (subp_app b) t0).
rewrite <- subp_compose_correct.
reflexivity.
}
}
}
{
simpl in *.
inversion H2t.
}
}
}
}
}
{
rewrite option_guard_True.
reflexivity.
ltac1:(congruence).
}
}
{
(* UFF, now the second inclusion *)
symmetry.
rewrite map_lookup_filter in Heql.
rewrite lookup_union in Heql.
rewrite map_lookup_filter in Heql.
rewrite lookup_fmap in Heql.
rewrite map_lookup_filter in Heql.
rewrite lookup_union in Heql.
simpl in Heql.
rewrite lookup_fmap in Heql.
rewrite map_lookup_filter in Heql.
simpl in Heql.
ltac1:(rewrite !(map_lookup_filter,lookup_union,lookup_fmap)).
destruct (a !! i) eqn:Hai, (b !! i) eqn:Hbi, (c !! i) eqn:Hci;
simpl in *;
assert(Hai' := Hai);
assert(Hbi' := Hbi);
assert(Hci' := Hci);
try (apply elem_of_dom_2 in Hai');
try (apply elem_of_dom_2 in Hbi');
try (apply elem_of_dom_2 in Hci');
try (apply not_elem_of_dom_1 in Hai');
try (apply not_elem_of_dom_1 in Hbi');
try (apply not_elem_of_dom_1 in Hci');
(repeat ((repeat (rewrite option_guard_decide));(repeat (rewrite option_guard_decide in Heql));ltac1:((repeat case_match); simplify_eq/=; simpl in *; try reflexivity)); try (solve [ltac1:(contradiction)]));
try reflexivity;
repeat (match! goal with
| [h: decide _ = _ |- _] => clear $h
end).
(* The above worked *)
Ltac2 just_specialize () :=
match! goal with
| [h: (?p -> ?q) |- _] =>
let f1 := ltac1:(P |- match goal with
| H : P |- _ => fail 1
| _ => idtac
end) in
(f1 (Ltac1.of_constr q));
let h := Control.hyp h in assert ($q) by (apply $h; ltac1:(tauto))
end.
Ltac2 mytac () := ((*try (just_specialize ());*) try (match! goal with
| [x : (TermOver BuiltinOrVar), h : (forall (_ : TermOver BuiltinOrVar), _) |- _] => let y := Control.hyp x in let h2 := Control.hyp h in let my := (Fresh.in_goal ident:(y)) in remember (t_over (bov_variable $y)) as $my;
apply $h2 in $h as $my
| [h: _ ∉ (dom _) |- _] => apply not_elem_of_dom_1 in $h
| [h: context [guard _] |- _] => rewrite option_guard_decide in $h
| [h1: (?m !! ?k = Some _), h2: context [?m !! ?k] |- _ ] => let h := Control.hyp h1 in rewrite $h in $h2
| [h1: (?m !! ?k = None), h2: context [?m !! ?k] |- _ ] => let h := Control.hyp h1 in rewrite $h in $h2
| [h: context [(union _ _) !! _ = _] |- _] => setoid_rewrite lookup_union in $h
| [h: context [(union _ _) = None] |- _] => setoid_rewrite union_None in $h
| [h: context [(union _ _) = Some _] |- _] => setoid_rewrite union_Some in $h
| [h: context[(filter _ _) !! _ = Some _] |- _] => setoid_rewrite map_lookup_filter in $h
| [h: context[(filter _ _) !! _ = None] |- _] => setoid_rewrite map_lookup_filter_None in $h
| [h: context[(_ <$> _) !! _ = _] |- _] => setoid_rewrite lookup_fmap in $h
| [h: decide _ = _ |- _] => clear $h
| [h: ~ (~ _) |- _] => apply dec_stable in $h
| [h: union _ _ = None |- _] => apply union_None in $h
| [h: _ <$> _ = None |- _] => apply fmap_None in $h
| [h: (ex _) |- _] => Std.destruct false [({Std.indcl_arg:=Std.ElimOnIdent(h); Std.indcl_eqn:=None; Std.indcl_as:=None; Std.indcl_in:=None})] None
| [h: (right _ = right _) |- _] => ltac1:(simplify_eq/=); clear $h
| [x : variable, h : (forall (_ : TermOver BuiltinOrVar), _) |- _] => let y := Control.hyp x in let h2 := Control.hyp h in
let myf := (Fresh.in_goal ident:(h)) in
let n := constr:($h2 (t_over (bov_variable $y))) in
let f1 := ltac1:(t |- learn_hyp (t)) in
f1 (Ltac1.of_constr n)
| [h: (forall _, _), a:_ |- _] => let f := ltac1:(ra rb|- learn_hyp (ra rb)) in f (Ltac1.of_constr (Control.hyp h)) (Ltac1.of_constr (Control.hyp a))
end); ltac1:(destruct_and?; (*destruct_or?; *)try congruence; (repeat case_match); simplify_eq/=); simpl in *;ltac1:(try tauto))
.
(* This loses information *)
Ltac2 apply_helper_lemma () :=
match! goal with
| [h: (t_over (bov_variable _) = subp_app _ _) |- _] => apply helper_lemma in $h
end
.
{ repeat (mytac ()); repeat (apply_helper_lemma ());
ltac1:(destruct_or!); (repeat (mytac ())).
}
{
apply dec_stable in n3.
repeat (mytac ()).
ltac1:(destruct_or!); (repeat (just_specialize ())); repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n6.
rewrite Heqab in n6.
rewrite subp_compose_correct in n6.
unfold compose in n6.
rewrite <- n3 in n6.
simpl in *.
ltac1:(rewrite Hai in n6).
repeat (mytac ()).
}
{
repeat (mytac ()).
ltac1:(destruct_or!); (repeat (just_specialize ())); repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
unfold compose in n4.
specialize (n0 (subp_app b t1) ltac:(tauto)).
apply dec_stable in n0.
ltac1:(contradiction n3).
}
{
apply dec_stable in n2.
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
remember ((subp_compose b c)) as bc.
assert (Hbc := Heqbc).
unfold subp_compose in Hbc.
unfold subp_normalize in Hbc.
ltac1:(setoid_rewrite <- Hbc in n0).
rewrite Heqbc in n0.
unfold compose in n4.
apply dec_stable in n3.
rewrite <- n3 in n4.
simpl in n4.
ltac1:(rewrite Hai in n4).
apply dec_stable in n4.
subst t.
ltac1:(contradiction n5).
reflexivity.
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n6.
rewrite Heqab in n6.
rewrite subp_compose_correct in n6.
unfold compose in n6.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
remember ((subp_compose b c)) as bc.
assert (Hbc := Heqbc).
unfold subp_compose in Hbc.
unfold subp_normalize in Hbc.
ltac1:(setoid_rewrite <- Hbc in n0).
rewrite Heqbc in n0.
unfold compose in n4.
ltac1:(contradiction).
}
{
remember ((subp_compose b c)) as bc.
assert (Hbc := Heqbc).
unfold subp_compose in Hbc.
unfold subp_normalize in Hbc.
setoid_rewrite <- Hbc in n0.
rewrite Heqbc in n0.
apply not_elem_of_dom_1 in n0.
remember (subp_app (subp_compose b c) (t_over (bov_variable i))).
assert(Htmp := Heqt1).
rewrite subp_compose_correct in Heqt1.
unfold compose in Heqt1.
simpl in Heqt1.
ltac1:(rewrite Hci' in Heqt1).
simpl in Heqt1.
ltac1:(rewrite Hbi in Heqt1).
simpl in Htmp.
ltac1:(rewrite n0 in Htmp).
ltac1:(simplify_eq/=).
}
{
remember ((subp_compose b c)) as bc.
assert (Hbc := Heqbc).
unfold subp_compose in Hbc.
unfold subp_normalize in Hbc.
setoid_rewrite <- Hbc in n0.
rewrite Heqbc in n0.
apply not_elem_of_dom_1 in n0.
apply dec_stable in n3.
subst t0.
apply dec_stable in n2.
simpl in *.
ltac1:(rewrite Hai in n2).
subst t.
ltac1:(contradiction).
}
{
repeat (mytac ()).
apply not_elem_of_dom_2 in Hci.
ltac1:(contradiction).
}
{
repeat (mytac ()).
clear n0.
apply not_elem_of_dom_2 in Hci.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
unfold compose in n4.
destruct t0; simpl in *.
{
destruct a0; simpl in *.
{ ltac1:(simplify_eq/=). }
{
destruct (b !! x) eqn:Hbx.
{
ltac1:(rewrite Hbx in n1).
ltac1:(rewrite Hbx in n0).
ltac1:(destruct_or!).
{ repeat (mytac ()). }
{
specialize (n0 t0 ltac:(tauto)).
ltac1:(contradiction).
}
}
{
ltac1:(rewrite Hbx in n1).
ltac1:(rewrite Hbx in n0).
ltac1:(destruct_or!)>[repeat (mytac ())|].
specialize (n0 (t_over (bov_variable x)) ltac:(tauto)).
ltac1:(contradiction).
}
}
}
{
ltac1:(destruct_or!)>[repeat (mytac ())|].
specialize (n0 (t_term s (map (subp_app b) l)) ltac:(tauto)).
ltac1:(contradiction).
}
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
unfold compose in n4.
ltac1:(destruct_or!)>[repeat (mytac ())|].
rewrite <- n1 in n4.
simpl in n4.
ltac1:(rewrite Hai in n4).
ltac1:(simplify_eq/=).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n5.
rewrite Heqab in n5.
rewrite subp_compose_correct in n5.
unfold compose in n5.
remember ((subp_compose b c)) as bc.
assert (Hbc := Heqbc).
unfold subp_compose in Hbc.
unfold subp_normalize in Hbc.
setoid_rewrite <- Hbc in n0.
rewrite Heqbc in n0.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n4.
rewrite Heqab in n4.
rewrite subp_compose_correct in n4.
unfold compose in n4.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n2.
rewrite Heqab in n2.
rewrite subp_compose_correct in n2.
unfold compose in n2.
ltac1:(destruct_or!)>[repeat (mytac ())|].
specialize (n0 (subp_app b t0) ltac:(tauto)).
apply dec_stable in n0.
rewrite <- n0 in n2.
simpl in *.
ltac1:(rewrite Hai in n2).
subst t.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n2.
rewrite Heqab in n2.
rewrite subp_compose_correct in n2.
ltac1:(destruct_or!)>[repeat (mytac ())|].
specialize (n0 (subp_app b t0) ltac:(tauto)).
apply dec_stable in n0.
unfold compose in n2.
rewrite <- n0 in n2.
simpl in *.
ltac1:(rewrite Hai in n2).
subst t.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n2.
rewrite Heqab in n2.
rewrite subp_compose_correct in n2.
unfold compose in n2.
ltac1:(contradiction).
}
{
repeat (mytac ()).
apply not_elem_of_dom_2 in Hci.
ltac1:(contradiction).
}
{
apply not_elem_of_dom_2 in Hbi.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n3.
rewrite Heqab in n3.
rewrite subp_compose_correct in n3.
unfold compose in n3.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n1.
rewrite Heqab in n1.
rewrite subp_compose_correct in n1.
unfold compose in n1.
ltac1:(contradiction).
}
{
repeat (mytac ()).
remember ((subp_compose a b)) as ab.
assert (Hab := Heqab).
unfold subp_compose in Hab.
unfold subp_normalize in Hab.
setoid_rewrite <- Hab in n.
rewrite Heqab in n.
rewrite subp_compose_correct in n.
unfold compose in n.
ltac1:(contradiction).
}
}
}
Unshelve.
{
repeat (mytac ()).
apply not_elem_of_dom_2 in x0.
ltac1:(contradiction).
}
Qed.