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. *)

Lemma subst_open_rec : forall e1 e2 u (x : atom) k,
lc u ->
[x ~> u] ({k ~> e2} e1) = {k ~> [x ~> u] e2} ([x ~> u] e1).