How to use Coq arithmetic solver tactics with SSReflect arithmetic statements - coq

Coq has some convenient tactics for automatically proving arithmetic lemmas, for instance lia:
From Coq Require Import ssreflect ssrfun ssrbool.
From mathcomp Require Import ssrnat.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Require Import Psatz.
Lemma obv : forall (x y z: nat), (x < y)%coq_nat -> (y < z)%coq_nat -> (z < 3)%coq_nat -> (x < 3)%coq_nat.
Proof.
move => x y z xlty yltz zlt3. lia.
Qed.
The tactics do not directly support SSReflect-style boolean reflection statements however:
Lemma obv_ssr: forall (x y z: nat), (x < y) && (y < z) && (z < 3) -> (x < 3).
Proof.
move => x y z H. Fail lia.
Abort.
Lemma obv_ssr: forall (x y z: nat), (x < y) -> (y < z) -> (z < 3) -> (x < 3).
Proof.
move => x y z xlty yltz zlt3. Fail lia.
Abort.
It's possible to solve them by converting to non-SSR format using views:
Lemma obv_ssr: forall (x y z: nat), (x < y) && (y < z) && (z < 3) -> (x < 3).
Proof.
move => x y z. move/andP => [/andP [/ltP x_lt_y /ltP y_lt_z] /ltP z_lt_3].
apply/ltP. lia.
Qed.
This is however very manual. Is there some kind of technique/approach/tactic that can automate this application of lemmas like lia to SSR-style statements?

This is not yet a totally resolved issue in general: you can track its progress here.
In your particular example the following is enough:
Lemma obv_ssr: forall (x y z: nat), (x < y) && (y < z) && (z < 3) -> (x < 3).
Proof.
move=> x y z.
rewrite -?(rwP andP) -?(rwP ltP).
lia.
Qed.
Sometimes you might want to throw in some more conversions of the standard arithmetic types using something like rewrite -?plusE -?multE -?minusE (adding more conversions if you have more arithmetic operations in your goal).
There are at least two projects trying to resolve the issue in general:
https://github.com/amahboubi/lia4mathcomp (see ssrnatlia tactic there, but I unless I'm mistaken it cannot solve your goal).
https://github.com/pi8027/mczify -- an active project with a different architecture and as far as I know it should be capable of solving a lot of SSReflect-style goals.

Related

induction integer record in 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.

Coq - prove that there exists a maximal element in a non empty sequence

