I'm trying to representat mod-n counters as a cut of the interval [0, ..., n-1] into two parts:
data Counter : ℕ → Set where
cut : (i j : ℕ) → Counter (suc (i + j))
Using this, defining the two crucial operations is straightforward (some proofs omitted for brevity):
_+1 : ∀ {n} → Counter n → Counter n
cut i zero +1 = subst Counter {!!} (cut zero i)
cut i (suc j) +1 = subst Counter {!!} (cut (suc i) j)
_-1 : ∀ {n} → Counter n → Counter n
cut zero j -1 = subst Counter {!!} (cut j zero)
cut (suc i) j -1 = subst Counter {!!} (cut i (suc j))
The problem comes when trying to prove that +1 and -1 are inverses. I keep running into situations where I need an eliminator for these substs introduced, i.e. something like
subst-elim : {A : Set} → {B : A → Set} → {x x′ : A} → {x=x′ : x ≡ x′} → {y : B x} → subst B x=x′ y ≡ y
subst-elim {A} {B} {x} {.x} {refl} = refl
but this turns out to be (somewhat) begging the question: it isn't accepted by the type checker, because subst B x=x' y : B x' and y : B x...
you can state the type of your subst-elim if you use Relation.Binary.HeterogeneousEquality from the stdlib.
However i'd probably just pattern match on the eventual proof of x ≡ x′ in a with or rewrite clause, so you don't have to make an explicit eliminator and so no typing problem.
Related
I have
1 subgoals, subgoal 1
n : nat
b : bool
m : nat
H1: P1
H2: P2
H3: P1
H4: P2
=========
some_goal
after I run the tactic auto_group_duplicates,
it will become
1 subgoals, subgoal 1
n, m : nat
b : bool
H1, H3: P1
H2, H4: P2
=========
some_goal
Is there a tactic like this one?
I don't think that there is a tactic like this. But you can always come up with something using Ltac.
From Coq Require Import Utf8.
Definition mark {A : Type} (x : A) := x.
Ltac bar :=
match goal with
| x : ?A, y : ?A |- _ =>
lazymatch A with
| context [ mark ] => fail
| _ =>
move y after x ;
change A with (mark A) in x
end
end.
Ltac remove_marks :=
repeat match goal with
| x : mark ?A |- _ =>
change (mark A) with A in x
end.
Ltac auto_group_duplicates :=
repeat bar ; remove_marks.
Lemma foo :
∀ (n : nat) (b : bool) (m : nat) (c : bool),
n = m →
b = c →
n = m →
b = c →
n = m →
True.
Proof.
intros n b m c e1 e2 e3 e4 e5.
auto_group_duplicates.
auto_group_duplicates.
Here I have to apply the tactic twice because Ltac unifies A with mark A annoyingly.
You can manually use the move tactic (see https://coq.inria.fr/refman/proof-engine/tactics.html?highlight=top#coq:tacn.move-%E2%80%A6-after-%E2%80%A6) to rearrange hypothesis.
I doubt that there is a general automatic tactic like the one you are looking for, but one could probably cook up a fancy match-goal-based one to automate rearranging hypothesis using this tactic as a basic block, although this is out of my league.
I'm trying to use Equations package to define a function over vectors in Coq. The minimum code that shows the problem that I will describe is available at the following gist.
My idea is to code a function that does a lookup on a "proof" that some type holds for all elements of a vector, which has a standard definition:
Inductive vec (A : Type) : nat -> Type :=
| VNil : vec A 0
| VCons : forall n, A -> vec A n -> vec A (S n).
Using the previous type, I had defined the following (also standard) lookup operation (using Equations):
Equations vlookup {A}{n}(i : fin n) (v : vec A n) : A :=
vlookup FZero (VCons x _) := x ;
vlookup (FSucc ix) (VCons _ xs) := vlookup ix xs.
Now, the trouble begins. I want to define the type of "proofs" that some
property holds for all elements in a vector. The following inductive type does this job:
Inductive vforall {A : Type}(P : A -> Type) : forall n, vec A n -> Type :=
| VFNil : vforall P _ VNil
| VFCons : forall n x xs,
P x -> vforall P n xs -> vforall P (S n) (VCons x xs).
Finally, the function that I want to define is
Equations vforall_lookup
{n}
{A : Type}
{P : A -> Type}
{xs : vec A n}
(idx : fin n) :
vforall P xs -> P (vlookup idx xs) :=
vforall_lookup FZero (VFCons _ _ pf _) := pf ;
vforall_lookup (FSucc ix) (VFCons _ _ _ ps) := vforall_lookup ix ps.
At leas to me, this definition make sense and it should type check. But, Equations had showed the following warning and left me with a proof obligation in which I had no idea on how to finish it.
The message presented after the definition of the previous function is:
Warning:
In environment
eos : end_of_section
fix_0 : forall (n : nat) (A : Type) (P : A -> Type) (xs : vec A n)
(idx : fin n) (v : vforall P xs),
vforall_lookup_ind n A P xs idx v (vforall_lookup idx v)
A : Type
P : A -> Type
n0 : nat
x : A
xs0 : vec A n0
idx : fin n0
p : P x
v : vforall P xs0
Unable to unify "VFCons P n0 x xs0 p v" with "v".
The obligation left is
Obligation 1 of vforall_lookup_ind_fun:
(forall (n : nat) (A : Type) (P : A -> Type) (xs : vec A n)
(idx : fin n) (v : vforall P xs),
vforall_lookup_ind n A P xs idx v (vforall_lookup idx v)).
Later, after looking at a similar definition in Agda standard library, I realised that the previous function definition is missing a case for the empty vector:
lookup : ∀ {a p} {A : Set a} {P : A → Set p} {k} {xs : Vec A k} →
(i : Fin k) → All P xs → P (Vec.lookup i xs)
lookup () []
lookup zero (px ∷ pxs) = px
lookup (suc i) (px ∷ pxs) = lookup i pxs
My question is, how can I specify that, for the empty vector case, the right hand side should be empty, i.e. a contradiction? The Equations manual shows an example for equality but I could adapt it to this case. Any idea on what am I doing wrong?
I think I finally understood what is going on in this example by looking closely at the obligation generated.
The definition is correct, and it is accepted (you can use vforall_lookup without solving the obligation). What fails to be generated is the induction principle associated to the function.
More precisely, Equations generates the right induction principle in three steps (this is detailed in the reference manual) in section "Elimination principle":
it generates the graph of the function (in my version of Equations it is called vforall_lookup_graph, in previous versions it was called vforall_lookup_ind). I am not sure that I fully understand what it is. Intuitively, it reflects the structure of the body of the function. In any case, it is a key component to generate the induction principle.
it proves that the function respects this graph (in a lemma called vforall_lookup_graph_correct or vforall_lookup_ind_fun);
it combines the last two results to generate the induction principle associated to the function (this lemma is called vforall_lookup_elim in all versions).
In your case, the graph was correctly generated but Equations was not able to prove automatically that the function respects its graph (step 2), so it is left to you.
Let's give it a try!
Next Obligation.
induction v.
- inversion idx.
- dependent elimination idx.
(* a powerful destruct provided by Equations
that correctly working with dependent types
*)
+ constructor.
+ constructor.
Coq rejects the last call to constructor with the error
Unable to unify "VFCons P n1 x xs p v" with "v".
This really looks like the error obtained in the first place, so I think the automatic resolution reached this same point and failed. Does this mean that we took a wrong path? Let's look closer at the goal before the second constructor.
We have to prove
vforall_lookup_graph (S n1) A P (VCons x xs) (FSucc f) (VFCons P n1 x xs p v) (vforall_lookup (FSucc f) (VFCons P n1 x xs p v))
while the type of vforall_lookup_graph_equation_2, the second constructor of vforall_lookup_graph_equation is
forall (n : nat) (A : Type) (P : A -> Type) (x : A) (xs0 : vec A n) (f : fin n) (p : P x) (v : vforall P xs0),
vforall_lookup_graph n A P xs0 f v (vforall_lookup f v) -> vforall_lookup_graph (S n) A P (VCons x xs0) (FSucc f) (VFCons P n x xs0 p v) (vforall_lookup f v)
The difference lies in the calls to vforall_lookup. In the first case, we have
vforall_lookup (FSucc f) (VFCons P n1 x xs p v)
and in the second case
vforall_lookup f v
But these are identical by definition of vforall_lookup! But by default the unification fails to recognize that. We need to help it a bit. We can either give the value of some argument, e.g.
apply (vforall_lookup_graph_equation_2 n0).
or we can use exact or refine that unify more aggressively than apply since they are given the whole term and not only its head
refine (vforall_lookup_graph_equation_2 _ _ _ _ _ _ _ _ _).
We can conclude easily by the induction hypothesis. This gives the following proof
Next Obligation.
induction v.
- inversion idx.
- dependent elimination idx.
+ constructor.
+ (* IHv is the induction hypothesis *)
exact (vforall_lookup_graph_equation_2 _ _ _ _ _ _ _ _ (IHv _)).
Defined.
Since I like doing proofs with dependent types by hand, I can't help giving a proof that does not use dependent elimination.
Next Obligation.
induction v.
- inversion idx.
- revert dependent xs.
refine (
match idx as id in fin k return
match k return fin k -> Type with
| 0 => fun _ => IDProp
| S n => fun _ => _
end id
with
| FZero => _
| FSucc f => _
end); intros.
+ constructor.
+ exact (vforall_lookup_graph_equation_2 _ _ _ _ _ _ _ _ (IHv _)).
Defined.
For example, we're proving 2 + 2 != 5:
data _+_≡_ : ℕ → ℕ → ℕ → Set where
znn : ∀ {n} → zero + n ≡ n
sns : ∀ {m n k} → m + n ≡ k → suc m + n ≡ suc k
And I can manually prove it:
2+2≠5 : 2 + 2 ≡ 5 → ⊥
2+2≠5 (sns (sns ()))
But I want the pattern (sns (sns ())) to be generated (just like filling a hole). Are there any ways to achieve that?
I am using Emacs 25 with agda2-mode.
Ok, so let's say you start from this configuration:
2+2≠5 : 2 + 2 ≡ 5 → ⊥
2+2≠5 h = {!!}
In this case you can use emacs' keyboard macros because the sub-term generated by matching on h will also be named h. So using:
<f3> (start recording the macro)
C-c C-f (move to the hole)
C-c C-c h RET (match on h)
<f4> (record the macro)
you've recorded the action of "moving to the first goal an matching on h". You can now keep pressing <f4> until you reach an absurd case.
I am trying to prove something simple:
open import Data.List
open import Data.Nat
open import Data.Bool
open import Data.Bool.Properties
open import Relation.Binary.PropositionalEquality
open import Data.Unit
repeat : ∀ {a} {A : Set a} → ℕ → A → List A
repeat zero x = []
repeat (suc n) x = x ∷ repeat n x
filter-repeat : ∀ {a} {A : Set a} → (p : A → Bool) → (x : A) → T (p x) → ∀ n →
filter p (repeat n x) ≡ repeat n x
I thought proving filter-repeat is going to be easy by pattern matching on p x:
filter-repeat p x prf zero = refl
filter-repeat p x prf (suc n) with p x
filter-repeat p x () (suc n) | false
filter-repeat p x prf (suc n) | true = cong (_∷_ x) (filter-repeat p x prf n)
However this complains that prf : ⊤ is not of type T (p x). So I thought, OK, this seems like a familiar problem, let's whip out inspect:
filter-repeat p x prf zero = refl
filter-repeat p x prf (suc n) with p x | inspect p x
filter-repeat p x () (suc n) | false | _
filter-repeat p x tt (suc n) | true | [ eq ] rewrite eq = cong (_∷_ x) (filter-repeat p x {!!} n)
but despite the rewrite, the type of the hole is still T (p x) instead of T true. Why is that? How do I reduce its type to T true so I can fill it with tt?
Workaround
I was able to work around it by using T-≡:
open import Function.Equality using (_⟨$⟩_)
open import Function.Equivalence
filter-repeat : ∀ {a} {A : Set a} → (p : A → Bool) → (x : A) → T (p x) → ∀ n →
filter p (repeat n x) ≡ repeat n x
filter-repeat p x prf zero = refl
filter-repeat p x prf (suc n) with p x | inspect p x
filter-repeat p x () (suc n) | false | _
filter-repeat p x tt (suc n) | true | [ eq ] = cong (_∷_ x) (filter-repeat p x (Equivalence.from T-≡ ⟨$⟩ eq) n)
but I would still like to understand why the inspect-based solution doesn't work.
As András Kovács says the inductive case requires prf to be of type T (p x) while you've already changed it to just ⊤ by pattern matching on p x. One simple solution is just to call filter-repeat recursively before pattern matching on p x:
open import Data.Empty
filter-repeat : ∀ {a} {A : Set a} → (p : A → Bool) → (x : A) → T (p x) → ∀ n →
filter p (repeat n x) ≡ repeat n x
filter-repeat p x prf 0 = refl
filter-repeat p x prf (suc n) with filter-repeat p x prf n | p x
... | r | true = cong (x ∷_) r
... | r | false = ⊥-elim prf
It also can sometimes be useful to use the protect pattern:
data Protect {a} {A : Set a} : A → Set where
protect : ∀ x → Protect x
filter-repeat : ∀ {a} {A : Set a} → (p : A → Bool) → (x : A) → T (p x) → ∀ n →
filter p (repeat n x) ≡ repeat n x
filter-repeat p x q 0 = refl
filter-repeat p x q (suc n) with protect q | p x | inspect p x
... | _ | true | [ _ ] = cong (x ∷_) (filter-repeat p x q n)
... | _ | false | [ r ] = ⊥-elim (subst T r q)
protect q saves the type of q from being rewritten, but it also means that in the false case the type of q is still T (p x) rather than ⊥, hence the additional inspect.
Another variant of the same idea is
module _ {a} {A : Set a} (p : A → Bool) (x : A) (prf : T (p x)) where
filter-repeat : ∀ n → filter p (repeat n x) ≡ repeat n x
filter-repeat 0 = refl
filter-repeat (suc n) with p x | inspect p x
... | true | [ r ] = cong (x ∷_) (filter-repeat n)
... | false | [ r ] = ⊥-elim (subst T r prf)
module _ ... (prf : T (p x)) where prevents the type of prf from being rewritten as well.
Dependent pattern matching only affects the goal and the context at the exact point of their use. Matching on p xrewrites the current context and reduces the type of prf to ⊤ in the true branch.
However, when you do the recursive filter-repeat call, you once again supply x as argument there, and T (p x) in filter-repeat depends on that x, not the old one in the outer context, even though they're definitionally equal. We could've passed something other than x, hypothetically, so no assumption can be made about it before the filter-repeat call.
x can be made invariant in the context by factoring it out from the induction:
open import Data.Empty
filter-repeat : ∀ {a} {A : Set a} → (p : A → Bool) → (x : A) → T (p x) → ∀ n →
filter p (repeat n x) ≡ repeat n x
filter-repeat p x prf = go where
go : ∀ n → filter p (repeat n x) ≡ repeat n x
go zero = refl
go (suc n) with p x | inspect p x
go (suc n) | true | [ eq ] = cong (_∷_ x) (go n)
go (suc n) | false | [ eq ] = ⊥-elim (subst T eq prf)
Here is what I am trying to prove:
A : Type
i : nat
index_f : nat → nat
n : nat
ip : n < i
partial_index_f : nat → option nat
L : partial_index_f (index_f n) ≡ Some n
V : ∀ i0 : nat, i0 < i → option A
l : ∀ z : nat, partial_index_f (index_f n) ≡ Some z → z < i
============================
V n ip
≡ match
partial_index_f (index_f n) as fn
return (partial_index_f (index_f n) ≡ fn → option A)
with
| Some z => λ p : partial_index_f (index_f n) ≡ Some z, V z (l z p)
| None => λ _ : partial_index_f (index_f n) ≡ None, None
end eq_refl
The obvious next step is either rewrite L or destruct (partial_index_f (index_f n). Trying to applying rewrite gives me an error:
Error: Abstracting over the term "partial_index_f (index_f n)"
leads to a term
"λ o : option nat,
V n ip
≡ match o as fn return (o ≡ fn → option A) with
| Some z => λ p : o ≡ Some z, V z (l z p)
| None => λ _ : o ≡ None, None
end eq_refl" which is ill-typed.
I do not understand what is causing this problem. I also would like to understand how I can deal with it in general.
I was able to prove it using the following steps, but I am not sure this is the best way:
destruct (partial_index_f (index_f n)).
inversion L.
generalize (l n0 eq_refl).
intros. subst n0.
replace l0 with ip by apply proof_irrelevance.
reflexivity.
congruence.
In Coq's theory, when you perform a rewrite with an equation, you have to generalize over the side of the equation that you want to replace. In your case, you want to replace partial_index_f (index_f n), so Coq tries to generalize that, as you can tell from the error message you got.
Now, if your goal contains something whose type mentions the thing that you want to replace, you might run into trouble, because this generalization might make the goal become ill-typed. (Notice that that type does not exactly occur in the goal, hence Coq does not try to deal with it like it does when something occurs in the goal.) Going back to your case, your l function has type ∀ z : nat, partial_index_f (index_f n) ≡ Some z → z < i, which mentions partial_index_f (index_f n), the term you want to replace. In the first branch of your match, you apply this function to the o = Some z hypothesis that you abstracted over. On the original goal, o was the thing you wanted to replace, but when Coq tries to generalize, the two do not match anymore, hence the error message.
I can't try to fix the problem on my own, but you can solve issues like this usually by generalizing over the term in your context that mentions the term you are replacing, because then its type will show in the goal, associated to a universally quantified variable. This might not help if your term is defined globally and you need it to have a certain shape after the rewrite in order to be able to perform additional reasoning steps, in which case you will probably have to generalize over the lemmas that you need as well.