Can I avoid using Option A when I know that head cannot fail? - coq

I am quite new in the world of the ATP, but definitely very motivated.
I am starting to deal with dependent types. I am involved in a project where I have defined the type for (finite and infinite) sequences.
Inductive sequence {X : Type} : Type :=
| FinSeq (x : list X)
| InfSeq (f : nat -> X).
Now I want to define the head of a non-empty sequence.
Lemma aux_hd : forall {A : Type} (l : list A),
0 < Datatypes.length l -> #hd_error A l = None -> False.
Proof. destruct l.
+ simpl. lia.
+ simpl. intros S. discriminate.
Qed.
Definition Hd {A : Type} (l : list A) : 0 < Datatypes.length l -> A :=
match (hd_error l) with
| Some a => (fun _ => a)
| None => fun pf => match (aux_hd l pf ??) with end
end.
Definition Head {A : Type} (s :sequence) (H : 0 << length s),
match s with
| FinSeq x => Hd x H
| InfSeq f => f 0 end.
My problem is in the definition of Hd: I don't know how to prove #hd_error A l = None, since we are already in such a match branch. I believe it should be really easy.
I have a similar problem in the last definition because I don't know how to transform H, for the particular case of the first match branch, where I know that length s = Datatypes.length x and, thus, 0 << length s -> 0 < Datatypes.length x.
Finally, I have omitted the details about << and length sequence, because I dont think it is relevant for the question but basically I have uplifted nat with an Inf to represent the length of the infinite sequences and << is the < for nat and num.
I have followed the course Software Foundations and I am currently studying more using "Certified Programming with Dependent Types" which is also really good.
Thanks in advance,
Miguel

When you match on something, all extra evidence must be passed as arguments to the match (this is the "convoy pattern" described in CPDT).
In Hd you want to remember that hd_error l = None, pass it as an argument. It's a little tricky because you have to explicitly annotate the match with a return clause (which in simpler cases was inferred for you):
Definition Hd {A : Type} (l : list A) : 0 < Datatypes.length l -> A :=
match (hd_error l) as X return hd_error l = X -> 0 < Datatypes.length l -> A with
| Some a => (fun _ _ => a)
| None => fun pf1 pf2 => match (aux_hd l pf2 pf1) with end
end eq_refl.
Similarly in Head, after pattern-matching on s you want to simplify 0 << length s; pass it as an argument:
Definition Head {A : Type} (s :sequence) (H : 0 << length s) :=
match s return (0 << length s) -> _ with
| FinSeq x => fun H => Hd x H
| InfSeq f => fun _ => f 0
end H.

Related

Exhaustiveness matching in proof objects for induction in Coq

