let pre_choice_std (shared_vars : int list) (std_ls : t_equal)
  : int list * int list * (int * int) list =

  (* A help function which will collect std, xor, uncertain and not_visited as
   * tas.
   * not_visited contains all the variables of shared_vars, that are not already
   * put into std, xor or uncertain. So, they four build a partition of
   * shared_vars
   *)

  let rec pre_choice_std_rec (std, xor, uncertain, not_visited as tas) =
    function
    | (n,t)::tail ->
        (* Test if n is in not_visited. In fact it cannot happen that n is not
         * in not_visited and it is in std, xor or uncertain. This is due to the
         * fact that std_ls must not contain two values for a variable.
         * What is acctually tested here is, if n is a shared variable. *)

        let (n_is_shared, not_visited_without_n) =
          remove_from_list n not_visited
        in
        if n_is_shared then
          match t with
          | Var(_) ->
              (* A binding x -> y can happen because of variable identification.
               * Act as if n is free. *)

              pre_choice_std_rec tas tail
          | PInv(Var(mm)) ->
              (* mm is not neccesarily free *)
              (match valeur_elem mm std_ls with
              | Var(m) ->
                  (* m is free in std_ls *)
                  (* Test if m is a shared variable *)
                  let (m_is_shared, not_visited_without_nm) =
                    remove_from_list m not_visited_without_n
                  in
                  if m_is_shared then
                    (* Only if n and m are shared we add them to uncertain.
                     * It is possible to remove m from not_visited, because, due
                     * to assumptions, it is not allowed, that there is another
                     * rule n2 -> PInv(m) in std_ls with n2 in shared_vars. *)

                    pre_choice_std_rec
                      (std, xor, (n,m)::uncertain, not_visited_without_nm) tail
                  else
                    (* m is not shared *)
                    (* Test, if it is possible that m and n change the sides. *)
                    if acceptable_value ([],FreeVar 0,[]) m (PInv(Var(n))) then
                      (* It is possible that n and m change sides, so we can say
                       * that n is xor, because m is not shared and therefore
                       * std. *)

                      pre_choice_std_rec
                        (std, n::xor, uncertain, not_visited_without_n) tail
                    else
                      (* It is not possible that n and m change sides, because
                       * of their types. So, n has to be std. *)

                      pre_choice_std_rec
                        (n::std, xor, uncertain, not_visited_without_n) tail
              | _ ->
                  (* m is not free in std_ls and cannot be PInv(_), due to
                   * normalisation, so n has to be standard. *)

                  pre_choice_std_rec
                    (n::std, xor, uncertain, not_visited_without_n) tail
              )
          | _ ->
              (* t is a standard term with a top symbol that cannot vanish,
               * i.e. n has to be standard *)

              pre_choice_std_rec
                (n::std, xor, uncertain, not_visited_without_n) tail
        else
          (* n is not in not_visited, i.e. it is not in shared_vars,
           * i.e. ignore it *)

          pre_choice_std_rec tas tail
    | [] -> tas
  in

  (* distributes variables with type 0 to xor and the others to std
   *)

  let rec distribute std xor = function
    | n::ns -> if var_type n = 0 then
                 distribute std (n::xor) ns
               else
                 distribute (n::std) xor ns
    | [] -> (std, xor)
  in

  (* apply pre_choice_std_rec with an initial tas, where not_visited is
   * shared_vars. *)

  let (std, xor, uncertain, not_visited) =
    pre_choice_std_rec ([],[],[],shared_vars) std_ls
  in
  (* All variables that are not_visited are free in std_ls and do not appear in
   * equations like x -> PInv(y) or if they do appear in such equations they
   * cannot change the side because of their types.
   * We can say that all variables in not_visited that have type 0 belong to
   * xor, because this will not change the std solution. *)

  let (std, xor) = distribute std xor not_visited
  in
  (std, xor, uncertain)