Can I tell Coq to do induction from n to n+2?












9















I'm trying to see if it's possible to prove evenb n = true <-> exists k, n = double k from https://softwarefoundations.cis.upenn.edu/lf-current/Logic.html without involving odd numbers at all. I tried something like the following:



Theorem evenb_double_k : forall n,
evenb n = true -> exists k, n = double k.
Proof.
intros n H. induction n as [|n' IHn'].
- exists 0. reflexivity.
- (* stuck *)


But apparently induction works one natural number at a time, and exists k : nat, S n' = double k is clearly not provable.



n' : nat
H : evenb (S n') = true
IHn' : evenb n' = true -> exists k : nat, n' = double k
______________________________________(1/1)
exists k : nat, S n' = double k


Is there a way to have induction go from n to n+2?










share|improve this question



























    9















    I'm trying to see if it's possible to prove evenb n = true <-> exists k, n = double k from https://softwarefoundations.cis.upenn.edu/lf-current/Logic.html without involving odd numbers at all. I tried something like the following:



    Theorem evenb_double_k : forall n,
    evenb n = true -> exists k, n = double k.
    Proof.
    intros n H. induction n as [|n' IHn'].
    - exists 0. reflexivity.
    - (* stuck *)


    But apparently induction works one natural number at a time, and exists k : nat, S n' = double k is clearly not provable.



    n' : nat
    H : evenb (S n') = true
    IHn' : evenb n' = true -> exists k : nat, n' = double k
    ______________________________________(1/1)
    exists k : nat, S n' = double k


    Is there a way to have induction go from n to n+2?










    share|improve this question

























      9












      9








      9


      3






      I'm trying to see if it's possible to prove evenb n = true <-> exists k, n = double k from https://softwarefoundations.cis.upenn.edu/lf-current/Logic.html without involving odd numbers at all. I tried something like the following:



      Theorem evenb_double_k : forall n,
      evenb n = true -> exists k, n = double k.
      Proof.
      intros n H. induction n as [|n' IHn'].
      - exists 0. reflexivity.
      - (* stuck *)


      But apparently induction works one natural number at a time, and exists k : nat, S n' = double k is clearly not provable.



      n' : nat
      H : evenb (S n') = true
      IHn' : evenb n' = true -> exists k : nat, n' = double k
      ______________________________________(1/1)
      exists k : nat, S n' = double k


      Is there a way to have induction go from n to n+2?










      share|improve this question














      I'm trying to see if it's possible to prove evenb n = true <-> exists k, n = double k from https://softwarefoundations.cis.upenn.edu/lf-current/Logic.html without involving odd numbers at all. I tried something like the following:



      Theorem evenb_double_k : forall n,
      evenb n = true -> exists k, n = double k.
      Proof.
      intros n H. induction n as [|n' IHn'].
      - exists 0. reflexivity.
      - (* stuck *)


      But apparently induction works one natural number at a time, and exists k : nat, S n' = double k is clearly not provable.



      n' : nat
      H : evenb (S n') = true
      IHn' : evenb n' = true -> exists k : nat, n' = double k
      ______________________________________(1/1)
      exists k : nat, S n' = double k


      Is there a way to have induction go from n to n+2?







      coq induction






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jan 1 at 21:14









      Max NgMax Ng

      11918




      11918
























          2 Answers
          2






          active

          oldest

          votes


















          6














          There is a tactic called fix. I will try to explain what is happening at a high level, because I think it is a cool hack, but be warned that fix is a double-edged sword, generally ill advised to use: it depends on really low-level details of Coq, that make proofs quite fragile, and when they break, the error messages are difficult to understand.



          fix foo i, where foo is a fresh variable, and i is an integer, is a tactic which applies to a goal with at least i arguments (for example, forall n, evenb n = true -> ... has two: n and a proof of evenb n = true), and assumes the goal that you are trying to prove, naming that new hypothesis foo. (Yes, you read that right.)



          Theorem evenb_double_k : forall n,
          evenb n = true -> exists k, n = double k.
          Proof.
          fix self 1.

          (*

          1 subgoal (ID 17)

          self : forall n : nat,
          evenb n = true -> exists k : nat, n = double k
          ============================
          forall n : nat, evenb n = true -> exists k : nat, n = double k

          *)


          Of course, there is a catch: that hypothesis must be applied to a proper subterm of n (which is the first argument of the goal, that's what the number parameter of fix self 1 means, we say that the first argument is the decreasing argument). What is a proper subterm of n? It is a value that you can get only by destructing n, at least once.



          Note that Coq won't immediately complain if you still decide to apply the hypothesis self directly (n is not a proper subterm of itself). Coq only checks the "subterm" requirement on Qed. EDIT: You can also use the command Guarded at any time to check this.



            apply self. (* seems fine, all goals done. *)
          Qed. (* ERROR! *)


          You can approximatively imagine fix as a form of strong induction, where the induction hypothesis (self) is given for all terms smaller than the current one, not only immediate predecessors. However this "subterm" relation does not actually appear in the statement of self. (This peculiarity is what makes fix a low-level, dangerous tactic.)



          After a fix you generally want to destruct the decreasing argument. This is where fix allows your proof to follow the structure of evenb. Below, we destruct again immediately in the S case. So we get three cases: n = O, n = S O, n = S (S n') for some n' : nat.



          The first case is easy, the second one is vacuous, and the third one is where you need the "induction hypothesis" self at n'.



          Proof.
          fix self 1.
          intros n.
          destruct n as [| [| n']].
          - exists 0; reflexivity.
          - discriminate.
          - simpl. intro H.
          apply self in H.
          destruct H as [k Hk].
          exists (S k).
          rewrite Hk; reflexivity.
          Qed.


          Some of the reasoning there is fairly generic, and it can be pulled out into a custom induction principle for even nats, which is concretely another Theorem.



          Theorem even_ind :
          forall (P : nat -> Prop),
          P O ->
          (forall n, evenb n = true -> P n -> P (S (S n))) ->
          forall n, evenb n = true -> P n.


          Compare it to the standard induction principle for nat, which is in fact also a theorem, named nat_ind. This is what the induction tactic uses under the hood.



          About nat_ind.

          (* nat_ind :
          forall P : nat -> Prop,
          P 0 ->
          (forall n : nat, P n -> P (S n)) ->
          forall n : nat, P n
          *)


          The induction step in nat_ind goes from n to S n, whereas the induction step for even_ind goes from n to S (S n), and has an extra hypothesis saying that our numbers are even.



          The proof of even_ind follows a similar structure to evenb_double_k, although it is more abstract because it generalizes over all predicates P on nat.



          Proof.
          intros P HO HSS.
          fix self 1.
          intros n.
          destruct n as [| [| n']].
          - intro; apply HO.
          - discriminate.
          - intros H. apply HSS.
          + apply H.
          + apply self.
          apply H.
          Qed.


          Another approach here is to not use fix at all (since it should be avoided), but keep induction as a primitive to prove the alternative even_ind principle. That is fine for nat, but for some complex inductive types, the default induction principle is too weak and a handwritten fix is the only way.



          Finally, going back to evenb_double_k, we can use the new induction principle with apply even_ind, as opposed to fix or induction. We now get only the two meaningful cases, O and S (S n') where n' is even.



          Theorem evenb_double_k' : forall n,
          evenb n = true -> exists k, n = double k.
          Proof.
          apply even_ind.
          - exists 0. reflexivity.
          - intros n H [k Hk].
          exists (S k).
          rewrite Hk.
          reflexivity.
          Qed.




          Definitions used in this answer:



          Fixpoint evenb n :=
          match n with
          | S (S n') => evenb n'
          | S O => false
          | O => true
          end.

          Fixpoint double k :=
          match k with
          | O => O
          | S k' => S (S (double k'))
          end.





          share|improve this answer


























          • Thanks for the detailed explanation. As with the other answer, I'm not familiar enough with Coq to understand every step yet, but I liked the idea of extracting the even_ind theorem and that it doesn't involve odd numbers at all.

            – Max Ng
            Jan 2 at 2:37






          • 1





            I think it's good to know that you can use Guarded. during the proof to early verify that your proof satisfy the "subterm" requirement.

            – eponier
            Jan 7 at 10:32











          • Oh yes I totally forgot about it but that's definitely very useful!

            – Li-yao Xia
            Jan 7 at 18:38



















          6














          Yes, absolutely! Let's use the induction principle from this answer.



          From Coq Require Import Arith.

          Lemma pair_induction (P : nat -> Prop) :
          P 0 -> P 1 ->
          (forall n, P n -> P (S n) -> P (S (S n))) ->
          forall n, P n.
          Proof.
          intros H0 H1 Hstep n.
          enough (P n / P (S n)) by easy.
          induction n; intuition.
          Qed.


          Now we can use the new principle like so (I switched the non-standard functions with their stdlib counterparts so that everything compiles):



          Theorem evenb_double_k : forall n,
          Nat.even n = true -> exists k, n = Nat.double k.
          Proof.
          intros n Ev.
          induction n as [| |n IHn _] using pair_induction.
          (* the rest of the proof has been removed to not spoil the fun *)
          Qed.





          share|improve this answer


























          • I still need time to understand the lemma but the proof worked beautifully. Thanks!

            – Max Ng
            Jan 2 at 2:29











          • We strengthened the new inductive step compared to the regular induction principle: to prove that a predicate holds of some number you will have two helper hypotheses saying that the predicate holds of the two immediate predecessors of the number. But we have to pay for this strengthening by having more proof obligations -- we have two base cases to get induction going. Intuitively, you start with P 0 and P 1 and produces P 2, then we can use P 1 and P 2 to get P 3 and so on and so forth. If e.g. one only has P 0 and doesn't have P 1, then one can't use the step to get P 2.

            – Anton Trunov
            Jan 2 at 9:30











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53998991%2fcan-i-tell-coq-to-do-induction-from-n-to-n2%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          2 Answers
          2






          active

          oldest

          votes








          2 Answers
          2






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          6














          There is a tactic called fix. I will try to explain what is happening at a high level, because I think it is a cool hack, but be warned that fix is a double-edged sword, generally ill advised to use: it depends on really low-level details of Coq, that make proofs quite fragile, and when they break, the error messages are difficult to understand.



          fix foo i, where foo is a fresh variable, and i is an integer, is a tactic which applies to a goal with at least i arguments (for example, forall n, evenb n = true -> ... has two: n and a proof of evenb n = true), and assumes the goal that you are trying to prove, naming that new hypothesis foo. (Yes, you read that right.)



          Theorem evenb_double_k : forall n,
          evenb n = true -> exists k, n = double k.
          Proof.
          fix self 1.

          (*

          1 subgoal (ID 17)

          self : forall n : nat,
          evenb n = true -> exists k : nat, n = double k
          ============================
          forall n : nat, evenb n = true -> exists k : nat, n = double k

          *)


          Of course, there is a catch: that hypothesis must be applied to a proper subterm of n (which is the first argument of the goal, that's what the number parameter of fix self 1 means, we say that the first argument is the decreasing argument). What is a proper subterm of n? It is a value that you can get only by destructing n, at least once.



          Note that Coq won't immediately complain if you still decide to apply the hypothesis self directly (n is not a proper subterm of itself). Coq only checks the "subterm" requirement on Qed. EDIT: You can also use the command Guarded at any time to check this.



            apply self. (* seems fine, all goals done. *)
          Qed. (* ERROR! *)


          You can approximatively imagine fix as a form of strong induction, where the induction hypothesis (self) is given for all terms smaller than the current one, not only immediate predecessors. However this "subterm" relation does not actually appear in the statement of self. (This peculiarity is what makes fix a low-level, dangerous tactic.)



          After a fix you generally want to destruct the decreasing argument. This is where fix allows your proof to follow the structure of evenb. Below, we destruct again immediately in the S case. So we get three cases: n = O, n = S O, n = S (S n') for some n' : nat.



          The first case is easy, the second one is vacuous, and the third one is where you need the "induction hypothesis" self at n'.



          Proof.
          fix self 1.
          intros n.
          destruct n as [| [| n']].
          - exists 0; reflexivity.
          - discriminate.
          - simpl. intro H.
          apply self in H.
          destruct H as [k Hk].
          exists (S k).
          rewrite Hk; reflexivity.
          Qed.


          Some of the reasoning there is fairly generic, and it can be pulled out into a custom induction principle for even nats, which is concretely another Theorem.



          Theorem even_ind :
          forall (P : nat -> Prop),
          P O ->
          (forall n, evenb n = true -> P n -> P (S (S n))) ->
          forall n, evenb n = true -> P n.


          Compare it to the standard induction principle for nat, which is in fact also a theorem, named nat_ind. This is what the induction tactic uses under the hood.



          About nat_ind.

          (* nat_ind :
          forall P : nat -> Prop,
          P 0 ->
          (forall n : nat, P n -> P (S n)) ->
          forall n : nat, P n
          *)


          The induction step in nat_ind goes from n to S n, whereas the induction step for even_ind goes from n to S (S n), and has an extra hypothesis saying that our numbers are even.



          The proof of even_ind follows a similar structure to evenb_double_k, although it is more abstract because it generalizes over all predicates P on nat.



          Proof.
          intros P HO HSS.
          fix self 1.
          intros n.
          destruct n as [| [| n']].
          - intro; apply HO.
          - discriminate.
          - intros H. apply HSS.
          + apply H.
          + apply self.
          apply H.
          Qed.


          Another approach here is to not use fix at all (since it should be avoided), but keep induction as a primitive to prove the alternative even_ind principle. That is fine for nat, but for some complex inductive types, the default induction principle is too weak and a handwritten fix is the only way.



          Finally, going back to evenb_double_k, we can use the new induction principle with apply even_ind, as opposed to fix or induction. We now get only the two meaningful cases, O and S (S n') where n' is even.



          Theorem evenb_double_k' : forall n,
          evenb n = true -> exists k, n = double k.
          Proof.
          apply even_ind.
          - exists 0. reflexivity.
          - intros n H [k Hk].
          exists (S k).
          rewrite Hk.
          reflexivity.
          Qed.




          Definitions used in this answer:



          Fixpoint evenb n :=
          match n with
          | S (S n') => evenb n'
          | S O => false
          | O => true
          end.

          Fixpoint double k :=
          match k with
          | O => O
          | S k' => S (S (double k'))
          end.





          share|improve this answer


























          • Thanks for the detailed explanation. As with the other answer, I'm not familiar enough with Coq to understand every step yet, but I liked the idea of extracting the even_ind theorem and that it doesn't involve odd numbers at all.

            – Max Ng
            Jan 2 at 2:37






          • 1





            I think it's good to know that you can use Guarded. during the proof to early verify that your proof satisfy the "subterm" requirement.

            – eponier
            Jan 7 at 10:32











          • Oh yes I totally forgot about it but that's definitely very useful!

            – Li-yao Xia
            Jan 7 at 18:38
















          6














          There is a tactic called fix. I will try to explain what is happening at a high level, because I think it is a cool hack, but be warned that fix is a double-edged sword, generally ill advised to use: it depends on really low-level details of Coq, that make proofs quite fragile, and when they break, the error messages are difficult to understand.



          fix foo i, where foo is a fresh variable, and i is an integer, is a tactic which applies to a goal with at least i arguments (for example, forall n, evenb n = true -> ... has two: n and a proof of evenb n = true), and assumes the goal that you are trying to prove, naming that new hypothesis foo. (Yes, you read that right.)



          Theorem evenb_double_k : forall n,
          evenb n = true -> exists k, n = double k.
          Proof.
          fix self 1.

          (*

          1 subgoal (ID 17)

          self : forall n : nat,
          evenb n = true -> exists k : nat, n = double k
          ============================
          forall n : nat, evenb n = true -> exists k : nat, n = double k

          *)


          Of course, there is a catch: that hypothesis must be applied to a proper subterm of n (which is the first argument of the goal, that's what the number parameter of fix self 1 means, we say that the first argument is the decreasing argument). What is a proper subterm of n? It is a value that you can get only by destructing n, at least once.



          Note that Coq won't immediately complain if you still decide to apply the hypothesis self directly (n is not a proper subterm of itself). Coq only checks the "subterm" requirement on Qed. EDIT: You can also use the command Guarded at any time to check this.



            apply self. (* seems fine, all goals done. *)
          Qed. (* ERROR! *)


          You can approximatively imagine fix as a form of strong induction, where the induction hypothesis (self) is given for all terms smaller than the current one, not only immediate predecessors. However this "subterm" relation does not actually appear in the statement of self. (This peculiarity is what makes fix a low-level, dangerous tactic.)



          After a fix you generally want to destruct the decreasing argument. This is where fix allows your proof to follow the structure of evenb. Below, we destruct again immediately in the S case. So we get three cases: n = O, n = S O, n = S (S n') for some n' : nat.



          The first case is easy, the second one is vacuous, and the third one is where you need the "induction hypothesis" self at n'.



          Proof.
          fix self 1.
          intros n.
          destruct n as [| [| n']].
          - exists 0; reflexivity.
          - discriminate.
          - simpl. intro H.
          apply self in H.
          destruct H as [k Hk].
          exists (S k).
          rewrite Hk; reflexivity.
          Qed.


          Some of the reasoning there is fairly generic, and it can be pulled out into a custom induction principle for even nats, which is concretely another Theorem.



          Theorem even_ind :
          forall (P : nat -> Prop),
          P O ->
          (forall n, evenb n = true -> P n -> P (S (S n))) ->
          forall n, evenb n = true -> P n.


          Compare it to the standard induction principle for nat, which is in fact also a theorem, named nat_ind. This is what the induction tactic uses under the hood.



          About nat_ind.

          (* nat_ind :
          forall P : nat -> Prop,
          P 0 ->
          (forall n : nat, P n -> P (S n)) ->
          forall n : nat, P n
          *)


          The induction step in nat_ind goes from n to S n, whereas the induction step for even_ind goes from n to S (S n), and has an extra hypothesis saying that our numbers are even.



          The proof of even_ind follows a similar structure to evenb_double_k, although it is more abstract because it generalizes over all predicates P on nat.



          Proof.
          intros P HO HSS.
          fix self 1.
          intros n.
          destruct n as [| [| n']].
          - intro; apply HO.
          - discriminate.
          - intros H. apply HSS.
          + apply H.
          + apply self.
          apply H.
          Qed.


          Another approach here is to not use fix at all (since it should be avoided), but keep induction as a primitive to prove the alternative even_ind principle. That is fine for nat, but for some complex inductive types, the default induction principle is too weak and a handwritten fix is the only way.



          Finally, going back to evenb_double_k, we can use the new induction principle with apply even_ind, as opposed to fix or induction. We now get only the two meaningful cases, O and S (S n') where n' is even.



          Theorem evenb_double_k' : forall n,
          evenb n = true -> exists k, n = double k.
          Proof.
          apply even_ind.
          - exists 0. reflexivity.
          - intros n H [k Hk].
          exists (S k).
          rewrite Hk.
          reflexivity.
          Qed.




          Definitions used in this answer:



          Fixpoint evenb n :=
          match n with
          | S (S n') => evenb n'
          | S O => false
          | O => true
          end.

          Fixpoint double k :=
          match k with
          | O => O
          | S k' => S (S (double k'))
          end.





          share|improve this answer


























          • Thanks for the detailed explanation. As with the other answer, I'm not familiar enough with Coq to understand every step yet, but I liked the idea of extracting the even_ind theorem and that it doesn't involve odd numbers at all.

            – Max Ng
            Jan 2 at 2:37






          • 1





            I think it's good to know that you can use Guarded. during the proof to early verify that your proof satisfy the "subterm" requirement.

            – eponier
            Jan 7 at 10:32











          • Oh yes I totally forgot about it but that's definitely very useful!

            – Li-yao Xia
            Jan 7 at 18:38














          6












          6








          6







          There is a tactic called fix. I will try to explain what is happening at a high level, because I think it is a cool hack, but be warned that fix is a double-edged sword, generally ill advised to use: it depends on really low-level details of Coq, that make proofs quite fragile, and when they break, the error messages are difficult to understand.



          fix foo i, where foo is a fresh variable, and i is an integer, is a tactic which applies to a goal with at least i arguments (for example, forall n, evenb n = true -> ... has two: n and a proof of evenb n = true), and assumes the goal that you are trying to prove, naming that new hypothesis foo. (Yes, you read that right.)



          Theorem evenb_double_k : forall n,
          evenb n = true -> exists k, n = double k.
          Proof.
          fix self 1.

          (*

          1 subgoal (ID 17)

          self : forall n : nat,
          evenb n = true -> exists k : nat, n = double k
          ============================
          forall n : nat, evenb n = true -> exists k : nat, n = double k

          *)


          Of course, there is a catch: that hypothesis must be applied to a proper subterm of n (which is the first argument of the goal, that's what the number parameter of fix self 1 means, we say that the first argument is the decreasing argument). What is a proper subterm of n? It is a value that you can get only by destructing n, at least once.



          Note that Coq won't immediately complain if you still decide to apply the hypothesis self directly (n is not a proper subterm of itself). Coq only checks the "subterm" requirement on Qed. EDIT: You can also use the command Guarded at any time to check this.



            apply self. (* seems fine, all goals done. *)
          Qed. (* ERROR! *)


          You can approximatively imagine fix as a form of strong induction, where the induction hypothesis (self) is given for all terms smaller than the current one, not only immediate predecessors. However this "subterm" relation does not actually appear in the statement of self. (This peculiarity is what makes fix a low-level, dangerous tactic.)



          After a fix you generally want to destruct the decreasing argument. This is where fix allows your proof to follow the structure of evenb. Below, we destruct again immediately in the S case. So we get three cases: n = O, n = S O, n = S (S n') for some n' : nat.



          The first case is easy, the second one is vacuous, and the third one is where you need the "induction hypothesis" self at n'.



          Proof.
          fix self 1.
          intros n.
          destruct n as [| [| n']].
          - exists 0; reflexivity.
          - discriminate.
          - simpl. intro H.
          apply self in H.
          destruct H as [k Hk].
          exists (S k).
          rewrite Hk; reflexivity.
          Qed.


          Some of the reasoning there is fairly generic, and it can be pulled out into a custom induction principle for even nats, which is concretely another Theorem.



          Theorem even_ind :
          forall (P : nat -> Prop),
          P O ->
          (forall n, evenb n = true -> P n -> P (S (S n))) ->
          forall n, evenb n = true -> P n.


          Compare it to the standard induction principle for nat, which is in fact also a theorem, named nat_ind. This is what the induction tactic uses under the hood.



          About nat_ind.

          (* nat_ind :
          forall P : nat -> Prop,
          P 0 ->
          (forall n : nat, P n -> P (S n)) ->
          forall n : nat, P n
          *)


          The induction step in nat_ind goes from n to S n, whereas the induction step for even_ind goes from n to S (S n), and has an extra hypothesis saying that our numbers are even.



          The proof of even_ind follows a similar structure to evenb_double_k, although it is more abstract because it generalizes over all predicates P on nat.



          Proof.
          intros P HO HSS.
          fix self 1.
          intros n.
          destruct n as [| [| n']].
          - intro; apply HO.
          - discriminate.
          - intros H. apply HSS.
          + apply H.
          + apply self.
          apply H.
          Qed.


          Another approach here is to not use fix at all (since it should be avoided), but keep induction as a primitive to prove the alternative even_ind principle. That is fine for nat, but for some complex inductive types, the default induction principle is too weak and a handwritten fix is the only way.



          Finally, going back to evenb_double_k, we can use the new induction principle with apply even_ind, as opposed to fix or induction. We now get only the two meaningful cases, O and S (S n') where n' is even.



          Theorem evenb_double_k' : forall n,
          evenb n = true -> exists k, n = double k.
          Proof.
          apply even_ind.
          - exists 0. reflexivity.
          - intros n H [k Hk].
          exists (S k).
          rewrite Hk.
          reflexivity.
          Qed.




          Definitions used in this answer:



          Fixpoint evenb n :=
          match n with
          | S (S n') => evenb n'
          | S O => false
          | O => true
          end.

          Fixpoint double k :=
          match k with
          | O => O
          | S k' => S (S (double k'))
          end.





          share|improve this answer















          There is a tactic called fix. I will try to explain what is happening at a high level, because I think it is a cool hack, but be warned that fix is a double-edged sword, generally ill advised to use: it depends on really low-level details of Coq, that make proofs quite fragile, and when they break, the error messages are difficult to understand.



          fix foo i, where foo is a fresh variable, and i is an integer, is a tactic which applies to a goal with at least i arguments (for example, forall n, evenb n = true -> ... has two: n and a proof of evenb n = true), and assumes the goal that you are trying to prove, naming that new hypothesis foo. (Yes, you read that right.)



          Theorem evenb_double_k : forall n,
          evenb n = true -> exists k, n = double k.
          Proof.
          fix self 1.

          (*

          1 subgoal (ID 17)

          self : forall n : nat,
          evenb n = true -> exists k : nat, n = double k
          ============================
          forall n : nat, evenb n = true -> exists k : nat, n = double k

          *)


          Of course, there is a catch: that hypothesis must be applied to a proper subterm of n (which is the first argument of the goal, that's what the number parameter of fix self 1 means, we say that the first argument is the decreasing argument). What is a proper subterm of n? It is a value that you can get only by destructing n, at least once.



          Note that Coq won't immediately complain if you still decide to apply the hypothesis self directly (n is not a proper subterm of itself). Coq only checks the "subterm" requirement on Qed. EDIT: You can also use the command Guarded at any time to check this.



            apply self. (* seems fine, all goals done. *)
          Qed. (* ERROR! *)


          You can approximatively imagine fix as a form of strong induction, where the induction hypothesis (self) is given for all terms smaller than the current one, not only immediate predecessors. However this "subterm" relation does not actually appear in the statement of self. (This peculiarity is what makes fix a low-level, dangerous tactic.)



          After a fix you generally want to destruct the decreasing argument. This is where fix allows your proof to follow the structure of evenb. Below, we destruct again immediately in the S case. So we get three cases: n = O, n = S O, n = S (S n') for some n' : nat.



          The first case is easy, the second one is vacuous, and the third one is where you need the "induction hypothesis" self at n'.



          Proof.
          fix self 1.
          intros n.
          destruct n as [| [| n']].
          - exists 0; reflexivity.
          - discriminate.
          - simpl. intro H.
          apply self in H.
          destruct H as [k Hk].
          exists (S k).
          rewrite Hk; reflexivity.
          Qed.


          Some of the reasoning there is fairly generic, and it can be pulled out into a custom induction principle for even nats, which is concretely another Theorem.



          Theorem even_ind :
          forall (P : nat -> Prop),
          P O ->
          (forall n, evenb n = true -> P n -> P (S (S n))) ->
          forall n, evenb n = true -> P n.


          Compare it to the standard induction principle for nat, which is in fact also a theorem, named nat_ind. This is what the induction tactic uses under the hood.



          About nat_ind.

          (* nat_ind :
          forall P : nat -> Prop,
          P 0 ->
          (forall n : nat, P n -> P (S n)) ->
          forall n : nat, P n
          *)


          The induction step in nat_ind goes from n to S n, whereas the induction step for even_ind goes from n to S (S n), and has an extra hypothesis saying that our numbers are even.



          The proof of even_ind follows a similar structure to evenb_double_k, although it is more abstract because it generalizes over all predicates P on nat.



          Proof.
          intros P HO HSS.
          fix self 1.
          intros n.
          destruct n as [| [| n']].
          - intro; apply HO.
          - discriminate.
          - intros H. apply HSS.
          + apply H.
          + apply self.
          apply H.
          Qed.


          Another approach here is to not use fix at all (since it should be avoided), but keep induction as a primitive to prove the alternative even_ind principle. That is fine for nat, but for some complex inductive types, the default induction principle is too weak and a handwritten fix is the only way.



          Finally, going back to evenb_double_k, we can use the new induction principle with apply even_ind, as opposed to fix or induction. We now get only the two meaningful cases, O and S (S n') where n' is even.



          Theorem evenb_double_k' : forall n,
          evenb n = true -> exists k, n = double k.
          Proof.
          apply even_ind.
          - exists 0. reflexivity.
          - intros n H [k Hk].
          exists (S k).
          rewrite Hk.
          reflexivity.
          Qed.




          Definitions used in this answer:



          Fixpoint evenb n :=
          match n with
          | S (S n') => evenb n'
          | S O => false
          | O => true
          end.

          Fixpoint double k :=
          match k with
          | O => O
          | S k' => S (S (double k'))
          end.






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 7 at 18:41

























          answered Jan 1 at 23:11









          Li-yao XiaLi-yao Xia

          12.9k1429




          12.9k1429













          • Thanks for the detailed explanation. As with the other answer, I'm not familiar enough with Coq to understand every step yet, but I liked the idea of extracting the even_ind theorem and that it doesn't involve odd numbers at all.

            – Max Ng
            Jan 2 at 2:37






          • 1





            I think it's good to know that you can use Guarded. during the proof to early verify that your proof satisfy the "subterm" requirement.

            – eponier
            Jan 7 at 10:32











          • Oh yes I totally forgot about it but that's definitely very useful!

            – Li-yao Xia
            Jan 7 at 18:38



















          • Thanks for the detailed explanation. As with the other answer, I'm not familiar enough with Coq to understand every step yet, but I liked the idea of extracting the even_ind theorem and that it doesn't involve odd numbers at all.

            – Max Ng
            Jan 2 at 2:37






          • 1





            I think it's good to know that you can use Guarded. during the proof to early verify that your proof satisfy the "subterm" requirement.

            – eponier
            Jan 7 at 10:32











          • Oh yes I totally forgot about it but that's definitely very useful!

            – Li-yao Xia
            Jan 7 at 18:38

















          Thanks for the detailed explanation. As with the other answer, I'm not familiar enough with Coq to understand every step yet, but I liked the idea of extracting the even_ind theorem and that it doesn't involve odd numbers at all.

          – Max Ng
          Jan 2 at 2:37





          Thanks for the detailed explanation. As with the other answer, I'm not familiar enough with Coq to understand every step yet, but I liked the idea of extracting the even_ind theorem and that it doesn't involve odd numbers at all.

          – Max Ng
          Jan 2 at 2:37




          1




          1





          I think it's good to know that you can use Guarded. during the proof to early verify that your proof satisfy the "subterm" requirement.

          – eponier
          Jan 7 at 10:32





          I think it's good to know that you can use Guarded. during the proof to early verify that your proof satisfy the "subterm" requirement.

          – eponier
          Jan 7 at 10:32













          Oh yes I totally forgot about it but that's definitely very useful!

          – Li-yao Xia
          Jan 7 at 18:38





          Oh yes I totally forgot about it but that's definitely very useful!

          – Li-yao Xia
          Jan 7 at 18:38













          6














          Yes, absolutely! Let's use the induction principle from this answer.



          From Coq Require Import Arith.

          Lemma pair_induction (P : nat -> Prop) :
          P 0 -> P 1 ->
          (forall n, P n -> P (S n) -> P (S (S n))) ->
          forall n, P n.
          Proof.
          intros H0 H1 Hstep n.
          enough (P n / P (S n)) by easy.
          induction n; intuition.
          Qed.


          Now we can use the new principle like so (I switched the non-standard functions with their stdlib counterparts so that everything compiles):



          Theorem evenb_double_k : forall n,
          Nat.even n = true -> exists k, n = Nat.double k.
          Proof.
          intros n Ev.
          induction n as [| |n IHn _] using pair_induction.
          (* the rest of the proof has been removed to not spoil the fun *)
          Qed.





          share|improve this answer


























          • I still need time to understand the lemma but the proof worked beautifully. Thanks!

            – Max Ng
            Jan 2 at 2:29











          • We strengthened the new inductive step compared to the regular induction principle: to prove that a predicate holds of some number you will have two helper hypotheses saying that the predicate holds of the two immediate predecessors of the number. But we have to pay for this strengthening by having more proof obligations -- we have two base cases to get induction going. Intuitively, you start with P 0 and P 1 and produces P 2, then we can use P 1 and P 2 to get P 3 and so on and so forth. If e.g. one only has P 0 and doesn't have P 1, then one can't use the step to get P 2.

            – Anton Trunov
            Jan 2 at 9:30
















          6














          Yes, absolutely! Let's use the induction principle from this answer.



          From Coq Require Import Arith.

          Lemma pair_induction (P : nat -> Prop) :
          P 0 -> P 1 ->
          (forall n, P n -> P (S n) -> P (S (S n))) ->
          forall n, P n.
          Proof.
          intros H0 H1 Hstep n.
          enough (P n / P (S n)) by easy.
          induction n; intuition.
          Qed.


          Now we can use the new principle like so (I switched the non-standard functions with their stdlib counterparts so that everything compiles):



          Theorem evenb_double_k : forall n,
          Nat.even n = true -> exists k, n = Nat.double k.
          Proof.
          intros n Ev.
          induction n as [| |n IHn _] using pair_induction.
          (* the rest of the proof has been removed to not spoil the fun *)
          Qed.





          share|improve this answer


























          • I still need time to understand the lemma but the proof worked beautifully. Thanks!

            – Max Ng
            Jan 2 at 2:29











          • We strengthened the new inductive step compared to the regular induction principle: to prove that a predicate holds of some number you will have two helper hypotheses saying that the predicate holds of the two immediate predecessors of the number. But we have to pay for this strengthening by having more proof obligations -- we have two base cases to get induction going. Intuitively, you start with P 0 and P 1 and produces P 2, then we can use P 1 and P 2 to get P 3 and so on and so forth. If e.g. one only has P 0 and doesn't have P 1, then one can't use the step to get P 2.

            – Anton Trunov
            Jan 2 at 9:30














          6












          6








          6







          Yes, absolutely! Let's use the induction principle from this answer.



          From Coq Require Import Arith.

          Lemma pair_induction (P : nat -> Prop) :
          P 0 -> P 1 ->
          (forall n, P n -> P (S n) -> P (S (S n))) ->
          forall n, P n.
          Proof.
          intros H0 H1 Hstep n.
          enough (P n / P (S n)) by easy.
          induction n; intuition.
          Qed.


          Now we can use the new principle like so (I switched the non-standard functions with their stdlib counterparts so that everything compiles):



          Theorem evenb_double_k : forall n,
          Nat.even n = true -> exists k, n = Nat.double k.
          Proof.
          intros n Ev.
          induction n as [| |n IHn _] using pair_induction.
          (* the rest of the proof has been removed to not spoil the fun *)
          Qed.





          share|improve this answer















          Yes, absolutely! Let's use the induction principle from this answer.



          From Coq Require Import Arith.

          Lemma pair_induction (P : nat -> Prop) :
          P 0 -> P 1 ->
          (forall n, P n -> P (S n) -> P (S (S n))) ->
          forall n, P n.
          Proof.
          intros H0 H1 Hstep n.
          enough (P n / P (S n)) by easy.
          induction n; intuition.
          Qed.


          Now we can use the new principle like so (I switched the non-standard functions with their stdlib counterparts so that everything compiles):



          Theorem evenb_double_k : forall n,
          Nat.even n = true -> exists k, n = Nat.double k.
          Proof.
          intros n Ev.
          induction n as [| |n IHn _] using pair_induction.
          (* the rest of the proof has been removed to not spoil the fun *)
          Qed.






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jan 2 at 8:34

























          answered Jan 1 at 22:59









          Anton TrunovAnton Trunov

          12.3k21327




          12.3k21327













          • I still need time to understand the lemma but the proof worked beautifully. Thanks!

            – Max Ng
            Jan 2 at 2:29











          • We strengthened the new inductive step compared to the regular induction principle: to prove that a predicate holds of some number you will have two helper hypotheses saying that the predicate holds of the two immediate predecessors of the number. But we have to pay for this strengthening by having more proof obligations -- we have two base cases to get induction going. Intuitively, you start with P 0 and P 1 and produces P 2, then we can use P 1 and P 2 to get P 3 and so on and so forth. If e.g. one only has P 0 and doesn't have P 1, then one can't use the step to get P 2.

            – Anton Trunov
            Jan 2 at 9:30



















          • I still need time to understand the lemma but the proof worked beautifully. Thanks!

            – Max Ng
            Jan 2 at 2:29











          • We strengthened the new inductive step compared to the regular induction principle: to prove that a predicate holds of some number you will have two helper hypotheses saying that the predicate holds of the two immediate predecessors of the number. But we have to pay for this strengthening by having more proof obligations -- we have two base cases to get induction going. Intuitively, you start with P 0 and P 1 and produces P 2, then we can use P 1 and P 2 to get P 3 and so on and so forth. If e.g. one only has P 0 and doesn't have P 1, then one can't use the step to get P 2.

            – Anton Trunov
            Jan 2 at 9:30

















          I still need time to understand the lemma but the proof worked beautifully. Thanks!

          – Max Ng
          Jan 2 at 2:29





          I still need time to understand the lemma but the proof worked beautifully. Thanks!

          – Max Ng
          Jan 2 at 2:29













          We strengthened the new inductive step compared to the regular induction principle: to prove that a predicate holds of some number you will have two helper hypotheses saying that the predicate holds of the two immediate predecessors of the number. But we have to pay for this strengthening by having more proof obligations -- we have two base cases to get induction going. Intuitively, you start with P 0 and P 1 and produces P 2, then we can use P 1 and P 2 to get P 3 and so on and so forth. If e.g. one only has P 0 and doesn't have P 1, then one can't use the step to get P 2.

          – Anton Trunov
          Jan 2 at 9:30





          We strengthened the new inductive step compared to the regular induction principle: to prove that a predicate holds of some number you will have two helper hypotheses saying that the predicate holds of the two immediate predecessors of the number. But we have to pay for this strengthening by having more proof obligations -- we have two base cases to get induction going. Intuitively, you start with P 0 and P 1 and produces P 2, then we can use P 1 and P 2 to get P 3 and so on and so forth. If e.g. one only has P 0 and doesn't have P 1, then one can't use the step to get P 2.

          – Anton Trunov
          Jan 2 at 9:30


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53998991%2fcan-i-tell-coq-to-do-induction-from-n-to-n2%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Mossoró

          Error while reading .h5 file using the rhdf5 package in R

          Pushsharp Apns notification error: 'InvalidToken'