Section BasicOperations.
Local Notation "{ k ~> u } t" := (open_rec k u t) (at level 67).
(** The first property we would like to show is the analogue to [subst_fresh]: index substitution has no effect for closed terms.  Here is an initial attempt at the proof. *)
(** At this point there are two problems.  Our goal is about substitution for index [S k] in term [e], while our induction hypothesis IHLC only tells use about index [k] in term [open e x].  To solve the first problem, we generalize our IH over all [k]. That way, when [k] is incremented in the [abs] case, it will still apply.  Below, we use the tactic [generalize dependent] to generalize over [k] before using induction. *)
(** At this point we are still stuck because the IH concerns [open e x] instead of [e]. The result that we need is that if an index substitution has no effect for an opened term, then it has no effect for the raw term (as long as we are *not* substituting for [0], hence [S k] below). << open e x = {S k ~> u}(open e x)  -> e = {S k ~> u} e >> In other words, expanding the definition of open: << {0 ~> x}e = {S k ~> u}({0 ~> x} e)  -> e = {S k ~> u} e >> Of course, to prove this result, we must generalize [0] and [S k] to be any pair of inequal numbers to get a strong enough induction hypothesis for the [abs] case. *)
(* Take-home Exercise: We've proven the above lemma very explicitly, so that you can step through it slowly to see how it works. However, with automation, it is possible to give a *much* shorter proof. Reprove this lemma on your own to see how compact you can make it. *)
Proof with try solve [eauto | congruence].
induction e; intros j v i u Neq H; simpl in *;
try solve [inversion H; f_equal; eauto].
Case "bvar".
destruct (j == n)...
destruct (i == n)...
Qed.
(** With the help of this lemma, we can complete the proof. *)
(** Take-home Exercise [subst_open_rec] *)
(** The next lemma demonstrates that free variable substitution distributes over index substitution.  The proof of this lemma is by straightforward induction over [e1]. When [e1] is a free variable, we need to appeal to [open_rec_lc], proved above. *)
(** *** Exercise [subst_open_var] *)
(** The lemma above is most often used with [k = 0] and [e2] as some fresh variable. Therefore, it simplifies matters to define the following useful corollary.  HINT: Do not use induction. Rewrite with [subst_open_rec] and [subst_neq_var].  *)
(** *** Take-home Exercise [subst_intro] *)
(** This lemma states that opening can be replaced with variable opening and substitution.  HINT: Prove by induction on [e], first generalizing the argument to [open_rec] by using the [generalize] tactic, e.g., [generalize 0].  *)

Lemma subst_intro : forall (x : atom) u e,
x `notin` (fv e) ->
open e u = [x ~> u](open e x).