induction integer record in coq - coq

The definition of int comes from compcert,
Record int: Type := mkint { intval: Z; intrange: -1 < intval < modulus }.
I wanna prove foo, suppose that the induction strategy needs to be used, because there is a recursive relationship in P1 and P2, and i is positive in P1 and P2 actually.
From compcert Require Import Integers.
Parameter P1 : int -> Prop.
Parameter P2 : int -> Prop.
Theorem foo:
forall i: int,
(P1 i) -> (P2 i).
Proof.
destruct i. induction intval.
admit.
induction p.
Abort.
If induction p, I need to prove two cases, BinNums.Zpos (BinNums.xI p) and BinNums.Zpos (BinNums.xO p). it is hard to prove, I would like to be able to use int like nat, that is something to prove P1 (i + 1) -> P2 (i + 1) by (P1 i) -> (P2 i)
Any hints? thank you very much!

The fact that you are using int numbers from CompCert makes everything more complicated, because there is too little arithmetic available for this datatype.
If you were using just plain integers of type Z, you would be able to perform the proof you require by using well_founded_induction and Zwf.Zwf_well_founded. Here is an example.
Theorem foo:
forall i: Z, (0 <= i)%Z -> P i.
intros i.
induction i using
(well_founded_ind (Zwf.Zwf_well_founded 0)).
Print Zwf.
intros ige0.
assert (cases : (i = 0 \/ 0 < i)%Z) by lia.
destruct cases as [case0 | casegt0].
rewrite case0.
now apply base_case.
assert (dec : i = ((i - 1) + 1)%Z) by lia.
rewrite dec.
apply rec_case.
apply H.
unfold Zwf.
lia.
lia.
Qed.
Now, if we want to make a similar proof using numbers of type int, life is more complicated because these numbers are in a record, and this record contains a field that is a proof. Usually, the value of the proof is irrelevant, only its existence matters, in in this case we would rather have the intval projection be injective. To make it short, I simply place myself in a theoretical setting where this is granted, this well known and acceptable in most use cases. Here is the full example:
Require Import ZArith Zwf.
Require Import Wellfounded.
Require Import Lia.
Require Import ProofIrrelevance.
Open Scope Z_scope.
Parameter modulus : Z.
Hypothesis modulus_gt_0 : 0 < modulus.
Record int : Type := mkint {intval : Z; intrange: -1 < intval < modulus}.
Lemma intval_inj : forall x y : int, intval x = intval y -> x = y.
Proof.
intros [x xp] [y yp]; simpl.
intros xy; revert xp; rewrite xy; intros xp.
now rewrite (proof_irrelevance _ xp yp).
Qed.
Definition int0 := mkint 0 (conj eq_refl modulus_gt_0).
Parameter P : int -> Prop.
Axiom base_case : P int0.
Lemma modulo_Z_bound (z : Z) : -1 < z mod modulus < modulus.
Proof.
assert (tmp := Z.mod_pos_bound z modulus modulus_gt_0).
lia.
Qed.
Axiom rec_case : forall x, P x -> P (mkint _ (modulo_Z_bound (intval x + 1))).
Theorem foo: forall i, P i.
intros i; destruct i as [z zbounds].
revert zbounds.
induction z as [z Ih] using (well_founded_ind (Zwf_well_founded 0)).
intros zbounds.
assert (cases : z = 0 \/ 0 < z) by lia.
destruct cases as [case0 | casegt0].
revert zbounds; rewrite case0.
intros zbounds; assert (isint0 : {|intval := 0; intrange := zbounds|} = int0).
now apply intval_inj; simpl.
now rewrite isint0; apply base_case.
assert (zm1_bounds : -1 < z - 1 < modulus) by lia.
assert (dec : {| intval := z; intrange := zbounds|} =
mkint _ (modulo_Z_bound (intval (mkint _ zm1_bounds) + 1))).
apply intval_inj; simpl.
replace (z - 1 + 1) with z by ring.
symmetry; apply Z.mod_small; lia.
rewrite dec.
apply rec_case.
apply Ih.
unfold Zwf.
lia.
Qed.
Note that mkint _ (modulo_Z_bound (intval x + 1)) is just a way to write x + 1 when x has type int (with the convention that
the successor of the largest number is 0).
There is a way to avoid using the proof_irrelevance axiom, but this would make this answer even longer.

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.

Proof irrelevance for boolean equality

