Require Import Program.
From Equations Require Import Equations.
Require Import extra_principles Util.
From mathcomp Require Import all_ssreflect.

Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.

Require Import continuity_zoo_Prop.
Require Import Lia.

Arguments ext_tree {_ _ _}, _ _ _.
(* Set Default Goal Selector "!".*)

(* This file presents Brouwer-like equivalents of extensional trees and interaction,
   trees, i.e. trees that ask their questions "in order", much like Brouwer trees 
   vs dialogue trees.
 *)


Section Brouwer_ext_tree.

  (*The goal of this Section is to provide an extensional tree equivalent to Brouwer
    trees, and to prove that it is equivalent to tree_fun_contW. *)


Variable A R : Type.
Notation Q := nat.
Implicit Type (F : (Q -> A) -> R).

Lemma from_pref_map_iota (f : nat -> A) m n k a : (n <= m) ->
    from_pref a (map f (iota k (S m))) n = f (k + n).
Proof.
move=> lenm.
have -> : k + n = nth k (iota k m.+1) n by rewrite nth_iota.
rewrite /from_pref (nth_map k) // size_iota //.
Qed.

Lemma from_pref_finite_equal l (alpha : Q -> A) a n :
  \max_(i <- l) i <= n ->
  map (from_pref a (map alpha (iota 0 n.+1))) l = map alpha l.
Proof.
  elim: l => [| k l ihl] //.
  rewrite big_cons geq_max; case /andP=> lekn /ihl h /=.
  by rewrite -h /= from_pref_map_iota.
Qed.

(*
Lemma leq_le i j : i <= j -> le i j.
Proof. by move/leP. Qed.
*)


(*Brouwer extensional trees: they go to option R, and None is considered to be "next query".*)
Definition Bext_tree := list A -> option R.

Fixpoint Beval_ext_tree_aux (tau : Bext_tree) (f : Q -> A) (n : nat) (l : seq A) (q : Q) :
  option R :=
  match n, tau l with
  |S k, None => Beval_ext_tree_aux tau f k (rcons l (f q)) (S q)
  |_, _ => tau l
  end.

Definition Beval_ext_tree tau f n := Beval_ext_tree_aux tau f n nil 0.

(*Continuity via Brouwer extensional trees*)
Definition Btree_fun_cont F :=
  exists tau : Bext_tree, forall alpha, exists n : nat, Beval_ext_tree tau alpha n = Some (F alpha).

(*The following is a bunch of lemmas that mimick lemmas about extensional trees,
 albeit for Brouwer extensional trees this time. *)


Definition wf_Bext_tree (tau : Bext_tree) :=
  forall f : Q -> A, exists n o, tau (map f (iota 0 n)) = Some o.

Definition Bvalid_ext_tree (tau : Bext_tree) :=
  forall (f : Q -> A) (k : Q) (r : R), tau (map f (iota 0 k)) = Some r ->
                          tau (map f (iota 0 k.+1)) = Some r.

Definition Btree_fun_cont_valid F :=
  exists tau : Bext_tree,
    (forall alpha, exists n : nat, Beval_ext_tree tau alpha n = Some (F alpha)) /\
      (Bvalid_ext_tree tau).

Lemma Bvalid_plus (tau : Bext_tree) :
  Bvalid_ext_tree tau -> forall f k j r,
      tau (map f (iota 0 k)) = Some r ->
      tau (map f (iota 0 (k + j))) = Some r.
Proof.
move=> H f k j; elim: j k => [| j ihj] k r e; first by rewrite addn0.
rewrite addnS; apply: (ihj k.+1).
exact: H.
Qed.

Lemma Bvalid_every_list (tau : Bext_tree) :
  Bvalid_ext_tree tau ->
  forall l l' r, tau l = Some r -> tau (l ++ l') = Some r.
