How to use `exists.elim` in Lean? - theorem-proving

This proof is a tactics-based version of the one in "Logic and Proof" by Avigad et al.
import data.nat.prime
open nat
theorem sqrt_two_irrational_V2 {a b : ℕ} (co : gcd a b = 1) : a^2 ≠ 2 * b^2 :=
begin
intro h,
have h1 : 2 ∣ a^2, by simp [h],
have h2 : 2 ∣ a, from prime.dvd_of_dvd_pow prime_two h1,
cases h2 with c aeq,
have h3 : 2 * (2 * c^2) = 2 * b^2,
by simp [eq.symm h, aeq];
simp [nat.pow_succ, mul_comm, mul_assoc, mul_left_comm],
have h4 : 2 * c^2 = b^2,
from eq_of_mul_eq_mul_left dec_trivial h3,
have h5 : 2 ∣ b^2,
by simp [eq.symm h4],
have hb : 2 ∣ b,
from prime.dvd_of_dvd_pow prime_two h5,
have h6 : 2 ∣ gcd a b, from dvd_gcd (exists.intro c aeq) hb,
have habs : 2 ∣ (1:ℕ), by simp * at *,
exact absurd habs dec_trivial, done
end
which works. I'm trying to work my way backwards in the Lean manual, because tactics mode is much more intuitive for me. When attempting the same without tactics, I have trouble with the exists.elim part, as all the examples in the Lean manual show how to use it only to get the final goal not an intermediary step. Can anyone help me fix this code? Could let or match also be used for the same purpose?
theorem sqrt_two_irrational_V1 {a b : ℕ} (co : gcd a b = 1) : a^2 ≠ 2 * b^2 :=
assume h : a^2 = 2 * b^2,
have 2 ∣ a^2,
by simp [h],
have ha : 2 ∣ a,
from prime.dvd_of_dvd_pow prime_two this,
-- this line below is wrong
exists.elim ha (assume c : ℕ, assume aeq : a = 2 * c),
-- also tried "let" and "match"
--let ⟨c, aeq⟩ := ha,
-- match ha with ⟨(c : ℕ), (aeq : a = 2 * c)⟩,
have 2 * (2 * c^2) = 2 * b^2,
by simp [eq.symm h, aeq];
simp [nat.pow_succ, mul_comm, mul_assoc, mul_left_comm],
have 2 * c^2 = b^2,
from eq_of_mul_eq_mul_left dec_trivial this,
have 2 ∣ b^2,
by simp [eq.symm this],
have hb : 2 ∣ b,
from prime.dvd_of_dvd_pow prime_two this,
have 2 ∣ gcd a b,
from dvd_gcd ha hb,
have habs : 2 ∣ (1:ℕ),
by simp * at *,
show false, from absurd habs dec_trivial

I moved one bracket to fix the proof. Usually when you use exists.elim the entire rest of the proof should be inside the brackets.
theorem sqrt_two_irrational_V1 {a b : ℕ} (co : gcd a b = 1) : a^2 ≠ 2 * b^2 :=
assume h : a^2 = 2 * b^2,
have 2 ∣ a^2,
by simp [h],
have ha : 2 ∣ a,
from prime.dvd_of_dvd_pow prime_two this,
-- this line below is wrong
exists.elim ha (assume c : ℕ, assume aeq : a = 2 * c,
-- also tried "let" and "match"
--let ⟨c, aeq⟩ := ha,
-- match ha with ⟨(c : ℕ), (aeq : a = 2 * c)⟩,
have 2 * (2 * c^2) = 2 * b^2,
by simp [eq.symm h, aeq];
simp [nat.pow_succ, mul_comm, mul_assoc, mul_left_comm],
have 2 * c^2 = b^2,
from eq_of_mul_eq_mul_left dec_trivial this,
have 2 ∣ b^2,
by simp [eq.symm this],
have hb : 2 ∣ b,
from prime.dvd_of_dvd_pow prime_two this,
have 2 ∣ gcd a b,
from dvd_gcd ha hb,
have habs : 2 ∣ (1:ℕ),
by simp * at *,
show false, from absurd habs dec_trivial)
I usually use let instead of exists.elim. The syntax is let ⟨c, aeq⟩ := ha in ... This actually causes an error in your current proof, this is due to a bug that means let introduces a hypothesis called _let_match into your context that causes an error if you use it. simp * at * uses it in your proof, but if you replace it with by clear_aux_decl; simp * at * the proof will work.
You could also write match ha with | ⟨c, aeq⟩ := instead of let ⟨c, aeq⟩ := ha in, but this time you have to put end at the end of the proof. This will have the same bug as happens with let and the fix is the same.

