Fail to use let-destruct for tuple in Coq - coq

I'm a new user for Coq. I have defined some functions:
Definition p (a : nat) := (a + 1, a + 2, a + 3).
Definition q :=
let (s, r, t) := p 1 in
s + r + t.
Definition q' :=
match p 1 with
| (s, r, t) => s + r + t
end.
I'm trying to destruct the result of p into a tuple representation. However coqc complains on q:
Error: Destructing let on this type expects 2 variables.
while q' can pass the compilation. If I change p to return a pair(a + 1, a + 2), the corresponding q and q' both work fine.
Why let-destruct only allows pair? Or have I made any error in syntax? I've checked with Coq manual but found no clue.
Thank you!

What is a bit confusing in Coq is that there are two different forms of destructing let. The one you are looking for needs a quote before the pattern:
Definition p (a : nat) := (a + 1, a + 2, a + 3).
Definition q :=
let '(s, r, t) := p 1 in
s + r + t.
Prefixing the pattern with a quote allows you to use nested patterns and use user-defined notations in them. The form without the quote only works with one-level patterns, and doesn't allow you to use notations, or refer to constructor names in your patterns.

Related

Beta expansion in coq: can I make a term into a function, abstracting over another given term?

I want to rewrite a term, as a function in a sort of beta expansion (inverse of beta reduction).
So, for example in the term a + 1 = RHS I would like to replace it as (fun x => x + 1) a = RHS. Obviously, the two terms are equal by betta reduction, but I can't figure out how to automate it.
The tactic pattern comes very close to what I want, except it only applies to a full goal, and I can't see how I would use it in a term inside an equality.
Similarly, I thought I could use the context holes. Here is my best attempt
Ltac betaExpansion term a:=
let T:= type of a in
match term with
context hole [a] =>
idtac hole;
let f:= fun x => context hole [x] in
remember ( fun x:T => f x ) as f'
end.
Goal forall a: nat, a + 1 = 0.
intros a.
match goal with
|- ?LHS = _ =>
betaExpansion LHS a (*Error: Variable f should be bound to a term but is bound to a tacvalue.*)
end.
This obviously fails, because f is a tacvalue when I really need a normal value. Can I somehow evaluate the expression to make it a value?
You should have a look at the pattern tactic. pattern t replaced all occurrences of t in the goal by a beta expanded variable.
You may also use the change ... with ... at tactic.
Goal forall (a:nat) , a+1 = 2* (a+1) - (a+1).
intro x; change (x+1) with ((fun z => z) (x+1)) at 1 3.
(*
x : nat
============================
(fun z : nat => z) (x + 1) = 2 * (x + 1) - (fun z : nat => z) (x + 1)
*)
Or, more automatically
Ltac betaexp term i :=
let x := fresh "x" in
let T := type of term in
change term with ((fun x : T => x) term) at i.
Goal forall (a:nat) , a+1 = a+1 .
intro x; betaexp (x+1) ltac:(1).

Lean define groups

This is a follow-up question of Lean pass type as parameter
I tried jmc's suggestion, which seemed to work, but then I got stuck at another point. The original purpose of the question was to define the categories of groups and rings, but now apparently I am unable to define group morphisms:
class group :=
(set: Type)
(add: set → set → set)
infix + := group.add
class group_morphism (G H: group) :=
(f: G.set → H.set)
(additive: ∀ g h : G.set, f(g + h) = (f g) + (f h))
I get an error at the first +. Lean seems to think that this refers to H.add, whereas it is supposed to refer to G.add.
The issue is that group should not be a class. If you look at the type of group.add, by #check #group.addyou will get
group.add : Π [c : group], group.set → group.set → group.set
The square brackets around c : group indicate that this is an implicit argument that will be inferred by type class inference. You won't have to explicitly type this argument, but Lean will try to work out what it is. Type class inference works best for types where there is only one inhabitant you ever want to use.
In mathlib the definition of group is closer to
class group (set : Type) :=
(add : set → set → set)
On a particular type, there is usually only one group structure you want to refer to, so in mathlib, a type like add_group int has only one inhabitant you care about.
Lean automatically chose H as the canonical representative of the type group, but this is not the one you wanted.
So usually when you deal with groups the type and the group structure are kept as separate objects, they are not put into a pair. However for category theory, the usual approach doesn't work, an object is a pair of a type and a group structure.
The setup in mathlib is closer to the following. The coe_to_sort tells Lean how to take a group_obj and interpret it as a Type without having explicitly write G.set, the group_obj_group instance tells Lean how to automatically infer the group structure on the type of a group_obj
class group (set : Type) :=
(add: set → set → set)
structure group_obj :=
(set : Type)
(group : group set)
instance coe_to_sort : has_coe_to_sort group_obj :=
{ S := Type,
coe := group_obj.set }
instance group_obj_group (G : group_obj) : group G := G.group
infix `+` := group.add
structure group_morphism (G H : group_obj) :=
(f: G → H)
(additive: ∀ g h : G.set, f(g + h) = (f g) + (f h))
You are redefining the + notation which will very quickly lead to headaches. Have a polymorphic + notation is very helpful. (How will you denote the addition in a ring?)
Further points:
you should use structure instead of class
mathematically, you are defining monoids and monoid homs, not groups and group homs
This works though
(set: Type)
(add: set → set → set)
def add {G : group} := group.add G
class group_morphism (G H: group) :=
(f: G.set → H.set)
(additive: ∀ g h : G.set, f(add g h) = add (f g) (f h))

