|  |  | @ -329,7 +329,13 @@ let ppx var_strength fs clss noneqs = | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | let pp_diff_cls = Trm.Map.pp_diff ~eq:Cls.equal Trm.pp Cls.pp Cls.pp_diff |  |  |  | let pp_diff_cls = Trm.Map.pp_diff ~eq:Cls.equal Trm.pp Cls.pp Cls.pp_diff | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | (* Basic queries ==========================================================*) |  |  |  | (* Basic representation queries ===========================================*) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | let trms r = | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   Iter.flat_map ~f:(fun (k, v) -> Iter.doubleton k v) (Subst.to_iter r.rep) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | let vars r = Iter.flat_map ~f:Trm.vars (trms r) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | let fv r = Var.Set.of_iter (vars r) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | (** test membership in carrier *) |  |  |  | (** test membership in carrier *) | 
			
		
	
		
		
			
				
					
					|  |  |  | let in_car r e = Subst.mem e r.rep |  |  |  | let in_car r e = Subst.mem e r.rep | 
			
		
	
	
		
		
			
				
					|  |  | @ -755,11 +761,97 @@ let rename x sub = | 
			
		
	
		
		
			
				
					
					|  |  |  |   in |  |  |  |   in | 
			
		
	
		
		
			
				
					
					|  |  |  |   if rep == x.rep && cls == x.cls then x else {x with rep; cls} |  |  |  |   if rep == x.rep && cls == x.cls then x else {x with rep; cls} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | let trms r = |  |  |  | let trivial vs r = | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |   Iter.flat_map ~f:(fun (k, v) -> Iter.doubleton k v) (Subst.to_iter r.rep) |  |  |  |   [%trace] | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ~call:(fun {pf} -> pf "@ %a@ %a" Var.Set.pp_xs vs pp_raw r) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ~retn:(fun {pf} ks -> pf "%a" Var.Set.pp_xs ks) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   @@ fun () -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   Var.Set.fold vs Var.Set.empty ~f:(fun v ks -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       let x = Trm.var v in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       match Subst.find x r.rep with | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       | None -> Var.Set.add v ks | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       | Some x' when Trm.equal x x' && Iter.is_empty (uses_of x r) -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           Var.Set.add v ks | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       | _ -> ks ) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | let vars r = Iter.flat_map ~f:Trm.vars (trms r) |  |  |  | let trim ks x = | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | let fv r = Var.Set.of_iter (vars r) |  |  |  |   [%trace] | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ~call:(fun {pf} -> pf "@ %a@ %a" Var.Set.pp_xs ks pp_raw x) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ~retn:(fun {pf} x' -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       pf "%a" pp_raw x' ; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       invariant x' ; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       assert (Var.Set.disjoint ks (fv x')) ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   @@ fun () -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   (* expand classes to include reps *) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   let reps = | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     Subst.fold x.rep Trm.Set.empty ~f:(fun ~key:_ ~data:rep reps -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         Trm.Set.add rep reps ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   let clss = | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     Trm.Set.fold reps x.cls ~f:(fun rep clss -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         Trm.Map.update rep clss ~f:(fun cls0 -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Cls.add rep (Option.value cls0 ~default:Cls.empty) ) ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   (* enumerate expanded classes and update solution subst *) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   let kills = Trm.Set.of_vars ks in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   Trm.Map.fold clss x ~f:(fun ~key:a' ~data:ecls x -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       (* remove mappings for non-rep class elements to kill *) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       let keep, drop = Trm.Set.diff_inter (Cls.to_set ecls) kills in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       if Trm.Set.is_empty drop then x | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       else | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let rep = Trm.Set.fold ~f:Subst.remove drop x.rep in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let x = {x with rep} in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         (* new class is keepers without rep *) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let keep' = Trm.Set.remove a' keep in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let ecls = Cls.of_set keep' in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if keep' != keep then | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           (* a' is to be kept: continue to use it as rep *) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           let cls = | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             if Cls.is_empty ecls then Trm.Map.remove a' x.cls | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             else Trm.Map.add ~key:a' ~data:ecls x.cls | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           {x with cls} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         else | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           (* a' is to be removed: choose new rep from the keepers *) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           let cls = Trm.Map.remove a' x.cls in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           let x = {x with cls} in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           match | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             Trm.Set.reduce keep ~f:(fun x y -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 if Theory.prefer x y < 0 then x else y ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           with | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           | Some b' -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               (* add mappings from each keeper to the new representative *) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               let rep = | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 Trm.Set.fold keep x.rep ~f:(fun elt rep -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     Subst.add ~key:elt ~data:b' rep ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               (* add trimmed class to new rep *) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               let cls = | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 if Cls.is_empty ecls then x.cls | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 else Trm.Map.add ~key:b' ~data:ecls x.cls | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               {x with rep; cls} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |           | None -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               (* entire class removed *) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |               x ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | let apply_and_elim ~wrt xs s r = | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   [%trace] | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ~call:(fun {pf} -> pf "@ %a%a@ %a" Var.Set.pp_xs xs Subst.pp s pp_raw r) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     ~retn:(fun {pf} (zs, r', ks) -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       pf "%a@ %a@ %a" Var.Set.pp_xs zs pp_raw r' Var.Set.pp_xs ks ; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       invariant r' ; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       assert (Var.Set.subset ks ~of_:xs) ; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       assert (Var.Set.disjoint ks (fv r')) ) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   @@ fun () -> | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   if Subst.is_empty s then (Var.Set.empty, r, Var.Set.empty) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |   else | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     let zs, r = apply_subst wrt s r in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     if is_unsat r then (Var.Set.empty, unsat, Var.Set.empty) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     else | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       let ks = trivial xs r in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       let r = trim ks r in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |       (zs, r, ks) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | (* Existential Witnessing and Elimination =================================*) |  |  |  | (* Existential Witnessing and Elimination =================================*) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -1138,98 +1230,6 @@ let solve_for_vars vss r = | 
			
		
	
		
		
			
				
					
					|  |  |  |               else `Continue us_xs ) |  |  |  |               else `Continue us_xs ) | 
			
		
	
		
		
			
				
					
					|  |  |  |             ~finish:(fun _ -> false) ) )] |  |  |  |             ~finish:(fun _ -> false) ) )] | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | let trivial vs r = |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   [%trace] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ~call:(fun {pf} -> pf "@ %a@ %a" Var.Set.pp_xs vs pp_raw r) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ~retn:(fun {pf} ks -> pf "%a" Var.Set.pp_xs ks) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   @@ fun () -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   Var.Set.fold vs Var.Set.empty ~f:(fun v ks -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       let x = Trm.var v in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       match Subst.find x r.rep with |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       | None -> Var.Set.add v ks |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       | Some x' when Trm.equal x x' && Iter.is_empty (uses_of x r) -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           Var.Set.add v ks |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       | _ -> ks ) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | let trim ks x = |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   [%trace] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ~call:(fun {pf} -> pf "@ %a@ %a" Var.Set.pp_xs ks pp_raw x) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ~retn:(fun {pf} x' -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       pf "%a" pp_raw x' ; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       invariant x' ; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       assert (Var.Set.disjoint ks (fv x')) ) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   @@ fun () -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   (* expand classes to include reps *) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   let reps = |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     Subst.fold x.rep Trm.Set.empty ~f:(fun ~key:_ ~data:rep reps -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         Trm.Set.add rep reps ) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   let clss = |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     Trm.Set.fold reps x.cls ~f:(fun rep clss -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         Trm.Map.update rep clss ~f:(fun cls0 -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             Cls.add rep (Option.value cls0 ~default:Cls.empty) ) ) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   (* enumerate expanded classes and update solution subst *) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   let kills = Trm.Set.of_vars ks in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   Trm.Map.fold clss x ~f:(fun ~key:a' ~data:ecls x -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       (* remove mappings for non-rep class elements to kill *) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       let keep, drop = Trm.Set.diff_inter (Cls.to_set ecls) kills in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       if Trm.Set.is_empty drop then x |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       else |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         let rep = Trm.Set.fold ~f:Subst.remove drop x.rep in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         let x = {x with rep} in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         (* new class is keepers without rep *) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         let keep' = Trm.Set.remove a' keep in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         let ecls = Cls.of_set keep' in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         if keep' != keep then |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           (* a' is to be kept: continue to use it as rep *) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           let cls = |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             if Cls.is_empty ecls then Trm.Map.remove a' x.cls |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             else Trm.Map.add ~key:a' ~data:ecls x.cls |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           {x with cls} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         else |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           (* a' is to be removed: choose new rep from the keepers *) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           let cls = Trm.Map.remove a' x.cls in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           let x = {x with cls} in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           match |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             Trm.Set.reduce keep ~f:(fun x y -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 if Theory.prefer x y < 0 then x else y ) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           with |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           | Some b' -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               (* add mappings from each keeper to the new representative *) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               let rep = |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 Trm.Set.fold keep x.rep ~f:(fun elt rep -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                     Subst.add ~key:elt ~data:b' rep ) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               (* add trimmed class to new rep *) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               let cls = |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 if Cls.is_empty ecls then x.cls |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 else Trm.Map.add ~key:b' ~data:ecls x.cls |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               {x with rep; cls} |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |           | None -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               (* entire class removed *) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |               x ) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | let apply_and_elim ~wrt xs s r = |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   [%trace] |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ~call:(fun {pf} -> pf "@ %a%a@ %a" Var.Set.pp_xs xs Subst.pp s pp_raw r) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     ~retn:(fun {pf} (zs, r', ks) -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       pf "%a@ %a@ %a" Var.Set.pp_xs zs pp_raw r' Var.Set.pp_xs ks ; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       invariant r' ; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       assert (Var.Set.subset ks ~of_:xs) ; |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       assert (Var.Set.disjoint ks (fv r')) ) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   @@ fun () -> |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   if Subst.is_empty s then (Var.Set.empty, r, Var.Set.empty) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |   else |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     let zs, r = apply_subst wrt s r in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     if is_unsat r then (Var.Set.empty, unsat, Var.Set.empty) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     else |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       let ks = trivial xs r in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       let r = trim ks r in |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |       (zs, r, ks) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | (* Replay debugging =======================================================*) |  |  |  | (* Replay debugging =======================================================*) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | type call = |  |  |  | type call = | 
			
		
	
	
		
		
			
				
					|  |  | 
 |