How to apply Z.divide_add_r in a hypothesis? - coq

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.

Related

Proving a_j ≤ b_j → sum (a_j) ≤ sum (b_j)

I have that for all j in {1, 2, .. N} such that j ≠ i it holds that a_j ≤ b_j. I want to prove in Coq that
How can I do that and what modules are the best for these kinds of manipulations?
The mathematical components library has a theory of "big" operations with lots of lemmas. Here is how one might prove your result:
From mathcomp Require Import all_ssreflect.
Lemma test N (f g : nat -> nat) (i : 'I_N) :
(forall j, j != i -> f i <= g i) ->
\sum_(j < N | j != i) f i <= \sum_(j < N | j != i) g i.
Proof. move=> f_leq_g; exact: leq_sum. Qed.
Edit
If you want to reason about operations over the real numbers, you will also need to install the mathematical components analysis library. Here is how one might adapt this proof to work over the real numbers:
(* Bring real numbers into scope, as well as
the theory of algebraic and numeric structures *)
Require Import Coq.Reals.Reals.
From mathcomp Require Import all_ssreflect ssralg ssrnum Rstruct reals.
(* Change summation and other notations to work over rings
rather than the naturals *)
Local Open Scope ring_scope.
Lemma test N (f g : nat -> R) (i : 'I_N) :
(forall j, j != i -> f i <= g i) ->
\sum_(j < N | j != i) f i <= \sum_(j < N | j != i) g i.
Proof. move=> f_leq_g; exact: Num.Theory.ler_sum. Qed.
You can do this without the mathematical components library using lia and induction.
Require Import Arith.
Require Import Lia.
Fixpoint sum (f: nat -> nat) (N: nat) :=
match N with
| 0 => 0
| S m => f 0 + sum (fun x => f (S x)) m
end.
Fixpoint sum_except (f: nat -> nat) (i : nat) (N: nat) {struct N} :=
match N with
| 0 => 0
| S m =>
match i with
| 0 => 0 + sum (fun x => f (S x)) m
| S j => f 0 + sum_except (fun x => f (S x)) j m
end
end.
Lemma SumLess : forall N a b,
(forall j, a j <= b j) ->
sum a N <= sum b N.
Proof.
induction N.
- simpl; lia.
- intros; simpl.
admit. (* I'll leave this as an exercise. Use lia. *)
Qed.
Lemma SumExceptLess :
forall N i a b,
(forall j, not (j = i) ->
a j <= b j) ->
sum_except a i N <= sum_except b i N.
Proof.
induction N.
- simpl. lia.
- destruct i.
simpl.
+ intros.
apply SumLess; auto.
+ intros; simpl.
admit. (* Again, I'll leave this for you to discover. Use lia. Follow the same pattern as you did in SumLess. *)
Qed.

Preserving structure with inductions on 2 variables

I've been learning about Coq's tactics and familiarizing myself with the system by reproving basic facts about natural numbers.
I've been trying to avoid using the theorems that are already proven in the library, and reproving things like the associativity of multiplication, etc.
However, I've been stymied in a couple of cases, where I have a property for n m:nat that I want to prove, but when I try to do induction on both n and m, the structure of the inductive hypothesises is useless for trying to prove the property.
I proved n = m -> o * n = o * m very easily:
Theorem times_alg_left : forall n m o:nat, n = m -> o * n = o * m.
intros n m o H.
rewrite H; reflexivity.
Defined.
But trying to prove S o * n = S o * m -> n = m completely flumoxed me. I decided, after considerable struggles, to try to prove 2 * n = 2 * m -> n = m, but that was no easier.
I end up with situations like this:
Theorem m2_eq : forall n m:nat, 2 * n = 2 * m -> n = m.
intros n m H.
induction n.
destruct m.
reflexivity.
discriminate.
induction m.
discriminate.
1 subgoal
n, m : nat
H : 2 * S n = 2 * S m
IHn : 2 * n = 2 * S m -> n = S m
IHm : 2 * S n = 2 * m -> (2 * n = 2 * m -> n = m) -> S n = m
______________________________________(1/1)
S n = S m
I've got 2 * S n = 2 * S m, but my inductive premises are talking about 2 * n = 2 * S m and 2 * S n = 2 * m.
I can't make anything happen from this situation.
Similarly, I started trying to proof things about Nat.sub and less than or equal to get around this limitation, but I ran into the same situation.
Theorem sub0_imp_le : forall n m:nat, n - m = 0 -> n <= m.
intros n m H.
induction n; induction m.
apply le_n.
apply le_0.
rewrite sub0 in H.
discriminate.
1 subgoal
n, m : nat
H : S n - S m = 0
IHn : n - S m = 0 -> n <= S m
IHm : S n - m = 0 -> (n - m = 0 -> n <= m) -> S n <= m
______________________________________(1/1)
S n <= S m
But I'm in the same pickle where my inductive premises are worthless.
How do I structure my tactics to solve these type of theorems, with 2 nat variables, and some kind of equality or subtraction situation going on?
You need to do induct on one number while generalizing the other, using the generalize dependent tactic, for instance. This is explained in detail in the Software Foundations book.
Using the Software Foundations book Arthur mentioned, I found the exmaple in question. I need to not introduce m before doing induction on n. I needed to do induction on n first instead, then introduce m.
https://softwarefoundations.cis.upenn.edu/lf-current/Tactics.html#lab143
Theorem times_alg_rem_left : forall n o m:nat, (S o) * n = (S o) * m -> n = m.
intros n o.
induction n.
simpl.
intros m eq.
destruct m.
reflexivity.
rewrite (timesz o) in eq.
simpl in eq.
discriminate.
intros m eq.
destruct m.
rewrite (timesz (S o)) in eq.
inversion eq.
apply f_equal.
apply IHn.
rewrite (times_nSm (S o) n) in eq.
rewrite (times_nSm (S o) m) in eq.
apply plus_alg_rem_right in eq.
assumption.
Defined.

How can I prove `false` and by extension anything from Coq hypothesis 'd=d+1'?

Goal forall (d : nat), d + 1 = d -> False.
Proof.
intros d H.
Abort.
How can I prove False from H? inversion H is just replicating it.
Here is how you can discover some helpful lemmas to do derive a contradiction from your context. First of all we need to import a module containing them, otherwise the Search command won't be able to discover those lemmas:
Require Import Coq.Arith.Arith.
Let's check if we have exactly the lemma we need (recall that x <> y is a notation for not (eq x y), and not A stands for A -> False):
Search (?x + _ <> ?x).
No luck this time. Ok, addition is commutative, let's trying it this way:
Search (_ + ?x <> ?x).
Nothing again. But we certainly should have something like that:
Search (S ?x <> ?x).
Finally we have the following lemma:
Nat.neq_succ_diag_l: forall n : nat, S n <> n
which we can use like so:
Require Import Coq.Arith.Arith.
Goal forall (d : nat), d + 1 = d -> False.
Proof.
intros d H.
rewrite Nat.add_comm in H.
now apply Nat.neq_succ_diag_l in H.
Qed.
The proof follows by induction on d and uses:
eq_add_S
: forall n m : nat, S n = S m -> n = m
The base case is 0 = 1 which by inversion leads to False, this concluding the case. The inductive case you have d + 1 = d -> False as the induction hypothesis and S d + 1 = S d -> False as your goal. We know that x + 1 = y + 1 -> x + y from eq_add_S, so we rewrite our goal and apply the induction hypothesis.
Complete proof:
Goal forall (d : nat), d + 1 = d -> False.
Proof.
induction d.
intros.
- inversion H.
- intros H.
erewrite <- eq_add_S in H; eauto.
Qed.

How do I prove the simplified Chinese Remainder Theorem?

I've managed to prove
Theorem modulo_inv : forall m n : Z, rel_prime m n -> exists x : Z, (m * x == 1 [n]). Admitted.
My question is how to finish the following proof (maybe using the modulo_inv theorem?):
Variables m n : Z.
Hypothesis co_prime : rel_prime m n.
Theorem SimpleChineseRemainder :
forall a b : Z, exists x : Z, (x == a [m]) /\ (x == b [n]).
Here is what I tried, but I don't know whether it is correct or not.
Proof.
intros a b.
exists ((a * n) * (n ^ (-1) mod m) + (b * m) * (m ^ (-1) mod n)).
refine (conj _ _).
(* case : ((a * n) * (n ^ (-1) mod m) + (b * m) * (m ^ (-1) mod n) == a [m]) *)
red.
rewrite Z.add_sub_swap.
apply Z.divide_add_r.
(* case : ((a * n) * (n ^ (-1) mod m) + (b * m) * (m ^ (-1) mod n) == b [n]) *)
Can anybody provide any suggestions?
Code-golfing Anton's answer, I was hoping that ring would be clever enough to use the Eq information, and that the proof would simply be
Theorem SimpleChineseRemainder' a b : exists x : Z, (x == a [m]) /\ (x == b [n]).
Proof.
destruct (rel_prime_bezout _ _ co_prime) as [u v Eq];
exists (a * v * n + b * u * m); split ; [ exists ((b-a)*u) | exists ((a-b)*v)]; ring.
Qed.
Unfortunately it didn't automatically exploit that u * m + v * n = 1 -> u * m = 1 - v * n. So until we have a stronger tactic, I guess that has to be added manually, like so:
Theorem SimpleChineseRemainder' a b : exists x : Z, (x == a [m]) /\ (x == b [n]).
Proof.
destruct (rel_prime_bezout _ _ co_prime) as [u v Eq].
exists (a * (v * n) + b * (u * m)); split ; [ exists ((b-a)*u) | exists ((a-b)*v)].
- replace (v*n) with (1-u*m) by (rewrite <- Eq; ring); ring.
- replace (u*m) with (1-v*n) by (rewrite <- Eq; ring); ring.
Qed.
EDIT: The nsatz tactic is able to solve the equation system. However, it introduces a notation for [ ... ] that conflicts with the notation introduced above, and I don't know how to handle that. However, by changing the notation to i.e. [[ ... ]], the proof becomes just two lines:
Require Import Nsatz.
Theorem SimpleChineseRemainder' a b :
exists x : Z, (x == a [[m]]) /\ (x == b [[n]]).
Proof.
destruct (rel_prime_bezout _ _ co_prime) as [u v Eq];
exists (a * v * n + b * u * m); split ; [ exists ((b-a)*u) | exists ((a-b)*v)]; nsatz.
Qed.
Reusing the proof from Wikipedia which is based on Bézout's lemma, we get the following:
From Coq Require Import ZArith Znumtheory.
Import Z.
Definition modulo (a b n : Z) : Prop := (n | (a - b)).
Notation "a == b [ n ]" := (modulo a b n) (at level 50).
Section SimpleChineseRemainder.
Variables m n : Z.
Hypothesis co_prime : rel_prime m n.
Theorem SimpleChineseRemainder a b : exists x : Z, (x == a [[m]]) /\ (x == b [[n]]).
Proof.
destruct (rel_prime_bezout _ _ co_prime) as [u v Eq].
exists (a * v * n + b * u * m); split; [| rewrite add_comm in *];
match goal with |- _ == ?c [_] => replace c with (c * 1) at 2 by apply mul_1_r end;
rewrite <-Eq, mul_add_distr_l, !mul_assoc;
now eexists; rewrite add_add_simpl_l_r, <-mul_sub_distr_r.
Qed.
End SimpleChineseRemainder.

Getting a stronger induction principle in Coq

Assume the following:
Inductive bin : Set := Z | O.
Fixpoint fib (n : nat) : list bin :=
match n with
| 0 => [Z]
| S k => match k with
| 0 => [O]
| S k' => fib k' ++ fib k
end
end.
I would like to show:
Theorem fib_first : forall n,
Nat.Even n -> n > 3 -> exists w, fib n = Z :: w.
However, by performing induction on n, I get a really useless inductive
hypothesis fixing n, stating that IH : Nat.Even n -> n > 3 -> exists w : list bin, fib n = Z :: w.
What I would ideally have is the following: IH : forall n : nat, Nat.Even n -> n > 3 -> exists w : list bin, fib n = Z :: w. Naturally I cannot assume the original proposition, but it feels like I need to prove something stronger perhaps?
My idea for the inductive reasoning would be made possible by expanding F n = F n-2 . F n-1, we know F n-2 is even iff F n is even, and since neither of F n-2 or F n-1 is empty, we can show the substring is shorter, therefore sufficient for the inductive hypothesis - how does one express this in Coq?
The trick is to unfold the definition of Nat.Even and do induction on n / 2 instead of n:
Theorem fib_first : forall n,
Nat.Even n -> exists w, fib n = Z :: w.
Proof.
intros n [m ->].
induction m as [|m IH].
- now exists nil.
- rewrite <- mult_n_Sm, plus_comm.
generalize (2 * m) IH. clear m IH. simpl.
intros n [w ->].
simpl. eauto.
Qed.
Note that your n > 3 hypothesis is not actually needed.