Using functions in definitions

I'm modeling a program in which users can choose from different operators and functions for writing queries (i.e. formulas) for the system. For showing these operators, here I defined add and mul functions and used nat datatype, instead of my program's functions and datatypes. How should I define formula that enables me to use it in definition compute_formula. I'm a bit stuck at solving this issue. Thank you.
Fixpoint add n m :=
match n with
| 0 => m
| S p => S (p + m)
end
where "n + m" := (add n m) : nat_scope.
Fixpoint mul n m :=
match n with
| 0 => 0
| S p => m + p * m
end
where "n * m" := (mul n m) : nat_scope.
Definition formula : Set :=
nat-> nat -> ?operators_add_mull ->formula.
Definition compute_formula (f: formula) : nat :=
match f with
|firstnumber,secondnumber, ?operators_add_mull =>
?operators_add_mull firstnumber secondnumber
end.
First, your syntax for defining a data type is not quite right: you need to use the Inductive keyword:
Inductive formula : Set :=
| Formula : nat -> nat -> ?operators_add_mul -> formula.
It remains to figure out what the arguments to the Formula constructor should be. The Coq function type -> is a type like any other, and we can use it as the third argument:
Inductive formula : Set :=
| Formula : nat -> nat -> (nat -> nat -> nat) -> formula.
After defining this data type, you can write an expression like Formula 3 5 add, which denotes the addition of 3 and 5. To inspect the formula data type, you need to write match using the Formula constructor:
Definition compute_formula (f : formula) : nat :=
match f with
| Formula n m f => f n m
end.

Idiomatic ways of selecting subterm to rewrite

Suppose we have a conclusion of form: a + b + c + d + e.
We also have a lemma: plus_assoc : forall n m p : nat, n + (m + p) = n + m + p.
What are idiomatic ways to arbitrarily "insert a pair of parentheses" into the term? That is, how can we easily choose where to rewrite if there's more than one available place.
What I generally end up doing is the following:
replace (a + b + c + d + e)
with (a + b + c + (d + e))
by now rewrite <- ?plus_assoc
And while this formulation does state exactly what I want to do,
it gets extremely long-winded for formulations more complicated than "a b c...".
rewrite <- lemma expects lemma to be an equality, that is, a term whose type is of the form something1 = something2. Like with most other tactics, you can also pass it a function that returns an equality, that is, a term whose type is of the form forall param1 … paramN, something1 = something2, in which case Coq will look for a place where it can apply the lemma to parameters to form a subterm of the goal. Coq's algorithm is deterministic, but letting it choose is not particularly useful except when performing repeated rewrites that eventually exhaust all possibilities. Here Coq happens to choose your desired goal with rewrite <- plus_assoc, but I assume that this was just an example and you're after a general technique.
You can get more control over where to perform the rewrite by supplying more parameters to the lemma, to get a more specific equality. For example, if you want to specify that (((a + b) + c) + d) + e should be turned into ((a + b) + c) + (d + e), i.e. that the associativity lemma should be applied to the parameters (a + b) + c, d and e, you can write
rewrite <- (plus_assoc ((a + b) + c) d e).
You don't need to supply all the parameters, just enough to pinpoint the place where you want to apply the lemma. For example, here, it's enough to specify d as the second argument. You can do this by leaving the third parameter out altogether and specifying the wildcard _ as the first parameter.
rewrite <- (plus_assoc _ d).
Occasionally there are identical subterms and you only want to rewrite one of them. In this case you can't use the rewrite family of tactics alone. One approach is to use replace with a bigger term where you pick what you want to change, or event assert to replace the whole goal. Another approach is to use the set tactics, which lets you give a name to a specific occurrence of a subterm, then rely on that name to identify specific subterms, and finally call subst to get rid of the name when you're done.
An alternative approach is to forget about which lemmas to apply, and just specify how you want to change the goal with something like assert or a plain replace … with ….. Then let automated tactics such as congruence, omega, solve [firstorder], etc. find parameters that make the proof work. With this approach, you do have to write down big parts of the goal, but you save on specifying lemmas. Which approach works best depends on where you are on a big proof and what tends to be stable during development and what isn't.
IMO your best option is to use the ssreflect pattern selection language, available in Coq 8.7 or by installing math-comp in earlier versions. This language is documented in the manual: https://hal.inria.fr/inria-00258384
Example (for Coq 8.7):
(* Replace with From mathcomp Require ... in Coq < 8.7 *)
From Coq Require Import ssreflect ssrfun ssrbool.
Lemma addnC n m : m + n = n + m. Admitted.
Lemma addnA m n o : m + (n + o) = m + n + o. Admitted.
Lemma example m n o p : n + o + p + m = m + n + o + p.
Proof. by rewrite -[_ + _ + o]addnA -[m + _ + p]addnA [m + _]addnC.
Qed.
If you don't want to prove a helper lemma, then one of your choices is using Ltac to pattern match on the structure of the equality on your hands. This way you can bind arbitrary complex subexpressions to pattern variables:
Require Import Coq.Arith.Arith.
Goal forall a b c d e,
(a + 1 + 2) + b + c + d + e = (a + 1 + 2) + (b + c + d) + e -> True.
intros a b c d e H.
match type of H with ?a + ?b + ?c + ?d + ?e = _ =>
replace (a + b + c + d + e)
with (a + (b + c + d) + e)
in H
by now rewrite <- ?plus_assoc
end.
Abort.
In the above piece of code ?a stands for a + 1 + 2. This, of course, doesn't improve anything if you are dealing with simple variables, it helps only when you are dealing with complex nested expressions.
Also, if you need to rewrite things in the goal, then you can use something like this:
match goal with
| |- ?a + ?b + ?c + ?d + ?e = _ => <call your tactics here>

