I have a function Z -> Z -> whatever which I treat as a sort of a map from (Z, Z) to whatever, let's type it as FF.
With whatever being a simple sum constructible from nix or inj_whatever.
This map I initialize with some data, in the fashion of:
Definition i (x y : Z) (f : FF) : FF :=
fun x' y' =>
if andb (x =? x') (y =? y')
then inj_whatever
else f x y.
The =? represents boolean decidable equality on Z, from Coq's ZArith.
Now I would like to have equality on two of such FFs, I don't mind invoking functional_extensionality. What I would like to do now is to have Coq computationally decide equality of two FFs.
For example, suppose we do something along the lines of:
Definition empty : FF := fun x y => nix.
Now we add some arbitrary values to make foo and foo', those are equivalent under functional extensionality:
Definition foo := i 0 0 (i 0 (-42) (i 56 1 empty)).
Definition foo' := i 0 (-42) (i 56 1 (i 0 0 empty)).
What is a good way to automatically have Coq determine foo = foo'. Ltac level stuff? Actual terminating computation? Do I need domain restriction to a finite one?
The domain restriction is a bit of an intricate one. I manipulate the maps in a way f : FF -> FF, where f can extend the subset of Z x Z that the computation is defined on. As such, come to think of it, it can't be f : FF -> FF, but more like f : FF -> FF_1 where FF_1 is a subset of Z x Z that is extended by a small constant. As such, when one applies f n times, one ends up with FF_n which is equivalent to domain restriction of FF plus n * constant to the domain. So the function f slowly (by a constant factor) expands the domain FF is defined on.
As I said in the comment more specifics are needed in order to elaborate a satisfactory answer. See the below example --- intended for a step by step description --- on how to play with equality on restricted function ranges using mathcomp:
From mathcomp Require Import all_ssreflect all_algebra.
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
(* We need this in order for the computation to work. *)
Section AllU.
Variable n : nat.
(* Bounded and unbounded fun *)
Definition FFb := {ffun 'I_n -> nat}.
Implicit Type (f : FFb).
Lemma FFP1 f1 f2 : reflect (f1 = f2) [forall x : 'I_n, f1 x == f2 x].
Proof. exact/(equivP eqfunP)/ffunP. Qed.
Lemma FFP2 f1 f2 :
[forall x : 'I_n, f1 x == f2 x] = all [fun x => f1 x == f2 x] (enum 'I_n).
Proof.
by apply/eqfunP/allP=> [eqf x he|eqf x]; apply/eqP/eqf; rewrite ?enumT.
Qed.
Definition f_inj (f : nat -> nat) : FFb := [ffun x => f (val x)].
Lemma FFP3 (f1 f2 : nat -> nat) :
all [fun x => f1 x == f2 x] (iota 0 n) -> f_inj f1 = f_inj f2.
Proof.
move/allP=> /= hb; apply/FFP1; rewrite FFP2; apply/allP=> x hx /=.
by rewrite !ffunE; apply/hb; rewrite mem_iota ?ltn_ord.
Qed.
(* Exercise, derive bounded eq from f_inj f1 = f_inj f2 *)
End AllU.
The final lemma should indeed allow you reduce equality of functions to a computational, fully runnable Gallina function.
A simpler version of the above, and likely more useful to you is:
Lemma FFP n (f1 f2 : nat -> nat) :
[forall x : 'I_n, f1 x == f2 x] = all [pred x | f1 x == f2 x] (iota 0 n).
Proof.
apply/eqfunP/allP=> eqf x; last by apply/eqP/eqf; rewrite mem_iota /=.
by rewrite mem_iota; case/andP=> ? hx; have /= -> := eqf (Ordinal hx).
Qed.
But it depends on how you (absent) condition on range restriction is specified.
After your edit, I think I should add a note on the more general topic of map equality, indeed you can define a more specific type of maps other than A -> B and then build a decision procedure.
Most typical map types [including the ones in the stdlib] will work, as long as they support the operation of "binding retrieval", so you can reduce equality to the check of finitely-many bound values.
In fact, the maps in Coq's standard library do already provide you such computational equality function.
Ok, this is a rather brutal solution which does not attempt to avoid doing the same case distinctions multiple times but it's fully automated.
We start with a tactic which inspects whether two integers are equal (using Z.eqb) and translates the results to a proposition which omega can deal with.
Ltac inspect_eq y x :=
let p := fresh "p" in
let q := fresh "q" in
let H := fresh "H" in
assert (p := proj1 (Z.eqb_eq x y));
assert (q := proj1 (Z.eqb_neq x y));
destruct (Z.eqb x y) eqn: H;
[apply (fun p => p eq_refl) in p; clear q|
apply (fun p => p eq_refl) in q; clear p].
We can then write a function which fires the first occurence of i it can find. This may introduce contradictory assumptions in the context e.g. if a previous match has revealed x = 0 but we now call inspect x 0, the second branch will have both x = 0 and x <> 0 in the context. It will be automatically dismissed by omega.
Ltac fire_i x y := match goal with
| [ |- context[i ?x' ?y' _ _] ] =>
unfold i at 1; inspect_eq x x'; inspect_eq y y'; (omega || simpl)
end.
We can then put everything together: call functional extensionality twice, repeat fire_i until there's nothing else to inspect and conclude by reflexivity (indeed all the branches with contradictions have been dismissed automatically!).
Ltac eqFF :=
let x := fresh "x" in
let y := fresh "y" in
intros;
apply functional_extensionality; intro x;
apply functional_extensionality; intro y;
repeat fire_i x y; reflexivity.
We can see that it discharges your lemma without any issue:
Lemma foo_eq : foo = foo'.
Proof.
unfold foo, foo'; eqFF.
Qed.
Here is a self-contained gist with all the imports and definitions.
Related
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).
Well, the code
From mathcomp Require Import ssreflect ssrnat ssrbool eqtype.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Inductive nat_rels m n : bool -> bool -> bool -> Set :=
| CompareNatLt of m < n : nat_rels m n true false false
| CompareNatGt of m > n : nat_rels m n false true false
| CompareNatEq of m == n : nat_rels m n false false true.
Lemma natrelP m n : nat_rels m n (m < n) (m > n) (m == n).
Proof.
case (leqP m n); case (leqP n m).
move => H1 H2; move: (conj H1 H2) => {H1} {H2} /andP.
rewrite -eqn_leq => /eqP /ssrfun.esym /eqP H.
by rewrite H; constructor.
move => H. rewrite leq_eqVlt => /orP.
case.
Error is Error: Case analysis on sort Set is not allowed for inductive definition or.
The last goal before the case is
m, n : nat
H : m < n
============================
m == n \/ m < n -> nat_rels m n true false (m == n)
I've already used this construction (rewrite leq_eqVlt => /orP; case) in very similar situation and it just worked:
Lemma succ_max_distr n m : (maxn n m).+1 = maxn (n.+1) (m.+1).
Proof.
wlog : m n / m < n => H; last first.
rewrite max_l /maxn; last by exact: ltnW.
rewrite leqNgt.
have: m.+1 < n.+2 by apply: ltnW.
by move => ->.
case: (leqP n m); last by apply: H.
rewrite leq_eqVlt => /orP. case.
What is the difference between two cases?
and Why "Case analysis on sort Set is not allowed for inductive definition or"?
The difference between the two cases is the sort of the goal (Set vs Prop) when you execute the case command. In the first situation your goal is nat_rels ... and you declared that inductive in Set; in the second situation your goal is an equality that lands in Prop.
The reason why you can't do a case analysis on \/ when the goal is in Set (the first situation) is because \/ has been declared as Prop-valued. The main restriction associated to such a declaration is that you cannot use informative content from a Prop to build something in Set (or more generally Type), so that Prop is compatible with an erasure-semantic at extraction time.
In particular, doing a case analysis on \/ gives away the side of the \/ that is valid, and you can't be allowed to use that information for building some data in Set.
You have at least two solutions at your disposal:
You could move your family nat_rels from Set to Prop if that's compatible with what you want to do later on.
Or you could use the fact that the hypothesis that you want to branch on is decidable and find a way to produce some {m == n} + { m <n } out of m <= n; here the notation { _ } + { _ } is the Set-valued disjunction of proposition.
In using the Coq apply ... with tactic, the examples I have seen all involve explicitly giving the names of variables to instantiate. For example, given a theorem about the transitivity of equality.
Theorem trans_eq : forall (X:Type) (n m o : X),
n = m -> m = o -> n = o.
To apply it:
Example test: forall n m: nat,
n = 1 -> 1 = m -> n = m.
Proof.
intros n m.
apply trans_eq with (m := 1). Qed.
Note that in the last line apply trans_eq with (m := 1)., I have to remember that the name of the variable to instantiate is m, rather than o or n or some other names y.
To me, whether m n o or x y z are used in the original statement of the theorem shouldn't matter, because they are like dummy variables or formal parameters of a function. And sometimes I can't remember the specific names I used or somebody else put down in a different file when defining the theorem.
Is there a way by which I can refer to the variables e.g. by their position and use something like:
apply trans_eq with (#1 := 1)
in the above example?
By the way, I tried: apply trans_eq with (1 := 1). and got Error: No such binder.
Thanks.
You can specialize the lemma with the right arguments. The _ is used for all arguments that we don't want to specialize (because they can be inferred). The # is required to specialize implicit arguments.
Example test: forall n m: nat,
n = 1 -> 1 = m -> n = m.
Proof.
intros n m.
apply (#trans_eq _ _ 1).
Qed.
You can omit the binder names after with, so in your case do apply trans_eq with 1.
Example test: forall n m: nat,
n = 1 -> 1 = m -> n = m.
Proof.
intros n m.
apply trans_eq with 1; auto.
Qed.
I've changed your original example a little to conclude the proof.
Why this works
To understand why this works, check the manual under Bindings:
Tactics that take a term as an argument may also accept bindings to
instantiate some parameters of the term by name or position. The
general form of a term with bindings is termtac with bindings where
bindings can take two different forms:
bindings::= (ident | natural := term)+
| one_term+
What is shown in this example is the form one_term, which is described as follows:
in the case of apply, or of constructor and its variants, only instances for the dependent products that are not bound in the conclusion of termtac are required.
Which is why only one term needs to be supplied.
I am learning Coq. I am stuck on a quite silly problem (which has no motivation, it is really silly). I want to build a function from ]2,+oo] to the set of integers mapping x to x-3. That should be simple... In any language I know, it is simple. But not in Coq. First, I write (I explain with a lot of details so that someone can explain what I don't understand in the behaviour of Coq)
Definition f : forall n : nat, n > 2 -> nat.
I get a subgoal
============================
forall n : nat, n > 2 -> nat
which means that Coq wants a map from a proof of n>2 to the set of integers. Fine. So I want to tell it that n = 3 + p for some integer p, and then return the integer p. I write :
intros n H.
And I get the context/subgoal
n : nat
H : n > 2
============================
nat
Then i suppose that I have proved n = 3 + p for some integer p by
cut(exists p, 3 + p = n).
I get the context/subgoal
n : nat
H : n > 2
============================
(exists p : nat, 3 + p = n) -> nat
subgoal 2 (ID 6) is:
exists p : nat, 3 + p = n
I move the hypothesis in the context by
intro K.
I obtain:
n : nat
H : n > 2
K : exists p : nat, 3 + p = n
============================
nat
subgoal 2 (ID 6) is:
exists p : nat, 3 + p = n
I will prove the existence of p later. Now I want to finish the proof by exact p. So i need first to do a
destruct K as (p,K).
and I obtain the error message
Error: Case analysis on sort Set is not allowed for inductive
definition ex.
And I am stuck.
You are absolutely right! Writing this function should be easy in any reasonable programming language, and, fortunately, Coq is no exception.
In your case, it is much easier to define your function by simply ignoring the proof argument you are supplying:
Definition f (n : nat) : nat := n - 3.
You may then wonder "but wait a second, the natural numbers aren't closed under subtraction, so how can this make sense?". Well, in Coq, subtraction on the natural numbers isn't really subtraction: it is actually truncated. If you try to subtract, say, 3 from 2, you get 0 as an answer:
Goal 2 - 3 = 0. reflexivity. Qed.
What this means in practice is that you are always allowed to "subtract" two natural numbers and get a natural number back, but in order for this subtraction make sense, the first argument needs to be greater than the second. We then get lemmas such as the following (available in the standard library):
le_plus_minus_r : forall n m, n <= m -> n + (m - n) = m
In most cases, working with a function that is partially correct, such as this definition of subtraction, is good enough. If you want, however, you can restrict the domain of f to make its properties more pleasant. I've taken the liberty of doing the following script with the ssreflect library, which makes writing this kind of function easier:
Require Import Ssreflect.ssreflect Ssreflect.ssrfun Ssreflect.ssrbool.
Require Import Ssreflect.ssrnat Ssreflect.eqtype.
Definition f (n : {n | 2 < n}) : nat :=
val n - 3.
Definition finv (m : nat) : {n | 2 < n} :=
Sub (3 + m) erefl.
Lemma fK : cancel f finv.
Proof.
move=> [n Pn] /=; apply/val_inj=> /=.
by rewrite /f /= addnC subnK.
Qed.
Lemma finvK : cancel finv f.
Proof.
by move=> n; rewrite /finv /f /= addnC addnK.
Qed.
Now, f takes as an argument a natural number n that is greater than 2 (the {x : T | P x} form is syntax sugar for the sig type from the standard library, which is used for forming types that work like subsets). By restricting the argument type, we can write an inverse function finv that takes an arbitrary nat and returns another number that is greater than 2. Then, we can prove lemmas fK and finvK, which assert that fK and finvK are inverses of each other.
On the definition of f, we use val, which is ssreflect's idiom for extracting the element out of a member of a type such as {n | 2 < n}. The Sub function on finv does the opposite, packaging a natural number n with a proof that 2 < n and returning an element of {n | 2 < n}. Here, we rely crucially on the fact that the < is expressed in ssreflect as a boolean computation, so that Coq can use its computation rules to check that erefl, a proof of true = true, is also a valid proof of 2 < 3 + m.
To conclude, the mysterious error message you got in the end has to do with Coq's rules governing computational types, with live in Type, and propositional types, which live in Prop. Coq's rules forbid you from using proofs of propositions to build elements that have computational content (such as natural numbers), except in very particular cases. If you wanted, you could still finish your definition by using {p | 3 + p = n} instead of exists p, 3 + p = n -- both mean the same thing, except the former lives in Type while the latter lives in Prop.
Suppose I have a premise like this:
H2: ~ a b c <> a b c
And I wish to change it to:
a b c = a b c
Where
a is Term -> Term -> Term
b and c are both Term
How can I do it? Thanks!
If you unfold the definitions of ~ and <>, you hypothesis has the following type:
H2: (a b c = a b c -> False) -> False
Therefore, what you wish to achieve is what logicians usually call "double negation elimination". It is not an intuitionistically-provable theorem, and is therefore defined in the Classical module of Coq (see http://coq.inria.fr/distrib/V8.4/stdlib/Coq.Logic.Classical_Prop.html for details):
Classical.NNPP : forall (p : Prop), ~ ~ p -> p
I assume your actual problem is more involved than a b c = a b c, but for the sake of mentioning it, if you really care about obtaining that particular hypothesis, you can safely prove it without even looking at H2:
assert (abc_refl : a b c = a b c) by reflexivity.
If your actual example is not immediately reflexive and the equality is actually false, maybe you want to turn your goal into showing that H2 is absurd. You can do so by eliminating H2 (elim H2., which is basically doing a cut on the False type), and you will end up in the context:
H2 : ~ a b c <> a b c
EQ : a b c = a b c
=====================
False
I'm not sure whether all of this helps, but you might have oversimplified your problem so that I cannot provide more insight on what your real problem is.
Just a little thought to add to Ptival's answer - if your desired goal was not trivially solved by reflexivity, you could still make progress provided you had decidable equality on your Term, for example by applying this little lemma:
Section S.
Parameter T : Type.
Parameter T_eq_dec : forall (x y : T), {x = y} + {x <> y}.
Lemma not_ne : forall (x y : T), ~ (x <> y) -> x = y.
Proof.
intros.
destruct (T_eq_dec x y); auto.
unfold not in *.
assert False.
apply (H n).
contradiction.
Qed.
End S.