Related

How to prove a*b*c=a*(b*c) in Coq?

Im trying to prove the above question. I have been given a definition of an induction:
Definition nat_ind
(p : nat -> Prop)
(basis : p 0)
(step : forall n, p n -> p (S n)) :
forall n, p n := fix f n :=
match n return p n with
| 0 => basis
| S n => step n (f n)
end.
This is my attempt, but don't know how to finish
Goal forall a b c, a * b * c = a * (b * c).
Proof.
apply nat_ind.
- intros a b c. revert a.
apply (nat_ind (fun a => a * b * c = a * (b * c))); simpl.
+ reflexivity.
+ intros. f_equal. intros.
After your very first nat_ind invocation, if you look at your goal, you see that Coq did not do the right thing at all!
______________________________________(1/3)
forall a b c : nat, a * b * c = a * (b * c)
______________________________________(2/3)
nat ->
(forall a b c : nat, a * b * c = a * (b * c)) ->
forall a b c : nat, a * b * c = a * (b * c)
______________________________________(3/3)
nat
What happened here is that it made a guess for your motive p, and decided to unify it with fun (_ : nat) => <YOUR_WHOLE_GOAL>, a function which given any nat would give your goal... Yes, this is silly!
One way to nudge it into doing the induction on a is by explicitly forcing it to do so, with:
apply nat_ind with (n := a)
(where the n matches the name used in your definition of nat_ind)
After this, you get the much more reasonable goals:
______________________________________(1/2)
forall b c : nat, 0 * b * c = 0 * (b * c)
______________________________________(2/2)
forall n : nat,
(forall b c : nat, n * b * c = n * (b * c)) ->
forall b c : nat, S n * b * c = S n * (b * c)
where indeed a has been replaced by 0 and S n respectively.
[EDIT: I guess this does not quite answer your question as you had gotten your way to the same point with the second induction call...]
To solve your goal, it will help a lot to have a property about distributivity of multiplication over addition:
forall n m p, (n + m) * p = n * p + m * p
All of these, as well as what you're trying to prove, already exists in Coq. Is this homework? Are you just training?

even (n + m) -> even n /\ even m \/ odd n /\ odd m

