diff --git a/lib/datastruct/bucketSort.ml b/lib/datastruct/bucketSort.ml
new file mode 100644
index 0000000000000000000000000000000000000000..d8d745e7dfe0903a7c09a19c58541fe5e04d31bc
--- /dev/null
+++ b/lib/datastruct/bucketSort.ml
@@ -0,0 +1,23 @@
+module Make = functor (K : Map.OrderedType) -> 
+struct 
+
+  module M = Map.Make(K) 
+
+  let add_to_list key value map = 
+    M.update key 
+      (function 
+      | None -> Some [value]
+      | Some list -> Some (value::list)
+      )
+      map 
+
+  let insert ~get_key map value = 
+    add_to_list (get_key value) value map 
+      
+  let sort ~get_key values = 
+    values
+    |> List.fold_left (insert ~get_key) M.empty 
+    |> M.bindings 
+    |> List.map snd
+
+end 
diff --git a/lib/datastruct/bucketSort.mli b/lib/datastruct/bucketSort.mli
new file mode 100644
index 0000000000000000000000000000000000000000..b952de7a90c11a3ab88799b3cc68ade5c978f5d3
--- /dev/null
+++ b/lib/datastruct/bucketSort.mli
@@ -0,0 +1,5 @@
+module Make :
+  functor (K : Map.OrderedType) ->
+    sig
+      val sort : get_key:('a -> K.t) -> 'a list -> 'a list list
+    end
diff --git a/lib/pqtree/pqChainInsertion.ml b/lib/pqtree/pqChainInsertion.ml
new file mode 100644
index 0000000000000000000000000000000000000000..7c98da6162b4ff3d96c82007fa03d1bf227e86f4
--- /dev/null
+++ b/lib/pqtree/pqChainInsertion.ml
@@ -0,0 +1,361 @@
+(** This modules contains an algorithm that, given a PQ-tree T on X,
+    and a chain S_0 = {s}, S_1, ... S_k = X, builds a PQ-tree
+    representing all the permutations represented by T and for which
+    each S_i is an interval, if such a PQ-tree exists.
+
+    This could be done by the Booth-Lueker interval insertion
+    algorithm (functionalBL or imperativeBL), with k insertions. This
+    algorithm improves upon repeated insertion by having a linear-time
+    complexity.
+*)
+
+open DataStruct 
+
+
+let consecutives list = 
+  let rec go accu = function 
+  | [] | [_] -> List.rev accu
+  | x::((y::_) as tail) -> go ((x,y)::accu) tail
+  in 
+  go [] list
+
+let last = function 
+| [] -> invalid_arg "last on empty list"
+| h::t -> List.fold_left (fun _ e -> e) h t  
+
+
+
+module IntPair = 
+struct 
+  type t = (int * int) 
+  let compare (x1,y1) (x2,y2) =
+    let diff = x1 - x2 in 
+    if diff = 0 then y1 - y2 
+    else diff
+end
+module IntPairSorter = BucketSort.Make(IntPair)
+module IntPairMap = Map.Make(IntPair)
+
+
+
+(* We parametrize the whole algorithm by the chain, encoded by a rank function d,
+   d(x) is such that x \in S_{d(x)} \setminus S_{d(x)-1}, and d(s) = 0.
+ *)
+module Make = 
+  functor (Chain : sig type t val s : t val d : t -> int end) ->
+  struct
+    
+
+    type elt = Chain.t 
+    type pqtree = elt PqTree.t
+
+    open Chain 
+    open PqTree
+
+    let q = function 
+    | [_1;_2] as children -> P children
+    | children -> Q children 
+
+    type external_subtree = 
+      | ConstantSubtree of int * pqtree 
+      | IncreasingSubtree of int * pqtree list * int (* an increasing subtree is necessarily a Q-node *)
+
+    let bounds = function 
+    | ConstantSubtree (delta,_) -> (delta, delta)
+    | IncreasingSubtree (delta_min, _, delta_max) -> (delta_min, delta_max)
+    let d_min = function 
+    | ConstantSubtree (delta,_) -> delta 
+    | IncreasingSubtree (delta,_,_) -> delta 
+    let d_max = function 
+    | ConstantSubtree (delta, _) -> delta 
+    | IncreasingSubtree (_,_,delta) -> delta 
+
+    let amplitude subtrees = (d_min (List.hd subtrees), d_max (last subtrees))
+
+    let tree_of_external_tree = function 
+    | ConstantSubtree (_,t) -> t 
+    | IncreasingSubtree (_, children,_) -> q children
+
+
+    let is_increasing_sequence subtrees = 
+      List.for_all 
+        (fun (subtree1, subtree2) -> d_max subtree1 <= d_min subtree2)
+        (consecutives subtrees)
+
+    let force_increasing_sequence subtrees = 
+      if is_increasing_sequence subtrees then Some subtrees 
+      else let reversed = List.rev subtrees in 
+        if is_increasing_sequence reversed then Some reversed
+        else None 
+
+    let expand_increasing_sequence subtrees = 
+      let contract = function 
+      | ConstantSubtree (_,t) -> [t]
+      | IncreasingSubtree (_, children, _) -> children
+      in  
+      List.concat_map contract subtrees
+
+
+    let sort_into_increasing_sequence subtrees = 
+      IntPairSorter.sort ~get_key:bounds subtrees
+
+
+    type sorting_group = 
+      | Group of int * pqtree list 
+      | Single of external_subtree 
+
+    let group_d_min = function 
+    | Group (delta,_) -> delta 
+    | Single subtree -> d_min subtree
+
+    let group_d_max = function 
+    | Group (delta,_) -> delta 
+    | Single subtree -> d_max subtree
+
+    let sort_children_of_p_node children =
+      let group = function 
+      | (ConstantSubtree (delta,_)::_) as trees -> [ Group (delta, List.map tree_of_external_tree trees) ]
+      | trees -> List.map (fun t -> Single t) trees
+      in
+      children
+    |> sort_into_increasing_sequence
+    |> List.concat_map group 
+
+
+    let is_increasing_group_sequence groups = 
+      List.for_all 
+        (fun (group1, group2) -> group_d_max group1 <= group_d_min group2)
+        (consecutives groups)
+
+    let groups_amplitude groups = 
+      ( group_d_min (List.hd groups), group_d_max (last groups))
+           
+
+      
+
+
+
+    type centered_subtree =
+    | Balanced of int * pqtree
+    | Skew of int * pqtree list * int 
+
+    let tree_of_centered_tree = function 
+    | Balanced (_, tree) -> tree
+    | Skew (_,children,_) -> q children
+
+    let bounds_centered = function 
+    | Balanced (delta,_) -> (delta, delta)
+    | Skew (delta0,_,delta1) -> (delta0,delta1)
+
+    let contract_centered = function
+    | Balanced (_,single) -> [ single ]
+    | Skew (_,children,_) -> children
+
+
+    type result = 
+      | NotRepresentable
+      | CenteredSubtree of centered_subtree
+      | ExternalSubtree of external_subtree 
+
+    type classification =
+      | Unclassifiable
+      | Internal of external_subtree list * centered_subtree * external_subtree list 
+      | External of external_subtree list 
+
+    let classify children =
+      let rec go classification children = 
+        match classification, children with 
+        | _, [] -> classification
+        | Unclassifiable, _
+        | _, NotRepresentable::_ -> Unclassifiable
+        | Internal (left, at_s, right), ExternalSubtree child::children -> 
+            go (Internal (left, at_s, child::right)) children 
+        | External left_of_s, ExternalSubtree child::children ->
+            go (External (child::left_of_s)) children
+        | External left_of_s, CenteredSubtree centered::children ->
+            go (Internal (left_of_s, centered, [])) children 
+        | Internal _, CenteredSubtree _ :: _ -> Unclassifiable 
+      in 
+      go (External []) children 
+
+          
+                       
+
+    type queue = 
+      { left_bound : int;
+        left_trees : pqtree list;
+        right_trees : pqtree list;
+        right_bound : int
+      }
+
+    let init_queue = function 
+    | Balanced (bound, tree) -> 
+        { left_bound = bound; left_trees = []; right_trees = [tree]; right_bound = bound }
+    | Skew (left_bound, right_trees, right_bound) ->
+        { left_bound; left_trees = []; right_trees; right_bound }
+                   
+    let is_balanced queue = queue.left_bound = queue.right_bound
+
+    let compact queue = 
+      match List.rev_append queue.left_trees queue.right_trees with 
+      | [single_child] when is_balanced queue -> Balanced (queue.left_bound, single_child)
+      | children when is_balanced queue -> Balanced (queue.left_bound, q children)
+      | children -> Skew (queue.left_bound, children, queue.right_bound)
+
+    let enqueue_right group queue = 
+      let (right_trees, right_bound) = match group with  
+      | Group (bound, children) -> (P children :: queue.right_trees, bound)
+      | Single (ConstantSubtree (bound, subtree)) -> (subtree :: queue.right_trees, bound)
+      | Single (IncreasingSubtree (_, subtrees, bound)) -> (List.rev_append subtrees queue.right_trees, bound)
+      in 
+      { queue with right_trees; right_bound }
+
+    let enqueue_left group queue = 
+      let (left_trees, left_bound) = match group with 
+      | Group (bound, children) -> (P children :: queue.left_trees, bound)
+      | Single (ConstantSubtree (bound, subtree)) -> (subtree :: queue.left_trees, bound)
+      | Single (IncreasingSubtree (_,subtrees, bound)) -> (List.rev_append subtrees queue.left_trees, bound)
+      in
+      { queue with left_trees; left_bound }
+
+    
+    let rec enqueue groups queue = 
+      let max_bound = max queue.left_bound queue.right_bound in 
+      match groups with 
+      | [] -> 
+          CenteredSubtree (compact queue)
+      | Group (dist,children) :: groups when dist >= max_bound -> 
+          queue 
+          |> compact 
+          |> tree_of_centered_tree 
+          |> (fun tree -> Balanced (dist, P (tree :: children)))
+          |> init_queue
+          |> enqueue groups
+      | single :: groups when group_d_min single >= max_bound -> 
+          queue 
+          |> compact 
+          |> init_queue
+          |> enqueue_right single 
+          |> enqueue groups 
+      | any :: groups when group_d_min any >= queue.right_bound -> 
+          queue 
+          |> enqueue_right any 
+          |> enqueue groups 
+      | any :: groups when group_d_min any >= queue.left_bound ->
+          queue 
+          |> enqueue_left any
+          |> enqueue groups
+      | _ (* when group_d_min any < min queue.left_bound queue.right_bound *) -> 
+          NotRepresentable
+
+    let build_p_internal left_subtrees s_subtree right_subtrees = 
+      let increasing_subtrees = 
+        sort_children_of_p_node (List.rev_append left_subtrees right_subtrees) 
+      in 
+      enqueue increasing_subtrees (init_queue s_subtree)
+
+
+
+    let build_q_internal left_subtrees s_subtree right_subtrees = 
+      if not (is_increasing_sequence left_subtrees && is_increasing_sequence right_subtrees) then 
+        NotRepresentable
+      else 
+        let (min_center, max_center) = bounds_centered s_subtree in 
+        let (min_left, max_left) = amplitude left_subtrees in 
+        let (min_right, max_right) = amplitude right_subtrees in 
+        let lefts = expand_increasing_sequence left_subtrees in 
+        let rights = expand_increasing_sequence right_subtrees in 
+        let centered_subtree left_bound trees right_bound = 
+          if left_bound = right_bound then 
+            CenteredSubtree (Balanced (left_bound, q trees))
+          else 
+            CenteredSubtree (Skew (left_bound, trees, right_bound))
+        in 
+        if max(min_center, max_center) <= min (min_left, min_right) then 
+          centered_subtree 
+            max_left 
+            (List.rev lefts @ [tree_of_centered_tree s_subtree] @ rights)
+            max_right
+        else if min_left >= min_center && max_center <= min_right then 
+          centered_subtree
+            max_left
+            (List.rev lefts @ contract_centered s_subtree @ rights)
+            max_right
+        else if min_right >= min_center && max_center <= min_left then 
+          centered_subtree
+            max_right
+            (List.rev rights @ contract_centered s_subtree @ lefts)
+            max_left
+        else NotRepresentable
+
+
+
+    let contract_group = function 
+    | Group (_, subtrees) -> [ P subtrees ]
+    | Single (ConstantSubtree (_,subtree)) -> [ subtree ]
+    | Single (IncreasingSubtree (_,subtrees,_)) -> subtrees 
+    
+    let build_p_external unsorted_subtrees = 
+      let groups = sort_children_of_p_node unsorted_subtrees in 
+      match groups with
+      | _ when not (is_increasing_group_sequence groups) -> NotRepresentable
+      | [ Group (delta,children) ] -> 
+          ExternalSubtree (ConstantSubtree (delta, P children))
+      | _ ->
+          let (delta_min, delta_max) = groups_amplitude groups in 
+          let subtrees = List.concat_map contract_group groups in 
+          ExternalSubtree (IncreasingSubtree (delta_min, subtrees, delta_max))
+
+
+
+    let build_q_external subtrees = 
+      match force_increasing_sequence subtrees with 
+      | None -> NotRepresentable
+      | Some subtrees -> 
+          ExternalSubtree (
+            let (delta_min, delta_max) = amplitude subtrees in 
+            if delta_min = delta_max then 
+              ConstantSubtree (delta_min, Q (List.map tree_of_external_tree subtrees))
+            else  
+              IncreasingSubtree (delta_min, expand_increasing_sequence subtrees, delta_max)
+          )
+
+
+
+    let dispatch root children =
+      match root, classify children with 
+      | Leaf x, _ when x = s -> 
+          CenteredSubtree (Balanced (0, Leaf s))
+      | Leaf x, _ -> 
+          ExternalSubtree (ConstantSubtree (d x, Leaf x))
+      | _, Unclassifiable -> NotRepresentable
+      | P _, Internal (left_of_s, at_s, right_of_s) -> 
+          build_p_internal left_of_s at_s (List.rev right_of_s)
+      | P _, External subtrees -> 
+          build_p_external subtrees 
+      | Q _, Internal (left_of_s, at_s, right_of_s) ->
+          build_q_internal left_of_s at_s (List.rev right_of_s)
+      | Q _, External subtrees -> 
+          build_q_external subtrees
+    
+
+    let children = function 
+    | Leaf _ -> []
+    | P children 
+    | Q children -> children 
+
+    let rec solve tree = 
+      children tree
+      |> List.map solve
+      |> dispatch tree
+
+    let insert_chain tree = 
+      match solve tree with 
+      | NotRepresentable -> None 
+      | CenteredSubtree (Balanced (_,tree)) -> Some tree 
+      | CenteredSubtree (Skew (_,trees,_)) -> Some (q trees)
+      | ExternalSubtree (ConstantSubtree (_, tree)) -> Some tree 
+      | ExternalSubtree (IncreasingSubtree (_, trees, _)) -> Some (q trees)
+
+
+  end
diff --git a/lib/pqtree/pqChainInsertion.mli b/lib/pqtree/pqChainInsertion.mli
new file mode 100644
index 0000000000000000000000000000000000000000..f79fb5011d6be5c2e7618f451f746133277dc889
--- /dev/null
+++ b/lib/pqtree/pqChainInsertion.mli
@@ -0,0 +1,5 @@
+module Make :
+  functor (Chain : sig type t val s : t val d : t -> int end) ->
+  sig 
+    val insert_chain : Chain.t PqTree.t -> Chain.t PqTree.t option
+  end