Teach Coq that associative law of natural numbers holds - coq

I have a simple question.
I want to teach Coq that there is vec_assoc.
Require Import Coq.Vectors.Vector.
Lemma vec_assoc (A:Type)(a b c:nat): t A ((a+b)+c) = t A (a+(b+c)).
Proof.
f_equal. symmetry. apply Nat.add_assoc. Qed.
Variable a b c:nat.
Variable A B:Type.
Variable I : (t A ((a+b)+c) -> B).
Variable p:t A (a+(b+c)).
Coq returns an error
`The term "p" has type "vector A (a + (b + c))"
while it is expected to have type "vector A (a + b + c)".`
When I execute Compute I p.
How do I teach Coq that associative law of natural number holds?

Well, associativity does not hold with respect to convertibility of Coq terms, it only holds propositionally. What that means is that in a context where a, b c : nat you can build a term pf : a + (b + c) = (a + b) + c but it is not the case that the specific proof eq_refl can be given the type a + (b + c) = (a + b) + c.
In your case, since you already have a proof that t A (a + (b + c)) = t A ((a + b) + c) you could do the application by first transporting p along this equality using eq_rect or the rew vec_assoc A a b c in p syntax from the module EqNotations of the standard library (just add Import EqNotations.).
In any case nothing will compute since both I and p are variables (and the proof vec_assoc is opaque thanks to Qed).

Related

Can't use PeanoNat.Nat.add_assoc in proof

Require Import PeanoNat.
Check PeanoNat.Nat.add_assoc.
Output:
Nat.add_assoc
: forall n m p : nat, n + (m + p) = n + m + p
So, the theorem is defined.
But when I create a theorem and try to use it, it gives an error:
Theorem a : forall a b c d e f,
a + b + c + d + e = f.
Proof.
intros.
PeanoNat.Nat.add_assoc a (b + c) d.
Error: The reference PeanoNat.Nat.add_assoc was not found in the
current environment.
Why can't it find the theorem?
What comes after Proof. is not the proof itself. It's a series of instructions, called tactics, that tells Coq how to build a proof. add_assoc is a proof, not a tactic that builds a proof. You would use the tactic rewrite (Nat.add_assoc a (b + c) d) to rewrite (any part of) the goal according to the equality
Nat.add_assoc a (b + c) d
: a + (b + c + d) = a + (b + c) + d
However, your goal a + b + c + d + e = f does not contain either of those terms—+ is left associative and your goal is actually (((a + b) + c) + d) + e = f—so this tactic will fail. In fact, your goal is unprovable, but I assume that it's just for example. You may also be interested in the tactic apply [prf]. It takes the conclusion (thing on the right side of all the ->s and foralls) of prf, matches it against the goal, and gives you subgoals for all of its hypotheses. See also: the Coq tactic reference.

Coq: How to rewrite inside a lambda?

Basically, I want to prove the following lemma, but I'm having trouble since I can't seem to directly rewrite inside of the lambdas.
However I feel like this should be possible, because if I were "inside" the lambda, I could easily prove it for any given x.
Lemma lemma :
forall {A B : Type} (f : A -> B) (g : A -> B),
(forall (x : A), f x = g x) -> (fun x => f x) = (fun x => g x).
The statement you're trying to prove is (essentially) functional extentionality, which is well-known to not be provable in Coq without extra axioms. Basically, the idea is that f and g can be intentionally very different (their definitions can look different), but still take on the same values. Equality of functions (fun x => f x) = (fun x => g x) would (without any additional axioms) imply that the two functions are syntactically the same.
For example, take f(n) = 0 and g(n) = 1 if x^(3 + n) + y^(3 + n) = z^(3 + n) has a non-trivial solution in integers, otherwise 0 (both functions from natural numbers to natural numbers). Then f and g are intentionally different - one doesn't syntactically reduce to the other. However, thanks to Andrew Wiles, we know that f and g are extentionally the same since g(n) = 0 for all n.
You can freely add your lemma (or various strengthenings) as an axiom to Coq without worrying about inconsistency.

rewrite single occurence in ltac