How can I prove this lemma:
Lemma even_plus_split n m :
even (n + m) -> even n /\ even m \/ odd n /\ odd m.
These are the only libraries and definition that can be used:
Require Import Arith.
Require Import Coq.omega.Omega.
Definition even (n: nat) := exists k, n = 2 * k.
Definition odd (n: nat) := exists k, n = 2 * k + 1.
I am new to Coq and confused about it. Can you give me a solution? Thanks in advance!
the code so far:
Lemma even_plus_split n m :
even (n + m) -> even n /\ even m \/ odd n /\ odd m.
Proof.
intros.
unfold even.
unfold even in H.
destruct H as [k H].
unfold odd.
exists (1/2*k).
result so far:
1 subgoal
n, m, k : nat
H : n + m = 2 * k
______________________________________(1/1)
(exists k0 : nat, n = 2 * k0) /\ (exists k0 : nat, m = 2 * k0) \/
(exists k0 : nat, n = 2 * k0 + 1) /\ (exists k0 : nat, m = 2 * k0 + 1)
I just want to make k0 equals to 1/2*k, and therefore I suppose it would make sense, but I can't do that.
I just want to make k0 equals to 1/2*k, and therefore I suppose it would make sense, but I can't do that.
There is a function called Nat.div2, which divides a natural number by 2. Running Search Nat.div2.
Nat.le_div2: forall n : nat, Nat.div2 (S n) <= n
Nat.lt_div2: forall n : nat, 0 < n -> Nat.div2 n < n
Nat.div2_decr: forall a n : nat, a <= S n -> Nat.div2 a <= n
Nat.div2_wd: Morphisms.Proper (Morphisms.respectful eq eq) Nat.div2
Nat.div2_spec: forall a : nat, Nat.div2 a = Nat.shiftr a 1
Nnat.N2Nat.inj_div2: forall a : N, N.to_nat (N.div2 a) = Nat.div2 (N.to_nat a)
Nnat.Nat2N.inj_div2: forall n : nat, N.of_nat (Nat.div2 n) = N.div2 (N.of_nat n)
Nat.div2_double: forall n : nat, Nat.div2 (2 * n) = n
Nat.div2_div: forall a : nat, Nat.div2 a = a / 2
Nat.div2_succ_double: forall n : nat, Nat.div2 (S (2 * n)) = n
Nat.div2_odd: forall a : nat, a = 2 * Nat.div2 a + Nat.b2n (Nat.odd a)
Nat.div2_bitwise:
forall (op : bool -> bool -> bool) (n a b : nat),
Nat.div2 (Nat.bitwise op (S n) a b) = Nat.bitwise op n (Nat.div2 a) (Nat.div2 b)
Of these, the most promising seems to be Nat.div2_odd: forall a : nat, a = 2 * Nat.div2 a + Nat.b2n (Nat.odd a). If you pose proof this lemma, you can destruct (Nat.odd a) and use simpl to get that either a = 2 * Nat.div2 a or a = 2 * Nat.div2 a + 1, for whichever a you choose.
This may not give you a solution directly (I am not convinced that setting k0 to k / 2 is the right decision), but if it does not, you should make sure that you can figure out how to prove this fact on paper before you try it in Coq. Coq is very good at making sure that you don't make any jumps of logic that you're not allowed to make; it's extremely bad at helping you figure out how to prove a fact that you don't yet know how to prove.
Everybody who tries to answer seems to be dancing around the fact that you actually chose a wrong direction for this proof. Here is a example:
if n = 601 and m = 399, then n + m = 2 * 500,
n = 2 * 300 + 1, and m = 2 * 199 + 1.
Between 500, 300, and 199, the 1/2 ratio does not appear anywhere.
Still the statement (even n /\ even m) / (odd n /\ odd m) is definitely true.
So for now, you have more a math problem than a Coq problem.
You have to make a proof for universally quantified numbers n and m, but somehow this proof should also work for specific choices of these numbers. So in a sense you can make the mental exercise of testing your proof on examples.

How to apply Z.divide_add_r in a hypothesis?

I have the following code:
Require Import Znumtheory.
Require Import Zdiv.
Require Import ZArith.
Import Z.
Definition modulo (a b n : Z) : Prop := (n | (a - b)).
Notation "( a == b [ n ])" := (modulo a b n).
This is a lemma I'm trying to prove:
Lemma modulo_plus_eq : forall a b c m n : Z,
(a * m + b * n == c [ n ]) -> (a * m == c [ n ]).
Here is what I tried so far:
Proof.
intros a b c m n Hab.
red in Hab |- *.
unfold Zminus in Hab.
rewrite Zplus_comm in Hab.
rewrite Zplus_assoc in Hab.
cut (n | b * n).
intros Hbn.
How do I finish the proof?
Here is a follow-up question: Chinese Remainder Theorem
Let me give you a couple of hints first: if you open scope Z some things will be easier, you can also get rid of parentheses in your _ == _ [ _ ] notation (but this is subjective, of course).
Open Scope Z.
Notation "a == b [ n ]" := (modulo a b n) (at level 50).
You have all the lemmas in the standard library to make the proof simpler:
Lemma modulo_plus_eq a b c m n :
a * m + b * n == c [ n ] -> a * m == c [ n ].
Proof.
intros H.
apply divide_add_cancel_r with (m := b * n).
- apply divide_factor_r.
- now rewrite add_sub_assoc, add_comm.
Qed.
We can also make the proof of modulo_plus_extension a bit simpler:
Lemma modulo_plus_extension a b c m n :
a * m == c [ n ] -> a * m + b * n == c [ n ].
Proof.
intros Ham; red in Ham |- *.
rewrite add_sub_swap.
apply divide_add_r; [assumption | apply divide_factor_r].
Qed.
You can use the Search command to find lemmas in the standard library which can do what you want in one or two steps. You just need to state what you want explicitly:
Search (?x + ?y - ?z = ?x - ?z + ?y).
And sometimes one can unfold notations, like so: unfold "_ == _ [ _ ]" in *., which is a bit more explicit than red in Ham |- *..
There is good support for linear integer arithmetic in the Psatz module with the lia tactic. (There is also an lra tactic for linear real arithmetic.)
See the ref man.
With it you can solve your goals with one line.
Require Import Psatz.
Lemma modulo_plus_extension :
forall a b c m n: Z, (a * m == c [ n ]) -> (a * m + b * n == c [ n ]).
Proof. unfold modulo, divide; destruct 1 as [z H]; exists (z+b); lia. Qed.
Lemma modulo_plus_eq :
forall a b c m n : Z, (a * m + b * n == c [ n ]) -> (a * m == c [ n ]).
Proof. unfold modulo, divide; destruct 1 as [z H]; exists (z-b); lia. Qed.
The goal that lia has to solve is
a, b, c, m, n, z : Z
H : a * m + b * n - c = z * n
============================
a * m - c = (z - b) * n
which you can solve yourself with a lot of appeals to commutativity, distributivity, etc. It is good to be able to do it by hand, but after a while it gets tedious, and then it is good to have a tactic that lets you focus on the interesting parts of the proof.
What you're trying to do isn't actually true. Z.divide_add_r says if you already know (n | m) and (n | p), then (n | m + p). You have a hypothesis of the form (n | m + p) and want (n | m) and (n | p), which is the converse of Z.divide_add_r, but that fact isn't true: for example, 3 | 3 but neither 3 | 1 nor 3 | 2 are true.

