diff --git a/src_colibri2/core/colibri2_core.ml b/src_colibri2/core/colibri2_core.ml index 780a21f70ba6b0054dcb010c667e44200eccbfbd..afc77d49c535fe795bb9d15ce7f3797c5dc027cf 100644 --- a/src_colibri2/core/colibri2_core.ml +++ b/src_colibri2/core/colibri2_core.ml @@ -194,9 +194,9 @@ module Events = struct type delay = Events.delay = | Immediate - | Delayed_by of int (** Must be strictly positive *) + | Delayed_by of int | LastEffort of int - (** Should try to ensure that a model exists, must be strictly positive *) + | LastEffortUncontextual of int | FixingModel type enqueue = Events.enqueue = diff --git a/src_colibri2/core/colibri2_core.mli b/src_colibri2/core/colibri2_core.mli index 974c065fd8aae1f400d24630e8cab171ce65d2e9..c377ed961540086a860a92bc7faa8363da063cde 100644 --- a/src_colibri2/core/colibri2_core.mli +++ b/src_colibri2/core/colibri2_core.mli @@ -1111,7 +1111,10 @@ and Events : sig | Immediate | Delayed_by of int (** Must be strictly positive *) | LastEffort of int - (** Should try to ensure that a model exists, must be strictly positive *) + (** After no propagation and decisions remains to be done *) + | LastEffortUncontextual of int + (** Same as before but could be moved as propagation before the time it is + added *) | FixingModel type enqueue = diff --git a/src_colibri2/core/events.ml b/src_colibri2/core/events.ml index 2641ad0178b3526dfc033edb3aa440d08cc0a15e..15f84bdcbe7b843e395d97cdeea3a2d7c779f8f7 100644 --- a/src_colibri2/core/events.ml +++ b/src_colibri2/core/events.ml @@ -34,7 +34,12 @@ module Print = struct { pdem_runable = (fun _ _ _ -> assert false) } end -type delay = Immediate | Delayed_by of int | LastEffort of int | FixingModel +type delay = + | Immediate + | Delayed_by of int + | LastEffort of int + | LastEffortUncontextual of int + | FixingModel type enqueue = | EnqRun : 'r Dem.t * 'r * Nodes.ThTerm.t option -> enqueue diff --git a/src_colibri2/core/events.mli b/src_colibri2/core/events.mli index 2f744c27eb2d1501bdd8a4083fbe73b6e31059a7..ebf78a13b5f29f566c71da3bc3e82e846938aa70 100644 --- a/src_colibri2/core/events.mli +++ b/src_colibri2/core/events.mli @@ -24,7 +24,10 @@ type delay = | Immediate | Delayed_by of int (** Must be strictly positive *) | LastEffort of int - (** Should try to ensure that a model exists, must be strictly positive *) + (** After no propagation and decisions remains to be done *) + | LastEffortUncontextual of int + (** Same as before but could be moved as propagation before the time it is + added *) | FixingModel type enqueue = diff --git a/src_colibri2/solver/scheduler.ml b/src_colibri2/solver/scheduler.ml index 0641b25554ae51edde2b12e3d8586e4a94a5c316..53127a77b53725fe29d14bea9ce574f05f82efcc 100644 --- a/src_colibri2/solver/scheduler.ml +++ b/src_colibri2/solver/scheduler.ml @@ -69,7 +69,7 @@ module PrioMake (S : sig end) = struct module Att = struct - type t = { id : int; v : S.t } + type t = { id : int; v : S.t; added_at : int } type prio = float @@ -109,9 +109,11 @@ struct (function None -> Some coef | Some v -> Some (coef *. v)) t.db x.Att.id - let insert t v = + let get_prio t x = Popop_stdlib.DInt.H.find_def t.db 1. x.Att.id + + let insert t ~added_at v = Context.Ref.set t.size (Context.Ref.get t.size + 1); - let x = { Att.v; id = t.next } in + let x = { Att.v; id = t.next; added_at } in t.next <- t.next + 1; Context.Ref.set t.prio (P.insert t.db x (Context.Ref.get t.prio)) @@ -123,15 +125,15 @@ struct Some x | exception Leftistheap.Empty -> None - let get_min_and_skew t = - match P.min (Context.Ref.get t.prio) with - | Some v -> Some (v, Popop_stdlib.DInt.H.find_def t.db 1. v.id) - | None -> None - - let pop t = - match P.extract_min (Context.Ref.get t.prio) with - | _, prio -> Context.Ref.set t.prio prio - | exception Leftistheap.Empty -> () + (* let get_min_and_skew t = + * match P.min (Context.Ref.get t.prio) with + * | Some v -> Some (v, Popop_stdlib.DInt.H.find_def t.db 1. v.id) + * | None -> None + * + * let pop t = + * match P.extract_min (Context.Ref.get t.prio) with + * | _, prio -> Context.Ref.set t.prio prio + * | exception Leftistheap.Empty -> () *) let size t = Context.Ref.get t.size @@ -159,6 +161,7 @@ module PrioLastEffort = PrioMake (struct | Events.Immediate -> 1 | Events.Delayed_by offset -> offset | Events.LastEffort offset -> offset + | Events.LastEffortUncontextual offset -> offset | Events.FixingModel -> 1) end) @@ -181,7 +184,8 @@ type bp = { type solve_step = | Propagate | FixModel - | BacktrackChoice of (Egraph.wt -> unit) * (Egraph.wt -> unit) Base.Sequence.t + | BacktrackChoice of + (Egraph.wt -> unit) * (Egraph.wt -> unit) Base.Sequence.t * solve_step type t = { choices : Prio.t; @@ -198,7 +202,8 @@ type t = { mutable steps : int; mutable stepsl : int; mutable last_todo : (Egraph.wt -> unit) * bp_kind; - allow_learning : bool; + last_effort_learnt : Events.daemon_key Context.Clicket.t; + allow_learning : bool; (** Learning *) mutable learning : bool; mutable learning_htbl : int ThTerm.H.t; mutable learning_tbl : int array; @@ -227,23 +232,25 @@ let get_steps t = t.steps let new_solver ~learning () = let context = Context.create () in + let creator = Context.creator context in let daemon_count = ref (-1) in let dec_count = ref (-1) in let t = { - choices = Prio.create (Context.creator context); - daemons = Context.TimeWheel.create (Context.creator context); - lasteffort = PrioLastEffort.create (Context.creator context); - fixing_model = Context.Ref.create (Context.creator context) []; + choices = Prio.create creator; + daemons = Context.TimeWheel.create creator; + lasteffort = PrioLastEffort.create creator; + fixing_model = Context.Ref.create creator []; prev_scheduler_state = None; - solver_state = Backtrackable.new_t (Context.creator context); + solver_state = Backtrackable.new_t creator; context; var_inc = ref 1.; level = 0; - solve_step = Context.Ref.create (Context.creator context) Propagate; + solve_step = Context.Ref.create creator Propagate; steps = 0; stepsl = 0; last_todo = ((fun _ -> ()), External); + last_effort_learnt = Context.Clicket.create creator; allow_learning = learning; learning = false; learning_htbl = ThTerm.H.create 32; @@ -258,13 +265,15 @@ let new_solver ~learning () = match get_event_priority att with | Immediate -> assert false (* absurd *) | Delayed_by offset -> Context.TimeWheel.add t.daemons att offset - | LastEffort _ -> PrioLastEffort.insert t.lasteffort att + | LastEffort _ -> PrioLastEffort.insert t.lasteffort att ~added_at:(-1) + | LastEffortUncontextual _ -> + PrioLastEffort.insert t.lasteffort att ~added_at:t.level | FixingModel -> Context.Ref.set t.fixing_model (att :: Context.Ref.get t.fixing_model) and sched_decision dec = incr dec_count; (* Debug.dprintf1 debug "[Scheduler] New possible decisions prio:%i" !dec_count; *) - Prio.insert t.choices dec + Prio.insert t.choices dec ~added_at:(-1) in Backtrackable.set_sched ~sched_daemon ~sched_decision t.solver_state; t @@ -516,7 +525,9 @@ let rec conflict_analysis t = (fun v -> Debug.dprintf3 debug_learn "[Learnt|%i] %a is useful" v.PrioLastEffort.Att.id Events.pp_daemon_key v.PrioLastEffort.Att.v; - PrioLastEffort.change t.lasteffort v 2.) + PrioLastEffort.change t.lasteffort v 2.; + if PrioLastEffort.get_prio t.lasteffort v = 16. then + Context.Clicket.push t.last_effort_learnt v.v) t.last_effort_made; Option.iter (fun v -> @@ -540,17 +551,19 @@ let rec conflict_analysis t = | Some prev -> ( pop_to t prev; Prio.reprio t.choices; - let has_learnt = PrioLastEffort.reprio_is_changed t.lasteffort in + PrioLastEffort.reprio t.lasteffort; match prev.kind with | Choices seq -> ( match Base.Sequence.next seq with | None -> rewind () | Some (choice, choices) -> - if has_learnt && false then ( - assert (Context.Ref.get t.solve_step = Propagate); - Context.Ref.set t.solve_step - (BacktrackChoice (choice, choices))) - else make_choice t choice choices) + Context.Clicket.iter t.last_effort_learnt ~f:(fun v -> + Debug.incr stats_lasteffort_propa; + let d = Backtrackable.get_delayed t.solver_state in + Backtrackable.run_daemon d v); + Context.Ref.set t.solve_step + (BacktrackChoice + (choice, choices, Context.Ref.get t.solve_step))) | External -> raise Contradiction) in rewind () @@ -614,47 +627,34 @@ let run_one_step_propagation ~nodec t = let d = Backtrackable.get_delayed t.solver_state in Backtrackable.run_daemon d att) (fun () -> true) + | None when nodec -> false | None -> ( - match PrioLastEffort.get_min_and_skew t.lasteffort with - | Some (att, skew) when skew > 16. -> - PrioLastEffort.pop t.lasteffort; - Debug.dprintf3 debug_learn "[Learnt|%i] %a is directly propagated" - att.PrioLastEffort.Att.id Events.pp_daemon_key - att.PrioLastEffort.Att.v; - Debug.incr stats_lasteffort_propa; - protect_against_contradiction t - (fun () -> - let d = Backtrackable.get_delayed t.solver_state in - Backtrackable.run_daemon d att.v) - (fun () -> true) - | _ when nodec -> false - | _ -> ( - match Prio.extract_min t.choices with - | Some chogen as o -> - t.last_decision_made <- o; - Debug.dprintf0 debug_queue "[Scheduler] Decision mode"; - try_run_dec t chogen.v; - true - | None -> ( - t.last_decision_made <- None; - Debug.dprintf1 debug_queue "[Scheduler] LastEffort: %i" - (PrioLastEffort.size t.lasteffort); - (* if Context.TimeWheel.current_time t.lasteffort < max_last_effort then *) - match PrioLastEffort.extract_min t.lasteffort with - | Some att as o -> - Debug.incr stats_lasteffort; - t.last_effort_made <- o; - protect_against_contradiction t - (fun () -> - let d = Backtrackable.get_delayed t.solver_state in - Backtrackable.run_daemon d att.v) - (fun () -> true) - | None -> - t.last_effort_made <- None; - false - (* else false *)))) - -let run_one_step_fix_model t = + match Prio.extract_min t.choices with + | Some chogen as o -> + t.last_decision_made <- o; + Debug.dprintf0 debug_queue "[Scheduler] Decision mode"; + try_run_dec t chogen.v; + true + | None -> ( + t.last_decision_made <- None; + Debug.dprintf1 debug_queue "[Scheduler] LastEffort: %i" + (PrioLastEffort.size t.lasteffort); + (* if Context.TimeWheel.current_time t.lasteffort < max_last_effort then *) + match PrioLastEffort.extract_min t.lasteffort with + | Some att as o -> + Debug.incr stats_lasteffort; + t.last_effort_made <- o; + protect_against_contradiction t + (fun () -> + let d = Backtrackable.get_delayed t.solver_state in + Backtrackable.run_daemon d att.v) + (fun () -> true) + | None -> + t.last_effort_made <- None; + false + (* else false *))) + +let run_one_step_fix_model ~nodec t = Debug.incr stats_fix_model; match Context.Ref.get t.fixing_model with | att :: l -> @@ -664,6 +664,7 @@ let run_one_step_fix_model t = let d = Backtrackable.get_delayed t.solver_state in Backtrackable.run_daemon d att) (fun () -> true) + | [] when nodec -> false | [] -> protect_against_contradiction t (fun () -> @@ -689,14 +690,20 @@ let run_one_step ~nodec t = Debug.dprintf0 debug "[Scheduler] FixModel"; Context.Ref.set t.solve_step FixModel; true) - | BacktrackChoice (choice, choices) -> ( - match run_one_step_propagation ~nodec:true t with + | BacktrackChoice (choice, choices, step) -> ( + let res = + match step with + | BacktrackChoice _ -> assert false + | Propagate -> run_one_step_propagation ~nodec:true t + | FixModel -> run_one_step_fix_model ~nodec:true t + in + match res with | true -> true | false -> - Context.Ref.set t.solve_step Propagate; + Context.Ref.set t.solve_step step; make_choice t choice choices; true) - | FixModel -> run_one_step_fix_model t + | FixModel -> run_one_step_fix_model ~nodec t let rec flush t = try Backtrackable.flush t.solver_state diff --git a/src_colibri2/stdlib/context.ml b/src_colibri2/stdlib/context.ml index 920f2face0b15a0226976d97cc3fd0c8cb28c503..5739853803e6301c201a04c28a56471e0b4c5947 100644 --- a/src_colibri2/stdlib/context.ml +++ b/src_colibri2/stdlib/context.ml @@ -556,3 +556,59 @@ module Memo(S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Memo with type key := let fold f t = S.H.fold f t.h end + +module type Clicket = sig + + type 'a t + + val create: creator -> 'a t + + val push: 'a t -> 'a -> unit + + val iter: f:('a -> unit) -> 'a t -> unit + + val todo: 'a t -> bool + + val pp: ?sep:unit Fmt.t -> 'a Fmt.t -> 'a t Fmt.t + +end + +module Clicket = struct + type 'a t = { + v : 'a Vector.vector; + h : int history; + mutable first_not_done : int; + } + + let restore t saved = t.first_not_done <- saved + let save t () = t.first_not_done + + let refresh t = + Expert.refresh + ~restore:(restore t) + t.h + + let save t = + Expert.save + ~restore:(restore t) + ~save:(save t) + t.h + + let clear t = + Vector.clear t.v; + t.first_not_done <- 0 + + let create creator = { v = Vector.create (); h = Expert.create creator; first_not_done = 0 } + let iter ~f t = refresh t; + for i=t.first_not_done to (Vector.length t.v) - 1 do + f (Vector.get t.v i) + done; + t.first_not_done <- Vector.length t.v; + if List.is_empty t.h.context.bps then + clear t + let todo t = t.first_not_done < Vector.length t.v + + let push t v = save t; Vector.push t.v v + + let pp ?sep pp fmt v = Vector.pp ?pp_sep:sep pp fmt v.v +end diff --git a/src_colibri2/stdlib/context.mli b/src_colibri2/stdlib/context.mli index ffb64fd06e2b1b8d5415ef1654bacffa12e90662..c6337a0a46252a21f72b1d2e7662dc4d4e32bf84 100644 --- a/src_colibri2/stdlib/context.mli +++ b/src_colibri2/stdlib/context.mli @@ -253,3 +253,25 @@ module type Memo = sig end module Memo (S:Colibri2_popop_lib.Popop_stdlib.Datatype) : Memo with type key := S.t + +(** Clicket *) +(** The added element are given back after each pop *) + +module type Clicket = sig + + type 'a t + + val create: creator -> 'a t + + val push: 'a t -> 'a -> unit + + val iter: f:('a -> unit) -> 'a t -> unit + (** iter on the one that have been added inside sub-branch *) + + val todo: 'a t -> bool + + val pp: ?sep:unit Fmt.t -> 'a Fmt.t -> 'a t Fmt.t + +end + +module Clicket : Clicket diff --git a/src_colibri2/tests/solve/models/function.smt2 b/src_colibri2/tests/solve/models/function.smt2 new file mode 100644 index 0000000000000000000000000000000000000000..3ce36e2acae9a0b5cad0fd034525c0c5d386adcf --- /dev/null +++ b/src_colibri2/tests/solve/models/function.smt2 @@ -0,0 +1,14 @@ +(set-logic ALL) +(set-info :status-colibri2 sat) + +(declare-fun f (Int) Int) + +(assert (< (f 1) (f 2))) + +(check-sat) +;(get-model) +(get-value ((f 1))) +(get-value ((f 2))) +(get-value ((f 3))) +(get-value ((f 4))) +;(get-value (f)) diff --git a/src_colibri2/tests/solve/models/function.smt2.oracle b/src_colibri2/tests/solve/models/function.smt2.oracle new file mode 100644 index 0000000000000000000000000000000000000000..ceb501abbbf79de11798f122f59e0730329b88d3 --- /dev/null +++ b/src_colibri2/tests/solve/models/function.smt2.oracle @@ -0,0 +1,5 @@ +sat +((f 1 0)) +((f 2 1)) +((f 3 0)) +((f 4 0)) diff --git a/src_colibri2/theories/FP/interval32.ml b/src_colibri2/theories/FP/interval32.ml index f0684baed16da75506f0cceff33b08199e8e1c3f..a23adc11371f513e416325fc5e3ea5c81ecb2d13 100644 --- a/src_colibri2/theories/FP/interval32.ml +++ b/src_colibri2/theories/FP/interval32.ml @@ -51,4 +51,4 @@ let is_singleton d = | Some x -> if Farith2.B32.B32.eq x (Farith2.B32.B32.of_q NE Q.zero) then None - else failwith "assert false" (* failSome (float32_to_B32 x) *) \ No newline at end of file + else None (** todo *) diff --git a/src_colibri2/theories/quantifier/trigger.ml b/src_colibri2/theories/quantifier/trigger.ml index bb49bbe7eb03519c45a56e83a74900f3475d4a4c..3f9a5cb7885c32bfad1d195716e44ba46011c729 100644 --- a/src_colibri2/theories/quantifier/trigger.ml +++ b/src_colibri2/theories/quantifier/trigger.ml @@ -329,21 +329,30 @@ module Delayed_instantiation = struct let name = "delayed_instantiation" end) - let delay = Events.LastEffort 1 + let delay = Events.LastEffortUncontextual 1 type runable = t * Ground.Subst.t [@@deriving show] let print_runable = pp_runable let run d (tri, subst) = - Debug.dprintf8 debug - "[Quant] %a delayed instantiation %a, pat %a, checks:%a" Ground.Subst.pp - subst Ground.ClosedQuantifier.pp tri.form - Fmt.(list ~sep:comma Pattern.pp) - tri.pats - Fmt.(list ~sep:comma Pattern.pp) - tri.checks; - instantiate_aux d tri subst + let instantiate d = + Debug.dprintf8 debug + "[Quant] %a delayed instantiation %a, pat %a, checks:%a" Ground.Subst.pp + subst Ground.ClosedQuantifier.pp tri.form + Fmt.(list ~sep:comma Pattern.pp) + tri.pats + Fmt.(list ~sep:comma Pattern.pp) + tri.checks; + instantiate_aux d tri subst + in + let n = Ground.ClosedQuantifier.node tri.form in + match Boolean.is d n with + | Some true -> instantiate d + | Some false -> () + | None -> + Daemon.attach_value d n Boolean.dom (fun d _ v -> + if Boolean.BoolValue.equal v Boolean.value_true then instantiate d) end let () = Events.register (module Delayed_instantiation)