coq syntax of theorem implication - coq

I follow this tutorial : https://softwarefoundations.cis.upenn.edu/lf-current/Basics.html
Section 'Proof by Rewritting' :
The code
Theorem plus_id_example : forall n m : nat,
n = m =>
n + n = m + m.
Produces the error :
Syntax error: '.' expected after [vernac:gallina] (in [vernac_aux]).
I don't get what am I doing wrong ?
Also, what is the best place to get documentation ? I mean, beginner-friendly documentation.

To use the text as it's written on the page you linked, you need to import some notations. In particular, ∀ and → don't exist by default. To import these notations use Require Import Utf8.
Require Import Utf8.
Theorem plus_id_example : ∀n m:nat,
n = m →
n + n = m + m.
The ASCII equivalents of these notations are forall for ∀ (as you figured out) and -> for →. If you have the notations imported, you can see what they stand for using Locate. Locate "→". will have output
Notation
"x → y" := forall _ : x, y : type_scope
(default interpretation)
Of course, this doesn't give us ->, since -> is itself a notation for the same thing. Coq will display that notation by default, so if you input
Theorem plus_id_example : forall n m : nat,
forall _ : n = m,
n + n = m + m.
(without Utf8 imported), the output is
1 subgoal
______________________________________(1/1)
forall n m : nat, n = m -> n + n = m + m
which uses the -> notation.

Related

coq program module throws out my hypotheses

EDIT: I fixed the issue by using subtypes, ie changing
forall(i: nat) to
forall(i: {n: nat | n <? length})
but I would still like to know why the program module behaves like this and if there's anything I could have done about it. The two programs are logically equivalent, so it would be silly for one to type-check but the other not to.
I am trying to write this function
Program Fixpoint indomain_arr (m: mem) (a: array) :=
match a with Array _ length => forall(i: nat), (i< length -> indomain m (inr(El a i))) end.
Obligation 1.
The specifics are not too important, I don't think, except for the fact that I have (i < length) as a hypothesis. When I proceed to obligation 1, the proof state is
m : mem
wildcard' : string
length, i : nat
============================
i <? length
which is annoying, as it doesn't include the hypothesis I put in the output proposition specifically so that I could solve this obligation. What is the fix for this? How can I bring that hypothesis back into my context?
Thanks.
I tried this code with coq 8.11.1.
Require Import Program.
Require Import Arith.
Inductive P (n : nat) : (n =? 0 = true) -> Prop :=
| P_intro : forall p, P n p.
Program Definition f (n : nat) : Prop :=
forall (i : nat), i < n -> P i _.
Next Obligation.
This results in the proof state
n, i : nat
============================
(i =? 0) = true
which doesn't have i < n as an assumption.
I tried another definition of f.
Program Definition f (n : nat) : Prop :=
forall (i : nat) (Hsmall : i < n), P i _.
Next Obligation.
(note that the hypothesis i < n is explicitly named as Hsmall)
Now I have the hypothesis in my proof state.
n, i : nat
Hsmall : i < n
============================
(i =? 0) = true

Trouble in implementing dependently typed lookup in Coq using Equations

