Coq : Admit assert - coq

Is there a way to admit asserts in Coq ?
Suppose I have a theorem like this:
Theorem test : forall m n : nat,
m * n = n * m.
Proof.
intros n m.
assert (H1: m + m * n = m * S n). { Admitted. }
Abort.
The above assert doesn't seem to work for me.
The error I receive is:
Error: No focused proof (No proof-editing in progress).
What I want is something like undefined in Haskell. Baiscally, I will come back to this later and prove it. Is there something like that in Coq to achieve it ?

In general the tactic admit (lower-case first letter) admits the current subgoal. Thus assert <your assertion>. admit. should work in your case.
Or in its full glory as follows.
Theorem test : forall m n : nat,
m * n = n * m.
Proof.
intros n m.
assert (H1: m + m * n = m * S n). admit.
Abort.
Edit: The version with ; is nonsense, because you do not want to admit all subgoals.

Related

How can i proof by absurd with coq?

I am reading Logical Foundations from Software Foundations series and i saw the plus_id_example that is:
Theorem plus_id_example : forall n m:nat,
n = m ->
n + n = m + m.
Proof.
intros n m.
intros H.
rewrite H.
reflexivity. Qed.
I could understand the solution, so i tried to solve it using absurd, what i want to do is:
Lets consider by absurd, that n+n <> m+m, so we have 2n <> 2m, n <> m, which is a contradiction since we have n=m as our hypothesis.
How could i write this using Coq tactics?
You can use one of the many contraposition-based lemmas in Coq: you can see them by using, for instance, Search "contra". in Coq.
Using the ssreflect tactic language, a proof based on this idea can be obtained as follows (I'm sure there must be shorter proofs):
Theorem plus_id_example : forall n m:nat,
n = m ->
n + n = m + m.
Proof.
move=> n m.
apply: contra_eq.
have twice : forall p, p + p = p * 2.
move=> p.
by rewrite -iter_addn_0 /= addn0.
by rewrite !twice eqn_mul2r.
Qed.

Coq theorem proving: Simple fraction law in peano arithmetic

I am learning coq and am trying to prove equalities in peano arithmetic.
I got stuck on a simple fraction law.
We know that (n + m) / 2 = n / 2 + m / 2 from primary school.
In peano arithmetic this does only hold if n and m are even (because then division produces correct results).
Compute (3 / 2) + (5 / 2). (*3*)
Compute (3 + 5) / 2. (*4*)
So we define:
Theorem fraction_addition: forall n m: nat ,
even n -> even m -> Nat.div2 n + Nat.div2 m = Nat.div2 (n + m).
From my understanding this is a correct and provable theorem.
I tried an inductive proof, e.g.
intros n m en em.
induction n.
- reflexivity.
- ???
Which gets me into the situation that
en = even (S n)
and IHn : even n -> Nat.div2 n + Nat.div2 m = Nat.div2 (n + m), so i don't find a way to apply the induction hypothesis.
After long research of the standard library and documentation, i don't find an answer.
You need to strengthen your induction hypothesis in cases like this.
One way of doing this is by proving an induction principle like this one:
From Coq Require Import Arith Even.
Lemma nat_ind2 (P : nat -> Prop) :
P 0 ->
P 1 ->
(forall n, P n -> P (S n) -> P (S (S n))) ->
forall n, P n.
Proof.
now intros P0 P1 IH n; enough (H : P n /\ P (S n)); [|induction n]; intuition.
Qed.
nat_ind2 can be used as follows:
Theorem fraction_addition n m :
even n -> even m ->
Nat.div2 n + Nat.div2 m = Nat.div2 (n + m).
Proof.
induction n using nat_ind2.
(* here goes the rest of the proof *)
Qed.
You can also prove your theorem without induction if you are ok with using the standard library.
If you use Even m in your hypothesis (which says exists n, m = 2*m) then you can use simple algebraic rewrites with lemmas from the standard library.
Require Import PeanoNat.
Import Nat.
Goal forall n m, Even n -> Even m -> n / 2 + m / 2 = (n+m)/2.
inversion 1; inversion 1.
subst.
rewrite <- mul_add_distr_l.
rewrite ?(mul_comm 2).
rewrite ?div_mul; auto.
Qed.
The question mark just means "rewrite as many (zero or more) times as possible".
inversion 1 does inversion on the first inductive hypothesis in the goal, in this case first Even n and then Even m. It gives us n = 2 * x and m = 2 * x0 in the context, which we then substitute.
Also note even_spec: forall n : nat, even n = true <-> Even n, so you can use even if you prefer that, just rewrite with even_spec first...

IndProp: ev_plus_plus

(** **** Exercise: 3 stars, standard, optional (ev_plus_plus)
This exercise just requires applying existing lemmas. No
induction or even case analysis is needed, though some of the
rewriting may be tedious. *)
Theorem ev_plus_plus : forall n m p,
even (n+m) -> even (n+p) -> even (m+p).
Proof.
intros n m p H1 H2.
Here is what I got:
1 subgoal (ID 89)
n, m, p : nat
H1 : even (n + m)
H2 : even (n + p)
============================
even (m + p)
I have proven the previous theorem:
Theorem ev_ev__ev : forall n m,
even (n+m) -> even n -> even m.
And wanted to apply it to H1, but
apply ev_ev__ev in H1.
gives an error:
Error: Unable to find an instance for the variable m.
Why can't it find "m" in the expression even (n + m)? How to fix?
Update
apply ev_ev__ev with (m:=m) in H1.
gives a very strange result:
2 subgoals (ID 90)
n, m, p : nat
H1 : even m
H2 : even (n + p)
============================
even (m + p)
subgoal 2 (ID 92) is:
even (n + m + m)
I thought that it will transform H1 to 2 hypothesis:
H11 : even n
H12 : even m
But instead it gave 2 subgoals, the second that we need to prove is more complicated than the initial one:
even (n + m + m)
What's happening here?
The statement forall n m, even (n+m) -> even n -> even m. does not mean "if we have that (n + m) is even then we have both that n is even and that m is even" (this is false, consider n = m = 1). Instead it means "if we have that (n+m) is even, and we have that n is even, then we have that m is even".
There is no way to get H11 : even n and H12 : even m just from H1 : even (n + m) without assuming a contradiction. I would suggest figuring out how to prove your theorem with pen and paper before trying to prove it in Coq.
Because Coq can't figure out what value it should give for m. You can apply the tactic eapply ev_ev__ev in H1. and see the goals
n, m, p : nat
H2 : even (n + p)
H1 : even ?m
============================
even (m + p)
subgoal 2 (ID 17) is:
even (n + m + ?m)
Coq has instantiated the m with a meta variable ?m, and you need to give a witness for this meta variable in the end to finish the proof.
Second approach is just apply the tactic with instantiating the value of m apply ev_ev__ev with (m := m) in H1.
You can see more on apply with tactics in software-foundations https://softwarefoundations.cis.upenn.edu/lf-current/Tactics.html
The thing that is happening is that Coq unifies H1 with the even n argument of ev_ev__ev instead of the even (n+m).
You can tell Coq exactly where you want H1 to go, and use _ wildcards for the places where you let Coq work out the details.
You probably wanted this the term ev_ev__ev n m H1 with type even n -> even m but your apply produced the term ev_ev__ev (n+m) m _ H1 which also left you with some more stuff to prove. To take a look at the proof context, do
Check ev_ev__ev (n+m) m _ H1.

Why does nesting the induction tactic also nest the inductive hypotheses under a lambda?

Theorem mult_comm : forall m n : nat,
m * n = n * m.
Proof.
intros.
induction n.
- simpl. rewrite (mult_0_r m). reflexivity.
- simpl.
rewrite <- IHn.
induction m.
simpl. reflexivity.
simpl.
The above is from the Software Foundation's second chapter.
1 subgoal
m, n : nat
IHn : S m * n = n * S m
IHm : m * n = n * m -> m * S n = m + m * n
______________________________________(1/1)
S (n + m * S n) = S (m + (n + m * n))
I am really confused as to what IHm is supposed to be here. The way I understand it, Coq tactics get compiled under the hood to some functional program, but I am really not sure what is going on here. I am pretty sure that this is not I intended it to do.
What I wanted to do is something like the following Idris program.
add_comm : {a,b : Nat} -> a + b = b + a
add_assoc : {a,b,c : Nat} -> (a + b) + c = a + (b + c)
total
mult_comm : {m,n : Nat} -> (m * n) = n * m
mult_comm {m = Z} {n = Z} = Refl
mult_comm {m = Z} {n = (S k)} = mult_comm {m=Z} {n=k}
mult_comm {m = (S k)} {n = Z} = mult_comm {m=k} {n=Z}
mult_comm {m = (S k)} {n = (S j)} =
let prf1 = mult_comm {m=k} {n=S j}
prf2 = mult_comm {m=S k} {n=j}
prf3 = mult_comm {m=k} {n=j}
prf_add_comm = add_comm {a=k} {b=j}
prf_add_assoc = add_assoc {a=k} {b=j} {c=j*k}
prf_add_assoc' = add_assoc {a=j} {b=k} {c=j*k}
in
rewrite prf1 in
rewrite sym prf2 in
rewrite prf3 in
rewrite sym prf_add_assoc in
rewrite sym prf_add_assoc' in
rewrite (add_comm {a=k} {b=j}) in
Refl
More specifically, I need prf1, prf2 and prf3 which I get using recursive calls to mult_comm. In Coq the two of the proofs are stuck in a lambda and I am not sure how that happened. I see that Coq's induction tactic is not doing what I think it should be doing.
In addition to the explanation of the above, let me also ask is there more introductory material to Coq than Software Foundations just in case I get stuck like this again on some tactic? Note that I know how to solve this in Coq as I've found the solution online.
I've tried tackling the SF book unsuccessfully back in 2016 as an introduction to dependently typed programming and now with the benefit of hindsight, I see that Little Typer and the Idris book are much better in that regard.
When you call the induction tactic, Coq uses heuristics to determine the predicate P : nat -> Prop that you want to prove by induction. Before calling induction for the second time, the proof state looks like this:
m, n : nat
IHn : m * n = n * m
============================
m * S n = m + m * n
What happened is that Coq decided to include the premise IHn in the induction predicate, which was inferred to be
P m := m * n = n * m -> m * S n = m + m * n
which is exactly what you had in your induction hypothesis. In this case, you could argue that it was silly for Coq to use the premise, but there are cases where dropping it would result in an unprovable goal. For instance, consider the following proof attempt:
Lemma double_inj : forall n m, n + n = m + m -> n = m.
Proof.
intros n m H.
induction n as [|n IH].
(* ... *)
If H were dropped after calling induction, you would have to prove forall n m, n = m, which clearly does not hold.
This example is one of the reasons why it is often a bad idea to call induction multiple times in a single Coq proof. As we suggest in that exercise in Software Foundations, it is better to prove an auxiliary lemma, since you can be explicit about the induction predicate. For this example, there are other options as well. You could, for instance, call clear IHn to drop the IHn premise, which would lead Coq to the correct predicate. The ssreflect proof language, which now ships with Coq, has a different tactic for performing induction called elim, which allows you to be more explicit in the choice of the predicate.
I agree with your final comment, but I should add that it is not the goal of Software Foundations to be an introduction to dependently typed programming. Though Coq supports this paradigm, it is generally cumbersome to write such programs directly, and much easier to use tactics to prove lemmas about simply typed programs. For instance, your proof of mult_comm is accepted by Idris because its termination checker is smart enough to recognize all recursive calls as decreasing, even though they are not decreasing with respect to a fixed argument (in the second clause, n decreases, whereas in the third m does). This is not possible in Coq, and you must split the definition into multiple recursive functions, one for each argument, or use well-founded induction on pairs of natural numbers, which would be overkill for this example.
Adam Chlipala has another Coq textbook called CPDT that you might want to check out. However, I don't think you will find a comprehensive description of Coq's tactics there, either. Like induction, many tactics rely on heuristics and are hard to explain in detail.
On a final note, Matthieu Sozeau has developed a package called Equations that makes dependently typed programming in Coq much closer to Idris or Agda. If you find this style of proving more intuitive, you could try to use it.

renaming part of hypothesis in Coq

After destructing n in my proof, I am stuck at the following:
1 subgoal
n : nat
X : Type
h : X
t : list X
n' : nat
E : n = S n'
H' : length t = n'
IHl : length t = n -> nth_error t n = None
______________________________________(1/1)
nth_error t n' = None
I want to rewrite using IHl, but that is not possible. How do I compose IHl and H' to make sense and prove this theorem?
I am just trying to elaborate on #Arthur answer.
I was able to reproduce your goal with the following script:
Require Import List.
Lemma toto (n : nat) (X : Type) (l : list nat) : length l = n -> nth_error l n = None.
Proof.
induction l as [ | h t IHl].
case_eq n.
simpl; auto.
simpl; discriminate.
case_eq n.
simpl; discriminate.
intros n' E.
simpl; intros E'; injection E'; clear E'; intros H'.
and I agree that this goal cannot be proved. Now, if you instead start your proof with the following text (the Proof and induction lines have to be replaced), it will be provable (I checked).
Proof.
revert n.
induction l as [ | h t IHl]; intros n.
The difference is that the induction hypothesis now has the following statement.
forall n : nat, length t = n -> nth_error t n = None
What happened? In the first (faulty) variant, you attempt to prove a statement for all lists whose length is equal to a precise n, because n is fixed before you start the proof by induction. In the second (correct) variant, you attempt to prove a statement for all lists l, and this statement accepts any n as long as length l = n.
In the first variant, n is fixed and the equality length l = n restricts l to be among those that have length precisely n. In the second case, l is chosen first, and n is not fixed, but the equality length l = n restricts n to follow the length of l.
This is called "loading the induction" because the statement forall n, length l = n -> nth_error l n = None is stronger (it is loaded) than the statement that you attempt to prove in the first variant (just for one specific n), but surprisingly it is easier to prove.
You cannot, because your induction hypothesis is not general enough. Here is a statement that should be easier to prove:
forall (X : Type) (t : list X), nth_error t (length t) = None