(* 
  Predicate that checks if a position (a list of bool) can
  be safely added (adding an element is done without any removing)
*)
Inductive pbfree : list bool -> pbtree -> Prop :=
  | pbfree_left1 : forall b l, pbfree (true :: l) (pbleft b)
  | pbfree_left2 : forall b l, pbfree l b -> pbfree (false :: l) (pbleft b)
  | pbfree_right1 : forall b l, pbfree (false :: l) (pbright b)
  | pbfree_right2 : forall b l, pbfree l b -> pbfree (true :: l) (pbright b)
  | pbfree_node1 :
      forall b c l, pbfree l b -> pbfree (false :: l) (pbnode b c)
  | pbfree_node2 :
      forall b c l, pbfree l b -> pbfree (true :: l) (pbnode c b).(* 
  Predicate that checks if a position (a list of bool) can
  be safely added (adding an element is done without any removing)
*)
Inductive pbfree : list bool -> pbtree -> Prop :=
  | pbfree_left1 : forall b l, pbfree (true :: l) (pbleft b)
  | pbfree_left2 : forall b l, pbfree l b -> pbfree (false :: l) (pbleft b)
  | pbfree_right1 : forall b l, pbfree (false :: l) (pbright b)
  | pbfree_right2 : forall b l, pbfree l b -> pbfree (true :: l) (pbright b)
  | pbfree_node1 :
      forall b c l, pbfree l b -> pbfree (false :: l) (pbnode b c)
  | pbfree_node2 :
      forall b c l, pbfree l b -> pbfree (true :: l) (pbnode c b).(* 
  Predicate that checks if a position (a list of bool) can
  be safely added (adding an element is done without any removing)
*)
Inductive pbfree : list bool -> pbtree -> Prop :=
  | pbfree_left1 : forall b l, pbfree (true :: l) (pbleft b)
  | pbfree_left2 : forall b l, pbfree l b -> pbfree (false :: l) (pbleft b)
  | pbfree_right1 : forall b l, pbfree (false :: l) (pbright b)
  | pbfree_right2 : forall b l, pbfree l b -> pbfree (true :: l) (pbright b)
  | pbfree_node1 :
      forall b c l, pbfree l b -> pbfree (false :: l) (pbnode b c)
  | pbfree_node2 :
      forall b c l, pbfree l b -> pbfree (true :: l) (pbnode c b).(* 
  Predicate that checks if a position (a list of bool) can
  be safely added (adding an element is done without any removing)
*)
Inductive pbfree : list bool -> pbtree -> Prop :=
  | pbfree_left1 : forall b l, pbfree (true :: l) (pbleft b)
  | pbfree_left2 : forall b l, pbfree l b -> pbfree (false :: l) (pbleft b)
  | pbfree_right1 : forall b l, pbfree (false :: l) (pbright b)
  | pbfree_right2 : forall b l, pbfree l b -> pbfree (true :: l) (pbright b)
  | pbfree_node1 :
      forall b c l, pbfree l b -> pbfree (false :: l) (pbnode b c)
  | pbfree_node2 :
      forall b c l, pbfree l b -> pbfree (true :: l) (pbnode c b).(* 
  Predicate that checks if a position (a list of bool) can
  be safely added (adding an element is done without any removing)
*)
Inductive pbfree : list bool -> pbtree -> Prop :=
  | pbfree_left1 : forall b l, pbfree (true :: l) (pbleft b)
  | pbfree_left2 : forall b l, pbfree l b -> pbfree (false :: l) (pbleft b)
  | pbfree_right1 : forall b l, pbfree (false :: l) (pbright b)
  | pbfree_right2 : forall b l, pbfree l b -> pbfree (true :: l) (pbright b)
  | pbfree_node1 :
      forall b c l, pbfree l b -> pbfree (false :: l) (pbnode b c)
  | pbfree_node2 :
      forall b c l, pbfree l b -> pbfree (true :: l) (pbnode c b).(* 
  Predicate that checks if a position (a list of bool) can
  be safely added (adding an element is done without any removing)
*)
Inductive pbfree : list bool -> pbtree -> Prop :=
  | pbfree_left1 : forall b l, pbfree (true :: l) (pbleft b)
  | pbfree_left2 : forall b l, pbfree l b -> pbfree (false :: l) (pbleft b)
  | pbfree_right1 : forall b l, pbfree (false :: l) (pbright b)
  | pbfree_right2 : forall b l, pbfree l b -> pbfree (true :: l) (pbright b)
  | pbfree_node1 :
      forall b c l, pbfree l b -> pbfree (false :: l) (pbnode b c)
  | pbfree_node2 :
      forall b c l, pbfree l b -> pbfree (true :: l) (pbnode c b).(* 
  Predicate that checks if a position (a list of bool) can
  be safely added (adding an element is done without any removing)
*)
Inductive pbfree : list bool -> pbtree -> Prop :=
  | pbfree_left1 : forall b l, pbfree (true :: l) (pbleft b)
  | pbfree_left2 : forall b l, pbfree l b -> pbfree (false :: l) (pbleft b)
  | pbfree_right1 : forall b l, pbfree (false :: l) (pbright b)
  | pbfree_right2 : forall b l, pbfree l b -> pbfree (true :: l) (pbright b)
  | pbfree_node1 :
      forall b c l, pbfree l b -> pbfree (false :: l) (pbnode b c)
  | pbfree_node2 :
      forall b c l, pbfree l b -> pbfree (true :: l) (pbnode c b).(* Add an element in a tree at a given position (list of bool) *)