In Software Foundations, they discuss how to build you own proof objects for induction:
https://softwarefoundations.cis.upenn.edu/lf-current/IndPrinciples.html#nat_ind2
Definition nat_ind2 :
∀ (P : nat → Prop),
P 0 →
P 1 →
(∀ n : nat, P n → P (S(S n))) →
∀ n : nat , P n :=
fun P ⇒ fun P0 ⇒ fun P1 ⇒ fun PSS ⇒
fix f (n:nat) := match n with
0 ⇒ P0
| 1 ⇒ P1
| S (S n') ⇒ PSS n' (f n')
end.
I experimented with this definition by commenting out "| 1 ⇒ P1". Coq then gives an error: "Non exhaustive pattern-matching: no clause found for pattern 1." I was expecting an error, of course. But I don't know how Coq figures out there is an error.
I would like to know how Coq does the exhaustiveness matching to know that 1 needs to be checked, since 1 isn't part of the constructor for nat. Roughly what algorithm is Coq following?
I'm not sure it answers fully your question, but you may look at the way "extended" matching are dealt with (see for instance https://coq.inria.fr/distrib/current/refman/language/extensions/match.html#mult-match ).
Let's look at a simple example.
Definition f (n: nat): nat :=
match n with
2 => 2
| 1 => 23
| _ => S n
end.
With the following command, I can see how f is expressed through simple pattern matchings.
Unset Printing Matching.
Print f.
(*
f =
fun n : nat =>
match n with
| 0 => S n
| S n0 =>
match n0 with
| 0 => 23
| S n1 => match n1 with
| 0 => 2
| S _ => S n
end
end
end
: nat -> nat
*)
If you remove the clause for 1 from your example, it seems impossible to
convert your match into nested simple 0 | S _ matchings `.

Definition by minimization in Coq

Assume P: nat -> T -> Prop is a proposition that for any given t: T,
either there exists a k: nat such that P holds for all numbers greater than or equal to k and no number less than k.
or P k t is false for all k : nat.
I want to define min_k : T -> nat + undef to be the minimum number k such that P k t holds, and undef otherwise.
Is that even possible? I tried to define something like
Definition halts (t : T) := exists k : nat, P k t.
Or maybe
Definition halts (t : T) := exists! k : nat, (~ P k t /\ P (S k) t).
and then use it like
Definition min_k (t : T) := match halts T with
| True => ??
| False => undef
end.
but I don't know how to go further from there.
Any ideas would be appreciated.
You can't match on a Prop. If you want to do case analysis then you need something in Type, typically bool or something like sumbool or sumor. In other words, you can do what you want as long as you have a pretty strong hypothesis.
Variable T : Type.
Variable P : nat -> T -> Prop.
Hypothesis PProperty : forall (t : T),
{k : nat | forall n, (k <= n -> P n t) /\ (n < k -> ~ P n t)}
+
{forall k, ~ P k t}.
Definition min_k (t : T) : option nat :=
match PProperty t with
| inleft kH => Some (proj1_sig kH)
| inright _ => None
end.
Crucially, this wouldn't have worked if PProperty was a Prop disjunction, i.e., if it was of the form _ \/ _ instead of the form _ + { _ }.
By the way, the idiomatic way of describing foo + undef in Coq is to use option foo, which is what I did above, but you can adapt it as you wish.
In addition to Ana's excellent answer, I think it is worth pointing out that option nat is essentially the same thing as {k : nat | ...} + {forall k, ~ P k t} if you erase the proofs of the latter type: in the first case (Some or inleft), you get a natural number out; in the second (None or inright) you get nothing at all.

Define list length in recursion in Coq Not sure if my function is wrong and got stuck

So i was trying to define a tail-recursive version of list length function and prove that the function is the same as "length" function
Below is my code. Got stuck when prove
Fixpoint length_tail (A: Type) (l: list A) (len: nat): nat :=
match l, len with
| [], len => len
| _ :: t, len => length_tail _ t (1 + len)
end.
Example length_rev: forall {A: Type} {l1: list A},
#length_tail _ l1 0 = #length _ l1.
Proof.
intros.
induction l1.
- simpl. reflexivity.
- simpl.
rewrite <- IHl1.
+ simpl.
Admitted.
Below is the original function for the "length":
Fixpoint length (l:natlist) : nat :=
match l with
| nil => O
| h :: t => S (length t)
end.
Tons of appreciations if anyone could help or give some hints!! Thanks!
Several things:
First, you pattern-match on both l and len the accumulator in your function but you are not looking at its shape, the following would do just as well:
Fixpoint length_tail (A: Type) (l: list A) (len: nat): nat :=
match l with
| [] => len
| _ :: t => length_tail _ t (1 + len)
end.
Second, the problem you are facing is that the lemma you want to prove by induction is not general enough. Indeed you are assuming that the accumulator is 0, but as you can see in the recursive call, you have 1 + len (which is just S len by the way), which will never be equal to 0.
In order to prove this by induction you need to prove something stronger.
Typically you want to give an expression that is equal to length_tail l len in terms of length l such that when instantiated with 0 you get length l.
To me it sounds like length_tail l len = len + length l is a good candidate.
You will have to do this often when proving properties about functions with accumulators.
There are several ways to go about this:
You could directly prove the more general lemma and then have a corollary, it could be useful for other things.
You can use assert of the stronger lemma in your proof and then conclude with it.
Or you can generalize your goal in your proof. I would personally not use it but I will show it to illustrate what one can do.
Fixpoint length_tail {A : Type} (l: list A) (len: nat): nat :=
match l, len with
| [], len => len
| _ :: t, len => length_tail t (1 + len)
end.
Example length_rev : forall {A: Type} {l : list A},
length_tail l 0 = length l.
Proof.
intros A l.
change (length l) with (0 + length l).
generalize 0 as n.
(* Now the goal is forall n : nat, length_tail l n = n + length l *)
Note that I marked the type as implicit in length_tail, this way it's much more readable don't you think?

How to reason with complex pattern-matchings?

Coq allows to write complex pattern-matchings, but then it decomposes them so that its kernel can handle them.
For instance, let us consider the following code.
Require Import List. Import ListNotations.
Inductive bar := A | B | C.
Definition f (l : list bar) :=
match l with
| _ :: A :: _ => 1
| _ => 2
end.
We pattern-match both on the list and on the second element. Printing f shows that Coq stores a more complex version of it.
Print f.
(* f = fun l : list bar => match l with
| [] => 2
| [_] => 2
| _ :: A :: _ => 1
| _ :: B :: _ => 2
| _ :: C :: _ => 2
end
: list bar -> nat
*)
The problem is that, in the proofs manipulating f, I have to deal with 5 cases instead of only 2, and 4 of them are redundant.
What is the best way to deal with this? Is there a way to reason with the pattern-matching as if it were exactly as defined?
You are correct in that Coq actually simplifies pattern-matching making a lot of redundancies appear.
There are however some ways to reason on the case analysis you meant opposed to what Coq understands.
Using Function and function induction is a way.
More recently, Equations also allows you to define pattern-matching for which it derives induction principles automatically (that you can invoke using funelim).
In order to convince coq cases can be factorised you have to use the notion of view.
They are described in the context of Equations in the examples.
I'll detail how to adapt your example to it.
From Equations Require Import Equations.
Require Import List. Import ListNotations.
Inductive bar := A | B | C.
Equations discr (b : list bar) : Prop :=
discr (_ :: A :: _) := False ;
discr _ := True.
Inductive view : list bar -> Set :=
| view_foo : forall x y, view (x :: A :: y)
| view_other : forall l, discr l -> view l.
Equations viewc l : view l :=
viewc (x :: A :: y) := view_foo x y ;
viewc l := view_other l I.
Equations f (l : list bar) : nat :=
f l with viewc l := {
| view_foo _ _ => 1 ;
| view_other _ _ => 2
}.
Goal forall l, f l < 3.
Proof.
intro l.
funelim (f l).
- repeat constructor.
- repeat constructor.
Qed.
As you can see, funelim only generates two subgoals.
It can be a bit heavy so if you don't want to use Equations of Function, you might have to prove your own induction principles by hand:
Require Import List. Import ListNotations.
Inductive bar := A | B | C.
Definition f (l : list bar) :=
match l with
| _ :: A :: _ => 1
| _ => 2
end.
Definition discr (l : list bar) : Prop :=
match l with
| _ :: A :: _ => False
| _ => True
end.
Lemma f_ind :
forall (P : list bar -> nat -> Prop),
(forall x y, P (x :: A :: y) 1) ->
(forall l, discr l -> P l 2) ->
forall l, P l (f l).
Proof.
intros P h1 h2 l.
destruct l as [| x [|[] l]].
3: eapply h1.
all: eapply h2.
all: exact I.
Qed.
Goal forall l, f l < 3.
Proof.
intro l.
eapply f_ind.
- intros. repeat constructor.
- intros. repeat constructor.
Qed.

Fixpoint with Prop inhabitant as argument

Consider the definition of find in the standard library, which as the type find: forall A : Type, (A -> bool) -> list A -> option A.
Of course, find has to return an option A and not an A because we don't know wether there is a "valid" element in the list.
Now, say I find this definition of find painful, because we have to deal with the option, even when we are sure that such an element exists in the list.
Hence, I'd like to define myFind which additionnaly takes a proof that there is such an element in the list. It would be something like:
Variable A: Type.
Fixpoint myFind
(f: A -> bool)
(l: list A)
(H: exists a, In a l /\ f a = true): A :=
...
If I am not mistaken, such a signature informally says: "Give me a function, a list, and a proof that you have a "valid" element in the list".
My question is: how can I use the hypothesis provided and define my fixpoint ?
What I have in mind is something like:
match l with
| nil => (* Use H to prove this case is not possible *)
| hd :: tl =>
if f hd
then hd
else
(* Use H and the fact that f hd = false
to prove H': exists a, In a tl /\ f a = true *)
myFind f tl H'
end.
An bonus point would be to know whether I can embbed a property about the result directly within the type, for instance in our case, a proof that the return value r is indeed such that f r = true.
We can implement this myFind function by structural recursion over the input list. In the case of empty list the False_rect inductive principle is our friend because it lets us switch from the logical world to the world of computations. In general we cannot destruct proofs of propositions if the type of the term under construction lives in Type, but if we have an inconsistency the system lets us.
We can handle the case of the non-empty input list by using the convoy pattern (there is a number of great answers on Stackoverflow explaining this pattern) and an auxiliary lemma find_not_head.
It might be useful to add that I use the convoy pattern twice in the implementation below: the one on the top level is used to let Coq know the input list is empty in the first match-branch -- observe that the type of H is different in both branches.
From Coq Require Import List.
Import ListNotations.
Set Implicit Arguments.
(* so we can write `f a` instead of `f a = true` *)
Coercion is_true : bool >-> Sortclass.
Section Find.
Variables (A : Type) (f : A -> bool).
(* auxiliary lemma *)
Fact find_not_head h l : f h = false ->
(exists a, In a (h :: l) /\ f a) ->
exists a, In a l /\ f a.
Proof. intros E [a [[contra | H] fa_true]]; [congruence | now exists a]. Qed.
Fixpoint myFind (l : list A) (H : exists a : A, In a l /\ f a) : {r : A | f r} :=
match l with
| [] => fun H : exists a : A, In a [] /\ f a =>
False_rect {r : A | f r}
match H with
| ex_intro _ _ (conj contra _) =>
match contra with end
end
| h :: l => fun H : exists a : A, In a (h :: l) /\ f a =>
(if f h as b return (f h = b -> {r : A | f r})
then fun Efh => exist _ h Efh
else fun Efh => myFind l (find_not_head Efh H)) eq_refl
end H.
End Find.
Here is a simplistic test:
From Coq Require Import Arith.
Section FindTest.
Notation l := [1; 2; 0; 9].
Notation f := (fun n => n =? 0).
Fact H : exists a, In a l /\ f a.
Proof. exists 0; intuition. Qed.
Compute myFind f l H.
(*
= exist (fun r : nat => f r) 0 eq_refl
: {r : nat | f r}
*)
End FindTest.
You can also use Program to help you construct the proof arguments interactively. You fill in as much as you can in the program body and leave _ blanks that you get to fill in later with proof tactics.
Require Import List Program.
Section Find.
Variable A : Type.
Variable test : A -> bool.
Program Fixpoint FIND l (H:exists a, test a = true /\ In a l) : {r | test r = true} :=
match l with
| [] => match (_:False) with end
| a::l' => if dec (test a) then a else FIND l' _
end.
Next Obligation.
firstorder; congruence.
Defined.
End Find.
Program is a little better at not forgetting information when you do case analysis (it knows the convoy pattern) but it is not perfect, hence the use of dec in the if statement.
(Notice how Coq was able to handle the first obligation, to construct a term of type False, all by itself!)