(declare-datatype nat ((zero) (s (s_0 nat))))

(declare-fun plus (nat nat) nat)
(assert (forall ((x nat)) (= (plus zero x) x)))
(assert (forall ((x nat) (y nat)) (= (plus (s x) y) (s (plus x y)))))
(declare-fun mult (nat nat) nat)
(assert (forall ((x nat)) (= (mult zero x) zero)))
(assert (forall ((x nat) (y nat)) (= (mult (s x) y) (plus (mult x y) y))))
(declare-fun minus (nat nat) nat)
(assert (forall ((n nat)) (= (minus zero n) zero) ))
(assert (forall ((n nat)) (= (minus n zero) n) ))
(assert (forall ((n nat) (m nat)) (= (minus (s n) (s m)) (minus n m)) ))

(declare-sort-parameter A)
(declare-sort-parameter B)

(declare-datatype list (par (a) ((Nil) (Cons (Cons_0 a) (Cons_1 (list a))))))
(define-sort lists (a) (list (list a)))
(declare-datatype option (par (a) ((None) (Some (Some_0 a)))))
(declare-datatype tree (par (a) ((Leaf) (Node (Node_0 (tree a)) (Node_1 a) (Node_2 (tree a))))))
(declare-datatype pair (par (a b) ((Pair (Pair_0 a) (Pair_1 b)))))
(define-sort ptree (a b) (tree (pair a b)))
(declare-fun NodeP ((ptree A B) A B (ptree A B)) (ptree A B))
(assert (forall ((l (ptree A B)) (x A) (y B) (r (ptree A B))) (= (NodeP l x y r) (Node l (Pair x y) r))))
(define-sort ivl (a) (pair a a))
(define-sort itree (a) (ptree (ivl A) a))
(declare-datatype cmp_val ((LT) (EQ) (GT)))
(declare-datatype tree23 (par (a) ((Leaf23) (Node2 (Node2_0 (tree23 a)) (Node2_1 a) (Node2_2 (tree23 a))) (Node3 (Node3_0 (tree23 a)) (Node3_1 a) (Node3_2 (tree23 a)) (Node3_3 a) (Node3_4 (tree23 a))))))
(declare-datatype upI (par (a) ((TI (TI_0 (tree23 a))) (OF (OF_0 (tree23 a)) (OF_1 a) (OF_2 (tree23 a))))))
(declare-datatype upD (par (a) ((TD (TD_0 (tree23 a))) (UF (UF_0 (tree23 a))))))
(declare-datatype tree23s (par (a) ((T (T_0 (tree23 a))) (TTs (TTs_0 (tree23 a)) (TTs_1 a) (TTs_2 (tree23s a))))))
(declare-datatype color ((Red) (Black)))
(declare-datatype unit ((Unit)))
(declare-datatype bal ((Lh) (Bal) (Rh)))
(define-sort tree_bal (a) (ptree a bal))
(declare-datatype trie ((Lf) (Nd (Nd_0 Bool) (Nd_1 trie) (Nd_2 trie))))
(declare-datatype trieP ((LfP) (NdP (NdP_0 (list Bool)) (NdP_1 Bool) (NdP_2 trieP) (NdP_3 trieP))))
(define-sort rbt (a) (ptree a color))
(declare-datatype treeh (par (a) ((LeafH (LeafH_0 nat) (LeafH_1 a)) (NodeH (NodeH_0 nat) (NodeH_1 (treeh a)) (NodeH_2 (treeh a))))))
(define-sort tree_ht (a) (ptree A nat))
(declare-datatype triple (par (a b c) ((Triple (Triple_0 a) (Triple_1 b) (Triple_2 c)))))
(define-sort lheap (a) (ptree A nat))

; uninterpreted functions
(declare-fun f ((list A)) (list A))

; auxiliary functions for sets and multisets -- remove these once a higher-order setting is used
(declare-fun in_set (A (list A)) Bool)
(assert (forall ((x A)) (not (in_set x (as Nil (list A))))))
(assert (forall ((x A) (y A) (ys (list A))) (= (in_set x (Cons y ys)) (or (= x y) (in_set x ys)))))
(declare-fun in_set_tree (A (tree A)) Bool)
(assert (forall ((x A)) (not (in_set_tree x (as Leaf (tree A))))))
(assert (forall ((x A) (l (tree A)) (y A) (r (tree A))) (= (in_set_tree x (Node l y r)) (or (= x y) (in_set_tree x l) (in_set_tree x r)))))
(declare-fun in_set_ptree (A (ptree A B)) Bool)
(assert (forall ((x A)) (not (in_set_ptree x (as Leaf (ptree A B))))))
(assert (forall ((x A) (l (ptree A B)) (y A) (z B) (r (ptree A B))) (= (in_set_ptree x (NodeP l y z r)) (or (= x y) (in_set_ptree x l) (in_set_ptree x r)))))
(declare-fun count (A (list A)) nat)
(assert (forall ((x A)) (= (count x (as Nil (list A))) zero)))
(assert (forall ((x A) (y A) (ys (list A))) (= (count x (Cons y ys)) (ite (= x y) (s (count x ys)) (count x ys)))))
(declare-fun same_set ((list A) (list A)) Bool)
(assert (forall ((xs (list A)) (ys (list A))) (= (same_set xs ys) (forall ((x A)) (= (in_set x xs) (in_set x ys))))))
(declare-fun same_mset ((list A) (list A)) Bool)
(assert (forall ((xs (list A)) (ys (list A))) (= (same_mset xs ys) (forall ((x A)) (= (count x xs) (count x ys))))))
(declare-fun count_tree (A (tree A)) nat)
(assert (forall ((x A)) (= (count_tree x (as Leaf (tree A))) zero)))
(assert (forall ((x A) (l (tree A)) (y A) (r (tree A))) (= (count_tree x (Node l y r))
  (let ((lc (count_tree x l)) (rc (count_tree x r))) (ite (= x y) (s (plus lc rc)) (plus lc rc))))))
(declare-fun count_ptree (A (ptree A B)) nat)
(assert (forall ((x A)) (= (count_ptree x (as Leaf (ptree A B))) zero)))
(assert (forall ((x A) (l (ptree A B)) (y A) (z B) (r (ptree A B))) (= (count_ptree x (NodeP l y z r))
  (let ((lc (count_ptree x l)) (rc (count_ptree x r))) (ite (= x y) (s (plus lc rc)) (plus lc rc))))))

; filter and map functions -- remove these once a higher-order setting is used
(declare-fun less (A A) Bool)
(assert (forall ((x nat)) (not (less x zero))))
(assert (forall ((x nat)) (less zero (s x))))
(assert (forall ((x nat) (y nat)) (= (less (s x) (s y)) (less x y))))
(declare-fun leq (A A) Bool)
(assert (forall ((x A) (y A)) (= (leq x y) (or (= x y) (less x y)))))
(declare-fun filter_less (A (list A)) (list A))
(assert (forall ((x A)) (= (filter_less x (as Nil (list A))) (as Nil (list A)))))
(assert (forall ((x A) (y A) (ys (list A))) (= (filter_less x (Cons y ys)) (ite (less y x) (Cons y (filter_less x ys)) (filter_less x ys)))))
(declare-fun filter_greater (A (list A)) (list A))
(assert (forall ((x A)) (= (filter_greater x (as Nil (list A))) (as Nil (list A)))))
(assert (forall ((x A) (y A) (ys (list A))) (= (filter_greater x (Cons y ys)) (ite (less x y) (Cons y (filter_greater x ys)) (filter_greater x ys)))))
(declare-fun filter_eq (A (list A)) (list A))
(assert (forall ((x A)) (= (filter_eq x (as Nil (list A))) (as Nil (list A)))))
(assert (forall ((x A) (y A) (ys (list A))) (= (filter_eq x (Cons y ys)) (ite (= x y) (Cons y (filter_eq x ys)) (filter_eq x ys)))))
(declare-fun filter_ge (A (list A)) (list A))
(assert (forall ((x A)) (= (filter_ge x (as Nil (list A))) (as Nil (list A)))))
(assert (forall ((x A) (y A) (ys (list A))) (= (filter_ge x (Cons y ys)) (ite (not (less y x)) (Cons y (filter_ge x ys)) (filter_ge x ys)))))
(declare-fun map_list_lists ((list A)) (lists A))
(assert (= (map_list_lists (as Nil (list A))) (as Nil (lists A))))
(assert (forall ((x A) (xs (list A))) (= (map_list_lists (Cons x xs)) (Cons (Cons x (as Nil (list A))) (map_list_lists xs)))))

; functions
(declare-fun pow (nat nat) nat)
(assert (forall ((x nat)) (= (pow x zero) (s zero))))
(assert (forall ((x nat) (e nat)) (= (pow x (s e)) (mult x (pow x e)))))
(declare-fun pow2 (nat) nat)
(assert (forall ((x nat)) (= (pow2 x) (pow (s (s zero)) x))))
(declare-fun fib (nat) nat)
(assert (= (fib zero) zero))
(assert (= (fib (s zero)) (s zero)))
(assert (forall ((n nat)) (= (fib (s (s n))) (plus (fib (s n)) (fib n)))))
(declare-fun in_range (nat nat nat) Bool)
(assert (forall ((x nat) (y nat) (z nat)) (= (in_range x y z) (and (leq y x) (leq x z)))))
(declare-fun div2 (nat) nat)
(assert (= (div2 zero) zero))
(assert (= (div2 (s zero)) zero))
(assert (forall ((n nat)) (= (div2 (s (s n))) (s (div2 n)))))
(declare-fun append ((list A) (list A)) (list A))
(assert (forall ((ys (list A))) (= (append (as Nil (list A)) ys) ys)))
(assert (forall ((x A) (xs (list A)) (ys (list A))) (= (append (Cons x xs) ys) (Cons x (append xs ys)))))
(define-fun-rec append2 ((x (list A)) (y (list A))) (list A)
  (ite ((_ is Nil) x) y (Cons (Cons_0 x) (append2 (Cons_1 x) y))))
(declare-fun len ((list A)) nat)
(assert (= (len (as Nil (list A))) zero))
(assert (forall ((x A) (xs (list A))) (= (len (Cons x xs)) (s (len xs)))))
(declare-fun rev ((list A)) (list A))
(assert (= (rev (as Nil (list A))) (as Nil (list A))))
(assert (forall ((x A) (xs (list A))) (= (rev (Cons x xs)) (append (rev xs) (Cons x (as Nil (list A)))))))
(declare-fun itrev ((list A) (list A)) (list A))
(assert (forall ((ys (list A))) (= (itrev (as Nil (list A)) ys) ys)))
(assert (forall ((x A) (xs (list A)) (ys (list A))) (= (itrev (Cons x xs) ys) (itrev xs (Cons x ys)))))
(declare-fun nth ((list A) nat) A)
(assert (forall ((x A) (xs (list A)) (n nat)) (= (nth (Cons x xs) n) (match n
  ((zero x)
   ((s k) (nth xs k)))))))
(declare-fun upd ((list A) nat A) (list A))
(assert (forall ((n nat) (x A)) (= (upd (as Nil (list A)) n x) (as Nil (list A)))))
(assert (forall ((x A) (xs (list A)) (n nat) (y A)) (= (upd (Cons x xs) n y) (match n
  ((zero (Cons y xs))
   ((s j) (Cons x (upd xs j y))))))))
; extensionality
(assert (forall ((xs (list A)) (ys (list A))) (= (= xs ys) (and (= (len xs) (len ys))
  (forall ((i nat)) (=> (less i (len xs)) (= (nth xs i) (nth ys i))))))))
(declare-fun butlast ((list A)) (list A))
(assert (= (butlast (as Nil (list A))) (as Nil (list A))))
(assert (forall ((x A) (xs (list A))) (= (butlast (Cons x xs))
  (ite (= xs (as Nil (list A))) (as Nil (list A)) (Cons x (butlast xs))))))
(declare-fun hd ((list A)) A)
(assert (forall ((x A) (xs (list A))) (= (hd (Cons x xs)) x)))
(declare-fun tl ((list A)) (list A))
(assert (= (tl (as Nil (list A))) (as Nil (list A))))
(assert (forall ((x A) (xs (list A))) (= (tl (Cons x xs)) xs)))
(declare-fun replicate (nat A) (list A))
(assert (forall ((x A)) (= (replicate zero x) (as Nil (list A)))))
(assert (forall ((n nat) (x A)) (= (replicate (s n) x) (Cons x (replicate n x)))))
(declare-fun T_append ((list A) (list A)) nat)
(assert (forall ((ys (list A))) (= (T_append (as Nil (list A)) ys) (s zero))))
(assert (forall ((x A) (xs (list A)) (ys (list A))) (= (T_append (Cons x xs) ys) (s (T_append xs ys)))))
(declare-fun T_rev ((list A)) nat)
(assert (= (T_rev (as Nil (list A))) (s zero)))
(assert (forall ((x A) (xs (list A))) (= (T_rev (Cons x xs)) (s (plus (T_rev xs) (T_append (rev xs) (Cons x (as Nil (list A)))))))))
(declare-fun T_itrev ((list A) (list A)) nat)
(assert (forall ((ys (list A))) (= (T_itrev (as Nil (list A)) ys) (s zero))))
(assert (forall ((x A) (xs (list A)) (ys (list A))) (= (T_itrev (Cons x xs) ys) (s (T_itrev xs (Cons x ys))))))
(declare-fun sorted ((list A)) Bool)
(assert (sorted (as Nil (list A))))
(assert (forall ((x A) (xs (list A))) (= (sorted (Cons x xs)) (and (forall ((y A)) (=> (in_set y xs) (leq x y))) (sorted xs)))))
; this (strict) variant is used for trees where each element can be present in a tree only once
(declare-fun sorted_s ((list A)) Bool)
(assert (sorted_s (as Nil (list A))))
(assert (forall ((x A)) (sorted_s (Cons x (as Nil (list A))))))
(assert (forall ((x A) (y A) (zs (list A))) (= (sorted_s (Cons x (Cons y zs))) (and (less x y) (sorted_s (Cons y zs))))))
(declare-fun Ball_sorted ((lists A)) Bool)
(assert (Ball_sorted (as Nil (lists A))))
(assert (forall ((xs (list A)) (xss (lists A))) (= (Ball_sorted (Cons xs xss)) (and (sorted xs) (Ball_sorted xss)))))
(declare-fun insort (A (list A)) (list A))
(assert (forall ((x A)) (= (insort x (as Nil (list A))) (Cons x (as Nil (list A))))))
(assert (forall ((x A) (y A) (ys (list A))) (= (insort x (Cons y ys)) (ite (leq x y) (Cons x (Cons y ys)) (Cons y (insort x ys))))))
(declare-fun isort ((list A)) (list A))
(assert (= (isort (as Nil (list A))) (as Nil (list A))))
(assert (forall ((x A) (xs (list A))) (= (isort (Cons x xs)) (insort x (isort xs)))))
(declare-fun T_insort (A (list A)) nat)
(assert (forall ((x A)) (= (T_insort x (as Nil (list A))) (s zero))))
(assert (forall ((x A) (y A) (ys (list A))) (= (T_insort x (Cons y ys)) (s (ite (leq x y) zero (T_insort x ys))))))
(declare-fun T_isort ((list A)) nat)
(assert (= (T_isort (as Nil (list A))) (s zero)))
(assert (forall ((x A) (xs (list A))) (= (T_isort (Cons x xs)) (s (plus (T_isort xs) (T_insort x (isort xs)))))))
(declare-fun quicksort ((list A)) (list A))
(assert (= (quicksort (as Nil (list A))) (as Nil (list A))))
(assert (forall ((x A) (xs (list A))) (= (quicksort (Cons x xs))
  (append (quicksort (filter_less x xs)) (append (Cons x (as Nil (list A))) (quicksort (filter_ge x xs)))))))
(declare-fun quicksort2 ((list A) (list A)) (list A))
(assert (forall ((ys (list A))) (= (quicksort2 (as Nil (list A)) ys) ys)))
(assert (forall ((x A) (xs (list A)) (ys (list A))) (= (quicksort2 (Cons x xs) ys)
  (quicksort2 (filter_less x xs) (Cons x (quicksort2 (filter_ge x xs) ys))))))
(declare-fun partition3 (A (list A)) (triple (list A) (list A) (list A)))
(assert (forall ((x A) (xs (list A))) (= (partition3 x xs)
  (Triple (filter_less x xs) (filter_eq x xs) (filter_greater x xs)))))
(declare-fun quicksort3 ((list A)) (list A))
(assert (= (quicksort3 (as Nil (list A))) (as Nil (list A))))
(assert (forall ((x A) (xs (list A))) (= (quicksort3 (Cons x xs)) (let ((t (partition3 x xs)))
  (append (quicksort3 (Triple_0 t)) (append (Cons x (Triple_1 t)) (quicksort3 (Triple_2 t))))))))
(declare-fun T_quicksort ((list A)) nat)
(assert (= (T_quicksort (as Nil (list A))) (s zero)))
(assert (forall ((x A) (xs (list A))) (= (T_quicksort (Cons x xs))
  (s (plus (T_quicksort (filter_less x xs)) (plus (T_quicksort (filter_ge x xs)) (mult (s (s zero)) (len xs))))))))
(declare-fun merge ((list A) (list A)) (list A))
(assert (forall ((ys (list A))) (= (merge (as Nil (list A)) ys) ys)))
(assert (forall ((xs (list A))) (= (merge xs (as Nil (list A))) xs)))
(assert (forall ((x A) (xs (list A)) (y A) (ys (list A))) (= (merge (Cons x xs) (Cons y ys))
  (ite (leq x y) (Cons x (merge xs (Cons y ys))) (Cons y (merge (Cons x xs) ys))))))
(declare-fun take (nat (list A)) (list A))
(assert (forall ((xs (list A))) (= (take zero xs) (as Nil (list A)))))
(assert (forall ((n nat)) (= (take n (as Nil (list A))) (as Nil (list A)))))
(assert (forall ((n nat) (x A) (xs (list A))) (= (take (s n) (Cons x xs)) (Cons x (take n xs)))))
(declare-fun drop (nat (list A)) (list A))
(assert (forall ((xs (list A))) (= (drop zero xs) xs)))
(assert (forall ((n nat)) (= (drop n (as Nil (list A))) (as Nil (list A)))))
(assert (forall ((n nat) (x A) (xs (list A))) (= (drop (s n) (Cons x xs)) (drop n xs))))
(declare-fun msort ((list A)) (list A))
(assert (forall ((xs (list A))) (= (msort xs) (let ((n (len xs))) (ite (leq n (s zero)) xs
  (merge (msort (take (div2 n) xs)) (msort (drop (div2 n) xs))))))))
(declare-fun C_merge ((list A) (list A)) nat)
(assert (forall ((ys (list A))) (= (C_merge (as Nil (list A)) ys) zero)))
(assert (forall ((xs (list A))) (= (C_merge xs (as Nil (list A))) zero)))
(assert (forall ((x A) (xs (list A)) (y A) (ys (list A))) (= (C_merge (Cons x xs) (Cons y ys))
  (s (ite (leq x y) (C_merge xs (Cons y ys)) (C_merge (Cons x xs) ys))))))
(declare-fun C_msort ((list A)) nat)
(assert (forall ((xs (list A))) (= (C_msort xs) (let ((n (len xs))) (let ((ys (take (div2 n) xs)) (zs (drop (div2 n) xs)))
  (ite (leq n (s zero)) zero (plus (plus (C_msort ys) (C_msort zs)) (C_merge (msort ys) (msort zs)))))))))
(declare-fun halve ((list A) (list A) (list A)) (pair (list A) (list A)))
(assert (forall ((xs (list A)) (ys (list A))) (= (halve (as Nil (list A)) xs ys) (Pair xs ys))))
(assert (forall ((x A) (xs (list A)) (ys (list A))) (= (halve (Cons x (as Nil (list A))) xs ys) (Pair (Cons x xs) ys))))
(assert (forall ((x A) (y A) (zs (list A)) (xs (list A)) (ys (list A))) (= (halve (Cons x (Cons y zs)) xs ys) (halve zs (Cons x xs) (Cons y ys)))))
(declare-fun msort2 ((list A)) (list A))
(assert (= (msort2 (as Nil (list A))) (as Nil (list A))))
(assert (forall ((x A)) (= (msort2 (Cons x (as Nil (list A)))) (Cons x (as Nil (list A))))))
(assert (forall ((x1 A) (x2 A) (xs (list A))) (= (msort2 (Cons x1 (Cons x2 xs)))
  (let ((p (halve (Cons x1 (Cons x2 xs)) (as Nil (list A)) (as Nil (list A))))) (merge (msort2 (Pair_0 p)) (msort2 (Pair_1 p)))))))
(declare-fun merge_adj ((lists A)) (lists A))
(assert (= (merge_adj (as Nil (lists A))) (as Nil (lists A))))
(assert (forall ((xs (list A))) (= (merge_adj (Cons xs (as Nil (lists A)))) (Cons xs (as Nil (lists A))))))
(assert (forall ((xs (list A)) (ys (list A)) (zss (lists A))) (= (merge_adj (Cons xs (Cons ys zss))) (Cons (merge xs ys) (merge_adj zss)))))
(declare-fun merge_all ((lists A)) (list A))
(assert (= (merge_all (as Nil (lists A))) (as Nil (list A))))
(assert (forall ((xs (list A))) (= (merge_all (Cons xs (as Nil (lists A)))) xs)))
(assert (forall ((xs (list A)) (xss (lists A))) (=> (distinct xss (Cons xs (as Nil (lists A)))) (= (merge_all xss) (merge_all (merge_adj xss))))))
(declare-fun msort_bu ((list A)) (list A))
(assert (forall ((xs (list A))) (= (msort_bu xs) (merge_all (map_list_lists xs)))))
(declare-fun C_merge_adj ((lists A)) nat)
(assert (= (C_merge_adj (as Nil (lists A))) zero))
(assert (forall ((xs (list A))) (= (C_merge_adj (Cons xs (as Nil (lists A)))) zero)))
(assert (forall ((xs (list A)) (ys (list A)) (zss (lists A))) (= (C_merge_adj (Cons xs (Cons ys zss))) (plus (C_merge xs ys) (C_merge_adj zss)))))
(declare-fun C_merge_all ((lists A)) nat)
(assert (= (C_merge_all (as Nil (lists A))) zero))
(assert (forall ((xs (list A))) (= (C_merge_all (Cons xs (as Nil (lists A)))) zero)))
(assert (forall ((xs (list A)) (xss (lists A))) (=> (and (distinct xss (Cons xs (as Nil (lists A)))) (distinct xss (as Nil (lists A))))
  (= (C_merge_all xss) (plus (C_merge_adj xss) (C_merge_all (merge_adj xss)))))))
(declare-fun C_msort_bu ((list A)) nat)
(assert (forall ((xs (list A))) (= (C_msort_bu xs) (C_merge_all (map_list_lists xs)))))
(declare-fun even (nat) Bool)
(assert (even zero))
(assert (forall ((x nat)) (= (even (s x)) (not (even x)))))
(declare-fun odd (nat) Bool)
(assert (not (odd zero)))
(assert (forall ((x nat)) (= (odd (s x)) (not (odd x)))))
(declare-fun runs ((list A)) (lists A))
(assert (= (runs (as Nil (list A))) (as Nil (lists A))))
(assert (forall ((x A)) (= (runs (Cons x (as Nil (list A)))) (Cons (Cons x (as Nil (list A))) (as Nil (lists A))))))
(declare-fun desc (A (list A) (list A)) (lists A))
(assert (forall ((x A) (xs (list A))) (= (desc x xs (as Nil (list A))) (Cons (Cons x xs) (as Nil (lists A))))))
(assert (forall ((x A) (xs (list A)) (y A) (ys (list A))) (= (desc x xs (Cons y ys))
  (ite (less y x) (desc y (Cons x xs) ys) (Cons (Cons x xs) (runs (Cons y ys)))))))
