(*

* How to halve a number

* ---------------------

*)

(* (* just so we start on the same page, what is a number? *)

*

* Inductive nat : Set :=

* | O : nat

* | S : nat -> nat.

*)

Module Type Halver.

Parameter half : nat -> nat.

Axiom e1 : half 0 = 0.

Axiom e2 : half 1 = 0.

Axiom e3 : forall n, half (S (S n)) = S (half n).

(* An equational specification is given as a module

* so now it is possible it give various implementations

*)

End Halver.

Module By_Default : Halver.

Fixpoint half (n : nat) : nat :=

match n with

| O => O

| S O => O

| S (S n) => S (half n)

end.

Definition e1 : half 0 = 0 := refl_equal _.

Definition e2 : half 1 = 0 := refl_equal _.

Definition e3 n : half (S (S n)) = S (half n) := refl_equal _.

(* This is the sort of thing one would normally start with,

* pattern match on a term and use recursive calls on a

* structurally smaller term, the idea of 'structurally smaller'

* is part of the type rules actually and it is the transitive

* closure of (1) p_i < C p_1 p_2 ... p_n

* and (2) f x < f

* rule (1) and (2) say that a term in smaller than any

* construction built from it, a construction being something

* literally built from constructor or a function

*)

End By_Default.

Module By_Divine_Inspiration : Halver.

(* Definition half n :=

* fst (nat_rect (fun _ => (nat * nat)%type)

* (O, O)

* (fun n Pn => let (p,q) := Pn in (q, S p))

* n).

* (* it seems impossible to prove this one correct *)

*)

Definition half n :=

fst (nat_rect (fun _ => (nat * nat)%type)

(O, O)

(fun n Pn => (snd Pn, S (fst Pn)))

n).

Definition e1 : half 0 = 0 := refl_equal _.

Definition e2 : half 1 = 0 := refl_equal _.

Definition e3 n : half (S (S n)) = S (half n) := refl_equal _.

End By_Divine_Inspiration.

Module By_Devising_Data : Halver.

(* This way seems like a 'view' in the sense of Wadler,

* The structure of the data make the program definition

* straight-forward.

*)

Inductive nat' : Set :=

| Zero : nat'

| One : nat'

| SuccSucc : nat' -> nat'.

Definition zero := Zero.

