Require Import Omega.
Require Import Autosubst.Autosubst.
Require Import MyTactics. (* TEMPORARY *)

(* -------------------------------------------------------------------------- *)

(* A more recognizable notation for lifting. *)

Notation lift i t := (t.[ren(+i)]).

(* -------------------------------------------------------------------------- *)

Section Extras.

Context A `{Ids A, Rename A, Subst A, SubstLemmas A}.

Lemma up_ren:
  forall xi,
  ren (upren xi) = up (ren xi).
Proof.
  intros. autosubst.
Qed.

Lemma upn_ren:
  forall i xi,
  ren (iterate upren i xi) = upn i (ren xi).
Proof.
  induction i; intros.
  { reflexivity. }
  { rewrite <- fold_up_upn. rewrite <- IHi. asimpl. reflexivity. }
Qed.

Lemma plus_upn: (* close to [up_liftn] *)
  forall i sigma,
  (+i) >>> upn i sigma = sigma >> ren (+i).
Proof.
  induction i; intros.
  { rewrite iterate_0. autosubst. }
  { rewrite iterate_S. asimpl. rewrite IHi. autosubst. }
Qed.

Lemma up_sigma_up_ren:
  forall t i sigma,
  t.[up sigma].[up (ren (+i))] = t.[up (ren (+i))].[upn (1 + i) sigma].
Proof.
  intros. asimpl. rewrite plus_upn. asimpl. reflexivity.
Qed.

Lemma upn_k_sigma_x:
  forall k sigma x,
  x < k ->
  upn k sigma x = ids x.
Proof.
  induction k; intros; asimpl.
  { omega. }
  { destruct x; asimpl.
    { eauto. }
    { rewrite IHk by omega. autosubst. }
  }
Qed.

Lemma push_substitution_last:
  forall t v i,
  t.[v .: ren (+i)] = t.[up (ren (+i))].[v/].
Proof.
  intros. autosubst.
Qed.

Lemma push_substitution_last_up_hoist:
  forall t v i j,
  t.[up (v .: ren (+i))].[up (ren (+j))] =
  t.[up (up (ren (+j + i)))].[up (lift j v .: ids)].
Proof.
  intros. autosubst.
Qed.

Lemma lift_lift:
  forall i j t,
  lift i (lift j t) = lift (i + j) t.
Proof.
  intros. autosubst.
Qed.

Lemma lift_upn:
  forall t i sigma,
  (lift i t).[upn i sigma] = lift i t.[sigma].
Proof.
  intros. asimpl.
  erewrite plus_upn.
  reflexivity.
Qed.

Lemma lift_up:
  forall t sigma,
  (lift 1 t).[up sigma] = lift 1 t.[sigma].
Proof.
  intros. change up with (upn 1). eapply lift_upn.
Qed.

Lemma up_sigma_f:
  forall (sigma : var -> A) (f : A -> A),
  f (ids 0) = ids 0 ->
  (forall i t, lift i (f t) = f (lift i t)) ->
  up (sigma >>> f) = up sigma >>> f.
Proof.
  intros. f_ext. intros [|x]; asimpl; eauto.
Qed.

Lemma upn_sigma_f:
  forall (sigma : var -> A) (f : A -> A),
  f (ids 0) = ids 0 ->
  (forall i t, lift i (f t) = f (lift i t)) ->
  forall i,
  upn i (sigma >>> f) = upn i sigma >>> f.
Proof.
  induction i; intros.
  { reflexivity. }
  { do 2 rewrite <- fold_up_upn. rewrite IHi. erewrite up_sigma_f by eauto. reflexivity. }
Qed.

Lemma upn_theta_sigma_ids:
  forall theta sigma i,
  theta >> sigma = ids ->
  upn i theta >> upn i sigma = ids.
Proof.
  intros theta sigma i Hid.
  rewrite up_comp_n.
  rewrite Hid.
  rewrite up_id_n.
  reflexivity.
Qed.

Lemma up_theta_sigma_ids:
  forall theta sigma,
  theta >> sigma = ids ->
  up theta >> up sigma = ids.
Proof.
  change up with (upn 1). eauto using upn_theta_sigma_ids.
Qed.

Lemma scons_scomp:
  forall (T : A) Gamma theta,
  T.[theta] .: (Gamma >> theta) = (T .: Gamma) >> theta.
Proof.
  intros. autosubst.
Qed.

(* BUG: the two sides of this equation are distinct, yet they are
   printed identically. *)

Goal
  forall v f,
  v .: (ids >>> f) = (v .: ids) >>> f.
Proof.
  intros.
  Fail reflexivity.
Abort.

End Extras.

(* This incantation means that [eauto with autosubst] can use the tactic
   [autosubst] to prove an equality. *)

Hint Extern 1 (_ = _) => autosubst : autosubst.

(* This incantation means that [eauto with autosubst] can use the lemmas
   whose names are listed here. This is useful when an equality involves
   metavariables, so the tactic [autosubst] fails. *)

Hint Resolve scons_scomp : autosubst.

(* -------------------------------------------------------------------------- *)