I'm trying to use Equations package to define a function over vectors in Coq. The minimum code that shows the problem that I will describe is available at the following gist.
My idea is to code a function that does a lookup on a "proof" that some type holds for all elements of a vector, which has a standard definition:
Inductive vec (A : Type) : nat -> Type :=
| VNil : vec A 0
| VCons : forall n, A -> vec A n -> vec A (S n).
Using the previous type, I had defined the following (also standard) lookup operation (using Equations):
Equations vlookup {A}{n}(i : fin n) (v : vec A n) : A :=
vlookup FZero (VCons x _) := x ;
vlookup (FSucc ix) (VCons _ xs) := vlookup ix xs.
Now, the trouble begins. I want to define the type of "proofs" that some
property holds for all elements in a vector. The following inductive type does this job:
Inductive vforall {A : Type}(P : A -> Type) : forall n, vec A n -> Type :=
| VFNil : vforall P _ VNil
| VFCons : forall n x xs,
P x -> vforall P n xs -> vforall P (S n) (VCons x xs).
Finally, the function that I want to define is
Equations vforall_lookup
{n}
{A : Type}
{P : A -> Type}
{xs : vec A n}
(idx : fin n) :
vforall P xs -> P (vlookup idx xs) :=
vforall_lookup FZero (VFCons _ _ pf _) := pf ;
vforall_lookup (FSucc ix) (VFCons _ _ _ ps) := vforall_lookup ix ps.
At leas to me, this definition make sense and it should type check. But, Equations had showed the following warning and left me with a proof obligation in which I had no idea on how to finish it.
The message presented after the definition of the previous function is:
Warning:
In environment
eos : end_of_section
fix_0 : forall (n : nat) (A : Type) (P : A -> Type) (xs : vec A n)
(idx : fin n) (v : vforall P xs),
vforall_lookup_ind n A P xs idx v (vforall_lookup idx v)
A : Type
P : A -> Type
n0 : nat
x : A
xs0 : vec A n0
idx : fin n0
p : P x
v : vforall P xs0
Unable to unify "VFCons P n0 x xs0 p v" with "v".
The obligation left is
Obligation 1 of vforall_lookup_ind_fun:
(forall (n : nat) (A : Type) (P : A -> Type) (xs : vec A n)
(idx : fin n) (v : vforall P xs),
vforall_lookup_ind n A P xs idx v (vforall_lookup idx v)).
Later, after looking at a similar definition in Agda standard library, I realised that the previous function definition is missing a case for the empty vector:
lookup : ∀ {a p} {A : Set a} {P : A → Set p} {k} {xs : Vec A k} →
(i : Fin k) → All P xs → P (Vec.lookup i xs)
lookup () []
lookup zero (px ∷ pxs) = px
lookup (suc i) (px ∷ pxs) = lookup i pxs
My question is, how can I specify that, for the empty vector case, the right hand side should be empty, i.e. a contradiction? The Equations manual shows an example for equality but I could adapt it to this case. Any idea on what am I doing wrong?
I think I finally understood what is going on in this example by looking closely at the obligation generated.
The definition is correct, and it is accepted (you can use vforall_lookup without solving the obligation). What fails to be generated is the induction principle associated to the function.
More precisely, Equations generates the right induction principle in three steps (this is detailed in the reference manual) in section "Elimination principle":
it generates the graph of the function (in my version of Equations it is called vforall_lookup_graph, in previous versions it was called vforall_lookup_ind). I am not sure that I fully understand what it is. Intuitively, it reflects the structure of the body of the function. In any case, it is a key component to generate the induction principle.
it proves that the function respects this graph (in a lemma called vforall_lookup_graph_correct or vforall_lookup_ind_fun);
it combines the last two results to generate the induction principle associated to the function (this lemma is called vforall_lookup_elim in all versions).
In your case, the graph was correctly generated but Equations was not able to prove automatically that the function respects its graph (step 2), so it is left to you.
Let's give it a try!
Next Obligation.
induction v.
- inversion idx.
- dependent elimination idx.
(* a powerful destruct provided by Equations
that correctly working with dependent types
*)
+ constructor.
+ constructor.
Coq rejects the last call to constructor with the error
Unable to unify "VFCons P n1 x xs p v" with "v".
This really looks like the error obtained in the first place, so I think the automatic resolution reached this same point and failed. Does this mean that we took a wrong path? Let's look closer at the goal before the second constructor.
We have to prove
vforall_lookup_graph (S n1) A P (VCons x xs) (FSucc f) (VFCons P n1 x xs p v) (vforall_lookup (FSucc f) (VFCons P n1 x xs p v))
while the type of vforall_lookup_graph_equation_2, the second constructor of vforall_lookup_graph_equation is
forall (n : nat) (A : Type) (P : A -> Type) (x : A) (xs0 : vec A n) (f : fin n) (p : P x) (v : vforall P xs0),
vforall_lookup_graph n A P xs0 f v (vforall_lookup f v) -> vforall_lookup_graph (S n) A P (VCons x xs0) (FSucc f) (VFCons P n x xs0 p v) (vforall_lookup f v)
The difference lies in the calls to vforall_lookup. In the first case, we have
vforall_lookup (FSucc f) (VFCons P n1 x xs p v)
and in the second case
vforall_lookup f v
But these are identical by definition of vforall_lookup! But by default the unification fails to recognize that. We need to help it a bit. We can either give the value of some argument, e.g.
apply (vforall_lookup_graph_equation_2 n0).
or we can use exact or refine that unify more aggressively than apply since they are given the whole term and not only its head
refine (vforall_lookup_graph_equation_2 _ _ _ _ _ _ _ _ _).
We can conclude easily by the induction hypothesis. This gives the following proof
Next Obligation.
induction v.
- inversion idx.
- dependent elimination idx.
+ constructor.
+ (* IHv is the induction hypothesis *)
exact (vforall_lookup_graph_equation_2 _ _ _ _ _ _ _ _ (IHv _)).
Defined.
Since I like doing proofs with dependent types by hand, I can't help giving a proof that does not use dependent elimination.
Next Obligation.
induction v.
- inversion idx.
- revert dependent xs.
refine (
match idx as id in fin k return
match k return fin k -> Type with
| 0 => fun _ => IDProp
| S n => fun _ => _
end id
with
| FZero => _
| FSucc f => _
end); intros.
+ constructor.
+ exact (vforall_lookup_graph_equation_2 _ _ _ _ _ _ _ _ (IHv _)).
Defined.

Excluded middle in axioms of real numbers

