Chaining definitions in coq - coq

I'm following trough the software foundations books for working with Coq. I'm currently at the Tactics chapter and I'm stuck on the forall_exists_challenge.
I would like to negate the test predicate using negb but I receive the error The term "test" has type "X -> bool" while it is expected to have type "bool".
Fixpoint forallb {X : Type} (test : X -> bool) (l : list X) : bool :=
match l with
| [] => true
| h :: t => test h && forallb test t
end.
Example test_forallb_1 : forallb oddb [1;3;5;7;9] = true.
Proof. simpl. reflexivity. Qed.
Example test_forallb_2 : forallb negb [false;false] = true.
Proof. simpl. reflexivity. Qed.
Example test_forallb_3 : forallb evenb [0;2;4;5] = false.
Proof. simpl. reflexivity. Qed.
Example test_forallb_4 : forallb (eqb 5) [] = true.
Proof. simpl. reflexivity. Qed.
Fixpoint existsb {X : Type} (test : X -> bool) (l : list X) : bool :=
match l with
| [] => false
| h :: t => test h || forallb test t
end.
Example test_existsb_1 : existsb (eqb 5) [0;2;3;6] = false.
Proof. simpl. reflexivity. Qed.
Example test_existsb_2 : existsb (andb true) [true;true;false] = true.
Proof. simpl. reflexivity. Qed.
Example test_existsb_3 : existsb oddb [1;0;0;0;0;3] = true.
Proof. simpl. reflexivity. Qed.
Example test_existsb_4 : existsb evenb [] = false.
Proof. simpl. reflexivity. Qed.
Definition existsb' {X : Type} (test : X -> bool) (l : list X) : bool :=
negb (forallb (negb test) l).
Example test_existsb_1' : existsb' (eqb 5) [0;2;3;6] = false.
Proof. simpl. reflexivity. Qed.
Theorem existsb_existsb' : forall (X : Type) (test : X -> bool) (l : list X),
existsb test l = existsb' test l.
Proof. (* FILL IN HERE *) Admitted.
I expect I could be able to negate a predicate in some way but I can't seem to quite figure out how.

As the error message says, negb expects a single boolean, rather than a whole predicate. The simplest way to make a new predicate using negb would be something like fun x => negb (test x). Note that now (test x) actually does have type bool so it can be fed to negb.
Alternatively, you could make a notation for function composition (I don't think such a notation exists in the standard library, though I don't know about Software Foundations). For example, Notation "f 'o' g" := (fun x => f (g x)) (at level 20). (you might need to change the level to avoid conflicts with existing notations). Then you'd be able to do negb o test.
A third solution, if you expect to be negating predicates a lot and don't want to go as far as a function composition notation, would be to make a new function that negates a boolean predicate instead of negating a boolean. For example, Definition neg_pred {X: Type} (pred: X -> bool): X -> bool := fun x => negb (pred x).. Then you can simply use neg_pred test.

Related

Coq's proof #Coq

I try to solve this proof but I don't find how to it.
I have two subgoals but I don't even know if it's correct.
Here the lemma that I trid to solve with this but I'm stuck :
2 subgoals
a, b : Nat
H : Equal (leB a b) True
______________________________________(1/2)
Equal match b with
| Z => False
| S m' => leB a m'
end (leB a b) / Equal (leB b (S a)) (leB a b)
______________________________________(2/2)
Equal (leB (S a) b) True / Equal (leB b (S a)) True
Inductive Bool : Type :=
True : Bool | False : Bool.
Definition Not(b : Bool) : Bool :=
Bool_rect (fun a => Bool)
False
True
b.
Lemma classic : forall b : Bool, Equal b (Not (Not b)).
Proof.
intro.
induction b.
simpl.
apply refl.
simpl.
apply refl.
Qed.
Definition Equal(T : Type)(x y : T) : Prop :=
forall P : T -> Prop, (P x) -> (P y).
Arguments Equal[T].
(* Avec certaines versions Arguments Equal[T] *)
Lemma refl : forall T : Type, forall x : T, Equal x x.
Proof.
intros.
unfold Equal.
intros.
assumption.
Qed.
Fixpoint leB n m : Bool :=
match n, m with
| Z, _ => True
| _, Z => False
| S n', S m' => leB n' m'
end.
First, don't introduce all variables in the beginning with intros. You will get a too weak induction hypothesis. Just introduce a.
Then in each branch, consider the different cases of b with the destruct tactic. It will simplify your goal and you can see if it is the left or the right side of goal that is true, and use your refl lemma to finish the goal.
The last case require that you use your induction hypothesis, and it is here that it is important that it holds for all b, not just one specific b.
Also, you didn't provide a definition for you Nat type, I guess it is something like this:
Inductive Nat := Z | S (n:Nat).
Here is a proof.
Lemma Linear : forall a b, (Equal (leB a b) True) \/ (Equal (leB b a) True).
Proof.
induction a.
- intros b. destruct b; simpl.
+ left. apply refl.
+ left. apply refl.
- intros b. destruct b; simpl.
+ right. apply refl.
+ destruct (IHa b) as [Hleft | Hright].
++ left. apply Hleft.
++ right. apply Hright.
Qed.
While it may not be as insightful, you can also use tactics that try these steps to get a shorter proof.
induction a; destruct b; firstorder.
will also prove your lemma.

