Skip to content

Instantly share code, notes, and snippets.

@sporkl
Last active March 12, 2026 15:39
Show Gist options
  • Select an option

  • Save sporkl/28c9fdde8e24170916e137cef47a5ebe to your computer and use it in GitHub Desktop.

Select an option

Save sporkl/28c9fdde8e24170916e137cef47a5ebe to your computer and use it in GitHub Desktop.
FingerTree verified in Rocq. Includes proofs of: operations maintaining balance invariants, algebraic property validity, and abstraction to list (partially complete).
From Stdlib Require Import List.
From Stdlib Require Import Lia.
(* helper functions for lists *)
Fixpoint list_init {t : Type} (n : nat) (f : nat -> t) : list t :=
match n with
| O => nil
| S m => (list_init m f) ++ ((f n) :: nil)
end.
Definition identity {t : Type} (x : t) : t := x.
Definition test_list : list nat := (list_init 100 identity).
(* core types *)
Inductive node {t : Type} : Type :=
| Leaf : t -> node
| Node2 : (node * node) -> node
| Node3 : (node * node * node) -> node.
Inductive digit {t : Type} : Type :=
| One : @node t -> digit
| Two : (@node t * @node t) -> digit
| Three : (@node t * @node t * @node t) -> digit
| Four : (@node t * @node t * @node t * @node t) -> digit.
Inductive fingertree {t : Type} : Type :=
| Empty : fingertree
| Single : @node t -> fingertree
| Deep : @digit t * fingertree * @digit t -> fingertree.
(* abstraction types *)
Definition flatten_node_once {t : Type} (no : @node t) : list (@node t) :=
match no with
| Leaf a => (Leaf a) :: nil (* weird case *)
| Node2 (a, b) => a :: b :: nil
| Node3 (a, b, c) => a :: b :: c :: nil
end.
Definition flatten_nodes_once {t : Type} (li : list (@node t)) : list (@node t) :=
concat (map flatten_node_once li).
Definition node_list_of_digit {t : Type} (dig : digit) : list (@node t) :=
match dig with
| One a => a :: nil
| Two (a, b) => a :: b :: nil
| Three (a, b, c) => a :: b :: c :: nil
| Four (a, b, c, d) => a :: b :: c :: d :: nil
end.
Fixpoint node_list_of_tree {t : Type} (tree : fingertree) : list (@node t) :=
match tree with
| Empty => nil
| Single no => no :: nil
| Deep (pr, m, sf) =>
(node_list_of_digit pr) ++ (flatten_nodes_once (node_list_of_tree m)) ++ (node_list_of_digit sf)
end.
Fixpoint items_of_node {t : Type} (no : @node t) :=
match no with
| Leaf x => x :: nil
| Node2 (a, b) => (items_of_node a) ++ (items_of_node b)
| Node3 (a, b, c) => (items_of_node a) ++ (items_of_node b) ++ (items_of_node c)
end.
Definition Abs {t : Type} (tree : fingertree) : list t :=
concat (map items_of_node (node_list_of_tree tree)).
(* adding to the tree *)
Definition digit_add_l {t : Type} (item : @node t) (dig : digit) : digit :=
match dig with
| One a => Two (item, a)
| Two (a, b) => Three (item, a, b)
| Three (a, b, c) => Four (item, a, b, c)
| Four (a, b, c, d) => Four (a, b, c, d) (* SHOULD NOT OCCUR *)
end.
Fixpoint add_l_help {t : Type} (item : @node t) (tree : fingertree) : fingertree :=
match item, tree with
| a, Empty => Single a
| a, (Single b) => Deep ((One a), Empty, (One b))
| x, Deep (Four (a, b, c, d), m, sf) =>
Deep (Two (x, a), add_l_help (Node3 (b, c, d)) m, sf)
| a, Deep (pr, m, sf) =>
Deep ((digit_add_l a pr), m, sf)
end.
Definition add_l {t : Type} (item : t) (tree : fingertree) : fingertree :=
add_l_help (Leaf item) tree.
Definition digit_add_r {t : Type} (item : @node t) (dig : digit) : digit :=
match dig with
| One a => Two (a, item)
| Two (a, b) => Three (a, b, item)
| Three (a, b, c) => Four (a, b, c, item)
| Four (a, b, c, d) => Four (a, b, c, d) (* SHOULD NOT OCCUR *)
end.
Fixpoint add_r_help {t : Type} (item : @node t) (tree : fingertree) : fingertree :=
match tree, item with
| Empty, a => Single a
| (Single a), b => Deep ((One a), Empty, (One b))
| Deep (pr, m, Four (a, b, c, d)), x =>
Deep (pr, add_r_help (Node3 (a, b, c)) m, Two (d, x))
| Deep (pr, m, sf), a =>
Deep (pr, m, digit_add_r a sf)
end.
Definition add_r {t : Type} (item : t) (tree : fingertree) : fingertree :=
add_r_help (Leaf item) tree.
Fixpoint tree_of_list {t : Type} (li : list t) : fingertree :=
match li with
| nil => Empty
| a :: d => add_l a (tree_of_list d)
end.
Fixpoint tree_of_list_rev {t : Type} (li : list t) : fingertree :=
match li with
| nil => Empty
| a :: d => add_r a (tree_of_list_rev d)
end.
(* test adding and conversions *)
Example test_add_1 : (1 :: nil) = Abs (add_l 1 Empty).
Proof. reflexivity. Qed.
Example test_add_2 : (1 :: nil) = Abs (add_r 1 Empty).
Proof. reflexivity. Qed.
Example test_add_3 : (1 :: 2 :: nil) = Abs (add_l 1 (add_l 2 Empty)).
Proof. reflexivity. Qed.
Example test_add_4 : (1 :: 2 :: nil) = Abs (add_r 2 (add_r 1 Empty)).
Proof. reflexivity. Qed.
Example test_add_5 : (1 :: 2 :: 3 :: nil) = Abs (add_l 1 (add_r 3 (add_l 2 Empty))).
Proof. reflexivity. Qed.
Example test_conversion_1 : test_list = Abs (tree_of_list test_list).
Proof. reflexivity. Qed.
Example test_conversion_2 : (rev test_list) = (Abs (tree_of_list_rev test_list)).
Proof. reflexivity. Qed.
Definition test_tree := tree_of_list test_list.
(* checking emptiness and tests *)
Definition tree_is_empty {t : Type} (tree : @fingertree t) : bool :=
match tree with
| Empty => true
| _ => false
end.
Example test_empty_1 : (@tree_is_empty nat Empty) = true.
Proof. reflexivity. Qed.
Example test_empty_2 : (tree_is_empty test_tree) = false.
Proof. reflexivity. Qed.
(* helpers for head and tail functions *)
Fixpoint tree_of_node_list {t : Type} (nl : list (@node t)) : fingertree :=
match nl with
| nil => Empty
| a :: b => add_l_help a (tree_of_node_list b)
end.
Definition digit_of_node {t : Type} (no : @node t) : @digit t :=
match no with
| Leaf a => One (Leaf a) (* should not occur *)
| Node2 (a, b) => Two (a, b)
| Node3 (a, b, c) => Three (a, b, c)
end.
(* left side head and tail *)
Definition digit_head_l {t : Type} (d : digit) : @node t :=
match d with
| One a => a
| Two (a, _) => a
| Three (a, _, _) => a
| Four (a, _, _, _) => a
end.
Definition tree_head_node_l {t : Type} (ft : fingertree) : option (@node t) :=
match ft with
| Empty => None
| Single x => Some x
| Deep (pr, m, sf) => Some (digit_head_l pr)
end.
Fixpoint node_head_l {t : Type} (no : @node t) : t :=
match no with
| Leaf x => x
| Node2 (a, b) => node_head_l a
| Node3 (a, b, c) => node_head_l a
end.
Definition tree_head_l {t : Type} (ft : fingertree) : option t :=
option_map node_head_l (tree_head_node_l ft).
Definition digit_tail_l {t : Type} (d : @digit t) : option digit :=
match d with
| One _ => None
| Two (_, b) => Some (One b)
| Three (_, b, c) => Some (Two (b, c))
| Four (_, b, c, d) => Some (Three (b, c, d))
end.
Inductive left_view {t : Type} : Type :=
| NilL
| ConsL (a : @node t) (d : @fingertree t).
Fixpoint view_l {t : Type} (ft : @fingertree t) : left_view :=
match ft with
| Empty => NilL
| Single x => ConsL x Empty
| Deep (pr, m, sf) =>
ConsL
(digit_head_l pr)
match (digit_tail_l pr) with
| None =>
match view_l m with
| NilL => tree_of_node_list (node_list_of_digit sf)
| ConsL a d => Deep (digit_of_node a, d, sf)
end
| Some pr1 => Deep (pr1, m, sf)
end
end.
Definition tree_tail_l {t : Type} (ft : @fingertree t) : option fingertree :=
match view_l ft with
| NilL => None
| ConsL a d => Some d
end.
Definition default_empty_tree {t : Type} (ft : option fingertree) : @fingertree t :=
match ft with
| Some x => x
| None => Empty
end.
Example test_head_tail_l_1 : (tree_head_l (tree_of_list (1 :: 2 :: 3 :: nil))) = Some 1.
Proof. reflexivity. Qed.
Example test_head_tail_l_2 :
(Abs (default_empty_tree (tree_tail_l (tree_of_list (1 :: 2 :: 3 :: nil)))))
=
(2 :: 3 :: nil).
Proof. reflexivity. Qed.
Example test_head_tail_l_3 : tree_head_l (tree_of_list test_list) = hd_error test_list.
Proof. reflexivity. Qed.
Example test_head_tail_l_4 :
Abs (default_empty_tree (tree_tail_l (tree_of_list test_list))) = (tl test_list).
Proof. reflexivity. Qed.
(* right side head and tail *)
Definition digit_head_r {t : Type} (d : digit) : @node t :=
match d with
| One x => x
| Two (_, x) => x
| Three (_, _, x) => x
| Four (_, _, _, x) => x
end.
Definition tree_head_node_r {t : Type} (ft : fingertree) : option (@node t) :=
match ft with
| Empty => None
| Single x => Some x
| Deep (pr, m, sf) => Some (digit_head_r sf)
end.
Fixpoint node_head_r {t : Type} (no : @node t) : t :=
match no with
| Leaf x => x
| Node2 (a, b) => node_head_l b
| Node3 (a, b, c) => node_head_l c
end.
Definition tree_head_r {t : Type} (ft : fingertree) : option t :=
option_map node_head_r (tree_head_node_r ft).
(* TODO once left side works *)
Example test_head_tail_r_1 : (tree_head_r (tree_of_list_rev (1 :: 2 :: 3 :: nil))) = Some 1.
Proof. reflexivity. Qed.
(* Example test_head_tail_r_2 : *)
(* (list_of_tree (default_empty_tree (tree_tail_r (tree_of_list_rev (Abs_of_list_t (1 :: 2 :: 3 :: nil)))))) *)
(* = *)
(* rev (Abs_of_list_t (2 :: 3 :: nil)). *)
(* Proof. reflexivity. Qed. *)
Example test_head_tail_r_3 : (tree_head_r (tree_of_list_rev test_list)) = (hd_error test_list).
Proof. reflexivity. Qed.
(* Example test_head_tail_r_4 : *)
(* (list_of_tree (default_empty_tree (tree_tail_r (tree_of_list_rev test_Abs)))) = rev (tl test_Abs). *)
(* Proof. reflexivity. Qed. *)
(* concatenation *)
Fixpoint node_list_of_list {t : Type} (li : list (@node t)) : list (@node t) :=
match li with
| nil => nil
| a :: nil => (Node2 (a, a)) :: nil (* SHOULD NOT OCCUR *)
| a :: b :: nil => (Node2 (a, b)) :: nil
| a :: b :: c :: nil => (Node3 (a, b, c)) :: nil
| a :: b :: c :: d :: nil => (Node2 (a, b)) :: (Node2 (c, d)) :: nil
| a :: b :: c :: xs => (Node3 (a, b, c)) :: (node_list_of_list xs)
end.
Fixpoint add_all_nodes_l {t : Type} (li : list (@node t)) (ft : fingertree) : fingertree :=
match li with
| nil => ft
| a :: d => add_l_help a (add_all_nodes_l d ft)
end.
Definition add_all_nodes_r_help {t : Type} (li : list (@node t)) (ft : fingertree) : fingertree :=
fold_right add_r_help ft li.
(* match li with *)
(* | nil => ft *)
(* | a :: d => add_r_help a (add_all_nodes_r_help d ft) *)
(* end. *)
Definition add_all_nodes_r {t : Type} (li : list (@node t)) (ft : fingertree) : fingertree :=
add_all_nodes_r_help (rev li) ft.
Fixpoint tree_append_help {t : Type} (ft1 : fingertree) (nl : list (@node t)) (ft2 : fingertree) :=
match ft1, nl, ft2 with
| Empty, _, _ => add_all_nodes_l nl ft2
| _, _, Empty => add_all_nodes_r nl ft1
| Single x, _, _ => add_l_help x (add_all_nodes_l nl ft2)
| _, _, Single x => add_r_help x (add_all_nodes_r nl ft1)
| Deep (pr1, m1, sf1), nl, Deep (pr2, m2, sf2) =>
Deep
(pr1,
tree_append_help m1 (node_list_of_list ((node_list_of_digit sf1) ++ nl ++ (node_list_of_digit pr2))) m2,
sf2)
end.
Check tree_append_help.
Definition tree_append {t : Type} (ft1 : fingertree) (ft2 : fingertree) : @fingertree t :=
tree_append_help ft1 nil ft2.
Definition small_test_list : list nat := 1 :: 2 :: 3 :: 4 :: 5 :: nil.
Definition small_test_tree : fingertree := tree_of_list small_test_list.
Example test_append_1 : (@tree_append nat Empty Empty) = Empty.
Proof. reflexivity. Qed.
Example test_append_2 : Abs (tree_append (Single (Leaf 1)) (Single (Leaf 2))) = (1 :: 2 :: nil).
Proof. reflexivity. Qed.
Example test_append_3 :
Abs (tree_append small_test_tree small_test_tree) = (small_test_list ++ small_test_list).
Proof. reflexivity. Qed.
Example test_append_4 : Abs (tree_append test_tree test_tree) = (test_list ++ test_list).
Proof. reflexivity. Qed.
(* theorems *)
(* nodes are balanced *)
Inductive BN {t : Type} : nat -> @node t -> Prop :=
| BN_Leaf : forall a, BN 0 (Leaf a)
| BN_Node2 : forall n a b, BN n a -> BN n b -> BN (S n) (Node2 (a, b))
| BN_Node3 : forall n a b c, BN n a -> BN n b -> BN n c -> BN (S n) (Node3 (a, b, c)).
(* digits are balanced *)
Inductive BD {t : Type} : nat -> @digit t -> Prop :=
| BD_One : forall n a, BN n a -> BD n (One a)
| BD_Two : forall n a b, BN n a -> BN n b -> BD n (Two (a, b))
| BD_Three : forall n a b c, BN n a -> BN n b -> BN n c -> BD n (Three (a, b, c))
| BD_Four : forall n a b c d, BN n a -> BN n b -> BN n c -> BN n d -> BD n (Four (a, b, c, d)).
(* fingertrees are balanced *)
Inductive BFT {t : Type} : nat -> @fingertree t -> Prop :=
| BFT_Empty : forall n, BFT n Empty
| BFT_Single : forall n no, BN n no -> BFT n (Single no)
| BFT_Deep : forall n pr m sf, BD n pr -> BFT (S n) m -> BD n sf -> BFT n (Deep (pr, m, sf)).
(* operations preserve BFT properties *)
Lemma add_l_help_preserves_BFT : forall (t : Type) n ft, BFT n ft -> forall (no : node), BN n no -> @BFT t n (add_l_help no ft).
Proof.
intros t n ft HBFT. (* intros no HBN. *)
unfold add_l_help.
induction HBFT as [| n' no' IHn | n' pr m sf IHpr IHm IHn IHsf].
{ apply BFT_Single. }
{ intros no HBN.
apply BFT_Deep.
{ apply BD_One. apply HBN. }
{ apply BFT_Empty. }
{ apply BD_One. apply IHn. } }
{ destruct pr.
{ intros no HBN.
apply BFT_Deep.
{ simpl. apply BD_Two.
{ apply HBN. }
{ inversion IHpr.
apply H1. } }
{ apply IHm. }
{ apply IHsf. } }
{ intros no HBN.
simpl.
destruct p as [a b].
apply BFT_Deep.
{ apply BD_Three.
{ apply HBN. }
{ inversion IHpr.
apply H2. }
{ inversion IHpr.
apply H3. } }
{ apply IHm. }
{ apply IHsf. } }
{ intros no HBN.
simpl.
destruct p as [[a b] c].
apply BFT_Deep; auto.
{ apply BD_Four; inversion IHpr; auto. } }
{ destruct p as [[[a b] c] d].
intros no HBN.
apply BFT_Deep.
{ apply BD_Two.
{ apply HBN. }
{ inversion IHpr.
apply H4. } }
{ destruct m.
{ apply BFT_Single.
apply BN_Node3.
all: inversion IHpr; auto. }
{ apply BFT_Deep.
{ apply BD_One.
apply BN_Node3.
all: inversion IHpr; auto. }
{ apply BFT_Empty. }
{ apply BD_One.
inversion IHm.
apply H1. } }
{ apply IHn.
apply BN_Node3.
all: inversion IHpr; auto. } }
{ apply IHsf. } } }
Qed.
Theorem add_l_preserves_BFT_0 : forall (t : Type) ft (x : t), BFT 0 ft -> BFT 0 (add_l x ft).
Proof.
intros t ft x HBFT.
unfold add_l.
apply add_l_help_preserves_BFT.
{ apply HBFT. }
{ apply BN_Leaf. }
Qed.
Ltac try_prove_BFT :=
repeat
match goal with
| |- BD _ (One _) => constructor
| |- BD _ (Two _) => constructor
| |- BD _ (Three _) => constructor
| |- BD _ (Four _) => constructor
| |- BFT _ (Single _) => constructor
| |- BFT _ Empty => constructor
| |- BFT _ (Deep _) => constructor
| H: BN ?n (Leaf _) |- BN ?n (Leaf _) => inversion H; constructor
| H: BD ?n (One (Leaf _)) |- BN ?n (Leaf _) => inversion H; clear H
| H: BN (S ?n) (Leaf ?t) |- BN ?n (Leaf ?t) => inversion H; clear H
| H: BN (S ?n) (Node2 (?no, _)) |- BN ?n ?no => inversion H; clear H
| H: BN (S ?n) (Node2 (_, ?no)) |- BN ?n ?no => inversion H; clear H
| H: BN (S ?n) (Node3 (?no, _, _)) |- BN ?n ?no => inversion H; clear H
| H: BN (S ?n) (Node3 (_, ?no, _)) |- BN ?n ?no => inversion H; clear H
| H: BN (S ?n) (Node3 (_, _, ?no)) |- BN ?n ?no => inversion H; clear H
| H: BD _ (One (Node2 (?no, _))) |- BN _ ?no => inversion H; auto
| H: BD _ (One (Node2 (_, ?no))) |- BN _ ?no => inversion H; auto
| H: BD _ (One (Node3 (?no, _, _))) |- BN _ ?no => inversion H; auto
| H: BD _ (One (Node3 (_, ?no, _))) |- BN _ ?no => inversion H; auto
| H: BD _ (One (Node3 (_, _, ?no))) |- BN _ ?no => inversion H; auto
| H: BD _ (One ?no) |- BN _ ?no => inversion H; auto
| H: BD _ (Two (?no, _)) |- BN _ ?no => inversion H; auto
| H: BD _ (Two (_, ?no)) |- BN _ ?no => inversion H; auto
| H: BD _ (Three (?no, _, _)) |- BN _ ?no => inversion H; auto
| H: BD _ (Three (_, ?no, _)) |- BN _ ?no => inversion H; auto
| H: BD _ (Three (_, _, ?no)) |- BN _ ?no => inversion H; auto
| H: BD _ (Four (?no, _, _, _)) |- BN _ ?no => inversion H; auto
| H: BD _ (Four (_, ?no, _, _)) |- BN _ ?no => inversion H; auto
| H: BD _ (Four (_, _, ?no, _)) |- BN _ ?no => inversion H; auto
| H: BD _ (Four (_, _, _, ?no)) |- BN _ ?no => inversion H; auto
| H: BFT _ (Deep (One (Node2 (?n, _)), _, _)) |- BN _ ?n => inversion H; clear H
| H: BFT _ (Deep (One (Node2 (_, ?n)), _, _)) |- BN _ ?n => inversion H; clear H
| H: BFT ?n (Single ?no) |- BN ?n ?no => inversion H; clear H
| H: BFT _ (Single (Leaf ?t)) |- BN _ (Leaf ?t) => inversion H; clear H
| H: BFT _ (Single (Node2 (?n, _))) |- BN _ ?n => inversion H; clear H
| H: BFT _ (Single (Node2 (_, ?n))) |- BN _ ?n => inversion H; clear H
| H: BFT _ (Single (Node3 (?n, _, _))) |- BN _ ?n => inversion H; clear H
| H: BFT _ (Single (Node3 (_, ?n, _))) |- BN _ ?n => inversion H; clear H
| H: BFT _ (Single (Node3 (_, _, ?n))) |- BN _ ?n => inversion H; clear H
| H: BFT ?n (Deep (One ?no, _, _)) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (Two (?no, _), _, _)) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (Two (_, ?no), _, _)) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (Three (?no, _, _), _, _)) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (Three (_, ?no, _), _, _)) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (Three (_, _, ?no), _, _)) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (Four (?no, _, _, _), _, _)) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (Four (_, ?no, _, _), _, _)) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (Four (_, _, ?no, _), _, _)) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (Four (_, _, _, ?no), _, _)) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (_, _, One ?no)) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (_, _, Two (?no, _))) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (_, _, Two (_, ?no))) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (_, _, Three (?no, _, _))) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (_, _, Three (_, ?no, _))) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (_, _, Three (_, _, ?no))) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (_, _, Four (?no, _, _, _))) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (_, _, Four (_, ?no, _, _))) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (_, _, Four (_, _, ?no, _))) |- BN ?n ?no => inversion H; clear H
| H: BFT ?n (Deep (_, _, Four (_, _, _, ?no))) |- BN ?n ?no => inversion H; clear H
| H: BFT _ (Deep (?d, _, _)) |- BD _ ?d => inversion H; clear H
| H: BFT _ (Deep (_, _, ?d)) |- BD _ ?d => inversion H; clear H
| H: BN _ ?no |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BD _ (One ?no) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Single ?no) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (One ?no, _, _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (_, Single ?no, _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (_, Deep (One ?no, _, _), _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (_, Deep (Two (?no, _), _, _), _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (_, Deep (Two (_, ?no), _, _), _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (_, Deep (Three (?no, _, _), _, _), _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (_, Deep (Three (_, ?no, _), _, _), _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (_, Deep (Three (_, _, ?no), _, _), _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (_, Deep (Four (?no, _, _, _), _, _), _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (_, Deep (Four (_, ?no, _, _), _, _), _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (_, Deep (Four (_, _, ?no, _), _, _), _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT _ (Deep (_, Deep (Four (_, _, _, ?no), _, _), _)) |- BD _ (digit_of_node ?no) => inversion H; clear H
| H: BFT ?no (Deep (_, ?f, _)) |- BFT (S ?no) ?f => inversion H; clear H; subst
| H: Some _ = Some _ |- _ => inversion H; try constructor; clear H
| H: Some (Deep _) = Some (Single _) |- _ => inversion H; clear H
| H: _ = ?s |- BFT _ ?s => rewrite <- H; simpl
end; simpl in *; auto.
Lemma add_r_help_preserves_BFT : forall (t : Type) n ft, BFT n ft -> forall (no : node), BN n no -> @BFT t n (add_r_help no ft).
Proof.
intros t n ft HBFT. (* intros no HBN. *)
unfold add_l_help.
induction HBFT as [| n' no' IHn | n' pr m sf IHpr IHm IHn IHsf].
{ apply BFT_Single. }
{ intros no HBN.
apply BFT_Deep.
{ apply BD_One. apply IHn. }
{ apply BFT_Empty. }
{ apply BD_One. apply HBN. } }
{ destruct sf; intros no HBN; simpl; repeat destruct p; try_prove_BFT.
apply IHn.
inversion IHsf.
constructor; auto. }
Qed.
Theorem add_r_preserves_BFT_0 : forall (t : Type) ft (x : t), BFT 0 ft -> BFT 0 (add_r x ft).
Proof.
intros t ft x HBFT.
unfold add_r.
apply add_r_help_preserves_BFT.
{ apply HBFT. }
{ apply BN_Leaf. }
Qed. (* only works properly on BFT 0, because it's adding a leaf node *)
Lemma node_list_of_digit_preserves_n :
forall (t : Type) n (dig : (@digit t)), BD n dig -> Forall (BN n) (node_list_of_digit dig).
Proof.
intros t n dig HBD.
destruct dig; repeat destruct p; simpl; repeat apply Forall_cons; try constructor; try_prove_BFT.
Qed.
Lemma tree_of_node_list_preserves_n :
forall (t : Type) n (li : list (@node t)), Forall (BN n) li -> BFT n (tree_of_node_list li).
Proof.
intros t n li HBN.
induction HBN.
{ constructor. }
{ simpl.
apply add_l_help_preserves_BFT.
{ apply IHHBN. }
{ apply H. } }
Qed.
Lemma digit_of_node_Sn_becomes_n :
forall (t : Type) n (no : @node t), BN (S n) no -> BD n (digit_of_node no).
Proof.
intros t n no HBN.
destruct no.
{ inversion HBN. }
{ repeat destruct p; simpl; try_prove_BFT. }
{ repeat destruct p; simpl; try_prove_BFT. }
Qed.
Lemma digit_head_l_preserves_n :
forall (t : Type) n (dig : @digit t), BD n dig -> BN n (digit_head_l dig).
Proof.
intros t n dig HBD.
destruct dig; simpl; repeat destruct p; try_prove_BFT.
Qed.
Theorem tail_l_preserves_BFT :
forall (t : Type) n (ft : @fingertree t), BFT n ft ->
forall (ftr : @fingertree t), tree_tail_l ft = Some ftr -> BFT n ftr.
Proof.
intros t n ft HBFT.
induction HBFT.
{ intros ftr Httl. inversion Httl. }
{ intros ftr Httl. inversion Httl. constructor. }
{ intros ftr Httl.
assert (BFT n (Deep (pr, m, sf))) as HBFTprmsf.
{ constructor; auto. }
destruct ftr.
{ constructor. }
{ constructor.
inversion Httl.
destruct pr; simpl in *; destruct m; repeat destruct p; simpl in *; try inversion H2.
{ inversion HBFTprmsf; subst.
assert (BFT n (tree_of_node_list (node_list_of_digit sf))).
{ apply tree_of_node_list_preserves_n.
apply node_list_of_digit_preserves_n.
auto. }
rewrite H2 in H1.
try_prove_BFT. } }
{ repeat destruct p.
inversion Httl.
destruct pr; simpl in *; destruct m; repeat destruct p; simpl in *; try_prove_BFT.
{ apply tree_of_node_list_preserves_n.
apply node_list_of_digit_preserves_n.
try_prove_BFT. }
{ subst. try_prove_BFT. }
{ subst. try_prove_BFT. }
{ apply digit_of_node_Sn_becomes_n.
apply digit_head_l_preserves_n.
try_prove_BFT. } } }
Qed.
(* TODO *)
(* Theorem tail_r_preserves_BFT : *)
(* forall (t : Type) n (ft : @fingertree t), BFT n ft -> BFT n (default_empty_tree (tree_tail_r ft)). *)
(* Proof. Admitted. *)
(* Theorem tree_append_help_preserves_BFT : *)
(* forall (t : Type) n (nol : list (@node t)), Forall (BN n) nol -> *)
(* forall ft1 ft2, BFT n ft1 -> BFT n ft2 -> BFT n (tree_append_help ft1 nol ft2). *)
(* Proof. *)
(* intros t n nol Hnol. *)
(* induction nol. *)
(* { intros ft1 ft2 HBFT1 HBFT2. *)
(* induction ft1; destruct ft2; simpl; repeat destruct p; auto. *)
(* { try_prove_BFT. } *)
(* { destruct d0; repeat destruct p; simpl; try_prove_BFT. *)
(* apply add_l_help_preserves_BFT; inversion HBFT2; inversion H3; auto; constructor; auto. } *)
(* { destruct d; repeat destruct p; simpl; try_prove_BFT. *)
(* apply add_r_help_preserves_BFT; inversion HBFT1; inversion H5; auto; constructor; auto. } *)
(* { destruct p0 as [[pr m] sf]. try_prove_BFT. *)
(* assert (Forall (BN n) (node_list_of_digit d)) as BNd. *)
(* { inversion HBFT1; subst; apply node_list_of_digit_preserves_n; auto. } *)
(* assert (Forall (BN n) (node_list_of_digit pr)) as BNpr. *)
(* { inversion HBFT2; subst; apply node_list_of_digit_preserves_n; auto. } *)
(* simpl. *)
(* Theorem tree_append_help_preserves_BFT : *)
(* forall (t : Type) n (nol : list (@node t)), Forall (BN n) nol -> *)
(* forall ft1 ft2, BFT n ft1 -> BFT n ft2 -> BFT n (tree_append_help ft1 nol ft2). *)
(* Proof. *)
(* intros t n nol Hnol. *)
(* induction nol. *)
(* { intros ft1 ft2 HBFT1 HBFT2. *)
(* induction HBFT1; induction HBFT2; simpl; repeat destruct p; simpl; try_prove_BFT. *)
(* { unfold add_all_nodes_r; simpl; constructor; auto. } *)
(* { destruct pr; repeat destruct p; simpl; try_prove_BFT. *)
(* apply add_l_help_preserves_BFT; inversion H0; auto; constructor; auto. } *)
(* { unfold add_all_nodes_r; simpl; constructor; auto. } *)
(* { destruct sf; repeat destruct p; simpl; try_prove_BFT. *)
(* apply add_r_help_preserves_BFT; inversion H0; auto; constructor; auto. } *)
(* { subst. simpl in *. *)
(* unfold tree_append_help. *)
(* admit. (1* seems to require induction hypothesis in the base case somehow *1) (1* TODO *1) *)
(* } } *)
(* { intros ft1 ft2 HBFT1 HBFT2. *)
(* induction HBFT1; induction HBFT2; simpl; repeat destruct p; simpl; try_prove_BFT. *)
(* Admitted. *)
Lemma add_all_nodes_l_preserves_BFT :
forall (t : Type) n (nol : list (@node t)), Forall (BN n) nol ->
forall ft, BFT n ft -> BFT n (add_all_nodes_l nol ft).
Proof.
intros t n nol Hno.
induction Hno.
{ intros ft HBFT. auto. }
{ intros ft HBFT; simpl.
apply add_l_help_preserves_BFT.
{ apply IHHno; auto. }
{ auto. } }
Qed.
Lemma add_all_nodes_r_rev_preserves_BFT :
forall (t : Type) n (nol : list (@node t)), Forall (BN n) nol ->
forall ft, BFT n ft -> BFT n (add_all_nodes_r (rev nol) ft).
Proof.
intros t n nol Hno.
induction Hno.
{ intros ft HBFT. auto. }
{ intros ft HBFT.
unfold add_all_nodes_r; simpl.
rewrite rev_app_distr; simpl.
unfold add_all_nodes_r in IHHno.
apply add_r_help_preserves_BFT.
{ apply IHHno; auto. }
{ auto. } }
Qed.
Lemma add_all_nodes_r_preserves_BFT :
forall (t : Type) n (nol : list (@node t)), Forall (BN n) nol ->
forall ft, BFT n ft -> BFT n (add_all_nodes_r nol ft).
Proof.
intros t n nol Hno.
induction Hno.
{ intros ft HBFT. auto. }
{ intros ft HBFT.
unfold add_all_nodes_r in *; simpl in *.
unfold add_all_nodes_r_help in *.
rewrite fold_right_app; simpl.
apply IHHno.
apply add_r_help_preserves_BFT; auto. }
Qed.
Lemma node_list_of_list_incr_n :
forall (t : Type) n li, Forall (BN n) li -> Forall (@BN t (S n)) (node_list_of_list li).
Proof.
intros t n li HBNS.
induction HBNS; auto.
simpl.
destruct l.
apply Forall_cons; try_prove_BFT; constructor; auto.
destruct l.
apply Forall_cons; apply Forall_inv in HBNS; try_prove_BFT; constructor; auto.
destruct l.
apply Forall_inv in HBNS as HBNS0.
apply Forall_inv_tail in HBNS as HBNS1.
apply Forall_inv in HBNS1.
apply Forall_cons; try_prove_BFT; constructor; auto.
destruct l.
apply Forall_inv in HBNS as HBNS0.
apply Forall_inv_tail in HBNS.
apply Forall_inv in HBNS as HBNS1.
apply Forall_inv_tail in HBNS.
apply Forall_inv in HBNS as HBNS2.
apply Forall_cons; try_prove_BFT; constructor; auto; constructor; auto.
apply Forall_inv in HBNS as HBNS0.
apply Forall_inv_tail in HBNS.
apply Forall_inv in HBNS as HBNS1.
apply Forall_cons.
constructor; auto.
simpl in *.
Admitted.
Lemma tree_append_help_preserves_BFT :
forall (t : Type) n (nol : list (@node t)), Forall (BN n) nol ->
forall ft1 ft2, BFT n ft1 -> BFT n ft2 -> BFT n (tree_append_help ft1 nol ft2).
Proof.
intros t n nol HBN ft1 ft2 HBFT1 HBFT2.
generalize dependent nol. generalize dependent ft2.
induction HBFT1; simpl; try_prove_BFT.
{ intros. apply add_all_nodes_l_preserves_BFT; auto. }
{ intros.
destruct ft2.
inversion HBFT2.
{ apply add_all_nodes_r_preserves_BFT; auto; try_prove_BFT. }
{ apply add_l_help_preserves_BFT; try apply add_all_nodes_l_preserves_BFT; auto. }
{ apply add_l_help_preserves_BFT; try apply add_all_nodes_l_preserves_BFT; auto. } }
{ intros.
destruct ft2.
{ apply add_all_nodes_r_preserves_BFT; auto; try_prove_BFT. }
{ apply add_r_help_preserves_BFT; try apply add_all_nodes_r_preserves_BFT; try_prove_BFT. }
{ repeat destruct p. constructor; try_prove_BFT.
inversion HBFT2; subst.
apply IHHBFT1; auto.
(* TODO: should be straightforward from here *)
(* looks like it wasn't :( *)
Admitted.
(* correctness theorems *)
Theorem head_l_undoes_add_l : forall (t : Type) (x : t) ft, tree_head_l (add_l x ft) = Some x.
Proof.
intros t x ft.
destruct ft.
{ reflexivity. }
{ reflexivity. }
{ destruct p as [[pr m] sf].
simpl.
destruct pr.
{ reflexivity. }
{ destruct p as [a b]. reflexivity. }
{ destruct p as [[a b] c]. reflexivity. }
{ destruct p as [[[a b] c] d].
destruct m; auto. } }
Qed.
Theorem head_r_undoes_add_r : forall (t : Type) (x : t) ft, tree_head_r (add_r x ft) = Some x.
Proof.
intros t x ft.
destruct ft.
{ reflexivity. }
{ reflexivity. }
{ destruct p as [[pr m] sf].
simpl.
destruct sf.
{ reflexivity. }
{ destruct p as [a b]. reflexivity. }
{ destruct p as [[a b] c]. reflexivity. }
{ destruct p as [[[a b] c] d].
destruct m; auto. } }
Qed.
(* theorems about abstraction to list *)
Lemma abs_add_l_help :
forall (t : Type) n ft, BFT n ft ->
forall (no : @node t), BN n no ->
node_list_of_tree (add_l_help no ft) = no :: (node_list_of_tree ft).
Proof.
intros t n ft HBFT.
induction HBFT as [| n' no' IHn | n' pr m sf IHpr IHm IHn IHsf].
{ reflexivity. }
{ reflexivity. }
{ intros no HBN.
unfold add_l_help.
destruct pr; simpl; repeat destruct p; try reflexivity.
fold (@add_l_help t).
unfold node_list_of_tree.
fold (@node_list_of_tree t).
simpl.
unfold flatten_nodes_once.
destruct m; auto.
assert (BN (S n') (Node3 (n2, n0, n))) as HBNbcd.
{ inversion IHpr; constructor; auto. }
apply IHn in HBNbcd.
rewrite HBNbcd. simpl. auto. }
Qed.
Theorem abs_add_l :
forall (t : Type) (x : t) ft, BFT 0 ft -> Abs (add_l x ft) = x :: (Abs ft).
Proof.
intros t x ft HBFT.
unfold Abs.
unfold add_l.
assert (BN 0 (Leaf x)) by constructor.
assert (node_list_of_tree (add_l_help (Leaf x) ft) = (Leaf x) :: (node_list_of_tree ft)).
{ apply abs_add_l_help with 0; auto. }
rewrite H0.
reflexivity.
Qed.
Lemma abs_add_r_help :
forall (t : Type) n ft, BFT n ft ->
forall (no : @node t), BN n no ->
node_list_of_tree (add_r_help no ft) = (node_list_of_tree ft) ++ (no :: nil).
Proof.
intros t n ft HBFT.
induction HBFT as [| n' no' IHn | n' pr m sf IHpr IHm IHn IHsf].
{ reflexivity. }
{ reflexivity. }
{ intros no HBN.
unfold add_r_help.
destruct sf; simpl; repeat destruct p; repeat rewrite <- app_assoc; try reflexivity.
fold (@add_r_help t).
unfold node_list_of_tree.
fold (@node_list_of_tree t).
simpl.
assert (BN (S n') (Node3 (n1, n2, n0))) as HBNn120.
{ inversion IHsf; constructor; auto. }
apply IHn in HBNn120.
rewrite HBNn120.
unfold flatten_nodes_once.
rewrite map_last.
rewrite concat_app.
simpl.
repeat rewrite <- app_assoc.
assert ((n1 :: n2 :: n0 :: nil) ++ n :: no :: nil = n1 :: n2 :: n0 :: n :: no :: nil) by auto.
rewrite H.
auto. }
Qed.
Theorem abs_add_r :
forall (t : Type) (x : t) ft, BFT 0 ft -> Abs (add_r x ft) = (Abs ft) ++ (x :: nil).
Proof.
intros t x ft HBFT.
unfold Abs.
unfold add_r.
assert (BN 0 (Leaf x)) by constructor.
assert (node_list_of_tree (add_r_help (Leaf x) ft) = (node_list_of_tree ft) ++ (Leaf x) :: nil).
{ apply abs_add_r_help with 0; auto. }
rewrite H0.
simpl.
rewrite map_app.
simpl.
rewrite concat_app.
reflexivity.
Qed.
Lemma abs_head_l_help :
forall (t : Type) n (ft : @fingertree t), BFT n ft -> (tree_head_node_l ft) = hd_error (node_list_of_tree ft).
Proof.
intros t n ft HBFT.
induction HBFT.
{ reflexivity. }
{ destruct no; repeat destruct p; auto. }
{ destruct pr.
{ destruct n0; repeat destruct p; auto. }
{ repeat destruct p; destruct n0; repeat destruct p; auto. }
{ repeat destruct p; destruct n1; repeat destruct p; auto. }
{ repeat destruct p; destruct n2; repeat destruct p; auto. } }
Qed.
Lemma hd_error_app : forall (t : Type) (a : list t) (b : list t), a <> nil -> hd_error (a ++ b) = hd_error a.
Proof.
intros t a b Ha.
unfold hd_error.
destruct a.
{ simpl.
destruct b.
{ auto. }
{ contradiction. } }
{ destruct b; auto. }
Qed.
Lemma items_of_node_not_nil : forall (t : Type) n (no : @node t), BN n no -> items_of_node no <> nil.
Proof.
intros t n no HBN.
induction HBN.
{ discriminate. }
{ repeat destruct p. simpl.
intros H.
apply app_eq_nil in H.
inversion H.
contradiction. }
{ intros H.
inversion H.
apply app_eq_nil in H1.
inversion H1.
contradiction. }
Qed.
Lemma node_head_l_hd_items_of_node :
forall t n (l : @node t), BN n l -> Some (node_head_l l) = hd_error (items_of_node l).
Proof.
intros t n l HBN.
induction HBN.
{ simpl; auto. }
{ simpl. rewrite IHHBN1.
rewrite hd_error_app.
auto.
apply (items_of_node_not_nil t n a).
auto. }
{ simpl. rewrite IHHBN1.
rewrite hd_error_app.
auto.
apply (items_of_node_not_nil t n a).
auto. }
Qed.
Lemma flatten_node_once_decr_n :
forall (t : Type) n no, BN (S n) no -> Forall (@BN t n) (flatten_node_once no).
Proof.
intros t n no HBN.
induction no.
{ inversion HBN. }
{ repeat destruct p. simpl. inversion HBN; auto. }
{ repeat destruct p. simpl. inversion HBN; auto. }
Qed.
Lemma flatten_nodes_once_decr_n :
forall (t : Type) n li, Forall (BN (S n)) li -> Forall (@BN t n) (flatten_nodes_once li).
Proof.
intros t n li HBNS.
induction HBNS; auto.
unfold flatten_nodes_once.
rewrite map_cons.
simpl.
apply Forall_app.
split.
{ apply flatten_node_once_decr_n; auto. }
{ unfold flatten_nodes_once in IHHBNS; auto. }
Qed.
Lemma node_list_of_tree_preserves_n :
forall (t : Type) n ft, BFT n ft -> (forall (no : @node t), In no (node_list_of_tree ft) -> BN n no).
Proof.
intros t n ft HBFT no Hno.
induction HBFT.
{ inversion Hno. }
{ simpl in Hno.
inversion Hno; subst; auto.
inversion H0. }
{ simpl in Hno.
apply in_app_or in Hno.
destruct Hno.
{ Check node_list_of_digit_preserves_n.
pose proof (node_list_of_digit_preserves_n _ _ _ H).
Search (Forall).
rewrite Forall_forall in H2.
apply H2; auto. }
{ apply in_app_or in H1.
destruct H1.
give_up.
(* { give_up. } (1* TODO: here. *1) *)
(* { apply node_list_of_digit_preserves_n in H0. *)
(* rewrite Forall_forall in H0. *)
(* apply H0; auto. } *)
{ Check node_list_of_digit_preserves_n.
pose proof (node_list_of_digit_preserves_n _ _ _ H0).
Search (Forall).
rewrite Forall_forall in H2.
apply H2; auto. } }
Admitted.
Theorem abs_head_l :
forall (t : Type) (ft : @fingertree t), BFT 0 ft -> tree_head_l ft = hd_error (Abs ft).
Proof.
intros t ft HBFT.
unfold tree_head_l.
unfold Abs.
rewrite (abs_head_l_help t 0 ft); auto.
remember (node_list_of_tree ft);
induction l; auto.
simpl.
rewrite hd_error_app.
apply (askjdlf t 0 a).
apply node_list_of_tree_preserves_n with ft; auto.
rewrite <- Heql; simpl; auto.
apply items_of_node_not_nil with 0.
apply node_list_of_tree_preserves_n with ft; auto.
rewrite <- Heql; simpl; auto.
Qed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment