Library lec2
bounded search from primitive recursion
Fixpoint search (n: nat) (f : nat → bool) : option nat :=
match n with
| O ⇒ None
| S n' ⇒ if (f n')
then Some n'
else search n' f
end.
Lemma searchSome : ∀ (f : nat → bool) (n m: nat) ,
search n f = Some m → f m = true ∧ m < n .
match n with
| O ⇒ None
| S n' ⇒ if (f n')
then Some n'
else search n' f
end.
Lemma searchSome : ∀ (f : nat → bool) (n m: nat) ,
search n f = Some m → f m = true ∧ m < n .
induction is a key reasoning technique in Coq.
Proof.
induction n.
- intros ? Heq. simpl in Heq. inversion Heq.
- intros ? Heq. simpl in Heq.
remember (f n) as fn.
destruct fn.
+ inversion Heq. clear Heq.
subst. auto.
+ apply IHn in Heq. split; try tauto.
omega.
Qed.
Lemma searchNone : ∀ (n: nat) (f : nat → bool),
search n f = None → ∀ m, m < n→ f m = false.
Proof.
induction n; intros ? Heq; simpl in Heq.
- intros. omega.
- remember (f n) as fn.
destruct fn.
+ inversion Heq.
+ intros ? Hlt.
assert (m = n ∨ m < n) as Hd by omega.
destruct Hd.
× subst. auto.
× auto.
Qed.
Lemma searchMax : ∀ (f : nat → bool) (b m c: nat) ,
f c = true
→ c < b
→ search b f = Some m
→ c ≤ m.
Proof.
induction b; intros ? ? Heq Hlt Hs; simpl in Hs.
- inversion Hlt.
- remember (f b) as fn.
destruct fn.
+ inversion Hs. clear Hs.
subst. omega.
+ apply IHb; auto.
assert (c = b ∨ c < b) as Hd by omega.
destruct Hd; try congruence.
Qed.
SearchPattern (nat→ nat → bool).
Check (beq_nat).
SearchAbout (beq_nat).
Definition isSqr (n: nat) : bool :=
match (search n (λ m, beq_nat (m×m) n)) with
| Some sqrt ⇒ true
| None ⇒ false
end.
Definition double (n:nat) : nat := n+n.
induction n.
- intros ? Heq. simpl in Heq. inversion Heq.
- intros ? Heq. simpl in Heq.
remember (f n) as fn.
destruct fn.
+ inversion Heq. clear Heq.
subst. auto.
+ apply IHn in Heq. split; try tauto.
omega.
Qed.
Lemma searchNone : ∀ (n: nat) (f : nat → bool),
search n f = None → ∀ m, m < n→ f m = false.
Proof.
induction n; intros ? Heq; simpl in Heq.
- intros. omega.
- remember (f n) as fn.
destruct fn.
+ inversion Heq.
+ intros ? Hlt.
assert (m = n ∨ m < n) as Hd by omega.
destruct Hd.
× subst. auto.
× auto.
Qed.
Lemma searchMax : ∀ (f : nat → bool) (b m c: nat) ,
f c = true
→ c < b
→ search b f = Some m
→ c ≤ m.
Proof.
induction b; intros ? ? Heq Hlt Hs; simpl in Hs.
- inversion Hlt.
- remember (f b) as fn.
destruct fn.
+ inversion Hs. clear Hs.
subst. omega.
+ apply IHb; auto.
assert (c = b ∨ c < b) as Hd by omega.
destruct Hd; try congruence.
Qed.
SearchPattern (nat→ nat → bool).
Check (beq_nat).
SearchAbout (beq_nat).
Definition isSqr (n: nat) : bool :=
match (search n (λ m, beq_nat (m×m) n)) with
| Some sqrt ⇒ true
| None ⇒ false
end.
Definition double (n:nat) : nat := n+n.
generalize.
the example below is based on
https://www.cs.purdue.edu/homes/suresh/565-Spring2013/sf/full/Gen.html
when we say induction, Coq just invokes the following lemma
- too weak induction hypothesis is perhaps the most common cause in getting stuck in an inductive proof.
- Already saw this in PS1, problem 2 (proof by structural induction)
note that it automatically infers the property P
Theorem double_injective_FAILED : ∀n m,
double n = double m
→ n = m.
Proof.
intros n m.
Check nat_ind.
induction n as [| n'].
- simpl. intros eq. destruct m as [| m'].
+ reflexivity.
+ inversion eq.
- intros eq. destruct m as [| m'].
+ inversion eq.
+ unfold double in eq. simpl in eq. f_equal.
inversion eq. clear eq.
SearchRewrite (_+ S _).
rewrite <- plus_n_Sm in H0.
rewrite <- plus_n_Sm in H0.
inversion H0. clear H0.
fold (double n') in H1.
fold (double m') in H1.
Here we are stuck. The induction hypothesis is about
a specific m. Before invoking induction, we should have
generalized it. We will do that below
Abort.
Theorem double_injective : ∀n m,
double n = double m
→ n = m.
Proof.
intros n.
induction n as [| n'].
- simpl. intros ? eq. destruct m as [| m'].
+ reflexivity.
+ inversion eq.
- intros ? eq. destruct m as [| m'].
+ inversion eq.
+ unfold double in eq. simpl in eq. f_equal.
inversion eq. clear eq.
SearchRewrite (_+ S _).
rewrite <- plus_n_Sm in H0.
rewrite <- plus_n_Sm in H0.
inversion H0. clear H0.
fold (double n') in H1.
fold (double m') in H1.
Theorem double_injective : ∀n m,
double n = double m
→ n = m.
Proof.
intros n.
induction n as [| n'].
- simpl. intros ? eq. destruct m as [| m'].
+ reflexivity.
+ inversion eq.
- intros ? eq. destruct m as [| m'].
+ inversion eq.
+ unfold double in eq. simpl in eq. f_equal.
inversion eq. clear eq.
SearchRewrite (_+ S _).
rewrite <- plus_n_Sm in H0.
rewrite <- plus_n_Sm in H0.
inversion H0. clear H0.
fold (double n') in H1.
fold (double m') in H1.
Here we are NOT stuck. The induction hypothesis IHn is NOT about
a specific m, but all possible values of m.
apply IHn' in H1. assumption.
Qed.
Qed.
take the model solution of PS2 problem 1 and start proving
the correctness of that isSqr function by induction.
Chances are, in your first attempt
you will end up with a too weak induction hypothesis.
By definining a more general function search above, we
were essentially saved from accidentally getting distracted by unnecessary details
and choosing a less general
property to prove by induction.
Also, the function search can be used to define many more functions,
e.g. like cube root, primality test, etc.
The correctness of search has been proved once and forall for
all possible instantiations of the argument f of search.
This is called parametric polymorphism.
Moral of the story: It often pays off
to make your proofs and definitions more general than your
current goal.