let remove_variants (literals: literal list) =
  (* extend an existing variant mapping to two more terms.
     invariant: variable with lower id are bound to variables with higher id.
     avoids cycles in renaming.
  *)

  let rec are_terms_variants mapping (term1: term) (term2: term) =
    match term1, term2 with
      | Var var1, Var var2 ->
          let cmp =
            Var.compare var1 var2
          in
            if cmp = 0 then
              mapping
            else if cmp < 0 then
              (var1, var2) :: mapping
            else
              (var2, var1) :: mapping
              
      | Const symbol1, Const symbol2 when
          Symbol.equal symbol1 symbol2 ->

          mapping
            
      | Func func1, Func func2 when
          Symbol.equal func1.symbol func2.symbol ->
          
          Tools.array_fold2 are_terms_variants mapping func1.subterms func2.subterms
            
      | _ ->
          raise Exit
  in

  (* find a renaming making all variants identical *)
  let rec find_renaming mapping literals =
    match literals with
      | [] ->
          failwith "Lemma: find_renaming"
          
      | _ :: [] ->
          mapping
          
      | l1 :: tail ->
          (* search for a variant for l1 in tail *)
          begin
            let rec find_renaming' mapping tail' =
              match tail' with
                | [] ->
                    (* no variant found *)
                    find_renaming mapping tail
                    
                | l2 :: tail' ->
                    let mapping' =
                      try
                        Some (are_terms_variants mapping l1.atom l2.atom)
                      with
                        | Exit ->
                            None
                    in
                      (* variant found *)
                      match mapping' with
                        | Some mapping ->
                            find_renaming mapping tail

                        | None ->
                            find_renaming' mapping tail'
            in
              find_renaming' mapping tail            

          end
  in
  let mapping =
    find_renaming [] literals
  in

  let rec dereference mapping var =
    try
      let var' =
        Var.VarTable.find mapping var
      in
        dereference mapping var'
    with
      | Not_found ->
          var
  in

    match mapping with
      | [] ->
          (* no variants *)
          literals

      | _ ->
          begin
            (* apply the renaming *)
            let mapping' =
              Var.VarTable.create 61
            in
              List.iter
                (fun (var1, var2) ->
                   Var.VarTable.add mapping' var1 var2
                )
                mapping;

              let mapping =
                Var.VarTable.fold
                  (fun var1 var2 acc ->
                     let var2' =
                       dereference mapping' var2
                     in
                       (request_var var1, request_var var2') :: acc
                  )
                  mapping'
                  []
              in
                
                (* apply unifier - have to use replace to avoid independent normalization *)
                List.map
                  (fun literal ->
                     replace_terms_in_literal literal mapping
                  )
                  literals
          end