(declare-fun nmsort ((list A)) (list A))
(assert (forall ((xs (list A))) (= (nmsort xs) (merge_all (runs xs)))))
(declare-fun C_runs ((list A)) nat)
(declare-fun C_asc (A (list A)) nat)
(assert (forall ((x A)) (= (C_asc x (as Nil (list A))) zero)))
(assert (forall ((x A) (y A) (ys (list A))) (= (C_asc x (Cons y ys)) (s (ite (not (less y x)) (C_asc y ys) (C_runs (Cons y ys)))))))
(declare-fun C_desc (A (list A)) nat)
(assert (forall ((x A)) (= (C_desc x (as Nil (list A))) zero)))
(assert (forall ((x A) (y A) (ys (list A))) (= (C_desc x (Cons y ys)) (s (ite (less y x) (C_desc y ys) (C_runs (Cons y ys)))))))
(assert (= (C_runs (as Nil (list A))) zero))
(assert (forall ((x A)) (= (C_runs (Cons x (as Nil (list A)))) zero)))
(assert (forall ((x A) (y A) (xs (list A))) (= (C_runs (Cons x (Cons y xs))) (s (ite (less y x) (C_desc y xs) (C_asc y xs))))))
(declare-fun C_nmsort ((list A)) nat)
(assert (forall ((xs (list A))) (= (C_nmsort xs) (plus (C_runs xs) (C_merge_all (runs xs))))))
(declare-fun concat ((lists A)) (list A))
(assert (= (concat (as Nil (lists A))) (as Nil (list A))))
(assert (forall ((xs (list A)) (xss (lists A))) (= (concat (Cons xs xss)) (append xs (concat xss)))))
(declare-fun lg (nat) Real)
(declare-fun ceil (Real) nat)
(declare-fun floor (Real) nat)
(declare-fun median ((list A)) A)
(declare-fun chop (nat (list nat)) (lists nat))
(declare-fun min (nat nat) nat)
(assert (forall ((x nat) (y nat)) (= (min x y) (ite (leq x y) x y))))
(declare-fun max (A A) A)
(assert (forall ((x A) (y A)) (= (max x y) (ite (leq x y) y x))))

(declare-fun inorder ((tree A)) (list A))
(assert (= (inorder (as Leaf (tree A))) (as Nil (list A))))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (inorder (Node l x r)) (append (inorder l) (append (Cons x (as Nil (list A))) (inorder r))))))
(declare-fun inorder2 ((tree A) (list A)) (list A))
(assert (forall ((xs (list A))) (= (inorder2 (as Leaf (tree A)) xs) xs)))
(assert (forall ((l (tree A)) (x A) (r (tree A)) (xs (list A))) (= (inorder2 (Node l x r) xs) (inorder2 l (Cons x (inorder2 r xs))))))
(declare-fun preorder ((tree A)) (list A))
(assert (= (preorder (as Leaf (tree A))) (as Nil (list A))))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (preorder (Node l x r)) (Cons x (append (preorder l) (preorder r))))))
(declare-fun size ((tree A)) nat)
(assert (= (size (as Leaf (tree A))) zero))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (size (Node l x r)) (s (plus (size l) (size r))))))
(declare-fun size1 ((tree A)) nat)
(assert (= (size1 (as Leaf (tree A))) (s zero)))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (size1 (Node l x r)) (plus (size1 l) (size1 r)))))
(declare-fun h ((tree A)) nat)
(assert (= (h (as Leaf (tree A))) zero))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (h (Node l x r)) (s (max (h l) (h r))))))
(declare-fun mh ((tree A)) nat)
(assert (= (mh (as Leaf (tree A))) zero))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (mh (Node l x r)) (s (min (mh l) (mh r))))))
(declare-fun lh ((tree A)) nat)
(assert (= (lh (as Leaf (tree A))) zero))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (lh (Node l x r)) (s (lh l)))))
(declare-fun complete ((tree A)) Bool)
(assert (complete (as Leaf (tree A))))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (complete (Node l x r)) (and (= (h l) (h r)) (complete l) (complete r)))))
(declare-fun acomplete ((tree A)) Bool)
(assert (forall ((t (tree A))) (= (acomplete t) (leq (minus (h t) (mh t)) (s zero)))))
(declare-fun balance (nat (list A)) (pair (tree A) (list A)))
(assert (forall ((n nat) (xs (list A))) (= (balance n xs) (ite (= n zero) (Pair (as Leaf (tree A)) xs)
  (let ((m (div2 n))) (let ((lys (balance m xs))) (let ((rzs (balance (minus n (s m)) (Cons_1 (Pair_1 lys)))))
    (Pair (Node (Pair_0 lys) (Cons_0 (Pair_1 lys)) (Pair_0 rzs)) (Pair_1 rzs)))))))))
(declare-fun bal_list (nat (list A)) (tree A))
(assert (forall ((n nat) (xs (list A))) (= (bal_list n xs) (Pair_0 (balance n xs)))))
(declare-fun balance_list ((list A)) (tree A))
(assert (forall ((xs (list A))) (= (balance_list xs) (bal_list (len xs) xs))))
(declare-fun bal_tree (nat (tree A)) (tree A))
(assert (forall ((n nat) (t (tree A))) (= (bal_tree n t) (bal_list n (inorder t)))))
(declare-fun balance_tree ((tree A)) (tree A))
(assert (forall ((t (tree A))) (= (balance_tree t) (bal_tree (size t) t))))
(declare-fun bst ((tree A)) Bool)
(assert (bst (as Leaf (tree A))))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (bst (Node l x r))
  (and (forall ((y A)) (=> (in_set_tree y l) (less y x))) (forall ((y A)) (=> (in_set_tree y r) (less x y))) (bst l) (bst r)))))
(declare-fun cmp (A A) cmp_val)
(assert (forall ((x A) (y A)) (= (cmp x y) (ite (less x y) LT (ite (= x y) EQ GT)))))
(declare-fun isin ((tree A) A) Bool)
(assert (forall ((x A)) (not (isin (as Leaf (tree A)) x))))
(assert (forall ((x A) (l (tree A)) (y A) (r (tree A))) (= (isin (Node l y r) x)
  (match (cmp x y) ((LT (isin l x)) (EQ true) (GT (isin r x)))))))
(declare-fun insert (A (tree A)) (tree A))
(assert (forall ((x A)) (= (insert x (as Leaf (tree A))) (Node (as Leaf (tree A)) x (as Leaf (tree A))))))
(assert (forall ((x A) (l (tree A)) (y A) (r (tree A))) (= (insert x (Node l y r))
  (match (cmp x y) ((LT (Node (insert x l) y r))
                    (EQ (Node l y r))
                    (GT (Node l y (insert x r))))))))
(declare-fun split_min ((tree A)) (pair A (tree A)))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (split_min (Node l x r))
  (ite (= l (as Leaf (tree A))) (Pair x r) (let ((xl (split_min l))) (Pair (Pair_0 xl) (Node (Pair_1 xl) x r)))))))
(declare-fun delete (A (tree A)) (tree A))
(assert (forall ((x A)) (= (delete x (as Leaf (tree A))) (as Leaf (tree A)))))
(assert (forall ((x A) (l (tree A)) (y A) (r (tree A))) (= (delete x (Node l y r))
  (match (cmp x y) ((LT (Node (delete x l) y r))
                    (EQ (ite (= r (as Leaf (tree A))) l (let ((ar (split_min r))) (Node l (Pair_0 ar) (Pair_1 ar)))))
                    (GT (Node l y (delete x r))))))))

(declare-fun join ((tree A) (tree A)) (tree A))
(assert (forall ((t (tree A))) (= (join t (as Leaf (tree A))) t)))
(assert (forall ((t (tree A))) (= (join (as Leaf (tree A)) t) t)))
(assert (forall ((t1 (tree A)) (x A) (t2 (tree A)) (t3 (tree A)) (y A) (t4 (tree A))) (= (join (Node t1 x t2) (Node t3 y t4))
  (match (join t2 t3)
    ((Leaf (Node t1 x (Node (as Leaf (tree A)) y t4)))
     ((Node u2 z u3) (Node (Node t1 x u2) z (Node u3 y t4))))))))
(declare-fun delete2 (A (tree A)) (tree A))
(assert (forall ((x A)) (= (delete2 x (as Leaf (tree A))) (as Leaf (tree A)))))
(assert (forall ((x A) (l (tree A)) (y A) (r (tree A))) (= (delete2 x (Node l y r))
  (match (cmp x y) ((LT (Node (delete2 x l) y r))
                    (EQ (join l r))
                    (GT (Node l y (delete2 x r))))))))

(declare-fun join0 ((tree A) (tree A)) (tree A))
(assert (forall ((t (tree A))) (= (join0 t (as Leaf (tree A))) t)))
(assert (forall ((t (tree A))) (= (join0 (as Leaf (tree A)) t) t)))
(assert (forall ((t1 (tree A)) (x A) (t2 (tree A)) (t3 (tree A)) (y A) (t4 (tree A)))
  (= (join0 (Node t1 x t2) (Node t3 y t4)) (Node t1 x (Node (join0 t2 t3) y t4)))))

(declare-fun ins_list (A (list A)) (list A))
(assert (forall ((x A)) (= (ins_list x (as Nil (list A))) (Cons x (as Nil (list A))))))
(assert (forall ((x A) (y A) (xs (list A))) (= (ins_list x (Cons y xs))
  (ite (less x y) (Cons x (Cons y xs)) (ite (= x y) (Cons y xs) (Cons y (ins_list x xs)))))))
(declare-fun del_list (A (list A)) (list A))
(assert (forall ((x A)) (= (del_list x (as Nil (list A))) (as Nil (list A)))))
(assert (forall ((x A) (y A) (xs (list A))) (= (del_list x (Cons y xs)) (ite (= x y) xs (Cons y (del_list x xs))))))

; interval trees
; this function is supposed to be the minimal element of type 'a'
(declare-const bot A)
(declare-fun low ((ivl A)) A)
(assert (forall ((x (ivl A))) (= (low x) (Pair_0 x))))
(declare-fun high ((ivl A)) A)
(assert (forall ((x (ivl A))) (= (high x) (Pair_1 x))))
; comparison overrides
(assert (forall ((x (ivl A)) (y (ivl A))) (= (less x y) (or (less (low x) (low y))
  (and (= (low x) (low y)) (less (high x) (high y)))))))
(assert (forall ((x (ivl A)) (y (ivl A))) (= (leq x y) (or (less (low x) (low y))
  (and (= (low x) (low y)) (leq (high x) (high y)))))))
(declare-fun isinp ((ptree A B) A) Bool)
(assert (forall ((x A)) (not (isinp (as Leaf (ptree A B)) x))))
(assert (forall ((l (ptree A B)) (x A) (y B) (r (ptree A B)) (z A)) (= (isinp (NodeP l x y r) z)
  (match (cmp z x) ((LT (isinp l z)) (EQ true) (GT (isinp r z)))))))
(declare-fun max_hi ((itree A)) A)
(assert (= (max_hi (as Leaf (ptree (ivl A) A))) (as bot A)))
(assert (forall ((l (itree A)) (x (ivl A)) (m A) (r (itree A))) (= (max_hi (NodeP l x m r)) m)))
(declare-fun max3 ((ivl A) A A) A)
(assert (forall ((x (ivl A)) (y A) (z A)) (= (max3 x y z) (max (high x) (max y z)))))
(declare-fun node_ivl ((itree A) (ivl A) (itree A)) (itree A))
(assert (forall ((l (itree A)) (x (ivl A)) (r (itree A))) (= (node_ivl l x r)
  (NodeP l x (max3 x (max_hi l) (max_hi r)) r))))
(declare-fun inv_max_hi ((itree A)) Bool)
(assert (inv_max_hi (as Leaf (ptree (ivl A) A))))
(assert (forall ((l (itree A)) (x (ivl A)) (m A) (r (itree A))) (= (inv_max_hi (NodeP l x m r))
  (and (= m (max3 x (max_hi l) (max_hi r))) (inv_max_hi l) (inv_max_hi r)))))
(declare-fun inorderp ((ptree A B)) (list A))
(assert (= (inorderp (as Leaf (ptree A B))) (as Nil (list A))))
(assert (forall ((l (ptree A B)) (x A) (y B) (r (ptree A B))) (= (inorderp (NodeP l x y r))
  (append (inorderp l) (append (Cons x (as Nil (list A))) (inorderp r))))))
(declare-fun insert_ivl ((ivl A) (itree A)) (itree A))
(assert (forall ((x (ivl A))) (= (insert_ivl x (as Leaf (ptree (ivl A) A))) (NodeP (as Leaf (ptree (ivl A) A)) x (high x) (as Leaf (ptree (ivl A) A))))))
(assert (forall ((x (ivl A)) (l (itree A)) (y (ivl A)) (z A) (r (itree A))) (= (insert_ivl x (NodeP l y z r))
  (match (cmp x y) ((LT (node_ivl (insert_ivl x l) y r))
                    (EQ (NodeP l y z r))
                    (GT (node_ivl l y (insert_ivl x r))))))))
(declare-fun split_min_ivl ((itree A)) (pair (ivl A) (itree A)))
(assert (forall ((l (itree A)) (x (ivl A)) (y A) (r (itree A))) (= (split_min_ivl (NodeP l x y r))
  (ite (= l (as Leaf (ptree (ivl A) A))) (Pair x r) (let ((xl (split_min_ivl l)))
    (Pair (Pair_0 xl) (node_ivl (Pair_1 xl) x r)))))))
(declare-fun delete_ivl ((ivl A) (itree A)) (itree A))
(assert (forall ((x (ivl A))) (= (delete_ivl x (as Leaf (ptree (ivl A) A))) (as Leaf (ptree (ivl A) A)))))
(assert (forall ((x (ivl A)) (l (itree A)) (y (ivl A)) (z A) (r (itree A))) (= (delete_ivl x (NodeP l y z r))
  (match (cmp x y) ((LT (node_ivl (delete_ivl x l) y r))
                    (EQ (ite (= r (as Leaf (ptree (ivl A) A))) l (let ((xy (split_min_ivl r)))
                      (node_ivl l (Pair_0 xy) (Pair_1 xy)))))
                    (GT (node_ivl l y (delete_ivl x r))))))))

; 2-3 trees
(declare-fun size23 ((tree23 A)) nat)
(assert (= (size23 (as Leaf23 (tree23 A))) zero))
(assert (forall ((l (tree23 A)) (x A) (r (tree23 A))) (= (size23 (Node2 l x r)) (s (plus (size23 l) (size23 r))))))
(assert (forall ((l (tree23 A)) (x A) (m (tree23 A)) (y A) (r (tree23 A)))
  (= (size23 (Node3 l x m y r)) (s (plus (size23 l) (plus (size23 m) (size23 r)))))))
(declare-fun h23 ((tree23 A)) nat)
(assert (= (h23 (as Leaf23 (tree23 A))) zero))
(assert (forall ((l (tree23 A)) (x A) (r (tree23 A))) (= (h23 (Node2 l x r)) (s (max (h23 l) (h23 r))))))
(assert (forall ((l (tree23 A)) (x A) (m (tree23 A)) (y A) (r (tree23 A))) (= (h23 (Node3 l x m y r)) (s (max (h23 l) (max (h23 m) (h23 r)))))))
(declare-fun hD ((upD A)) nat)
(assert (forall ((t (tree23 A))) (= (hD (TD t)) (h23 t))))
(assert (forall ((t (tree23 A))) (= (hD (UF t)) (s (h23 t)))))
(declare-fun complete23 ((tree23 A)) Bool)
(assert (complete23 (as Leaf23 (tree23 A))))
(assert (forall ((l (tree23 A)) (x A) (r (tree23 A))) (= (complete23 (Node2 l x r))
  (and (= (h23 l) (h23 r)) (complete23 l) (complete23 r)))))
(assert (forall ((l (tree23 A)) (x A) (m (tree23 A)) (y A) (r (tree23 A))) (= (complete23 (Node3 l x m y r))
  (and (= (h23 l) (h23 m)) (= (h23 m) (h23 r)) (complete23 l) (complete23 m) (complete23 r)))))
(declare-fun isin23 ((tree23 A) A) Bool)
(assert (forall ((x A)) (not (isin23 (as Leaf23 (tree23 A)) x))))
(assert (forall ((x A) (l (tree23 A)) (y A) (r (tree23 A))) (= (isin23 (Node2 l y r) x)
  (match (cmp x y) ((LT (isin23 l x)) (EQ true) (GT (isin23 r x)))))))
(assert (forall ((x A) (l (tree23 A)) (y A) (m (tree23 A)) (z A) (r (tree23 A))) (= (isin23 (Node3 l y m z r) x)
  (match (cmp x y) ((LT (isin23 l x)) (EQ true) (GT
  (match (cmp x z) ((LT (isin23 m x)) (EQ true) (GT (isin23 r x))))))))))

(declare-fun inorder23 ((tree23 A)) (list A))
(assert (= (inorder23 (as Leaf23 (tree23 A))) (as Nil (list A))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A))) (= (inorder23 (Node2 t1 x t2))
  (append (inorder23 t1) (append (Cons x (as Nil (list A))) (inorder23 t2))))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A))) (= (inorder23 (Node3 t1 x t2 y t3))
  (append (inorder23 t1) (append (Cons x (as Nil (list A))) (append (inorder23 t2) (append (Cons y (as Nil (list A))) (inorder23 t3))))))))
(declare-fun treeI ((upI A)) (tree23 A))
(assert (forall ((t (tree23 A))) (= (treeI (TI t)) t)))
(assert (forall ((l (tree23 A)) (x A) (r (tree23 A))) (= (treeI (OF l x r)) (Node2 l x r))))
(declare-fun treeD ((upD A)) (tree23 A))
(assert (forall ((t (tree23 A))) (= (treeD (TD t)) t)))
(assert (forall ((t (tree23 A))) (= (treeD (UF t)) t)))
(declare-fun ins (A (tree23 A)) (upI A))
(assert (forall ((x A)) (= (ins x (as Leaf23 (tree23 A))) (OF (as Leaf23 (tree23 A)) x (as Leaf23 (tree23 A))))))
(assert (forall ((x A) (l (tree23 A)) (y A) (r (tree23 A))) (= (ins x (Node2 l y r))
  (match (cmp x y) ((LT (match (ins x l) (((TI ll) (TI (Node2 ll y r)))
                                          ((OF l1 z l2) (TI (Node3 l1 z l2 y r))))))
                    (EQ (TI (Node2 l y r)))
                    (GT (match (ins x r) (((TI rr) (TI (Node2 l y rr)))
                                          ((OF r1 z r2) (TI (Node3 l y r1 z r2)))))))))))
(assert (forall ((x A) (l (tree23 A)) (y A) (m (tree23 A)) (z A) (r (tree23 A))) (= (ins x (Node3 l y m z r))
  (match (cmp x y) ((LT (match (ins x l) (((TI ll) (TI (Node3 ll y m z r)))
                                          ((OF l1 u l2) (OF (Node2 l1 u l2) y (Node2 m z r))))))
                    (EQ (TI (Node3 l y m z r)))
                    (GT (match (cmp x z) ((LT (match (ins x m) (((TI mm) (TI (Node3 l y mm z r)))
                                                                ((OF m1 u m2) (OF (Node2 l y m1) u (Node2 m2 z r))))))
                                          (EQ (TI (Node3 l y m z r)))
                                          (GT (match (ins x r) (((TI rr) (TI (Node3 l y m z rr)))
                                                                ((OF r1 u r2) (OF (Node2 l y m) z (Node2 r1 u r2))))))))))))))
(declare-fun insert23 (A (tree23 A)) (tree23 A))
(assert (forall ((x A) (t (tree23 A))) (= (insert23 x t) (treeI (ins x t)))))
(declare-fun hI ((upI A)) nat)
(assert (forall ((t (tree23 A))) (= (hI (TI t)) (h23 t))))
(assert (forall ((l (tree23 A)) (x A) (r (tree23 A))) (= (hI (OF l x r)) (h23 l))))
(declare-fun node21 ((upD A) A (tree23 A)) (upD A))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A))) (= (node21 (TD t1) x t2) (TD (Node2 t1 x t2)))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A))) (= (node21 (UF t1) x (Node2 t2 y t3)) (UF (Node3 t1 x t2 y t3)))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A)) (z A) (t4 (tree23 A)))
  (= (node21 (UF t1) x (Node3 t2 y t3 z t4)) (TD (Node2 (Node2 t1 x t2) y (Node2 t3 z t4))))))
(declare-fun node22 ((tree23 A) A (upD A)) (upD A))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A))) (= (node22 t1 x (TD t2)) (TD (Node2 t1 x t2)))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A))) (= (node22 (Node2 t1 x t2) y (UF t3)) (UF (Node3 t1 x t2 y t3)))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A)) (z A) (t4 (tree23 A)))
  (= (node22 (Node3 t1 x t2 y t3) z (UF t4)) (TD (Node2 (Node2 t1 x t2) y (Node2 t3 z t4))))))
(declare-fun node31 ((upD A) A (tree23 A) A (tree23 A)) (upD A))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A))) (= (node31 (TD t1) x t2 y t3) (TD (Node3 t1 x t2 y t3)))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A)) (z A) (t4 (tree23 A)))
  (= (node31 (UF t1) x (Node2 t2 y t3) z t4) (TD (Node2 (Node3 t1 x t2 y t3) z t4)))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A)) (z A) (t4 (tree23 A)) (u A) (t5 (tree23 A)))
  (= (node31 (UF t1) x (Node3 t2 y t3 z t4) u t5) (TD (Node3 (Node2 t1 x t2) y (Node2 t3 z t4) u t5)))))
(declare-fun node32 ((tree23 A) A (upD A) A (tree23 A)) (upD A))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A))) (= (node32 t1 x (TD t2) y t3) (TD (Node3 t1 x t2 y t3)))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A)) (z A) (t4 (tree23 A)))
  (= (node32 t1 x (UF t2) y (Node2 t3 z t4)) (TD (Node2 t1 x (Node3 t2 y t3 z t4))))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A)) (z A) (t4 (tree23 A)) (u A) (t5 (tree23 A)))
  (= (node32 t1 x (UF t2) y (Node3 t3 z t4 u t5)) (TD (Node3 t1 x (Node2 t2 y t3) z (Node2 t4 u t5))))))
(declare-fun node33 ((tree23 A) A (tree23 A) A (upD A)) (upD A))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A))) (= (node33 t1 x t2 y (TD t3))
  (TD (Node3 t1 x t2 y t3)))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A)) (z A) (t4 (tree23 A)))
  (= (node33 t1 x (Node2 t2 y t3) z (UF t4)) (TD (Node2 t1 x (Node3 t2 y t3 z t4))))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A)) (z A) (t4 (tree23 A)) (u A) (t5 (tree23 A)))
  (= (node33 t1 x (Node3 t2 y t3 z t4) u (UF t5)) (TD (Node3 t1 x (Node2 t2 y t3) z (Node2 t4 u t5))))))
(declare-fun split_min23 ((tree23 A)) (pair A (upD A)))
(assert (forall ((x A)) (= (split_min23 (Node2 (as Leaf23 (tree23 A)) x (as Leaf23 (tree23 A)))) (Pair x (UF (as Leaf23 (tree23 A)))))))
(assert (forall ((x A) (y A)) (= (split_min23 (Node3 (as Leaf23 (tree23 A)) x (as Leaf23 (tree23 A)) y (as Leaf23 (tree23 A))))
  (Pair x (TD (Node2 (as Leaf23 (tree23 A)) y (as Leaf23 (tree23 A))))))))
(assert (forall ((l (tree23 A)) (x A) (r (tree23 A))) (=> (and (distinct l (as Leaf23 (tree23 A))) (distinct r (as Leaf23 (tree23 A))))
  (= (split_min23 (Node2 l x r))
    (let ((xl (split_min23 l))) (Pair (Pair_0 xl) (node21 (Pair_1 xl) x r)))))))
(assert (forall ((l (tree23 A)) (x A) (m (tree23 A)) (y A) (r (tree23 A))) (=> (and (distinct l (as Leaf23 (tree23 A))) (distinct m (as Leaf23 (tree23 A))) (distinct r (as Leaf23 (tree23 A))))
  (= (split_min23 (Node3 l x m y r))
    (let ((xl (split_min23 l))) (Pair (Pair_0 xl) (node31 (Pair_1 xl) x m y r)))))))
(declare-fun del (A (tree23 A)) (upD A))
(assert (forall ((x A)) (= (del x (as Leaf23 (tree23 A))) (TD (as Leaf23 (tree23 A))))))
(assert (forall ((x A) (y A)) (= (del x (Node2 (as Leaf23 (tree23 A)) y (as Leaf23 (tree23 A)))) (ite (= x y) (UF (as Leaf23 (tree23 A))) (TD (Node2 (as Leaf23 (tree23 A)) y (as Leaf23 (tree23 A))))))))
(assert (forall ((x A) (y A) (z A)) (= (del x (Node3 (as Leaf23 (tree23 A)) y (as Leaf23 (tree23 A)) z (as Leaf23 (tree23 A))))
  (TD (ite (= x y) (Node2 (as Leaf23 (tree23 A)) z (as Leaf23 (tree23 A))) (ite (= x z) (Node2 (as Leaf23 (tree23 A)) y (as Leaf23 (tree23 A))) (Node3 (as Leaf23 (tree23 A)) y (as Leaf23 (tree23 A)) z (as Leaf23 (tree23 A)))))))))