Fixpoint pbadd (a : A) (t : pbtree) (l : list bool) {struct l} : pbtree :=
  match l with
  | nil => pbleaf a
  | false :: l1 =>
      match t with
      | pbnode t1 t2 => pbnode (pbadd a t1 l1) t2
      | pbleft t1 => pbleft (pbadd a t1 l1)
      | pbright t2 => pbnode (pbadd a (pbleaf empty) l1) t2
      | _ => pbleft (pbadd a (pbleaf empty) l1)
      end
  | true :: l1 =>
      match t with
      | pbnode t1 t2 => pbnode t1 (pbadd a t2 l1)
      | pbright t2 => pbright (pbadd a t2 l1)
      | pbleft t1 => pbnode t1 (pbadd a (pbleaf empty) l1)
      | _ => pbright (pbadd a (pbleaf empty) l1)
      end
  end.

(* Specifications: *)
Theorem pbadd_prop1 : forall a1 a2 l1, compute_pbcode (pbadd a1 (pbleaf a2) l1) = (a1, l1) :: nil.
Theorem pbadd_prop2 : forall a1 l1 l2, pbfree l1 l2 -> permutation (compute_pbcode (pbadd a1 l2 l1)) ((a1, l1) :: compute_pbcode l2).
Theorem pbfree_pbadd_prop1 : forall a1 l l1, ~ is_prefix l l1 -> ~ is_prefix l1 l -> pbfree l (pbadd a1 (pbleaf empty) l1).
Theorem pbfree_pbadd_prop2 : forall a l1 l2 l3, pbfree l1 l3 -> ~ is_prefix l2 l1 -> ~ is_prefix l1 l2 -> pbfree l1 (pbadd a l3 l2).
Theorem distinct_pbleaves_pbadd_prop1 : forall a a1 l1, distinct_pbleaves (pbadd a1 (pbleaf a) l1).
Theorem in_pbleaf_node : forall a1 a2 a3 a4 l, ~ inpb (pbnode a1 a2) (pbadd a3 (pbleaf a4) l).
Theorem inpbleaf_eq : forall a1 a2 a3 l, inpb (pbleaf a1) (pbadd a2 (pbleaf a3) l) -> a1 = a2.
Theorem inpbleaf_pbadd_inv : forall a1 a2 a3 l, inpb (pbleaf a1) (pbadd a2 a3 l) -> a1 = a2 \/ inpb (pbleaf a1) a3.
Theorem inpb_pbadd : forall a1 l1 t1, inpb (pbleaf a1) (pbadd a1 t1 l1).
Theorem inpb_pbadd_ex : forall a1 l1 t1 t, inpb t (pbadd a1 t1 l1) -> inpb (pbleaf a1) t \/ inpb t t1.