I'm trying to prove group axioms for Z_3 type:
Require Import Coq.Arith.PeanoNat.
Record Z_3 : Type := Z3
{
n :> nat;
proof : (Nat.ltb n 3) = true
}.
Proposition lt_0_3 : (0 <? 3) = true.
Proof.
simpl. reflexivity.
Qed.
Definition z3_0 : Z_3 := (Z3 0 lt_0_3).
Proposition lt_1_3 : (1 <? 3) = true.
Proof.
reflexivity.
Qed.
Definition z3_1 : Z_3 := (Z3 1 lt_1_3).
Proposition lt_2_3 : (2 <? 3) = true.
Proof.
reflexivity.
Qed.
Definition z3_2 : Z_3 := (Z3 2 lt_2_3).
Proposition three_ne_0 : 3 <> 0.
Proof.
discriminate.
Qed.
Lemma mod_upper_bound_bool : forall (a b : nat), (not (eq b O)) -> (Nat.ltb (a mod b) b) = true.
Proof.
intros a b H. apply (Nat.mod_upper_bound a b) in H. case Nat.ltb_spec0.
- reflexivity.
- intros Hcontr. contradiction.
Qed.
Definition Z3_op (x y: Z_3) : Z_3 :=
let a := (x + y) mod 3 in
Z3 a (mod_upper_bound_bool _ 3 three_ne_0).
Lemma Z3_eq n m p q : n = m -> Z3 n p = Z3 m q.
Proof.
intros H. revert p q. rewrite H. clear H. intros. apply f_equal.
We are almost done:
1 subgoal (ID 41)
n, m : nat
p, q : (m <? 3) = true
============================
p = q
What theorem should I use to prove that p = q?
Update 1
Theorem bool_dec :
(forall x y: bool, {x = y} + {x <> y}).
Proof.
intros x y. destruct x.
- destruct y.
+ left. reflexivity.
+ right. intro. discriminate H.
- destruct y.
+ right. intro. discriminate H.
+ left. reflexivity.
Qed.
Lemma Z3_eq n m p q : n = m -> Z3 n p = Z3 m q.
Proof.
intros H. revert p q. rewrite H. clear H. intros. apply f_equal. apply UIP_dec. apply bool_dec.
Qed.
You are probably interested in knowing that every two proofs of a decidable equality are equal. This is explained and proved here: https://coq.inria.fr/library/Coq.Logic.Eqdep_dec.html
You are interested in particular in the lemma UIP_dec: https://coq.inria.fr/library/Coq.Logic.Eqdep_dec.html#UIP_dec
Theorem UIP_dec :
forall (A:Type),
(forall x y:A, {x = y} + {x <> y}) ->
forall (x y:A) (p1 p2:x = y), p1 = p2.
You will have then to prove that equalities of booleans are decidable (i.e. that you can write a function which says whether two given booleans are equal or not) which you should also be able to find in the standard library but which should be easily provable by hand as well.
This is a different question but since you asked: bool_dec exists and even has that name!
The easy way to find it is to use the command
Search sumbool bool.
It will turn up several lemmata, including pretty early:
Bool.bool_dec: forall b1 b2 : bool, {b1 = b2} + {b1 <> b2}
Why did I search sumbool? sumbool is the type which is written above:
{ A } + { B } := sumbool A B
You can find it using the very nice Locate command:
Locate "{".
will turn up
"{ A } + { B }" := sumbool A B : type_scope (default interpretation)
(and other notations involving "{").

Z_3: left id proof