Why is following Coq rewrite not applying on right hand side of assumption?

I have following Coq env.
1 subgoals
m : nat
IHm : forall n : nat, n + n = m + m -> n = m
n : nat
H : S (n + S n) = S (m + S m)
ll := ll : forall k : nat, k + S k = S k + k
Doing rewrite ll in H, only changes the LHS S (n + S n) to S (S n + n) but not the RHS S (m + S m). ll should be applicable on all variables of type nat. What is wrong here?
Expanding on Emilio's comment, rewrite H and rewrite H in H' will first find an instantiation for all (dependently) quantified variables of H, and then replace all occurrences* of that instantiated LHS with the RHS. I believe it finds the topmost/leftmost instantiation in the syntax tree. So, for example, if you do this:
Goal forall a b, (forall x, x + 0 = x) -> (a + 0) * (a + 0) * (b + 0) = a * a * b.
intros a b H.
rewrite H.
the rewrite H will choose to instantiate x with a, and the resulting goal will be a * a * (b + 0) = a * a * b. You can prefix the lemma with ! (as in rewrite !H) to mean "rewrite everywhere, picking as many instantiations as you can", or with ? (as in rewrite ?H) to mean try rewrite !H, i.e., you can pick multiple instantiations, and also don't fail if you can't find any.
*There's actually a bit more nuance, which is that the replacement is done in a single pass with rewrite H and in multiple passes with rewrite ?H and rewrite !H. This only shows up when the first replacement(s) expose other replacement locations that weren't previously available. This shows up, for example, if you rewrite with a + 0 = a in the goal (a + 0) + 0 = a; rewrite H leaves the goal a + 0 = 0.

Coq: Insufficient Justification error

I am new to Coq and am getting an Insufficient Justification error for hypothesis H3. I tried rewriting it several times but the error persists. Could someone please explain why? Thanks.
Section GroupTheory.
Variable G: Set.
Variable operation: G -> G -> G.
Variable e : G.
Variable inv : G -> G.
Infix "*" := operation.
Hypothesis associativity : forall x y z : G, (x * y) * z = x * (y * z).
Hypothesis identity : forall x : G, exists e : G, (x * e = x) /\ (e * x = x).
Hypothesis inverse : forall x : G, (x * inv x = e) /\ (inv x * x = e).
Theorem latin_square_property :
forall a b : G, exists x : G, a * x = b.
proof.
let a : G, b : G.
take (inv a * b).
have H1:(a * (inv a * b) = (a * inv a) * b) by associativity.
have H2:(a * inv a = e) by inverse.
have H3:(e * b = b) by identity.
have (a * (inv a * b) = (a * inv a) * b) by H1.
~= (e * b) by H2.
~= (b) by H3.
hence thesis.
end proof.
Qed.
End GroupTheory.
The reason is that your identity axiom is independent of the unit e, defined in the section, because you've bound e with the existential quantifier in the definition of the identity axiom.
We can amend identity, getting rid of exists e in the definition:
Hypothesis identity : forall x : G, (x * e = x) /\ (e * x = x).
After that you'll be able to finish your proof.