Proof.
  unfold Bvalid_ext_tree ; intros Hvalid l l' r Heqr.
  destruct l' as [ | a l'] ; [now rewrite cats0 | ].
  rewrite - (take_size (l ++ a :: l')) - (map_nth_iota0 a) size_cat ; [ | lia].
  apply Bvalid_plus ; auto.
  rewrite map_nth_iota0 ; [ | rewrite size_cat ; lia].
  now rewrite (take_size_cat (a :: l') erefl).
Qed.

Fixpoint Beval_ext_tree_trace_aux
  (tau : Bext_tree) (f : Q -> A) (n : nat) (l : seq A) (q : Q) : Q :=
  match n, tau l with
  | S k, None => S (Beval_ext_tree_trace_aux tau f k (rcons l (f q)) (S q))
  | _ , _ => 0
  end.

Definition Beval_ext_tree_trace tau f n := Beval_ext_tree_trace_aux tau f n nil 0.

Lemma Beval_ext_tree_map_aux tau f n l q :
  Beval_ext_tree_aux tau f n l q =
    tau (l ++ map f (iota q ((Beval_ext_tree_trace_aux tau f n l q)))).
Proof.
elim: n l q =>[| n ihn] l q /=; first by rewrite cats0.
case e: (tau l) => [a |] /=; first by rewrite cats0.
by rewrite -cat_rcons.
Qed.

Lemma Beval_ext_tree_constant (tau : Bext_tree) (f : Q -> A) n r l q :
    tau l = Some r ->
    Beval_ext_tree_aux tau f n l q = Some r.
Proof. by elim: n l q => [| n ihn] l q //= ->. Qed.

Lemma Beval_ext_tree_output_unique tau f l n1 n2 o1 o2 q :
  Beval_ext_tree_aux tau f n1 l q = Some o1 ->
  Beval_ext_tree_aux tau f n2 l q = Some o2 ->
  o1 = o2.
Proof.
elim: n1 n2 l q => [| n1 ihn1] [ | n2] l q /=.
1, 2: by move=> -> [].
1, 2: case: (tau l) => [ a -> [] // | q' //].
intros H. eapply ihn1 ; eassumption.
Qed.

Lemma Beval_ext_tree_monotone (tau : Bext_tree ) f n k r l q :
  Beval_ext_tree_aux tau f n l q = Some r ->
  Beval_ext_tree_aux tau f (n + k) l q = Some r.
Proof.
  revert l q ; induction n as [ | n IHn] ; simpl in * ; intros l q H.
  1: now eapply Beval_ext_tree_constant.
  destruct (tau l) ; [ assumption |].
  now eapply IHn.
Qed.

Lemma eval_ext_tree_from_pref a (tau : @ext_tree Q A R) f n l :
  eval_ext_tree_aux tau f n (map f l) =
    eval_ext_tree_aux tau (from_pref a (map f (iota 0 (\max_(q <- l ++ (eval_ext_tree_trace_aux tau f n (map f l))) q).+1))) n (map f l).
Proof.
  elim: n l => [| n ihn l] //=.
  case: (tau _) => [q |] //.
  rewrite from_pref_map_iota; last first.
    by rewrite big_cat /= maxnC leq_max leq_bigmax_seq ?mem_head.
  - by rewrite -map_rcons ihn cat_rcons.
Qed.

(*Same for the trace of eval_ext_tree*)
Lemma eval_ext_tree_trace_from_pref a (tau : ext_tree Q A R) f n k l :
  \max_(q <- l ++ (eval_ext_tree_trace_aux tau f n (map f l))) q <= k ->
  eval_ext_tree_trace_aux tau f n (map f l) =
    eval_ext_tree_trace_aux tau (from_pref a (map f (iota 0 (S k)))) n (map f l).
Proof.
  elim: n l => [| n ihn] l //=.
  case: (tau _) => [q |] // h.
  rewrite from_pref_map_iota; last first.
  - by move/bigmax_leqP_seq: h; apply; rewrite // mem_cat mem_head orbT.
  - by rewrite -map_rcons in h *; rewrite ihn // cat_rcons.
Qed.

(*A technical lemma to prove that eval_ext_tree using lists as partial oracles
 is monotone*)

 Lemma eval_ext_tree_pref_monotone_aux a (tau : ext_tree Q A R) f n r l (ll := eval_ext_tree_trace_aux tau f n [seq f i | i <- l] : seq Q
 ):
 eval_ext_tree_aux tau f n (map f l) = output r ->
 eval_ext_tree_aux tau (from_pref a (map f (iota 0 (n + (\max_(i <- l ++ ll) i).+1))))
   (n + (\max_(i <- l ++ ll) i).+1) (map f l) =
   output r.
Proof.
  move=> h.
  apply: eval_ext_tree_monotone.
  rewrite -h (eval_ext_tree_from_pref a).
  apply: eval_ext_tree_continuous.
  rewrite addnS -eval_ext_tree_trace_from_pref -/ll ?leq_addl // from_pref_finite_equal.
  - by rewrite from_pref_finite_equal // big_cat /= leq_maxr.
  - by apply: (leq_trans _ (leq_addl _ _)); rewrite big_cat leq_maxr.
Qed.

Lemma eval_ext_tree_pref_monotone (tau : ext_tree Q A R) f n r a :
  eval_ext_tree tau f n = output r ->
  eval_ext_tree tau (from_pref a (map f (iota 0 (n + (\max_(i <- eval_ext_tree_trace tau f n) i).+1))))
    (n + (\max_(i <- eval_ext_tree_trace tau f n) i).+1) = output r.
Proof.
  exact: eval_ext_tree_pref_monotone_aux _ _ _ _ _ nil.
Qed.

(*Turning ext_tree to Brouwer ext_tree*)
Definition extree_to_extree (tau : ext_tree Q A R) (a : A) : ext_tree Q A R :=
  fun l => eval_ext_tree tau (from_pref a l) (size l).

Definition extree_to_Bextree (tau : ext_tree Q A R) (a : A) : Bext_tree :=
  fun l =>
    let m := (\max_(i <- (eval_ext_tree_trace tau (from_pref a l) (size l))) i).+1 in
    if m <= size l then
      (match extree_to_extree tau a l with
            | output r => Some r
            | ask q => None
       end)
    else None.

Lemma extree_to_Bextree_spec tau alpha n r a :
  eval_ext_tree tau alpha n = output r ->
  extree_to_Bextree tau a (map alpha (iota 0 (n + (\max_(i <- eval_ext_tree_trace tau alpha n) i).+1))) = Some r.
Proof.
  intros he.
  rewrite /extree_to_Bextree /extree_to_extree size_map size_iota.
  rewrite (eval_ext_tree_pref_monotone _ he) /eval_ext_tree_trace.
  case: ifP => //.
  set x := eval_ext_tree_trace_aux _ _ _ _.
  suff -> : x = eval_ext_tree_trace_aux tau alpha n [::].
  - by rewrite {}/x addnS ltnS leq_addl.
  - rewrite {}/x.
  set m1 := (X in n + X).
  rewrite (eval_ext_tree_trace_monotone m1 he) /m1 addnS.
  rewrite -[LHS](eval_ext_tree_trace_from_pref a (l := [::])) //.
  by rewrite -addnS -(eval_ext_tree_trace_monotone _ he) leq_addl.
Qed.

Lemma ext_tree_to_Bext_tree_valid tau a:
  Bvalid_ext_tree (extree_to_Bextree tau a).
Proof.
  move=> f k r.
  rewrite /extree_to_Bextree /extree_to_extree !size_map !size_iota.
  case: k => [| k] //.
  set m1 := (X in X < _); set m2 := (X in X < k.+2).
  case: ifP => // lem.
  set fk := from_pref _ _; set fk1 := from_pref _ _.
  case e : (eval_ext_tree tau fk k.+1) => [// | aa] [] ea.
  rewrite ea in e => {ea aa}.
  have e1 : eval_ext_tree tau fk k.+1 = eval_ext_tree tau fk1 k.+1.
    apply: eval_ext_tree_continuous.
    by rewrite from_pref_finite_equal ?from_pref_finite_equal // ltnW.
  have e2 : eval_ext_tree tau fk1 k.+2 = eval_ext_tree tau fk1 k.+1.
    by rewrite -e1 e -addn1; apply: eval_ext_tree_monotone; rewrite -[LHS]e1.
  suff -> : m2 < k.+2 by rewrite e2 -e1 e.
  suff <- : m1 = m2 by rewrite ltnS; exact: ltnW.
  rewrite /m1 /m2 -/fk -/fk1.
  suff -> : eval_ext_tree_trace tau fk k.+1 = eval_ext_tree_trace tau fk1 k.+2 by [].
  rewrite -[_.+2]addn1 /eval_ext_tree_trace.
  rewrite -[RHS](@eval_ext_tree_trace_monotone _ _ _ _ _ _ _ r); last by rewrite -[LHS]e1.
  by apply: eval_ext_tree_trace_continuous; rewrite !from_pref_finite_equal // ltnW.
  Qed.

Hint Resolve ext_tree_to_Bext_tree_valid.

(*Continuity via ext_trees implies continuity via Brouwer ext_trees*)
Lemma tree_fun_cont_to_Brouwer_aux F (a : A) tau alpha :
  (exists n : Q, eval_ext_tree tau alpha n = output (F alpha)) ->
  exists n : Q, Beval_ext_tree (extree_to_Bextree tau a) alpha n = Some (F alpha).
Proof.
  case=> n Htau.
  exists (n + (\max_(i <- eval_ext_tree_trace tau alpha n) i).+1).
  rewrite /Beval_ext_tree -[[::]]/(map alpha (iota 0 0)).
  move: {3 4}0 => k.
  move/(extree_to_Bextree_spec a): Htau.
  set m := n + _.
  suff aux ttau mm kk f r :
    ttau (map f (iota 0 (mm + kk))) = Some r ->
    (forall i j a', ttau (map f (iota 0 j)) = Some a' ->
                    ttau (map f (iota 0 (j + i))) = Some a') ->
                    Beval_ext_tree_aux ttau f mm (map f (iota 0 kk)) kk = Some r.
    move=> h; apply: aux; last by move=> i j aa; apply: Bvalid_plus.
    exact: Bvalid_plus.
    clear => e h.
    elim: mm kk e => [| m ihm] k e //=.
    case er: (ttau [seq f i | i <- iota 0 k]) => [aa |].
    symmetry; rewrite -e addnC; exact: h.
  by rewrite -map_rcons iota_rcons; apply: ihm; rewrite addnS.
  Qed.

(*Getting rid of the o:O assumption*)
Definition extree_to_Bextree_noo (tau : ext_tree Q A R) : Bext_tree :=
  fun l => match l with
           | nil => match (tau l) with
                    | output r => Some r
                    | ask _ => None
                    end
           | a :: q => extree_to_Bextree tau a (a::q)
           end.

Lemma extree_to_Bextree_noo_eq tau f n k :
  Beval_ext_tree_aux (extree_to_Bextree_noo tau) f n (map f (iota 0 (S k))) (S k) =
              Beval_ext_tree_aux (extree_to_Bextree tau (f 0)) f n (map f (iota 0 (S k))) (S k).
Proof.
  revert k ; induction n ; intros ; [reflexivity |].
  cbn.
  set t := extree_to_Bextree _ _ _.
  destruct t ; [reflexivity |].
  rewrite - map_rcons iota_rcons.
  exact (IHn (k.+1)).
Qed.

Proposition tree_fun_cont_to_Brouwer F : tree_fun_cont F -> Btree_fun_cont F.
Proof.
  intros [tau Htau].
  exists (extree_to_Bextree_noo tau).
  intros alpha.
  specialize (Htau alpha).
  destruct (tree_fun_cont_to_Brouwer_aux (alpha 0) Htau) as [n Haux].
  destruct Htau as [m Htau].
  exists n.
  destruct n; [now inversion Haux |].
  cbn in *.
  remember (tau nil) as r ; destruct r.
  1: change [:: alpha 0] with (map alpha (iota 0 1)) ; now erewrite extree_to_Bextree_noo_eq.
  suff: @output Q _ r = output (F alpha) ; [intros H ; now inversion H |].
  rewrite - Htau ; symmetry.
  now eapply (@eval_ext_tree_monotone _ _ _ _ _ 0).
Qed.

End Brouwer_ext_tree.

Section Brouwer_interaction_trees.

Variable A R : Type.
Notation Q := nat.
Implicit Type (F : (Q -> A) -> R).

CoInductive Bitree : Type :=
  | Bret : R -> Bitree
| Bvis : (A -> Bitree) -> Bitree.

Local Notation itree := (@Itree nat A R).

Fixpoint Bieval (b : Bitree) (f : Q -> A) (n : nat) : option R :=
  match n with
  | 0 => match b with
         | Bret a => Some a
         | Bvis k => None
         end
  | S n => match b with
           | Bret a => Some a
           | Bvis k => Bieval (k (f 0)) (f \o S) n
           end
  end.

Lemma Bieval_monotone b f n r:
  Bieval b f n = Some r ->
  Bieval b f n.+1 = Some r.
Proof.
  revert b f ; induction n ; intros b f Heq ; cbn in * ; [destruct b ; now inversion Heq | ].
  destruct b ; [now inversion Heq | ].
  now eapply (IHn (b (f 0)) (f \o succn)).
Qed.

Lemma Bieval_monotone_plus b f n m r:
  Bieval b f n = Some r ->
  Bieval b f (n + m) = Some r.
Proof.
  revert n ; induction m ; intros n Heq ; [ now rewrite addn0 | ].
  rewrite addnS - addSn ; now apply IHm, Bieval_monotone.
Qed.

Lemma Bieval_output_unique b f n m r r' :
  Bieval b f n = Some r ->
  Bieval b f m = Some r' ->
  r = r'.
Proof.
  destruct (@leqP n m) as [Hinf | Hinf].
  - rewrite - (subnKC Hinf) ; intros Heqr Heqr'.
    erewrite Bieval_monotone_plus in Heqr' ; eauto ; now inversion Heqr'.
  - rewrite - (subnKC Hinf) ; intros Heqr Heqr'.
    erewrite Bieval_monotone_plus in Heqr ; [ | eapply Bieval_monotone ; eauto].
    now inversion Heqr.
Qed.

Definition Bcoind_dial_cont F :=
  exists τ : Bitree, forall f : Q -> A, exists n : nat, Bieval τ f n = Some (F f).

Fixpoint Bitree_to_option (i : Bitree) (l : list A) : option R :=
  match l with
  | nil => match i with
           | Bvis k => None
           | Bret a => Some a
           end
  | cons a l' => match i with
                 | Bvis k => Bitree_to_option (k a) l'
                 | Bret a => Some a
                 end
  end.

Lemma Bitree_to_option_Bieval (i : Bitree) (n : nat) (alpha : Q -> A) :
  Bieval i alpha n = Bitree_to_option i (map alpha (iota 0 n)).
Proof.
  revert alpha i ; induction n as [ | n IHn] ; intros ; [auto | ].
  cbn ; destruct i as [ | k] ; [reflexivity | ].
  suff: forall m, [seq alpha i | i <- iota m.+1 n] = [seq (alpha \o succn) i | i <- iota m n].
  { intros H ; rewrite H ; now apply IHn. }
  clear ; revert alpha ; induction n as [ | n IHn] ; intros alpha m ; [auto | ].
  cbn ; f_equal.
  now apply IHn.
Qed.

(*Going from Brouwer interaction trees to interaction trees*)

CoFixpoint Bitree_to_itree_aux (b : Bitree) (n : nat) : itree :=
  match b with
  | Bret a => ret a
  | Bvis k => vis n (fun a => Bitree_to_itree_aux (k a) (S n))
  end.

Definition Bitree_to_itree b := Bitree_to_itree_aux b 0.

Lemma Bitree_to_itreeP_aux b alpha n m r:
  Bieval b (n_comp alpha n) m = Some r <->
    ieval (Bitree_to_itree_aux b n) alpha m = output r.
Proof.
  split.
  - revert n b ; induction m ; cbn ; intros n b Heq.
    + destruct b ; inversion Heq ; now subst.
    + destruct b ; [inversion Heq ; now subst | ].
      apply IHm.
      rewrite n_comp_n_plus in Heq ; now rewrite addn0 in Heq.
  - revert n b ; induction m ; cbn ; intros n b Heq.
    + destruct b ; now inversion Heq.
    + destruct b ; [now inversion Heq | ].
      change (n_comp alpha n \o succn) with (n_comp alpha n.+1).
      apply IHm.
      now rewrite n_comp_n_plus addn0.
Qed.

Lemma Bitree_to_itreeP b alpha m r :
  Bieval b alpha m = Some r <->
    ieval (Bitree_to_itree b) alpha m = output r.
Proof.
  exact (Bitree_to_itreeP_aux b alpha 0 m r).
Qed.

Lemma Bitree_cont_to_itree_cont (F : (nat -> A) -> R) :
  Bcoind_dial_cont F -> coind_dial_cont F.
Proof.
  intros [b Hb].
  exists (Bitree_to_itree b) ; intros alpha.
  specialize (Hb alpha) as [n Hn] ; exists n.
  now apply Bitree_to_itreeP.
Qed.

CoFixpoint itree_to_Bitree (l : seq A) (d : itree) : Bitree.
Proof.
  refine (match d with
          | ret a => Bret a
          | vis n k => Bvis (fun a => _)
          end).
  refine (if n < size l
          then itree_to_Bitree (rcons l a) (k (nth a l n))
          else itree_to_Bitree (rcons l a) (vis n k)).
Defined.

Lemma itree_to_Bitree_seq (n m : nat) (d : itree) (alpha : Q -> A) (r : R) :
  Bieval (itree_to_Bitree (map alpha (iota 0 m)) d) (n_comp alpha m) n = Some r ->
  Bieval (itree_to_Bitree (map alpha (iota 0 m.+1)) d) (n_comp alpha m.+1) n = Some r.
Proof.
  elim: n d alpha m => [| n ihn] [| q k] alpha m //=.
  rewrite !size_map !size_iota !n_comp_n_plus addn0 addn1.
  rewrite -!map_rcons !iota_rcons -!map_cons.
  have aux s : 0 :: iota 1 s = iota 0 s.+1 by rewrite -cat1s -(iotaD 0 1 s) add1n.
  rewrite !aux.
  case: (ltngtP q m) => H.
  - have -> : q < m.+1 by rewrite ltnS ltnW.
    move/ihn; set u1 := nth _ _ _. set u2 := nth _ _ _.
    suff -> : u1 = u2 by [].
   rewrite {}/u1 {}/u2 !(nth_map 0) ?size_iota //; last by rewrite ltnS ltnW.
   rewrite !nth_iota //; last by rewrite ltnS ltnW.
  - rewrite ltnS leqNgt H; exact: ihn.
  - rewrite ltnS leq_eqVlt H eqxx /=.
     move/Bieval_monotone=> /=.
     rewrite size_map size_iota ltnS leqnn n_comp_n_plus addn1 -map_rcons -map_cons.
     by rewrite iota_rcons aux.
Qed.

Lemma itree_to_BitreeP (n m : nat) (d : itree) (alpha : Q -> A) (r : R) :
  ieval d alpha n = output r ->
  exists k, Bieval (itree_to_Bitree (map alpha (iota 0 m)) d) (n_comp alpha m) k = Some r.
Proof.
  elim: n d m => [| n ihn] [rr | q k] m //= Hyp ; inversion Hyp ; subst.
  - by exists 0.
  - by exists 0.
  - have {Hyp ihn} [i Hj] := ihn (k (alpha q)) m.+1 Hyp.
    exists (i.+1 + (q.+1 - m)).
    case: (posnP (q.+1 - m)) => Heqx.
    + rewrite Heqx addn0 /= size_map size_iota.
      have ltqn : q < m by rewrite /leq -Heqx eqxx.
      rewrite ltqn (nth_map 0) ?size_iota //.
      by rewrite n_comp_n_plus -map_rcons addn0 iota_rcons nth_iota.
    + have {Heqx} leqmq : m <= q by move: Heqx; rewrite subn_gt0 ltnS.
      have e : q = m + (q - m) by rewrite (subnKC).
      move: Hj. rewrite subSn // addSn -addnS.
      rewrite [in vis _ _]e [in alpha _]e {leqmq e}. move: (q - m) => x.
      elim: x m => [| x ihx] m.
      * rewrite addn0 addn2 /=.
        rewrite size_map size_iota /= ltnn /= size_rcons size_map size_iota ltnSn.
        rewrite !n_comp_n_plus -!map_rcons addn0 addn1 !iota_rcons.
        rewrite (nth_map 0) ?size_iota // nth_iota // add0n => h.
        exact: itree_to_Bitree_seq.
      * rewrite [m + x.+1]addnS => h.
        rewrite [i + _]addnS /= size_map size_iota -if_neg -leqNgt -addnS leq_addr.
        rewrite n_comp_n_plus addn0 -map_rcons iota_rcons [m + _]addnS.
        apply: ihx; exact: itree_to_Bitree_seq.
Qed.

Lemma itree_to_Bitree_cont (F : (nat -> A) -> R) :
  coind_dial_cont F -> Bcoind_dial_cont F.
Proof.
  intros [d Hd].
  exists (itree_to_Bitree nil d).
  intros alpha ; specialize (Hd alpha) as [n Hn].
  now apply (itree_to_BitreeP (n := n) 0).
Qed.


End Brouwer_interaction_trees.