(assert (forall ((x A) (l (tree23 A)) (y A) (r (tree23 A))) (=> (and (distinct l (as Leaf23 (tree23 A))) (distinct r (as Leaf23 (tree23 A)))) (= (del x (Node2 l y r))
  (match (cmp x y) ((LT (node21 (del x l) y r))
                    (EQ (let ((ar (split_min23 r))) (node22 l (Pair_0 ar) (Pair_1 ar))))
                    (GT (node22 l y (del x r)))))))))
(assert (forall ((x A) (l (tree23 A)) (y A) (m (tree23 A)) (z A) (r (tree23 A))) (=> (and (distinct l (as Leaf23 (tree23 A))) (distinct m (as Leaf23 (tree23 A))) (distinct r (as Leaf23 (tree23 A))))
  (= (del x (Node3 l y m z r))
    (match (cmp x y) ((LT (node31 (del x l) y m z r))
                      (EQ (let ((am (split_min23 m))) (node32 l (Pair_0 am) (Pair_1 am) z r)))
                      (GT (match (cmp x z) ((LT (node32 l y (del x m) z r))
                                            (EQ (let ((br (split_min23 r))) (node33 l y m (Pair_0 br) (Pair_1 br))))
                                            (GT (node33 l y m z (del x r))))))))))))
(declare-fun delete23 (A (tree23 A)) (tree23 A))
(assert (forall ((x A) (t (tree23 A))) (= (delete23 x t) (treeD (del x t)))))

(declare-fun len23s ((tree23s A)) nat)
(assert (forall ((t (tree23 A))) (= (len23s (T t)) (s zero))))
(assert (forall ((t (tree23 A)) (x A) (ts (tree23s A))) (= (len23s (TTs t x ts)) (s (len23s ts)))))
(declare-fun in_trees ((tree23 A) (tree23s A)) Bool)
(assert (forall ((t (tree23 A)) (t' (tree23 A))) (= (in_trees t (T t')) (= t t'))))
(assert (forall ((t (tree23 A)) (t' (tree23 A)) (x A) (ts (tree23s A))) (= (in_trees t (TTs t' x ts)) (or (= t t') (in_trees t ts)))))
(declare-fun inorder23s ((tree23s A)) (list A))
(assert (forall ((t (tree23 A))) (= (inorder23s (T t)) (inorder23 t))))
(assert (forall ((t (tree23 A)) (x A) (ts (tree23s A))) (= (inorder23s (TTs t x ts)) (append (inorder23 t) (Cons x (inorder23s ts))))))
(declare-fun join_adj ((tree23s A)) (tree23s A))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A))) (= (join_adj (TTs t1 x (T t2))) (T (Node2 t1 x t2)))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A))) (= (join_adj (TTs t1 x (TTs t2 y (T t3)))) (T (Node3 t1 x t2 y t3)))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A)) (z A) (ts (tree23s A))) (= (join_adj (TTs t1 x (TTs t2 y (TTs t3 z ts))))
  (TTs (Node2 t1 x t2) y (join_adj (TTs t3 z ts))))))
(declare-fun join_all ((tree23s A)) (tree23 A))
(assert (forall ((t (tree23 A))) (= (join_all (T t)) t)))
(assert (forall ((x A) (t (tree23 A)) (ts (tree23s A))) (= (join_all (TTs t x ts)) (join_all (join_adj (TTs t x ts))))))
(declare-fun not_T ((tree23s A)) Bool)
(assert (forall ((ts (tree23s A))) (= (not_T ts) (forall ((t (tree23 A))) (distinct ts (T t))))))
(declare-fun leaves ((list A)) (tree23s A))
(assert (= (leaves (as Nil (list A))) (T (as Leaf23 (tree23 A)))))
(assert (forall ((x A) (xs (list A))) (= (leaves (Cons x xs)) (TTs (as Leaf23 (tree23 A)) x (leaves xs)))))
(declare-fun tree23_of_list ((list A)) (tree23 A))
(assert (forall ((xs (list A))) (= (tree23_of_list xs) (join_all (leaves xs)))))
(declare-fun T_join_adj ((tree23s A)) nat)
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A))) (= (T_join_adj (TTs t1 x (T t2))) (s zero))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A))) (= (T_join_adj (TTs t1 x (TTs t2 y (T t3)))) (s zero))))
(assert (forall ((t1 (tree23 A)) (x A) (t2 (tree23 A)) (y A) (t3 (tree23 A)) (z A) (ts (tree23s A)))
  (= (T_join_adj (TTs t1 x (TTs t2 y (TTs t3 z ts)))) (s (T_join_adj ts)))))
(declare-fun T_join_all ((tree23s A)) nat)
(assert (forall ((t (tree23 A))) (= (T_join_all (T t)) (s zero))))
(assert (forall ((x A) (t (tree23 A)) (ts (tree23s A))) (= (T_join_all (TTs t x ts))
  (s (plus (T_join_adj (TTs t x ts)) (T_join_all (join_adj (TTs t x ts))))))))
(declare-fun T_leaves ((list A)) nat)
(assert (= (T_leaves (as Nil (list A))) (s zero)))
(assert (forall ((x A) (xs (list A))) (= (T_leaves (Cons x xs)) (s (T_leaves xs)))))
(declare-fun T_tree23_of_list ((list A)) nat)
(assert (forall ((xs (list A))) (= (T_tree23_of_list xs) (s (plus (T_leaves xs) (T_join_all (leaves xs)))))))

; red-black trees
(declare-fun R ((rbt A) A (rbt A)) (rbt A))
(assert (forall ((l (rbt A)) (x A) (r (rbt A))) (= (R l x r) (NodeP l x Red r))))
(declare-fun Bx ((rbt A) A (rbt A)) (rbt A))
(assert (forall ((l (rbt A)) (x A) (r (rbt A))) (= (Bx l x r) (NodeP l x Black r))))
(declare-fun color_of ((rbt A)) color)
(assert (= (color_of (as Leaf (rbt A))) Black))
(assert (forall ((l (rbt A)) (x A) (c color) (r (rbt A))) (= (color_of (NodeP l x c r)) c)))
(declare-fun paint (color (rbt A)) (rbt A))
(assert (forall ((c color)) (= (paint c (as Leaf (rbt A))) (as Leaf (rbt A)))))
(assert (forall ((c color) (l (rbt A)) (x A) (d color) (r (rbt A))) (= (paint c (NodeP l x d r)) (NodeP l x c r))))
(declare-fun invc ((rbt A)) Bool)
(assert (invc (as Leaf (rbt A))))
(assert (forall ((l (rbt A)) (x A) (c color) (r (rbt A))) (= (invc (NodeP l x c r))
  (and (=> (= c Red) (and (= (color_of l) Black) (= (color_of r) Black))) (invc l) (invc r)))))
(declare-fun bh ((rbt A)) nat)
(assert (= (bh (as Leaf (rbt A))) zero))
(assert (forall ((l (rbt A)) (x A) (c color) (r (rbt A))) (= (bh (NodeP l x c r)) (ite (= c Black) (s (bh l)) (bh l)))))
(declare-fun invh ((rbt A)) Bool)
(assert (invh (as Leaf (rbt A))))
(assert (forall ((l (rbt A)) (x A) (c color) (r (rbt A))) (= (invh (NodeP l x c r)) (and (= (bh l) (bh r)) (invh l) (invh r)))))
(declare-fun inv_rbt ((rbt A)) Bool)
(assert (forall ((t (rbt A))) (= (inv_rbt t) (and (invc t) (invh t) (= (color_of t) Black)))))
(declare-fun baliL ((rbt A) A (rbt A)) (rbt A))
(assert (forall ((l (rbt A)) (t1 (rbt A)) (x A) (t2 (rbt A)) (y A) (t3 (rbt A)) (z A) (t4 (rbt A)))
  (= (baliL l z t4) (ite (or (= l (R (R t1 x t2) y t3)) (= l (R t1 x (R t2 y t3))))
    (R (Bx t1 x t2) y (Bx t3 z t4)) (Bx l z t4)))))
(declare-fun baliR ((rbt A) A (rbt A)) (rbt A))
(assert (forall ((t1 (rbt A)) (x A) (t2 (rbt A)) (y A) (t3 (rbt A)) (z A) (t4 (rbt A)) (r (rbt A)))
  (= (baliR t1 x r) (ite (or (= r (R t2 y (R t3 z t4))) (= r (R (R t2 y t3) z t4)))
    (R (Bx t1 x t2) y (Bx t3 z t4)) (Bx t1 x r)))))
(declare-fun insRB (A (rbt A)) (rbt A))
(assert (forall ((x A)) (= (insRB x (as Leaf (rbt A))) (R (as Leaf (rbt A)) x (as Leaf (rbt A))))))
(assert (forall ((x A) (l (rbt A)) (y A) (r (rbt A))) (= (insRB x (Bx l y r))
  (match (cmp x y) ((LT (baliL (insRB x l) y r))
                    (EQ (Bx l y r))
                    (GT (baliR l y (insRB x r))))))))
(assert (forall ((x A) (l (rbt A)) (y A) (r (rbt A))) (= (insRB x (R l y r))
  (match (cmp x y) ((LT (R (insRB x l) y r))
                    (EQ (R l y r))
                    (GT (R l y (insRB x r))))))))
(declare-fun insertRB (A (rbt A)) (rbt A))
(assert (forall ((x A) (t (rbt A))) (= (insertRB x t) (paint Black (insRB x t)))))
(declare-fun invc2 ((rbt A)) Bool)
(assert (forall ((t (rbt A))) (= (invc2 t) (invc (paint Black t)))))

(declare-fun baldL ((rbt A) A (rbt A)) (rbt A))
(assert (forall ((l (rbt A)) (x A) (r (rbt A)) (l1 (rbt A)) (l2 (rbt A)) (r1 (rbt A)) (r2 (rbt A)) (r3 (rbt A)) (r4 (rbt A)) (r5 (rbt A)) (xl A) (xr1 A) (xr2 A) (xr3 A))
  (= (baldL l x r) (ite (= l (R l1 xl l2)) (R (Bx l1 xl l2) x r)
    (ite (= r (Bx r1 xr1 r2)) (baliR l x (R r1 xr1 r2)) (ite (= r (R (Bx r3 xr2 r4) xr3 r5))
      (R (Bx l x r3) xr2 (baliR r4 xr3 (paint Red r5))) (R l x r)))))))
(declare-fun baldR ((rbt A) A (rbt A)) (rbt A))
(assert (forall ((l (rbt A)) (x A) (r (rbt A)) (r1 (rbt A)) (r2 (rbt A)) (l1 (rbt A)) (l2 (rbt A)) (l3 (rbt A)) (l4 (rbt A)) (l5 (rbt A)) (xr A) (xl1 A) (xl2 A) (xl3 A))
  (= (baldR l x r) (ite (= r (R r1 xr r2)) (R l x (Bx r1 xr r2))
    (ite (= l (Bx l1 xl1 l2)) (baliL (R l1 xl1 l2) x r) (ite (= l (R l3 xl2 (Bx l4 xl3 l5)))
      (R (baliL (paint Red l3) xl2 l4) xl3 (Bx l5 x r)) (R l x r)))))))
(declare-fun split_minRB ((rbt A)) (pair A (rbt A)))
(assert (forall ((l (rbt A)) (x A) (c color) (r (rbt A))) (= (split_minRB (NodeP l x c r))
  (ite (= l (as Leaf (rbt A))) (Pair x r) (let ((xl (split_minRB l)))
    (Pair (Pair_0 xl) (ite (= (color_of l) Black) (baldL (Pair_1 xl) x r) (R (Pair_1 xl) x r))))))))
(declare-fun delRB (A (rbt A)) (rbt A))
(assert (forall ((x A) (l (rbt A)) (y A) (c color) (r (rbt A))) (= (delRB x (NodeP l y c r))
  (match (cmp x y) ((LT (let ((ll (delRB x l))) (ite (and (distinct l (as Leaf (rbt A))) (= (color_of l) Black)) (baldL ll y r) (R ll y r))))
                    (EQ (ite (= r (as Leaf (rbt A))) l (let ((ar (split_minRB r))) (ite (= (color_of r) Black)
                      (baldR l (Pair_0 ar) (Pair_1 ar)) (R l (Pair_0 ar) (Pair_1 ar))))))
                    (GT (let ((rr (delRB x r))) (ite (and (distinct r (as Leaf (rbt A))) (= (color_of r) Black)) (baldR l y rr) (R l y rr)))))))))

(declare-fun deleteRB (A (rbt A)) (rbt A))
(assert (forall ((x A) (t (rbt A))) (= (deleteRB x t) (paint Black (delRB x t)))))
(declare-fun joinRB ((rbt A) (rbt A)) (rbt A))
(assert (forall ((t (rbt A))) (= (joinRB t (as Leaf (rbt A))) t)))
(assert (forall ((t (rbt A))) (= (joinRB (as Leaf (rbt A)) t) t)))
(assert (forall ((t1 (rbt A)) (x A) (t2 (rbt A)) (t3 (rbt A))) (= (joinRB t1 (R t2 x t3)) (R (joinRB t1 t2) x t3))))
(assert (forall ((t1 (rbt A)) (x A) (t2 (rbt A)) (t3 (rbt A))) (= (joinRB (R t1 x t2) t3) (R t1 x (joinRB t2 t3)))))
(declare-fun delRB2 (A (rbt A)) (rbt A))
(assert (forall ((x A) (l (rbt A)) (y A) (c color) (r (rbt A))) (= (delRB2 x (NodeP l y c r))
  (match (cmp x y) ((LT (let ((ll (delRB2 x l))) (ite (and (distinct l (as Leaf (rbt A))) (= (color_of l) Black)) (baldL ll y r) (R ll y r))))
                    (EQ (joinRB l r))
                    (GT (let ((rr (delRB2 x r))) (ite (and (distinct r (as Leaf (rbt A))) (= (color_of r) Black)) (baldR l y rr) (R l y rr)))))))))

; AVL trees
(declare-fun ht ((tree_ht A)) nat)
(assert (= (ht (as Leaf (ptree A nat))) zero))
(assert (forall ((l (tree_ht A)) (x A) (n nat) (r (tree_ht A))) (= (ht (NodeP l x n r)) n)))
(declare-fun node ((tree_ht A) A (tree_ht A)) (tree_ht A))
(assert (forall ((l (tree_ht A)) (x A) (r (tree_ht A))) (= (node l x r) (NodeP l x (s (max (ht l) (ht r))) r))))
(declare-fun avl ((tree_ht A)) Bool)
(assert (avl (as Leaf (ptree A nat))))
(assert (forall ((l (tree_ht A)) (x A) (n nat) (r (tree_ht A))) (= (avl (NodeP l x n r))
  (let ((hl (h l)) (hr (h r))) (and (or (= hl hr) (= (s hl) hr) (= hl (s hr))) (= n (s (max hl hr))) (avl l) (avl r))))))
(declare-fun balL ((tree_ht A) A (tree_ht A)) (tree_ht A))
(assert (forall ((XY (tree_ht A)) (z A) (Z (tree_ht A))) (= (balL XY z Z) (ite (= (ht XY) (s (s (ht Z))))
  (match XY (((Node X x Y) (ite (leq (ht Y) (ht X)) (node X (Pair_0 x) (node Y z Z))
                (match Y (((Node Y1 y Y2) (node (node X (Pair_0 x) Y1) (Pair_0 y) (node Y2 z Z)))
                          ((Leaf (pair A nat)) (node XY z Z))))))
             ((Leaf (pair A nat)) (node XY z Z)))) (node XY z Z)))))
(declare-fun balR ((tree_ht A) A (tree_ht A)) (tree_ht A))
(assert (forall ((X (tree_ht A)) (x A) (YZ (tree_ht A))) (= (balR X x YZ) (ite (= (ht YZ) (s (s (ht X))))
  (match YZ (((Node Y y Z) (ite (leq (ht Y) (ht Z)) (node (node X x Y) (Pair_0 y) Z)
                (match Y (((Node Y1 z Y2) (node (node X x Y1) (Pair_0 z) (node Y2 (Pair_0 y) Z)))
                          (_ (node X x YZ))))))
             (_ (node X x YZ)))) (node X x YZ)))))
(declare-fun insertAVL (A (tree_ht A)) (tree_ht A))
(assert (forall ((x A)) (= (insertAVL x (as Leaf (ptree A nat))) (NodeP (as Leaf (ptree A nat)) x (s zero) (as Leaf (ptree A nat))))))
(assert (forall ((x A) (l (tree_ht A)) (y A) (n nat) (r (tree_ht A))) (= (insertAVL x (NodeP l y n r))
  (match (cmp x y) ((LT (balL (insertAVL x l) y r))
                    (EQ (NodeP l y n r))
                    (GT (balR l y (insertAVL x r))))))))
(declare-fun split_max ((tree_ht A)) (pair (tree_ht A) A))
(assert (forall ((l (tree_ht A)) (x A) (n nat) (r (tree_ht A))) (= (split_max (NodeP l x n r))
  (ite (= r (as Leaf (ptree A nat))) (Pair l x) (let ((rx (split_max r))) (Pair (balL l x (Pair_0 rx)) (Pair_1 rx)))))))
(declare-fun deleteAVL (A (tree_ht A)) (tree_ht A))
(assert (forall ((x A)) (= (deleteAVL x (as Leaf (ptree A nat))) (as Leaf (ptree A nat)))))
(assert (forall ((x A) (l (tree_ht A)) (y A) (n nat) (r (tree_ht A))) (= (deleteAVL x (NodeP l y n r))
  (match (cmp x y) ((LT (balR (deleteAVL x l) y r))
                    (EQ (ite (= l (as Leaf (ptree A nat))) r (let ((ly (split_max l))) (balR (Pair_0 ly) (Pair_1 ly) r))))
                    (GT (balL l y (deleteAVL x r))))))))
(declare-fun fibt (nat) (tree unit))
(assert (= (fibt zero) (as Leaf (tree unit))))
(assert (= (fibt (s zero)) (Node (as Leaf (tree unit)) Unit (as Leaf (tree unit)))))
(assert (forall ((n nat)) (= (fibt (s (s n))) (Node (fibt (s n)) Unit (fibt n)))))
(declare-fun avl0 ((tree A)) Bool)
(assert (avl0 (as Leaf (tree A))))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (avl0 (Node l x r)) (and (avl0 l) (avl0 r)
  (or (= (s (h l)) (h r)) (= (h l) (h r)) (= (h l) (s (h r))))))))
(declare-fun avl_bal ((tree_bal A)) Bool)
(assert (avl_bal (as Leaf (tree_bal A))))
(assert (forall ((l (tree_bal A)) (x A) (b bal) (r (tree_bal A))) (= (avl_bal (NodeP l x b r))
  (and (match b ((Lh (= (h l) (s (h r))))
                 (Bal (= (h l) (h r)))
                 (Rh (= (s (h l)) (h r)))))
    (avl_bal l) (avl_bal r)))))
