Inductive heap: Type :=
  | Empty
  | Node (l: heap) (x: E.t) (r: heap).Inductive heap: Type :=
  | Empty
  | Node (l: heap) (x: E.t) (r: heap).Inductive heap: Type :=
  | Empty
  | Node (l: heap) (x: E.t) (r: heap).Fixpoint partition (pivot: E.t) (h: heap) { struct h } : heap * heap :=
  match h with
  | Empty => (Empty, Empty)
  | Node a x b =>
      match E.compare x pivot with
      | EQ _ => (a, b)
      | LT _ =>
        match b with
        | Empty => (h, Empty)
        | Node b1 y b2 =>
            match E.compare y pivot with
            | EQ _ => (Node a x b1, b2)
            | LT _ =>
              let (small, big) := partition pivot b2
              in (Node (Node a x b1) y small, big)
            | GT _ =>
              let (small, big) := partition pivot b1
              in (Node a x small, Node big y b2)
            end
        end
     | GT _ =>
        match a with
        | Empty => (Empty, h)
        | Node a1 y a2 =>
            match E.compare y pivot with
            | EQ _ => (a1, Node a2 x b)
            | LT _ =>
              let (small, big) := partition pivot a2
              in (Node a1 y small, Node big x b)
            | GT _ =>
              let (small, big) := partition pivot a1
              in (small, Node big y (Node a2 x b))
            end
        end
    end
  end.Definition insert (x: E.t) (h: heap) : heap :=
  let (a, b) := partition x h in Node a x b.Fixpoint findMin (h: heap) : option E.t :=
  match h with
  | Empty => None
  | Node Empty x b => Some x
  | Node a x b => findMin a
  end.Fixpoint deleteMin (h: heap) : heap :=
  match h with
  | Empty => Empty
  | Node Empty x b => b
  | Node (Node Empty x b) y c => Node b y c
  | Node (Node a x b) y c => Node (deleteMin a) x (Node b y c)
  end.Fixpoint findMax (h: heap) : option E.t :=
  match h with
  | Empty => None
  | Node a x Empty => Some x
  | Node a x b => findMax b
  end.Fixpoint deleteMax (h: heap) : heap :=
  match h with
  | Empty => Empty
  | Node b x Empty => b
  | Node b x (Node c y Empty) => Node b x c
  | Node a x (Node b y c) => Node (Node a x b) y (deleteMax c)
  end.(** Induction principles for some of the operators. *)

Scheme heap_ind := Induction for heap Sort Prop.(** Specification *)

Fixpoint In (x: E.t) (h: heap) : Prop :=
  match h with
  | Empty => False
  | Node a y b => In x a \/ E.eq x y \/ In x b
  end.(** Invariants *)

Fixpoint lt_heap (h: heap) (x: E.t) : Prop :=
  match h with
  | Empty => True
  | Node a y b => lt_heap a x /\ E.lt y x /\ lt_heap b x
  end.Fixpoint gt_heap (h: heap) (x: E.t) : Prop :=
  match h with
  | Empty => True
  | Node a y b => gt_heap a x /\ E.lt x y /\ gt_heap b x
  end.Fixpoint bst (h: heap) : Prop :=
  match h with
  | Empty => True
  | Node a x b => bst a /\ bst b /\ lt_heap a x /\ gt_heap b x
  end.Definition le (x y: E.t) := E.eq x y \/ E.lt x y.

