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 in_flattenPair_inv : forall (A B : Set)(ls : list (A * list B)) a b, In (a, b) (flattenPair ls) -> exists lsb, In b lsb /\ In (a , lsb) ls.