(** * MoreDep
Porting a chapter of Adam Chlipala's Certified Programming with Dependent Types,
#More Dependent Types#. *)
From Stdlib Require Import Bool Arith List Program.
From Equations.Prop Require Import Equations.
Set Equations Transparent.
Set Keyed Unification.
Set Implicit Arguments.
Section ilist.
Variable A : Set.
Inductive ilist : nat -> Set :=
| Nil : ilist O
| Cons : forall n, A -> ilist n -> ilist (S n).
Derive Signature for ilist.
Arguments Cons {n}.
Equations app n1 (ls1 : ilist n1) n2 (ls2 : ilist n2) : ilist (n1 + n2) :=
app Nil ls2 := ls2;
app (Cons x ls1) ls2 := Cons x (app ls1 ls2).
Equations inject (ls : list A) : ilist (length ls) :=
inject nil := Nil;
inject (cons h t) := Cons h (inject t).
Equations unject n (ls : ilist n) : list A :=
unject Nil := nil;
unject (Cons x ls) := cons x (unject ls).
Theorem unject_inverse : forall ls, unject (inject ls) = ls.
Proof.
intros. funelim (inject ls); simp unject; congruence.
Qed.
Equations hd n (ls : ilist (S n)) : A :=
hd (Cons x _) := x.
End ilist.
Inductive type : Set :=
| Nat : type
| Bool : type
| Prod : type -> type -> type.
Derive NoConfusion EqDec for type.
Inductive exp : type -> Set :=
| NConst : nat -> exp Nat
| Plus : exp Nat -> exp Nat -> exp Nat
| Eq : exp Nat -> exp Nat -> exp Bool
| BConst : bool -> exp Bool
| And : exp Bool -> exp Bool -> exp Bool
| If : forall t, exp Bool -> exp t -> exp t -> exp t
| Pair : forall t1 t2, exp t1 -> exp t2 -> exp (Prod t1 t2)
| Fst : forall t1 t2, exp (Prod t1 t2) -> exp t1
| Snd : forall t1 t2, exp (Prod t1 t2) -> exp t2.
Derive Signature NoConfusion for exp.
Derive NoConfusionHom for exp.
Derive Subterm for exp.
Equations typeDenote (t : type) : Set :=
typeDenote Nat := nat;
typeDenote Bool := bool;
typeDenote (Prod t1 t2) := (typeDenote t1 * typeDenote t2)%type.
Equations expDenote t (e : exp t) : typeDenote t :=
expDenote (NConst n) := n;
expDenote (Plus e1 e2) := expDenote e1 + expDenote e2;
expDenote (Eq e1 e2) := Nat.eqb (expDenote e1) (expDenote e2);
expDenote (BConst b) := b;
expDenote (And e1 e2) := expDenote e1 && expDenote e2;
expDenote (If e e1 e2) with expDenote e => {
| true := expDenote e1;
| false := expDenote e2
};
expDenote (Pair e1 e2) := (expDenote e1, expDenote e2);
expDenote (Fst e) := fst (expDenote e);
expDenote (Snd e) := snd (expDenote e).
Equations pairOutType2 (t : type) : Set :=
pairOutType2 (Prod t1 t2) := option (exp t1 * exp t2);
pairOutType2 _ := option unit.
Equations pairOutTypeDef (t : type) : Set :=
pairOutTypeDef (Prod t1 t2) := exp t1 * exp t2;
pairOutTypeDef _ := unit.
Transparent pairOutTypeDef.
Definition pairOutType' (t : type) := option (match t with
| Prod t1 t2 => exp t1 * exp t2
| _ => unit
end).
Equations pairOut t (e : exp t) : option (pairOutTypeDef t) :=
pairOut (Pair e1 e2) => Some (e1, e2);
pairOut _ => None.
Set Printing Depth 1000000.
From Stdlib Require Import Wellfounded.
Equations cfold {t} (e : exp t) : exp t :=
(* Works with well-foundedness too: cfold e by wf (signature_pack e) exp_subterm := *)
cfold (NConst n) => NConst n;
cfold (Plus e1 e2) with (cfold e1, cfold e2) => {
| pair (NConst n1) (NConst n2) := NConst (n1 + n2);
| pair e1' e2' := Plus e1' e2'
};
cfold (Eq e1 e2) with (cfold e1, cfold e2) => {
| pair (NConst n1) (NConst n2) := BConst (Nat.eqb n1 n2);
| pair e1' e2' => Eq e1' e2'
};
cfold (BConst b) := BConst b;
cfold (And e1 e2) with (cfold e1, cfold e2) => {
| pair (BConst b1) (BConst b2) := BConst (b1 && b2);
| pair e1' e2' := And e1' e2'
};
cfold (If e e1 e2) with cfold e => {
| BConst true => cfold e1;
| BConst false => cfold e2;
| _ => If e (cfold e1) (cfold e2) }
;
cfold (Pair e1 e2) := Pair (cfold e1) (cfold e2);
cfold (Fst e) with cfold e => {
| e' with pairOut e' => {
| Some p := fst p;
| None := Fst e'
}
};
cfold (Snd e) with cfold e => {
| e' with pairOut e' => {
| Some p := snd p;
| None := Snd e'
}
}.
Inductive color : Set := Red | Black.
Derive NoConfusion for color.
Inductive rbtree : color -> nat -> Set :=
| Leaf : rbtree Black 0
| RedNode : forall n, rbtree Black n -> nat -> rbtree Black n -> rbtree Red n
| BlackNode : forall c1 c2 n, rbtree c1 n -> nat -> rbtree c2 n -> rbtree Black (S n).
Derive Signature NoConfusion for rbtree.
From Stdlib Require Import Arith Lia.
Section depth.
Variable f : nat -> nat -> nat.
Equations depth {c n} (t : rbtree c n) : nat :=
depth Leaf := 0;
depth (RedNode t1 _ t2) := S (f (depth t1) (depth t2));
depth (BlackNode t1 _ t2) := S (f (depth t1) (depth t2)).
End depth.
Theorem depth_min : forall c n (t : rbtree c n), depth min t >= n.
Proof.
intros. funelim (depth Nat.min t); cbn;
auto;
match goal with
| [ |- context[min ?X ?Y] ] =>
let H := fresh in destruct (Nat.min_dec X Y) as [H|H]; rewrite H
end; lia.
Qed.
Lemma depth_max' : forall c n (t : rbtree c n), match c with
| Red => depth max t <= 2 * n + 1
| Black => depth max t <= 2 * n
end.
Proof.
intros; funelim (depth Nat.max t); cbn; auto;
match goal with
| [ |- context[max ?X ?Y] ] =>
let H := fresh in destruct (Nat.max_dec X Y) as [H|H]; rewrite H
end;
repeat match goal with
| [ H : context[match ?C with Red => _ | Black => _ end] |- _ ] =>
destruct C
end; lia.
Qed.
Theorem depth_max : forall c n (t : rbtree c n), depth max t <= 2 * n + 1.
Proof.
intros; generalize (depth_max' t); destruct c; lia.
Qed.
Theorem balanced : forall c n (t : rbtree c n), 2 * depth min t + 1 >= depth max t.
Proof.
intros; generalize (depth_min t); generalize (depth_max t); lia.
Qed.
Inductive rtree : nat -> Set :=
| RedNode' : forall c1 c2 n, rbtree c1 n -> nat -> rbtree c2 n -> rtree n.
Section present.
Variable x : nat.
Equations present {c n} (t : rbtree c n) : Prop :=
present Leaf := False;
present (RedNode a y b) := present a \/ x = y \/ present b;
present (BlackNode a y b) := present a \/ x = y \/ present b.
Equations rpresent {n} (t : rtree n) : Prop :=
rpresent (RedNode' a y b) => present a \/ x = y \/ present b.
End present.
Notation "{< x >}" := (sigmaI _ _ x).
Import Sigma_Notations.
(* No need for convoy pattern! *)
Equations balance1 n (a : rtree n) (data : nat) c2 (b : rbtree c2 n) : Σ c, rbtree c (S n) :=
balance1 (RedNode' t1 y t2) data d with t1 => {
| RedNode a x b := {};
| _ with t2 => {
| RedNode b x c := {};
| b := {}
}
}.
Equations balance2 n (a : rtree n) (data : nat) c2 (b : rbtree c2 n) : Σ c, rbtree c (S n) :=
balance2 (RedNode' (c2:=c0) t1 z t2) data a with t1 => {
| RedNode b y c := {};
| _ with t2 => {
| RedNode c z' d := {};
| _ := {}
}
}.
Section insert.
Variable x : nat.
Equations insResult (c : color) (n : nat) : Set :=
insResult Red n := rtree n;
insResult Black n := Σ c', rbtree c' n.
Transparent insResult.
Equations ins {c n} (t : rbtree c n) : insResult c n :=
ins Leaf := {< RedNode Leaf x Leaf >};
ins (RedNode a y b) with le_lt_dec x y => {
| left _ := RedNode' (pr2 (ins a)) y b;
| right _ := RedNode' a y (pr2 (ins b))
};
ins (@BlackNode c1 c2 _ a y b) with le_lt_dec x y => {
| left _ with c1 => {
| Red := balance1 (ins a) y b;
| Black := {}
};
| right _ with c2 => {
| Red := balance2 (ins b) y a;
| Black := {< BlackNode a y (pr2 (ins b))>}
}
}.
Equations insertResult (c : color) (n : nat) : Set :=
insertResult Red n := rbtree Black (S n);
insertResult Black n := Σ c', rbtree c' n.
Transparent insertResult.
Equations makeRbtree c n (r : insResult c n) : insertResult c n :=
makeRbtree Red _ (RedNode' a x b) := BlackNode a x b;
makeRbtree Black _ r := r.
Arguments makeRbtree [c n] _.
Equations insert {c n} (t : rbtree c n) : insertResult c n :=
insert t := makeRbtree (ins t).
Section present.
Variable z : nat.
Lemma present_balance1 : forall n (a : rtree n) (y : nat) c2 (b : rbtree c2 n),
present z (pr2 (balance1 a y b))
<-> rpresent z a \/ z = y \/ present z b.
Proof. intros. funelim (balance1 a y b); subst; simpl in *; tauto. Qed.
Lemma present_balance2 : forall n (a : rtree n) (y : nat) c2 (b : rbtree c2 n),
present z (pr2 (balance2 a y b))
<-> rpresent z a \/ z = y \/ present z b.
Proof. intros. funelim (balance2 a y b); subst; simpl in *; tauto. Qed.
Equations present_insResult (c : color) (n : nat) (t : rbtree c n) (r : insResult c n): Prop :=
@present_insResult Red n t r := rpresent z r <-> z = x \/ present z t;
@present_insResult Black n t r := present z (pr2 r) <-> z = x \/ present z t.
Theorem present_ins : forall c n (t : rbtree c n),
present_insResult t (ins t).
Proof.
intros. funelim (ins t); simp present_insResult in *; simpl in *;
try match goal with
[ |- context [balance1 ?A ?B ?C] ] => generalize (present_balance1 A B C)
end;
try match goal with
[ |- context [balance2 ?A ?B ?C] ] => generalize (present_balance2 A B C)
end; try tauto.
Qed.
Ltac present_insert t t0 :=
intros; funelim (insert t); cbn; generalize (present_ins t0);
try rewrite present_insResult_equation_1; try rewrite present_insResult_equation_2;
funelim (ins t0); intro; assumption.
Theorem present_insert_Red : forall n (t : rbtree Red n),
present z (insert t)
<-> (z = x \/ present z t).
Proof.
intros.
funelim (insert t).
generalize (present_ins t). simpl.
try rewrite present_insResult_equation_1; try rewrite present_insResult_equation_2.
funelim (ins t). intros; assumption. intros; assumption.
Qed.
Theorem present_insert_Black : forall n (t : rbtree Black n),
present z (pr2 (insert t))
<-> (z = x \/ present z t).
Proof. present_insert t t. Qed.
End present.
End insert.