(* Specifications: *)
Lemma le_lt_trans: forall x1 x2 x3, le x1 x2 -> E.lt x2 x3 -> E.lt x1 x3.
Lemma lt_le_trans: forall x1 x2 x3, E.lt x1 x2 -> le x2 x3 -> E.lt x1 x3.
Lemma le_trans: forall x1 x2 x3, le x1 x2 -> le x2 x3 -> le x1 x3.
Lemma lt_heap_trans: forall x y, le x y -> forall h, lt_heap h x -> lt_heap h y.
Lemma gt_heap_trans: forall x y, le y x -> forall h, gt_heap h x -> gt_heap h y.
Lemma In_partition: forall x pivot, ~E.eq x pivot -> forall h, bst h -> (In x h <-> In x (fst (partition pivot h)) \/ In x (snd (partition pivot h))).
Lemma partition_lt: forall x pivot h, lt_heap h x -> lt_heap (fst (partition pivot h)) x /\ lt_heap (snd (partition pivot h)) x.
Lemma partition_gt: forall x pivot h, gt_heap h x -> gt_heap (fst (partition pivot h)) x /\ gt_heap (snd (partition pivot h)) x.
Lemma partition_split: forall pivot h, bst h -> lt_heap (fst (partition pivot h)) pivot /\ gt_heap (snd (partition pivot h)) pivot.
Lemma partition_bst: forall pivot h, bst h -> bst (fst (partition pivot h)) /\ bst (snd (partition pivot h)).
Lemma insert_bst: forall x h, bst h -> bst (insert x h).
Lemma In_insert: forall x h y, bst h -> (In y (insert x h) <-> E.eq y x \/ In y h).
Lemma deleteMin_lt: forall x h, lt_heap h x -> lt_heap (deleteMin h) x.
Lemma deleteMin_bst: forall h, bst h -> bst (deleteMin h).
Lemma In_deleteMin: forall y x h, findMin h = Some x -> (In y h <-> E.eq y x \/ In y (deleteMin h)).
Lemma gt_heap_In: forall x y h, gt_heap h x -> In y h -> E.lt x y.
Lemma findMin_min: forall x h, findMin h = Some x -> bst h -> forall y, In y h -> le x y.
Lemma findMin_empty: forall h, h <> Empty -> findMin h <> None.
Lemma deleteMax_gt: forall x h, gt_heap h x -> gt_heap (deleteMax h) x.
Lemma deleteMax_bst: forall h, bst h -> bst (deleteMax h).
Lemma In_deleteMax: forall y x h, findMax h = Some x -> (In y h <-> E.eq y x \/ In y (deleteMax h)).
Lemma lt_heap_In: forall x y h, lt_heap h x -> In y h -> E.lt y x.
Lemma findMax_max: forall x h, findMax h = Some x -> bst h -> forall y, In y h -> le y x.
Lemma findMax_empty: forall h, h <> Empty -> findMax h <> None.
Lemma le_lt_trans: forall x1 x2 x3, le x1 x2 -> E.lt x2 x3 -> E.lt x1 x3.
Lemma lt_le_trans: forall x1 x2 x3, E.lt x1 x2 -> le x2 x3 -> E.lt x1 x3.
Lemma le_trans: forall x1 x2 x3, le x1 x2 -> le x2 x3 -> le x1 x3.
Lemma lt_heap_trans: forall x y, le x y -> forall h, lt_heap h x -> lt_heap h y.
Lemma gt_heap_trans: forall x y, le y x -> forall h, gt_heap h x -> gt_heap h y.
Lemma In_partition: forall x pivot, ~E.eq x pivot -> forall h, bst h -> (In x h <-> In x (fst (partition pivot h)) \/ In x (snd (partition pivot h))).
Lemma partition_lt: forall x pivot h, lt_heap h x -> lt_heap (fst (partition pivot h)) x /\ lt_heap (snd (partition pivot h)) x.
Lemma partition_gt: forall x pivot h, gt_heap h x -> gt_heap (fst (partition pivot h)) x /\ gt_heap (snd (partition pivot h)) x.
Lemma partition_split: forall pivot h, bst h -> lt_heap (fst (partition pivot h)) pivot /\ gt_heap (snd (partition pivot h)) pivot.
Lemma partition_bst: forall pivot h, bst h -> bst (fst (partition pivot h)) /\ bst (snd (partition pivot h)).
Lemma insert_bst: forall x h, bst h -> bst (insert x h).
Lemma In_insert: forall x h y, bst h -> (In y (insert x h) <-> E.eq y x \/ In y h).
Lemma deleteMin_lt: forall x h, lt_heap h x -> lt_heap (deleteMin h) x.
Lemma deleteMin_bst: forall h, bst h -> bst (deleteMin h).
Lemma In_deleteMin: forall y x h, findMin h = Some x -> (In y h <-> E.eq y x \/ In y (deleteMin h)).
Lemma gt_heap_In: forall x y h, gt_heap h x -> In y h -> E.lt x y.
Lemma findMin_min: forall x h, findMin h = Some x -> bst h -> forall y, In y h -> le x y.
Lemma findMin_empty: forall h, h <> Empty -> findMin h <> None.
Lemma deleteMax_gt: forall x h, gt_heap h x -> gt_heap (deleteMax h) x.
Lemma deleteMax_bst: forall h, bst h -> bst (deleteMax h).
Lemma In_deleteMax: forall y x h, findMax h = Some x -> (In y h <-> E.eq y x \/ In y (deleteMax h)).
Lemma lt_heap_In: forall x y h, lt_heap h x -> In y h -> E.lt y x.
Lemma findMax_max: forall x h, findMax h = Some x -> bst h -> forall y, In y h -> le y x.
Lemma findMax_empty: forall h, h <> Empty -> findMax h <> None.