I want to calculate a product of huge (specific) matrices. From a point complexity of view, the product should be taken the form of an elementwise expression.
I tried to "vectorize" the matrices with mxvec / vec_mx and calculate the product via one dimensional streams. But indices access was blocked by the term of enum ('I_p * 'I_q).
I want to know a nth value of enum ('I_p * 'I_q) because I want to decscribe a multiplication of matrices in the form of a primitive expression in an underlying field.
How do I do this? In particular, how do I prove this statement?
From mathcomp Require Import all_ssreflect.
Lemma nth_enum_prod p q (a : 'I_q) :
val a = index (ord0, a) (enum (prod_finType (ordinal_finType p.+1) (ordinal_finType q))).
I'm surprised you need to vectorize the matrices if your definition is point-wise, usually you should be able to define your result as \matrix_(i, j) op, for example the standard definition of matrix multiplication is:
\matrix_(i, k) \sum_j (A i j * B j k).
By the way, a quick "dirty" proof of your lemma is:
Lemma nth_enum_prod p q (a : 'I_q) : val a = index (#ord0 p, a) (enum predT).
Proof.
have /(_ _ 'I_q) pair_snd_inj: injective [eta pair ord0] by move => n T i j [].
have Hfst : (ord0, a) \in [seq (ord0, x2) | x2 <- enum 'I_q].
by move=> n; rewrite mem_map /= ?mem_enum.
rewrite enumT !unlock /= /prod_enum enum_ordS /= index_cat {}Hfst.
by rewrite index_map /= ?index_enum_ord.
Qed.
but indeed if you find yourself using this it means you are into a different kind of problem. I just posted it as an illustration on how to manipulate this kind of expressions.
edit: based on your comment, a more principled way to manipulate the above is to define a lemma about index and products; I've left the full proof as an exercise, but the outline is:
Lemma index_allpairs (T U : eqType) (x : T) (y : U) r s :
(* TODO: Some conditions are missing here *)
index (x,y) [seq (x,y) | x <- r , y <- s] =
size s * (index x r) + index y s.
Proof.
Admitted.
Lemma index_ord_allpairs p q (x : 'I_p) (y : 'I_q) :
index (x,y) [seq (x,y) | x <- enum 'I_p , y <- enum 'I_q] = q * x + y.
Proof. by rewrite index_allpairs ?mem_enum ?size_enum_ord ?index_enum_ord. Qed.
Lemma nth_enum_prod p q (a : 'I_q) : val a = index (#ord0 p, a) (enum predT).
Proof. by rewrite enumT unlock index_ord_allpairs muln0. Qed.
Related
I'm trying to do a simple function that like this
Fixpoint find_0 (n : BinNums.Z) :=
match n with
Z0 => n
| Zpos p => find_0 p
| Zneg q => find_0 q
end.
But p is positive and not Z so this is ill typed.
If I try
Fixpoint find_0 (n : BinNums.Z) :=
match n with
Z0 => n
| Zpos p => find_0 (n - 1)
| Zneg q => find_0 (n + 1)
end.
then Coq can't verify that this is strong normalizing, the error
Recursive definition of find_0 is ill-formed.
In environment
find_0 : BinNums.Z -> BinNums.Z
n : BinNums.Z
p : positive
Recursive call to find_0 has principal argument equal to
"n - 1" instead of a subterm of "n".
Recursive definition is:
"fun n : BinNums.Z =>
match n with
| 0 => n
| Z.pos _ => find_0 (n - 1)
| BinInt.Z.neg _ => find_0 (n + 1)%Z
end".
What to do in this situation?
Regards
Since the definition of Bignums.Z:
Inductive Z : Set :=
Z0 : Z
| Zpos : positive -> Z
| Zneg : positive -> Z.
is not recursive, you cannot write recursive functions over it. Instead you write a simple non recursive Definition to handle the constructors of Bignums.Z and there you call recursive functions you define on positives. It is also good style to define the functions you need on positives separataely on positives.
Every recursive function in Coq must clearly have a decreasing aspect. For many inductive types, this decreasing aspect is provided naturally by the recursive structure of this inductive type. If you look at the definition of positive, you see this:
Inductive positive : Set :=
xI : positive -> positive | xO : positive -> positive | xH : positive.
When an object p of type positive fits the pattern xO q, q is visibly smaller than p, if only as a piece of data (and here because the agreed meaning of xO is multiplication by 2, q is also numerically smaller than p).
When looking at the data type for Z, you see that there is no recursion and thus no visible decreasing pattern, where the smaller object would also be of type Z, so you cannot write a recursive function using the Fixpoint approach.
However, there exists an extension of Coq, called Equations, that will make it possible to write the function you want. The trick is that you still need to explain that something is decreasing during the recursive call. This calls for an extra object, a relation that is known to have no infinite path. Such a relation is called well-founded. Here the relation we will use is called Zwf.
From Equations Require Import Equations.
Require Import ZArith Zwf Lia.
#[export]Instance Zwf_wf (base : Z) : WellFounded (Zwf base).
Proof.
constructor; apply Zwf_well_founded.
Qed.
Equations find0 (x : Z) : Z by wf (Z.abs x) (Zwf 0) :=
find0 Z0 := Z0; find0 (Zpos p) := find0 (Zpos p - 1);
find0 (Zneg p) := find0 (Zneg p + 1).
Next Obligation.
set (x := Z.pos p); change (Zwf 0 (Z.abs (x - 1)) (Z.abs x)).
unfold Zwf. lia.
Qed.
Next Obligation.
set (x := Z.neg p); change (Zwf 0 (Z.abs (x + 1)) (Z.abs x)).
unfold Zwf. lia.
Qed.
There is a little more work than for a direct recursive function using Fixpoint, because we need to explain that we are using a well founded relation, make sure the Equations extension will find the information (this is the purpose of the Instance part of the script. Then, we also need to show that each recursive call satisfies the decrease property. Here, what decreases is the numeric value of the absolute value of the integer.
The Equations tool will gives you a collection of theorems to help reason on the find0 function. In particular, theorems find0_equation1, find0_equation2, and find0_equation3 really express that we defined a function that follows the algorithm you intended.
In the ℝn - n-dimensional Euclidean space R^n with the standard inner product, which is the dot product, the Cauchy–Schwarz inequality becomes:
[1]: https://i.stack.imgur.com/ZNBfx.png
Is anyone aware of an implementation for sums of Cauchy-Schwartz Inequality in Coq, e.g. infotheo?
Another proof is in https://github.com/math-comp/math-comp/blob/f4fb83f19cbe9503f7cfe03ba8217311744e33ac/mathcomp/character/classfun.v#L943
Lemma cfCauchySchwarz phi psi :
`|'[phi, psi]| ^+ 2 <= '[phi] * '[psi] ?= iff ~~ free (phi :: psi).
but note that in this case the proof has not been generalized over arbitrary dot products on pre-hilbert spaces, but it would work.
https://github.com/roglo/cauchy_schwarz
compiles with Coq 13.1 and has the theorem
Cauchy_Schwarz_inequality
: ∀ (u v : list R) (n : nat),
(Σ (k = 1, n), (u.[k] * v.[k])²
≤ Σ (k = 1, n), ((u.[k])²) * Σ (k = 1, n), ((v.[k])²))%R
I am trying to prove the following theorem after formalizing lambda calculus with Debruijn indices and substitution in Coq.
Theorem atom_equality : forall e : expression , forall x : nat,
(beta_reduction (Var x) e) -> (e = Var x).
and these are the definitions for expression and beta reduction
Inductive expression : Type :=
| Var (n : nat)
| Abstraction (e : expression)
| Application (e1 : expression) (e2 : expression).
.
.
Inductive beta_reduction : expression -> expression -> Prop :=
| beta_1step (x y : expression) : beta_1reduction x y -> beta_reduction x y
| beta_reflexivity (x : expression) : beta_reduction x x
| beta_transitivity (x y z : expression) : beta_reduction x y -> beta_reduction y z -> beta_reduction x z.
I am stuck in a loop while trying to prove this theorem.
Proof.
intro e. induction e.
- intros. inversion H.
After applying these steps, these are the hypothesis and subgoals I've to work with
3 subgoals
n, x : nat
H : beta_reduction (Var x) (Var n)
x0, y : expression
H0 : beta_1reduction (Var x) (Var n)
H1 : x0 = Var x
H2 : y = Var n
______________________________________(1/3)
Var n = Var x
______________________________________(2/3)
Var n = Var n
______________________________________(3/3)
Var n = Var x
I can solve the first subgoal by "inversion H0" tactic and second subgoal by "reflexivity". However when I reach the third subgoal, this is what I am left with
1 subgoal
n, x : nat
H : beta_reduction (Var x) (Var n)
x0, y, z : expression
H0 : beta_reduction (Var x) y
H1 : beta_reduction y (Var n)
H2 : x0 = Var x
H3 : z = Var n
______________________________________(1/1)
Var n = Var x
This is exactly what I started with. I will have to prove that y can only take the value of Var x for H0 to be provable.
(beta_1reduction is the one step beta reduction of lambda calculus, and beta_reduction is its reflexive, transitive closure)
You are stuck because inversion on H is not enough. Instead, you would need a kind of induction on H to provide you with the needed hypothesis in the transitive case, to allow you to conclude.
However, since H's type is an inductive predicate, induction on it is tricky. Indeed, if you use the usual induction H., Coq will lose all informations about the indices in H's type, and especially the Var x one. This will make your proof attempts fail.
Instead, what you can use is rely on the dependent induction tactic (you will need to Require Import Program.Equality to have access to this tactic). This tactic automatically handles the kind of induction on inductive predicates where the indices are not variables. Here you could start your proof with intros e n H. dependent induction H. and the rest should be easy.
In general, when you define inductive predicates (such as beta_reduction) over inductive datatypes (such as expression), and you want to use hypothesis using those inductive predicates (here H), doing induction directly on the predicate (using dependent induction) as we did here is very powerful. In particular, it specializes which constructors of your datatype can appear in the inductive hypothesis, thus in a way performs a kind of induction on the datatype at the same time.
#Meven's answer is a good explanation of what is wrong and gives a good solution. If you want to do it without the dependent induction tactic, you can remember the lost information yourself.
Proof.
(beta_reduction (Var x) e) -> (e = Var x).
intros e x H.
remember (Var x) as q eqn:Hq.
induction H; rewrite Hq in *.
- inversion H.
- reflexivity.
- rewrite IHbeta_reduction1 in IHbeta_reduction2.
apply IHbeta_reduction2.
reflexivity.
reflexivity.
Qed.
In order to understand how general recursive Function definitions works, and how they comply with Coq's structural recursion constraint, I tried to reimplement it on the Peano natural numbers. I want to define recursive nat -> nat functions that can use any previous values, not just the predecessor. Here is what I did :
Definition nat_strong_induction_set
(* erased at extraction, type specification *)
(P : nat -> Set)
(* The strong induction step. To build the P n it can, but does not have to,
recursively query the construction of any previous P k's. *)
(ind_step : forall n : nat, (forall k : nat, (lt k n -> P k)) -> P n)
(n : nat)
: P n.
Proof.
(* Force the hypothesis of ind_step as a standard induction hypothesis *)
assert (forall m k : nat, lt k m -> P k) as partial_build.
{ induction m.
- intros k H0. destruct k; inversion H0.
- intros k H0. apply ind_step. intros k0 H1. apply IHm. apply (lt_transitive k0 k).
assumption. apply le_lt_equiv. assumption. }
apply (partial_build (S n) n). apply succ_lt.
Defined.
I used some custom lemmas on nats that I didn't paste here. It works, I managed to define the euclidean division div a b with it, which recursively uses div (a-b) b. The extraction is almost what I expected :
let nat_strong_induction_set ind_step n =
let m = S n in
let rec f n0 k =
match n0 with
| O -> assert false (* absurd case *)
| S n1 -> ind_step k (fun k0 _ -> f n1 k0)
in f m n
Except for the n0 parameter. We see that the only effect of this parameter is to stop the recursion at the S n-nth step. The extraction also mentions that this assert false should not happen. So why is it extracted ? This seems better
let nat_strong_induction_set ind_step n =
let rec f k = ind_step k (fun k0 _ -> f k0)
in f n
It looks like a glitch of Coq's structural recursion constraint, to ensure the termination of all recursions. The Coq definition of nat_strong_induction_set writes lt k n, so Coq knows only previous P k's will be queried. This makes a decreasing chain in the nats, which is forced to terminate in less than S n steps. This allows a structural recursive definition on an additional fuel parameter n0 starting at S n, it won't affect the result. So if it is only a part of the termination proof, why is it not erased by the extraction ?
Your match is not erased because your definition mixes two things: the termination argument, where the match is needed, and the computationally relevant recursive call, where it isn't.
To force erasure, you need to convince Coq that the match is computationally irrelevant. You can do so by making the termination argument -- that is, the induction on m -- produce the proof of a proposition instead of a function of type forall m k, lt k m -> P k. Luckily, the standard library provides an easy way of doing so, with the Fix combinator:
Require Import Coq.Arith.Wf_nat.
Definition nat_strong_induction_set
(P : nat -> Set)
(ind_step : forall n : nat, (forall k : nat, (lt k n -> P k)) -> P n)
(n : nat)
: P n :=
Fix lt_wf P ind_step n.
Here, lt_wf is a proof that lt is well-founded. When you extract this function, you get
let rec nat_strong_induction_set ind_step n =
ind_step n (fun y _ -> nat_strong_induction_set ind_step y)
which is exactly what you wanted.
(As an aside, note that you don't need well-founded recursion to define division -- check for instance how it is defined in the Mathematical Components library.)
I'm new to Coq and am doing some exercises to get more familiar with it.
My understanding is that proving a proposition in Coq "really" is writing down a type in Gallina and then showing that it's inhabited using tactics to combine terms together in deterministic ways.
I'm wondering if there's a way to get a pretty-printed representation of the actual term, with all the tactics removed.
In the example below, an anonymous term of type plus_comm (x y : N) : plus x y = plus y x is ultimately produced... I think. What should I do if I want to look at it? In a certain sense, I'm curious what the tactics "desugar" to.
Here's the code in question, lifted essentially verbatim from a tutorial on YouTube https://www.youtube.com/watch?v=OaIn7g8BAIc.
Inductive N : Type :=
| O : N
| S : N -> N
.
Fixpoint plus (x y : N) : N :=
match x with
| O => y
| S x' => S (plus x' y)
end.
Lemma plus_0 (x : N) : plus x O = x.
Proof.
induction x.
- simpl. reflexivity.
- simpl. rewrite IHx. reflexivity.
Qed.
Lemma plus_S (x y : N) : plus x (S y) = S(plus x y).
Proof.
induction x.
- simpl. reflexivity.
- simpl. rewrite IHx. reflexivity.
Qed.
Lemma plus_comm (x y : N) : plus x y = plus y x.
Proof.
induction x.
- simpl. rewrite plus_0. reflexivity.
- simpl. rewrite IHx. rewrite plus_S. reflexivity.
Qed.
First of all, plus_comm is not a part of the type. You get a term named plus_comm of type forall x y : N, plus x y = plus y x. You can check it using the following command
Check plus_comm.
So, an alternative way of defining the plus_comm lemma is
Lemma plus_comm : forall x y : N, plus x y = plus y x.
As a side note: in this case you'll need to add intros x y. (or just intros.) after the Proof. part.
Tactics (and the means to glue them together) are a metalanguage called Ltac, because they are used to produce terms of another language, called Gallina, which is the specification language of Coq.
For example, forall x y : N, plus x y = plus y x is an instance of Gallina sentence as well as the body of the plus function. To obtain the term attached to plus_comm use the Print command:
Print plus_comm.
plus_comm =
fun x y : N =>
N_ind (fun x0 : N => plus x0 y = plus y x0)
(eq_ind_r (fun n : N => y = n) eq_refl (plus_0 y))
(fun (x0 : N) (IHx : plus x0 y = plus y x0) =>
eq_ind_r (fun n : N => S n = plus y (S x0))
(eq_ind_r (fun n : N => S (plus y x0) = n) eq_refl (plus_S y x0))
IHx) x
: forall x y : N, plus x y = plus y x
It is not an easy read, but with some experience you'll be able to understand it.
Incidentally, here is how we could have proved the lemma not using tactics:
Definition plus_comm : forall x y : N, plus x y = plus y x :=
fix IH (x y : N) :=
match x return plus x y = plus y x with
| O => eq_sym (plus_0 y)
| S x => eq_ind _ (fun p => S p = plus y (S x)) (eq_sym (plus_S y x)) _ (eq_sym (IH x y))
end.
To explain a few things: fix is the means of defining recursive functions, eq_sym is used to change x = y into y = x, and eq_ind corresponds to the rewrite tactic.