With Coq's axioms of real numbers completeness and total_order_T, using the same technique as in the standard lib lemma Un_cv_crit_lub, I managed to prove
Lemma NatForallDec : forall (f : nat -> bool),
{ forall n:nat, f n = false } + { ~forall n:nat, f n = false }.
and
Lemma NatForallDecIncr : forall (f : nat -> bool),
(forall n m:nat, f n = true -> n <= m -> f m = true)
-> { forall n:nat, f n = false } + { exists n:nat, f n = true }.
That is disturbing because it looks like some sort of oracle : if a proposition f about the natural numbers is decidable for each number, then the infinite conjunction of f becomes decidable too. So the axioms of the real numbers say that we can extract an algorithm which makes an infinite number of decisions in finite time...
Are there other examples of excluded middle that follow from the axioms of real numbers, and that have little to do with real numbers ?
And concerning real numbers, can a least upper bound be realized as a convergent sequence ?
Definition Cv_lub (A : R -> Prop) (l : R) (n : nat) :
is_lub A l
-> { x : R | A x /\ (l - x <= 1 / INR n)%R }.

Cannot rewrite subterm in Coq

I have a proof in Coq where one of the hypothesis is:
H : m = pred q * n + (r + n)
And I have a proven lemma which states:
Lemma suma_conmutativa: forall m, forall n, m + n = n + m.
Where + is Notation for a function called suma that I defined:
Fixpoint suma (m:nat) (n:nat) : nat :=
match m with
| 0 => n
| S k => S (suma k n)
end.
Notation "m + n" := (suma m n).
For some reason when I try to rewrite suma_conmutativa with r n in H I get the following error:
Error: Found no subterm matching "r + n" in H.
However, there clearly is a subterm matching r + n in H. Why can't Coq find it?
Thank you.
I am not an expert of notations in Coq, but here is how I understand your problem.
Coq replaces the first occurrence of + with suma. suma binds its arguments to scope nat_scope. Classic notation + is bound to nat_scope and is prefered for the second occurrence of +.
The solution I propose is to bound your notation to nat_scope to completely hide the original notation. This gives:
Notation "m + n" := (suma m n) : nat_scope.

Abstracting over the term ... leads to a term ... which is ill-typed

Here is what I am trying to prove:
A : Type
i : nat
index_f : nat → nat
n : nat
ip : n < i
partial_index_f : nat → option nat
L : partial_index_f (index_f n) ≡ Some n
V : ∀ i0 : nat, i0 < i → option A
l : ∀ z : nat, partial_index_f (index_f n) ≡ Some z → z < i
============================
V n ip
≡ match
partial_index_f (index_f n) as fn
return (partial_index_f (index_f n) ≡ fn → option A)
with
| Some z => λ p : partial_index_f (index_f n) ≡ Some z, V z (l z p)
| None => λ _ : partial_index_f (index_f n) ≡ None, None
end eq_refl
The obvious next step is either rewrite L or destruct (partial_index_f (index_f n). Trying to applying rewrite gives me an error:
Error: Abstracting over the term "partial_index_f (index_f n)"
leads to a term
"λ o : option nat,
V n ip
≡ match o as fn return (o ≡ fn → option A) with
| Some z => λ p : o ≡ Some z, V z (l z p)
| None => λ _ : o ≡ None, None
end eq_refl" which is ill-typed.
I do not understand what is causing this problem. I also would like to understand how I can deal with it in general.
I was able to prove it using the following steps, but I am not sure this is the best way:
destruct (partial_index_f (index_f n)).
inversion L.
generalize (l n0 eq_refl).
intros. subst n0.
replace l0 with ip by apply proof_irrelevance.
reflexivity.
congruence.
In Coq's theory, when you perform a rewrite with an equation, you have to generalize over the side of the equation that you want to replace. In your case, you want to replace partial_index_f (index_f n), so Coq tries to generalize that, as you can tell from the error message you got.
Now, if your goal contains something whose type mentions the thing that you want to replace, you might run into trouble, because this generalization might make the goal become ill-typed. (Notice that that type does not exactly occur in the goal, hence Coq does not try to deal with it like it does when something occurs in the goal.) Going back to your case, your l function has type ∀ z : nat, partial_index_f (index_f n) ≡ Some z → z < i, which mentions partial_index_f (index_f n), the term you want to replace. In the first branch of your match, you apply this function to the o = Some z hypothesis that you abstracted over. On the original goal, o was the thing you wanted to replace, but when Coq tries to generalize, the two do not match anymore, hence the error message.
I can't try to fix the problem on my own, but you can solve issues like this usually by generalizing over the term in your context that mentions the term you are replacing, because then its type will show in the goal, associated to a universally quantified variable. This might not help if your term is defined globally and you need it to have a certain shape after the rewrite in order to be able to perform additional reasoning steps, in which case you will probably have to generalize over the lemmas that you need as well.