Best way to make a relation associative in Coq - coq

I’ve a relation C that takes three parameters. It represents an operation of my theory. So C(a, b, c) represents a = b # c, however I didn’t (succeed to) define this operator in Coq, so I use only the relation C. I want this relation to be associative: (d # e) # f = d # (e # f). And I have to express it with C. I thought of two axioms, but I don’t know which one is best (if they’re are both correct).
Parameter Entity: Set.
Parameter C : Entity -> Entity -> Entity -> Prop.
Axiom asso1 : forall a c d e,
((exists b, C a b c /\ C b d e) <-> (exists f, C a d f /\ C f e c)).
Axiom asso2 : forall s t u a b c d,
(C a s t -> C b a u -> C d s c -> C c t u -> b = d).
What do you think about it?

Both axioms are equivalent if you also know that C is a functional relation (i.e., it represents a function): every input pair maps to a unique output.
(* A functional relation is one that is total and deterministic in the following sense: *)
Axiom total_C : forall a b, exists c, C c a b.
Axiom deterministic_C : forall a b c c', C c a b -> C c' a b -> c = c'.

Related

How can I reorder existential variables in Coq?

In some cases it is easier to instantiate the one existential term before another. In this contrived example, I wish to set c = 3 first, and from that choose, say a = 1 and b = 2.
Lemma three_nats : exists (a : nat) (b : nat) (c : nat),
a + b = c.
Proof.
eexists.
eexists.
exists 3.
(* Now what? *)
Is there a way to use just the simple exists 3 on c first?
You can use that it is enough to prove that there exists c,b,a such that a+b=c.
enough (exists c a b, a + b = c).
Now you have two goals. First, that
exists c a b, a + b = c -> exists a b c, a + b = c.
and second, that
exists c a b, a + b = c.
Btw, you can finish off the first part of the proof quickly with firstorder like this:
enough (exists c a b, a + b = c) by firstorder.
Or if you don't want to repeat the goal, just apply this lemma:
Lemma ex_swap {A B C} {P:A->B->C->Prop}:
(exists c a b, P a b c) -> exists a b c, P a b c.
Proof. firstorder. Qed.

Defining functions inside proof scope