Coordinates in Coq

I apologize if this is obviously posted somewhere, but I have been trying Google search and SO search and found nothing on this yet.
Part A.
Is there a standard library for defining coordinates/vectors and points in R^2 and R^3 in Coq? I pretty much want to do standard stuff, like adding vectors, cross products, scaling, etc.
If not, how is this for a start:
Require Import Coq.Reals.Reals.
Inductive Coordinate2 : Type := Point2: R -> R -> Coordinate2.
Definition R2plus (u:Coordinate2) (v:Coordinate2) : Coordinate2 :=
match u, v with
| (Point2 ux uy),(Point2 vx vy)=>(Point2 ((ux+vx)%R) ((uy+vy)%R))
end.
(* etc. *)
Notation "x + y" := (R2plus x y).
Also, why when I run:
Eval compute in ((2%R) < (3%R))%R.
Do I get
= (2 < 3)%R
: Prop
rather than
True
or something?
Part B.
Is this even a good idea? I want to build an algorithm which computes some things using real numbers, and prove the algorithm correct in Coq. Is Coq.Reals.Reals the right thing to be using, or is it really too abstract?
Instead of defining Coordinate2 you could also use (R * R)%type, list R, or t R 2, where t A n, defined in Vector, is a list of size n.
You might want to give your notations a scope and a delimiting key to avoid clashes with other notations.
Notation "x + y" := (R2plus x y) : r2_scope.
Delimit Scope r2_scope with R2.
Eval compute in ((Point2 0 1) + (Point2 2 3))%R2.
Prop, Set, and Type are sorts, which means something of type Prop might be defined inductively.
For example, for the nats, le is defined as
Inductive le : nat -> nat -> Prop :=
| le_n : forall n, le n n
| le_S : forall n m : nat, le n m -> le n (S m).
2 <= 2 is true because it's inhabited by le_n 2
2 <= 3 is true because it's inhabited by le_S 2 2 (le_n 2)
2 <= 4 is true because it's inhabited by le_S 2 3 (le_S 2 2 (le_n 2))
3 <= 2 is false because it's not inhabited
For 2 <= 3 to reduce to True, le would have to be defined like, for example,
Fixpoint le (n m : nat) : Prop :=
match n with
| 0 => True
| S n =>
match m with
| 0 => False
| S m => le n m
end
end.
Coq's definition of Rplus and Rlt are actually axioms. To check the definition of something use the Print command.
To answer part B, I guess it depends on how well you understand mathematical analysis and the various ways of defining the reals. If you're more familiar with numerical methods, you might want to use the rationals instead.