(* BEGIN NEW MATERIAL *)

Class heightable (A : Type) : Type := Heightable {
  height : A -> nat;
  is_height_zero : forall a : A, {height a = 0} + {height a <> 0} (* Should run in O(1) time for trees *)
 }.(* BEGIN NEW MATERIAL *)

Class heightable (A : Type) : Type := Heightable {
  height : A -> nat;
  is_height_zero : forall a : A, {height a = 0} + {height a <> 0} (* Should run in O(1) time for trees *)
 }.(* BEGIN NEW MATERIAL *)

Class heightable (A : Type) : Type := Heightable {
  height : A -> nat;
  is_height_zero : forall a : A, {height a = 0} + {height a <> 0} (* Should run in O(1) time for trees *)
 }.(* BEGIN NEW MATERIAL *)

Class heightable (A : Type) : Type := Heightable {
  height : A -> nat;
  is_height_zero : forall a : A, {height a = 0} + {height a <> 0} (* Should run in O(1) time for trees *)
 }.Definition is_height_zero_spec {A : Type} (height : A -> nat) : Type :=
  forall a : A, {height a = 0} + {height a <> 0}.Definition list_height {A} `{heightable A} (LA : list A) : nat :=
  fold_right max 0 (map height LA).Fixpoint list_is_height_zero_bool {A} `{heightable A} (L : list A) : bool :=
  match L with
   | nil => true
   | a :: L' =>
      if is_height_zero a then list_is_height_zero_bool L' else false
  end.Instance list_heightable {A} `{heightable A} : heightable (list A).Class decomposible (A : Type) : Type := Decomposible {
  decompose : A -> (A * A)
 }.Class decomposible (A : Type) : Type := Decomposible {
  decompose : A -> (A * A)
 }.Class decomposible (A : Type) : Type := Decomposible {
  decompose : A -> (A * A)
 }.Class roundableLeft (A : Type) : Type := RoundableLeft {
   roundL : nat -> A -> option A
 }.Class roundableLeft (A : Type) : Type := RoundableLeft {
   roundL : nat -> A -> option A
 }.Class roundableLeft (A : Type) : Type := RoundableLeft {
   roundL : nat -> A -> option A
 }.Class roundableRight (A : Type) : Type := RoundableRight {
   roundR : nat -> A -> option A
 }.Class roundableRight (A : Type) : Type := RoundableRight {
   roundR : nat -> A -> option A
 }.Class roundableRight (A : Type) : Type := RoundableRight {
   roundR : nat -> A -> option A
 }.Class avgable (A : Type) : Type := Avgable {
    avg : nat -> A -> A -> option A
 }.Class avgable (A : Type) : Type := Avgable {
    avg : nat -> A -> A -> option A
 }.Class avgable (A : Type) : Type := Avgable {
    avg : nat -> A -> A -> option A
 }.

(* Specifications: *)
Lemma ord_spec1 : forall x y, x <= y <-> x = glb x y.
Lemma ord_spec2 : forall x y, x <= y <-> lub x y = y.
Lemma lub_idem : forall x, lub x x = x.
Lemma glb_idem : forall x, glb x x = x.
Lemma lub_commute : forall x y, lub x y = lub y x.
Lemma glb_commute : forall x y, glb x y = glb y x.
Lemma lub_absorb : forall x y, lub x (glb x y) = x.
Lemma glb_absorb : forall x y, glb x (lub x y) = x.
Lemma lub_assoc : forall x y z, lub (lub x y) z = lub x (lub y z).
Lemma glb_assoc : forall x y z, glb (glb x y) z = glb x (glb y z).
Lemma glb_bot : forall x, glb x bot = bot.
Lemma lub_top : forall x, lub x top = top.
Lemma lub_bot : forall x, lub x bot = x.
Lemma glb_top : forall x, glb x top = x.
Lemma distrib2 : forall x y z, lub x (glb y z) = glb (lub x y) (lub x z).
Lemma distrib_spec : forall x y1 y2, lub x y1 = lub x y2 -> glb x y1 = glb x y2 -> y1 = y2.
Lemma comp_inv : forall x, comp (comp x) = x.
Lemma demorgan1 : forall x y, comp (lub x y) = glb (comp x) (comp y).
Lemma demorgan2 : forall x y, comp (glb x y) = lub (comp x) (comp y).