As an exercise I want to prove that there is always exists a maximum element in a non-empty sequence.
Theorem largest_el_in_list (s: seq rat) x : x \in s -> exists y, y \in s /\ forall z, z \in s -> y >= z.
My idea was to go by induction on s, and then to destruct x. The largest element in this first case is the only element in the list. However, in the second case I'm getting quite confused. Am I supposed to use the inductive hypothesis? My idea was that we can get rid of the existential by exists max a a1, where a is the maximal element we found in the previous step, and a1 is the new element being added to the sequence. But if I do this, then I can't use the inductive hypothesis and I get completely stuck.
I've been stuck for hours and would love to know if I have the right idea.
Edit:
Here is the proof so far, with the current proof state below:
Theorem largest_el_in_list (s: seq rat) x : x \in s -> exists y, y \in s /\ forall z, z \in s -> y >= z.
Proof.
elim/last_ind : s => //= s x0 IH x_in_rcons.
case : s IH x_in_rcons.
move => _ x_in_sx0.
exists x0. split.
rewrite in_cons. apply/orP. left. by apply/eqP.
rewrite in_cons in x_in_sx0. case/orP : x_in_sx0 => //= xeqx0 z z_in_sx0.
rewrite in_cons in z_in_sx0. case/orP : z_in_sx0 => //= zeqx0. case/eqP : zeqx0 => zeqx0.
by rewrite zeqx0.
move => a l IH x_in_rcons.
exists (maxr x0 a). split.
have [agex0 | x0gta] := (lerP x0 a).
by rewrite mem_head.
rewrite rcons_cons in_cons. apply/orP. right. by rewrite in_rcons.
move => z z_in_rcons.
Admitted.
Proof state:
x: rat_eqType
x0, a: rat
l: seq rat
IH: x \in a :: l ->
exists y : rat, y \in a :: l /\ (forall z : rat, z \in a :: l -> z <= y)
x_in_rcons: x \in rcons (a :: l) x0
z: rat
z_in_rcons: z \in rcons (a :: l) x0
-------------------------------
(1/1)
z <= maxr x0 a
ANOTHER EDIT:
Imports:
From finprob Require Import prob.
From mathcomp Require Import all_ssreflect all_algebra seq.
From extructures Require Import ord fset fmap ffun.
Import Num.Theory.
Import GRing.
Import Bool.
Import Num.Def.
You can find extructures here https://github.com/arthuraa/extructures
And finprob here https://github.com/arthuraa/finprob
UPDATE:
Although changing the definition clears the path, there is still an issue. Here is the updated proof and proof state:
Theorem largest_el_in_list (s: seq rat) : s != [::] -> exists y, y \in s /\ forall z, z \in s -> y >= z.
Proof.
elim/last_ind : s => //= s x0 IH x_in_rcons.
case : s IH x_in_rcons.
move => _ x_in_sx0.
exists x0. split.
rewrite in_cons. apply/orP. left. by apply/eqP.
move => z z_in_cons.
rewrite in_cons in z_in_cons.
case/orP : z_in_cons => //= zeqx0.
case/eqP : zeqx0 => zeqx0. by rewrite zeqx0.
move => a l IH cons_nempty.
case IH => //= x [x_in_cons IH'].
exists x.
split.
rewrite in_cons in x_in_cons.
rewrite in_cons.
case/orP : x_in_cons => [xeqa | x_in_l].
by rewrite xeqa orTb. apply/orP. right. rewrite in_rcons. apply/orP. by right.
move => z z_in_cons.
apply IH'.
rewrite in_cons. rewrite in_cons in z_in_cons.
case/orP : z_in_cons => [zeqa | z_in_cons].
by rewrite zeqa orTb.
Admitted.
x0, a: rat
l: seq rat
IH: a :: l != [::] ->
exists y : rat, y \in a :: l /\ (forall z : rat, z \in a :: l -> z <= y)
cons_nempty: rcons (a :: l) x0 != [::]
x: rat
x_in_cons: x \in a :: l
IH': forall z : rat, z \in a :: l -> z <= x
z: rat
z_in_cons: z \in rcons l x0
-------------------------
(1/1)
(z == a) || (z \in l)
I don't see how this can be true, because we know from z_in_cons that z is either equal to x0, or it is in l. Thus, if we go by cases, the first case is impossible because we are lacking some information about x0.
Another approach would be to explicitly provide, right from the start, a value for y, the existence of which you are looking for. This should be the maximum of the list, which you could either specify yourself, via a Fixpoint definition, or be the maximum as defined in Coq.
But if you want to keep the proof by induction, as you suggest in your comment, here is one way (I suppose one can write it in a more concise manner). I'm using here nat instead of rat, for convenience:
Theorem largest_el_in_list (s: seq nat) :
s != [::] -> exists y, y \in s /\ forall z, z \in s -> y >= z.
Proof.
elim: s => [//=|n s IH _].
have [/eqP ->|/IH [max [maxins ismax]]] := boolP (s == nil).
- exists n.
split=> [|y]; first by rewrite in_cons eq_refl orTb.
by rewrite in_cons ?in_nil => /orP [/eqP ->|].
- have [lenx|] := boolP (n <= max).
- exists max.
split=> [|z]; first by rewrite in_cons maxins orbT.
by rewrite in_cons => /orP [/eqP ->|/ismax].
- rewrite -ltnNge.
exists n.
split=> [|z]; first by rewrite in_cons eq_refl orTb.
rewrite in_cons => /orP [/eqP -> //|/ismax ltzx].
by rewrite (#leq_trans max) // ltnW.
Qed.
May be the issue comes from the variable x.
A possible fix is to have x universally quantified, e.g. by starting the proof with a move: x (before the induction on s).
Another solution would be to remove x, which occurs only once in your statement and makes the subgoals hard to read, and prove instead:
Theorem largest_el_in_list (s: seq rat) : s <> nil ->
exists y, y \in s /\ forall z, z \in s -> y >= z.

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.

Case splitting on if-then-else condition

This is a silly beginner question, but how do I prove this theorem?
Open Scope Z.
Theorem test : forall x y:Z, (x > 0 -> y = 1) \/ (x <= 0 -> y = 2) -> y >= 1.
Proof.
intros.
destruct x.
destruct H.
(* stuck *)
Qed.
What I'm really trying to do is model an if-then-else statement as a Prop and case split on the condition to prove it. I get stuck with the context like this:
y: nat
H: 0 > 0 -> y = 1
-----------------
(1/3)
y >= 1
(2/3)
y >= 1
(3/3)
y >= 1
I sort of understand that to get rid of impossible cases, I need to find a contradiction in the hypothesis, but how do I do that here?
Advice on how this could be done better is welcome, e.g. is this the best way to model if-then-else?
how do I prove this theorem?
Theorem test : forall x y:Z, (x > 0 -> y = 1) \/ (x <= 0 -> y = 2) -> y >= 1.
Your theorem is not true.
Suppose H: x > 0 -> y = 1 but x is actully 0, then you have no way of proving y >= 1 as you know nothing about y.
Perhaps you meant to use and (/\) instead of or? Then here's one proof that uses lia to do the tedious Z arithmetic.
Require Import ZArith Lia. Open Scope Z.
Theorem test : forall x y:Z, (x > 0 -> y = 1) /\ (x <= 0 -> y = 2) -> y >= 1.
Proof. intros x y [H1 H2]. enough (x>0 \/ x<=0) as [H|H]; lia. Qed.
I think what you are looking for is the lemma
Z_lt_le_dec : forall x y : Z, {x < y} + {y <= x}
of the library. What { … } + { … } means is similar to \/, i.e. it is a kind of disjuction, but here this disjuction constructs a type in Set rather than Prop. This means that while you cannot use a \/ disjuction to build a function returning a nat (because of Coq’s enforcement that propositions should be irrelevant) you can use a { … } + { … } one. You can write
Definition test (x : Z) := if (Z_lt_le_dec 0 x) then 1 else 2.
which is syntactic sugar for a pattern matching like this one
Definition test (x : Z) := match (Z_lt_le_dec 0 x) with
| left _ => 1
| right _ => 2
end.
where left and right are the two constructors of { … } + { … }.
To check that this test does what it should, you can now try to go and prove
Lemma test_ge1 (x : Z) : 1 <= test x.

diffefentiation of (1/2)*(x-y)^2 on x is x - y

I want to prove following.
Require Import Coq.Reals.Reals.
Require Import Coquelicot.Coquelicot.
Goal forall x y:R, is_derive (fun x:R => (1/2)*(x-y)^2) x (x-y).
intros x y.
evar (e:R).
replace (x-y) with e.
apply is_derive_scal.
apply is_derive_pow.
I know that differentiation of x - y on x is 1, but I can not find the lemma which represents it.
How do I prove it?
Most of the tedious work can be done with Coquelicot's auto_derive tactic.
Require Import Coq.Reals.Reals.
Require Import Coquelicot.Coquelicot.
Require Import Lra.
Goal forall x y:R, is_derive (fun x:R => (1/2)*(x-y)^2) x (x-y).
intros.
auto_derive.
auto.
lra.
Qed.
However, the lemma that you are asking for can be built from is_derive_plus, because subtraction is just addition with negative values.
Variables x y:R.
Check is_derive_plus (fun x => x) (fun x => - y) x 1 0 (is_derive_id _) (is_derive_const _ _)
: is_derive (fun x => x - y) x (1+0).