(declare-fun is_bal ((tree_bal A)) Bool)
(assert (forall ((l (tree_bal A)) (x A) (b bal) (r (tree_bal A))) (= (is_bal (NodeP l x b r)) (= b Bal))))
(declare-fun incr ((tree_bal A) (tree_bal B)) Bool)
(assert (forall ((t (tree_bal A)) (t' (tree_bal B))) (= (incr t t') (or (= t (as Leaf (tree_bal A))) (and (is_bal t) (not (is_bal t')))))))
(declare-fun decr ((tree_bal A) (tree_bal B)) Bool)
(assert (forall ((t (tree_bal A)) (t' (tree_bal B))) (= (decr t t') (and (distinct t (as Leaf (tree_bal A)))
  (or (= t' (as Leaf (tree_bal B))) (and (not (is_bal t)) (is_bal t')))))))
(declare-fun rot2 ((tree_bal A) A (tree_bal A) A (tree_bal A)) (tree_bal A))
(assert (forall ((At (tree_bal A)) (x A) (B1 (tree_bal A)) (y A) (b bal) (B2 (tree_bal A)) (z A) (C (tree_bal A)))
  (= (rot2 At x (NodeP B1 y b B2) z C) (let ((b1 (ite (= b Rh) Lh Bal)) (b2 (ite (= b Lh) Rh Bal)))
    (NodeP (NodeP At x b1 B1) y Bal (NodeP B2 z b2 C))))))
(declare-fun balL_bal ((tree_bal A) A bal (tree_bal A)) (tree_bal A))
(assert (forall ((X (tree_bal A)) (x A) (b bal) (Y (tree_bal A)) (y A) (Z (tree_bal A)))
  (= (balL_bal (NodeP X x b Y) y Lh Z) (match b
    ((Lh (NodeP X x Bal (NodeP Y y Bal Z)))
     (Bal (NodeP X x Rh (NodeP Y y Lh Z)))
     (Rh (rot2 X x Y y Z)))))))
(assert (forall ((AB (tree_bal A)) (c A) (C (tree_bal A))) (= (balL_bal AB c Bal C) (NodeP AB c Lh C))))
(assert (forall ((AB (tree_bal A)) (c A) (C (tree_bal A))) (= (balL_bal AB c Rh C) (NodeP AB c Bal C))))
(declare-fun balR_bal ((tree_bal A) A bal (tree_bal A)) (tree_bal A))
(assert (forall ((X (tree_bal A)) (x A) (b bal) (Y (tree_bal A)) (y A) (Z (tree_bal A)))
  (= (balR_bal X x Rh (NodeP Y y b Z)) (match b
    ((Lh (rot2 X x Y y Z))
     (Bal (NodeP (NodeP X x Rh Y) y Lh Z))
     (Rh (NodeP (NodeP X x Bal Y) y Bal Z)))))))
(assert (forall ((AB (tree_bal A)) (c A) (C (tree_bal A))) (= (balL_bal AB c Bal C) (NodeP AB c Lh C))))
(assert (forall ((AB (tree_bal A)) (c A) (C (tree_bal A))) (= (balL_bal AB c Rh C) (NodeP AB c Bal C))))
(declare-fun insert_bal (A (tree_bal A)) (tree_bal A))
(assert (forall ((x A)) (= (insert_bal x (as Leaf (tree_bal A))) (NodeP (as Leaf (tree_bal A)) x Bal (as Leaf (tree_bal A))))))
(assert (forall ((x A) (l (tree_bal A)) (y A) (b bal) (r (tree_bal A))) (= (insert_bal x (NodeP l y b r))
  (match (cmp x y) ((LT (let ((l' (insert_bal x l))) (ite (incr l l') (balL_bal l' y b r) (NodeP l' y b r))))
                    (EQ (NodeP l y b r))
                    (GT (let ((r' (insert_bal x r))) (ite (incr r r') (balR_bal l y b r') (NodeP l y b r')))))))))
(declare-fun split_max_bal ((tree_bal A)) (pair (tree_bal A) A))
(assert (forall ((l (tree_bal A)) (x A) (b bal) (r (tree_bal A))) (= (split_max_bal (NodeP l x b r))
  (ite (= r (as Leaf (tree_bal A))) (Pair l x) (let ((rx (split_max_bal r)))
    (let ((t (ite (decr r (Pair_0 rx)) (balL_bal l x b (Pair_0 rx))
      (NodeP l x b (Pair_0 rx))))) (Pair t (Pair_1 rx))))))))
(declare-fun delete_bal (A (tree_bal A)) (tree_bal A))
(assert (forall ((x A)) (= (delete_bal x (as Leaf (tree_bal A))) (as Leaf (tree_bal A)))))
(assert (forall ((x A) (l (tree_bal A)) (y A) (b bal) (r (tree_bal A))) (= (delete_bal x (NodeP l y b r))
  (match (cmp x y) ((LT (let ((l' (delete_bal x l))) (ite (decr l l') (balR_bal l' y b r) (NodeP l' y b r))))
                    (EQ (ite (= l (as Leaf (tree_bal A))) r (let ((ly (split_max_bal l))) (ite (decr l (Pair_0 ly))
                      (balR_bal (Pair_0 ly) (Pair_1 ly) b r)
                      (NodeP (Pair_0 ly) (Pair_1 ly) b r)))))
                    (GT (let ((r' (delete_bal x r))) (ite (decr r r') (balL_bal l y b r') (NodeP l y b r')))))))))
(declare-fun debal ((tree_bal A)) (tree_ht A))
(assert (= (debal (as Leaf (tree_bal A))) (as Leaf (ptree A nat))))
(assert (forall ((l (tree_bal A)) (x A) (b bal) (r (tree_bal A))) (= (debal (NodeP l x b r))
  (NodeP (debal l) x (s (max (h l) (h r))) (debal r)))))
(declare-fun debal2 ((tree_bal A)) (tree_ht A))

; these are supposed to be uninterpreted and defined by their specification below
(declare-fun joinp ((ptree A B) A (ptree A B)) (ptree A B))
(declare-fun invp ((ptree A B)) Bool)
(assert (forall ((l (ptree A B)) (x A) (r (ptree A B)) (y A)) (= (in_set_ptree y (joinp l x r))
  (or (in_set_ptree y l) (= x y) (in_set_ptree y r)))))
(assert (forall ((l (ptree A B)) (x A) (y B) (r (ptree A B)))
  (=> (bst (NodeP l x y r)) (bst (joinp l x r)))))
(assert (invp (as Leaf (ptree A B))))
(assert (forall ((l (ptree A B)) (x A) (r (ptree A B)))
  (=> (and (invp l) (invp r)) (invp (joinp l x r)))))
(assert (forall ((l (ptree A B)) (x A) (y B) (r (ptree A B)))
  (=> (invp (NodeP l x y r)) (and (invp l) (invp r)))))

(declare-fun split_minp ((ptree A B)) (pair A (ptree A B)))
(assert (forall ((l (ptree A B)) (x A) (y B) (r (ptree A B))) (= (split_minp (NodeP l x y r))
  (ite (= l (as Leaf (ptree A B))) (Pair x r) (let ((xl (split_minp l))) (Pair (Pair_0 xl) (joinp (Pair_1 xl) x r)))))))
(declare-fun join2 ((ptree A B) (ptree A B)) (ptree A B))
(assert (forall ((l (ptree A B)) (r (ptree A B))) (= (join2 l r) (ite (= r (as Leaf (ptree A B)))
  l (let ((mr (split_minp r))) (joinp l (Pair_0 mr) (Pair_1 mr)))))))
(declare-fun splitp ((ptree A B) A) (triple (ptree A B) Bool (ptree A B)))
(assert (forall ((x A)) (= (splitp (as Leaf (ptree A B)) x) (Triple (as Leaf (ptree A B)) false (as Leaf (ptree A B))))))
(assert (forall ((l (ptree A B)) (y A) (z B) (r (ptree A B)) (x A)) (= (splitp (NodeP l y z r) x)
  (match (cmp x y) ((LT (let ((t (splitp l x))) (Triple (Triple_0 t) (Triple_1 t) (joinp (Triple_2 t) y r))))
                    (EQ (Triple l true r))
                    (GT (let ((t (splitp r x))) (Triple (joinp l y (Triple_0 t)) (Triple_1 t) (Triple_2 t)))))))))
(declare-fun union ((ptree A B) (ptree A B)) (ptree A B))
(assert (forall ((t (ptree A B))) (= (union (as Leaf (ptree A B)) t) t)))
(assert (forall ((t (ptree A B))) (= (union t (as Leaf (ptree A B))) t)))
(assert (forall ((l1 (ptree A B)) (x A) (y B) (r1 (ptree A B)) (t (ptree A B))) (=> (distinct t (as Leaf (ptree A B))) (= (union (NodeP l1 x y r1) t)
  (let ((t' (splitp t x))) (joinp (union l1 (Triple_0 t')) x (union r1 (Triple_2 t'))))))))
(declare-fun inter ((ptree A B) (ptree A B)) (ptree A B))
(assert (forall ((t (ptree A B))) (= (inter (as Leaf (ptree A B)) t) (as Leaf (ptree A B)))))
(assert (forall ((t (ptree A B))) (= (inter t (as Leaf (ptree A B))) (as Leaf (ptree A B)))))
(assert (forall ((l1 (ptree A B)) (x A) (y B) (r1 (ptree A B)) (t (ptree A B))) (=> (distinct t (as Leaf (ptree A B))) (= (inter (NodeP l1 x y r1) t)
  (let ((t' (splitp t x))) (let ((l' (inter l1 (Triple_0 t')))
    (r' (inter r1 (Triple_2 t'))))
      (ite (Triple_1 t') (joinp l' x r') (join2 l' r'))))))))
(declare-fun diff ((ptree A B) (ptree A B)) (ptree A B))
(assert (forall ((t (ptree A B))) (= (diff (as Leaf (ptree A B)) t) (as Leaf (ptree A B)))))
(assert (forall ((t (ptree A B))) (= (diff t (as Leaf (ptree A B))) t)))
(assert (forall ((l2 (ptree A B)) (x A) (y B) (r2 (ptree A B)) (t (ptree A B))) (=> (distinct t (as Leaf (ptree A B))) (= (diff t (NodeP l2 x y r2))
  (let ((t' (splitp t x))) (join2 (diff (Triple_0 t') l2) (diff (Triple_2 t') r2)))))))
(declare-fun joinL ((rbt A) A (rbt A)) (rbt A))
(declare-fun diff1 ((ptree A B) (ptree A B)) (ptree A B))

; Braun trees
(declare-fun braun ((tree A)) Bool)
(assert (braun (as Leaf (tree A))))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (braun (Node l x r))
  (and (or (= (size l) (size r)) (= (size l) (s (size r)))) (braun l) (braun r)))))
(declare-fun splice ((list A) (list A)) (list A))
(assert (forall ((ys (list A))) (= (splice (as Nil (list A)) ys) ys)))
(assert (forall ((x A) (xs (list A)) (ys (list A))) (= (splice (Cons x xs) ys) (Cons x (splice ys xs)))))
(declare-fun list_of ((tree A)) (list A))
(assert (= (list_of (as Leaf (tree A))) (as Nil (list A))))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (list_of (Node l x r))
  (Cons x (splice (list_of l) (list_of r))))))
(declare-fun lookup1 ((tree A) nat) A)
(assert (forall ((l (tree A)) (x A) (r (tree A)) (n nat)) (= (lookup1 (Node l x r) n) (ite (= n (s zero)) x (lookup1 (ite (even n) l r) (div2 n))))))
(declare-fun update1 (nat A (tree A)) (tree A))
(assert (forall ((n nat) (x A)) (= (update1 n x (as Leaf (tree A))) (Node (as Leaf (tree A)) x (as Leaf (tree A))))))
(assert (forall ((n nat) (x A) (l (tree A)) (y A) (r (tree A))) (= (update1 n x (Node l y r))
  (ite (= n (s zero)) (Node l x r) (ite (even n) (Node (update1 (div2 n) x l) y r) (Node l y (update1 (div2 n) x r)))))))
(declare-fun adds ((list A) nat (tree A)) (tree A))
(assert (forall ((n nat) (t (tree A))) (= (adds (as Nil (list A)) n t) t)))
(assert (forall ((x A) (xs (list A)) (n nat) (t (tree A))) (= (adds (Cons x xs) n t) (adds xs (s n) (update1 (s n) x t)))))
(declare-fun del_hi (nat (tree A)) (tree A))
(assert (forall ((n nat)) (= (del_hi n (as Leaf (tree A))) (as Leaf (tree A)))))
(assert (forall ((n nat) (l (tree A)) (x A) (r (tree A))) (= (del_hi n (Node l x r))
  (ite (= n (s zero)) (as Leaf (tree A)) (ite (even n) (Node (del_hi (div2 n) l) x r) (Node l x (del_hi (div2 n) r)))))))
(declare-fun add_lo (A (tree A)) (tree A))
(assert (forall ((x A)) (= (add_lo x (as Leaf (tree A))) (Node (as Leaf (tree A)) x (as Leaf (tree A))))))
(assert (forall ((x A) (l (tree A)) (y A) (r (tree A))) (= (add_lo x (Node l y r)) (Node (add_lo y r) x l))))
(declare-fun merge_braun ((tree A) (tree A)) (tree A))
(assert (forall ((r (tree A))) (= (merge_braun (as Leaf (tree A)) r) r)))
(assert (forall ((l (tree A)) (x A) (r (tree A)) (rr (tree A))) (= (merge_braun (Node l x r) rr) (Node rr x (merge_braun l r)))))
(declare-fun del_lo ((tree A)) (tree A))
(assert (= (del_lo (as Leaf (tree A))) (as Leaf (tree A))))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (del_lo (Node l x r)) (merge_braun l r))))
(declare-fun diff_braun ((tree A) nat) nat)
(assert (forall ((n nat)) (= (diff_braun (as Leaf (tree A)) n) zero)))
(assert (forall ((l (tree A)) (x A) (r (tree A)) (n nat)) (= (diff_braun (Node l x r) n)
  (ite (= n zero) (s zero) (ite (even n) (diff_braun r (s_0 (div2 n))) (diff_braun l (div2 n)))))))
(declare-fun size_fast ((tree A)) nat)
(assert (= (size_fast (as Leaf (tree A))) zero))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (size_fast (Node l x r)) (let ((n (size_fast r))) (s (plus (mult (s (s zero)) n) (diff_braun l n)))))))
(declare-fun braun2_of (A nat) (pair (tree A) (tree A)))
(assert (forall ((x A) (n nat)) (= (braun2_of x n)
  (ite (= n zero) (Pair (as Leaf (tree A)) (Node (as Leaf (tree A)) x (as Leaf (tree A))))
    (let ((st (braun2_of x (div2 (s_0 n))))) (ite (odd n)
      (Pair (Node (Pair_0 st) x (Pair_0 st)) (Node (Pair_1 st) x (Pair_0 st)))
      (Pair (Node (Pair_1 st) x (Pair_0 st)) (Node (Pair_1 st) x (Pair_1 st)))))))))
(declare-fun braun_of (A nat) (tree A))
(assert (forall ((x A) (n nat)) (= (braun_of x n) (Pair_0 (braun2_of x n)))))
(declare-fun take_nths (nat nat (list A)) (list A))
(assert (forall ((i nat) (k nat)) (= (take_nths i k (as Nil (list A))) (as Nil (list A)))))
(assert (forall ((i nat) (k nat) (x A) (xs (list A))) (= (take_nths i k (Cons x xs))
  (ite (= i zero) (Cons x (take_nths (s_0 (pow2 k)) k xs)) (take_nths (s_0 i) k xs)))))
(declare-fun braun_list ((tree A) (list A)) Bool)
(assert (forall ((xs (list A))) (= (braun_list (as Leaf (tree A)) xs) (= xs (as Nil (list A))))))
(assert (forall ((l (tree A)) (x A) (r (tree A)) (xs (list A))) (= (braun_list (Node l x r) xs)
  (and (distinct xs (as Nil (list A))) (= x (hd xs)) (braun_list l (take_nths (s zero) (s zero) xs))
    (braun_list r (take_nths (s (s zero)) (s zero) xs))))))
(declare-fun nodes ((list (tree A)) (list A) (list (tree A))) (list (tree A)))
(assert (forall ((ls (list (tree A))) (xs (list A)) (rs (list (tree A)))) (= (nodes ls xs rs)
  (match xs ((Nil (as Nil (list (tree A))))
             ((Cons x xs0) (match ls
                ((Nil (match rs
                   ((Nil (Cons (Node (as Leaf (tree A)) x (as Leaf (tree A))) (nodes (as Nil (list (tree A))) xs0 (as Nil (list (tree A))))))
                    ((Cons r rs0) (Cons (Node (as Leaf (tree A)) x r) (nodes (as Nil (list (tree A))) xs0 rs0))))))
                 ((Cons l ls0) (match rs
                   ((Nil (Cons (Node l x (as Leaf (tree A))) (nodes ls0 xs0 (as Nil (list (tree A))))))
                    ((Cons r rs0) (Cons (Node l x r) (nodes ls0 xs0 rs0))))))))))))))
(declare-fun brauns (nat (list A)) (list (tree A)))
(assert (forall ((k nat) (xs (list A))) (= (brauns k xs)
  (ite (= xs (as Nil (list A))) (as Nil (list (tree A))) (let ((ys (take (pow2 k) xs)) (zs (drop (pow2 k) xs)))
    (let ((ts (brauns (s k) zs))) (nodes ts ys (drop (pow2 k) ts))))))))
(declare-fun brauns1 ((list A)) (tree A))
(assert (forall ((xs (list A))) (= (brauns1 xs)
  (ite (= xs (as Nil (list A))) (as Leaf (tree A)) (nth (brauns zero xs) zero)))))
(declare-fun T_brauns (nat (list A)) nat)
(assert (forall ((k nat) (xs (list A))) (= (T_brauns k xs) (ite (= xs (as Nil (list A))) zero
  (let ((ys (take (pow2 k) xs)) (zs (drop (pow2 k) xs)))
    (let ((ts (brauns (s k) zs))) (plus (mult (s (s (s (s zero)))) (min (pow2 k) (len xs)))
      (T_brauns (s k) zs))))))))
(declare-fun braun_of_naive (A nat) (tree A))
(assert (forall ((x A) (n nat)) (= (braun_of_naive x n) (ite (= n zero) (as Leaf (tree A))
  (let ((m (div2 (s_0 n)))) (ite (odd n) (Node (braun_of_naive x m) x (braun_of_naive x m))
    (Node (braun_of_naive x (s m)) x (braun_of_naive x m))))))))
(declare-fun nat_of ((list Bool)) nat)
(assert (= (nat_of (as Nil (list Bool))) (s zero)))
(assert (forall ((b Bool) (bs (list Bool))) (= (nat_of (Cons b bs)) (plus (mult (s (s zero)) (nat_of bs)) (ite b (s zero) zero)))))
(declare-fun lookup_trie ((tree A) (list Bool)) A)
(declare-fun update_trie ((list Bool) A (tree A)) (tree A))

; Huffman's algorithm
(declare-fun cachedWeight ((treeh A)) nat)
(assert (forall ((w nat) (x A)) (= (cachedWeight (LeafH w x)) w)))
(assert (forall ((w nat) (l (treeh A)) (r (treeh A))) (= (cachedWeight (NodeH w l r)) w)))
(declare-fun uniteTrees ((treeh A) (treeh A)) (treeh A))
(assert (forall ((t1 (treeh A)) (t2 (treeh A))) (= (uniteTrees t1 t2)
  (NodeH (plus (cachedWeight t1) (cachedWeight t2)) t1 t2))))
(declare-fun insortTree ((treeh A) (list (treeh A))) (list (treeh A)))
(assert (forall ((u (treeh A))) (= (insortTree u (as Nil (list (treeh A)))) (Cons u (as Nil (list (treeh A)))))))
(assert (forall ((u (treeh A)) (t (treeh A)) (ts (list (treeh A)))) (= (insortTree u (Cons t ts))
  (ite (leq (cachedWeight u) (cachedWeight t)) (Cons u (Cons t ts)) (Cons t (insortTree u ts))))))
(declare-fun huffman ((list (treeh A))) (treeh A))
(assert (forall ((t (treeh A))) (= (huffman (Cons t (as Nil (list (treeh A))))) t)))
(assert (forall ((t1 (treeh A)) (t2 (treeh A)) (ts (list (treeh A)))) (= (huffman (Cons t1 (Cons t2 ts))) (huffman (insortTree (uniteTrees t1 t2) ts)))))
(declare-fun in_alphabet (A (treeh A)) Bool)
(assert (forall ((w nat) (x A) (y A)) (= (in_alphabet x (LeafH w y)) (= x y))))
(assert (forall ((w nat) (x A) (t1 (treeh A)) (t2 (treeh A))) (= (in_alphabet x (NodeH w t1 t2)) (or (in_alphabet x t1) (in_alphabet x t2)))))
(declare-fun in_alphabet_F (A (list (treeh A))) Bool)
(assert (forall ((x A)) (not (in_alphabet_F x (as Nil (list (treeh A)))))))
(assert (forall ((x A) (t (treeh A)) (ts (list (treeh A)))) (= (in_alphabet_F x (Cons t ts)) (or (in_alphabet x t) (in_alphabet_F x ts)))))
(declare-fun consistent ((treeh A)) Bool)
(assert (forall ((w nat) (x A)) (consistent (LeafH w x))))
(assert (forall ((w nat) (t1 (treeh A)) (t2 (treeh A))) (= (consistent (NodeH w t1 t2))
  (and (forall ((x A)) (distinct (in_alphabet x t1) (in_alphabet x t2))) (consistent t1) (consistent t2)))))
(declare-fun consistent_F ((list (treeh A))) Bool)
(assert (consistent_F (as Nil (list (treeh A)))))
(assert (forall ((t (treeh A)) (ts (list (treeh A)))) (= (consistent_F (Cons t ts)) (and (consistent t) (consistent_F ts)))))
(declare-fun depth ((treeh A) A) nat)
(assert (forall ((w nat) (x A) (y A)) (= (depth (LeafH w x) y) zero)))
(assert (forall ((w nat) (t1 (treeh A)) (t2 (treeh A)) (x A)) (= (depth (NodeH w t1 t2) x)
  (ite (in_alphabet x t1) (s (depth t1 x)) (ite (in_alphabet x t2) (s (depth t2 x)) zero)))))
(declare-fun height ((treeh A)) nat)
(assert (forall ((w nat) (x A)) (= (height (LeafH w x)) zero)))
(assert (forall ((w nat) (t1 (treeh A)) (t2 (treeh A))) (= (height (NodeH w t1 t2)) (s (max (height t1) (height t2))))))
(declare-fun height_F ((list (treeh A))) nat)
(assert (= (height_F (as Nil (list (treeh A)))) zero))
(assert (forall ((t (treeh A)) (ts (list (treeh A)))) (= (height_F (Cons t ts)) (max (height t) (height_F ts)))))
(declare-fun freq ((treeh A) A) nat)
(assert (forall ((w nat) (x A) (y A)) (= (freq (LeafH w x) y) (ite (= x y) w zero))))
(assert (forall ((w nat) (t1 (treeh A)) (t2 (treeh A)) (x A)) (= (freq (NodeH w t1 t2) x) (plus (freq t1 x) (freq t2 x)))))
(declare-fun freq_F ((list (treeh A)) A) nat)
(assert (forall ((x A)) (= (freq_F (as Nil (list (treeh A))) x) zero)))
(assert (forall ((t (treeh A)) (ts (list (treeh A))) (x A)) (= (freq_F (Cons t ts) x) (plus (freq t x) (freq_F ts x)))))
(declare-fun weight ((treeh A)) nat)
(assert (forall ((w nat) (x A)) (= (weight (LeafH w x)) w)))
(assert (forall ((w nat) (t1 (treeh A)) (t2 (treeh A))) (= (weight (NodeH w t1 t2)) (plus (weight t1) (weight t2)))))
(declare-fun cost ((treeh A)) nat)
(assert (forall ((w nat) (x A)) (= (cost (LeafH w x)) zero)))
(assert (forall ((w nat) (t1 (treeh A)) (t2 (treeh A))) (= (cost (NodeH w t1 t2)) (plus (plus (weight t1) (cost t1)) (plus (weight t2) (cost t2))))))
(declare-fun optimum ((treeh A)) Bool)
(assert (forall ((t (treeh A))) (= (optimum t) (forall ((u (treeh A))) (=> (consistent u)
  (=> (forall ((x A)) (= (in_alphabet x t) (in_alphabet x u))) (=> (forall ((y A)) (= (freq u y) (freq t y))) (leq (cost t) (cost u)))))))))
(declare-fun swapLeaves ((treeh A) nat A nat A) (treeh A))
(declare-fun swapSyms ((treeh A) A A) (treeh A))
(assert (forall ((t (treeh A)) (x A) (y A)) (= (swapSyms t x y) (swapLeaves t (freq t x) x (freq t y) y))))
(declare-fun swapFourSyms ((treeh A) A A A A) (treeh A))
(assert (forall ((t (treeh A)) (x A) (y A) (z A) (u A)) (= (swapFourSyms t x y z u)
  (ite (= x u) (swapSyms t y z) (ite (= y z) (swapSyms t x u) (swapSyms (swapSyms t x z) y u))))))
(declare-fun sibling ((treeh A) A) A)
(declare-fun mergeSibling ((treeh A) A) (treeh A))
(assert (forall ((w nat) (x A) (y A)) (= (mergeSibling (LeafH w x) y) (LeafH w x))))
(assert (forall ((w nat) (wx nat) (x A) (wy nat) (y A) (z A)) (= (mergeSibling (NodeH w (LeafH wx x) (LeafH wy y)) z)
  (ite (or (= z x) (= z y)) (LeafH (plus wx wy) z) (NodeH w (LeafH wx x) (LeafH wy y))))))
(assert (forall ((w nat) (v nat) (va (treeh A)) (vb (treeh A)) (t2 (treeh A)) (x A))
  (= (mergeSibling (NodeH w (NodeH v va vb) t2) x) (NodeH w (mergeSibling (NodeH v va vb) x) (mergeSibling t2 x)))))
(assert (forall ((w nat) (t1 (treeh A)) (v nat) (va (treeh A)) (vb (treeh A)) (x A))
  (= (mergeSibling (NodeH w t1 (NodeH v va vb)) x) (NodeH w (mergeSibling t1 x) (mergeSibling (NodeH v va vb) x)))))
(declare-fun splitLeaf ((treeh A) nat A nat A) (treeh A))
(assert (forall ((wx nat) (x A) (wy nat) (y A) (wz nat) (z A)) (= (splitLeaf (LeafH wx x) wy y wz z)
  (ite (= x y) (NodeH wx (LeafH wx x) (LeafH wz z)) (LeafH wx x)))))
(assert (forall ((w nat) (t1 (treeh A)) (t2 (treeh A)) (wx nat) (x A) (wy nat) (y A))
  (= (splitLeaf (NodeH w t1 t2) wx x wy y) (NodeH w (splitLeaf t1 wx x wy y) (splitLeaf t2 wx x wy y)))))
(declare-fun splitLeaf_F ((list (treeh A)) nat A nat A) (list (treeh A)))
(declare-fun minima ((treeh A) A A) Bool)
(assert (forall ((t (treeh A)) (x A) (y A)) (= (minima t x y) (and (in_alphabet x t) (in_alphabet y t)
  (distinct x y) (forall ((z A)) (=> (in_alphabet z t) (=> (distinct z x) (=> (distinct z y)
    (and (leq (freq t x) (freq t z)) (leq (freq t y) (freq t z)))))))))))
(declare-fun sortedByWeight ((list (treeh A))) Bool)
(assert (sortedByWeight (as Nil (list (treeh A)))))
(assert (forall ((t (treeh A))) (sortedByWeight (Cons t (as Nil (list (treeh A)))))))
(assert (forall ((t1 (treeh A)) (t2 (treeh A)) (ts (list (treeh A)))) (= (sortedByWeight (Cons t1 (Cons t2 ts)))
  (and (leq (weight t1) (weight t2)) (sortedByWeight (Cons t2 ts))))))

; Priority queues
(declare-fun heap ((tree A)) Bool)
(assert (heap (as Leaf (tree A))))
(assert (forall ((l (tree A)) (m A) (r (tree A))) (= (heap (Node l m r))
  (and (forall ((x A)) (=> (and (in_set_tree x l) (in_set_tree x r)) (leq m x))) (heap l) (heap r)))))
(declare-fun heapp ((ptree A B)) Bool)
(assert (heapp (as Leaf (ptree A B))))
(assert (forall ((l (ptree A B)) (m A) (n B) (r (ptree A B))) (= (heapp (NodeP l m n r))
  (and (forall ((x A)) (=> (and (in_set_ptree x l) (in_set_ptree x r)) (leq m x))) (heapp l) (heapp r)))))
(declare-fun get_min ((tree A)) A)
(assert (forall ((l (tree A)) (m A) (r (tree A))) (= (get_min (Node l m r)) m)))
(declare-fun get_minp ((ptree A B)) A)
(assert (forall ((l (ptree A B)) (m A) (n B) (r (ptree A B))) (= (get_minp (NodeP l m n r)) m)))
(declare-fun mht ((lheap A)) nat)
(assert (= (mht (as Leaf (ptree A nat))) zero))
(assert (forall ((l (lheap A)) (m A) (n nat) (r (lheap A))) (= (mht (NodeP l m n r)) n)))
(declare-fun ltree ((lheap A)) Bool)
(assert (ltree (as Leaf (ptree A nat))))
(assert (forall ((l (lheap A)) (m A) (n nat) (r (lheap A))) (= (ltree (NodeP l m n r))
  (and (leq (mht r) (mht l)) (= n (s (mht r))) (ltree l) (ltree r)))))
(declare-fun node_lheap ((lheap A) A (lheap A)) (lheap A))
(assert (forall ((l (lheap A)) (x A) (r (lheap A))) (= (node_lheap l x r)
  (let ((mhl (mht l)) (mhr (mht r))) (ite (leq mhr mhl) (NodeP l x (s mhr) r) (NodeP r x (s mhl) l))))))
(declare-fun merge_lheap ((lheap A) (lheap A)) (lheap A))
(assert (forall ((t (lheap A))) (= (merge_lheap (as Leaf (ptree A nat)) t) t)))
(assert (forall ((t (lheap A))) (= (merge_lheap t (as Leaf (ptree A nat))) t)))
(assert (forall ((l1 (lheap A)) (a1 A) (n1 nat) (r1 (lheap A)) (l2 (lheap A)) (a2 A) (n2 nat) (r2 (lheap A)))
  (= (merge_lheap (NodeP l1 a1 n1 r1) (NodeP l2 a2 n2 r2))
    (ite (leq a1 a2) (node_lheap l1 a1 (merge_lheap r1 (NodeP l2 a2 n2 r2)))
      (node_lheap l2 a2 (merge_lheap (NodeP l1 a1 n1 r1) r2))))))
(declare-fun insert_lheap (A (lheap A)) (lheap A))
(assert (forall ((x A) (t (lheap A))) (= (insert_lheap x t)
  (merge_lheap (NodeP (as Leaf (ptree A nat)) x (s zero) (as Leaf (ptree A nat))) t))))
(declare-fun del_min_lheap ((lheap A)) (lheap A))
(assert (= (del_min_lheap (as Leaf (ptree A nat))) (as Leaf (ptree A nat))))
(assert (forall ((l (lheap A)) (x A) (n nat) (r (lheap A))) (= (del_min_lheap (NodeP l x n r)) (merge_lheap l r))))
(declare-fun T_merge_lheap ((lheap A) (lheap A)) nat)
(assert (forall ((t (lheap A))) (= (T_merge_lheap (as Leaf (ptree A nat)) t) (s zero))))
(assert (forall ((t (lheap A))) (= (T_merge_lheap t (as Leaf (ptree A nat))) (s zero))))
(assert (forall ((l1 (lheap A)) (a1 A) (n1 nat) (r1 (lheap A)) (l2 (lheap A)) (a2 A) (n2 nat) (r2 (lheap A)))
  (= (T_merge_lheap (NodeP l1 a1 n1 r1) (NodeP l2 a2 n2 r2))
    (s (ite (leq a1 a2) (T_merge_lheap r1 (NodeP l2 a2 n2 r2)) (T_merge_lheap (NodeP l1 a1 n1 r1) r2))))))
(declare-fun T_insert_lheap (A (lheap A)) nat)
(assert (forall ((x A) (t (lheap A))) (= (T_insert_lheap x t)
  (s (T_merge_lheap (NodeP (as Leaf (ptree A nat)) x (s zero) (as Leaf (ptree A nat))) t)))))
(declare-fun T_del_min_lheap ((lheap A)) nat)
(assert (= (T_del_min_lheap (as Leaf (ptree A nat))) (s zero)))
(assert (forall ((l (lheap A)) (x A) (n nat) (r (lheap A))) (= (T_del_min_lheap (NodeP l x n r)) (s (T_merge_lheap l r)))))

(declare-fun insert_braun (A (tree A)) (tree A))
(assert (forall ((x A)) (= (insert_braun x (as Leaf (tree A))) (Node (as Leaf (tree A)) x (as Leaf (tree A))))))
(assert (forall ((x A) (l (tree A)) (y A) (r (tree A))) (= (insert_braun x (Node l y r))
  (ite (less x y) (Node (insert_braun y r) x l) (Node (insert_braun x r) y l)))))
(declare-fun del_left ((tree A)) (pair A (tree A)))
(assert (forall ((x A) (r (tree A))) (= (del_left (Node (as Leaf (tree A)) x r)) (Pair x r))))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (del_left (Node l x r))
  (let ((yl (del_left l))) (Pair (Pair_0 yl) (Node r x (Pair_1 yl)))))))
(declare-fun sift_down ((tree A) A (tree A)) (tree A))
(assert (forall ((x A) (t (tree A))) (= (sift_down (as Leaf (tree A)) x t) (Node (as Leaf (tree A)) x (as Leaf (tree A))))))
(assert (forall ((x A) (t (tree A)) (y A)) (= (sift_down (Node (as Leaf (tree A)) x t) y (as Leaf (tree A)))
  (ite (leq y x)
    (Node (Node (as Leaf (tree A)) x (as Leaf (tree A))) y (as Leaf (tree A)))
    (Node (Node (as Leaf (tree A)) y (as Leaf (tree A))) x (as Leaf (tree A)))))))
(assert (forall ((l1 (tree A)) (x1 A) (r1 (tree A)) (y A) (l2 (tree A)) (x2 A) (r2 (tree A)))
  (= (sift_down (Node l1 x1 r1) y (Node l2 x2 r2)) (ite (and (leq y x1) (leq y x2))
    (Node (Node l1 x1 r1) y (Node l2 x2 r2)) (ite (leq x1 x2)
      (Node (sift_down l1 y r1) x1 (Node l2 x2 r2)) (Node (Node l1 x1 r1) x2 (sift_down l2 y r2)))))))
(declare-fun del_min_braun ((tree A)) (tree A))
(assert (= (del_min_braun (as Leaf (tree A))) (as Leaf (tree A))))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (del_min_braun (Node l x r))
  (match l ((Leaf (as Leaf (tree A)))
            (_ (let ((yl (del_left l))) (sift_down r (Pair_0 yl) (Pair_1 yl)))))))))

; Binomial heaps

; Queues

; Splay trees
(declare-const splay_undefined (tree A))
(declare-fun splay (A (tree A)) (tree A))
(assert (forall ((x A) (ABt (tree A)) (b A) (CDt (tree A))) (= (splay x (Node ABt b CDt))
  (match (cmp x b) ((LT (match ABt ((Leaf (Node ABt b CDt))
                                   ((Node At y B't) (match (cmp x y)
                                        ((LT (ite (= At (as Leaf (tree A))) (Node At y (Node B't b CDt))
                                            (match (splay x At) (((Node A1t y' A2t) (Node A1t y' (Node A2t y (Node B't b CDt))))
                                                                (_ (as splay_undefined (tree A)))))))
                                         (EQ (Node At y (Node B't b CDt)))
                                         (GT (ite (= B't (as Leaf (tree A))) (Node At y (Node B't b CDt))
                                            (match (splay x B't) (((Node B1t b' B2t) (Node (Node At y B1t) b' (Node B2t b CDt)))
                                                                 (_ (as splay_undefined (tree A)))))))))))))
                    (EQ (Node ABt b CDt))
                    (GT (match CDt ((Leaf (Node ABt b CDt))
                                   ((Node Ct c Dt) (match (cmp x c)
                                        ((LT (ite (= Ct (as Leaf (tree A))) (Node (Node ABt b Ct) c Dt)
                                            (match (splay x Ct) (((Node C1t c' C2t) (Node (Node ABt b C1t) c' (Node C2t c Dt)))
                                                                (_ (as splay_undefined (tree A)))))))
                                         (EQ (Node (Node ABt b Ct) c Dt))
                                         (GT (ite (= Dt (as Leaf (tree A))) (Node (Node ABt b Ct) c Dt)
                                            (match (splay x Dt) (((Node D1t d D2t) (Node (Node (Node ABt b Ct) c D1t) d D2t))
                                                                (_ (as splay_undefined (tree A))))))))))))))))))
(declare-fun splay_max ((tree A)) (tree A))
(assert (= (splay_max (as Leaf (tree A))) (as Leaf (tree A))))
(assert (forall ((At (tree A)) (x A)) (= (splay_max (Node At x (as Leaf (tree A)))) (Node At x (as Leaf (tree A))))))
(assert (forall ((At (tree A)) (x A) (B't (tree A)) (y A) (CDt (tree A))) (= (splay_max (Node At x (Node B't y CDt)))
  (ite (= CDt (as Leaf (tree A))) (Node (Node At x B't) y (as Leaf (tree A))) (match (splay_max CDt)
    (((Node Ct z Dt) (Node (Node (Node At x B't) y Ct) z Dt))
     (_ (as splay_undefined (tree A)))))))))
(declare-fun isin_splay ((tree A) A) Bool)
(assert (forall ((t (tree A)) (x A)) (= (isin_splay t x) (match (splay x t)
  ((Leaf false)
   ((Node At y B't) (= x y)))))))
(declare-fun insert_splay (A (tree A)) (tree A))
(assert (forall ((x A) (t (tree A))) (= (insert_splay x t) (ite (= t (as Leaf (tree A))) (Node (as Leaf (tree A)) x (as Leaf (tree A)))
  (match (splay x t) (((Node l y r) (match (cmp x y) ((LT (Node l x (Node (as Leaf (tree A)) y r)))
                                                            (EQ (Node l y r))
                                                            (GT (Node (Node l y (as Leaf (tree A))) x r)))))
                        (_ (as splay_undefined (tree A)))))))))
(declare-fun delete_splay (A (tree A)) (tree A))
(assert (forall ((x A) (t (tree A))) (= (delete_splay x t) (ite (= t (as Leaf (tree A))) (as Leaf (tree A))
  (match (splay x t) (((Node l y r) (ite (distinct x y) (Node l y r) (ite (= l (as Leaf (tree A))) r
    (match (splay_max l) (((Node l' z r') (Node l' z r))
                            (_ (as splay_undefined (tree A)))))))) (_ (as splay_undefined (tree A)))))))))


; Skew heaps
(declare-fun merge_skew ((tree A) (tree A)) (tree A))
(assert (forall ((t (tree A))) (= (merge_skew (as Leaf (tree A)) t) t)))
(assert (forall ((t (tree A))) (= (merge_skew t (as Leaf (tree A))) t)))
(assert (forall ((l1 (tree A)) (a1 A) (r1 (tree A)) (l2 (tree A)) (a2 A) (r2 (tree A))) (= (merge_skew (Node l1 a1 r1) (Node l2 a2 r2))
  (ite (leq a1 a2) (Node (merge_skew (Node l2 a2 r2) r1) a1 l1) (Node (merge_skew (Node l1 a1 r1) r2) a2 l2)))))
(declare-fun rh ((tree A) (tree A)) nat)
(assert (forall ((l (tree A)) (r (tree A))) (= (rh l r) (ite (leq (size l) (size r)) (s zero) zero))))
(declare-fun psi_skew ((tree A)) nat)
(assert (= (psi_skew (as Leaf (tree A))) zero))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (psi_skew (Node l x r)) (plus (plus (psi_skew l) (psi_skew r)) (rh l r)))))
(declare-fun lrh ((tree A)) nat)
(assert (= (lrh (as Leaf (tree A))) zero))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (lrh (Node l x r)) (plus (rh l r) (lrh l)))))
(declare-fun rlh ((tree A)) nat)
(assert (= (rlh (as Leaf (tree A))) zero))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (= (rlh (Node l x r)) (plus (minus (s zero) (rh l r)) (rlh l)))))
(declare-fun T_merge_skew ((tree A) (tree A)) nat)
(assert (forall ((t (tree A))) (= (T_merge_skew (as Leaf (tree A)) t) (s zero))))
(assert (forall ((t (tree A))) (= (T_merge_skew t (as Leaf (tree A))) (s zero))))
(assert (forall ((l1 (tree A)) (a1 A) (r1 (tree A)) (l2 (tree A)) (a2 A) (r2 (tree A))) (= (T_merge_skew (Node l1 a1 r1) (Node l2 a2 r2))
  (s (ite (leq a1 a2) (T_merge_skew (Node l2 a2 r2) r1) (T_merge_skew (Node l1 a1 r1) r2))))))

; lemmas

;
; Section 1

; T_rev(xs) <= (|xs|+1)^2
(assert (forall ((xs (list A))) (leq (T_rev xs) (pow (s (len xs)) (s (s zero))))))
; T_itrev(xs,ys) = |xs|+1
(assert (forall ((xs (list A)) (ys (list A))) (= (T_itrev xs ys) (s (len xs)))))
; itrev(xs,ys) = rev(xs) @ ys
(assert (forall ((xs (list A)) (ys (list A))) (= (itrev xs ys) (append (rev xs) ys))))

;
; Section 2

; sorted(sort(xs))
;(assert (forall ((xs (list nat))) (sorted (sort xs))))
; mset(sort(xs)) = mset(xs)
;(assert (forall ((xs (list nat))) (same_mset (sort xs) xs)))
; mset(insort(x,xs)) = {{x}} + mset(xs)
(assert (forall ((x A) (xs (list A)) (y A)) (= (count y (insort x xs)) (ite (= x y) (s (count y xs)) (count y xs)))))
; sorted(isort(xs))
(assert (forall ((xs (list A))) (sorted (isort xs))))
; mset(isort(xs)) = mset(xs)
(assert (forall ((xs (list A))) (same_mset (isort xs) xs)))
; set(insort(x,xs)) = {x} U set(xs)
(assert (forall ((x A) (xs (list A)) (y A)) (= (in_set y (insort x xs)) (or (= x y) (in_set y xs)))))
; sorted(insort(a,xs)) = sorted(xs)
(assert (forall ((x A) (xs (list A))) (= (sorted (insort x xs)) (sorted xs))))
; T_isort(xs) <= (|xs|+1)^2
(assert (forall ((xs (list A))) (leq (T_isort xs) (pow (s (len xs)) (s (s zero))))))
; T_insort(x,xs) <= |xs| + 1
(assert (forall ((x A) (xs (list A))) (leq (T_insort x xs) (s (len xs)))))
; |insort(x,xs)| = |xs| + 1
(assert (forall ((x A) (xs (list A))) (= (len (insort x xs)) (s (len xs)))))
; |isort(xs)| = |xs|
(assert (forall ((xs (list A))) (= (len (isort xs)) (len xs))))
; ((!xs. mset(f(xs)) = mset(xs)) & (!xs.sorted(f(xs)))) -> f(xs) = isort(xs)
(assert (forall ((xs (list A))) (=> (and (forall ((ys (list A))) (same_mset (f ys) ys))
  (forall ((ys (list A))) (sorted (f ys)))) (= (f xs) (isort xs)))))
; mset(quicksort(xs)) = mset(xs)
(assert (forall ((xs (list A))) (same_mset (quicksort xs) xs)))
; mset(filter(P(xs))) = filter_mset(P,mset(xs))

; (!x.P(x)=(~Q(x))) -> filter_mset(P,M) + filter_mset(Q,M) = M

; sorted(quicksort(xs))
(assert (forall ((xs (list A))) (sorted (quicksort xs))))
; sorted(xs @ ys) = (sorted xs & sorted ys & (!x in set(xs). !y in set(ys). x <= y))
(assert (forall ((xs (list A)) (ys (list A))) (= (sorted (append xs ys)) (and (sorted xs) (sorted ys)
  (forall ((x A) (y A)) (=> (and (in_set x xs) (in_set y ys)) (leq x y)))))))
; set(quicksort(xs)) = set(xs)
(assert (forall ((xs (list A))) (same_set xs (quicksort xs))))
; quicksort2(xs,ys) = quicksort(xs) @ ys
(assert (forall ((xs (list A)) (ys (list A))) (= (quicksort2 xs ys) (append (quicksort xs) ys))))
; quicksort3(xs) = quicksort(xs)
(assert (forall ((xs (list A))) (= (quicksort3 xs) (quicksort xs))))
; sorted(xs) -> T_quicksort(xs) = a * |xs|^2 + b * |xs| + c

; T_quicksort(xs) <= a * |xs|^2 + b * |xs| + c

; mset(merge(xs,ys)) = mset(xs) + mset(ys)
(assert (forall ((xs (list A)) (ys (list A)) (x A)) (= (count x (merge xs ys)) (plus (count x xs) (count x ys)))))
; set(merge(xs,ys)) = set(xs) U set(ys)
(assert (forall ((xs (list A)) (ys (list A)) (x A)) (= (in_set x (merge xs ys)) (or (in_set x xs) (in_set x ys)))))
; mset(msort(xs)) = mset(xs)
(assert (forall ((xs (list A))) (same_set xs (msort xs))))
; sorted(merge(xs,ys)) = (sorted(xs) & sorted(ys))
(assert (forall ((xs (list A)) (ys (list A))) (= (sorted (merge xs ys)) (and (sorted xs) (sorted ys)))))
; sorted(msort(xs))
(assert (forall ((xs (list A))) (sorted (msort xs))))
; |merge(xs,ys)| = |xs| + |ys|
(assert (forall ((xs (list A)) (ys (list A))) (= (len (merge xs ys)) (plus (len xs) (len ys)))))
; |msort(xs)| = |xs|
(assert (forall ((xs (list A))) (= (len (msort xs)) (len xs))))
; C_merge(xs,ys) <= |xs| + |ys|
(assert (forall ((xs (list A)) (ys (list A))) (leq (C_merge xs ys) (plus (len xs) (len ys)))))
; |xs| = 2^k -> C_msort(xs) <= k * 2^k
(assert (forall ((xs (list A)) (k nat)) (=> (= (len xs) (pow2 k)) (leq (C_msort xs) (mult k (pow2 k))))))
; mset(msort2(xs)) = mset(xs)
(assert (forall ((xs (list A))) (same_mset (msort2 xs) xs)))
; sorted(msort2(xs))
(assert (forall ((xs (list A))) (sorted (msort2 xs))))
; |merge_adj(xs)| = (|xs| + 1) div 2
(assert (forall ((xs (lists A))) (= (len (merge_adj xs)) (div2 (s (len xs))))))
; mset_mset (merge_adj(xss)) = mset_mset(xss)

; mset(merge_all(xss)) = mset_mset(xss)

; mset(msort_bu(xs)) = mset(xs)
(assert (forall ((xs (list A))) (same_mset xs (msort_bu xs))))
; Ball(set(xss),sorted) -> Ball(set(merge_adj(xss)),sorted)
(assert (forall ((xss (lists A))) (=> (Ball_sorted xss) (Ball_sorted (merge_adj xss)))))
; Ball(set(xss),sorted) -> sorted(merge_all(xss))
(assert (forall ((xss (lists A))) (=> (Ball_sorted xss) (sorted (merge_all xss)))))
; sorted(msort_bu(xs))
(assert (forall ((xs (list A))) (sorted (msort_bu xs))))
; even(|xss|) & (!xs in set(xss).|xs| = m) -> (!xs in set(merge_adj(xss)). |xs| = 2 * m)
(assert (forall ((xss (lists A)) (m nat)) (=> (and (even (len xss)) (forall ((xs (list A))) (=> (in_set xs xss) (= (len xs) m))))
  (forall ((xs (list A))) (=> (in_set xs (merge_adj xss)) (= (len xs) (mult (s (s zero)) m)))))))
; (!xs in set(xss). |xs| = m) -> C_merge_adj(xss) <= m * |xss|
(assert (forall ((xss (lists A)) (m nat)) (=> (forall ((xs (list A))) (=> (in_set xs xss) (= (len xs) m)))
  (leq (C_merge_adj xss) (mult m (len xss))))))
; (!xs in set(xss). |xs| = m) & |xss| = 2^k -> C_merge_all(xss) <= m * k * 2^k
(assert (forall ((xss (lists A)) (m nat) (k nat)) (=> (and (forall ((xs (list A))) (=> (in_set xs xss) (= (len xs) m)))
  (= (len xss) (pow2 k))) (leq (C_merge_all xss) (mult m (mult k (pow2 k)))))))
; |xs| = 2^k -> C_msort_bu(xs) <= k * 2^k
(assert (forall ((xs (list A)) (k nat)) (=> (= (len xs) (pow2 k)) (leq (C_msort_bu xs) (mult k (pow2 k))))))
; (!xs, ys. f (xs @ ys) = f(xs) @ ys) -> mset_mset(asc x f ys) = {{x}} + mset(f([])) + mset(ys)

; mset_mset(desc(x,xs,ys)) = {{x}} + mset(xs) + mset(ys)

; mset_mset(runs(xs)) = mset(xs)

; mset(nmsort(xs)) = mset(xs)
(assert (forall ((xs (list A))) (same_mset xs (nmsort xs))))
; Ball(set(runs(xs)),sorted)
(assert (forall ((xs (list A))) (Ball_sorted (runs xs))))
; sorted(nmsort(xs))
(assert (forall ((xs (list A))) (sorted (nmsort xs))))
; C_merge_adj(xss) <= |concat(xss)|
(assert (forall ((xss (lists A))) (leq (C_merge_adj xss) (len (concat xss)))))
; |concat(merge_adj(xss))| = |concat(xss)|
(assert (forall ((xss (lists A))) (= (len (concat (merge_adj xss))) (len (concat xss)))))
; C_merge_all(xss) <= |concat(xss)| * ceil(lg(|xss|))

; 2 <= n -> ceil(lg(n)) = ceil(lg((n-1) div 2 + 1)) + 1

; (!xs,ys. f(xs @ ys) = f(xs) @ ys) -> |concat(asc(a,f(ys)))| = 1 + |f([])| + |ys|
;(assert (forall ((x A) (xs (list A))) (=> (forall ((ys (list A)) (zs (list A))) (= (f (append xs ys)) (append (f xs) ys)))
;  (= (len (concat (asc a x (f xs)))) (s (plus (len (f (as Nil (list A)))) (len xs)))))))
; |concat(desc(a,xs,ys))| = 1 + |xs| + |ys|
(assert (forall ((x A) (xs (list A)) (ys (list A))) (= (len (concat (desc x xs ys))) (s (plus (len xs) (len ys))))))
; |concat(runs(xs))| = |xs|
(assert (forall ((xs (list A))) (= (len (concat (runs xs))) (len xs))))
; (!xs,ys. f(xs @ ys) = f(xs) @ ys) -> |asc(a,f(ys))| <= 1 + |ys|

; |desc(a,xs,ys)| <= 1 + |ys|
(assert (forall ((x A) (xs (list A)) (ys (list A))) (leq (len (desc x xs ys)) (s (len ys)))))
; |runs(xs)| <= |xs|
(assert (forall ((xs (list A))) (leq (len (runs xs)) (len xs))))
; C_asc(a,ys) <= |ys|
(assert (forall ((x A) (ys (list A))) (leq (C_asc x ys) (len ys))))
; C_desc(a,ys) <= |ys|
(assert (forall ((x A) (ys (list A))) (leq (C_desc x ys) (len ys))))
; TODO I think this is not valid and the -1 is superfluous
; C_runs(xs) <= |xs| - 1
;(assert (forall ((xs (list A))) (leq (C_runs xs) (- (len xs) 1))))
; |xs| = n -> C_nmsort(xs) <= n + n * ceil(lg(n))

; C_merge_all(runs(xs)) <= n * ceil(lg(n))

; mset(sort_key(f,xs)) = mset(xs)

; sorted(map(f,sort_key(f,xs)))

; filter((lambda y. (f y = k)), sort_key(f,xs)) = filter((lambda y. (f y = k)),xs)

; mset(isort_key(f,xs)) = mset(xs)

; sorted(map(f,isort_key(f,xs)))

; (!x in set(xs). f(a) <= f(x)) -> insort_key(f,a,xs) = a # xs

; ~P(x) -> filter(P,insort_key(f,x,xs)) = filter(P,xs)

; sorted(map(f,xs)) & P(x) -> filter(P, insort_key(f,x,xs)) = insort_key(f,x,filter(P,xs))

; filter((lamdba y. f(y) = k),isort_key(f,xs)) = filter((lambda y. f(y) = k),xs)

;
; Section 3

; Theorem 3.1 and 3.2 are maybe a bit too long

; mset(xs) = mset(ys) -> sort(xs) = sort(ys)
; mset(xs) = mset(ys) -> select(k,xs) = select(k,ys)
; xs != [] -> select0(xs) = select(0,xs)
; |xs| > 1 -> select1(xs) = select(1,xs)
; k < |xs| -> select_fixed(k,xs) = select(k,xs)
; |xs| > 1 -> select1(xs) = select_fixed(1,xs)
; T_select_fixed(k,xs) <= C1 * k * |xs| + C2 * |xs| + C3 *k + C4
; k < |xs| & i < |xs| & distinct(xs) -> (?z. distinct (xs[i:=z]) & select(k,(xs[i:=z])) != select(k,xs))
; distinct(xs) -> (select(i,xs) = select(k,xs) <-> i = k)
; k < |ys| + |zs| & (!y in set(ys).!z in set(zs). y <= z) -> select(k,ys @ zs) = if k < |ys| then select(k,ys) else select(k-|ys|,zs)
; k < |xs| -> select(k,xs) = let (ls,es,gs) = partition3(x,xs)
;   in if k < |ls| then select(k,ls) else if k < |ls| + |es| then x else select(k-|ls|-|es|,gs)
; xs != [] & k < |xs| -> reduce_select_median(k,xs) != [] & median(reduce_select_median(k,xs)) = select(k,xs)
; 
; the functions in section 3.2 are a bit hard to define for now
; 
; k < |xs| -> mom_select(k,xs) = select(k,xs)
; T_mom_select(k,xs) <= T'_mom_select(|xs|)

;
; Section 4

; |t|_1 = |t| + 1
(assert (forall ((t (tree A))) (= (size1 t) (s (size t)))))
; h(t) <= |t|
(assert (forall ((t (tree A))) (leq (h t) (size t))))
; mh(t) <= h(t)
(assert (forall ((t (tree A))) (leq (mh t) (h t))))
; 2^mh(t) <= |t|_1
(assert (forall ((t (tree A))) (leq (pow2 (mh t)) (size1 t))))
; |t|_1 <= 2^h(t)
(assert (forall ((t (tree A))) (leq (size1 t) (pow2 (h t)))))
; inorder2(t,xs) = inorder(t) @ xs
(assert (forall ((t (tree A)) (xs (list A))) (= (inorder2 t xs) (append (inorder t) xs))))
; complete(t) <-> mh(t) = h(t)
(assert (forall ((t (tree A))) (= (complete t) (= (mh t) (h t)))))
; complete(t) -> |t|_1 = 2^h(t)
(assert (forall ((t (tree A))) (=> (complete t) (= (size1 t) (pow2 (h t))))))
; ~complete(t) -> |t|_1 < 2^h(t)
(assert (forall ((t (tree A))) (=> (not (complete t)) (less (size1 t) (pow2 (h t))))))
; ~complete(t) -> 2^mh(t) < |t|_1
(assert (forall ((t (tree A))) (=> (not (complete t)) (less (pow2 (mh t)) (size1 t)))))
; complete(t) <-> |t|_1 = 2^h(t)
(assert (forall ((t (tree A))) (= (complete t) (= (size1 t) (pow2 (h t))))))
; u in subtrees(t) & complete(u) -> h(u) <= h(mcs(t))

; acomplete(s) & |s| <= |t| -> h(s) <= h(t)
(assert (forall ((t (tree A)) (t' (tree A))) (=> (and (acomplete t) (leq (size t) (size t'))) (leq (h t) (h t')))))
; acomplete(t) -> h(t) = ceil(lg(|t|_1))

; acomplete(t) -> mh(t) = floor(lg(|t|_1))

; n <= |xs| & bal(n,xs) = (t, zs) -> xs = inorder(t) @ zs & |t| = n
(assert (forall ((n nat) (xs (list A)) (t (tree A)) (zs (list A))) (=> (and (leq n (len xs)) (= (balance n xs) (Pair t zs)))
  (and (= xs (append (inorder t) zs)) (= (size t) n)))))
; n <= |xs| -> inorder(bal_list(n,xs)) = take(n,xs)
(assert (forall ((n nat) (xs (list A))) (=> (leq n (len xs)) (= (inorder (bal_list n xs)) (take n xs)))))
; inorder(balance_list(xs)) = xs
(assert (forall ((xs (list A))) (= (inorder (balance_list xs)) xs)))
; n <= |t| -> inorder(bal_tree(n,t)) = take(n,inorder(t))
(assert (forall ((n nat) (t (tree A))) (=> (leq n (size t)) (= (inorder (bal_tree n t)) (take n (inorder t))))))
; inorder(balance_tree(t)) = inorder(t)
(assert (forall ((t (tree A))) (= (inorder (balance_tree t)) (inorder t))))
; n <= |xs| & bal(n,xs) = (t,zs) -> h(t) = ceil(lg(n+1))

; n <= |xs| & bal(n,xs) = (t,zs) -> mh(t) = floor(lg(n+1))

; n <= |xs| & bal(n,xs) = (t,ys) -> acomplete(t)
(assert (forall ((n nat) (xs (list A)) (t (tree A)) (ys (list A)))
  (=> (and (leq n (len xs)) (= (balance n xs) (Pair t ys))) (acomplete t))))
; invar_sz(t) = sz(t) = |t|

; invar_f(t) -> b_val(t) = F(t)

; invar_ch(t) -> ch(t) = (complete(t), ?)

; invar_ch(l) & invar_ch(r) -> invar_ch(node_ch(l,a,r))

; invar_mx(t) -> mx(t) = if t = <> then None else Some(Max(set_tree(t)))

; 
; Section 5

; inorder(join(l,r)) = inorder(l) @ inorder(r)
(assert (forall ((l (tree A)) (r (tree A))) (= (inorder (join l r)) (append (inorder l) (inorder r)))))
; h(join(l,r)) <= max(h(l),h(r)) + 1
(assert (forall ((l (tree A)) (r (tree A))) (leq (h (join l r)) (s (max (h l) (h r))))))
; bst(t) = sorted(inorder(t))
(assert (forall ((t (tree A))) (= (bst t) (sorted_s (inorder t)))))
; set_tree(t) = set(inorder(t))
(assert (forall ((t (tree A)) (x A)) (= (in_set_tree x t) (in_set x (inorder t)))))
; sorted(inorder(t)) -> inorder(insert(x,t)) = ins_list(x,inorder(t))
(assert (forall ((x A) (t (tree A))) (=> (sorted_s (inorder t)) (= (inorder (insert x t)) (ins_list x (inorder t))))))
; sorted(xs @ y # ys) = (sorted(xs @ [y]) & sorted(y # ys))
(assert (forall ((xs (list A)) (y A) (ys (list A))) (= (sorted_s (append xs (Cons y ys)))
  (and (sorted_s (append xs (Cons y (as Nil (list A))))) (sorted_s (Cons y ys))))))
; sorted(x # xs @ y # ys) = (sorted(x # xs) & x < y & sorted(xs @ [y]) & sorted(y # ys))
(assert (forall ((x A) (xs (list A)) (y A) (ys (list A))) (= (sorted_s (append (Cons x xs) (Cons y ys)))
  (and (sorted_s (Cons x xs)) (less x y) (sorted_s (append xs (Cons y (as Nil (list A))))) (sorted_s (Cons y ys))))))
; sorted(x # xs) -> sorted(xs)
(assert (forall ((x A) (xs (list A))) (=> (sorted_s (Cons x xs)) (sorted_s xs))))
; sorted(xs @ [y]) -> sorted(xs)
(assert (forall ((xs (list A)) (y A)) (=> (sorted_s (append xs (Cons y (as Nil (list A))))) (sorted_s xs))))
; sorted(xs @ [a]) -> ins_list(x,xs @ a # ys) =
;   if x < a then ins_list(x,xs) @ a # ys else xs @ ins_list(x,a # ys)
(assert (forall ((xs (list A)) (x A) (y A) (ys (list A))) (=> (sorted_s (append xs (Cons y (as Nil (list A)))))
  (= (ins_list x (append xs (Cons y ys))) (ite (less x y) (append (ins_list x xs) (Cons y ys))
    (append xs (ins_list x (Cons y ys))))))))
; sorted(xs @ a # ys) -> del_list(x, xs @ a # ys) =
;   if x < a then del_list(x,xs) @ a # ys else xs @ del_list(x, a # ys)
(assert (forall ((xs (list A)) (x A) (y A) (ys (list A))) (=> (sorted_s (append xs (Cons y ys)))
  (= (del_list x (append xs (Cons y ys))) (ite (less x y) (append (del_list x xs) (Cons y ys))
    (append xs (del_list x (Cons y ys))))))))
; sorted(x # xs) = ((!y in set(xs). x < y) & sorted(xs))
(assert (forall ((x A) (xs (list A))) (= (sorted_s (Cons x xs)) (and (forall ((y A)) (=> (in_set y xs) (less x y))) (sorted_s xs)))))
; sorted(xs @ [x]) = (sorted(xs) & (!y in set(xs). y < x))
(assert (forall ((xs (list A)) (x A)) (= (sorted_s (append xs (Cons x (as Nil (list A))))) (and (sorted_s xs) (forall ((y A)) (=> (in_set y xs) (less y x)))))))
; set_tree(empty) = {}

; sorted(inorder(t)) -> set_tree(insert(x,t)) = set_tree(t) U {x}
(assert (forall ((t (tree A)) (x A)) (=> (sorted_s (inorder t))
  (forall ((y A)) (= (in_set_tree y (insert x t)) (or (in_set_tree y t) (= x y)))))))
; sorted(inorder(t)) -> set_tree(delete(x,t)) = set_tree(t) - {x}
(assert (forall ((t (tree A)) (x A)) (=> (sorted_s (inorder t))
  (forall ((y A)) (= (in_set_tree y (delete x t)) (and (in_set_tree y t) (distinct x y)))))))
; sorted(inorder(t)) -> isin(t,x) = (x in set_tree(t))
(assert (forall ((t (tree A)) (x A)) (=> (sorted_s (inorder t)) (= (isin t x) (in_set_tree x t)))))
; set(ins_list(x,xs)) = set(xs) U {x}
(assert (forall ((xs (list A)) (x A) (y A)) (= (in_set y (ins_list x xs)) (or (in_set y xs) (= x y)))))
; sorted(xs) -> set(del_list(x,xs)) = set(xs) - {x}
(assert (forall ((xs (list A)) (x A)) (=> (sorted_s xs)
  (forall ((y A)) (= (in_set y (del_list x xs)) (and (in_set y xs) (distinct x y)))))))
; sorted(inorder(empty))
(assert (sorted_s (inorder (as Leaf (tree A)))))
; sorted(inorder(t)) -> sorted(inorder(insert(x,t)))
(assert (forall ((x A) (t (tree A))) (=> (sorted_s (inorder t)) (sorted_s (inorder (insert x t))))))
; sorted(inorder(t)) -> sorted(inorder(delete(x,t)))
(assert (forall ((x A) (t (tree A))) (=> (sorted_s (inorder t)) (sorted_s (inorder (delete x t))))))
; sorted(xs) -> sorted(ins_list(x,xs))
(assert (forall ((x A) (xs (list A))) (=> (sorted_s xs) (sorted_s (ins_list x xs)))))
; sorted(xs) -> sorted(del_list(x,xs))
(assert (forall ((x A) (xs (list A))) (=> (sorted_s xs) (sorted_s (del_list x xs)))))

; interval trees:

; inv_max_hi(t) & a in set_tree(t) -> high(a) <= max_hi(t)
(assert (forall ((t (itree A))) (=> (inv_max_hi t) (forall ((x (ivl A))) (=> (in_set_ptree x t)
  (leq (high x) (max_hi t)))))))
; inv_max_hi(t) & t != <> -> (?a in set_tree(t). high(a) = max_hi(t))
(assert (forall ((t (itree A))) (=> (and (inv_max_hi t) (distinct t (as Leaf (ptree (ivl A) A))))
  (exists ((x (ivl A))) (and (in_set_ptree x t) (= (high x) (max_hi t)))))))
; sorted(inorder(t)) -> inorder(insert(x,t)) = ins_list(x,inorder(t))
(assert (forall ((t (itree A)) (x (ivl A))) (=> (sorted_s (inorderp t))
  (= (inorderp (insert_ivl x t)) (ins_list x (inorderp t))))))
; sorted(inorder(t)) -> inorder(delete(x,t)) = del_list(x,inorder(t))
(assert (forall ((t (itree A)) (x (ivl A))) (=> (sorted_s (inorderp t))
  (= (inorderp (delete_ivl x t)) (del_list x (inorderp t))))))
; inv_max_hi(t) -> inv_max_hi(insert(x,t))
(assert (forall ((t (itree A)) (x (ivl A))) (= (inv_max_hi t) (inv_max_hi (insert_ivl x t)))))
; inv_max_hi(t) -> inv_max_hi(delete(x,t))
(assert (forall ((t (itree A)) (x (ivl A))) (= (inv_max_hi t) (inv_max_hi (delete_ivl x t)))))
; inv_max_hi(s) & sorted(inorder(s)) -> set_tree(insert(x,s)) = set_tree(s) U {x}
(assert (forall ((x (ivl A)) (t (itree A))) (=> (and (inv_max_hi t) (sorted_s (inorderp t)))
  (forall ((y (ivl A))) (= (in_set_ptree y (insert_ivl x t)) (or (in_set_ptree y t) (= x y)))))))
; inv_max_hi(s) & sorted(inorder(s)) -> set_tree(delete(x,s)) = set_tree(s) - {x}
(assert (forall ((x (ivl A)) (t (itree A))) (=> (and (inv_max_hi t) (sorted_s (inorderp t)))
  (forall ((y (ivl A))) (= (in_set_ptree y (delete_ivl x t)) (and (in_set_ptree y t) (distinct x y)))))))
; inv_max_hi(s) & sorted(inorder(s)) -> inv_max_hi(insert(x,s)) & sorted(inorder(insert(x,s)))
(assert (forall ((x (ivl A)) (t (itree A))) (=> (and (inv_max_hi t) (sorted_s (inorderp t)))
  (and (inv_max_hi (insert_ivl x t)) (sorted_s (inorderp (insert_ivl x t)))))))
; inv_max_hi(s) & sorted(inorder(s)) -> inv_max_hi(delete(x,s)) & sorted(inorder(delete(x,s)))
(assert (forall ((x (ivl A)) (t (itree A))) (=> (and (inv_max_hi t) (sorted_s (inorderp t)))
  (and (inv_max_hi (delete_ivl x t)) (sorted_s (inorderp (delete_ivl x t)))))))
; inv_max_hi(t) & sorted(inorder(t)) -> search(t,x) = has_overlap(set_tree(t),x)

; inv_max_hi(t) & bst(t) -> search1(t,x) = (?iv in set_tree(t). in_ivl(x,iv))


; 2-3 trees:

; complete(t) -> 2^h(t) <= |t| + 1
(assert (forall ((x A) (xs (list A))) (=> (sorted_s xs) (sorted_s (ins_list x xs)))))
; |maxn(n)| = (3^n - 1) div 2

; |t| <= (3^h(t) - 1) div 2

; complete(t) -> complete(treeI(ins(a,t))) & hI(ins(a,t)) = h(t)
(assert (forall ((x A) (t (tree23 A))) (=> (complete23 t) (and (complete23 (treeI (ins x t))) (= (hI (ins x t)) (h23 t))))))
; complete(t) -> complete(insert(a,t))
(assert (forall ((x A) (t (tree23 A))) (=> (complete23 t) (complete23 (insert23 x t)))))
; complete(r) & complete(treeD(l')) & h(r) = hD(l') -> complete(treeD(node21(l',a,r)))
(assert (forall ((x A) (l' (upD A)) (r (tree23 A))) (=> (and (complete23 r) (complete23 (treeD l')) (= (h23 r) (hD l')))
  (complete23 (treeD (node21 l' x r))))))
; 0 < h(r) -> hD(node21(l',a,r)) = max(hD(l'),h(r)) + 1
(assert (forall ((l' (upD A)) (x A) (r (tree23 A))) (=> (less zero (h23 r)) (= (hD (node21 l' x r)) (s (max (hD l') (h23 r)))))))
; split_min(t) = (x,t') & 0 < h(t) & complete(t) -> hD(t') = h(t)
(assert (forall ((x A) (t (tree23 A)) (t' (upD A))) (=> (and (= (split_min23 t) (Pair x t')) (less zero (h23 t)) (complete23 t))
  (= (hD t') (h23 t)))))
; split_min(t) = (x,t') & complete(t) & 0 < h(t) -> complete(treeD(t'))
(assert (forall ((x A) (t (tree23 A)) (t' (upD A))) (=> (and (= (split_min23 t) (Pair x t')) (complete23 t) (less zero (h23 t)))
  (complete23 (treeD t')))))
; complete(t) -> hD(del(x,t)) = h(t)
(assert (forall ((x A) (t (tree23 A))) (=> (complete23 t) (= (hD (del x t)) (h23 t)))))
; complete(t) -> complete(treeD(del(x,t)))
(assert (forall ((x A) (t (tree23 A))) (=> (complete23 t) (complete23 (treeD (del x t))))))
; complete(t) -> complete(delete(x,t))
(assert (forall ((x A) (t (tree23 A))) (=> (complete23 t) (complete23 (delete23 x t)))))
; not_T(ts) -> len(join_adj(ts)) < len(ts)
(assert (forall ((ts (tree23s A))) (=> (not_T ts) (less (len23s (join_adj ts)) (len23s ts)))))
; not_T(ts) -> len(join_adj(ts)) <= len(ts) div 2
(assert (forall ((ts (tree23s A))) (=> (not_T ts) (leq (len23s (join_adj ts)) (div2 (len23s ts))))))
; not_T(ts) -> inorder2(join_adj(ts)) = inorder2(ts)
(assert (forall ((ts (tree23s A))) (=> (not_T ts) (= (inorder23s (join_adj ts)) (inorder23s ts)))))
; inorder(join_all(ts)) = inorder2(ts)
(assert (forall ((ts (tree23s A))) (= (inorder23 (join_all ts)) (inorder23s ts))))
; inorder(tree23_of_list(as)) = as
(assert (forall ((xs (list A))) (= (inorder23 (tree23_of_list xs)) xs)))
; (!t in trees(ts). complete(t) & h(t) = n) & not_T(ts) -> (!t in trees(join_adj(ts)). complete(t) & h(t) = n + 1)
(assert (forall ((n nat) (ts (tree23s A))) (=> (forall ((t (tree23 A))) (=> (in_trees t ts) (and (complete23 t) (= (h23 t) n))))
  (forall ((t (tree23 A))) (=> (in_trees t (join_adj ts)) (and (complete23 t) (= (h23 t) (s n))))))))
; (!t in trees(ts). complete(t) & h(t) = n) -> complete(join_all(ts))
(assert (forall ((n nat) (ts (tree23s A))) (=> (forall ((t (tree23 A))) (=> (in_trees t ts) (and (complete23 t) (= (h23 t) n))))
  (complete23 (join_all ts)))))
; t in trees(leaves(as)) -> complete(t) & h(t) = 0
(assert (forall ((t (tree23 A)) (xs (list A))) (=> (in_trees t (leaves xs)) (and (complete23 t) (= (h23 t) zero)))))
; complete(tree23_of_list(as))
(assert (forall ((xs (list A))) (complete23 (tree23_of_list xs))))
; not_T(ts) -> T_join_adj(ts) <= len(ts) div 2
(assert (forall ((ts (tree23s A))) (=> (not_T ts) (leq (T_join_adj ts) (div2 (len23s ts))))))
; T_tree23_of_list(as) <= 3 * |as| + 4
(assert (forall ((xs (list A))) (leq (T_tree23_of_list xs) (plus (mult (s (s (s zero))) (len xs)) (s (s (s (s zero))))))))
 
; red-black trees:

; invc(t) & invh(t) -> h(t) <= 2 * bh(t) + (if color(t) = Black then 0 else 1)
(assert (forall ((t (rbt A))) (=> (and (invc t) (invh t)) (leq (h t) (plus (mult (s (s zero)) (bh t)) (ite (= (color_of t) Black) zero (s zero)))))))
; invc(t) & invh(t) -> 2^bh(t) <= |t|_1
(assert (forall ((t (rbt A))) (=> (and (invc t) (invh t)) (leq (pow2 (bh t)) (size1 t)))))
; 2^(h(t)/2) <= 2^bh(t) <= |t|_1

; rbt(t) -> h(t) <= 2 * lg(|t|_1) ; TODO double check this
(assert (forall ((t (rbt A))) (=> (inv_rbt t) (leq (pow2 (h t)) (mult (size1 t) (size1 t))))))
; invh(l) & invh(r) & invc2(l) & invc(r) & bh(l) = bh(r) ->
;   invc(baliL(l,a,r)) & invh(baliL(l,a,r)) & bh(baliL(l,a,r)) = bh(l) + 1
(assert (forall ((l (rbt A)) (x A) (r (rbt A))) (=> (and (invh l) (invh r) (invc2 l) (invc r) (= (bh l) (bh r)))
  (and (invc (baliL l x r)) (invh (baliL l x r)) (= (bh (baliL l x r)) (s (bh l)))))))
; invh(l) & invh(r) & invc(l) & invc2(r) & bh(l) = bh(r) ->
;   invc(baliR(l,a,r)) & invh(baliR(l,a,r)) & bh(baliR(l,a,r)) = bh(l) + 1
(assert (forall ((l (rbt A)) (x A) (r (rbt A))) (=> (and (invh l) (invh r) (invc l) (invc2 r) (= (bh l) (bh r)))
  (and (invc (baliR l x r)) (invh (baliR l x r)) (= (bh (baliR l x r)) (s (bh l)))))))
; invc(t) & invh(t) -> invc2(ins(x,t)) & (color(t) = Black -> invc(ins(x,t))) & invh(ins(x,t)) & bh(ins(x,t)) = bh(t)
(assert (forall ((x A) (t (rbt A))) (=> (and (invc t) (invc t))
  (and (invc2 (insRB x t)) (=> (= (color_of t) Black) (and (invc (insRB x t)) (invh (insRB x t)) (= (bh (insRB x t)) (bh t))))))))
; rbt(t) -> rbt(insert(x,t))
(assert (forall ((x A) (t (rbt A))) (=> (inv_rbt t) (inv_rbt (insertRB x t)))))
; split_min(t) = (x,t') & t != <> & invh(t) & invc(t) -> invh(t') & (color(t) = Red -> bh(t') = bh(t) & invc(t')) &
;   (color(t) = Black -> bh(t') = bh(t) - 1 & invc2(t'))
(assert (forall ((t (rbt A)) (x A) (t' (rbt A))) (=> (and (= (split_minRB t) (Pair x t')) (distinct t (as Leaf (rbt A))) (invh t) (invc t))
  (and (invc t')
       (=> (= (color_of t) Red) (and (= (bh t') (bh t)) (invc t')))
       (=> (= (color_of t) Black) (and (= (s (bh t')) (bh t)) (invc2 t')))))))
; invh(t) & invc(t) & t' = del(x,t) -> invh(t') & (color(t) = Red -> bh(t') = bh(t) & invc(t')) &
;   (color(t) = Black -> bh(t') = bh(t) - 1 & invc2(t'))
; deliberate use of s_0 here since t can be a leaf as well
(assert (forall ((t (rbt A)) (x A) (t' (rbt A))) (=> (and (invh t) (invc t) (= (delRB x t) t'))
  (and (invh t')
       (=> (= (color_of t) Red) (and (= (bh t') (bh t)) (invc t')))
       (=> (= (color_of t) Black) (and (= (bh t') (s_0 (bh t)))))))))
; rbt(t) -> rbt(delete(x,t))
(assert (forall ((t (rbt A)) (x A)) (=> (inv_rbt t) (inv_rbt (deleteRB x t)))))
; invh(l) & invh(r) & bh(l) + 1 = bh(r) & invc2(l) & invc(r) & t' = baldL(l,a,r) ->
;   invh(t') & bh(t') = bh(r) & invc2(t') & (color(r) = Black -> invc(t'))
(assert (forall ((l (rbt A)) (x A) (r (rbt A)) (t' (rbt A))) (=> (and (invh l) (invh r) (= (s (bh l)) (bh r)) (invc2 l) (invc r) (= t' (baldL l x r)))
  (and (invh t') (= (bh t') (bh r)) (invc2 t') (=> (= (color_of r) Black) (invc t'))))))
; invh(l) & invh(r) & bh(l) = bh(r) + 1 & invc(l) & invc2(r) & t' = baldR(l,a,r) ->
;   invh(t') & bh(t') = bh(l) & invc2(t') & (color(l) = Black -> invc(t'))
(assert (forall ((l (rbt A)) (x A) (r (rbt A)) (t' (rbt A))) (=> (and (invh l) (invh r) (= (bh l) (s (bh r))) (invc l) (invc2 r) (= t' (baldR l x r)))
  (and (invh t') (= (bh t') (bh l)) (invc2 t') (=> (= (color_of l) Black) (invc t'))))))
; invh(l) & invh(r) & bh(l) = bh(r) & invc(l) & invc(r) & t' = join(l,r) ->
;   invh(t') & bh(t') = bh(l) & invc2(t') & (color(l) = Black & color(r) = Black -> invc(t'))
(assert (forall ((l (rbt A)) (r (rbt A)) (t' (rbt A))) (=> (and (invh l) (invh r) (= (bh l) (bh r)) (invc l) (invc r) (= t' (joinRB l r)))
  (and (invh t') (= (bh t') (bh l)) (invc2 t') (=> (= (color_of l) Black) (invc t'))))))
; invc(t) & invh(t) -> h(t) <= 2 * lg(|t|_1) + 2

; invh(t) <-> bhs(t) = { bh(t) }

; inorder(rbt_of_list(as)) = as
;(assert (forall ((xs (list A))) (= (inorder (rbt_of_list a xs)) xs)))
; rbt(rbt_of_list(as))
;(assert (forall ((xs (list A))) (inv_rbt (rbt_of_list a xs))))

; AVL trees:

; avl(t) -> fib(h(t) + 2) <= |t|_1
(assert (forall ((t (tree_ht A))) (=> (avl t) (leq (fib (plus (h t) (s (s zero)))) (size1 t)))))
; ((1 + sqrt(5))/2)^n <= fib(n + 2)

; avl(t) -> h(t) <= 1 / lg((1 + sqrt(5))/2) * lg(|t|_1)

; avl(t) -> avl(insert(x,t)) & h(insert(x,t)) in { h(t), h(t) + 1 }
(assert (forall ((x A) (t (tree_ht A))) (=> (avl t) (and (avl (insertAVL x t)) (or (= (h (insertAVL x t)) (h t)) (= (h (insertAVL x t)) (s (h t))))))))
; avl(l) & avl(r) & h(r) - 1 <= h(l) & h(l) <= h(r) + 2 -> avl(balL(l,a,r))
(assert (forall ((x A) (l (tree_ht A)) (r (tree_ht A))) (=> (and (avl l) (avl r) (leq (h r) (s (h l))) (leq (h l) (s (s (h r))))) (avl (balL l x r)))))
; avl(l) & avl(r) & h(l) - 1 <= h(r) & h(r) <= h(l) + 2 -> avl(balR(l,a,r))
(assert (forall ((x A) (l (tree_ht A)) (r (tree_ht A))) (=> (and (avl l) (avl r) (leq (h l) (s (h r))) (leq (h r) (s (s (h l))))) (avl (balR l x r)))))
; avl(t) & t != <> -> avl(fst(split_max(t))) & h(t) in { h(fst(split_max(t))), h(fst(split_max(t))) + 1 }
(assert (forall ((t (tree_ht A))) (=> (and (avl t) (distinct t (as Leaf (ptree A nat))))
  (let ((sm (split_max t))) (and (avl (Pair_0 sm)) (or (= (h t) (h (Pair_0 sm))) (= (h t) (s (h (Pair_0 sm))))))))))
; avl(t) & t' = delete(x,t) -> avl(t') & h(t) in { h(t'), h(t') + 1 }
(assert (forall ((x A) (t (tree_ht A)) (t' (tree_ht A))) (=> (and (avl t) (= t' (deleteAVL x t))) (and (avl t') (or (= (h t) (h t')) (= (h t) (s (h t'))))))))
; avl(t) & h(t) = n -> 2^(n div 2) <= |t|_1
(assert (forall ((t (tree_ht A)) (n nat)) (=> (avl t) (= (h t) n) (leq (pow2 (div2 n)) (size1 t)))))
; avl(t) -> h(t) <= 2 * lg(|t|_1) ; TODO double check this
(assert (forall ((t (tree_ht A))) (=> (avl t) (leq (pow2 (h t)) (mult (size1 t) (size1 t))))))
; avl0(fibt(n))
(assert (forall ((n nat)) (avl0 (fibt n))))
; |fibt(n)|_1 = fib(n + 2)
(assert (forall ((n nat)) (= (size1 (fibt n)) (fib (s (s n))))))
; avl(t) -> |fibt(h(t))|_1 <= |t|_1
(assert (forall ((t (tree A))) (leq (size1 (fibt (h t))) (size1 t))))
; acomplete(t) -> avl0(t)
(assert (forall ((t (tree A))) (=> (acomplete t) (avl0 t))))
; inorder(avl_of_list(as)) = as
;(assert (forall ((xs (list A))) (= (inorder (avl_of_list a xs)) xs)))
; avl(avl_of_list(as))
;(assert (forall ((xs (list A))) (avl (avl_of_list a xs))))
; avl(t) & t' = insert(x,t) -> avl(t') & h(t') = h(t) + if incr(t,t') then 1 else 0
(assert (forall ((x A) (t (tree_bal A)) (t' (tree_bal A))) (=> (and (avl_bal t) (= t' (insert_bal x t)))
  (and (avl_bal t') (= (h t') (ite (incr t t') (s (h t)) (h t)))))))
; avl(t) & t' = delete(x,t) -> avl(t') & h(t) = h(t') + if decr(t,t') then 1 else 0
(assert (forall ((x A) (t (tree_bal A)) (t' (tree_bal A))) (=> (and (avl_bal t) (= t' (delete_bal x t)))
  (and (avl_bal t') (= (h t) (ite (decr t t') (s (h t')) (h t')))))))
; split_max(t) = (t',a) & avl(t) & t != <> -> avl(t') & h(t) = h(t') + if decr(t,t') then 1 else 0
(assert (forall ((x A) (t (tree_bal A)) (t' (tree_bal A))) (=> (and (= (split_max_bal t) (Pair t' x))
  (avl_bal t) (distinct t (as Leaf (tree_bal A)))) (and (avl_bal t') (= (h t) (ite (decr t t') (s (h t')) (h t')))))))
; avl(t) -> avl_ht(debal(t))
(assert (forall ((t (tree_bal A))) (=> (avl_bal t) (avl (debal t)))))
; avl(t) -> debal2(t) = debal(t)
(assert (forall ((t (tree_bal A))) (=> (avl_bal t) (= (debal2 t) (debal t)))))

; 
; split_min(t) = (m,t') & t != <> -> m in set_tree(t) & set_tree(t) = {m} U set_tree(t')
(assert (forall ((t (ptree A B)) (m A) (t' (ptree A B))) (=> (and (= (split_minp t) (Pair m t')) (distinct t (as Leaf (ptree A B))))
  (and (in_set_ptree m t) (forall ((x A)) (= (in_set_ptree x t) (or (= x m) (in_set_ptree x t'))))))))
; split_min(t) = (m,t') & bst(t) & t != <> -> bst(t') & (!x in set_tree(t').m < x)
(assert (forall ((t (ptree A B)) (m A) (t' (ptree A B))) (=> (and (= (split_minp t) (Pair m t'))
  (bst t) (distinct t (as Leaf (ptree A B)))) (and (bst t') (forall ((x A)) (=> (in_set_ptree x t') (less m x)))))))
; split_min(t) = (m,t') & inv(t) & t != <> -> inv(t')
(assert (forall ((t (ptree A B)) (m A) (t' (ptree A B))) (=> (and (= (split_minp t) (Pair m t'))
  (invp t) (distinct t (as Leaf (ptree A B)))) (invp t'))))
; set_tree(join2(l,r)) = set_tree(l) U set_tree(r)
(assert (forall ((l (ptree A B)) (x A) (r (ptree A B))) (= (in_set_ptree x (join2 l r))
  (or (in_set_ptree x l) (in_set_ptree x r)))))
; bst(l) & bst(r) & (!x in set_tree(l).!y in set_tree(r). x < y) -> bst(join2(l,r))
(assert (forall ((l (ptree A B)) (r (ptree A B))) (=> (and (bst l) (bst r)
  (forall ((x A) (y A)) (=> (and (in_set_ptree x l) (in_set_ptree y r)) (less x y))))
  (bst (join2 l r)))))
; inv(l) & inv(r) -> inv(join2(l,r))
(assert (forall ((l (ptree A B)) (r (ptree A B))) (=> (and (invp l) (invp r)) (invp (join2 l r)))))
; split(t,x) = (l,b,r) & bst(t) ->
;   set_tree(l) = { a in set_tree(t) | a < x } & set_tree(r) = { a in set_tree(t) | x < a } & b = (x in set_tree(t)) & bst(l) & bst(r)
(assert (forall ((t (ptree A B)) (x A) (y Bool) (l (ptree A B)) (r (ptree A B))) (=> (and (= (splitp t x) (Triple l y r))
  (bst t)) (and
    (forall ((z A)) (= (in_set_ptree z l) (and (in_set_ptree z t) (less z x))))
    (forall ((z A)) (= (in_set_ptree z r) (and (in_set_ptree z t) (less x z))))
    (= y (in_set_ptree x t)) (bst l) (bst r)))))
; split(t,x) = (l,b,r) & inv(t) -> inv(l) & inv(r)
(assert (forall ((t (ptree A B)) (x A) (y Bool) (l (ptree A B)) (r (ptree A B))) (=> (and (= (splitp t x) (Triple l y r))
  (invp t)) (and (invp l) (invp r)))))
; bst(t2) -> set_tree(union(t1,t2)) = set_tree(t1) U set_tree(t2)
(assert (forall ((t1 (ptree A B)) (t2 (ptree A B))) (=> (bst t2)
  (forall ((x A)) (= (in_set_ptree x (union t1 t2)) (or (in_set_ptree x t1) (in_set_ptree x t2)))))))
; bst(t1) & bst(t2) -> bst(union(t1,t2))
(assert (forall ((t1 (ptree A B)) (t2 (ptree A B))) (=> (and (bst t1) (bst t2))
  (bst (union t1 t2)))))
; inv(t1) & inv(t2) -> inv(union(t1,t2))
(assert (forall ((t1 (ptree A B)) (t2 (ptree A B))) (=> (and (invp t1) (invp t2)) (invp (union t1 t2)))))
; bst(t1) & bst(t2) -> set_tree(inter(t1,t2)) = set_tree(t1) /cap set_tree(t2)
(assert (forall ((t1 (ptree A B)) (t2 (ptree A B))) (=> (and (bst t1) (bst t2))
  (forall ((x A)) (= (in_set_ptree x (inter t1 t2)) (and (in_set_ptree x t1) (in_set_ptree x t2)))))))
; bst(t1) & bst(t2) -> bst(inter(t1,t2))
(assert (forall ((t1 (ptree A B)) (t2 (ptree A B))) (=> (and (bst t1) (bst t2))
  (bst (inter t1 t2)))))
; inv(t1) & inv(t2) -> inv(inter(t1,t2))
(assert (forall ((t1 (ptree A B)) (t2 (ptree A B))) (=> (and (invp t1) (invp t2)) (invp (inter t1 t2)))))
; bst(t1) & bst(t2) -> set_tree(diff(t1,t2)) = set_tree(t1) - set_tree(t2)
(assert (forall ((t1 (ptree A B)) (t2 (ptree A B))) (=> (and (bst t1) (bst t2))
  (forall ((x A)) (= (in_set_ptree x (diff t1 t2)) (and (in_set_ptree x t1) (not (in_set_ptree x t2))))))))
; bst(t1) & bst(t2) -> bst(diff(t1,t2))
(assert (forall ((t1 (ptree A B)) (t2 (ptree A B))) (=> (and (bst t1) (bst t2))
  (bst (diff t1 t2)))))
; inv(t1) & inv(t2) -> inv(diff(t1,t2))
(assert (forall ((t1 (ptree A B)) (t2 (ptree A B))) (=> (and (invp t1) (invp t2)) (invp (diff t1 t2)))))
; invc(l) & invc(r) & invh(l) & invh(r) & bh(l) <= bh(r) ->
;   invc2(joinL(l,x,r)) & (bh(l) != bh(r) & color(r) = Black -> invc(joinL(l,x,r))) & invh(joinL(l,x,r)) & bh(joinL(l,x,r)) = bh(r)
(assert (forall ((l (rbt A)) (x A) (r (rbt A))) (=> (and (invc l) (invc r) (invh l) (invh r) (leq (bh l) (bh r)))
  (and (invc2 (joinL l x r)) (=> (and (distinct (bh l) (bh r)) (= (color_of r) Black)) (invc (joinL l x r)))
    (invh (joinL l x r)) (= (bh (joinL l x r)) (bh l))))))
; bh(l) < bh(r) -> set_tree(joinL(l,x,r)) = set_tree(l) U {x} U set_tree(r)
(assert (forall ((l (rbt A)) (x A) (r (rbt A))) (=> (less (bh l) (bh r))
  (forall ((y A)) (= (in_set_ptree y (joinL l x r)) (or (in_set_ptree y l) (= x y) (in_set_ptree y r)))))))
; bst(<l,(a,n),r>) & bh(l) <= bh(r) -> bst(joinL(l,a,r))
(assert (forall ((l (rbt A)) (x A) (n color) (r (rbt A))) (=> (and (bst (NodeP l x n r)) (leq (bh l) (bh r))) (bst (joinL l x r)))))
; bst(t1) & bst(t2) -> set_tree(diff1(t1,t2)) = set_tree(t1) - set_tree(t2)
(assert (forall ((t1 (ptree A B)) (t2 (ptree A B))) (=> (and (bst t1) (bst t2))
  (forall ((x A)) (= (in_set_ptree x (diff1 t1 t2)) (and (in_set_ptree x t1) (not (in_set_ptree x t2))))))))

; 
; Braun-trees:

; acomplete(l) & acomplete(r) & |l|=|r|+1 -> acomplete(<l,x,r>)
(assert (forall ((l (tree A)) (x A) (r (tree A))) (=> (and (acomplete l) (acomplete r) (= (size l) (s (size r)))) (acomplete (Node l x r)))))
; braun(t) -> acomplete(t)
(assert (forall ((t (tree A))) (=> (braun t) (acomplete t))))
; braun(<l,x,r>) & n in {1..|<l,x,r>|} & 1 < n -> (odd(n) -> n div 2 in {1..|r|}) & (even(n) -> n div 2 in {1..|l|})
(assert (forall ((l (tree A)) (x A) (r (tree A)) (n nat)) (=> (and (braun (Node l x r)) (in_range n (s zero) (size (Node l x r))) (less (s zero) n))
  (and (=> (odd n) (in_range (div2 n) (s zero) (size r))) (=> (even n) (in_range (div2 n) (s zero) (size l)))))))
; |list(t)|=|t|
(assert (forall ((t (tree A))) (= (len (list_of t)) (size t))))
; braun(t) & i < |t| -> list(t!i) = lookup1(t,(i+1))
(assert (forall ((t (tree A)) (i nat)) (=> (and (braun t) (less i (size t))) (= (nth (list_of t) i) (lookup1 t (s i))))))
; n < |xs| + |ys| & |ys| <= |xs| & |xs| <= |ys| + 1 -> splice(xs,ys) ! n = (if even(n) then xs else ys) ! (n div 2)
(assert (forall ((n nat) (xs (list A)) (ys (list A))) (=> (and (less n (plus (len xs) (len ys))) (leq (len ys) (len xs)) (leq (len xs) (s (len ys))))
  (= (nth (splice xs ys) n) (nth (ite (even n) xs ys) (div2 n))))))
; braun(t) -> list(t) = map(lookup1(t)) [1..<|t|+1]
;(assert (forall ((t (tree A))) (=> (braun t) (= (list_of t) (map (lookup1 t ???)))))
; braun(t) & n in {1..|t|} -> |update1(n,x,t)| = |t|
(assert (forall ((n nat) (t (tree A)) (x A)) (=> (and (braun t) (in_range n (s zero) (size t))) (= (size (update1 n x t)) (size t)))))
; braun(t) & n in {1..|t|} -> braun(update1(n,x,t))
(assert (forall ((n nat) (t (tree A)) (x A)) (=> (and (braun t) (in_range n (s zero) (size t))) (braun (update1 n x t)))))
; braun(t) & n in {1..|t|} -> lookup1(update1(n,x,t),m) = if n = m then x else lookup1(t,m)
(assert (forall ((n nat) (m nat) (t (tree A)) (x A)) (=> (and (braun t) (in_range n (s zero) (size t)))
  (= (lookup1 (update1 n x t) m) (ite (= n m) x (lookup1 t m))))))
; braun(t) & n in {1..|t|} -> list(update1(n,x,t)) = (list(t))[n-1 := x]
(assert (forall ((n nat) (t (tree A)) (x A)) (=> (and (braun t) (in_range (s n) (s zero) (size t))) (= (list_of (update1 (s n) x t)) (upd (list_of t) n x)))))
; braun(t) -> |update1(|t|+1,x,t)| = |t| + 1
(assert (forall ((t (tree A)) (x A)) (=> (braun t) (= (size (update1 (s (size t)) x t)) (s (size t))))))
; braun(t) -> braun(update1(|t|+1,x,t))
(assert (forall ((t (tree A)) (x A)) (=> (braun t) (braun (update1 (s (size t)) x t)))))
; braun(t) -> list(update1(|t|+1,x,t)) = list(t) @ [x]
(assert (forall ((t (tree A)) (x A)) (=> (braun t) (= (list_of (update1 (s (size t)) x t)) (append (list_of t) (Cons x (as Nil (list A))))))))
; braun(t) -> |adds(xs,|t|,t)| = |t| + |xs| & braun(adds(xs,|t|,t))
(assert (forall ((t (tree A)) (xs (list A))) (=> (braun t) (and (= (size (adds xs (size t) t)) (plus (size t) (len xs))) (braun (adds xs (size t) t))))))
; braun(t) -> list(adds(xs,|t|,t)) = list(t) @ xs
(assert (forall ((xs (list A)) (t (tree A))) (=> (braun t) (= (list_of (adds xs (size t) t)) (append (list_of t) xs)))))
; |ys| <= |xs| -> splice(xs @ [x],ys) = splice(xs,ys @ [x])
(assert (forall ((x A) (xs (list A)) (ys (list A))) (=> (leq (len ys) (len xs))
  (= (splice (append xs (Cons x (as Nil (list A)))) ys) (splice xs (append ys (Cons x (as Nil (list A)))))))))
; |xs| <= |ys| + 1 -> splice(xs,ys @ [y]) = splice(xs,ys) @ [y]
(assert (forall ((y A) (xs (list A)) (ys (list A))) (=> (leq (len xs) (s (len ys)))
  (= (splice xs (append ys (Cons y (as Nil (list A))))) (append (splice xs ys) (Cons y (as Nil (list A))))))))
; braun(t) -> braun(del_hi(|t|,t))
(assert (forall ((t (tree A))) (=> (braun t) (braun (del_hi (size t) t)))))
; braun(t) -> list(del_hi(|t|,t)) = butlast(list(t))
(assert (forall ((t (tree A))) (=> (braun t) (= (list_of (del_hi (size t) t)) (butlast (list_of t))))))
; braun(t) -> braun(add_lo(x,t))
(assert (forall ((x A) (t (tree A))) (=> (braun t) (braun (add_lo x t)))))
; braun(t) -> list(add_lo(a,t)) = a # list(t)
(assert (forall ((x A) (t (tree A))) (=> (braun t) (= (list_of (add_lo x t)) (Cons x (list_of t))))))
; braun(<l,x,r>) -> braun(merge(l,r))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (=> (braun (Node l x r)) (braun (merge_braun l r)))))
; braun(<l,x,r>) -> list(merge(l,r)) = splice(list(l),list(r))
(assert (forall ((l (tree A)) (x A) (r (tree A))) (=> (braun (Node l x r)) (= (list_of (merge_braun l r)) (splice (list_of l) (list_of r))))))
; braun(t) -> braun(del_lo(t))
(assert (forall ((t (tree A))) (=> (braun t) (braun (del_lo t)))))
; braun(t) -> list(del_lo(t)) = tl(list(t))
(assert (forall ((t (tree A))) (=> (braun t) (= (list_of (del_lo t)) (tl (list_of t))))))
; braun(t) -> size_fast(t) = |t|
(assert (forall ((t (tree A))) (=> (braun t) (= (size_fast t) (size t)))))
; braun(t) & |t| in {n,n+1} -> diff(t,n) = |t| - n
(assert (forall ((t (tree A)) (n nat)) (=> (and (braun t) (or (= (size t) n) (= (size t) (s n)))) (= (diff_braun t n) (minus (size t) n)))))
; list(braun_of(x,n)) = replicate(n,x)
(assert (forall ((x A) (n nat)) (= (list_of (braun_of x n)) (replicate n x))))
; braun(braun_of(x,n))
(assert (forall ((x A) (n nat)) (braun (braun_of x n))))
; braun2_of(x,n) = (s,t) -> list(s) = replicate(n,x) & list(t) = replicate(n + 1, x)
(assert (forall ((x A) (n nat) (t (tree A)) (t' (tree A))) (=> (= (braun2_of x n) (Pair t t'))
  (and (= (list_of t) (replicate n x)) (= (list_of t') (replicate (s n) x))))))
; braun2_of(x,n) = (s,t) -> |s| = n & |t| = n + 1 & braun(s) & braun(t)
(assert (forall ((x A) (n nat) (t (tree A)) (t' (tree A))) (=> (= (braun2_of x n) (Pair t t'))
  (and (= (size t) n) (= (size t') (s n)) (braun t) (braun t')))))
; take_nths(i,k,drop(j,xs)) = take_nths(i + j,k,xs)
(assert (forall ((i nat) (k nat) (j nat) (xs (list A))) (= (take_nths i k (drop j xs)) (take_nths (plus i j) k xs))))
; take_nths(0,0,xs) = xs
(assert (forall ((xs (list A))) (= (take_nths zero zero xs) xs)))
; splice(take_nths(0,1,xs),take_nths(1,1,xs)) = xs
(assert (forall ((xs (list A))) (= (splice (take_nths zero (s zero) xs) (take_nths (s zero) (s zero) xs)) xs)))
; take_nths(i,m,take_nths(j,n,xs)) = take_nths(i * 2^n + j, m + n, xs)
(assert (forall ((i nat) (m nat) (j nat) (n nat) (xs (list A)))
  (= (take_nths i m (take_nths j n xs)) (take_nths (plus (mult i (pow2 n)) j) (plus m n) xs))))
; take_nths(i,k,xs) = [] <-> |xs| <= i
; TODO unsat
;(assert (forall ((i nat) (k nat) (xs (list A))) (= (= (take_nths i k  xs) (as Nil (list A))) (leq (len xs) i))))
; i < |xs| -> hd(take_nths(i,k,xs)) = xs ! i
(assert (forall ((i nat) (k nat) (xs (list A))) (=> (less i (len xs)) (= (hd (take_nths i k xs)) (nth xs i)))))
; |xs| = |ys| | |xs| = |ys| + 1 -> take_nths(0,1,splice(xs,ys)) = xs & take_nths(1,1,splice(xs,ys)) = ys
(assert (forall ((xs (list A)) (ys (list A))) (=> (or (= (len xs) (len ys)) (= (len xs) (s (len ys))))
  (and (= (take_nths zero (s zero) (splice xs ys)) xs)
       (= (take_nths (s zero) (s zero) (splice xs ys)) ys)))))
; |take_nths(0,1,xs)| = |take_nths(1,1,xs)| | |take_nths(0,1,xs)| = |take_nths(1,1,xs)| + 1
(assert (forall ((xs (list A))) (or (= (len (take_nths zero (s zero) xs)) (len (take_nths (s zero) (s zero) xs)))
  (= (len (take_nths zero (s zero) xs)) (s (len (take_nths (s zero) (s zero) xs)))))))
; braun_list(t,xs) <-> braun(t) & xs = list(t)
(assert (forall ((t (tree A)) (xs (list A))) (= (braun_list t xs) (and (braun t) (= xs (list_of t))))))
; |nodes(ls,xs,rs)| = |xs|
(assert (forall ((ls (list (tree A))) (xs (list A)) (rs (list (tree A)))) (= (len (nodes ls xs rs)) (len xs))))
; i < |xs| -> nodes(ls,xs,rs) ! i = <if i < |ls| then ls ! i else <>, xs ! i, if i < |rs| then rs ! i else <>>
(assert (forall ((i nat) (ls (list (tree A))) (xs (list A)) (rs (list (tree A)))) (=> (less i (len xs))
  (= (nth (nodes ls xs rs) i) (Node (ite (less i (len ls)) (nth ls i) (as Leaf (tree A)))
    (nth xs i) (ite (less i (len rs)) (nth rs i) (as Leaf (tree A))))))))
; |brauns(k,xs)| = min(|xs|,2^k)
(assert (forall ((k nat) (xs (list A))) (= (len (brauns k xs)) (min (len xs) (pow2 k)))))
; i < min(|xs|,2^k) -> braun_list(brauns(k,xs) ! i, take_nths(i,k,xs))
(assert (forall ((i nat) (k nat) (xs (list A))) (=> (less i (min (len xs) (pow2 k))) (braun_list (nth (brauns k xs) i) (take_nths i k xs)))))
; braun(brauns1(xs)) & list(brauns1(xs)) = xs
(assert (forall ((xs (list A))) (and (braun (brauns1 xs)) (= (list_of (brauns1 xs)) xs))))
; T_brauns(k,xs) = 4 * |xs|
(assert (forall ((k nat) (xs (list A))) (= (T_brauns k xs) (mult (s (s (s (s zero)))) (len xs)))))
; |ts| = 2^k & (!i<2^k.braun_list(ts ! i, take_nths(i,k,xs))) -> list_fast_rec(ts) = xs
; TODO list_fast_rec needs map function
;(assert (forall ((k nat) (ts (list A)) (xs (list A))) (=> (and (= (len ts) (pow2 k))
;  (forall ((i nat)) (=> (less i (pow2 k)) (braun_list (nths a ts i) (take_nths i k xs)))))
;    (= (list_fast_rec a ts) xs))))
; map_value(ts) = take(2^k,xs)

; list_fast_rec(map(left,ts) @ map(right,ts)) = drop(2^k,xs)

; TODO these two need sum functions
; (!t in set(ts).t != <>) -> ...
; Theorem 11.9

; braun(t) -> h(t) = ceil(lg(|t|_1))

; braun(t) -> 2^h(t) <= 2 * |t| + 1
(assert (forall ((t (tree A))) (=> (braun t) (leq (pow2 (h t)) (s (mult (s (s zero)) (size t)))))))
; n <= |xs| & bal(n,xs) = (t,zs) -> braun(t)
(assert (forall ((n nat) (xs (list A)) (t (tree A)) (zs (list A))) (=> (and (leq n (len xs)) (= (balance n xs) (Pair t zs))) (braun t))))
; braun(t) & nat_of(bs) in {1..|t|} -> lookup_trie(t,bs) = lookup1(t,nat_of(bs))
(assert (forall ((t (tree A)) (bs (list Bool))) (=> (and (braun t) (leq (s zero) (nat_of bs)) (leq (nat_of bs) (size t)))
  (= (lookup_trie t bs) (lookup1 t (nat_of bs))))))
; update_trie(bs,x,t) = update1(nat_of(bs),x,t)

; del_lo2(t) = del_lo(t)

; braun(t) -> lh(t) = h(t)
(assert (forall ((t (tree A))) (=> (braun t) (= (lh t) (h t)))))
; T_size_fast(t) <= h(t)^2

; list(braun_of_naive(x,n)) = replicate(n,x)
(assert (forall ((x A) (n nat)) (= (list_of (braun_of_naive x n)) (replicate n x))))

; TODO most of these contain lambdas
; Tries:
; ...


; 
; Huffman's algorithm:
; consistent(t) & a in alphabet(t) & b in alphabet(t) & freq(t,a) <= freq(t,b) & depth(t,a) <= depth(t,b) -> cost(swapSyms(t,a,b)) <= cost(t)
(assert (forall ((t (treeh A)) (x A) (y A)) (=> (and (consistent t) (in_alphabet x t) (in_alphabet y t)
  (leq (freq t x) (freq t y)) (leq (depth t x) (depth t y))) (leq (cost (swapSyms t x y)) (cost t)))))
; consistent(t) & sibling(t,a) != a -> cost(mergeSibling(t,a)) + freq(t,a) + freq(t,sibling(t,a)) = cost(t)
(assert (forall ((t (treeh A)) (x A)) (=> (and (consistent t) (distinct (sibling t x) x))
  (= (plus (plus (cost (mergeSibling t x)) (freq t x)) (freq t (sibling t x))) (cost t)))))
; consistent(t) & a in alphabet(t) & freq(t,a) = wa + wb -> cost(splitLeaf(t,wa,a,wb,b)) = cost(t) + wa + wb
(assert (forall ((t (treeh A)) (x A) (wx nat) (y A) (wy nat)) (=> (and (consistent t) (in_alphabet x t) (= (freq t x) (plus wx wy)))
  (= (cost (splitLeaf t wx x wy y)) (plus (plus (cost t) wx) wy)))))
; ts != [] -> alphabet (huffman ts) = alphabet_F ts
(assert (forall ((ts (list (treeh A)))) (=> (distinct ts (as Nil (list (treeh A))))
  (forall ((x A)) (= (in_alphabet x (huffman ts)) (in_alphabet_F x ts))))))
; consistent_F ts & ts != [] -> consistent (huffman ts)
(assert (forall ((ts (list (treeh A)))) (=> (and (consistent_F ts) (distinct ts (as Nil (list (treeh A))))) (consistent (huffman ts)))))
; ts != [] -> freq (huffman ts) a = freq_F ts a
(assert (forall ((ts (list (treeh A)))) (=> (distinct ts (as Nil (list (treeh A)))) (forall ((x A)) (= (freq (huffman ts) x) (freq_F ts x))))))
; consistent t & minima t a b & c in alphabet t & d in alphabet t & depth t c = height t & depth t d = height t & c != d
;   -> cost (swapFourSyms t a b c d) <= cost t
(assert (forall ((t (treeh A)) (x A) (y A) (z A) (u A)) (=> (and (consistent t) (minima t x y) (in_alphabet z t)
  (in_alphabet u t) (= (depth t z) (height t)) (= (depth t u) (height t)) (distinct z u))
    (leq (cost (swapFourSyms t x y z u)) (cost t)))))
; consistent t & optimum t & a in alphabet t & b not in alphabet t & freq t a = wa + wb &
;   (!c in alphabet t. wa <= freq t c & wb <= freq t c) -> optimum (splitLeaf t wa a wb b)
(assert (forall ((t (treeh A)) (x A) (y A) (wx nat) (wy nat)) (=> (and (consistent t) (optimum t) (in_alphabet x t)
  (not (in_alphabet y t)) (= (freq t x) (plus wx wy)) (forall ((z A)) (=> (in_alphabet z t) (and (leq wx (freq t z))
    (leq wy (freq t z)))))) (optimum (splitLeaf t wx x wy y)))))
; consistent_F ts & ts != [] & a in alphabet_F ts & freq_F ts a = wa + wb
;   -> splitLeaf (huffman ts) wa a wb b = huffman (splitLeaf_F ts wa a wb b)
(assert (forall ((ts (list (treeh A))) (x A) (y A) (wx nat) (wy nat)) (=> (and (consistent_F ts) (distinct ts (as Nil (list (treeh A))))
  (in_alphabet_F x ts) (= (freq_F ts x) (plus wx wy))) (= (splitLeaf (huffman ts) wx x wy y) (huffman (splitLeaf_F ts wx x wy y))))))
; consistent_F ts & height_F ts = 0 & sortedByWeight ts & ts != [] -> optimum (huffman ts)
(assert (forall ((ts (list (treeh A)))) (=> (and (consistent_F ts) (= (height_F ts) zero) (sortedByWeight ts)
  (distinct ts (as Nil (list (treeh A))))) (optimum (huffman ts)))))

; Priority queues

; Leftist heaps
; heap t & t != <> -> get_min t = Min (set_tree t)

; mset_tree (merge t1 t2) = mset_tree t1 + mset_tree t2
(assert (forall ((t1 (lheap A)) (t2 (lheap A)) (x A)) (= (count_ptree x (merge_lheap t1 t2)) (plus (count_ptree x t1) (count_ptree x t2)))))
; ltree l & ltree r -> ltree (merge l r)
; TODO if we write lheap instead of ltree Vampire crashes. Fix it with a user error message.
(assert (forall ((l (lheap A)) (r (lheap A))) (=> (and (ltree l) (ltree r)) (ltree (merge_lheap l r)))))
; heap l & heap r -> heap (merge l r)
(assert (forall ((l (lheap A)) (r (lheap A))) (=> (and (heapp l) (heapp r)) (heapp (merge_lheap l r)))))
; mset_tree (insert x t) = mset_tree t + {{x}}
(assert (forall ((x A) (y A) (t (lheap A))) (= (count_ptree y (insert_lheap x t)) (ite (= x y) (s (count_ptree y t)) (count_ptree y t)))))
; mset_tree (del_min t) = mset_tree t - {{ get_min t}}
(assert (forall ((x A) (t (lheap A))) (= (count_ptree x (del_min_lheap t)) (ite (= x (get_minp t)) (s_0 (count_ptree x t)) (count_ptree x t)))))
; ltree t -> ltree (insert x t)
(assert (forall ((x A) (t (lheap A))) (=> (ltree t) (ltree (insert_lheap x t)))))
; heap t -> heap (insert x t)
(assert (forall ((x A) (t (lheap A))) (=> (heapp t) (heapp (insert_lheap x t)))))
; ltree t -> ltree (del_min t)
(assert (forall ((t (lheap A))) (=> (ltree t) (ltree (del_min_lheap t)))))
; heap t -> heap (del_min t)
(assert (forall ((t (lheap A))) (=> (heapp t) (heapp (del_min_lheap t)))))
; ltree l & ltree r -> T_merge l r <= mh l + mh r + 1
(assert (forall ((l (lheap A)) (r (lheap A))) (=> (and (ltree l) (ltree r)) (leq (T_merge_lheap l r) (plus (plus (mh l) (mh r)) (s zero))))))
; ltree l & ltree r -> T_merge l r <= lg |l|_1 + lg |r|_1 + 1 ; TODO double check this
(assert (forall ((l (lheap A)) (r (lheap A))) (=> (and (ltree l) (ltree r)) (leq (pow2 (T_merge_lheap l r)) (mult (mult (size1 l) (size1 r)) (s (s zero)))))))
; ltree t -> T_insert x t <= lg |t|_1 + 3 ; TODO double check this
(assert (forall ((x A) (t (lheap A))) (=> (ltree t) (leq (pow2 (T_insert_lheap x t)) (mult (size1 t) (pow2 (s (s (s zero)))))))))
; ltree t -> T_del_min t <= 2 * lg |t|_1 + 1 ; TODO double check this
(assert (forall ((t (lheap A))) (=> (ltree t) (leq (pow2 (T_del_min_lheap t)) (mult (mult (size1 t) (size1 t)) (s (s zero)))))))
; Braun tree priority queues
; |insert x t| = |t| + 1
(assert (forall ((x A) (t (tree A))) (= (size (insert_braun x t)) (s (size t)))))
; mset_tree (insert x t) = {{x}} + mset_tree t
(assert (forall ((x A) (y A) (t (tree A))) (= (count_tree y (insert_braun x t)) (ite (= x y) (s (count_tree y t)) (count_tree y t)))))
; braun t -> braun (insert x t)
(assert (forall ((x A) (t (tree A))) (=> (braun t) (braun (insert_braun x t)))))
; heap t -> heap (insert x t)
(assert (forall ((x A) (t (tree A))) (=> (heap t) (heap (insert_braun x t)))))
; del_left t = (x,t') & t != <> -> mset_tree t = {{x}} + mset_tree t'
(assert (forall ((x A) (t (tree A)) (t' (tree A))) (=> (and (= (del_left t) (Pair x t')) (distinct t (as Leaf (tree A))))
  (forall ((y A)) (= (count_tree y t) (ite (= x y) (count_tree y t') (s (count_tree y t'))))))))
; del_left t = (x,t') & t != <> & heap t -> heap t'
(assert (forall ((x A) (t (tree A)) (t' (tree A))) (=> (and (= (del_left t) (Pair x t')) (distinct t (as Leaf (tree A))) (heap t)) (heap t'))))
; del_left t = (x,t') & t != <> -> |t| = |t'| + 1
(assert (forall ((x A) (t (tree A)) (t' (tree A))) (=> (and (= (del_left t) (Pair x t')) (distinct t (as Leaf (tree A)))) (= (size t) (s (size t'))))))
; del_left t = (x,t') & t != <> & braun t -> braun t'
(assert (forall ((x A) (t (tree A)) (t' (tree A))) (=> (and (= (del_left t) (Pair x t')) (distinct t (as Leaf (tree A))) (braun t)) (braun t'))))
; braun <l,a,r> -> |sift_down l a r| = |l| + |r| + 1
(assert (forall ((l (tree A)) (x A) (r (tree A))) (=> (braun (Node l x r)) (= (size (sift_down l x r)) (s (plus (size l) (size r)))))))
; braun <l,a,r> -> braun (sift_down l a r)
(assert (forall ((l (tree A)) (x A) (r (tree A))) (=> (braun (Node l x r)) (braun (sift_down l x r)))))
; braun <l,a,r> -> mset_tree (sift_down l a r) = {{a}} + (mset_tree l + mset_tree r)
(assert (forall ((l (tree A)) (x A) (r (tree A))) (=> (braun (Node l x r)) (forall ((y A)) (= (count_tree y (sift_down l x r)) (ite (= x y)
    (s (plus (count_tree y l) (count_tree y r))) (plus (count_tree y l) (count_tree y r))))))))
; braun <l,a,r> & heap l & heap r -> heap (sift_down l a r)
(assert (forall ((l (tree A)) (x A) (r (tree A))) (=> (and (braun (Node l x r)) (heap l) (heap r)) (heap (sift_down l x r)))))
; braun t -> braun (del_min t)
(assert (forall ((t (tree A))) (=> (braun t) (braun (del_min_braun t)))))
; heap t & braun t -> heap (del_min t)
(assert (forall ((t (tree A))) (=> (and (heap t) (braun t)) (heap (del_min_braun t)))))
; braun t -> |del_min t| = |t| - 1
; deliberate use of s_0 to be consistent with the case of t being a leaf
(assert (forall ((t (tree A))) (=> (braun t) (= (size (del_min_braun t)) (s_0 (size t))))))
; braun t & t != <> -> mset_tree (del_min t) = mset_tree t - {{ get_min t }}
(assert (forall ((x A) (t (tree A))) (=> (and (braun t) (distinct t (as Leaf (tree A))))
  (= (count_tree x (del_min_braun t)) (ite (= x (get_min t)) (s_0 (count_tree x t)) (count_tree x t))))))


; Binomial heaps
; invar_btree t -> |mset_tree t| = 2^(rank t)
; invar ts -> |ts| <= lg (|mset_heap ts| + 1)
; invar_tree t1 & invar_tree t2 & rank t1 = rank t2 -> invar_tree (link t1 t2)
; mset_tree (link t1 t2) = mset_tree t1 + mset_tree t2
; invar_tree t & invar ts & (!t' in set ts. rank t <= rank t') -> invar (ins_tree t ts)
; mset_heap (ins_tree t ts) = mset_tree t + mset_heap ts
; invar t -> invar (insert x t)
; mset_heap (insert x t) = {{x}} + mset_heap t
; invar ts1 & invar ts2 -> invar (merge ts1 ts2)
; mset_heap (merge ts1 ts2) = mset_heap ts1 + mset_heap ts2
; t' in set (merge ts1 ts2) & (!t1 in set ts1. rank t < rank t1) & (!t2 in set ts2. rank t < rank t2) ->
;   rank t < rank t'
; mset_heap ts != {{}} & invar ts -> get_min ts = Min_mset (mset_heap ts)
; ts != [] & invar ts -> invar (del_min ts)
; ts != [] -> mset_heap ts = mset_heap (del_min ts) + {{get_min ts}}
; get_min_rest ts = (t',ts') & ts != [] & invar ts -> invar_tree t'
; get_min_rest ts = (t',ts') & ts != [] & invar ts -> invar ts'
; ts != [] & get_min_rest ts = (t',ts') -> root t' = get_min ts
; T_ins_tree t ts <= |ts| + 1
; invar ts -> T_insert x ts <= lg (|mset_heap ts| + 1) + 2
; T_ins_tree t ts + |ins_tree t ts| = 2 + |ts|
; |merge ts1 ts2| + T_merge ts1 ts2 <= 2 * (|ts1| + |ts2|) + 1
; invar ts1 & invar ts2 -> T_merge ts1 ts2 <= 4 * lg (|mset_heap ts1| + |mset_heap ts2| + 1) + 1
; invar ts & ts != [] -> T_del_min ts <= 6 * lg(|mset_heap ts| + 1) + 3
; invar_btree t -> nol l t = rank t choose l

; Dynamic programming
; from this chapter everything uses states with lambdas so we cannot parse these

; Queues
; T_enq a (fs, rs) + psi(enq a (fs, rs)) - psi(fs,rs) <= 4
; T_deq (fs, rs) + psi(deq (fs, rs)) - psi(fs,rs) <= 3
; rev_step^|xs|(xs,ys) = ([],rev xs @ ys)
; rev_step^|xs|(xs,[]) = ([],rev xs)
; ...

; Splay trees
; splay a t = <> <-> t = <>
(assert (forall ((x A) (t (tree A))) (= (= (splay x t) (as Leaf (tree A))) (= t (as Leaf (tree A))))))
; splay_max t = <> <-> t = <>
(assert (forall ((t (tree A))) (= (= (splay_max t) (as Leaf (tree A))) (= t (as Leaf (tree A))))))
; sorted (inorder t) -> isin t x = (x in set (inorder t))
(assert (forall ((t (tree A)) (x A)) (=> (sorted_s (inorder t)) (= (isin_splay t x) (in_set x (inorder t))))))
; splay x t = <l, a, r> & sorted (inorder t) -> (x in set (inorder t)) = (x = a)
(assert (forall ((t (tree A)) (x A) (l (tree A)) (y A) (r (tree A))) (=> (and (= (splay x t) (Node l y r))
  (sorted_s (inorder t))) (= (in_set x (inorder t)) (= x y)))))
; sorted (inorder t) -> inorder (insert x t) = ins_list x (inorder t)
(assert (forall ((t (tree A)) (x A)) (=> (sorted_s (inorder t)) (= (inorder (insert_splay x t)) (ins_list x (inorder t))))))
; sorted (inorder t) -> inorder (delete x t) = del_list x (inorder t)
(assert (forall ((t (tree A)) (x A)) (=> (sorted_s (inorder t)) (= (inorder (delete_splay x t)) (del_list x (inorder t))))))
; inorder (splay x t) = inorder t
(assert (forall ((t (tree A)) (x A)) (= (inorder (splay x t)) (inorder t))))
; sorted (inorder t) & splay x t = <l,a,r> -> sorted (inorder l @ x # inorder r)
(assert (forall ((t (tree A)) (x A) (l (tree A)) (y A) (r (tree A))) (=> (and (sorted_s (inorder t)) (= (splay x t) (Node l y r)))
  (sorted_s (append (inorder l) (Cons x (inorder r)))))))
; splay_max t = <l,a,r> & sorted (inorder t) -> inorder l @ [a] = inorder t & r = <>
(assert (forall ((t (tree A)) (l (tree A)) (y A) (r (tree A))) (=> (and (= (splay_max t) (Node l y r)) (sorted_s (inorder t)))
  (and (= (append (inorder l) (Cons y (as Nil (list A)))) (inorder t)) (= r (as Leaf (tree A)))))))
; |splay a t| = |t|
(assert (forall ((x A) (t (tree A))) (= (size (splay x t)) (size t))))
; |splay_max t| = |t|
(assert (forall ((t (tree A))) (= (size (splay_max t)) (size t))))
; A_splay a t = T_splay a t + psi(splay t) - psi t

; bst t & <l,x,r> in subtrees t -> A_splay x t <= 3 * (phi t - phi <l,x,r>) + 1

; bst t & x in set_tree t -> A_splay x t <= 3 * (phi t - 1) + 1

; t != <> & bst t -> (?y in set_tree t. splay y t = splay x t & T_splay y t = T_splay x t)

; bst t -> A_splay x t <= 3 * phi t + 1

; bst t -> T_insert x t + psi (insert x t) - psi t <= 4 * phi t + 3

; t != <> -> A_splay_max t <= 3 * (phi t - 1) + 1

; A_splay_max t <= 3 * phi t + 1

; bst t -> T_delete a t + psi (delete t) - psi t <= 6 * phi t + 3


; Skew heaps
; |merge t1 t2| = |t1| + |t2|
(assert (forall ((t1 (tree A)) (t2 (tree A))) (= (size (merge_skew t1 t2)) (plus (size t1) (size t2)))))
; mset_tree (merge t1 t2) = mset_tree t1 + mset_tree t2
(assert (forall ((x A) (t1 (tree A)) (t2 (tree A))) (= (count_tree x (merge_skew t1 t2)) (plus (count_tree x t1) (count_tree x t2)))))
; heap t1 & heap t2 -> heap (merge t1 t2)
(assert (forall ((t1 (tree A)) (t2 (tree A))) (=> (and (heap t1) (heap t2)) (heap (merge_skew t1 t2)))))
; 2^(lrh t) <= |t| + 1
(assert (forall ((t (tree A))) (leq (pow2 (lrh t)) (s (size t)))))
; 2^(rlh t) <= |t| + 1
(assert (forall ((t (tree A))) (leq (pow2 (rlh t)) (s (size t)))))
; lrh t <= lg |t|_1
(assert (forall ((t (tree A))) (leq (pow2 (lrh t)) (size1 t))))
; rlh t <= lg |t|_1
(assert (forall ((t (tree A))) (leq (pow2 (rlh t)) (size1 t))))
; T_merge t1 t2 + psi (merge t1 t2) - psi t1 - psi t2 <= lrh (merge t1 t2) + rlh t1 + rlh t2 + 1
(assert (forall ((t1 (tree A)) (t2 (tree A))) (leq (minus (minus (plus (T_merge_skew t1 t2) (psi_skew (merge_skew t1 t2)))
  (psi_skew t1)) (psi_skew t2)) (s (plus (plus (lrh (merge_skew t1 t2)) (rlh t1)) (rlh t2))))))
; T_insert a t + psi (insert t) - psi t <= 3 * lg(|t|_1 + 2) + 2

; T_del_min t + psi (del_min t) - psi t <= 3 * lg(|t|_1 + 2) + 2


; Pairing heaps
; h != Empty -> get_min h in mset_heap h
; h != Empty & pheap h  & x in mset_heap h -> get_min h <= x
; mset_heap (merge h1 h2) = mset_heap h1 + mset_heap h2
; mset_heap (merge_pairs hs) = sum (image_mset mset_heap (mset hs))
; h != Empty -> mset_heap (del_min h) = mset_heap h - {{get_min h}}
; pheap h1 & pheap h2 -> pheap (merge h1 h2)
; (!h in set hs. pheap h) -> pheap (merge_pairs hs)
; pheap h -> pheap (del_min h)
; |link hp| = |hp|
; |pass1 hp| = |hp|
; |pass2 hp| = |hp|
; is_root h1 & is_root h2 -> |merge h1 h2| = |h1| + |h2|
; is_root hp -> psi (insert x hp) - psi hp <= lg (|hp| + 1)
; h1 = <hs1, x1, <>> & h2 = <hs2,x2,<>> -> psi (merge h1 h2) - psi h1 - psi h2 <= lg (|h1| + |h2|) + 1
; psi (del_min <hs,x,<>>) - psi <hs,x,<>> <= 2 * lg (|hs| + 1) - len hs + 2
; psi (pass1 hs) - psi hs <= 2 * lg (|hs| + 1) - len hs + 2
; hs != <> -> psi (pass2 hs) - psi hs <= lg |hs|
; psi (pass2 hs) - psi hs <= lg (|hs| + 1)
; is_root h -> T_insert a h + psi (insert h) - psi h <= lg (|h| + 1) + 1
; is_root h1 & is_root h2 -> T_merge h1 h2 + psi (merge h1 h2) - psi h1 - psi h2 <= lg (|h1| + |h2| + 1) + 2
; T_pass2 (pass1 hs1) + T_pass1 hs1 <= len hs1 + 2
; is_root h -> T_del_min h + psi (del_min h) - psi h <= 2 * lg (|h| + 1) + 5

(declare-sort S 0)
(assert-not (forall ((x S)) (= (inorder (as Leaf (tree S))) (as Nil (list S)))))