3

Let's say that I know certain natural numbers are good. I know 1 is good, if n is good then 3n is, and if n is good then n+5 is, and those are only ways of constructing good numbers. It seems to me that the adequate formalization of this in Coq is

Inductive good : nat -> Prop :=
  | g1 : good 1
  | g3 : forall n, good n -> good (n * 3)
  | g5 : forall n, good n -> good (n + 5).

However, despite being obvious, the fact that 0 is not good seems not being provable using this definition (because when I invert, in case of g3 I only get the same thing in the hypothesis).

Now it isn't so obvious what exactly are good numbers. And it really seems that I don't need to characterize them totally in order to know that 0 is not good. For example, I can know that 2 is not good just by doing few inversions.

Veky
  • 2,646
  • 1
  • 21
  • 30

2 Answers2

4

This problem needs induction. And induction needs some predicate P : nat -> Prop to work with. A primitive (constant) predicate like (fun n => ~good 0) doesn't give you much: you won't be able to prove the base case for 1 (which corresponds to the constructor g1), because the predicate "forgets" its argument.

So you need to prove some logically equivalent (or stronger) statement which readily will give you the necessary predicate. An example of such equivalent statement is forall n, good n -> n > 0, which you can later use to disprove good 0. The corresponding predicate P is (fun n => n > 0).

Require Import Coq.Arith.Arith.
Require Import Coq.omega.Omega.

Inductive good : nat -> Prop :=
  | g1 : good 1
  | g3 : forall n, good n -> good (n * 3)
  | g5 : forall n, good n -> good (n + 5).

Lemma good_gt_O: forall n, good n -> n > 0.
Proof.
  intros n H. induction H; omega.
Qed.

Goal ~ good 0.
  intro H. now apply good_ge_O in H.
Qed.

Here is a proof of the aforementioned equivalence:

Lemma not_good0_gt_zero_equiv_not_good0 :
  (forall n, good n -> n > 0) <-> ~ good 0.
Proof.
  split; intros; firstorder.
  destruct n; [tauto | omega].
Qed.

And it's easy to show that forall n, n = 0 -> ~ good n which implicitly appears in @eponier's answer is equivalent to ~ good 0 too.

Lemma not_good0_eq_zero_equiv_not_good0 :
  (forall n, n = 0 -> ~ good n) <-> ~ good 0.
Proof.
  split; intros; subst; auto.
Qed.

Now, the corresponding predicate used to prove forall n, n = 0 -> ~ good n is fun n => n = 0 -> False. This can be shown by using manual application of the goal_ind induction principle, automatically generated by Coq:

Example not_good_0_manual : forall n, n = 0 -> ~ good n.
Proof.
  intros n Eq contra.
  generalize Eq.
  refine (good_ind (fun n => n = 0 -> False) _ _ _ _ _);
    try eassumption; intros; omega.
Qed.

generalize Eq. introduces n = 0 as a premise to the current goal. Without it the goal to prove would be False and the corresponding predicate would be the boring fun n => False again.

Anton Trunov
  • 15,074
  • 2
  • 23
  • 43
  • In fact the right definition IMO for "x is a power of 3" should be `exists n, n^3 == x` – ejgallego May 29 '16 at 23:15
  • Argh. That happens when I try to simplify things for StackOverflow. :-/ Your solution is very nice, but of course, the problem is harder than that: there are other constructors in the inductive type, so its characterization is not so simple as just "being the power of 3". In fact I'm not sure there _is_ a simple characterization at all. – Veky May 29 '16 at 23:24
  • @ejgallego "a power of *two* means a number of the form 2^n where n is an integer" (from [here](https://en.wikipedia.org/wiki/Power_of_two)), so by analogy: `3^k` is a power of 3. `n^3` is the cube of `n`. – Anton Trunov May 29 '16 at 23:25
  • Oh yes sorry indeed for my typo. – ejgallego May 29 '16 at 23:28
  • 1
    @Veky , if you are not even sure on paper, there's little point of trying it in Coq until you know what you want (unless we are talking of some special situation.) – ejgallego May 29 '16 at 23:29
  • Sure of what? That 0 is not in the closure? Yes, I'm sure of _that_, despite not knowing the total characterization of the closure. Ok, let's say there is another constructor. I've updated the question. – Veky May 29 '16 at 23:48
  • @AntonTrunov Thank you very much. I like eponier's answer slightly better since it seems applicable more widely. – Veky May 30 '16 at 12:26
  • Hmm... of course you can prove a more general thing. And it works. But my wonder was because eponier's thing is _not_ more general - at least I don't see how it is. If you say the induction is nat_ind, well of course - but the whole time I thought we were talking about good_ind, not nat_ind. // Ok, now I see you wrote more than I thought at first. I'll need some time to digest it. :-/ – Veky Jun 01 '16 at 17:34
4

Indeed g3 can be applied an unbounded number of times when trying to disprove good 0. That is why we can think this proof requires induction (and we can see that the auxiliary lemma needed in the solution of @AntonTrunov uses induction). The same idea is used in theorem loop_never_stop of http://www.cis.upenn.edu/~bcpierce/sf/current/Imp.html#lab428.

Require Import Omega.

Example not_good_0 : ~ good 0.
Proof.
  intros contra. remember 0 as n. induction contra.
  discriminate. apply IHcontra. omega. omega.
Qed.
eponier
  • 3,062
  • 9
  • 20
  • 3
    And `remember 0 as n` is a crucial component of this solution. It *sort of* replaces the original statement with `forall n, n = 0 -> ~ good n.`. Great answer! – Anton Trunov May 30 '16 at 09:32
  • Yes, the "remember 0" trick was what I was missing. It seems that you can't really prove ~ good 0, but you have to prove good n -> n <> 0. Weird. :-) – Veky May 30 '16 at 11:30
  • 1
    @Veky I have found the exact paragraph of Sotware Foundations discussing this problem http://www.cis.upenn.edu/~bcpierce/sf/current/MoreInd.html#lab341 (Generalizing inductions). – eponier May 31 '16 at 12:35
  • @eponier Link doesn't work. :-/ If it is just about strenghtening induction claim so that hypothesis is actually useful in the step, I know _that_ - but can't relate it to what's happening here. Strengthening induction is actually proving a stronger claim. I can't convince myself that "n = 0 -> P n" is stronger than "P 0". It just seems written in a strange way to satisfy a technicality. – Veky Jun 01 '16 at 06:22
  • @Veky The link doesn't work because the SF people updated the book to v4.0 and it seems that all the examples from v.3.2 with `beautiful` are gone, including `~ beautiful 1` (I guess eponier is referring to them, because it's very similar to your example). It looks like a [case study of regexps](http://www.cis.upenn.edu/~bcpierce/sf/current/IndProp.html#lab220) replaces that section, treating the issue. – Anton Trunov Jun 01 '16 at 12:15
  • 1
    @Veky SF,v3.2:"The problem is that induction over a `Prop` only works properly over completely general instances of the `Prop`, i.e. one in which all the arguments are *free* variables. So it behaves more like `destruct` than like `inversion`. When you're tempted to do use `induction` like this, it is generally an indication that you need to be proving something more general. But in some cases, it suffices to pull out any concrete arguments into separate equations, like this: `∀n, n=1→¬beautiful n`. There's a `remember` tactic that can generate the second proof state out of the original one." – Anton Trunov Jun 01 '16 at 12:23
  • 1
    @AntonTrunov Thank you. So, it seems the only mysterious thing is: in what precise way is proving `~ beautiful n` in the context of `n = 1` (which is what `remember` asks you to do) "more general" than proving `~ beautiful 1`. – Veky Jun 01 '16 at 13:20
  • @Veky I've edit my answer to try to address your concern. IMO, it's not Coq-specific, it's induction-specific. – Anton Trunov Jun 01 '16 at 16:42
  • 1
    @AntonTrunov That was the exact paragraph I was referring to, thank you. The correct link to the old version is http://www.cis.upenn.edu/~bcpierce/sf/sf-3.2/MoreInd.html#lab341. – eponier Jun 02 '16 at 08:26
  • @eponier Thanks, I didn't know they keep old versions online. Do you happen to know if they post change logs? I've read v3.2 and would like to know what is new in v4.0. – Anton Trunov Jun 02 '16 at 08:33
  • @AntonTrunov If you are still interested, I asked someone of Software Foundations by e-mail about the changelog. The answer is it does not exist. But the main changes are in Logic and IndProp that have been rewritten (plus the fact that for decidable properties, `sumbool` was replaced by `reflect` (which is defined in IndProp)). – eponier Sep 23 '16 at 08:59
  • Yes, I'm still interested! Thanks a lot! :) – Anton Trunov Sep 23 '16 at 10:11