I'm trying to prove that injective functions are left invertible in Coq. I've reached a point in my proof where my goal is an "exists" proposition. I want to define a function that uses terms from proof scope (types and functions I've intro'ed before) and then show the function to the "exists" goal. Here's what I wrote so far:
(* function composition *)
Definition fun_comp {A B C: Type} (f:A -> B) (g:B -> C) : A -> C :=
fun a: A => g (f a).
Notation "g .o f" := (fun_comp f g) (at level 70).
Definition nonempty (A: Type) := exists a: A, a = a.
(* identity function for any given type *)
Definition fun_id (A: Type) := fun a: A => a.
(* left invertible *)
Definition l_invertible {A B: Type} (f: A -> B) :=
exists fl:B->A, fl .o f = fun_id A.
Definition injective {A B: Type} (f: A -> B) :=
forall a a': A, f a = f a' -> a = a'.
(* is a given element in a function's image? *)
Definition elem_in_fun_image {A B: Type} (b: B) (f: A -> B) :=
exists a: A, f a = b.
Theorem injective_is_l_invertible:
forall (A B: Type) (f: A -> B), nonempty A /\ injective f -> l_invertible f.
Proof.
intros A B f H.
destruct H as [Hnempty Hinj].
unfold l_invertible.
unfold nonempty in Hnempty.
destruct Hnempty as [a0].
(* here would go my function definition and invoking "exists myfun" *)
Here's the function I'm trying to define:
Definition fL (b: B) := if elem_in_fun_image b f
then f a
else a0.
Here's what the proof window looks like:
1 subgoal
A : Type
B : Type
f : A -> B
a0 : A
H : a0 = a0
Hinj : injective f
========================= (1 / 1)
exists fl : B -> A, (fl .o f) = fun_id A
How do I do this? I'm very new to Coq so other comments and pointers are welcome.
This definition cannot be performed in the basic logic. You need to add in a few extra axioms:
(* from Coq.Logic.FunctionalExtensionality *)
functional_extensionality : forall A B (f g : A -> B),
(forall x, f x = g x) -> f = g
(* from Coq.Logic.Classical *)
classic : forall P : Prop, P \/ ~ P
(* from Coq.Logic.ClassicalChoice *)
choice : forall (A B : Type) (R : A->B->Prop),
(forall x : A, exists y : B, R x y) ->
exists f : A->B, (forall x : A, R x (f x)).
The goal is to define a relation R that characterizes the left inverse that you want to construct. The existentially quantified f will then be the inverse! You will need the classic axiom to show the precondition of choice, and you will need functional extensionality to show the equation that you want. I'll leave it as an exercise to find out what R needs to be and how to complete the proof.
Your script should start with the following line.
Require Import ClassicalChoice FunctionalEquality.
Because, as suggested by #arthur-azevedo-de-amorim, you will need these axioms.
Then, you should use choice with the relation "R y x" being
"f x = A or there is no element in A such whose image by f is y".
You will need the axiom classic to prove the existential statement that is required by choice:
assert (pointwise : forall y: B, exists x : A,
f x = y \/ (forall x : A f x <> y)).
choice will give you an existential statement for a function that returns the value you want. You only need to say that this function is the right one. You can give a name to that function by typing destruct (choice ... pointwise) (you have to fill in the ...).
You will have to prove an equality between two functions, but using the axiom functional_extensionality, you can reduce this problem to just proving that the two functions are equal on any x.
For that x, just instantiate the characteristic property of the function (as produced by destruct (choice ... pointwise) with the
value f x. There is a disjuction, but the right-hand side case is self-contradictory, because obviously f x is f x for some x.
For the left-hand side case, you will get an hypothesis of the form (I name the function produced by (choice ... pointwise) with the name it:
f (it (f x)) = f x
Here you can apply your injectivity assumption. to deduce that it (f x) = x.
This pretty much spells out the proof. In my own, experiment, I used classic, NNP, not_all_ex_not, functional_extensionality, which are lemmas coming from ClassicalChoice of FunctionalEquality.

example for introduction pattern (p1 & ... & pn) does not work

I am reading the Coq (8.5p1) reference manual,
introduction via (p1 & ... & pn) is a shortcut for introduction via
(p1,(...,(...,pn)...)); it expects the hypothesis to be a sequence of
right-associative binary inductive constructors such as conj or
ex_intro; for instance, an hypothesis with type A/(exists x, B/\C/\D)
can be introduced via pattern (a & x & b & c & d);
Trying to test this out, I did:
Goal forall A B C D: Prop, A/\(exists x:nat, B/\C/\D) -> D.
intros (a & x & b & c & d).
But Coq is telling me:
Error: Not an inductive product.
And I got the same error for a few other variants, such as one without the -> D.
Can some one please explain what's the correct usage (in a hopefully useful example)?
Since your goal starts with forall A B C D: Prop, you need to introduce A B C D first:
intros A B C D (a & x & b & c & d).
I think this syntax was introduced to get rid of nested square brackets, which can be used to destructure during the introduction phase. Compare the following two proofs:
Goal forall A B C D: Prop,
A /\ (exists x:nat, B /\ C /\ D) -> D.
intros A B C D (_ & _ & _ & _ & d). assumption. Qed.
Goal forall A B C D: Prop,
A /\ (exists x:nat, B /\ C /\ D) -> D.
intros A B C D [_ [_ [_ [_ d]]]]. assumption. Qed.
I think the first one is easier on eyes.

Type that contains all functions of N elements in Coq

I am learning Coq and as an exercise I want to define a type FnArity (N:nat) to encode all functions of N arguments. That is:
Check FnArity 3 : (forall A B C : Set, A -> B -> C).
Should work but
Check FnArity 2 : (forall A B C D : Set, A -> B -> C -> D).
Should not work.
This is for pedagogic purposes so any relevant resources are welcome.
EDIT: From the answers so far I realize I am probably approaching this wrong so here is the proposition I am trying to prove:
Composing N composition operators is equivalent to a composition operator that composes f and g where g expects N arguments. In haskell-ish terms:
(.).(.) ... N times ... (.).(.) f g = \a1, .. aN -> f (g (a1, .. , aN))
EDIT2: In coq terms:
Definition compose { A B C : Type } (F : C -> B) (G : A -> C ) : A -> B :=
fun x => F ( G (x) ).
Definition compose2 {A1 A2 B C : Type} (F : C -> B) (G : A1 -> A2 -> C)
: A1 -> A2 -> B := fun x y => F ( G x y ).
Definition compose3 {A1 A2 A3 B C : Type} (F : C -> B) (G : A1 -> A2 -> A3 -> C)
: A1 -> A2 -> A3 -> B := fun x y z => F ( G x y z ).
(* The simplest case *)
Theorem dual_compose : forall {A B C D : Type} (f: D -> C) (g : A -> B -> D) ,
(compose compose compose) f g = compose2 f g.
Proof. reflexivity. Qed.
Theorem triple_compose : forall {A1 A2 A3 B C : Type} (f: C -> B) (g : A1 -> A2 -> A3 -> C) ,
(compose (compose (compose) compose) compose) f g =
compose3 f g.
What I want is to define the generalized theorem for composeN.
The types that you wrote down do not quite represent what you stated in your problem: forall A B C, A -> B -> C is not the type of all functions of three arguments, but the type of certain polymorphic functions of two arguments. You probably meant to write something like { A & { B & { C & A -> B -> C }}} instead, where A, B and C are existentially quantified. You probably also meant to say Compute (FnArity 3) instead of using the Check command, since the latter is the one that evaluates a term (and, as jbapple pointed out, no term can have the type that you had originally written).
Here's a piece of code that does what you want, I think. We start by writing a function FnArityAux1 : list Type -> Type -> Type, that computes a function type with arguments given on a list:
Fixpoint FnArityAux1 (args : list Type) (res : Type) : Type :=
match args with
| [] => res
| T :: args' => T -> FnArityAux1 args' res
end.
For instance, FnArityAux1 [nat; bool] bool evaluates to nat -> bool -> bool. We can then use this function to define FnArity as follows:
Fixpoint FnArityAux2 (args : list Type) (n : nat) : Type :=
match n with
| 0 => { T : Type & FnArityAux1 args T }
| S n' => { T : Type & FnArityAux2 (args ++ [T]) n' }
end.
Definition FnArity n := FnArityAux2 [] n.
In this definition, we use another auxiliary function FnArityAux2 that has an argument args whose purpose is to carry around all the existentially quantified types produced so far. For each "iteration step", it quantifies over another type T, adds that type to the list of arguments, and recurses. When the recursion is over, we use FnArityAux1 to combine all accumulated types into a single function type. Then, we can define FnArity simply by starting the process with an empty list -- that is, no quantified types at all.
No, this is not possible, since (forall A B C : Set, A -> B -> C) is uninhabited.
Goal (forall A B C : Set, A -> B -> C) -> False.
intros f.
specialize (f True True False).
apply f; trivial.
Qed.
As such, Check FnArity 3 : (forall A B C : Set, A -> B -> C). can never work.

A good way to formalize groups in Coq

I try to formalize groups in Coq. I want to be as general as possible. I try to do something, but I'm not really happy with it. I found different implementations and I don't know which one to choose.
For example I found this :
https://people.cs.umass.edu/~arjun/courses/cs691pl-spring2014/assignments/groups.html
(* The set of the group. *)
Parameter G : Set.
(* The binary operator. *)
Parameter f : G -> G -> G.
(* The group identity. *)
Parameter e : G.
(* The inverse operator. *)
Parameter i : G -> G.
(* For readability, we use infix <+> to stand for the binary operator. *)
Infix "<+>" := f (at level 50, left associativity).
(* The operator [f] is associative. *)
Axiom assoc : forall a b c, a <+> b <+> c = a <+> (b <+> c).
(* [e] is the right-identity for all elements [a] *)
Axiom id_r : forall a, a <+> e = a.
(* [i a] is the right-inverse of [a]. *)
Axiom inv_r : forall a, a <+> i a = e.
but why the author use axioms and not definitions ? Moreover, I don't like to have some parameters at top level.
On the book CoqArt, I found this implementation :
Record group : Type :=
{A : Type;
op : A→A→A;
sym : A→A;
e : A;
e_neutral_left : ∀ x:A, op e x = x;
sym_op : ∀ x:A, op (sym x) x = e;
op_assoc : ∀ x y z:A, op (op x y) z = op x (op y z)}.
On this definition I think the definition is to specialize, because if I want to define monoïds, I will redefine op_assoc or neutre left. Beyond that,
for some theorems, I don't need to use groups. For example if I want to proove that right_inverse is the same as left_inverse if the law is associative.
An other question is what are good axioms for groups :
use neutral element as axiom or left neutral element
use inverse element as axiom or left inverse
What is the more convenient to work with ?
Finally, if I want to proove some other theorems, I probably want to have some syntactic sugar in order to use the binary operation and inverse elements. What are your advices to have a convenient notation for groups ?
For the moment I did this :
Definition binary_operation {S:Set} := S -> S -> S.
Definition commutative {S:Set} (dot:binary_operation) := forall (a b:S), dot a b = dot b a.
Definition associative {S:Set} (dot:binary_operation) := forall (a b c:S), dot (dot a b) c = dot a (dot b c).
Definition left_identity {S:Set} (dot:binary_operation) (e:S) := forall a:S, (dot e a) = a.
Definition right_identity {S:Set} (dot:binary_operation) (e:S) := forall a:S, (dot a e) = a.
Definition identity {S:Set} (dot: binary_operation) (e:S) := left_identity dot e /\ right_identity dot e.
Definition left_inv {S:Set} (dot:binary_operation) (a' a e:S) := identity dot e -> dot a' a = e.
Definition right_inv {S:Set} (dot:binary_operation) (a' a e:S) := identity dot e -> dot a a' = e.
Definition inv {S:Set} (dot:binary_operation) (a' a e:S) := left_inv dot a' a e /\ right_inv dot a' a e.
I found an implementation in the code source of Coq but I don't understand why it is a good implementation : https://github.com/tmiya/coq/blob/master/group/group2.v
I can't provide a complete answer, but perhaps this can help you a bit.
Your first article provides definitions and axioms sufficient for proving exercises without paying too much attention to being 'good' or 'useful' implementation. That's why axioms and not definitions.
If you want 'to be as general as possible', you can use example from CoqArt, or wrap your group definition in a section, using Variable instead of Parameter.
Section Group.
(* The set of the group. *)
Variable G : Set.
(* The binary operator. *)
Variable f : G -> G -> G.
(* The group identity. *)
Variable e : G.
(* The inverse operator. *)
Variable i : G -> G.
(* For readability, we use infix <+> to stand for the binary operator. *)
Infix "<+>" := f (at level 50, left associativity).
(* The operator [f] is associative. *)
Variable assoc : forall a b c, a <+> b <+> c = a <+> (b <+> c).
(* [e] is the right-identity for all elements [a] *)
Variable id_r : forall a, a <+> e = a.
(* [i a] is the right-inverse of [a]. *)
Variable inv_r : forall a, a <+> i a = e.
If you then prove some theorems inside this section, like this:
Theorem trivial : forall a b, a <+> e <+> b = a <+> b.
intros.
rewrite id_r.
auto.
Qed.
After section ends,
End Group.
Coq generalizes them
Check trivial.
trivial
: forall (G : Set) (f : G -> G -> G) (e : G),
(forall a : G, f a e = a) -> forall a b : G, f (f a e) b = f a b
As for your last example, it's probably not about actual definition of group, but instead about proving that a set, a binary operation and four axioms for this operation define a group.