Axiom reuse with Typeclasses in Coq - coq

I am trying to use typeclasses for code reuse, but I am getting setoid errors applying parent typeclass axioms in child typeclass theorems. I made a MRE with the following Equality and Addition operations:
Require Import Setoid.
(* Equality *)
Parameter CEq : forall A, A->A->Prop.
Arguments CEq [A] _ _.
Notation "x ¦ y" := (CEq x y) (at level 70, no associativity).
Axiom ceq_reflexivity: forall A, forall a:A, a¦a.
Axiom ceq_symmetry: forall A, forall a b:A, a¦b->b¦a.
Axiom ceq_transitivity: forall A, forall a b c:A, a¦b->b¦c->a¦c.
Add Parametric Relation A : (A) (#CEq A)
reflexivity proved by (#ceq_reflexivity A)
symmetry proved by (#ceq_symmetry A)
transitivity proved by (#ceq_transitivity A)
as ceq_rel.
(* Addition *)
Parameter CAdd: forall A, A->A->A.
Arguments CAdd [A] _ _.
Infix "±" := CAdd (at level 50, left associativity).
The following are the parent and child classes:
(* Parent Typeclass *)
Class CDiscT (CDisc: Set) := {
O: forall CDisc, CDisc;
cdisc_add_neutral:forall CDisc, forall x:CDisc, x±(O CDisc)¦x;
}.
(* Natural Set & Child Typeclass *)
Parameter CNat: Set.
Class CNatT `{CDiscT CNat} := {}.
And here is the failing theorem:
(* Axiom inheritance test *)
Example test `{CNatT}: (O CNat)¦(O CNat)±(O CNat).
Proof.
rewrite <- cdisc_add_neutral. (* Error *)
reflexivity.
Qed.
Here is the error:
Error:
Tactic failure: setoid rewrite failed: Unable to satisfy the following constraints:
In environment:
H : CDiscT CNat
H0 : CNatT
?s : "subrelation (CEq (A:=Prop)) (Basics.flip Basics.impl)"
What is missing here to be able to use CDiscT axioms inside CNatT theorems? Is there a better way to do this?

This may be in part because your example is too simplified, but rewriting right-to-left with cdisc_add_neutral is problematic because the right-hand side x matches anything and can have any type.
The error you get is that Coq is trying to rewrite the whole goal with it, but that would use logical implication impl, which in turn requires that your relation CEq is a subrelation of impl.
You can avoid this by specializing the lemma a bit:
rewrite <- (cdisc_add_neutral CNat) at 1.
You need the at 1 because now the subterm that matches is O CNat, but it occurs three times in your goal. rewrite tries to rewrite all of them by default, which requires Proper instances that are missing here. (You can get those via the Parametric Morphism mechanism described in the manual).
Also, you can rewrite left-to-right:
rewrite cdisc_add_neutral

Related

Rewrite with variable from inner scope?

Is it possible to rewrite something that uses variables from another scope,
such as a function call that uses a variable from a match, fun, or fix ?
For example,
Theorem foo (f : nat -> nat) (rw : forall x, f x = 5) x : match x with
| 0 => 5
| S a => f a
end = 5.
rewrite rw.
(* Error: Found no subterm matching "f ?M160" in the current goal. *)
destruct x; try rewrite rw; apply eq_refl.
Qed.
So, the theorem is provable, but trying to rewrite rw initially fails,
seemingly because a is in another scope. But, the rewrite applies
unconditionally, so it seems like it should apply there too.
Of course, this is a toy example. Assume that, in a real-world scenario,
getting into the scope is a bit more complicated than just a destruct.
From Rewrite tactic fails to find term occurrence within pattern matching it looks like this isn't possible in Coq. So, is it just that it isn't implemented, or does it cause contradictions or allow for bad behavior like smuggling variables out of their scope?
What about harder cases like fix ?
You have likely heard that the Logic of Coq is not powerful enough to derive functional exensionality.
Now what you prove above is a point wise equality, that is you prove that an applied function has a certain value.
A rewrite in the match would correspond to a proof that two unapplied functions are equal: The original match statement (which is a function of x) and the rewritten match statement (also a function of x). This means you would prove a more general result as intermediate step - and Coq's logic is not able to prove this more general result.
Functional extensionality is compatible with Coq's logic, though. So one can add it as axiom and then one can add some setoid instances which allow to setoid_rewrite under binders. But afaik this does not work for rewrites under matches either.
It would also be possible to detect that in the end you prove a point wise equality, do the destruct behind the scenes, do the point wise rewrite and put things together again, but this would work only in rather trivial cases, which I guess are not sufficiently interesting to implement this.
To close here is an example of proving functional extensionality (suggested by the edit by #scubed) with a rewrite under binders - which is enabled by a global type class instance which is itself based on the functional extensionality axiom. So this proves an axiom with itself and it doesn't help for your match case, but it shows that rewriting under binders is equivalent to functional extensionality.
Require Import PeanoNat.
Require Import Setoid.
Require Import Morphisms.
Definition fun1 (x : nat) := x + 1.
Definition fun2 (x : nat) := 1 + x.
Example Fun1EqFun2: fun1 = fun2.
Proof.
unfold fun1, fun2.
Fail setoid_rewrite Nat.add_comm.
Abort.
Require Import FunctionalExtensionality.
(* This is derived from the error message of setoid_rewrite above *)
Global Instance:
forall (A B : Type),
Proper
(#pointwise_relation A B eq ==>
#pointwise_relation A B eq ==> Basics.flip Basics.impl) eq.
Proof.
(* See what all this Setoid stuff actually means ... *)
unfold Proper, pointwise_relation, respectful, Basics.flip, Basics.impl.
intros A B f g fgeq f' g' fg'eq gg'eq.
apply functional_extensionality.
intros x.
rewrite fgeq, fg'eq, gg'eq.
reflexivity.
Qed.
Theorem eq_arg (A B : Type) (f : A -> B) : f = (fun x => f x). reflexivity. Qed.
Lemma functional_extensionality' :
forall (A B : Type), forall (f g : A -> B),
(forall a : A, (f a) = (g a)) -> f = g.
Proof.
intros.
setoid_rewrite eq_arg at 2.
setoid_rewrite H.
reflexivity.
Qed.

SsrReflect and setoid rewriting

I can't use Ssreflect's rewrite with setoids. Although I don't think this information is relevant to solve the problem, I'm using this formulation of category theory in coq: https://github.com/jwiegley/category-theory.
As far as I know, Ssreflect's rewriting can use user-defined equivalence relations if a suitable RewriteRelation Typeclass instance can be resolved.
Context { x y : obj[C]}.
About RewriteRelation.
(* ∀ A : Type, crelation A → Prop *)
Instance equivrw : (#RewriteRelation (x ~> y) (#equiv (x ~> y) (homset x y))) := {}. (* defined and correctly type-checked *)
About equivrw.
(* RewriteRelation equiv (coq omits implicit arguments) *)
Lemma test_rwrel (a b c : x ~> y) : (#equiv (x ~> y) (homset x y) a b) -> (#equiv (x ~> y) (homset x y) b c) -> (#equiv (x ~> y) (homset x y) a c).
Proof.
move => ->.
(* Fails: not a rewritable relation: (a ≈ b) in rule __top_assumption_ *)
Using the default rewrite tactic instead works (even without manually declaring the instance, because something similar is already declared in the library).
Something funny:
Instance equivrw : (#RewriteRelation False equiv) := {}.
Lemma test_rwrel (a b c : False) : (equiv a b) -> (equiv b c) -> (equiv a c).
Proof.
move => ->.
by [].
Qed.
This works fine.
Why doesn't SSReflect use the RewriteRelation instance I have manually declared to rewrite by user-defined equivalence?
Thanks in advance.
EDIT:
I have figured out why Ssreflect doesn't see my relation. Apparently, you can add relations to be used with Ssreflect's rewrite only with Add Parametric Relation which is documented in the manual, and RewriteRelation instances don't change anything. I have tried to create a fake relation using axioms and adding it with Add Parametric Relation and rewriting works correctly. But now I'm again in trouble. The relation that I want to be able to use has type crelation (x ~> y) (which is (x ~> y) -> (x ~> y) -> Type), but to use Add Parametric Relation I need a term with type relation (x ~> y) (which is (x ~> y) -> (x ~> y) -> Prop. Why two different kinds of relations (relation and crelation) have been defined in the standard library?
How can I convert a crelation to a relation without getting universe inconsistency errors?
And I still can't understand why the above example with False works.
It's not sufficient nor necessary to declare a relation as a RewriteRelation. You must prove properties that ensure that the rewriting is logically valid, the most common one being transitivity (but you often want also reflexivity, and even symmetry as well).
As you have noticed already, the setoid rewriting plugin is actually made of two twin systems, one for relations in Prop, and one for relations in Type (whose module names are prefixed with C). You generally use just one or the other, depending on the sort of your relations.
I'm not sure whether SSReflect changes things, but here is an example usage of setoid rewriting without it:
Require Setoid. to activate the plugin.
Require Import CEquivalence. if you use Type relations, or Require Import Equivalence. if you use Prop relations.
Implement instances for properties of equivalence relations (any of Reflexive, Symmetric, Transitive, or Equivalence for all 3).
You may also have to prove Proper lemmas if the terms you are rewriting are not at the toplevel of the goal.
Note that at step 3, if you do not/cannot prove all three properties, then you will not be allowed to rewrite in all directions.
To the best of my knowledge, commands such as Add Parametric Relation you may find in the documentation are just boilerplate that desugar to these instances. But in my opinion as a user, they add an unnecessary layer of indirection; declaring the instances directly makes things more understandable (especially if you're already familiar with type classes).
Require Setoid. (* 1 *)
Require Import CMorphisms. (* 2 *)
Axiom obj : Type.
Axiom equiv : obj -> obj -> Type.
Axiom cat : forall a b c, equiv a b -> equiv b c -> equiv a c.
(* 3 *)
Instance Transitive_equiv : Transitive equiv.
Proof.
exact cat.
Qed.
(* Example usage *)
Goal forall a b c,
equiv a b -> equiv b c -> equiv a c.
Proof.
intros a b c H1 H2.
rewrite H1.
(* or,
rewrite H2
*)

What is a good example of a simple proof in Coq where the conclusion has a existential quantifier?

I wanted to see a few hands on examples of Coq proofs of the form:
\exists A(x1,...,xn)
essentially where the Goal had an existential quantifier. I was having issues manipulating the goal in meaningful ways to make progress in my proof and wanted to see a few examples of common tactics to manipulate.
What are some good existential quantifiers examples in Coq to prove?
My specific example I had:
Theorem Big_Small_ForwardImpl :
forall (P : Program) (S' : State),
(BigStepR (B_PgmConf P) (B_StateConf S')) -> (ConfigEquivR (S_PgmConf P) (S_BlkConf EmptyBlk S')).
Proof.
intros.
induction P.
unfold ConfigEquivR.
refine (ex_intro _ _ _) .
my context and goals was:
1 subgoal
l : list string
s : Statement
S' : State
H : BigStepR (B_PgmConf (Pgm l s)) (B_StateConf S')
______________________________________(1/1)
exists N : nat, NSmallSteps N (S_PgmConf (Pgm l s)) (S_BlkConf EmptyBlk S')
but then changed to:
1 subgoal
l : list string
s : Statement
S' : State
H : BigStepR (B_PgmConf (Pgm l s)) (B_StateConf S')
______________________________________(1/1)
NSmallSteps ?Goal (S_PgmConf (Pgm l s)) (S_BlkConf EmptyBlk S')
after using the refine (ex_intro _ _ _) tactic. Since I am not sure what is going on I was hoping some simpler examples could show me how to manipulate existential quantifiers in my Coq goal.
helpful comment:
The ?Goal was introduced by Coq as a placeholder for some N that will have to be deduced later in the proof.
The following example is based on the code provided in this answer.
Suppose we have a type T and a binary relation R on elements of type T. For the purpose of this example, we can define those as follows.
Variable T : Type.
Variable R : T -> T -> Prop.
Let us prove the following simple theorem.
Theorem test : forall x y, R x y -> exists t, R x t.
Here is a possible solution.
Proof.
intros. exists y. apply H.
Qed.
Instead of explicitly specifying that y is the element we are looking for, we can rely on Coq's powerful automatic proof mechanisms in order to automatically deduce which variable satisfies R x t:
Proof.
intros.
eexists. (* Introduce a temporary placeholder of the form ?t *)
apply H. (* Coq can deduce from the hypothesis H that ?t must be y *)
Qed.
There exist numerous tactics that make ise of the same automated deduction mechanisms, such as eexists, eapply, eauto, etc.
Note that their names often correspond to usual tactics prefixed with an e.

When are the constructors of an inductive type exhaustive?

For a simple inductive type like the natural numbers nat, it is easy to prove that the two constructors (zero and successor) give all possible natural numbers,
Lemma nat_destruct (n : nat) : n = O \/ exists m : nat, n = S m.
Proof.
destruct n. left. reflexivity. right. exists n. reflexivity.
Qed.
However I hear it is not so simple for equality proofs. There is only one equality constructor, eq_refl, but Coq cannot prove that
eq_destruct : forall (A : Type) (x : A) (prEq : x = x), prEq = eq_refl
What exactly blocks this proof ? Probably a first problem is that equality is not just a type, but a type family eq : forall A : Type, A -> A -> Prop. Is there a simpler type family where such a proof is impossible ? With 1 or 2 arguments instead of 3 maybe ?
I wrote about this issue in a blog post. In general, this arises when you define a type family over a type that does not have decidable equality. For example, consider the following type:
Inductive foo : Type -> Type :=
| Foo : foo unit.
It is not possible to show (I am pretty sure) that every inhabitant of foo unit is of the form Foo.
This phenomenon is easier to see at the level of proof terms. When you destruct a term of such a family, you must generalize over the index of the family. You can only relate this index to a known shape such as unit if the type has decidable equality.

Inductively defined dense vector lemmas

Inspired by another question on StackOverflow, I defined a dense vector to be a vector with option A type elements that only contains Some _ elements, and no None elements.
Require Import Vector.
Section Dense.
Variable A:Type.
Inductive Is_dense : forall n, t (option A) n -> Prop :=
| snil : Is_dense 0 (nil _)
| scons: forall n s, Is_dense n s -> forall a, Is_dense (S n) (cons _ (Some a) _ s).
How can I prove the following two lemmas?
Lemma Is_dense_tl: forall n (s: t (option A) (S n)),
Is_dense (S n) s -> Is_dense n (tl s).
and
Lemma dense_hd: forall n (s: t (option A) (S n)), Is_dense (S n) s -> A.
And also, in the first lemma, when I do inversion s. I get the elements h n' X that were used by s's constructor, but how can I get an equality stating s = cons (option A) h n' X?
Because of type dependency, inversion can't directly generate what you expect, because it is not true in general. However, it is true for a large family of types, whose equality is decidable. In your case, you can apply Eqdep_dec.inj_pair2_eq_dec to get the equality you want, if you provide the fact that equality upon nat is decidable (and it is).
Here is the proof for the first lemma:
Lemma Is_dense_tl: forall n (s: t (option A) (S n)),
Is_dense (S n) s -> Is_dense n (tl s).
Proof.
intros n s hs.
inversion hs; subst; clear hs.
apply Eqdep_dec.inj_pair2_eq_dec in H0.
- now rewrite <- H0; simpl.
- (* insert proof of decidablity *) admit.
Qed.
EDIT: About your comment about the second lemma.
The main difference between your two lemmas is that the first one tries to prove the property Is_dense n (tl s) which lives in Prop, whereas the second one tries to exhibit a term of type A. In short, the former creates a term of sort Prop, the latter a term of sort Type.
To avoid inconsistency in Coq's logic, there is a hierarchy to organize the sorts, which is (not exactly, but to give you the rough idea) Prop: Set Set:Type_0 and Type_n: Type_n+1. On top of this hierarchy is built a type system where the dependent pair (e.g. the type {n: nat | even n } is the type of even natural numbers) is restricted. You can build a Prop from other Prop (e.g. forall p:Prop, p -> p lives in Prop). However you need to be careful when Type is involved. For example, (again, please refer to Coq's documentation for the exact statement) forall n:Type_i, Type_j is of type Type_max(i,j).
This restriction is here to avoid inconsistency (like Russel's paradox) in Coq's type system.
In your case, you are trying to inspect (using inversion) a term of sort Prop (Is_dense (S n) s) to build a term of type A, of sort Type. This is forbidden by the type system. To build a term of sort Type, you need to inspect terms of at least the sort Set. In your example, all you have to do is change the definition of Is_dense to land in Type instead of Prop, and you're good to go.