3#ifndef TURBO_COMMON_SOLVING_HPP
4#define TURBO_COMMON_SOLVING_HPP
15#include "battery/utility.hpp"
16#include "battery/allocator.hpp"
17#include "battery/vector.hpp"
18#include "battery/shared_ptr.hpp"
20#include "lala/simplifier.hpp"
21#include "lala/vstore.hpp"
22#include "lala/cartesian_product.hpp"
23#include "lala/interval.hpp"
25#include "lala/pir.hpp"
26#include "lala/fixpoint.hpp"
27#include "lala/search_tree.hpp"
28#include "lala/bab.hpp"
29#include "lala/split_strategy.hpp"
30#include "lala/interpretation.hpp"
32#include "lala/flatzinc_parser.hpp"
34#ifdef WITH_XCSP3PARSER
35 #include "lala/XCSP3_parser.hpp"
41 #define TURBO_ITV_BITS 32
44#if (TURBO_ITV_BITS == 64)
46#elif (TURBO_ITV_BITS == 16)
48#elif (TURBO_ITV_BITS == 32)
51 #error "Invalid value for TURBO_ITV_BITS: must be 16, 32 or 64."
53using Itv = Interval<ZLB<bound_value_type, battery::local_memory>>;
55static std::atomic<bool> got_signal;
56static void (*prev_sigint)(int);
57static void (*prev_sigterm)(int);
64 if (signum == SIGINT && prev_sigint != SIG_DFL && prev_sigint != SIG_IGN) {
65 (*prev_sigint)(signum);
67 if (signum == SIGTERM && prev_sigterm != SIG_DFL && prev_sigterm != SIG_IGN) {
68 (*prev_sigterm)(signum);
79 if(
static_cast<bool>(got_signal)) {
89template <
class A,
class Timepo
int>
92 if(a.config.timeout_ms == 0) {
95 if(a.stats.time_ms_of(
Timer::OVERALL) >=
static_cast<int64_t
>(a.config.timeout_ms)) {
96 if(a.config.verbose_solving) {
97 printf(
"%% CPU: Timeout reached.\n");
106template <
class Alloc,
size_t n>
123template <
class Alloc,
size_t n>
126 return Alloc{}.allocate(bytes);
129 Alloc{}.deallocate(data);
140template <
class Universe,
141 class BasicAllocator,
143 class StoreAllocator>
148 using LIStore = VStore<universe_type, BasicAllocator>;
150 using IStore = VStore<Universe, StoreAllocator>;
151#ifdef TURBO_IPC_ABSTRACT_DOMAIN
152 using IProp = PC<IStore, PropAllocator>;
154 using IProp = PIR<IStore, PropAllocator>;
157 using Split = SplitStrategy<IProp, BasicAllocator>;
158 using IST = SearchTree<IProp, Split, BasicAllocator>;
159 using IBAB = BAB<IST, LIStore>;
167 using F = TFormula<basic_allocator_type>;
177 template <
class U2,
class BasicAlloc2,
class PropAllocator2,
class StoreAllocator2>
201 store = deps.template clone<IStore>(other.
store);
202 iprop = deps.template clone<IProp>(other.
iprop);
203 split = deps.template clone<Split>(other.
split);
205 bab = deps.template clone<IBAB>(other.
bab);
209 template <
class U2,
class BasicAlloc2,
class PropAllocator2,
class StoreAllocator2>
229 template <
class Alloc>
249 size_t num_subproblems = 1;
269 VarEnv<BasicAllocator>
env;
281 CUDA
void allocate(
int num_vars,
bool with_simplifier) {
285 if(with_simplifier) {
294 printf(
"%% Abstract domain allocated.\n");
312 CUDA
void typing(
F& f,
bool toplevel =
true)
const {
314 printf(
"%% Typing the formula...\n");
318 if(f.sig() == ::lala::IN && f.seq(1).is(F::S) && f.seq(1).s().size() > 1) {
319 f.type_as(
iprop->aty());
322 for(
int i = 0; i < f.seq().size(); ++i) {
323 typing(f.seq(i),
false);
327 for(
int i = 0; i < f.eseq().size(); ++i) {
328 typing(f.eseq(i),
false);
333 printf(
"%% Typed AST:\n");
340 template <
class F,
class Env,
class A>
341 CUDA
bool interpret_and_diagnose_and_tell(
const F& f, Env&
env, A& a) {
342 IDiagnostics diagnostics;
343 if(!interpret_and_tell(f,
env, a, diagnostics)) {
344 IDiagnostics diagnostics2;
345 interpret_and_tell<true>(f,
env, a, diagnostics2);
346 diagnostics2.print();
356 printf(
"%% Interpreting the formula...\n");
358 if(!interpret_and_diagnose_and_tell(f,
env, *
bab)) {
362 printf(
"%% Interpreted AST:\n");
367 printf(
"%% Formula has been interpreted.\n");
378 if(
bab->is_minimization()) {
381 else if(
bab->is_maximization()) {
382 auto minobj =
env.variable_of(
"__MINIMIZE_OBJ");
383 assert(minobj.has_value());
384 assert(minobj->get().avar_of(
store->aty()).has_value());
390 bool can_interpret =
true;
394 can_interpret &= interpret_default_strategy<F>();
395 return can_interpret;
408#ifdef WITH_XCSP3PARSER
414 std::cerr <<
"Could not parse input file." << std::endl;
419 printf(
"%% Input file parsed\n");
422 printf(
"%% Parsed AST:\n");
430 printf(
"%% Formula syntactically simplified.\n");
437 IDiagnostics diagnostics;
438 typename ISimplifier::template tell_type<basic_allocator_type> tell{
basic_allocator};
439 if(!top_level_ginterpret_in<IKind::TELL>(*
simplifier, f,
env, tell, diagnostics)) {
440 printf(
"%% ERROR: Could not simplify the formula because:\n");
441 IDiagnostics diagnostics2;
442 top_level_ginterpret_in<IKind::TELL, true>(*
simplifier, f,
env, tell, diagnostics2);
443 diagnostics2.print();
450 size_t num_vars = num_quantified_vars(f);
456 GaussSeidelIteration fp_engine;
457 fp_engine.fixpoint(
iprop->num_deductions(), [&](
size_t i) { return iprop->deduce(i); });
465 printf(
"%% Simplifying the formula...\n");
467 fp_engine.fixpoint(
simplifier->num_deductions(), [&](
size_t i) { return simplifier->deduce(i); });
470 printf(
"%% Formula simplified.\n");
473 num_vars = num_quantified_vars(f);
475 stats.
print_stat(
"constraints_after_simplification", num_constraints(f));
486 if(f.sig() == Sig::MAXIMIZE && f.seq(0).is_variable()) {
487 LVar<basic_allocator_type> minimize_obj(
"__MINIMIZE_OBJ");
488 f = F::make_binary(f,
491 F::make_exists(f.seq(0).type(), minimize_obj, battery::get<1>(max_var)),
494 F::make_lvar(f.seq(0).type(), minimize_obj),
496 F::make_unary(Sig::NEG, f.seq(0)))));
498 else if(f.sig() == Sig::AND) {
499 for(
int i = 0; i < f.seq().size(); ++i) {
507 f = ternarize(f, VarEnv<BasicAllocator>(), {0,1,2});
508 battery::vector<F> extra;
509 f = normalize(f, extra);
510 size_t num_vars = num_quantified_vars(f);
526 size_t preprocessing_fixpoint_iterations = 0;
527 SimplifierStats preprocessing_stats;
528 size_t eliminated_variables = 0;
529 local::B has_changed =
true;
530 GaussSeidelIteration fp_engine;
532 while(!
iprop->is_bot() && has_changed) {
534 preprocessing_fixpoint_iterations++;
535 SimplifierStats local_preprocessing_stats;
536 fp_engine.fixpoint(
iprop->num_deductions(), [&](
size_t i) { return iprop->deduce(i); }, has_changed);
540 has_changed |=
simplifier->algebraic_simplify(tnf, local_preprocessing_stats);
541 simplifier->eliminate_entailed_constraints(*
iprop, tnf, local_preprocessing_stats);
542 has_changed |=
simplifier->i_cse(tnf, local_preprocessing_stats);
545 local_preprocessing_stats.print(
stats, preprocessing_fixpoint_iterations);
547 preprocessing_stats.merge(local_preprocessing_stats);
550 simplifier->eliminate_useless_variables(tnf, eliminated_variables);
552 F extra_f = F::make_nary(AND, std::move(extra));
555 printf(
"%% Formula simplified.\n");
557 F f2 = F::make_binary(std::move(f), AND, std::move(extra_f));
558 num_vars = num_quantified_vars(f2);
559 preprocessing_stats.print(
stats);
561 stats.
print_stat(
"preprocessing_fixpoint_iterations", preprocessing_fixpoint_iterations);
563 stats.
print_stat(
"constraints_after_simplification", num_tnf_constraints(f2));
564 if(
iprop->is_bot()) {
575 #define STR(x) STR_(x)
576 #ifdef TURBO_IPC_ABSTRACT_DOMAIN
584 #ifdef TURBO_NO_ENTAILED_PROP_REMOVAL
585 return "deactivated";
587 return "by_indexes_scan";
597 auto max_var = find_maximize_var(*f_ptr);
598 if(max_var.has_value()) {
599 auto max_var_decl = find_existential_of(*f_ptr, max_var.value());
600 if(max_var_decl.has_value()) {
605 #ifdef TURBO_IPC_ABSTRACT_DOMAIN
606 constexpr bool use_ipc =
true;
608 constexpr bool use_ipc =
false;
617 if constexpr(use_ipc) {
618 printf(
"%% WARNING: -network_analysis option is only valid with the PIR abstract domain.\n");
631 CUDA
bool interpret_default_strategy() {
632 typename F::Sequence seq;
633 seq.push_back(F::make_nary(
"first_fail", {}));
634 seq.push_back(F::make_nary(
"indomain_min", {}));
635 F search_strat = F::make_nary(
"search", std::move(seq));
636 if(!interpret_and_diagnose_and_tell(search_strat,
env, *
bab)) {
643 size_t num_occurrences;
644 bool infinite_domain;
650 void analyze_pir()
const {
652 printf(
"%% Analyzing the constraint network...\n");
654 if(
iprop->is_bot()) {
655 printf(
"%% Constraint network UNSAT at root, analysis cancelled...\n");
658 std::vector<vstat> vstats(
store->vars(), vstat{});
659 for(
int i = 0; i <
store->vars(); ++i) {
660 auto width = (*store)[i].width().lb();
661 vstats[i].infinite_domain = width.is_top();
662 if(!vstats[i].infinite_domain) {
663 vstats[i].domain_size = width.value() + 1;
667 std::map<Sig, size_t> op_stats{{{Sig::EQ,0}, {Sig::LEQ,0}, {Sig::NEQ,0}, {Sig::GT,0}, {ADD,0}, {MUL,0}, {EMOD,0}, {EDIV,0}, {MIN,0}, {MAX,0}}};
668 std::map<Sig, size_t> reified_op_stats{{{Sig::EQ,0}, {Sig::LEQ,0}}};
670 for(
int i = 0; i <
iprop->num_deductions(); ++i) {
671 bytecode_type bytecode =
iprop->load_deduce(i);
672 vstats[bytecode.x.vid()].num_occurrences++;
673 vstats[bytecode.y.vid()].num_occurrences++;
674 vstats[bytecode.z.vid()].num_occurrences++;
675 if(!op_stats.contains(bytecode.op)) {
676 printf(
"%% WARNING: operator not explicitly managed in PIR: %d\n", bytecode.op);
677 op_stats[bytecode.op] = 0;
679 auto dom =
iprop->project(bytecode.x);
680 if((is_arithmetic_comparison(bytecode.op)) &&
681 (dom.lb().value() != dom.ub().value() || dom.lb().value() == 0))
683 if(dom.lb().value() != dom.ub().value()) {
684 reified_op_stats[bytecode.op]++;
687 op_stats[negate_arithmetic_comparison(bytecode.op)]++;
691 op_stats[bytecode.op]++;
695 size_t num_constants = 0;
696 size_t num_2bits_vars = 0;
697 size_t num_64bits_vars = 0;
698 size_t num_128bits_vars = 0;
699 size_t num_256bits_vars = 0;
700 size_t num_512bits_vars = 0;
701 size_t num_65536bits_vars = 0;
702 size_t num_infinites = 0;
703 double average_occ_vars = 0;
704 size_t sum_props_of_vars = 0;
705 size_t max_occ_vars = 0;
706 size_t num_vars_in_2_constraints = 0;
707 size_t num_vars_in_3_constraints = 0;
708 size_t num_vars_in_4_to_10_constraints = 0;
709 size_t num_vars_in_more_than_10_constraints = 0;
710 size_t largest_dom = 0;
711 size_t sum_domain_size = 0;
712 for(
int i = 0; i < vstats.size(); ++i) {
713 if(vstats[i].infinite_domain) {
717 largest_dom = battery::max(largest_dom, vstats[i].domain_size);
718 sum_domain_size += vstats[i].domain_size;
720 if(vstats[i].domain_size == 1) {
724 num_2bits_vars += vstats[i].domain_size == 2;
725 num_64bits_vars += vstats[i].domain_size <= 64;
726 num_128bits_vars += vstats[i].domain_size <= 128;
727 num_256bits_vars += vstats[i].domain_size <= 256;
728 num_512bits_vars += vstats[i].domain_size <= 512;
729 num_65536bits_vars += vstats[i].domain_size <= 65536;
730 sum_props_of_vars += vstats[i].num_occurrences;
731 max_occ_vars = battery::max(max_occ_vars, vstats[i].num_occurrences);
733 num_vars_in_2_constraints += vstats[i].num_occurrences == 2;
734 num_vars_in_3_constraints += vstats[i].num_occurrences == 3;
735 num_vars_in_4_to_10_constraints += vstats[i].num_occurrences > 3 && vstats[i].num_occurrences <= 10;
736 num_vars_in_more_than_10_constraints += vstats[i].num_occurrences > 10;
738 average_occ_vars =
static_cast<double>(sum_props_of_vars) /
static_cast<double>(vstats.size() - num_constants);
745 stats.
print_stat(
"avg_constraints_per_unassigned_var", average_occ_vars);
749 stats.
print_stat(
"num_vars_in_2_constraints", num_vars_in_2_constraints);
750 stats.
print_stat(
"num_vars_in_3_constraints", num_vars_in_3_constraints);
751 stats.
print_stat(
"num_vars_in_4_to_10_constraints", num_vars_in_4_to_10_constraints);
752 stats.
print_stat(
"num_vars_in_more_than_10_constraints", num_vars_in_more_than_10_constraints);
766 for(
auto& [sig,count] : op_stats) {
767 std::string stat_name(
"num_op_");
768 stat_name += string_of_sig_txt(sig);
771 for(
auto& [sig,count] : reified_op_stats) {
772 std::string stat_name(
"num_op_reified_");
773 stat_name += string_of_sig_txt(sig);
797 template <
class BestStore>
841 if(!
bab->objective_var().is_untyped() && !
best->is_top()) {
849 template <
class U2,
class BasicAlloc2,
class PropAlloc2,
class StoreAlloc2>
851 if(
bab->is_optimization() && !other.
best->is_top() &&
bab->compare_bound(*other.
best, *
best)) {
858template <
class Universe,
class Allocator = battery::standard_allocator>
860 battery::statistics_allocator<Allocator>,
861 battery::statistics_allocator<UniqueLightAlloc<Allocator, 0>>,
862 battery::statistics_allocator<UniqueLightAlloc<Allocator, 1>>>;
#define TURBO_ITV_BITS
Definition common_solving.hpp:41
bool must_quit(A &a)
Definition common_solving.hpp:78
int bound_value_type
Definition common_solving.hpp:49
Interval< ZLB< bound_value_type, battery::local_memory > > Itv
Definition common_solving.hpp:53
void block_signal_ctrlc()
Definition common_solving.hpp:72
bool check_timeout(A &a, const Timepoint &start)
Definition common_solving.hpp:90
void signal_handler(int signum)
Definition common_solving.hpp:59
Definition common_solving.hpp:169
Definition common_solving.hpp:170
Definition common_solving.hpp:144
abstract_ptr< IBAB > bab
Definition common_solving.hpp:266
Configuration< BasicAllocator > config
Definition common_solving.hpp:278
CUDA bool interpret(const F &f)
Definition common_solving.hpp:354
CUDA void deallocate()
Definition common_solving.hpp:299
VStore< universe_type, BasicAllocator > LIStore
Definition common_solving.hpp:148
CUDA void print_final_solution()
Definition common_solving.hpp:830
StoreAllocator store_allocator
Definition common_solving.hpp:258
CUDA AbstractDomains(const tag_gpu_block_copy &, bool enable_sharing, const AbstractDomains< U2, BasicAlloc2, PropAllocator2, StoreAllocator2 > &other, const BasicAllocator &basic_allocator=BasicAllocator(), const PropAllocator &prop_allocator=PropAllocator(), const StoreAllocator &store_allocator=StoreAllocator())
Definition common_solving.hpp:178
SplitStrategy< IProp, BasicAllocator > Split
Definition common_solving.hpp:157
BasicAllocator basic_allocator
Definition common_solving.hpp:256
BAB< IST, LIStore > IBAB
Definition common_solving.hpp:159
CUDA void meet(AbstractDomains< U2, BasicAlloc2, PropAlloc2, StoreAlloc2 > &other)
Definition common_solving.hpp:850
CUDA bool on_solution_node()
Definition common_solving.hpp:819
CUDA bool on_node()
Definition common_solving.hpp:779
void initialize_simplifier(const F &f)
Definition common_solving.hpp:436
Statistics< BasicAllocator > stats
Definition common_solving.hpp:279
abstract_ptr< LIStore > best
Definition common_solving.hpp:265
AVar minimize_obj_var
Definition common_solving.hpp:276
CUDA void allocate(int num_vars, bool with_simplifier)
Definition common_solving.hpp:281
battery::shared_ptr< TFormula< basic_allocator_type >, basic_allocator_type > FormulaPtr
Definition common_solving.hpp:398
AbstractDomains(AbstractDomains &&other)=default
const char * name_of_entailed_removal() const
Definition common_solving.hpp:583
abstract_ptr< IStore > store
Definition common_solving.hpp:260
VarEnv< BasicAllocator > env
Definition common_solving.hpp:269
CUDA bool is_printing_intermediate_sol()
Definition common_solving.hpp:789
CUDA AbstractDomains(const AbstractDomains< U2, BasicAlloc2, PropAllocator2, StoreAllocator2 > &other, const BasicAllocator &basic_allocator=BasicAllocator(), const PropAllocator &prop_allocator=PropAllocator(), const StoreAllocator &store_allocator=StoreAllocator(), const tag_copy_cons &tag=tag_copy_cons{})
Definition common_solving.hpp:210
Simplifier< IProp, BasicAllocator > ISimplifier
Definition common_solving.hpp:156
abstract_ptr< IST > search_tree
Definition common_solving.hpp:264
CUDA void on_failed_node()
Definition common_solving.hpp:826
PropAllocator prop_allocator_type
Definition common_solving.hpp:162
BasicAllocator basic_allocator_type
Definition common_solving.hpp:161
CUDA void print_solution(const BestStore &best_store)
Definition common_solving.hpp:798
abstract_ptr< ISimplifier > simplifier
Definition common_solving.hpp:262
void preprocess()
Definition common_solving.hpp:591
void preprocess_tcn(F &f)
Definition common_solving.hpp:506
void preprocess_ipc(F &f)
Definition common_solving.hpp:449
const char * name_of_abstract_domain() const
Definition common_solving.hpp:573
abstract_ptr< Split > split
Definition common_solving.hpp:263
SolverOutput< BasicAllocator > solver_output
Definition common_solving.hpp:272
CUDA bool update_solution_stats()
Definition common_solving.hpp:808
PropAllocator prop_allocator
Definition common_solving.hpp:257
typename Universe::local_type universe_type
Definition common_solving.hpp:145
VStore< Universe, StoreAllocator > IStore
Definition common_solving.hpp:150
FormulaPtr parse_cn()
Definition common_solving.hpp:403
void add_minimize_objective_var(F &f, const F::Existential &max_var)
Definition common_solving.hpp:484
StoreAllocator store_allocator_type
Definition common_solving.hpp:163
PIR< IStore, PropAllocator > IProp
Definition common_solving.hpp:154
abstract_ptr< IProp > iprop
Definition common_solving.hpp:261
CUDA void print_solution()
Definition common_solving.hpp:793
CUDA void prune()
Definition common_solving.hpp:803
CUDA AbstractDomains(const this_type &other, const BasicAllocator &basic_allocator=BasicAllocator(), const PropAllocator &prop_allocator=PropAllocator(), const StoreAllocator &store_allocator=StoreAllocator())
Definition common_solving.hpp:222
TFormula< basic_allocator_type > F
Definition common_solving.hpp:167
SearchTree< IProp, Split, BasicAllocator > IST
Definition common_solving.hpp:158
CUDA AbstractDomains(const Configuration< Alloc > &config, const BasicAllocator &basic_allocator=BasicAllocator(), const PropAllocator &prop_allocator=PropAllocator(), const StoreAllocator &store_allocator=StoreAllocator())
Definition common_solving.hpp:230
CUDA void print_mzn_statistics()
Definition common_solving.hpp:837
size_t stop_after_n_nodes
Definition config.hpp:38
battery::string< allocator_type > problem_path
Definition config.hpp:54
CUDA InputFormat input_format() const
Definition config.hpp:245
bool print_intermediate_solutions
Definition config.hpp:36
bool disable_simplify
Definition config.hpp:45
bool print_ast
Definition config.hpp:42
CUDA void print_mzn_statistics() const
Definition config.hpp:219
Arch arch
Definition config.hpp:51
size_t or_nodes
Definition config.hpp:48
size_t stop_after_n_solutions
Definition config.hpp:37
bool force_ternarize
Definition config.hpp:44
bool network_analysis
Definition config.hpp:46
bool print_statistics
Definition config.hpp:40
int verbose_solving
Definition config.hpp:41
size_t subproblems_power
Definition config.hpp:49
Definition statistics.hpp:110
CUDA void print_timing_stat(const char *name, Timer timer) const
Definition statistics.hpp:283
size_t nodes
Definition statistics.hpp:118
CUDA void print_mzn_end_stats() const
Definition statistics.hpp:318
CUDA void print_mzn_statistics(int verbose=0) const
Definition statistics.hpp:287
size_t constraints
Definition statistics.hpp:115
int depth_max
Definition statistics.hpp:121
CUDA void print_mzn_final_separator() const
Definition statistics.hpp:339
size_t fails
Definition statistics.hpp:119
std::chrono::steady_clock::time_point start_timer_host() const
Definition statistics.hpp:183
bool exhaustive
Definition statistics.hpp:122
std::chrono::steady_clock::time_point stop_timer(Timer timer, std::chrono::steady_clock::time_point start)
Definition statistics.hpp:193
size_t variables
Definition statistics.hpp:114
size_t solutions
Definition statistics.hpp:120
size_t eps_num_subproblems
Definition statistics.hpp:123
CUDA void meet(const Statistics< Alloc > &other)
Definition statistics.hpp:158
CUDA void print_mzn_separator() const
Definition statistics.hpp:335
CUDA void print_stat(const char *name, const char *value) const
Definition statistics.hpp:206
CUDA void print_mzn_objective(const auto &obj, bool is_minimization) const
Definition statistics.hpp:323
CUDA void print_memory_statistics(int verbose, const char *key, size_t bytes) const
Definition statistics.hpp:256
Definition common_solving.hpp:107
CUDA void deallocate(void *data)
Definition common_solving.hpp:118
UniqueAlloc & operator=(UniqueAlloc &&alloc)=default
UniqueAlloc(const UniqueAlloc &alloc)=default
UniqueAlloc & operator=(const UniqueAlloc &alloc)=default
Alloc allocator
Definition common_solving.hpp:108
CUDA void * allocate(size_t bytes)
Definition common_solving.hpp:115
UniqueAlloc(UniqueAlloc &&alloc)=default
CUDA UniqueAlloc(const Alloc &alloc)
Definition common_solving.hpp:110
Definition common_solving.hpp:124
CUDA void * allocate(size_t bytes)
Definition common_solving.hpp:125
CUDA void deallocate(void *data)
Definition common_solving.hpp:128