let mk_ite a b c = 
  let cofactors x a =
    try
      let (y, pos, neg) = d_ite a in
        if Term.eq x y then (pos, neg) else (a, a)
    with
        Not_found -> (a, a)
  in
  let topvar x s2 s3 =
    let to_option f s = try Some(f s) with Not_found -> None in
    let max x y = if Term.(<<<) x y then x else y in
      match to_option d_ite s2, to_option d_ite s3 with
        | Some(y,_,_), Some(z,_,_) -> max x (max y z)
        | Some(y,_,_), None -> max x y
        | NoneSome(z,_,_) -> max x z
        | NoneNone -> x
  in
  let rec build s3 =
    let module H3 = Hashtbl.Make(
      struct
        type t = Term.t * Term.t * Term.t
        let equal (a1, a2, a3) (b1, b2, b3) = 
          Term.eq a1 b1 && Term.eq a2 b2 && Term.eq a3 b3
        let hash = Hashtbl.hash
      end)
    in
    let ht =  H3.create 17 in
    let _ = Tools.add_at_reset (fun () -> H3.clear ht) in
      try
        H3.find ht s3
      with 
          Not_found ->
            let b = build_fun s3 in
              H3.add ht s3 b; b 
  and build_fun (s1, s2, s3) =
    if Term.eq s2 s3 then s2
    else if is_full s2 && is_empty s3 then s1
    else if is_full s1 then s2
    else if is_empty s1 then s3
    else 
      try
        let (y, _, _) = d_ite s1 in
        let x = topvar y s2 s3 in
        let (pos1, neg1) = cofactors x s1 in
        let (pos2, neg2) = cofactors x s2 in
        let (pos3, neg3) = cofactors x s3 in
        let pos = build (pos1, pos2, pos3) in
        let neg = build (neg1, neg2, neg3) in
          if Term.eq pos neg then pos else 
            Term.App.mk_app Sym.Propset.mk_ite [x; pos; neg]
      with
          Not_found -> 
            Term.App.mk_app Sym.Propset.mk_ite [s1; s2; s3]
  in
  let lift a =
    if is_interp a then a else
      Term.App.mk_app Sym.Propset.mk_ite [a; mk_full(); mk_empty()]
  in
  let  drop a =
    try
      let (b1, b2, b3) = d_ite a in
        if is_full b2 && is_empty b3 then b1
        else 
          a
    with
        Not_found -> a
  in        
    try
      drop (build (lift a, lift b, lift c))
    with
        Not_found -> invalid_arg "ite"