type config = Config.config
type bound = Bound.bound
type statistic = Statistic.statistic
type literal = Term.literal
type clause = Term.clause
type subst = Subst.subst
type choice_point = State.choice_point
type state = State.state
type context_unifier_space = Context_unifier.context_unifier_space
type space_registry = Context_unifier_space.space_registry
type raw_context_unifier = Context_unifier.raw_context_unifier
type selected = Selection_types.selected
type problem_literals = Problem_literals.problem_literals
type context = Context.context
type context_element = Context.element
type guiding_step = Jumping.guiding_step
type guiding_path = Jumping.guiding_path
type lemmas_propositional = Lemma_propositional.lemmas_propositional
type selection = {
sel_config: config;
sel_bound: bound;
sel_statistic: statistic;
sel_state: state;
sel_context: context;
sel_space_registry: space_registry;
sel_problem_literals: problem_literals;
sel_clause_spaces: context_unifier_space array;
mutable sel_lemma_spaces: (context_unifier_space * bool) list;
sel_best_closing: raw_context_unifier option ref;
mutable sel_unit_asserts: (literal * raw_context_unifier) list;
mutable sel_assert: Selection_assert.candidates;
mutable sel_split: Selection_split.candidates;
mutable sel_no_splits_yet: bool;
sel_process_close: raw_context_unifier -> unit;
sel_process_assert: raw_context_unifier -> bool;
sel_process_split: raw_context_unifier -> unit;
sel_is_element_incomplete_assert: Context.element -> bool;
sel_is_element_incomplete_split: Context.element -> bool;
mutable sel_decay_counter: int ref;
mutable sel_guiding_path: guiding_path;
mutable sel_lemmas_propositional: lemmas_propositional;
}
exception SATISFIABLE
let process_close_candidate (state: state) (best_closing: raw_context_unifier option ref)
(candidate: raw_context_unifier) : unit =
let explanation =
State.get_explanation
state
(Context_unifier.get_context_literals candidate.Context_unifier.rcu_context_partners)
in
begin
match explanation with
| [] ->
raise (Context_unifier.CLOSE candidate)
| head :: [] when
State.choice_point_equal (State.root_choice_point state) head ->
raise (Context_unifier.CLOSE candidate)
| _ ->
()
end;
begin
match !best_closing with
| None ->
best_closing := Some candidate
| Some old ->
let old_explanation =
State.get_explanation
state
(Context_unifier.get_context_literals old.Context_unifier.rcu_context_partners)
in
let rec compare_explanations x y =
match x, y with
| [], [] ->
Context_unifier.compare_context_unifiers ~different:true candidate old
| [], _ ->
-1
| _, [] ->
1
| x0 :: t0, x1 :: t1 ->
if State.choice_point_equal x0 x1 then
compare_explanations t0 t1
else
State.compare_age x0 x1
in
if compare_explanations explanation old_explanation < 0 then
best_closing := Some candidate
end
let create_spaces
(space_registry: space_registry) (statistic: statistic) (problem_literals: problem_literals)
process_close_candidate process_assert_candidate process_split_candidate
is_element_incomplete_assert is_element_incomplete_split
(clauses: clause list) (is_lemma: bool)
: context_unifier_space list * (literal * raw_context_unifier) list =
List.fold_left
(fun (context_unifier_spaces, unit_asserts) clause ->
let new_context_unifier_space =
Context_unifier_space.create_space space_registry problem_literals
clause
process_close_candidate process_assert_candidate process_split_candidate
is_element_incomplete_assert is_element_incomplete_split
is_lemma
in
let new_unit_asserts =
match clause with
| unit_literal :: [] ->
let raw_context_unifier =
Context_unifier.create_context_unifier
new_context_unifier_space [| Context_unifier.assert_partner |] false
in
Statistic.inc_computed_assert_candidates statistic;
(unit_literal, raw_context_unifier) :: unit_asserts
| _ ->
unit_asserts
in
(new_context_unifier_space :: context_unifier_spaces),
new_unit_asserts
)
([], [])
clauses
let create (config: config) (bound: bound) (statistic: statistic) (state: state) (context: context)
(clauses: clause list) (lemmas: clause list) (initial_interpretation: literal list)
(guiding_path: guiding_path) : selection =
let problem_literals =
Problem_literals.create config bound statistic state context
in
let space_registry =
Context_unifier_space.create config bound
in
let selection_assert =
Selection_assert.create config bound statistic state context problem_literals
and selection_split =
Selection_split.create config bound statistic state context problem_literals space_registry
in
let best_closing =
ref None
in
let process_close_candidate (candidate: raw_context_unifier) : unit =
process_close_candidate state best_closing candidate
and process_assert_candidate (candidate: raw_context_unifier) : bool =
Selection_assert.add selection_assert candidate
and process_split_candidate (candidate: raw_context_unifier) : unit =
Selection_split.add selection_split candidate
and is_element_incomplete_assert (element: Context.element) : bool =
Selection_assert.is_element_incomplete selection_assert element
and is_element_incomplete_split (element: Context.element) : bool =
Selection_split.is_element_incomplete selection_split element
in
let clause_spaces, unit_asserts =
create_spaces space_registry statistic problem_literals
process_close_candidate process_assert_candidate process_split_candidate
is_element_incomplete_assert is_element_incomplete_split
clauses false
in
let lemmas_propositional =
Lemma_propositional.create config state context selection_assert process_close_candidate process_assert_candidate space_registry
in
let lemma_spaces, lemma_asserts =
match Config.lemma config with
| Flags.LM_Propositional ->
List.iter
(fun lemma ->
Lemma_propositional.add_lemma lemmas_propositional lemma true
)
lemmas;
[], []
| Flags.LM_None
| Flags.LM_Grounded
| Flags.LM_Lifted ->
let lemma_spaces, lemma_asserts =
create_spaces space_registry statistic problem_literals
process_close_candidate process_assert_candidate process_split_candidate
is_element_incomplete_assert is_element_incomplete_split
lemmas true
in
let lemma_spaces =
List.map (fun lemma -> (lemma, true)) lemma_spaces
in
lemma_spaces, lemma_asserts
in
let initial_interpretation' =
List.map
(fun literal ->
let new_context_unifier_space : context_unifier_space =
Context_unifier_space.create_space ~register:false
space_registry
problem_literals
[Term.init_literal]
process_close_candidate
process_assert_candidate
process_split_candidate
is_element_incomplete_assert
is_element_incomplete_split
false
in
let raw_context_unifier =
Context_unifier.create_context_unifier
new_context_unifier_space [| Context_unifier.assert_partner |] false
in
(literal, raw_context_unifier)
)
initial_interpretation
in
let sorted_unit_asserts =
List.sort
(fun (x, _) (y, _) ->
compare
(Term_attributes.weight_of_literal x)
(Term_attributes.weight_of_literal y)
)
(initial_interpretation' @ lemma_asserts @ unit_asserts)
in
let selection = {
sel_config = config;
sel_bound = bound;
sel_statistic = statistic;
sel_state = state;
sel_context = context;
sel_problem_literals = problem_literals;
sel_space_registry = space_registry;
sel_clause_spaces = Array.of_list clause_spaces;
sel_lemma_spaces = lemma_spaces;
sel_best_closing = best_closing;
sel_unit_asserts = sorted_unit_asserts;
sel_assert = selection_assert;
sel_split = selection_split;
sel_no_splits_yet = true;
sel_process_close = process_close_candidate;
sel_process_assert = process_assert_candidate;
sel_process_split = process_split_candidate;
sel_is_element_incomplete_assert = is_element_incomplete_assert;
sel_is_element_incomplete_split = is_element_incomplete_split;
sel_decay_counter = ref 0;
sel_guiding_path = guiding_path;
sel_lemmas_propositional = lemmas_propositional;
}
in
selection
let raise_close (selection: selection) : unit =
match !(selection.sel_best_closing) with
| Some closing ->
selection.sel_best_closing := None;
raise (Context_unifier.CLOSE closing)
| None ->
()
let add (selection: selection) (context_element: Context.element) : unit =
begin
match Config.lemma selection.sel_config with
| Flags.LM_Propositional ->
Lemma_propositional.extend_context selection.sel_lemmas_propositional context_element;
| Flags.LM_None
| Flags.LM_Grounded
| Flags.LM_Lifted ->
()
end;
if selection.sel_no_splits_yet then
Problem_literals.add selection.sel_problem_literals context_element Context_unifier.CloseAssert
else
Problem_literals.add selection.sel_problem_literals context_element Context_unifier.All;
raise_close selection
let filter_lemma (selection: selection) (lemma: clause) : bool =
let rec clauses_equal x y =
match x, y with
| [], [] ->
true
| hx :: tx, hy :: ty when
Term.literal_equal hx hy
||
Term.are_literals_variants hx hy
->
clauses_equal tx ty
| _ ->
false
in
let lemma_length =
List.length lemma
in
let are_spaces_equal old =
let x =
lemma_length = Array.length old.Context_unifier.cus_input_partners
&&
(
clauses_equal
old.Context_unifier.cus_clause
lemma
)
in
Context_unifier.increase_lemma_learned old;
x
in
Tools.array_exists
are_spaces_equal
selection.sel_clause_spaces
||
List.exists
(fun (x, _) ->
are_spaces_equal x
)
selection.sel_lemma_spaces
let get_min_lemma_utility (selection: selection) : int =
let min =
List.fold_left
(fun acc (space, _) ->
match acc with
| Some old ->
if old <= !(space.Context_unifier.cus_utility) then
acc
else
Some !(space.Context_unifier.cus_utility)
| _ ->
Some !(space.Context_unifier.cus_utility)
)
None
selection.sel_lemma_spaces
in
match min with
| None ->
0
| Some value ->
value
let prune_lemmas (selection: selection) : unit =
let max_lemmas = Config.lemma_max selection.sel_config
and min_lemmas = Config.lemma_min selection.sel_config
in
if max_lemmas > 0 && List.length selection.sel_lemma_spaces >= max_lemmas then begin
while List.length selection.sel_lemma_spaces > min_lemmas do
let min =
get_min_lemma_utility selection
in
selection.sel_lemma_spaces <-
List.find_all
(fun (space, _) ->
begin
let utility = !(space.Context_unifier.cus_utility)
in
let keep = utility > min
in
if not keep then begin
Problem_literals.unregister_space selection.sel_problem_literals space
end;
keep
end;
)
selection.sel_lemma_spaces
done;
end
let prune_lemmas (selection: selection) : unit =
let max_lemmas = Config.lemma_max selection.sel_config
and min_lemmas = Config.lemma_min selection.sel_config
in
if max_lemmas > 0 && List.length selection.sel_lemma_spaces >= max_lemmas then begin
let rec find_min min =
let pruned =
List.fold_left
(fun pruned (space, _) ->
if !(space.Context_unifier.cus_utility) > min then
pruned
else
pruned + 1
)
0
selection.sel_lemma_spaces
in
if pruned >= (max_lemmas - min_lemmas) then
pruned
else
find_min (min + 1)
in
let min =
find_min (get_min_lemma_utility selection)
in
let rec prune pruned acc spaces =
match spaces with
| [] ->
acc
| ((space, _) as head) :: tail ->
if
(pruned >= (max_lemmas - min_lemmas))
||
(!(space.Context_unifier.cus_utility) > min)
then begin
prune pruned (head :: acc) tail
end
else begin
prune (pruned + 1) acc tail
end
in
let keep =
prune 0 [] selection.sel_lemma_spaces
in
selection.sel_lemma_spaces <- keep;
Array.iter
(fun space ->
space.Context_unifier.cus_utility :=
!(space.Context_unifier.cus_utility) / Const.decay_clause_utility_ratio
)
selection.sel_clause_spaces;
List.iter
(fun (space, _) ->
space.Context_unifier.cus_utility :=
!(space.Context_unifier.cus_utility) / Const.decay_clause_utility_ratio
)
selection.sel_lemma_spaces
end
let add_lemma (selection: selection) (lemma: clause) : unit =
if filter_lemma selection lemma then begin
if Config.print_lemmas selection.sel_config then begin
print_endline ("REDUNDANT LEMMA: " ^ Term.clause_to_string lemma);
end;
end
else begin
match Config.lemma selection.sel_config with
| Flags.LM_Propositional ->
if Config.print_lemmas selection.sel_config then begin
print_endline ("LEMMA: " ^ Term.clause_to_string lemma);
end;
let global_lemma =
not selection.sel_bound#is_derivation_incomplete
in
Lemma_propositional.add_lemma selection.sel_lemmas_propositional lemma global_lemma
| Flags.LM_None
| Flags.LM_Grounded
| Flags.LM_Lifted ->
if Config.print_lemmas selection.sel_config then begin
print_endline ("LEMMA: " ^ Term.clause_to_string lemma);
end;
prune_lemmas selection;
let new_context_unifier_space =
Context_unifier_space.create_space
selection.sel_space_registry
selection.sel_problem_literals
lemma
selection.sel_process_close
selection.sel_process_assert
selection.sel_process_split
selection.sel_is_element_incomplete_assert
selection.sel_is_element_incomplete_split
true
in
new_context_unifier_space.Context_unifier.cus_utility := (get_min_lemma_utility selection);
let global_lemma =
not selection.sel_bound#is_derivation_incomplete
in
selection.sel_lemma_spaces <- (new_context_unifier_space, global_lemma) :: selection.sel_lemma_spaces;
begin
match lemma with
| unit_literal :: [] ->
begin
match Context.check_contradictory selection.sel_context unit_literal with
| Some element ->
let context_partner =
Context_unifier.create_context_partner
element
None
true
in
let raw_context_unifier =
Context_unifier.create_context_unifier
new_context_unifier_space [| context_partner |] false
in
selection.sel_best_closing := Some raw_context_unifier;
raise_close selection
| None ->
let raw_context_unifier =
Context_unifier.create_context_unifier
new_context_unifier_space [| Context_unifier.assert_partner |] false
in
Statistic.inc_computed_assert_candidates selection.sel_statistic;
selection.sel_unit_asserts <- (unit_literal, raw_context_unifier) :: selection.sel_unit_asserts
end
| _ ->
()
end;
end
let check_replayed_decision (selected: selected) (guiding_step : guiding_step option) : unit =
if not Const.debug then
()
else if
selected.Selection_types.candidate_type = State.Propagation
then
()
else begin
match guiding_step with
| None ->
()
| Some (Jumping.Split saved_literal) ->
if
selected.Selection_types.candidate_type = State.SplitLeft
&&
Term.are_literals_skolem_variants selected.Selection_types.literal saved_literal
then
()
else begin
print_endline ("SAVED: " ^ Term.literal_to_string saved_literal);
print_endline ("FOUND: " ^ Term.literal_to_string selected.Selection_types.literal);
failwith "Selection.check_replayed_decision 1"
end
| Some (Jumping.Left saved_literal)
| Some (Jumping.Right saved_literal) ->
if
selected.Selection_types.candidate_type = State.SplitRight
&&
Term.are_literals_skolem_variants selected.Selection_types.literal saved_literal
then
()
else begin
print_endline ("SAVED: " ^ Term.literal_to_string saved_literal);
print_endline ("FOUND: " ^ Term.literal_to_string selected.Selection_types.literal);
failwith "Selection.check_replayed_decision 2"
end
end
let rec select_unit_assert
(selection: selection) (candidates: (literal * raw_context_unifier) list)
: selected option =
match candidates with
| [] ->
selection.sel_unit_asserts <- [];
None
| (candidate, raw_context_unifier) :: tail ->
begin
match Context.check_subsumed selection.sel_context candidate with
| Some _ ->
select_unit_assert selection tail
| None ->
selection.sel_unit_asserts <- tail;
State.apply_propagation
selection.sel_state
candidate
Subst.empty
raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_clause
raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_vars
0
(Context_unifier.create_space_utility_inc raw_context_unifier.Context_unifier.rcu_space)
[| |] ;
Some {
Selection_types.candidate_type = State.Propagation;
Selection_types.literal = candidate;
Selection_types.raw_context_unifier = raw_context_unifier;
}
end
let select (selection: selection) : selected =
if Selection_assert.has_closing_candidate selection.sel_assert then begin
match Selection_assert.select selection.sel_assert with
| Some selected ->
selected
| None ->
failwith "Selection.select"
end
else
begin
match select_unit_assert selection selection.sel_unit_asserts with
| Some selected ->
selected
| None ->
begin
match Selection_assert.select selection.sel_assert with
| Some selected ->
selected
| None ->
begin
match Selection_split.select_right_split selection.sel_split with
| Some selected ->
selected
| None ->
if selection.sel_no_splits_yet then begin
selection.sel_no_splits_yet <- false;
Problem_literals.compute_deferred
selection.sel_problem_literals Context_unifier.Split;
end;
begin
let replay =
match selection.sel_guiding_path with
| [] ->
None
| head :: tail ->
selection.sel_guiding_path <- tail;
Some head
in
match Selection_split.select selection.sel_split replay with
| Some selected ->
check_replayed_decision selected replay;
selected
| None ->
if
Config.is_horn selection.sel_config
||
selection.sel_no_splits_yet
then
Selection_assert.check_exceeding selection.sel_assert
else
Selection_split.check_exceeding selection.sel_split;
raise SATISFIABLE
end
end
end
end
let get_lemmas (selection: selection) : clause list =
begin
match Config.lemma selection.sel_config with
| Flags.LM_Propositional ->
Lemma_propositional.get_lemmas selection.sel_lemmas_propositional;
| Flags.LM_None
| Flags.LM_Grounded
| Flags.LM_Lifted ->
List.rev (
List.fold_left
(fun acc (space, global) ->
if global then
space.Context_unifier.cus_clause :: acc
else
acc
)
[]
selection.sel_lemma_spaces
)
end
let in_replay (selection: selection) : bool =
selection.sel_guiding_path != []
let decay_clause_utility (selection: selection) : unit =
selection.sel_decay_counter :=
(!(selection.sel_decay_counter) + 1) mod Const.decay_clause_utility_interval;
if !(selection.sel_decay_counter) = 0 then begin
Array.iter
(fun space ->
space.Context_unifier.cus_utility :=
!(space.Context_unifier.cus_utility) / Const.decay_clause_utility_ratio
)
selection.sel_clause_spaces;
List.iter
(fun (space, _) ->
space.Context_unifier.cus_utility :=
!(space.Context_unifier.cus_utility) / Const.decay_clause_utility_ratio
)
selection.sel_lemma_spaces
end
let backtrack (selection: selection) (retracted: choice_point) (explanation: literal list) : unit =
selection.sel_best_closing := None;
Problem_literals.backtrack selection.sel_problem_literals;
Array.iter
(fun space ->
if Problem_literals.is_space_subsumed selection.sel_problem_literals space then
()
else
Context_unifier_space.backtrack space
)
selection.sel_clause_spaces;
List.iter
(fun (space, _) ->
if Problem_literals.is_space_subsumed selection.sel_problem_literals space then
()
else
Context_unifier_space.backtrack space
)
selection.sel_lemma_spaces;
Selection_assert.backtrack selection.sel_assert;
Selection_split.backtrack selection.sel_split retracted explanation;
begin
match Config.lemma selection.sel_config with
| Flags.LM_Propositional ->
Lemma_propositional.backtrack selection.sel_lemmas_propositional;
| Flags.LM_None
| Flags.LM_Grounded
| Flags.LM_Lifted ->
()
end