Inductive datMap(A B : Set)(f : A -> DistApproxTree B -> Prop) : DistApproxTree A -> DistApproxTree B  -> Prop :=
| datMap_leaf_None :
    datMap f (dat_leaf None) (dat_leaf None)
| datMap_leaf_Some : 
  forall a t,
    f a t ->
    datMap f (dat_leaf (Some a)) t
| datMap_internal : 
  forall t1a t2a t1b t2b,
    datMap f t1a t1b ->
    datMap f t2a t2b ->
    datMap f (dat_internal t1a t2a) (dat_internal t1b t2b).Inductive datMap(A B : Set)(f : A -> DistApproxTree B -> Prop) : DistApproxTree A -> DistApproxTree B  -> Prop :=
| datMap_leaf_None :
    datMap f (dat_leaf None) (dat_leaf None)
| datMap_leaf_Some : 
  forall a t,
    f a t ->
    datMap f (dat_leaf (Some a)) t
| datMap_internal : 
  forall t1a t2a t1b t2b,
    datMap f t1a t1b ->
    datMap f t2a t2b ->
    datMap f (dat_internal t1a t2a) (dat_internal t1b t2b).Inductive datMap(A B : Set)(f : A -> DistApproxTree B -> Prop) : DistApproxTree A -> DistApproxTree B  -> Prop :=
| datMap_leaf_None :
    datMap f (dat_leaf None) (dat_leaf None)
| datMap_leaf_Some : 
  forall a t,
    f a t ->
    datMap f (dat_leaf (Some a)) t
| datMap_internal : 
  forall t1a t2a t1b t2b,
    datMap f t1a t1b ->
    datMap f t2a t2b ->
    datMap f (dat_internal t1a t2a) (dat_internal t1b t2b).Inductive datMap(A B : Set)(f : A -> DistApproxTree B -> Prop) : DistApproxTree A -> DistApproxTree B  -> Prop :=
| datMap_leaf_None :
    datMap f (dat_leaf None) (dat_leaf None)
| datMap_leaf_Some : 
  forall a t,
    f a t ->
    datMap f (dat_leaf (Some a)) t
| datMap_internal : 
  forall t1a t2a t1b t2b,
    datMap f t1a t1b ->
    datMap f t2a t2b ->
    datMap f (dat_internal t1a t2a) (dat_internal t1b t2b).(* a variant of datMap that builds a tree of a maximum depth *)
Inductive datMap_depth(A B : Set)(f : nat -> A -> DistApproxTree B -> Prop) : nat -> DistApproxTree A -> DistApproxTree B -> Prop :=
| datMap_depth_leaf_None :
  forall n, 
    datMap_depth f n (dat_leaf None) (dat_leaf None)
| datMap_depth_leaf_Some :
  forall n a t,
    f n a t ->
    datMap_depth f n (dat_leaf (Some a)) t
| datMap_depth_internal :
  forall n t1a t2a t1b t2b,
    datMap_depth f n t1a t1b ->
    datMap_depth f n t2a t2b ->
    datMap_depth f (S n) (dat_internal t1a t2a) (dat_internal t1b t2b).(* a variant of datMap that builds a tree of a maximum depth *)
Inductive datMap_depth(A B : Set)(f : nat -> A -> DistApproxTree B -> Prop) : nat -> DistApproxTree A -> DistApproxTree B -> Prop :=
| datMap_depth_leaf_None :
  forall n, 
    datMap_depth f n (dat_leaf None) (dat_leaf None)
| datMap_depth_leaf_Some :
  forall n a t,
    f n a t ->
    datMap_depth f n (dat_leaf (Some a)) t
| datMap_depth_internal :
  forall n t1a t2a t1b t2b,
    datMap_depth f n t1a t1b ->
    datMap_depth f n t2a t2b ->
    datMap_depth f (S n) (dat_internal t1a t2a) (dat_internal t1b t2b).(* a variant of datMap that builds a tree of a maximum depth *)
Inductive datMap_depth(A B : Set)(f : nat -> A -> DistApproxTree B -> Prop) : nat -> DistApproxTree A -> DistApproxTree B -> Prop :=
| datMap_depth_leaf_None :
  forall n, 
    datMap_depth f n (dat_leaf None) (dat_leaf None)
| datMap_depth_leaf_Some :
  forall n a t,
    f n a t ->
    datMap_depth f n (dat_leaf (Some a)) t
| datMap_depth_internal :
  forall n t1a t2a t1b t2b,
    datMap_depth f n t1a t1b ->
    datMap_depth f n t2a t2b ->
    datMap_depth f (S n) (dat_internal t1a t2a) (dat_internal t1b t2b).(* a variant of datMap that builds a tree of a maximum depth *)
Inductive datMap_depth(A B : Set)(f : nat -> A -> DistApproxTree B -> Prop) : nat -> DistApproxTree A -> DistApproxTree B -> Prop :=
| datMap_depth_leaf_None :
  forall n, 
    datMap_depth f n (dat_leaf None) (dat_leaf None)
| datMap_depth_leaf_Some :
  forall n a t,
    f n a t ->
    datMap_depth f n (dat_leaf (Some a)) t
| datMap_depth_internal :
  forall n t1a t2a t1b t2b,
    datMap_depth f n t1a t1b ->
    datMap_depth f n t2a t2b ->
    datMap_depth f (S n) (dat_internal t1a t2a) (dat_internal t1b t2b).Definition dat_correct_bind(A B : Set)(c1 : Comp B)(c2 : B -> Comp A)(n : nat)(t : DistApproxTree A) :=
  exists tb, dat_correct c1 n tb /\
    (datMap_depth (fun n' b ta => (dat_correct (c2 b) n' ta)) n tb t).Definition dat_correct_bind2(A B : Set)(c1 : Comp B)(c2 : B -> Comp A)(n : nat)(t : DistApproxTree A) :=
  exists tb, dat_correct c1 n tb /\
    (datMap (fun b ta => (dat_correct (c2 b) n ta)) tb t).

Lemma lowDistApprox_bind_evalDist_limit : forall (A B :Set)(c1 : Comp B)(c2 : B -> Comp A) a, well_formed_comp c1 -> (forall b, In b (getSupport c1) -> well_formed_comp (c2 b)) -> (forall (a : B), rat_inf_limit (lowDistApprox c1 a) (evalDist c1 a)) -> (forall (b : B) (a : A), In b (getSupport c1) -> rat_inf_limit (lowDistApprox (c2 b) a) (evalDist (c2 b) a)) -> rat_inf_limit (lowDistApprox_bind c1 c2 a) (evalDist (Bind c1 c2) a).