Isabelle: this lemma about polynomials is only provable for idoms - polynomial-math

In short: I have only a backgroung in computer science and not mathematics. I have proven a lemma in Isabelle for idoms and concluded that it cannot be proven for polynomials of rings 'a::comm_ring_1 poly. But I am not fully sure.
In the Isabelle library, there is the following lemma:
Polynomial.coeff_mult_degree_sum:
coeff (p * q) (degree p + degree q) = coeff p (degree p) * coeff q (degree q)
(where (p∷?'a∷comm_semiring_0 poly) and (q∷?'a∷comm_semiring_0 poly); the lemma is from HOL/Library/Polynomial.thy)
I have proven the following lemma in Isabelle (product/sum of polynomials):
lemma coeff_mult_setprod_setsum:
fixes S :: "'b::idom poly set"
shows "finite S ⟹ coeff (setprod (λx. x) S) (setsum (λx. degree x) S) = setprod (λ x. coeff x (degree x)) S"
by (induct rule: finite_induct, simp, simp_all add: coeff_setprod_setsum_induct_step)
My question:
Is it true that the above lemma requires idoms (i.e., without zero divisors) and cannot be proven for S :: "'a::comm_ring_1 poly set"?
..
..
Here is the full proof:
(* tested with Isabelle2013-2 *)
theory Notepad
imports
Main
"~~/src/HOL/Library/Polynomial"
begin
lemma degree_product_setsum:
fixes S :: "('a::comm_ring_1) poly set"
assumes "finite S"
shows "degree (∏S) ≤ setsum degree S"
using `finite S`
proof-
(* Sledgehammer proof *)
have th1: "⋀x⇩1 x⇩2 x⇩3. degree ((x⇩1∷'a poly) * x⇩2) ≤ degree x⇩1 + x⇩3 ∨ ¬ degree x⇩2 ≤ x⇩3"
by (metis add_le_cancel_right degree_mult_le dual_order.trans nat_add_commute)
show ?thesis using `finite S`
apply(induct)
apply(simp)
by (metis (full_types) th1 setprod.insert setsum.insert)
qed
lemma coeff_setprod_setsum_induct_step:
fixes x :: "'b::idom poly" and F :: "'b::idom poly set"
assumes a1: "finite F"
and a2: "x ∉ F"
and a3: "coeff (∏F) (setsum degree F) = (∏x∷'b poly∈F. coeff x (degree x))"
shows "coeff (x * ∏F) (degree x + setsum degree F) = coeff x (degree x) * (∏x∈F. coeff x (degree x))"
proof-
from coeff_mult_degree_sum[of x "∏F"]
have 1: "coeff (x * ∏F) (degree x + degree (∏F)) = coeff x (degree x) * coeff (∏F) (degree (∏F))" by fast
from a1
have 3: "degree (∏F) ≤ setsum degree F" using degree_product_setsum by fast
(** BEWARE SLEDGEHAMMER PROOF! (don't care at the moment about it) *)
show ?thesis
proof -
have "(∏R∈F. coeff R (degree R)) = 0 ∨ setsum degree F ≤ degree (∏F)"
by (metis a3 le_degree)
hence f1: "setsum degree F = degree (∏F) ∨ (∏R∈F. coeff R (degree R)) = 0"
by (metis "3" le_antisym)
have f2: "setsum degree F = degree (∏F) ∨ ¬ setsum degree F ≤ degree (∏F)"
by (metis "3" le_antisym)
hence "coeff (∏F) (degree (∏F)) = (∏R∈F. coeff R (degree R)) ⟶ coeff x (degree x) * (∏R∈F. coeff R (degree R)) = coeff (x * ∏F) (degree (x * ∏F))"
by (metis (full_types) "1" degree_mult_eq leading_coeff_0_iff mult_eq_0_iff)
moreover
{ assume "coeff (∏F) (degree (∏F)) ≠ (∏R∈F. coeff R (degree R))"
hence "setsum degree F ≠ degree (∏F)"
using a3 by force }
moreover
{ assume "coeff x (degree x) * (∏R∈F. coeff R (degree R)) = coeff (x * ∏F) (degree (x * ∏F))"
hence "setsum degree F = degree (∏F) ⟶ coeff (x * ∏F) (degree x + setsum degree F) = coeff x (degree x) * (∏R∈F. coeff R (degree R))"
by (metis (lifting, no_types) "1" calculation(2))}
ultimately have "setsum degree F = degree (∏F) ⟶ coeff (x * ∏F) (degree x + setsum degree F) = coeff x (degree x) * (∏R∈F. coeff R (degree R))"
by fastforce
hence "setsum degree F ≠ degree (∏F) ∧ ¬ degree x + setsum degree F ≤ degree x + degree (∏F) ∨ coeff (x * ∏F) (degree x + setsum degree F) = coeff x (degree x) * (∏R∈F. coeff R (degree R))"
using f2 add_le_cancel_left by blast
hence "setsum degree F ≠ degree (∏F) ∧ coeff (x * ∏F) (degree x + setsum degree F) = 0 ∨ coeff (x * ∏F) (degree x + setsum degree F) = coeff x (degree x) * (∏R∈F. coeff R (degree R))"
by (metis (full_types) coeff_0 degree_mult_eq le_degree mult_eq_0_iff)
thus "coeff (x * ∏F) (degree x + setsum degree F) = coeff x (degree x) * (∏x∈F. coeff x (degree x))"
using f1 by force
qed
qed
lemma coeff_setprod_setsum:
fixes S :: "'b::idom poly set" (* lemma is not true for S :: "'a::comm_ring_1 poly set"*)
shows "finite S ⟹ coeff (setprod (λx. x) S) (setsum (λx. degree x) S) = setprod (λ x. coeff x (degree x)) S"
by (induct rule: finite_induct, simp, simp_all add: coeff_setprod_setsum_induct_step)
Looking at three polynomials, the problem is visible:
notepad
begin
fix p q r :: "'a::comm_ring_1 poly"
have "coeff (p * q * r) (degree (p * q) + degree r) = coeff (p * q) (degree (p * q)) * coeff r (degree r)"
using Polynomial.coeff_mult_degree_sum[of "p * q" r] by fast
end
However, it is impossible to imply that degree (p * q) is equal to degree p + degree q for the type 'a::comm_ring_1 poly.
Consider this lemma that requires idoms:
Polynomial.degree_mult_eq: (?p∷?'a∷idom poly) ≠ (0∷?'a∷idom poly) ⟹ (?q∷?'a∷idom poly) ≠ (0∷?'a∷idom poly) ⟹
degree (?p * ?q) = degree ?p + degree ?q
..
..
..
Solution from Brian Huffman
lemma degree_setprod_le: "degree (∏i∈S. f i) ≤ (∑i∈S. degree (f i))"
apply(cases "finite S", simp_all, induct rule: finite_induct, simp_all)
by (metis (lifting) degree_mult_le dual_order.trans nat_add_left_cancel_le)
lemma coeff_mult_sum: "degree p ≤ m ⟹ degree q ≤ n ⟹ coeff (p * q) (m + n) = coeff p m * coeff q n"
apply(cases "degree p = m ∧ degree q = n")
apply(insert coeff_mult_degree_sum[of p q], simp) [1]
apply(cases "degree p < m", cases "degree q < n")
by(insert coeff_eq_0[of q n] coeff_eq_0[of p m] degree_mult_le[of p q] coeff_eq_0[of "p*q" "m + n"], simp_all)
lemma coeff_mult_setprod_setsum:
"coeff (setprod (λx. x) S) (setsum (λx. degree x) S) = setprod (λ x. coeff x (degree x)) S"
by(cases "finite S", induct rule: finite_induct, simp_all add: coeff_mult_sum degree_setprod_le)

Yes, your lemma coeff_mult_setprod_setsum is in fact provable for arbitrary comm_ring_1 types. The reason it works without the idom class constraint is that you are never actually computing the degree of the result of a polynomial multiplication, you only are using the degrees of the factors.
I was able to prove this by induction on S using the following two lemmas:
lemma degree_setprod_le: "degree (∏i∈S. f i) ≤ (∑i∈S. degree (f i))" Proof is by cases on whether S is finite, followed by induction on S, and using library lemma degree_mult_le to solve the inductive step.
lemma coeff_mult_sum: "degree p ≤ m ⟹ degree q ≤ n ⟹ coeff (p * q) (m + n) = coeff p m * coeff q n" Proof is by case analysis on whether degree p < m or degree p = m (similarly for q and n). In the less-than cases, library lemma coeff_eq_0 shows that both sides are zero; the final case follows from library lemma coeff_mult_degree_sum.

The problem is, quite simply, that if you don't have an integral domain, coefficients might become zero when multiplying two polynomials, in fact, even the entire polynomial can become zero. For example, consider the commutative ring ℤ/4ℤ, i.e. integers modulo 4. Then the polynomial 2X has degree 1, but 2X · 2X = 4X² = 0 has degree -∞ (or 0, by Isabelle convention).
You need the fact that there are no zero divisors for something like this.
On a related note: it is called “idom”, for “integral domain”, not “ideom”.

Related

Cannot rewrite goal with assertion?

I am not sure I understand why in some cases rewriting H works, and in some it doesnt.
Here for example:
Theorem add_assoc2 : forall n m: nat, n + m = m + n.
Proof. intros. rewrite add_comm. reflexivity. Qed.
Theorem plus_4: forall n m p q: nat,
n + (n * p) + m + (m * p) = n + m + (n * p) + (m * p).
Proof.
intros.
assert (H: n * p + m = m + n * p).
{ rewrite <- add_assoc2. reflexivity. }
rewrite H.
Gives:
1 goal
n, m, p, q : nat
H : n * p + m = m + n * p
______________________________________(1/1)
n + n * p + m + m * p = n + m + n * p + m * p
But Coq complains: Found no subterm matching "n * p + m" in the current goal.
Why?
I clearly see one, on the left side. When using induction, rewriting with IHn doesn't pose any problem, even if there are some other terms in front of rewriteable expression.
You can "see" a subterm n * p + m, but this is misleading: Coq doesn't show you the implicit parentheses around all the + expressions.
Use
Set Printing Parentheses.
to make them visible. Your proof state is really:
n, m, p, q : nat
H : ((n * p) + m) = (m + (n * p))
============================
(((n + (n * p)) + m) + (m * p)) = (((n + m) + (n * p)) + (m * p))
Coq was right that there is no subterm that matches H's left hand side expression ((n * p) + m). You need to rewrite using some associativity lemmas to shift the parentheses around.
Also, add_assoc2 is not a good name for a lemma forall n m: nat, n + m = m + n. This is a commutativity property, not associativity.

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.

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.

How to prove x + y - z = x + (y - z) in Coq

I want to prove this :
1 subgoals
x : nat
y : nat
z : nat
______________________________________(1/1)
x + y - z = x + (y - z)
It looks trivial, but it confuse me a lot, and I need it for another proof.
Thanks.
What you're trying to prove doesn't hold if y <= z, because with nat a-b is zero if a <= b.
Omega is a useful tactic to use for inequalities and simple arithmetic over nat.
Require Import Omega.
Theorem foo:
forall x y z:nat, (x = 0 \/ z <= y) <-> x + y - z = x + (y - z).
intros; omega.
Qed.
However, your identity of course holds for the integers Z.
Require Import ZArith.
Open Scope Z.
Theorem fooZ:
forall x y z:Z, x + y - z = x + (y - z).
intros; omega.
Qed.

Degree of polynomial smaller than a number

I am working on a lemma that shows that the degree of a sum of monomials is always less or equal to n if the exponent of each monomial is less or equal to n.
lemma degree_poly_smaller:
fixes a :: "('a::comm_ring_1 poly)" and n::nat
shows "degree (∑x∷nat | x ≤ n . monom (coeff a x) x) ≤ n"
sorry
What I have to so far is the following (please mind that I am a beginner in Isabelle):
lemma degree_smaller:
fixes a :: "('a::comm_ring_1 poly)" and n::nat
shows "degree (∑x∷nat | x ≤ n . monom (coeff a x) x) ≤ n"
proof-
have th01: "⋀k. k ≤ n ⟹
degree (setsum (λ x . monom (coeff a x) k) {x∷nat. x ≤ n}) ≤ n"
by (metis degree_monom_le monom_setsum order_trans)
have min_lemma1: "k∈{x∷nat. x ≤ n} ⟹ k ≤ n" by simp
from this th01 have th02:
"⋀k. k∈{x∷nat. x ≤ n} ⟹
degree (setsum (λ x . monom (coeff a x) k) {x∷nat. x ≤ n}) ≤ n"
by (metis mem_Collect_eq)
have min_lemma2: "(SOME y . y ≤ n) ≤ n" by (metis (full_types) le0 some_eq_ex)
from this have th03:
"degree (∑x∷nat | x ≤ n . monom (coeff a x) (SOME y . y ≤ n)) ≤ n"
by (metis th01)
from min_lemma1 min_lemma2 have min_lemma3:
"(SOME y . y∈{x∷nat. x ≤ n}) ≤ n" by (metis (full_types) mem_Collect_eq some_eq_ex)
from this th01 th02 th03 have th04:
"degree (∑x∷nat | x ≤ n . monom (coeff a x) (SOME y . y∈{x∷nat. x ≤ n}) ) ≤ n"
by presburger
Here is the problem, I don't understand why the following lemma is not sufficient to finish the proof. In particular, I would expect the last part (where the sorry is) to be simple enough for sledgehammer to find a proof:
from this th01 th02 th03 th04 have th05:
"degree
(setsum (λ i . monom (coeff a i) (SOME y . y∈{x∷nat. x ≤ n})) {x∷nat. x ≤ n})
≤ n"
by linarith
(* how can I prove this last step ? *)
from this have
"degree (setsum (λ i . monom (coeff a i) i) {x∷nat. x ≤ n}) ≤ n" sorry
from this show ?thesis by auto
qed
.
SOLUTION from Brian Huffman's excellent answer:
.
lemma degree_setsum_smaller:
"finite A ⟹ ∀x∈A. degree (f x) ≤ n ⟹ degree (∑x∈A. f x) ≤ n"
apply(induct rule: finite_induct)
apply(auto)
by (metis degree_add_le)
lemma finiteSetSmallerThanNumber:
"finite {x∷nat. x ≤ n}"
by (metis finite_Collect_le_nat)
lemma degree_smaller:
fixes a :: "('a::comm_ring_1 poly)" and n::nat
shows "degree (∑x∷nat | x ≤ n . monom (coeff a x) x) ≤ n"
apply (rule degree_setsum_smaller)
apply(simp add: finiteSetSmallerThanNumber)
by (metis degree_0 degree_monom_eq le0 mem_Collect_eq monom_eq_0_iff) (* from sledgehammer *)
The last step does not follow from your th05. The problem is that you seem to want to unify (SOME y. y∈{x∷nat. x ≤ n}) with the bound variable i. However, in HOL (SOME y. y∈{x∷nat. x ≤ n}) has a single value that depends only on n and not on i. Furthermore, you don't get to choose the value; a theorem using SOME is not the same as a theorem with a universally quantified variable.
My advice is to avoid using SOME altogether, and instead try to prove a generalization of your theorem first:
lemma degree_setsum_smaller:
"finite A ⟹ ∀x∈A. degree (f x) ≤ n ⟹ degree (∑x∈A. f x) ≤ n"
You should be able to prove degree_setsum_smaller by induction over A (use induct rule: finite_induct), and then use it to prove degree_poly_smaller. Lemma degree_add_le from the polynomial library should be useful.
It is generally considered bad style to use auto as anything other than the last method in an apply script, because such proofs tend to be quite fragile. I would eliminate the "finiteSetSmallerThanNumber" lemma completely, it is a needlessly specific special case of Collect_le_nat. Also, camel case names for theorems are usually not used in Isabelle.
At any rate, this is my suggestion of how to make the proofs nicer:
lemma degree_setsum_smaller:
"finite A ⟹ ∀x∈A. degree (f x) ≤ n ⟹ degree (∑x∈A. f x) ≤ n"
by (induct rule: finite_induct, simp_all add: degree_add_le)
lemma degree_smaller:
fixes a :: "('a::comm_ring_1 poly)" and n::nat
shows "degree (∑x∷nat | x ≤ n . monom (coeff a x) x) ≤ n"
proof (rule degree_setsum_smaller)
show "finite {x. x ≤ n}" using finite_Collect_le_nat .
{
fix x assume "x ≤ n"
hence "degree (monom (coeff a x) x) ≤ n"
by (cases "coeff a x = 0", simp_all add: degree_monom_eq)
}
thus "∀x∈{x. x≤ n}. degree (monom (coeff a x) x) ≤ n" by simp
qed