(* dat_better is an inductive predicate that lets us conclude that one tree will produce an approximation that is at least as good as some other tree. *)
Inductive dat_better(A : Set) : DistApproxTree A -> DistApproxTree A -> Prop :=
| dat_better_leaf_None : forall t,
  dat_better t (dat_leaf None)
| dat_better_leaf_Some : forall a,
  dat_better (dat_leaf (Some a)) (dat_leaf (Some a))
| dat_better_internal : forall ta1 ta2 tb1 tb2,
  dat_better ta1 tb1 ->
  dat_better ta2 tb2 ->
  dat_better (dat_internal ta1 ta2) (dat_internal tb1 tb2).(* dat_better is an inductive predicate that lets us conclude that one tree will produce an approximation that is at least as good as some other tree. *)
Inductive dat_better(A : Set) : DistApproxTree A -> DistApproxTree A -> Prop :=
| dat_better_leaf_None : forall t,
  dat_better t (dat_leaf None)
| dat_better_leaf_Some : forall a,
  dat_better (dat_leaf (Some a)) (dat_leaf (Some a))
| dat_better_internal : forall ta1 ta2 tb1 tb2,
  dat_better ta1 tb1 ->
  dat_better ta2 tb2 ->
  dat_better (dat_internal ta1 ta2) (dat_internal tb1 tb2).(* dat_better is an inductive predicate that lets us conclude that one tree will produce an approximation that is at least as good as some other tree. *)
Inductive dat_better(A : Set) : DistApproxTree A -> DistApproxTree A -> Prop :=
| dat_better_leaf_None : forall t,
  dat_better t (dat_leaf None)
| dat_better_leaf_Some : forall a,
  dat_better (dat_leaf (Some a)) (dat_leaf (Some a))
| dat_better_internal : forall ta1 ta2 tb1 tb2,
  dat_better ta1 tb1 ->
  dat_better ta2 tb2 ->
  dat_better (dat_internal ta1 ta2) (dat_internal tb1 tb2).(* dat_better is an inductive predicate that lets us conclude that one tree will produce an approximation that is at least as good as some other tree. *)
Inductive dat_better(A : Set) : DistApproxTree A -> DistApproxTree A -> Prop :=
| dat_better_leaf_None : forall t,
  dat_better t (dat_leaf None)
| dat_better_leaf_Some : forall a,
  dat_better (dat_leaf (Some a)) (dat_leaf (Some a))
| dat_better_internal : forall ta1 ta2 tb1 tb2,
  dat_better ta1 tb1 ->
  dat_better ta2 tb2 ->
  dat_better (dat_internal ta1 ta2) (dat_internal tb1 tb2).

(* Specifications: *)
Lemma dat_better_refl : forall (A : Set)(t : DistApproxTree A), dat_better t t.
Lemma dat_better_trans : forall (A : Set)(t1 t2 : DistApproxTree A), dat_better t1 t2 -> forall t3, dat_better t2 t3 -> dat_better t1 t3.
Lemma dat_correct_dat_better : forall (A : Set)(c : Comp A) ls n1 t1, dat_correct_h c ls n1 t1 -> forall n2 t2, dat_correct_h c ls n2 t2 -> n1 >= n2 -> dat_better t1 t2.
Lemma lowDistApprox_dat_better_le : forall (A : Set)(eqd : eq_dec A)(t1 t2 : DistApproxTree A), dat_better t1 t2 -> forall (a : A), lowDistApproxFromTree eqd t2 a <= lowDistApproxFromTree eqd t1 a.
Lemma datMap_better : forall (A B : Set)(t : DistApproxTree B) n (rel : nat -> B -> DistApproxTree A -> Prop) t1 t2, (forall n b t1 t2, rel n b t1 -> rel (pred n) b t2 -> dat_better t1 t2) -> datMap (rel n) t t1 -> datMap (rel (pred n)) t t2 -> dat_better t1 t2.
Lemma datMap_depth_better : forall (A B : Set)(tb1 tb2 : DistApproxTree B), dat_better tb1 tb2 -> forall n1 n2 (f : nat -> B -> DistApproxTree A -> Prop) t1 t2, (forall n1 n2 b t1 t2, n1 >= n2 -> f n1 b t1 -> f n2 b t2 -> dat_better t1 t2) -> datMap (f n1) tb1 t1 -> datMap_depth f n2 tb2 t2 -> n1 >= n2 -> dat_better t1 t2.
Lemma dat_bind_2_better : forall (n : nat) (A B : Set)(c1 : Comp B)(c2 : B -> Comp A) t1 t2, dat_correct_bind2 c1 c2 n t1 -> dat_correct_bind c1 c2 n t2 -> dat_better t1 t2.
Lemma dat_correct_h_bind_app : forall (A B : Set) t (c1 : Comp B)(c2 : B -> Comp A) n ls1 ls2 a, evalDet_steps (cs_more c1 ls1) (cs_done a nil) -> dat_correct_h (Bind c1 c2) (ls1 ++ ls2) n t -> dat_correct_h (c2 a) ls2 n t.
Lemma dat_correct_bind_same_h : forall n (A : Set)(c : Comp A) ls t, dat_correct_h c ls n t -> forall (B : Set)(c1 : Comp B)(c2 : B -> Comp A) t1, c = Bind c1 c2 -> well_formed_comp c1 -> (forall a ls', evalDet_steps (cs_more c1 ls) (cs_done a ls') -> ls' = nil) -> dat_correct_h c1 ls n t1 -> datMap_depth (fun (depth : nat) (b : B) t2 => dat_correct_h (c2 b) nil depth t2) n t1 t.
Lemma lowDistApprox_le_bind : forall n (A B : Set)(c1 : Comp B)(c2 : B -> Comp A) a r1 r2, well_formed_comp c1 -> (forall b, In b (getSupport c1) -> well_formed_comp (c2 b)) -> lowDistApprox (Bind c1 c2) a n r1 -> lowDistApprox_bind c1 c2 a n r2 -> r1 <= r2.
Lemma dat_correct_bind_same: forall (A B : Set)(c1 : Comp B)(c2 : B -> Comp A) n t, well_formed_comp c1 -> dat_correct (Bind c1 c2) n t -> dat_correct_bind c1 c2 n t.