Fixpoint succ (n : nat') :=

match n with

| Zero => One

| One => SuccSucc Zero

| SuccSucc n => SuccSucc (succ n)

end.

Fixpoint nat_to_nat' (n : nat) : nat' :=

match n with

| O => zero

| S n => succ (nat_to_nat' n)

end.

Fixpoint half' (n : nat') : nat :=

match n with

| Zero => O

| One => O

| SuccSucc n => S (half' n)

end.

Definition half n := half' (nat_to_nat' n).

Definition e1 : half 0 = 0 := refl_equal _.

Definition e2 : half 1 = 0 := refl_equal _.

Lemma succ_succs n : succ (succ n) = SuccSucc n.

induction n; simpl; try reflexivity.

rewrite IHn; reflexivity.

Qed.

Theorem e3 n : half (S (S n)) = S (half n).

intro n.

unfold half.

simpl.

rewrite succ_succs.

reflexivity.

Qed.

End By_Devising_Data.

Module By_Mutual_Induction : Halver.

Inductive Even : nat -> Set :=

| EvenO : Even O

| EvenS n : Odd n -> Even (S n)

with Odd : nat -> Set :=

| OddS n : Even n -> Odd (S n).

Fixpoint even_or_odd n : Even n + Odd n :=

match n as n return Even n + Odd n with

| O => inl _ EvenO

| S n =>

match even_or_odd n with

| inl even => inr _ (OddS _ even)

| inr odd => inl _ (EvenS _ odd)

end

end.

Fixpoint halfE n (e : Even n) : nat :=

match e with

| EvenO => O

| EvenS n odd => S (halfO n odd)

end

with halfO n (o : Odd n) : nat :=

match o with

| OddS n even => halfE n even

end.

Definition half (n : nat) : nat :=

match even_or_odd n with

| inl even => halfE n even

| inr odd => halfO n odd

end.

(* Proving this program correct is quite a lot

* of work compared to the previous implementations,

* these tricky inversion lemmas which would be trivial

* to prove using pattern matching at least show some

* techniques.

*)

Lemma unique_lemma_1 (e : Even 0) : e = EvenO.

intro e.

refine (

match e as e' in Even Zero return

match Zero return Even Zero -> Prop with

| O => fun e'' : Even 0 => e'' = EvenO

| S _ => fun _ => True

end e'

with

| EvenO => refl_equal _

| EvenS _ _ => I

end

).

Qed.

Lemma unique_lemma_2 n (e : Even (S n)) : { o' : _ | e = EvenS n o' }.

intros n e.

refine (

match e as e' in Even SuccN return

match SuccN return Even SuccN -> Set with

| O => fun _ => True

| S n => fun e' : Even (S n) =>

{ o' : _ | e' = EvenS n o' }

end e'

with

| EvenO => I

| EvenS n' o' => exist _ o' (refl_equal _)

end

).

Qed.

Lemma unique_lemma_3 n (o : Odd (S n)) : { e' : _ | o = OddS n e' }.

intros n o.

refine (

match o as o' in Odd SuccN return

match SuccN return Odd SuccN -> Set with

| O => fun _ => True

| S n => fun o' : Odd (S n) =>

{ e' : _ | o' = OddS n e' }

end o'

with

| OddS n' e' => exist _ e' (refl_equal _)

end

).

Qed.

(* There is only one way to prove a number is Even

* and similarly to prove it's Odd

*)

Theorem unique_classificationE n (e e' : Even n) : e = e'

with unique_classificationO n (o o' : Odd n) : o = o'.

induction n; intros.

rewrite unique_lemma_1 with e.

rewrite unique_lemma_1 with e'.

reflexivity.

destruct (unique_lemma_2 _ e) as [o eq].

destruct (unique_lemma_2 _ e') as [o' eq'].

rewrite eq; rewrite eq'.

rewrite (unique_classificationO n o o').

reflexivity.

destruct n.

intro H; inversion H.

intros.

destruct (unique_lemma_3 _ o) as [e eq].

destruct (unique_lemma_3 _ o') as [e' eq'].

rewrite eq; rewrite eq'.

rewrite (unique_classificationE n e e').

reflexivity.

Qed.

Lemma halfE_SS n e e' : halfE (S (S n)) e' = S (halfE n e)

with halfO_SS n o o' : halfO (S (S n)) o' = S (halfO n o).

intros.

destruct (unique_lemma_2 _ e') as [o eq].

destruct (unique_lemma_3 _ o) as [e'' eq'].

subst.

simpl.

assert (e = e'') as E by apply unique_classificationE.

rewrite E; reflexivity.

intros.

destruct (unique_lemma_3 _ o') as [e eq].

destruct (unique_lemma_2 _ e) as [o'' eq'].

subst.

simpl.

assert (o = o'') as O by apply unique_classificationO.

rewrite O; reflexivity.

Qed.

Definition which P Q : P + Q -> bool :=

fun choice =>

match choice with

| inl _ => true

| inr _ => false

end.

Lemma even_or_odd_SS n : which _ _ (even_or_odd (S (S n))) = which _ _ (even_or_odd n).

induction n.

reflexivity.

simpl in *.

destruct (even_or_odd n).

reflexivity.

reflexivity.

Qed.

Definition e1 : half 0 = 0 := refl_equal _.

Definition e2 : half 1 = 0 := refl_equal _.

Theorem e3 n : half (S (S n)) = S (half n).

intro n.

unfold half.

generalize (even_or_odd_SS n).

destruct (even_or_odd n); destruct (even_or_odd (S (S n)));

simpl; intro hyp; try discriminate hyp.

apply halfE_SS.

apply halfO_SS.

Qed.

End By_Mutual_Induction.

Module By_Well_Founded_Induction : Halver.

Section Well_Founded_Relations.

Variable A : Type.

Variable R : A -> A -> Prop.

Inductive Acc (x : A) : Prop :=

| below : (forall y : A, R y x -> Acc y) -> Acc x.

(* x must be a parameter (instead of Acc : A -> Prop) for

* Set/Type elimination, but why?

*)

Definition Well_Founded := forall x : A, Acc x.

Inductive Transitive_Closure : A -> A -> Prop :=

| step x y : R x y -> Transitive_Closure x y

| transitivity x y z : R x y -> Transitive_Closure y z -> Transitive_Closure x z.

Definition Well_Founded_Induction

(W : Well_Founded)

(P : A -> Type)

(rec : forall x, (forall y, R y x -> P y) -> P x)

: forall a, P a :=

fun a => Acc_rect P (fun x _ hyp => rec x hyp) a (W a).

End Well_Founded_Relations.

Section Transitive_Relation.

Variable A : Type.

Variable R : A -> A -> Prop.

Theorem Transitive_Closure_Well_Founded :

Well_Founded A R -> Well_Founded A (Transitive_Closure A R).

Proof.

unfold Well_Founded; intros R_Acc x.

induction (R_Acc x) as [x R_ind T_ind].

apply below; intros y Trans.

induction Trans.

apply T_ind; assumption.

pose (IHTrans R_ind T_ind) as IH; inversion IH as [H']; subst.

apply H'.

apply step.

assumption.

Defined.

End Transitive_Relation.

Section Nat_Structural_Measure.

(* Looking at the definition of nat: *)

(*

* Inductive nat : Set :=

* | O : nat

* | S : nat -> nat.

*)

(* shows there is one (simple) recursive field *)

Inductive nat_step : nat -> nat -> Prop :=

| nat_step_a : forall x, nat_step x (S x).

(* the nat_step relation expresses this recursion

* every inductive type admits a step relation

* (indexed inductives define indexed relations,

* but maybe wrappig them in sigT would be better?)

*)

Theorem nat_step_Well_Founded : Well_Founded nat nat_step.

unfold Well_Founded.

induction x;

apply below; intros y Ry.

inversion Ry.

inversion Ry.

subst.

assumption.

Defined.

(* Could one generically define all Φ_step relations,

* and give a generic proof that they are all Well_Founded?

*)

(* The transitive closure of the step relation corresponds to

* the usual idea of lt/(<) on nat:

*)

Definition nat_struct := Transitive_Closure nat nat_step.

Definition nat_struct_Well_Founded :=

Transitive_Closure_Well_Founded nat nat_step nat_step_Well_Founded.

(* In general terms it is a typed version of the 'structurally smaller'

* relation in the metatheory which lets definitions like the one in

* By_Default be accepted

*)

End Nat_Structural_Measure.

(* Now the equations we want to satisy are: *)

(*

* half O := O

* half (S O) := O

* half (S (S n)) := S (half n)

*)

(* so in terms of (toned down) eliminators that is:

*

* half n := nat_case n

* O

* (fun n' Pn' =>

* nat_case n'

* O

* (fun n'' Pn'' =>

* S (half n''))).

*

* clearly that definition is not acceptable with

* no termination argument what-so-ever! so to

* rectify that, we can let P express that this

* number is smaller than n, and use well founded

* induction on the size measure.

*)

Lemma SSsmaller m : nat_struct m (S (S m)).

intro m.

apply transitivity with (S m).

constructor.

apply step.

constructor.

Defined.

Definition half := Well_Founded_Induction nat nat_struct nat_struct_Well_Founded

(fun _ => nat)

(nat_rec (fun x => (forall y : nat, nat_struct y x -> nat) -> nat)

(fun rec => O)

(fun n Pn rec =>

nat_rec (fun x => (forall y : nat, nat_struct y (S x) -> nat) -> nat)

(fun rec => O)

(fun m Pm rec => S (rec m (SSsmaller m)))

n

rec)).

(*

* The definition may look a bit complicated but I think this could

* be computed automatically from the equational specification,

* the method seems like a good way to compile dependent pattern matching

* into a basic type theory though, so that we don't have to use something

* like a 'match' construct.

*)

Definition e1 : half 0 = 0 := refl_equal _.

Definition e2 : half 1 = 0 := refl_equal _.

Definition e3 n : half (S (S n)) = S (half n) := refl_equal _.

(*

* It's not luck (at least I think it's not, and I really hope so)

* that the recursive equality is provable by reflexivity, but it

* does require the SSsmaller proof term to be canonical (made up

* of constructors), since every proof that a term is structurally

* smaller than another can be a canonical proof that poses no

* problem. I don't yet know how it will interact with dependent

* pattern match specialization though. (I can't think of any

* functions over inductive families that aren't 'step' recursive

* though, does anyone know of some examples?)

*)

End By_Well_Founded_Induction.

## Sunday, 1 March 2009

### How to halve a number

Subscribe to:
Post Comments (Atom)

## 2 comments:

holy jesus wtf

You sir are a genius. I just would not ask you to help split a bill.

Post a Comment