How can I invoke rewrite in ltac to only rewrite one occurrence? I think coq's documentation mentions something about rewrite at but I haven't been able to actually use it in practice and there are no examples.
This is an example of what I am trying to do:
Definition f (a b: nat): nat.
Admitted.
Theorem theorem1: forall a b: nat, f a b = 4.
Admitted.
Theorem theorem2: forall (a b: nat), (f a b) + (f a b) = 8.
Proof.
intros a b.
(*
my goal here is f a b + f a b = 8
I want to only rewrite the first f a b
The following tactic call doesn't work
*)
rewrite -> theorem1 at 1.
When I try rewrite -> theorem1 at 1. as you suggest, I get the
following error message:
Error: Tactic failure: Setoid library not loaded.
So, as a reaction, I restarted your script, including the following command
at the very beginning.
Require Import Setoid.
And now, it works (I am testing with coq 8.6).
You are using the rewrite at variant of the tactic, which as the manual specifies is always performed via setoid rewriting (see https://coq.inria.fr/refman/Reference-Manual010.html#hevea_tactic121).
Another possibility to have finer control over your rewriting rules is to assert the general shape of your desired rewrite (which here one would prove via theorem1), then perform a focused rewrite with the new hypothesis.
This works without resort to any libraries:
intros a b.
assert (H: f a b + f a b = 4 + f a b) by (rewrite theorem1; reflexivity).
rewrite H.
There are several options, one of them was pointed out by #Yves.
Another option is to use the pattern tactic:
pattern (f a b) at 1.
rewrite theorem1.
The trick here is in fact that pattern (f a b) at 1. turns the goal
f a b + f a b = 8
into
(fun n : nat => n + f a b = 8) (f a b)
Basically, it beta-expands your goal, abstracting on the first occurrence of f a b. Also, normally rewrite won't rewrite under binders (e.g. lambdas), because if it did, you'd be able to go from let's say fun x => x + 0 to fun x => x, which are not equal in vanilla Coq.
Then rewrite theorem1. rewrites the argument (f a b) to 4 and simplifies a bit (it does beta-reduction), hence you obtain 4 + f a b = 8.
Side note: you can also use the replace tactic like so:
replace (f a b + f a b) with (4 + f a b) by now rewrite theorem1.

can I force Coq to print parentheses?

I'm new to Coq, working on set-theoretic proof writing.
I realized that parentheses are omitted, and it makes difficult for me to read the formula. For example,
1 subgoal
A, B : {set T}
H : B \subset A
______________________________________(1/1)
A :\: A :|: A :&: B = B
But I would like Coq to print (A :\: A) :|: (A :&: B) = B. This output above is gained by the foloowing code.
Require Import ssreflect ssrbool ssrnat fintype finset.
Theorem a_a_b__b' (A B : {set T}) : B \subset A -> (A :\: (A :\: B)) = B.
Proof.
move=> H.
rewrite setDDr.
To my surprise, if I see the original coding of setDDr in finset.v, it has parentheses as follows
Lemma setDDr A B C : A :\: (B :\: C) = (A :\: B) :|: (A :&: C).
Proof. by rewrite !setDE setCI setIUr setCK. Qed.
So I'm wondering why parentheses disappear and how to force Coq to print parentheses explicitly in CoqIde.
You can turn off all notations with this command:
Unset Printing Notations.
Printing Notations is a flag, Unset turns it off. You can find more information about notation from here: https://coq.inria.fr/refman/user-extensions/syntax-extensions.html#syntax-extensions-and-interpretation-scopes.
For example,
(n + m) * 0 = n * 0 + m * 0
would be printed as
eq (Nat.mul (Nat.add n m) O) (Nat.add (Nat.mul n O) (Nat.mul m O))
I know, it's not a really good solution.
In the latest versions of Coq Set Printing Parentheses should work.
I am not aware of a mechanism to do what you propose (but it could well exist, Coq notation support is rich and complex).
Coq is supposed to insert parenthesis based on the precedence of the operators, that means that you'll have to redefine the precedence of :|: to achieve what you want. This is not possible to do easily, and most people won't like it. The current precedence of :|: is what is expected by mathematicians.
A possible workaround is to define a different, local notation for you own use:
From mathcomp
Require Import ssreflect ssrbool eqtype ssrnat seq choice fintype finset.
Section U.
Variable (T: finType).
Local Notation "A :||: B" := (#setU T A B) (at level 48, left associativity).
Theorem a_a_b__b' (A B : {set T}) : B \subset A -> (A :\: (A :\: B)) = B.
Proof.
move=> H; rewrite setDDr.
But I'd suggest you use this only temporarily, try to get used to the current precedence rules, as you'll have to read other people proofs, and they'll have to read yours, so deviating from standard practice has a non trivial cost.

Coq proof tactics

I am a beginner at Coq proof system (about 4 days). I've tried hard, but I am not able to prove the following.
forall a b c : nat, S (S (a + b)) = S (S (a + c)) -> b = c.
As far as I know, we need to prove the bijectivity of +, so that we can somehow use f(b) = f(c) -> b = c. How do I do this ?
As pointed out in Vinz's answer, you can find the bijectivity theorem about plus directly in the Coq standard library. You can also prove it directly using primitive tactics and mathematical induction on a as follows.
Theorem plus_l_bij: forall a b c : nat, a + b = a + c -> b = c.
Proof.
induction a as [|a'].
intros b c H. apply H.
intros b c H. simpl plus in H. inversion H. apply IHa' in H1. apply H1.
Qed.
After induction a, the base case a = 0 is trivial.
The proof for the second case a = S a', rearranges
S a' + b = S a' + c
to
S (a' + b) = S (a' + c)
and then removes the constructor S using its bijectivity. Finally, the induction hypothesis can be applied to finish the proof.
Using SearchAbout plus or SearchPattern (_ + _ = _ + _ -> _) you could check the available lemmas about +. But if you didn't import the correct modules, that could be useless. What I usually do is that I go look at the online documentation. Here is the documentation for plus and you could have a particular look to plus_reg_l and plus_reg_r.