Theorem that finding in a list works properly

I am proving theorem about finding in a list. I got stuck at proving that if you actually found something then it is true. What kind of lemmas or strategy may help for proving such kind of theorems? I mean it looks like induction on the list is not enough in this case. But still the theorem is surely true.
(*FIND P = OPTION_MAP (SND :num # α -> α ) ∘ INDEX_FIND (0 :num) P*)
Require Import List.
Require Import Nat.
Fixpoint INDEX_FIND {a:Type} (i:nat) (P:a->bool) (l:list a) :=
match l with
| nil => None
| (h::t) => if P h then Some (i,h) else INDEX_FIND (S i) P t
end.
Definition FIND {a:Type} (P:a->bool) (l:list a)
:= (option_map snd) (INDEX_FIND 0 P l).
Theorem find_prop {a:Type} P l (x:a):
(FIND P l) = Some x
->
(P x)=true.
Proof.
unfold FIND.
unfold option_map.
induction l.
+ simpl.
intro H. inversion H.
+ simpl.
destruct (P a0).
- admit.
- admit.
Admitted.
(this is a translation of definition from HOL4 which also lacks such kind of theorem)
HOL version of the theorem:
Theorem find_prop:
FIND (P:α->bool) (l:α list) = SOME x ⇒ P x
Proof
cheat
QED
It looks like what you are missing is an equation relating P a0 and its destructed value. This can be obtained with the variant of destruct documented there destruct (P a0) eqn:H.
You may want to try to strengthen the property before proving your theorem. Using the SSReflect proof language, you can try the following route.
Lemma index_find_prop {a:Type} P (x:a) l :
forall i j, (INDEX_FIND i P l) = Some (j, x) -> P x = true.
Proof.
elim: l => [//=|x' l' IH i j].
rewrite /INDEX_FIND.
case Px': (P x').
- by case=> _ <-.
- exact: IH.
Qed.
Lemma opt_snd_inv A B X x :
option_map (#snd A B) X = Some x -> exists j, X = Some (j, x).
Proof.
case: X => ab; last by [].
rewrite (surjective_pairing ab) /=.
case=> <-.
by exists ab.1.
Qed.
Theorem find_prop {a:Type} P l (x:a):
(FIND P l) = Some x -> (P x)=true.
Proof.
rewrite /FIND => /(#opt_snd_inv _ _ (INDEX_FIND 0 P l) x) [j].
exact: index_find_prop.
Qed.
I'm confident there are shorter proofs ;)

How to prove that the subsequence of an empty list is empty?

I'm new in coq. i am trying to prove that the subsequence of an empty list is empty
This is the lemma i'm working on:
Lemma sub_nil : forall l , subseq l nil <-> l=nil.
i tried to split so i can have
subseq l nil -> l = nil
and
l = nil -> subseq l nil
to prove the first one i tried an induction on l but i blocked when it comes to prove that
subseq (a :: l) nil -> a :: l = nil
thanks.
The tactic to use here is inversion. Paraphrasing the coq documentation for inversion! :
Given an inductive hypothesis (H:I t), then inversion applied to H derives for each possible constructor c i of (I t), all the necessary conditions that should hold for the instance (I t) to be proved by c i.
Assuming the subseq predicate is given as follows:
Inductive subseq {A:Type} : list A -> list A -> Prop :=
| SubNil : forall (l:list A), subseq nil l
| SubCons1 : forall (s l:list A) (x:A), subseq s l -> subseq s (x::l)
| SubCons2 : forall (s l: list A) (x:A), subseq s l -> subseq (x::s) (x::l).
The proof would be stuck here(exactly at the place you specified):
Lemma sub_nil2 : forall (A:Type) (l: list A) , subseq l nil <-> l=nil.
Proof.
split.
- destruct l eqn:E; intros.
* reflexivity.
(*Now unable to prove a::l0 = [] because the hypothesis: subseq (a :: l0) [] is absurd.*)
* inversion H.(*Coq reasons that this hypothesis is not possible and discharges the proof trivially*)
- intros. subst. apply SubNil.
Qed.
Note that I used the destruct tactic but the issue remains even with induction tactic.
The entire proof can be written cleanly as below:
Lemma sub_nil : forall (A:Type) (l: list A) , subseq l nil <-> l=nil.
Proof.
split; intros.
- inversion H. reflexivity.
- subst. apply SubNil.
Qed.

Coq: Why rewrite of lemma in theorem create two subgoal?

I'm trying to proof that my function nonzeros' distribute over concat of list.
I wrote nonzeros' with a filter in this way:
Definition nonzeros' (l : list nat) : list nat := filter (fun x => match x with | O => false | _ => true end) l.
I've already proofed this 2 lemmas:
Lemma nonzeros'_remove_0 :
forall (a b: list nat),
nonzeros' (0 :: b) = nonzeros' b.
Proof.
intros a b.
unfold nonzeros'.
simpl.
reflexivity.
Qed.
Lemma nonzeros'_not_remove_Sn :
forall (a b: list nat) (n : nat),
nonzeros' (S n :: b) = S n :: nonzeros' b.
Proof.
intros a b n.
unfold nonzeros'.
simpl.
reflexivity.
Qed.
Now I have to proof the distribution over concat:
Lemma nonzero'_distribution_over_concat :
forall (a b : list nat),
nonzeros' (concat a b) = concat (nonzeros' a) (nonzeros' b).
In order to proof it I do the following:
Proof.
intros a b.
induction a as [| h t IHa].
-
simpl.
reflexivity.
-
simpl.
destruct h.
+ rewrite nonzeros'_remove_0. rewrite nonzeros'_remove_0. rewrite IHa. reflexivity.
The problem is that after the tactics
rewrite nonzeros'_remove_0.
Coq create 2 subgoal:
______________________________________(1/2)
nonzeros' (concat t b) = concat (nonzeros' (0 :: t)) (nonzeros' b)
______________________________________(2/2)
list nat
The second subgoal is unexpected. Why does it appear?
The lemma has an unused parameter a : list nat:
Lemma nonzeros'_remove_0 :
forall (a b: list nat),
nonzeros' (0 :: b) = nonzeros' b.
so to apply that lemma you need to provide such a list, and there is no way to tell which list it should be, other than by asking you via an extra goal. One could also develop automation to make an arbitrary choice here, but a better fix is to remove that unused parameter from the lemma in the first place.
Lemma nonzeros'_remove_0 :
forall (b: list nat),
nonzeros' (0 :: b) = nonzeros' b.

Folding back after unfolding

I have fold_length defined like this:
Inductive list (X: Type) : Type :=
| nil : list X
| cons : X -> list X -> list X.
Arguments nil {X}.
Arguments cons {X} _ _.
Notation "x :: y" := (cons x y)
(at level 60, right associativity).
Notation "[ ]" := nil.
Fixpoint fold {X Y:Type} (f: X -> Y -> Y) (l:list X) (b:Y) : Y :=
match l with
| nil => b
| h :: t => f h (fold f t b)
end.
Definition fold_length {X : Type} (l : list X) : nat :=
fold (fun _ n => S n) l 0.
I have to prove a theorem and this is my code so far:
Theorem fold_length_correct : forall X (l : list X),
fold_length l = length l.
Proof.
intros X l.
induction l as [| n l' IHl'].
- simpl.
unfold fold_length.
simpl.
reflexivity.
- simpl.
unfold fold_length.
simpl.
Right now, my goal looks like this:
X : Type
n : X
l' : list X
IHl' : fold_length l' = length l'
============================
S (fold (fun (_ : X) (n0 : nat) => S n0) l' 0) = S (length l')
Now I want to convert the expression (fold (fun (_ : X) (n0 : nat) => S n0) l' 0) to fold_length l' using the definition of fold_length. Is there a way to do that in Coq (There seems to something named fold tactic in Coq. Can that achieve this.) ?
Also, is there a way to prove the above theorem without the usage of unfold and fold tactic ?
To answer your first question, yes, the fold tactic can be used here to replace the left side of the equality with S (fold_length l'). Usually, for a function f, fold f is not powerful enough to detect what it can fold. But if you specify the whole term, like here fold (fold_length l'), it works.
Regarding your second question, note that tactics like reflexivity or assumption can conclude if the terms involved are equal up to some simplifications. Here, the base case of the induction can be just reflexivity. For the second case, assuming that fold is List.fold_right, simpl can surprisingly simplify without unfolding and you should not need unfold or fold here either.