Transform casual list into dependently typed list in Coq - coq

I have following definition of list in Coq:
Variable A : Set.
Variable P : A -> Prop.
Hypothesis P_dec : forall x, {P x}+{~(P x)}.
Inductive plist : nat -> Set :=
pnil : plist O
| pcons : A -> forall n, plist n -> plist n
| pconsp : forall (a:A) n, plist n -> P a -> plist (S n)
.
It describes "list of elements of type A where at least n of them fulfill predicate P".
My task is to create function that will convert casual list into plist (with maximum possible n). My attempt was to first count all elements that match P and then set the output type according to the result:
Fixpoint pcount (l : list A) : nat :=
match l with
| nil => O
| h::t => if P_dec h then S(pcount t) else pcount t
end.
Fixpoint plistIn (l : list A) : (plist (pcount l)) :=
match l with
| nil => pnil
| h::t => match P_dec h with
| left proof => pconsp h _ (plistIn t) proof
| right _ => pcons h _ (plistIn t)
end
end.
However, I get an error in the line with left proof:
Error:
In environment
A : Set
P : A -> Prop
P_dec : forall x : A, {P x} + {~ P x}
plistIn : forall l : list A, plist (pcount l)
l : list A
h : A
t : list A
proof : P h
The term "pconsp h (pcount t) (plistIn t) proof" has type
"plist (S (pcount t))" while it is expected to have type
"plist (pcount (h :: t))".
The problem is that Coq cannot see that S (pcount t) equals pcount (h :: t) knowing that P h, which was already proven. I cannot let Coq know this truth.
How to define this function correctly? Is it even possible to do so?

You can use dependent pattern-matching, as the result type plist (pcount (h :: t)) depends on whether P_dec h is left or right.
Below, the keyword as introduces a new variable p, and return tells the type of the whole match expression, parameterized by p.
Fixpoint plistIn (l : list A) : (plist (pcount l)) :=
match l with
| nil => pnil
| h::t => match P_dec h as p return plist (if p then _ else _) with
| left proof => pconsp h (pcount t) (plistIn t) proof
| right _ => pcons h _ (plistIn t)
end
end.
The type plist (if p then _ else _) must be equal to plist (pcount (h :: t)) when substituting p := P_dec h. Then in each branch, say left proof, you need to produce plist (if left proof then _ else _) (which reduces to the left branch).
It's a bit magical that Coq can infer what goes in the underscores here, but to be safe you can always spell it out: if p then S (pcount t) else pcount t (which is meant to exactly match the definition of pcount).

Related

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.

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

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.

Decreasing argument with dependent types

When dealing with non-dependent types, Coq (usually) infers which argument is decreasing in a fixpoint. However, it is not the case with dependent types.
For instance, consider the following example in which I have a type A_list which ensures that a property P holds for all elements (of type A) in the list:
Require Import Coq.Lists.List.
Variable A: Type.
Variable P: A -> Prop.
Definition A_list := {a: list A | Forall P a}.
Now, say I want to have a fixpoint working with such a list recursively (the 2 lemmas are not interesting here. The dummy_arg is to simulate working with multiple arguments.) :
Lemma Forall_tl: forall P (h: A) t, Forall P (h::t) -> Forall P t.
Admitted.
Lemma aux: forall (l1: list A) l2 P, l1 = l2 -> Forall P l1 -> Forall P l2.
Admitted.
Fixpoint my_fixpoint (l: A_list) (dummy_arg: A) :=
match (proj1_sig l) as x return proj1_sig l = x -> bool with
| nil => fun _ => true
| hd::tl =>
fun h =>
my_fixpoint (exist (Forall P) tl (Forall_tl P hd tl (aux _ _ _ h (proj2_sig l)))) dummy_arg
end eq_refl.
Which, as expected, returns an error "Cannot guess decreasing argument of fix." since, strictly speaking, we are not decreasing on the argument. Nonetheless, we are obviously decreasing on proj1_sig l (the list embedded in the sig).
This is probably solvable using Program Fixpoints, but since it must be a very common pattern to decrease on a projection of a dependent type, I wonder what is the "right" way to manage such cases.
You can solve this problem using one of the methods I mentioned in this answer, including Program.
If you decouple the list and the proof, then it can be done using ordinary recursion :
Fixpoint my_fixpoint (l: list A) (pf : Forall P l) (dummy_arg: A) : bool :=
match l as x return Forall P x -> bool with
| nil => fun _ => true
| hd::tl => fun h => my_fixpoint tl (Forall_tl P hd tl h) dummy_arg
end pf.

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!)

When is the first input to `list_rec` not a constant function?

The list_rec function has the type:
list_rec
: forall (A : Type) (P : list A -> Set),
P nil ->
(forall (a : A) (l : list A), P l -> P (a :: l)%list) ->
forall l : list A, P l
In all of the examples I've come up with, P is just a constant function that ignores the input list and returns the same type no matter what. For example, P might be fun _ : list A => nat or fun _ : list A => list B. What are some use cases for making the output of P dependent on the input? Why is the type of P list A -> Set instead of just Set?
We can, for example, use list_rec with a non-constant P function to implement a function that converts a list to a vector (a length-indexed list).
Require List Vector.
Import List.ListNotations Vector.VectorNotations.
Set Implicit Arguments.
Section VecExample.
Variable A : Set.
Definition P (xs : list A) : Set := Vector.t A (length xs).
Definition list_to_vector : forall xs : list A, Vector.t A (length xs) :=
list_rec P [] (fun x _ vtail => x :: vtail).
End VecExample.
You can compare it with the standard definition of the Vector.of_list function, which does exactly the same (t means Vector.t in the following code), using explicit recursion instead of hiding it behind a recursion principle:
Fixpoint of_list {A} (l : list A) : t A (length l) :=
match l as l' return t A (length l') with
|Datatypes.nil => []
|(h :: tail)%list => (h :: (of_list tail))
end.
A simple test:
Eval compute in list_to_vector [1;2;3].
Eval compute in Vector.of_list [1;2;3].
Both function calls return the same result:
= [1; 2; 3]
: Vector.t nat (length [1; 2; 3])
Try to prove s ++ [] = s.
[Hint: Define P as fun s => s ++ [] = s.]