I am close to ending the proof for Z_3 left id. Here is what I have so far
Require Import Coq.Arith.PeanoNat.
Require Import Coq.Bool.Bool.
Require Import Coq.Logic.Eqdep_dec.
Record Z_3 : Type := Z3
{
n :> nat;
proof : (Nat.ltb n 3) = true
}.
Proposition lt_0_3 : (0 <? 3) = true.
Proof.
simpl. reflexivity.
Qed.
Definition z3_0 : Z_3 := (Z3 0 lt_0_3).
Proposition lt_1_3 : (1 <? 3) = true.
Proof.
reflexivity.
Qed.
Definition z3_1 : Z_3 := (Z3 1 lt_1_3).
Proposition lt_2_3 : (2 <? 3) = true.
Proof.
reflexivity.
Qed.
Definition z3_2 : Z_3 := (Z3 2 lt_2_3).
Proposition three_ne_0 : 3 <> 0.
Proof.
discriminate.
Qed.
Lemma mod_upper_bound_bool : forall (a b : nat), b <> O -> (a mod b <? b) = true.
Proof.
intros a b H. apply (Nat.mod_upper_bound a b) in H. case Nat.ltb_spec0.
- reflexivity.
- intros Hcontr. contradiction.
Qed.
Definition Z3_op (x y: Z_3) : Z_3 :=
let a := (x + y) mod 3 in
Z3 a (mod_upper_bound_bool _ 3 three_ne_0).
Lemma Z3_eq n m p q : n = m -> Z3 n p = Z3 m q.
Proof.
intros H. revert p q. rewrite H. clear H. intros. apply f_equal. apply UIP_dec. apply bool_dec.
Qed.
Proposition Z3_left_id' : forall x: Z_3, (Z3_op z3_0 x) = x.
Proof.
intro. unfold Z3_op. destruct x as [n proof]. apply Z3_eq.
Result:
1 subgoal (ID 46)
n : nat
proof : (n <? 3) = true
============================
(z3_0 + {| n := n; proof := proof |}) mod 3 = n
I found the following theorems that could be useful:
Nat.ltb_spec0
: forall x y : nat, reflect (x < y) (x <? y)
Nat.mod_small: forall a b : nat, a < b -> a mod b = a
Is it possible to get rid of profs in the goal, convert proof from bool to Prop, and then use Nat.mod_small?
Update
Proposition Z3_left_id' : forall x: Z_3, (Z3_op z3_0 x) = x.
Proof.
intro. unfold Z3_op. destruct x as [vx proof]. apply Z3_eq. unfold n, z3_0. rewrite plus_O_n. apply Nat.mod_small.
1 subgoal (ID 67)
vx : nat
proof : (vx <? 3) = true
============================
vx < 3
You need the coercion to execute. Unfortunately,
by naming the bound variable of your proof n and the projection from Z_3 to nat n, you painted yourself in a corner.
Here are four solutions:
1/ this one I mention just for the record: you can talk about the constant n that was defined in this file by using the file name as a module qualifier.
unfold user4035_oct_16.n.
user4035_oct_16 is the name of the current file, this is ugly.
2/ you could call a computation function that computes everything, however computation of modulo leaves unsightly terms in the goal, so you could decide to not compute that particular part.
cbn -[Nat.modulo].
I like this one, but it requires that you spend sometime learning how to use cbn.
3/ You can avoid the name clash by renaming variables in the goal.
rename n into m.
unfold n, Z3_0.
Not very nice either.
4/ Just go back in your script and replace destruct x as [n proof] with destruct x as [vx proof], then you can type:
unfold n, z3_0.
you will be able to use the lemmas you suggest.
Proof:
Proposition Z3_left_id : forall x: Z_3, (Z3_op z3_0 x) = x.
Proof.
intro. unfold Z3_op. destruct x as [vx proof]. apply Z3_eq. unfold n, z3_0. rewrite plus_O_n. apply Nat.mod_small. apply Nat.ltb_lt in proof. assumption.
Qed.

I want to do induction on Peano nats but I want to prove a property P over nats 1 ... n. Does Coq provide a tactic/tool to do this?

I want to prove something for natural numbers not including 0. So my base case for property P would be P 1 instead of P 0.
I'm considering using n >= 0 as a hypothesis in the goal, but is there another way to do this in Coq?
Consider shifting the property to become a property on all nats.
Definition P' (n : nat) := P (S n).
So forall n, n >= 1 -> P n is equivalent to forall n, P' n.
Just add n > 0 or n <> 0 as an assumption. Example:
Require Import Arith.
Goal forall n, n > 0 -> forall a, a = n - 1 -> a + 1 = n.
induction n; intros H.
- now apply Nat.nlt_0_r in H. (* This case, 0 > 0, is simply impossible *)
- intros a H1.
now rewrite H1; simpl; rewrite Nat.sub_0_r, Nat.add_comm.
Qed.
One possible variant is to perform directly a proof by induction on the property 0 <= n.
Require Import Arith.
Goal forall n, 1 <= n -> forall a, a = n - 1 -> a + 1 = n.
induction 1.
(* first case being considered is P 1. *)
now intros a a0; rewrite a0.
now simpl; intros a a_m; rewrite a_m, Nat.add_1_r, Nat.sub_0_r.
Qed.
This behavior is granted by the fact that the order _ <= _ is actually defined as an inductive relation.

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.