type config = Config.config
type bound = Bound.bound
type statistic = Statistic.statistic
type choice_point = State.choice_point
type literal = Term.literal
type pureness = Term_attributes.pureness
type subst = Subst.subst
type state = State.state
type context_unifier_space = Context_unifier.context_unifier_space
type raw_context_unifier = Context_unifier.raw_context_unifier
type problem_literals = Problem_literals.problem_literals
type selected = Selection_types.selected
type context = Context.context
type space_registry = Context_unifier_space.space_registry
type candidate_literal = {
cl_literal: literal;
cl_context_element: Context.element;
cl_is_remainder_literal: bool;
cl_index: int;
}
type quality = {
cq_remainder_size: int;
cq_pureness: pureness;
cq_term_quality: int;
cq_generation: int;
}
type candidate = {
ca_raw_context_unifier: raw_context_unifier;
ca_quality: quality;
}
type right_split = {
rs_candidate: candidate;
rs_literal: literal;
rs_index: int;
rs_explanation: literal array;
}
let compare_candidates (first: candidate) (second: candidate) : int =
let pureness_universal =
Term_attributes.cmp_pureness first.ca_quality.cq_pureness second.ca_quality.cq_pureness
in
if pureness_universal <> 0 then
pureness_universal
else begin
if first.ca_quality.cq_remainder_size < second.ca_quality.cq_remainder_size then
-1
else if first.ca_quality.cq_remainder_size > second.ca_quality.cq_remainder_size then
1
else begin
if first.ca_quality.cq_term_quality < second.ca_quality.cq_term_quality then
-1
else if first.ca_quality.cq_term_quality > second.ca_quality.cq_term_quality then
1
else begin
let pureness_generalization =
Term_attributes.cmp_universality first.ca_quality.cq_pureness second.ca_quality.cq_pureness
in
if pureness_generalization <> 0 then
pureness_generalization
else begin
if first.ca_quality.cq_generation < second.ca_quality.cq_generation then
-1
else if first.ca_quality.cq_generation > second.ca_quality.cq_generation then
1
else
Context_unifier.compare_context_unifiers ~different:Const.stable_derivation
first.ca_raw_context_unifier second.ca_raw_context_unifier
end
end
end
end
let candidate_to_string title candidate =
let context_element : Context.element =
Context_unifier.creating_context_element candidate.ca_raw_context_unifier
in
(title ^ Term.literal_to_string context_element.Context.el_literal)
^ "\n"
^ (Context_unifier.raw_context_unifier_to_string candidate.ca_raw_context_unifier)
^ "\n"
module Valid =
Heap.MinMaxHeap (
struct
type t = candidate
let compare = compare_candidates
let to_string = candidate_to_string ""
end
)
type candidates = {
cd_config: config;
cd_bound: bound;
cd_statistic: statistic;
cd_state: state;
cd_context: context;
cd_problem_literals: problem_literals;
cd_space_registry: space_registry;
cd_unprocessed: raw_context_unifier array;
mutable cd_unprocessed_size: int;
cd_valid: Valid.t;
mutable cd_invalid: (raw_context_unifier * choice_point) list;
mutable cd_added: (candidate * literal * int * choice_point) list;
mutable cd_right_splits: (candidate * literal * int * literal array) list;
mutable cd_applied_right_splits: ((candidate * literal * int * literal array) * choice_point) list;
cd_exceeding_elements: (int, Context.element) Hashtbl.t;
mutable cd_check_exceeding: bool;
}
exception EXCEEDING_EXHAUSTED
let null_quality = {
cq_remainder_size = -1;
cq_pureness = Term_attributes.get_pureness Term.null_literal.Term.atom;
cq_term_quality = -1;
cq_generation = -1;
}
let null_candidate = {
ca_raw_context_unifier = Context_unifier.null_context_unifier;
ca_quality = null_quality;
}
let create (config: config) (bound: bound) (statistic: statistic) (state: state)
(context: context) (problem_literals: problem_literals) (space_registry: space_registry) : candidates =
let unprocessed =
if Config.is_horn config then
[| |]
else
Array.make (max 1 Const.max_unprocessed_split_candidates) Context_unifier.null_context_unifier
in
{
cd_config = config;
cd_bound = bound;
cd_statistic = statistic;
cd_state = state;
cd_context = context;
cd_problem_literals = problem_literals;
cd_space_registry = space_registry;
cd_unprocessed = unprocessed;
cd_unprocessed_size = 0;
cd_valid = Valid.create null_candidate;
cd_invalid = [];
cd_added = [];
cd_right_splits = [];
cd_applied_right_splits = [];
cd_exceeding_elements = Hashtbl.create 64;
cd_check_exceeding = false;
}
let size (candidates: candidates) : int =
Valid.size candidates.cd_valid
let is_marked_exceeding (candidates: candidates) (context_element: Context.element) : bool =
try
ignore (Hashtbl.find candidates.cd_exceeding_elements context_element.Context.el_id: Context.element);
true
with
| Not_found ->
false
let is_element_incomplete (candidates: candidates) (element: Context.element) : bool =
Config.restart candidates.cd_config = Flags.RS_Delayed
&&
not candidates.cd_check_exceeding
&&
is_marked_exceeding candidates element
let mark_exceeding (candidates: candidates) (context_element: Context.element) : unit =
Hashtbl.add candidates.cd_exceeding_elements context_element.Context.el_id context_element
let get_term_quality (candidates: candidates) (literal: literal) : int =
if Config.iterative_deepening candidates.cd_config = Flags.IT_TermDepth then
Term_attributes.weight_of_literal literal
else
Term_attributes.depth_of_literal literal
let get_remainder_size (candidate_literals: candidate_literal list) : int =
List.fold_left
(fun acc remainder_literal ->
if remainder_literal.cl_is_remainder_literal then
acc + 1
else
acc
)
0
candidate_literals
exception CONFLICT of Context.element
let build_candidate_literals ?(insert_db: bool = false) ~(check: bool) ?(check_true: bool = false)
(config: config) (context: context) (raw_context_unifier: raw_context_unifier)
: candidate_literal list =
let subst =
Context_unifier.recompute_unifier ~recompute:false raw_context_unifier
in
let remainder_states =
Context_unifier.compute_remainder_states raw_context_unifier subst
in
let admissible =
Admissible.make_admissible config raw_context_unifier subst remainder_states
in
if Const.debug then begin
let remainder_choice_points_admissible =
Context_unifier.compute_remainder_states raw_context_unifier subst
in
if not (remainder_states = remainder_choice_points_admissible) then begin
failwith "Selection_split.remainder_choice_points";
end;
end;
let input_partners =
raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_input_partners
in
let candidate_literals =
Array.make
(Array.length input_partners)
{
cl_context_element = Context.null_element;
cl_literal = Term.null_literal;
cl_is_remainder_literal = false;
cl_index = -1;
}
in
Array.iter
(fun input_partner ->
let index =
input_partner.Context_unifier.ip_index
in
let context_partner =
raw_context_unifier.Context_unifier.rcu_context_partners.(index)
in
let context_element =
context_partner.Context_unifier.cp_element;
in
let split_literal =
Subst.apply_to_literal ~insert_db:insert_db
admissible
input_partner.Context_unifier.ip_literal
Subst.input_literal_offset
in
if check then begin
if remainder_states.(index) then begin
begin
match Context.check_subsumed context split_literal with
| None -> ()
| Some conflict ->
raise (CONFLICT conflict)
end;
begin
match Context.check_contradictory context split_literal with
| None -> ()
| Some conflict ->
raise (CONFLICT conflict)
end;
end;
if remainder_states.(index) && Config.productivity config then begin
match
Context.check_productive context context_element.Context.el_literal split_literal
with
| None -> ()
| Some conflict ->
raise (CONFLICT conflict)
end;
if remainder_states.(index) && check_true && Context.is_true context split_literal then begin
raise (CONFLICT (Context.null_element))
end;
end;
let candidate_literal = {
cl_context_element = context_element;
cl_literal = split_literal;
cl_is_remainder_literal = remainder_states.(index);
cl_index = index;
}
in
candidate_literals.(index) <- candidate_literal
)
input_partners;
Array.to_list candidate_literals
let remainder_literals_to_string_ (candidate_literals: candidate_literal list) : string =
let candidate_literals_repr =
List.fold_left
(fun acc candidate_literal ->
if candidate_literal.cl_is_remainder_literal then
Term.literal_to_string candidate_literal.cl_literal :: acc
else
"___" :: acc
)
[]
candidate_literals
in
"Remain.: " ^ "[" ^ String.concat ", " (List.rev candidate_literals_repr) ^ "]" ^ "\n"
let find_best_candidate_literal (candidates: candidates) (candidate_literals: candidate_literal list) :
(candidate_literal * pureness * int * Bound.complexity) =
let best =
List.fold_left
(fun acc candidate_literal ->
if not candidate_literal.cl_is_remainder_literal then begin
acc
end
else begin
let pureness = Term_attributes.get_pureness candidate_literal.cl_literal.Term.atom
and term_quality = get_term_quality candidates candidate_literal.cl_literal
and complexity = candidates.cd_bound#get_complexity candidate_literal.cl_literal
in
let cmp =
match acc with
| None ->
1
| Some (_best_candidate_literal, best_pureness, best_term_quality, best_complexity) ->
if
candidates.cd_bound#exceeds best_complexity
&&
candidates.cd_bound#exceeds complexity
then
0
else
let cmp_complexity =
if candidates.cd_bound#exceeds complexity then
-1
else if candidates.cd_bound#exceeds best_complexity then
1
else
0
in
if cmp_complexity <> 0 then
cmp_complexity
else
let cmp_pureness =
Term_attributes.cmp_pureness best_pureness pureness
in
if cmp_pureness <> 0 then
cmp_pureness
else
let cmp_term_quality =
compare best_term_quality term_quality
in
if cmp_term_quality <> 0 then
cmp_term_quality
else
Term_attributes.cmp_universality best_pureness pureness
in
if cmp <= 0 then
acc
else
Some (candidate_literal, pureness, term_quality, complexity)
end
)
None
candidate_literals
in
match best with
| None ->
print_endline (remainder_literals_to_string_ candidate_literals);
failwith "Selection_split.find_best_candidate_literal"
| Some best ->
best
let remainder_literals_to_string (config: config) (context: context)
(raw_context_unifier: raw_context_unifier) : string =
let remainder_literals =
build_candidate_literals ~check:false config context raw_context_unifier
in
remainder_literals_to_string_ remainder_literals
let remainder_to_string_ (candidates: candidates) (title: string)
(remainder: candidate) (best_remainder_literal: literal) (remainder_literals: candidate_literal list) : string =
State.active_choice_point_to_string candidates.cd_state
^ title ^ ": " ^ Term.literal_to_string best_remainder_literal ^ "\n"
^
if Config.print_derivation_context_unifier candidates.cd_config then
Context_unifier.raw_context_unifier_to_string remainder.ca_raw_context_unifier
^ remainder_literals_to_string_ remainder_literals
else
""
let remainder_to_string (candidates: candidates) (title: string) (remainder: candidate) : string =
let remainder_literals =
build_candidate_literals ~check:false
candidates.cd_config candidates.cd_context remainder.ca_raw_context_unifier
in
let (best_candidate_literal, _, _, _) =
find_best_candidate_literal candidates remainder_literals
in
remainder_to_string_ candidates title remainder best_candidate_literal.cl_literal remainder_literals
let add_valid (candidates: candidates) (candidate: candidate) : unit =
try
Valid.add candidates.cd_valid candidate
with
| Heap.OVERFLOW ->
raise (Const.NO_SOLUTION "Selection_split.add_valid: candidate set overflow")
let build_candidate' (raw_context_unifier: raw_context_unifier)
(remainder_size: int) (pureness: pureness) (term_quality: int)
: candidate =
let quality = {
cq_remainder_size = remainder_size;
cq_pureness = pureness;
cq_term_quality = term_quality;
cq_generation = Context_unifier.generation_of_candidate raw_context_unifier.Context_unifier.rcu_context_partners;
}
in
{
ca_raw_context_unifier = raw_context_unifier;
ca_quality = quality;
}
let build_candidate (candidates: candidates) (raw_context_unifier: raw_context_unifier) : unit =
try
let candidate_literals =
build_candidate_literals ~insert_db:false ~check:true
candidates.cd_config candidates.cd_context raw_context_unifier
in
let best_candidate_literal, pureness, term_quality, complexity =
find_best_candidate_literal candidates candidate_literals
in
let split_literal =
best_candidate_literal.cl_literal;
in
let remainder_size =
get_remainder_size candidate_literals
in
if candidates.cd_check_exceeding then begin
ignore (
candidates.cd_bound#register
complexity
(Context_unifier.get_creation_choice_point raw_context_unifier.Context_unifier.rcu_context_partners)
: bool);
if candidates.cd_bound#has_min_exceeding then
raise EXCEEDING_EXHAUSTED;
end
else if candidates.cd_bound#exceeds complexity then begin
match Config.restart candidates.cd_config with
| Flags.RS_Eager
| Flags.RS_Lazy ->
failwith "Selection_split.build_candidate: exceeding candidate without delayed restart."
| Flags.RS_Delayed ->
let context_element =
Context_unifier.creating_context_element raw_context_unifier
in
if
Context.element_equal Context.plus_v_element context_element
||
Context.element_equal Context.minus_v_element context_element
then begin
let candidate =
build_candidate' raw_context_unifier remainder_size pureness term_quality
in
if Config.print_split_candidates candidates.cd_config then begin
print_string (remainder_to_string_
candidates
"New Split Candidate"
candidate
split_literal
candidate_literals);
end;
add_valid candidates candidate;
end
else if is_marked_exceeding candidates context_element then
()
else
mark_exceeding candidates context_element;
end
else begin
let candidate =
build_candidate' raw_context_unifier remainder_size pureness term_quality
in
if Config.print_split_candidates candidates.cd_config then begin
print_string (remainder_to_string_
candidates
"New Split Candidate"
candidate
split_literal
candidate_literals);
end;
add_valid candidates candidate;
end
with
| CONFLICT conflicting_element ->
if candidates.cd_check_exceeding then
()
else if
Context_unifier.is_permanently_blocking
conflicting_element
raw_context_unifier.Context_unifier.rcu_context_partners
then
()
else if
Config.restart candidates.cd_config = Flags.RS_Delayed
&&
raw_context_unifier.Context_unifier.rcu_exceeding_complexity
then begin
let context_element =
Context_unifier.creating_context_element raw_context_unifier
in
if is_marked_exceeding candidates context_element then
()
else
candidates.cd_invalid <-
(raw_context_unifier, conflicting_element.Context.el_choice_point) :: candidates.cd_invalid
end
else
candidates.cd_invalid <-
(raw_context_unifier, conflicting_element.Context.el_choice_point) :: candidates.cd_invalid
let clear_unprocessed (candidates: candidates) : unit =
for index = 0 to candidates.cd_unprocessed_size - 1 do
candidates.cd_unprocessed.(index) <- Context_unifier.null_context_unifier;
done;
candidates.cd_unprocessed_size <- 0
let build_unprocessed ~(force: bool) (candidates: candidates) : unit =
if
not force
&&
candidates.cd_unprocessed_size < Array.length candidates.cd_unprocessed - 1
then begin
()
end
else begin
for index = 0 to candidates.cd_unprocessed_size - 1 do
if not (Context_unifier.is_raw_context_unifier_invalid candidates.cd_unprocessed.(index)) then begin
build_candidate candidates candidates.cd_unprocessed.(index);
end;
candidates.cd_unprocessed.(index) <- Context_unifier.null_context_unifier;
done;
candidates.cd_unprocessed_size <- 0
end
let add_unprocessed (candidates: candidates) (candidate: raw_context_unifier) : unit =
candidates.cd_unprocessed.(candidates.cd_unprocessed_size) <- candidate;
candidates.cd_unprocessed_size <- candidates.cd_unprocessed_size + 1;
build_unprocessed ~force:false candidates
let add (candidates: candidates) (candidate: raw_context_unifier) : unit =
Statistic.inc_computed_split_candidates candidates.cd_statistic;
add_unprocessed candidates candidate
let rec get_best_candidate (candidates: candidates) : (candidate * literal * int) option =
if Valid.is_empty candidates.cd_valid then
None
else begin
let candidate =
Valid.remove_min candidates.cd_valid
in
if Context_unifier.is_raw_context_unifier_invalid candidate.ca_raw_context_unifier then begin
get_best_candidate candidates;
end
else begin
try
let candidate_literals =
build_candidate_literals ~check:true
candidates.cd_config candidates.cd_context candidate.ca_raw_context_unifier
in
let (best_candidate_literal, _, _, _) =
find_best_candidate_literal candidates candidate_literals
in
Some (candidate, best_candidate_literal.cl_literal, best_candidate_literal.cl_index)
with
| CONFLICT conflicting_element ->
begin
if
Context_unifier.is_permanently_blocking
conflicting_element
candidate.ca_raw_context_unifier.Context_unifier.rcu_context_partners
then
()
else
candidates.cd_invalid <-
(candidate.ca_raw_context_unifier, conflicting_element.Context.el_choice_point) :: candidates.cd_invalid
end;
get_best_candidate candidates;
end
end
let check_replay_literal (candidate: candidate) (saved_literal: literal) (split_literal: literal) : unit =
if
Const.debug
&&
not (Term.are_literals_skolem_variants saved_literal split_literal)
then begin
print_endline ("SAVED: " ^ Term.literal_to_string saved_literal);
print_endline ("FOUND: " ^ Term.literal_to_string split_literal);
print_endline (Context_unifier.raw_context_unifier_to_string candidate.ca_raw_context_unifier);
failwith "Selection_split.check_replay_literal";
end
let split (candidates: candidates)
(candidate: candidate) (split_literal: literal) (index: int)
(replay: Jumping.guiding_step option) : selected =
let split_literal =
Term.insert_literal split_literal
in
let context_unifier =
Context_unifier.recompute_full_unifier ~recompute:false candidate.ca_raw_context_unifier
in
if candidate.ca_quality.cq_remainder_size = 1 then begin
let context_literals =
Context_unifier.get_context_literals
candidate.ca_raw_context_unifier.Context_unifier.rcu_context_partners
in
State.apply_propagation
candidates.cd_state
split_literal
context_unifier
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_clause
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_vars
index
(Context_unifier.create_space_utility_inc candidate.ca_raw_context_unifier.Context_unifier.rcu_space)
context_literals;
candidates.cd_invalid <-
(candidate.ca_raw_context_unifier, State.active_choice_point candidates.cd_state) :: candidates.cd_invalid;
{
Selection_types.candidate_type = State.Propagation;
Selection_types.literal = split_literal;
Selection_types.raw_context_unifier = candidate.ca_raw_context_unifier;
}
end
else begin
match replay with
| None ->
let split_choice_point: choice_point =
State.apply_split_left
candidates.cd_state
split_literal
context_unifier
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_clause
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_vars
index
(Context_unifier.create_space_utility_inc candidate.ca_raw_context_unifier.Context_unifier.rcu_space);
in
candidates.cd_added <-
(candidate, split_literal, index, split_choice_point) :: candidates.cd_added;
{
Selection_types.candidate_type = State.SplitLeft;
Selection_types.literal = split_literal;
Selection_types.raw_context_unifier = candidate.ca_raw_context_unifier;
}
| Some (Jumping.Split saved_literal) ->
check_replay_literal candidate saved_literal split_literal;
let split_choice_point: choice_point =
State.apply_split_left
candidates.cd_state
split_literal
context_unifier
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_clause
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_vars
index
(Context_unifier.create_space_utility_inc candidate.ca_raw_context_unifier.Context_unifier.rcu_space);
in
candidates.cd_added <-
(candidate, split_literal, index, split_choice_point) :: candidates.cd_added;
{
Selection_types.candidate_type = State.SplitLeft;
Selection_types.literal = split_literal;
Selection_types.raw_context_unifier = candidate.ca_raw_context_unifier;
}
| Some (Jumping.Left saved_literal) ->
check_replay_literal candidate saved_literal split_literal;
State.apply_split_right
candidates.cd_state
split_literal
context_unifier
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_clause
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_vars
index
(Context_unifier.create_space_utility_inc candidate.ca_raw_context_unifier.Context_unifier.rcu_space)
[| |];
candidates.cd_invalid <-
(candidate.ca_raw_context_unifier, State.active_choice_point candidates.cd_state) :: candidates.cd_invalid;
{
Selection_types.candidate_type = State.SplitRight;
Selection_types.literal = split_literal;
Selection_types.raw_context_unifier = candidate.ca_raw_context_unifier;
}
| Some (Jumping.Right saved_literal) ->
let right_split_literal =
Term.request_negated_literal (Term.request_skolemized_literal split_literal)
in
check_replay_literal candidate saved_literal right_split_literal;
State.apply_split_right
candidates.cd_state
right_split_literal
context_unifier
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_clause
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_vars
index
(Context_unifier.create_space_utility_inc candidate.ca_raw_context_unifier.Context_unifier.rcu_space)
[| |];
candidates.cd_invalid <-
(candidate.ca_raw_context_unifier, State.active_choice_point candidates.cd_state) :: candidates.cd_invalid;
{
Selection_types.candidate_type = State.SplitRight;
Selection_types.literal = right_split_literal;
Selection_types.raw_context_unifier = candidate.ca_raw_context_unifier;
}
end
let check_right_split_consistent (candidates: candidates) (split_literal: literal) : unit =
if Const.debug then begin
let contradictory_element =
Context.check_contradictory candidates.cd_context split_literal
in
match contradictory_element with
| Some _ ->
failwith "Selection_split.check_right_split_consistent"
| None ->
()
end
let rec select_right_split (candidates: candidates) : selected option =
match candidates.cd_right_splits with
| [] ->
None
| ((candidate, split_literal, index, context_literals) as right_split) :: tail ->
candidates.cd_right_splits <- tail;
if
Tools.array_exists
(fun literal -> Context.element_for_literal candidates.cd_context literal = None)
context_literals
then begin
select_right_split candidates
end
else begin
match Context.check_contradictory candidates.cd_context split_literal with
| Some _ ->
select_right_split candidates
| None ->
begin
if Array.length context_literals = 0 then
()
else
candidates.cd_applied_right_splits <-
(right_split, State.active_choice_point candidates.cd_state) :: candidates.cd_applied_right_splits;
end;
let right_split =
Term.request_negated_literal (Term.request_skolemized_literal split_literal)
in
match Context.check_contradictory candidates.cd_context right_split with
| Some element ->
let input_partner =
Context_unifier.create_input_partner
0
right_split
[]
in
let universal =
Term.request_universal_literal right_split
in
let vars =
List.map
(fun var ->
Subst.make_var var Subst.input_literal_offset
)
(Term.vars_of_literal universal)
in
let space =
Context_unifier.create_space
(Context_unifier_space.get_id candidates.cd_space_registry)
[universal]
vars
vars
vars
[| input_partner |]
[| |]
(fun _ -> ())
(fun _ -> false)
(fun _ -> ())
(fun _ -> false)
(fun _ -> false)
true
in
let context_partner =
Context_unifier.create_context_partner
element
None
true
in
let context_unifier =
Context_unifier.create_context_unifier
space
[| context_partner |]
false
in
raise (Context_unifier.CLOSE context_unifier)
| None ->
let context_unifier =
Context_unifier.recompute_full_unifier ~recompute:false candidate.ca_raw_context_unifier
in
State.apply_split_right
candidates.cd_state
right_split
context_unifier
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_clause
candidate.ca_raw_context_unifier.Context_unifier.rcu_space.Context_unifier.cus_vars
index
(Context_unifier.create_space_utility_inc candidate.ca_raw_context_unifier.Context_unifier.rcu_space)
context_literals;
Some
{
Selection_types.candidate_type = State.SplitRight;
Selection_types.literal = right_split;
Selection_types.raw_context_unifier = candidate.ca_raw_context_unifier;
}
end
let select (candidates: candidates) (replay: Jumping.guiding_step option) : selected option =
match select_right_split candidates with
| (Some _) as right_split ->
right_split
| None ->
build_unprocessed ~force:true candidates;
let left_split =
get_best_candidate candidates
in
match left_split with
| None ->
None
| Some (candidate, split_literal, index) ->
Some (split candidates candidate split_literal index replay)
let check_exceeding (candidates: candidates) : unit =
if not (candidates.cd_unprocessed_size = 0) then
failwith "Selection_split.check_exceeding";
candidates.cd_check_exceeding <- true;
begin
try
Context.iter
(fun element ->
if is_marked_exceeding candidates element then
Problem_literals.compute_for_element candidates.cd_problem_literals element Context_unifier.Split;
)
candidates.cd_context;
build_unprocessed ~force:true candidates;
with
| EXCEEDING_EXHAUSTED ->
()
end;
clear_unprocessed candidates;
candidates.cd_check_exceeding <- false
let backtrack_right_splits (candidates: candidates) : unit =
if Config.jumping candidates.cd_config then begin
candidates.cd_right_splits <- [];
candidates.cd_applied_right_splits <- [];
end
else begin
let rec backtrack_right_splits' applied_splits =
match applied_splits with
| [] ->
candidates.cd_applied_right_splits <- []
| ((_, _, _, explanation) as applied, applied_at) :: tail ->
if
Tools.array_exists
(fun literal -> Context.element_for_literal candidates.cd_context literal = None)
explanation
then
backtrack_right_splits' tail
else if State.is_choice_point_invalid applied_at then
candidates.cd_right_splits <- applied :: candidates.cd_right_splits
else
candidates.cd_applied_right_splits <- applied_splits
in
backtrack_right_splits' candidates.cd_applied_right_splits;
end
let backtrack_invalid (candidates: candidates) : unit =
let rec backtrack_invalid still_invalid now_unprocessed invalid =
match invalid with
| [] ->
candidates.cd_invalid <- still_invalid;
List.iter (add_unprocessed candidates) now_unprocessed
| (raw_context_unifier, conflicting_choice_point) as candidate :: tail ->
if Context_unifier.is_raw_context_unifier_invalid raw_context_unifier then
backtrack_invalid still_invalid now_unprocessed tail
else if State.is_choice_point_invalid conflicting_choice_point then
backtrack_invalid still_invalid (raw_context_unifier :: now_unprocessed) tail
else
backtrack_invalid (candidate :: still_invalid) now_unprocessed tail
in
backtrack_invalid [] [] candidates.cd_invalid
let backtrack_added (candidates: candidates) (retracted: choice_point) (explanation: literal array) : unit =
candidates.cd_added <-
List.find_all
(fun (candidate, split_literal, index, choice_point) ->
if State.choice_point_equal choice_point retracted then begin
add_valid candidates candidate;
candidates.cd_right_splits <- (candidate, split_literal, index, explanation) :: candidates.cd_right_splits;
false;
end
else if Context_unifier.is_raw_context_unifier_invalid candidate.ca_raw_context_unifier then
false
else if (State.is_choice_point_invalid choice_point) then begin
add_valid candidates candidate;
false
end
else
true
)
candidates.cd_added
let backtrack_exceeding (candidates: candidates) : unit =
let invalid_elements =
Hashtbl.fold
(fun id element acc ->
if State.is_choice_point_invalid element.Context.el_choice_point then
id :: acc
else
acc
)
candidates.cd_exceeding_elements
[]
in
List.iter
(fun id ->
Hashtbl.remove candidates.cd_exceeding_elements id
)
invalid_elements
let backtrack (candidates: candidates) (retracted: choice_point) (explanation: literal list) : unit =
let explanation =
Array.of_list (
Tools.list_remove_first
(fun literal -> Term.literal_equal literal (State.left_split_literal retracted))
explanation
)
in
backtrack_invalid candidates;
backtrack_right_splits candidates;
backtrack_added candidates retracted explanation;
if Const.debug then begin
match candidates.cd_right_splits with
| [] ->
failwith "Selection_split.backtrack: no right split found"
| _ ->
()
end;
backtrack_exceeding candidates;