To work with integers in tCPA, one needs to use the arithmetic library for them:
Require Import ZArith.
Dana: Good news!
Bong-sun: Yes?
Dana: The ring tactic works for integers!
Bong-sun: Good news indeed. Thanks.
Pablito (making sure): You mean it works even with subtractions?
Dana: Yup.
Bong-sun: Let me check:
Theorem binomial_expansion_at_rank_2 :
forall x y : Z,
((x - y) * (x - y) = x * x - 2 * x * y + y * y)%Z.
Proof.
intros x y.
ring.
Qed.
Bong-sun: OK.
Halcyon: This is so cool!
To make integers coexist with natural numbers in the same syntactic unit, one needs to declare the type of subexpressions explicitly:
Fixpoint Sigma0 (n : nat) (f : nat -> Z) : Z :=
match n with
| O =>
f 0
| S n' =>
Sigma0 n' f + f (S n')
end.
Lemma fold_unfold_Sigma0_O :
forall (f : nat -> Z),
Sigma0 0 f =
f 0.
Lemma fold_unfold_Sigma0_S :
forall (n' : nat)
(f : nat -> Z),
Sigma0 (S n') f =
(Sigma0 n' f + f (S n'))%Z.
Unlike for nat-valued functions, the fundamental theorem of calculus holds for int-valued functions:
Theorem fundamental_for_int_valued_functions :
forall (f : nat -> Z)
(n : nat),
Sigma0 n (fun i => (f (S i) - f i)%Z) = (f (S n) - f 0%nat)%Z.
The proof is by routine induction on n, using the ring tactic in the induction step. (See the accompanying file.)
Unlike for nat-valued functions, the summation by parts holds unconditionally for int-valued functions:
Theorem summation_by_parts_for_int_valued_functions : (* Abel's lemma *)
forall (f g : nat -> Z)
(n : nat),
(Sigma0 n (fun i => f i * (g (S i) - g i)) + f 0%nat * g 0%nat + Sigma0 n (fun i => g (S i) * (f (S i) - f i)))%Z
=
(f (S n) * g (S n))%Z.
The proof is by routine induction on n, using the ring tactic in the induction step. (See the accompanying file.)
Here is a simple implementation of the absolute-value function:
Definition abs (n : Z) : Z :=
if (n <? 0)%Z
then 0 - n
else n.
In one of his trip reports, Dijkstra mentions the following two identities about absolute values:
Theorem Dijkstra_s_abs :
forall a b : Z,
(abs a < b <-> a < b /\ 0 - a < b)%Z
/\
(a < abs b <-> a < b \/ a < 0 - b)%Z.
Their proof is by cases:
first conjunct:
a is either negative or zero or positive (trichotomy)
case a < 0: abs a = 0 - a
to show: 0 - a < b <-> a < b /0 - a < b
proof of the implication: 0 - a < b -> a < b /0 - a < b
case b < 0:
impossible since 0 - a is positive
case b = 0:
impossible since 0 - a is positive
case b > 0:
since a is negative, a < 0 - a
since a < 0 - a and 0 - a < b, then a < b by transitivity of <
proof of the converse implication: a < b /0 - a < b -> 0 - a < b
immediate since the second conjunct in the assumption is what we need to prove
case a = 0: abs a = 0
to show: 0 < b <-> 0 < b /0 < b, which is immediate
case a > 0: abs a = a
to show: a < b <-> a < b /0 - a < b
proof of the first implication: a < b -> a < b /0 - a < b
case b < 0:
impossible since a is positive
case b = 0:
impossible since a is positive
case b > 0:
since a is positive, 0 - a < a
since 0 - a < a and a < b, then 0 - a < b by transitivity of <
proof of the converse implication: a < b /0 - a < b -> a < b
immediate since the first conjunct in the assumption is what we need to prove
second conjunct:
b is either negative or zero or positive (trichotomy)
case b < 0: abs b = 0 - b
to show: a < 0 - b <-> a < b / a < 0 - b
proof of the implication: a < 0 - b -> a < b / a < 0 - b
immediate since the second disjunct is the assumption
proof of the converse implication: a < b / a < 0 - b -> a < 0 - b
or equivalently: (a < b -> a < 0 - b) /(a < 0 - b -> a < 0 - b)
proof of the first conjunct: a < b -> a < 0 - b
since b is negative, 0 - b is positive and therefore b < 0 - b
so we have a < b and b < 0 - b
and therefore, by transitivity, a < 0 - b
proof of the second conjunct: a < 0 - b -> a < 0 - b
immediate
case b = 0: abs b = 0
to show: a < 0 <-> a < 0 / a < 0
immediate
case b > 0: abs b = b
to show: a < b <-> a < b / a < 0 - b
proof of the first implication: a < b -> a < b / a < 0 - b
immediate
proof of a < b / a < 0 - b -> a < b
or equivalently: (a < b -> a < b) /(a < 0 - b -> a < b)
proof of the first conjunct: a < b -> a < b
immediate
proof of a < 0 - b -> a < b
since b is positive, 0 - b is negative and therefore 0 - b < b
so we have a < 0 - b and 0 - b < b
and therefore, by transitivity, a < b
This informal proof is formalized in the accompanying file, as an illustration that the skills acquired so far with natural numbers apply to integers.
The rest of this chapter is dedicated to proving divisibility properties of polynomials, using the following exponentation function:
Fixpoint zpower (x : Z) (n : nat) : Z :=
match n with
O =>
1%Z
| S n' =>
x * zpower x n'
end.
As a warmup, prove the following properties of exponentation over integers.
Exponentiating one yields one:
Property about_exponentiating_one :
forall n : nat,
(zpower 1 n = 1)%Z.
Exponentiating a product yields the product of the exponentiations:
Property about_exponentiating_a_product :
forall (x y : Z)
(n : nat),
(zpower (x * y) n = zpower x n * zpower y n)%Z.
Exponentiating with a sum yields the product of the exponentiations:
Property about_exponentiating_with_a_sum :
forall (x : Z)
(i j : nat),
(zpower x (i + j) = zpower x i * zpower x j)%Z.
Exponentiating with a product yields a tower of exponentiations:
Property about_exponentiating_with_a_product :
forall (x : Z)
(y z : nat),
zpower x (y * z) = zpower (zpower x y) z.
The following properties are about the result of exponentiating an integer x with an odd natural number, plus or minus one: The result is divisible by x + 1 or by x - 1, respectively.
Prove the following property:
Property about_exponentiating_an_integer_with_an_odd_natural_number_and_then_adding_one :
forall (x : Z)
(n : nat),
exists q : Z,
(zpower x (2 * n + 1) + 1 = q * (x + 1))%Z.
Prove the following property:
Property about_exponentiating_an_integer_with_an_odd_natural_number_and_then_subtracting_one :
forall (x : Z)
(n : nat),
exists q : Z,
(zpower x (2 * n + 1) - 1 = q * (x - 1))%Z.
Dana: Let’s consider the case where n is 0. This base case reads:
forall x : Z, exists q : Z, x^1 + 1 = q * (x + 1)
Bong-sun: Peace of cake, then, since:
x^1 = 1
Dana: OK, so q is 1.
Alfrothul: May I?
Dana: By all means.
Alfrothul: Let’s consider the case where n is 1. This case reads:
forall x : Z, exists q : Z, x^3 + 1 = q * (x + 1)
Bong-sun: q must be a polynomial.
Dana: Of degree 2, since multiplying by x + 1 – which is a polynomial of degree 1 – yields x^3 + 1 – which is a polynomial of degree 3.
Bong-sun: Right. And its coefficient for x^2 must be 1, since the coefficient of x^3 is 1.
Alfrothul: Likewise, its coefficient for x^0 must be 1.
Dana: So let’s posit:
q = x^2 + b * x^1 + 1
Halcyon: OK.
Dana: Now we must find what b stands for to satisfy:
x^3 + 1 = (x^2 + b * x^1 + 1) * (x + 1)
Bong-sun: Let’s calculate:
x^3 + 1 = (x^2 + b * x^1 + 1) * (x + 1)
= (x^2 + b * x^1 + 1) * (x^1 + 1)
= (x^3 + b * x^2 + 1 * x^1) + (x^2 + b * x^1 + 1)
= x^3 + (b + 1) * x^2 + (1 + b) * x^1 + 1
Alfrothul: For this equality to hold, the coefficients of x^2 and of x^1 must be 0, so:
b + 1 = 0
1 + b = 0
Bong-sun: So:
b = -1
Dana: Right. So:
q = x^2 - x^1 + 1
Alfrothul: How about we consider the case where n is 2? This case reads:
forall x : Z, exists q : Z, x^5 + 1 = q * (x + 1)
Bong-sun: Again, q must be a polynomial.
Dana: Of degree 4, since multiplying by x + 1 yields x^5 + 1.
Bong-sun: Right. And its coefficient for x^5 must be 1.
Alfrothul: Likewise, its coefficient for x^0 must be 1.
Dana: All true. But let’s be pedandic and posit:
q = a * x^4 + b * x^3 + c * x^2 + d * x^1 + e * x^0
Halcyon (thoughtfully): There is nothing wrong with being pedantic.
Dana: So now we must find what a, b, c, d, and e stand for to satisfy:
x^5 + 1 = (a * x^4 + b * x^3 + c * x^2 + d * x^1 + e * x^0) * (x + 1)
Bong-sun: Again, let’s calculate:
x^5 + 1 = (a * x^4 + b * x^3 + c * x^2 + d * x^1 + e * x^0) * (x + 1)
= (a * x^4 + b * x^3 + c * x^2 + d * x^1 + e * x^0) * (x^1 + 1)
= (a * x^5 + b * x^4 + c * x^3 + d * x^2 + e * x^1) + (a * x^4 + b * x^3 + c * x^2 + d * x^1 + e * x^0)
= (a * x^5 + b * x^4 + c * x^3 + d * x^2 + e * x^1)
+ (a * x^4 + b * x^3 + c * x^2 + d * x^1 + e * x^0)
= a * x^5 + (b + a) * x^4 + (c + b) * x^3 + (d + c) * x^2 + (e + d) * x^1 + e * x^0
Alfrothul: For this equality to hold, the coefficient of x^5 must be 1, the coefficients of x^4, x^3, x^2, and x^1 must be 0, and the coefficient of x^0 must be 1, so:
a = 1
b + a = 0
c + b = 0
d + c = 0
e + d = 0
e = 1
Bong-sun: So:
a = 1
b = 0 - a = 0 - 1 = -1
c = 0 - b = 0 - -1 = 1
d = 0 - c = 0 - 1 = -1
e = 0 - d = 0 - -1 = 1
e = 1
Dana: Right. So:
q = x^4 - x^3 + x^2 - x^1 + 1
Alfrothul: Guys, there is a pattern here:
q = x^4 - x^3 + (x^2 - x^1 + (1))
Bong-sun: Indeed there is one, and we are going to exploit it. In the case where n is n' + 1, the induction hypothesis reads:
exists q' : Z, x^(2 * n' + 1) + 1 = q' * (x + 1)
Alfrothul: Right. And we need to prove:
exists q : Z, x^(2 * (n' + 1) + 1) + 1 = q * (x + 1)
Bong-sun: Based on our calculations, here is our witness:
q = x^(n' + 2) - x^(n' + 1) + q'
Dana: Rock’n’roll:
Property about_exponentiating_an_integer_with_an_odd_natural_number_and_then_adding_one :
forall (x : Z)
(n : nat),
exists q : Z,
(zpower x (2 * n + 1) + 1 = q * (x + 1))%Z.
Proof.
intros x n.
Pablito (helpful): The *goals* window reads:
x : Z
n : nat
============================
exists q : Z, (zpower x (2 * n + 1) + 1)%Z = (q * (x + 1))%Z
Dana: Thanks, Pablito. First, let’s get more comfortable:
rewrite -> Nat.add_1_r.
Pablito: The *goals* window reads:
x : Z
n : nat
============================
exists q : Z, (zpower x (S (2 * n)) + 1)%Z = (q * (x + 1))%Z
Dana: And now we can use our fold-unfold lemmas and simplify the goal at the outset:
rewrite -> fold_unfold_zpower_S.
Pablito: The *goals* window reads:
x : Z
n : nat
============================
exists q : Z, (x * zpower x (2 * n) + 1)%Z = (q * (x + 1))%Z
Dana: Now let’s start the induction proof. The O case formalizes the informal steps we took earlier in the base case. Let’s focus on the S case:
induction n as [ | n' [q' H_q']].
- simpl (2 * 0).
rewrite -> fold_unfold_zpower_O.
rewrite -> Z.mul_1_r.
exists 1%Z.
rewrite -> Z.mul_1_l.
reflexivity.
-
Pablito: The *goals* window reads:
x : Z
n' : nat
q' : Z
H_q' : (x * zpower x (2 * n') + 1)%Z = (q' * (x + 1))%Z
============================
exists q : Z, (x * zpower x (2 * S n') + 1)%Z = (q * (x + 1))%Z
Dana: Let’s put our calculation to work:
exists (zpower x (S (S (2 * n'))) - zpower x (S (2 * n')) + q')%Z.
Pablito: The *goals* window reads:
x : Z
n' : nat
q' : Z
H_q' : (x * zpower x (2 * n') + 1)%Z = (q' * (x + 1))%Z
============================
(x * zpower x (2 * S n') - 1)%Z = ((zpower x (S (S (2 * n'))) - zpower x (S (2 * n')) + q') * (x + 1))%Z
Anton: And now what?
Bong-sun: Well, the right-hand side reads (... + q') * (x - 1), so let’s distribute this multiplication over this addition:
rewrite -> Z.mul_add_distr_r.
Pablito: The *goals* window reads:
x : Z
n' : nat
q' : Z
H_q' : (x * zpower x (2 * n') + 1)%Z = (q' * (x + 1))%Z
============================
(x * zpower x (2 * S n') + 1)%Z = ((zpower x (2 * S n') - zpower x (S (2 * n'))) * (x + 1) + q' * (x + 1))%Z
Anton: OK, OK. Now the right-hand side of the Leibniz equality denoted by H_q' occurs in the goal:
rewrite <- H_q'.
Pablito: The *goals* window reads:
x : Z
n' : nat
q' : Z
H_q' : (x * zpower x (2 * n') + 1)%Z = (q' * (x + 1))%Z
============================
(x * zpower x (2 * S n') + 1)%Z =
((zpower x (2 * S n') - zpower x (S (2 * n'))) * (x + 1) + (x * zpower x (2 * n') + 1))%Z
Dana: Now all we need to do is to change 2 * S n' into S (S (2 * n')), use the fold-unfold lemma for zpower in the S case a bunch of times, and leave the rest to the ring tactic:
rewrite -> two_times_S.
repeat (rewrite -> fold_unfold_zpower_S).
ring.
Halcyon: And then Qed?
Dana: Yup.
Alfrothul: How about we program the pattern, look:
Fixpoint the_pattern_for_Exercise_08a (x : Z) (n : nat) : Z :=
match n with
O =>
1
| S n' =>
zpower x (S (S (2 * n'))) - zpower x (S (2 * n')) + the_pattern_for_Exercise_08a x n'
end.
Bong-sun (fast on her feet): Cool idea, Alfrothul. Then we can restate the theorem to not just say that there exists a q but to say which q does the job:
Theorem Exercise_08a:
forall (x : Z)
(n : nat),
(zpower x (2 * n + 1) + 1 = (the_pattern_for_Exercise_08a x n) * (x + 1))%Z.
Dana: The proof of this theorem is pretty much the same.
Mimer: Right. That is because the definition of the_pattern_for_Exercise_08a can actually be extracted from your first proof. We shall investigate this point in a later chapter.
Halcyon: You really mean that proofs are programs...
Mimer: I do.
The following properties are about the result of exponentiating an integer x with the successor of a multiple of four, plus or minus one: The result is divisible by x + 1 or by x - 1, respectively.
Prove the following property:
Property about_exponentiating_an_integer_with_the_successor_of_a_multiple_of_four_and_then_adding_one :
forall (x : Z)
(n : nat),
exists q : Z,
(zpower x (4 * n + 1) + 1 = q * (x + 1))%Z.
Prove the following property:
Property about_exponentiating_an_integer_with_the_successor_of_a_multiple_of_four_and_then_subtracting_one :
forall (x : Z)
(n : nat),
exists q : Z,
(zpower x (4 * n + 1) - 1 = q * (x - 1))%Z.
Carmen (wisely): Il n’est pas défendu de penser.Anton: What’s that now?Halcyon (helpful): It’s French for “It is not forbidden to think.”Bong-sun: Which is a code word for “Consider proving these properties as corollaries.”Anton: So, déjà vu, eh.Bong-sun: Most likely.Carmen (curious): What are you guys doing?Halcyon: Formalizing mathematical properties in the Coq Proof Assistant.Mimer (diplomatically): Named after a rebellious bird.Halcyon (courteously): Un oiseau rebelle.Carmen (philosophically): L’amour, toujours l’amour.
The following property is about the result of exponentiating an integer x with the multiple k of an odd natural number and then adding one: The result is divisible by x^k + 1.
Prove this property:
Property about_exponentiating_an_integer_with_the_multiple_of_an_odd_natural_number_and_then_adding_one :
forall (x : Z)
(n k : nat),
exists q : Z,
(zpower x (k * (2 * n + 1)) + 1 = q * (zpower x k + 1))%Z.
Hint: Consider first the successive cases where k is 0, 1, 2, and 3.
Alfrothul: So x^y + 1 is composite if y can be factored with an odd number larger than one.
Dana: So y should be a power of 2.
Alfrothul: Let’s say that x is 3 and y is 2^1. Well, 3^2 + 1 = 9 + 1 = 10 = 2 * 5, a composite number.
Bong-sun: And let’s say that x is 12 and y is 1. Well, 12^2 + 1 = 144 + 1 = 145 = 5 * 29, another composite number.
Dana: OK. Let’s say that x is 2. Is 2^(2^n) + 1 prime?
Bong-sun: If n is 0, yes, since 3 is prime.
Alfrothul: If n is 1, yes, since 5 is prime.
Bong-sun: If n is 2, yes, since 17 is prime.
Anton: If n is 3, yes, since 257 is prime.
Pablito (in sweat): If n is 4, yes, since 65537 is prime.
Leonhard Euler (precise): If n is 5, no, since 4294967297 is divisible by 641.
Pierre de Fermat (philosophical): Well, not all conjectures hold.
Mimer: Pierrot! Lenny! Thanks ever so much for stopping by!
The fourth wall (facepalming): Why don’t we move on to the next exercise.
Fermat numbers are natural numbers of the form 2^(2^n) + 1, where n is a natural number. Euler disproved the conjecture that these numbers are all prime.
The following property is about the result of exponentiating an integer x with the multiple k of an odd natural number and then subtracting one: The result is divisible by x^k - 1.
Prove this property:
Property about_exponentiating_an_integer_with_the_multiple_of_an_odd_natural_number_and_then_subtracting_one :
forall (x : Z)
(n k : nat),
exists q : Z,
(zpower x (k * (2 * n + 1)) - 1 = q * (zpower x k - 1))%Z.
Hint: Consider first the successive cases where k is 0, 1, 2, and 3.
The following property is about the result of exponentiating an integer x with an even multiple, 2 * k, of a natural number and then subtracting one: The result is divisible by x^(2 * k) - 1.
Prove this property:
Property about_exponentiating_an_integer_with_an_even_multiple_of_a_natural_number_and_then_subtracting_one :
forall (x : Z)
(n k : nat),
exists q : Z,
(zpower x (2 * k * n) - 1 = q * (zpower x (2 * k) - 1))%Z.
Hint: Consider first the successive cases where k is 0, 1, 2, and 3.
As a corollary of Exercise 11 and Exercise 12, prove the following property:
Property about_exponentiating_an_integer_with_a_product_of_natural_numbers_and_then_subtracting_one :
forall (x : Z)
(m n : nat),
exists q : Z,
(zpower x (m * n) - 1 = q * (zpower x m - 1))%Z.
Thanks to Sanjay Adhith for mentioning Dijkstra’s trip report in passing.
Section Divisibility of polynomials was inspired by Oleg A. Ivanov’s Problem 1 in Chapter 12 and Problem 10 in Chapter 17 of “Portal Through Mathematics: Journey to Advanced Thinking”, 2017, ISBN 978-0-88385-651-2, MAA.
Expanded the prelude with a concrete example [08 Jul 2025]
Added the interlude about Fermat numbers and its executive summary [29 Jun 2025]
Added the prelude and fixed typos in the solution for Exercise 08a [29 Jun 2025]
Added Section Divisibility of polynomials [27 Jun 2025]
Added Section Two identities about absolute values [09 Jun 2025]
Created [08 Jun 2025]