diff --git a/src_colibri2/core/demon.ml b/src_colibri2/core/demon.ml index 110ade1ed2bf6feda7d86d1845d83656f57ddf8b..2b07e5d7b2d5114a4beeee8408687e4ddc686893 100644 --- a/src_colibri2/core/demon.ml +++ b/src_colibri2/core/demon.ml @@ -115,7 +115,7 @@ module Key = struct val key: (Key.t, Data.t, info) t - val delayed: int option + val delay: Events.delay val wakeup: Egraph.t -> Key.t -> Data.t Events.Fired.t -> info -> Key.t alive @@ -168,7 +168,7 @@ module Key = struct Egraph.set_env d D.key.dk_data (module DemTable'); (** wakeup *) let alive = D.wakeup d k events info in - (** delayed can be modified *) + (** delay can be modified *) begin match alive with | AliveStopped | AliveRedirected _ -> let demstate = match alive with @@ -257,7 +257,7 @@ module Key = struct let enqueue = enqueue let key = D.key.dk_id - let delayed = D.delayed + let delay = D.delay end in Egraph.Wait.register_dem (module Dem) @@ -384,7 +384,7 @@ module Fast = struct val key: Data.t t (** never killed *) - val delayed: int option + val delay: Events.delay val throttle: int (** todo int ref? *) (** number of time run in a row *) val wakeup: Egraph.t -> Data.t Events.Fired.event -> unit @@ -421,7 +421,9 @@ module Fast = struct D.Data.pp (Events.Fired.get_data event); D.wakeup d event; Debug.dprintf0 debug "[Demon] @[Done@]"; - if Option.is_some D.delayed then Egraph.flush_internal d; + (match D.delay with + | Immediate -> () + | Delayed_by _ | LastEffort _ -> Egraph.flush_internal d); run_one () in try run_one (); @@ -469,7 +471,7 @@ module Fast = struct let enqueue = enqueue let key = D.key.dk_id - let delayed = D.delayed + let delay = D.delay end in Egraph.Wait.register_dem (module Dem) @@ -505,7 +507,7 @@ module Fast = struct let register_init_daemon (type a) ~name - ?(delayed=Some 1) + ?(delay=Events.Delayed_by 1) ?(throttle=100) (thterm: (module Nodes.RegisteredThTerm with type t = a) ) (f:Egraph.t -> a -> unit) @@ -515,7 +517,7 @@ module Fast = struct let module DaemonInit = struct let key = create name module Data = Popop_stdlib.DUnit - let delayed = delayed + let delay = delay let throttle = throttle let wakeup d = function | Events.Fired.EventRegSem(thterm,()) -> @@ -530,7 +532,7 @@ module Fast = struct let register_init_daemon_value (type a) ~name - ?(delayed=Some 1) + ?(delay=Events.Delayed_by 1) ?(throttle=100) (value: (module Nodes.RegisteredValue with type t = a) ) (f:Egraph.t -> a -> unit) @@ -540,7 +542,7 @@ module Fast = struct let module DaemonInit = struct let key = create name module Data = Popop_stdlib.DUnit - let delayed = delayed + let delay = delay let throttle = throttle let wakeup d = function | Events.Fired.EventRegValue(value,()) -> @@ -554,7 +556,7 @@ module Fast = struct let register_change_repr_daemon ~name - ?(delayed=Some 1) + ?(delay=Events.Delayed_by 1) ?(throttle=100) (f:Egraph.t -> Node.t -> unit) (init_d:Egraph.t) @@ -562,7 +564,7 @@ module Fast = struct let module DaemonInit = struct let key = create name module Data = Popop_stdlib.DUnit - let delayed = delayed + let delay = delay let throttle = throttle let wakeup d = function | Events.Fired.EventChange(node,()) -> @@ -576,7 +578,7 @@ module Fast = struct let register_change_domain_daemon (type a) (type b) ~name - ?(delayed=Some 1) + ?(delay=Events.Delayed_by 1) ?(throttle=100) ?(pp=Fmt.nop) (dom:a DomKind.t) @@ -588,7 +590,7 @@ module Fast = struct type t = b let pp = pp end - let delayed = delayed + let delay = delay let throttle = throttle let wakeup d = function | Events.Fired.EventDom(node,dom',data) -> @@ -608,7 +610,7 @@ module Fast = struct let register_get_value_daemon (type a) (type b) ~name - ?(delayed=Some 1) + ?(delay=Events.Delayed_by 1) ?(throttle=100) ?(pp=Fmt.nop) (value: (module Nodes.RegisteredValue with type s = a) ) @@ -621,7 +623,7 @@ module Fast = struct type t = b let pp = pp end - let delayed = delayed + let delay = delay let throttle = throttle let wakeup d = function | Events.Fired.EventValue(node,value,v,data) -> @@ -643,7 +645,7 @@ module Fast = struct } let register_simply - ?(delayed=Some 1) + ?(delay=Events.Delayed_by 1) ?(throttle=100) name = @@ -653,7 +655,7 @@ module Fast = struct type t = Egraph.t -> Node.t -> unit let pp = Fmt.nop end - let delayed = delayed + let delay = delay let throttle = throttle let wakeup d = function | Events.Fired.EventDom(node,_,f) -> diff --git a/src_colibri2/core/demon.mli b/src_colibri2/core/demon.mli index e04f49348c32da145c11ef929da5db72ddccd42e..5c52b1cf15355c574766ca9378c7db8a8bfefd00 100644 --- a/src_colibri2/core/demon.mli +++ b/src_colibri2/core/demon.mli @@ -66,7 +66,7 @@ module Key: sig val key: (Key.t, Data.t, info) t - val delayed: int option + val delay: Events.delay val wakeup: Egraph.t -> Key.t -> Data.t Events.Fired.t -> info -> Key.t alive @@ -75,7 +75,7 @@ module Key: sig module Register (D:S): sig val init: Egraph.t -> unit - (** to run for each new delayed *) + (** to run for each new delay *) end type ('k,'i) state = @@ -113,7 +113,7 @@ module Fast: sig val key: Data.t t (** never killed *) - val delayed: int option + val delay: Events.delay val throttle: int (** todo int ref? *) (** number of time run in a row *) val wakeup: Egraph.t -> Data.t Events.Fired.event -> unit @@ -122,7 +122,7 @@ module Fast: sig module Register (D:S): sig val init: Egraph.t -> unit - (** to run for each new delayed *) + (** to run for each new delay *) end val attach: Egraph.t -> 'd t -> 'd Create.t -> unit @@ -130,7 +130,7 @@ module Fast: sig (** helper *) val register_init_daemon: name:string -> - ?delayed:int option -> + ?delay:Events.delay -> ?throttle:int -> (module RegisteredThTerm with type t = 'a) -> (Egraph.t -> 'a -> unit) -> @@ -141,7 +141,7 @@ module Fast: sig (** helper *) val register_init_daemon_value: name:string -> - ?delayed:int option -> + ?delay:Events.delay -> ?throttle:int -> (module RegisteredValue with type t = 'a) -> (Egraph.t -> 'a -> unit) -> @@ -152,7 +152,7 @@ module Fast: sig (** helper *) val register_change_repr_daemon: name:string -> - ?delayed:int option -> + ?delay:Events.delay -> ?throttle:int -> (Egraph.t -> Node.t -> unit) -> Egraph.t -> @@ -162,7 +162,7 @@ module Fast: sig (** helper *) val register_change_domain_daemon: name:string -> - ?delayed:int option -> + ?delay:Events.delay -> ?throttle:int -> ?pp:('b Fmt.t) -> 'a DomKind.t -> @@ -173,7 +173,7 @@ module Fast: sig (** helper *) val register_get_value_daemon: name:string -> - ?delayed:int option -> + ?delay:Events.delay -> ?throttle:int -> ?pp:('b Fmt.t) -> (module RegisteredValue with type s = 'a) -> @@ -188,7 +188,7 @@ module Fast: sig (** helper *) val register_simply: - ?delayed:int option -> + ?delay:Events.delay -> ?throttle:int -> string -> (Egraph.t -> unit) * waiter diff --git a/src_colibri2/core/egraph.ml b/src_colibri2/core/egraph.ml index b245e071ced200686425747fed9f518745b30a97..c8dd819b334dfcd260a10c62a50cbb30f016a709 100644 --- a/src_colibri2/core/egraph.ml +++ b/src_colibri2/core/egraph.ml @@ -903,6 +903,9 @@ module Delayed = struct let register_decision t chogen = t.sched_decision chogen + let register_delayed_event t dem v = + t.sched_daemon (Events.Wait.DaemonKey(dem,v)) + let contradiction d = d.env.current_delayed <- unsat_delayed; raise Contradiction diff --git a/src_colibri2/core/egraph.mli b/src_colibri2/core/egraph.mli index 5b9b615faeca31a6a2ad79af3a23b8b28aa9dc56..3acdf6808b53c807265f72f0778d6332b66312e7 100644 --- a/src_colibri2/core/egraph.mli +++ b/src_colibri2/core/egraph.mli @@ -124,6 +124,9 @@ val register_decision: t -> choice -> unit [choose_decision] of the [Cho] will be called at that time to know if the decision is still needed. *) +val register_delayed_event: t -> (_,'a) Events.Dem.t -> 'a -> unit +(** register an event for later. *) + val contradiction: t -> 'b (** {3 Low level} *) diff --git a/src_colibri2/core/events.ml b/src_colibri2/core/events.ml index 7f4bc3718aa190fd2322f3dd0d0462132c89e71d..6c67f5657a2a867042de9d37605b6f82fcb24a7e 100644 --- a/src_colibri2/core/events.ml +++ b/src_colibri2/core/events.ml @@ -108,6 +108,11 @@ module Fired = struct type 'b t = 'b event list end +type delay = + | Immediate + | Delayed_by of int + | LastEffort of int + module Wait = struct type t = | Event: ('k,'d) Dem.t * 'k -> t @@ -163,14 +168,14 @@ module Wait = struct val print_event : event Format.printer val enqueue : delayed_ro -> event Fired.event -> runable enqueue val key : (event, runable) Dem.t - val delayed : int option + val delay : delay end val register_dem : (module Dem with type event = 'k and type runable = 'd) -> unit val get_dem : ('k, 'd) Dem.t -> (module Dem with type event = 'k and type runable = 'd) - val get_priority: daemon_key -> int + val get_priority: daemon_key -> delay val print_dem_event : ('a, 'b) Dem.t -> 'a Format.printer @@ -212,7 +217,7 @@ module Wait = struct val enqueue: delayed_ro -> event Fired.event -> runable enqueue val key: (event,runable) Dem.t - val delayed: int option + val delay: delay end module Registry = Dem.Make_Registry(struct @@ -235,7 +240,7 @@ module Wait = struct let get_priority = function | DaemonKey(dem,_) -> let module Dem = (val get_dem dem) in - Option.value ~default:1 Dem.delayed + Dem.delay let print_dem_event = Registry.printk let () = Print.pdem_event.Print.pdem_event <- print_dem_event @@ -248,9 +253,9 @@ module Wait = struct let new_pending_daemon (type k) (type d) t (dem:(k,d) Dem.t) runable = let module Dem = (val get_dem dem) in let daemonkey = DaemonKey(dem, runable) in - if Option.is_none Dem.delayed - then S.schedule_immediate t daemonkey - else S.schedule t daemonkey + match Dem.delay with + | Immediate -> S.schedule_immediate t daemonkey + | _ -> S.schedule t daemonkey let wakeup_event translate t info wevent = match wevent with diff --git a/src_colibri2/core/events.mli b/src_colibri2/core/events.mli index 22567d8373083047924b5ae26c8eabb10be54b69..dc54152417182a1a7e0379071f6ffea5849b44e0 100644 --- a/src_colibri2/core/events.mli +++ b/src_colibri2/core/events.mli @@ -49,6 +49,13 @@ end module Dem: Keys.Key2 +type delay = + | Immediate + | Delayed_by of int + (** Must be strictly positive *) + | LastEffort of int + (** When no decisions remains, must be strictly positive *) + module Wait : sig type t = | Event: ('k,'d) Dem.t * 'k -> t @@ -88,14 +95,14 @@ module Wait : sig val print_event : event Format.printer val enqueue : delayed_ro -> event Fired.event -> runable enqueue val key : (event, runable) Dem.t - val delayed : int option + val delay : delay end val register_dem : (module Dem with type event = 'k and type runable = 'd) -> unit val get_dem : ('k, 'd) Dem.t -> (module Dem with type event = 'k and type runable = 'd) - val get_priority: daemon_key -> int + val get_priority: daemon_key -> delay val print_dem_event : ('a, 'b) Dem.t -> 'a Format.printer diff --git a/src_colibri2/solver/scheduler.ml b/src_colibri2/solver/scheduler.ml index 2795ae7aa45ff4989caa2e01c6212c0db77b5494..69cb1a8d5abde1fc3cdb602a97a54ade3e493a81 100644 --- a/src_colibri2/solver/scheduler.ml +++ b/src_colibri2/solver/scheduler.ml @@ -37,6 +37,7 @@ let debug_dotgui = Debug.register_flag let var_decay = 1. /. 0.95 let stats_propa = Debug.register_stats_int ~name:"Scheduler.daemon" ~init:0 +let stats_lasteffort = Debug.register_stats_int ~name:"Scheduler.lasteffort" ~init:0 let stats_dec = Debug.register_stats_int ~name:"Scheduler.decision" ~init:0 let stats_con = Debug.register_stats_int ~name:"Scheduler.conflict" ~init:0 @@ -77,6 +78,7 @@ type bp = type t = { mutable choices : Prio.t; daemons : Events.Wait.daemon_key Context.TimeWheel.t; + lasteffort : Events.Wait.daemon_key Context.TimeWheel.t; mutable prev_scheduler_state : bp option; solver_state : Egraph.Backtrackable.t; mutable delayed : Egraph.t option; @@ -111,6 +113,7 @@ let new_solver () = let context = Context.create () in { choices = Prio.empty; daemons = Context.TimeWheel.create (Context.creator context); + lasteffort = Context.TimeWheel.create (Context.creator context); prev_scheduler_state = None; solver_state = Egraph.Backtrackable.new_t (Context.creator context); context; @@ -160,7 +163,11 @@ let new_delayed = incr daemon_count; Debug.dprintf1 debug "[Scheduler] New possible daemon:%i" !daemon_count; - Context.TimeWheel.add t.daemons att (Egraph.Wait.get_priority att) + match Egraph.Wait.get_priority att with + | Immediate -> assert false (* absurd *) + | Delayed_by offset -> Context.TimeWheel.add t.daemons att offset + | LastEffort offset -> + Context.TimeWheel.add t.lasteffort att offset in let sched_decision dec = incr dec_count; @@ -286,11 +293,21 @@ let run_one_step t d = conflict_analysis t end | None -> - let act, prio = Prio.extract_min t.choices in - match act with - | Att.Decision (_,chogen) -> + match Prio.extract_min t.choices with + | Att.Decision (_,chogen), prio -> Debug.dprintf0 debug "[Scheduler] decision"; try_run_dec t d prio chogen + | exception Leftistheap.Empty -> + match Context.TimeWheel.next t.lasteffort with + | Some att -> begin + Debug.incr stats_lasteffort; + try + Egraph.Backtrackable.run_daemon d att; d + with Egraph.Contradiction -> + Debug.dprintf0 debug "[Scheduler] Contradiction"; + conflict_analysis t + end + | None -> d let rec flush t d = try @@ -309,7 +326,7 @@ let rec run_inf_step ?limit ~nodec t d = 0 < Context.TimeWheel.size t.daemons || match Prio.min t.choices with | Some (Att.Decision _) -> not nodec - | None -> false + | None -> 0 < Context.TimeWheel.size t.lasteffort in if run then diff --git a/src_colibri2/theories/bool/boolean.ml b/src_colibri2/theories/bool/boolean.ml index 727488e801ce4b970ec4f0045e5a1136e34553ee..1ed56789125e729d2fe2ecae6e3fb214f7b92b83 100644 --- a/src_colibri2/theories/bool/boolean.ml +++ b/src_colibri2/theories/bool/boolean.ml @@ -155,7 +155,7 @@ module DaemonPropaNot = struct Format.fprintf fmt "%a,%a -> %a" Th.pp v Node.pp cl1 Node.pp cl2 end - let delayed = Some 1 + let delay = Events.Delayed_by 1 let key = Demon.Fast.create "Bool.DaemonPropaNot" let throttle = 100 let wakeup d = @@ -207,7 +207,7 @@ module DaemonPropa = struct | All thterm -> Format.fprintf fmt "All(%a)" ThE.pp thterm end - let delayed = Some 1 + let delay = Events.Delayed_by 1 let throttle = 100 let wakeup_lit d thterm watched watcher = @@ -314,7 +314,7 @@ module DaemonInit = struct module Data = DUnit - let delayed = Some 1 + let delay = Events.Delayed_by 1 let throttle = 100 let wakeup d = function | Events.Fired.EventRegSem(thterm,()) -> diff --git a/src_colibri2/theories/bool/equality.ml b/src_colibri2/theories/bool/equality.ml index 44a5540291b83d481be76e7d4f637b7f807659ba..0052db570c9715a1e253b0c83703a2088b5c8b46 100644 --- a/src_colibri2/theories/bool/equality.ml +++ b/src_colibri2/theories/bool/equality.ml @@ -332,7 +332,7 @@ module DaemonPropa = struct module Data = DUnit type info = unit let default = () - let delayed = Some 1 + let delay = Events.Delayed_by 1 let wakeup d v _ev () = norm_dom d (ThE.index v) @@ -347,7 +347,7 @@ module DaemonInit = struct module Data = DUnit type info = unit let default = () - let delayed = None + let delay = Events.Immediate let wakeup d () ev () = List.iter (function Events.Fired.EventRegSem(clsem,()) -> @@ -422,7 +422,7 @@ module DaemonPropaITE = struct Egraph.register d branch; Egraph.merge d own branch - let delayed = Some 1 + let delay = Events.Delayed_by 1 let throttle = 100 let wakeup d = function | Events.Fired.EventValue(cond,dom,_,clsem) -> @@ -445,7 +445,7 @@ module DaemonInitITE = struct module Key = DUnit module Data = DUnit - let delayed = Some 1 + let delay = Events.Delayed_by 1 let throttle = 100 let wakeup d = function | Events.Fired.EventRegSem(clsem,()) -> @@ -521,7 +521,7 @@ let init_diff_to_value (type a) (type b) module Data = Val let key = key let throttle = 100 - let delayed = Some 1 + let delay = Events.Delayed_by 1 let wakeup d = function | Events.Fired.EventDom(_,_,v) -> diff --git a/src_colibri2/theories/bool/uninterp.ml b/src_colibri2/theories/bool/uninterp.ml index 15569c6427a0edaff1856ff147a1846543eadb00..09e734e6069025d6e6ca40545962eb4ff4110978 100644 --- a/src_colibri2/theories/bool/uninterp.ml +++ b/src_colibri2/theories/bool/uninterp.ml @@ -125,7 +125,7 @@ module DaemonPropa = struct Demon.Key.attach d key v [EventChange(f,()); EventChange(g,())] - let delayed = None (** can be not None *) + let delay = Events.Immediate (** can be not None *) let wakeup d (nodesem:k) _ev () = match ThE.sem nodesem with | Th.Fun _ -> Demon.AliveStopped @@ -148,7 +148,7 @@ module DaemonInit = struct module Data = DUnit type info = unit let default = () - let delayed = Some 1 + let delay = Events.Delayed_by 1 let wakeup d () ev () = List.iter diff --git a/src_colibri2/theories/quantifier/quantifier.ml b/src_colibri2/theories/quantifier/quantifier.ml index 178623387a988d5ebe20728c0d15edecbe212ce9..081775add4263884fc7d0a6d6fe64e67a273f35d 100644 --- a/src_colibri2/theories/quantifier/quantifier.ml +++ b/src_colibri2/theories/quantifier/quantifier.ml @@ -396,8 +396,9 @@ module Trigger = struct [@@deriving eq, ord, hash] let pp fmt t = - Fmt.pf fmt "[%a -> %a]" Pattern.pp t.pat Ground.ThClosedQuantifier.pp - t.form + Fmt.pf fmt "[%a, %a -> %a]" Pattern.pp t.pat + Fmt.(list ~sep:comma Pattern.pp) + t.checks Ground.ThClosedQuantifier.pp t.form end include T @@ -424,7 +425,7 @@ module Trigger = struct List.fold_left aux pats tl | _ -> t :: pats in - let pats = aux [] t in + let pats = List.sort_uniq ~cmp:Expr.Term.compare (aux [] t) in let tyvs = Expr.Ty.Var.S.of_list tyvs in let tvs = Expr.Term.Var.S.of_list tvs in let pats_full, pats_partial = @@ -445,7 +446,7 @@ module Trigger = struct aux ( { pat = a; - checks = other @ pats_partial; + checks = other @ l @ pats_partial; form = cq; eager = true; } @@ -454,6 +455,13 @@ module Trigger = struct in aux [] [] pats_full in + Debug.dprintf6 debug "@[pats_full:%a,@ pats_partial:%a,@ tri:%a@]@." + Fmt.(list ~sep:comma Pattern.pp) + pats_full + Fmt.(list ~sep:comma Pattern.pp) + pats_partial + Fmt.(list ~sep:comma pp) + multi_pats; multi_pats let compute_all_triggers (cq : Ground.ThClosedQuantifier.t) = @@ -519,6 +527,49 @@ module Trigger = struct | Var _ -> Datastructure.Queue.push env_vars d t | App (f, _, _) -> Context.Queue.push (F.EnvApps.find env_tri_by_apps d f) t + let instantiate_aux d tri subst = + let form = Ground.ThClosedQuantifier.sem tri.form in + Debug.dprintf8 debug "[Quant] %a instantiation found %a, pat %a, checks:%a" + Ground.Subst.pp subst Expr.Term.pp form.body Pattern.pp tri.pat + Fmt.(list ~sep:comma Pattern.pp) + tri.checks; + Debug.incr nb_instantiation; + let n = Ground.convert ~subst form.body in + if Debug.test_flag Debug.stats && not (Egraph.is_registered d n) then + Debug.incr nb_new_instantiation; + Egraph.register d n; + Egraph.merge d n (Ground.ThClosedQuantifier.node tri.form) + + module Delayed_instantiation = struct + type event = unit + + let print_event = Unit.pp + + let enqueue _ _ = assert false + + let key = + Events.Dem.create_key + ( module struct + type d = t * Ground.Subst.t + + type t = unit + + let name = "delayed_instantiation" + end ) + + let delay = Events.LastEffort 1 + + type runable = t * Ground.Subst.t [@@deriving show] + + let print_runable = pp_runable + + let run d (tri, subst) = + instantiate_aux d tri subst; + None + end + + let () = Egraph.Wait.register_dem (module Delayed_instantiation) + let instantiate d tri subst = if tri.eager @@ -527,16 +578,8 @@ module Trigger = struct try not (Node.S.is_empty (Pattern.check_term_exists d subst pat)) with Not_found -> false) tri.checks - then ( - let form = Ground.ThClosedQuantifier.sem tri.form in - Debug.dprintf4 debug "[Quant] %a instantiation found %a" Ground.Subst.pp - subst Expr.Term.pp form.body; - Debug.incr nb_instantiation; - let n = Ground.convert ~subst form.body in - if Debug.test_flag Debug.stats && not (Egraph.is_registered d n) then - Debug.incr nb_new_instantiation; - Egraph.register d n; - Egraph.merge d n (Ground.ThClosedQuantifier.node tri.form) ) + then instantiate_aux d tri subst + else Egraph.register_delayed_event d Delayed_instantiation.key (tri, subst) let match_ d tri n = Debug.dprintf4 debug "[Quant] match %a %a" pp tri Node.pp n; @@ -843,7 +886,7 @@ let init, attach = | ({ binder = Forall; _ } as e), false -> Egraph.merge d (skolemize d e) n | { binder = Exists; _ }, false | { binder = Forall; _ }, true -> - let triggers = Trigger.compute_all_triggers th in + let triggers = Trigger.compute_top_triggers th in Debug.dprintf4 debug "[Quant] For %a adds %a" Ground.ThClosedQuantifier.pp th Fmt.(list ~sep:semi (Fmt.using (fun t -> t.Trigger.pat) Pattern.pp)) @@ -888,10 +931,9 @@ let add_info_on_ground_terms d thg = Context.Queue.iter (fun trg -> Trigger.match_ d trg res) trgs let init d = - let delayed = Some 10 in - Demon.Fast.register_change_repr_daemon ~delayed ~name:"Quantifier.merge" merge - d; - Demon.Fast.register_init_daemon ~delayed ~name:"Quantifier.new_quantifier" + let delay = Events.Delayed_by 10 in + Demon.Fast.register_change_repr_daemon ~delay ~name:"Quantifier.merge" merge d; + Demon.Fast.register_init_daemon ~delay ~name:"Quantifier.new_quantifier" (module Ground.ThClosedQuantifier) quantifier_registered d; Ground.register_converter d add_info_on_ground_terms;