contractor default_strategy::build_contractor(box const & box, scoped_vec<shared_ptr<constraint>> const & ctrs, bool const complete, SMTConfig const & config) const { bool const use_cache = true; // 1. Categorize constraints vector<shared_ptr<nonlinear_constraint>> nl_ctrs; vector<shared_ptr<ode_constraint>> ode_ctrs_rev; vector<shared_ptr<generic_forall_constraint>> generic_forall_ctrs; for (shared_ptr<constraint> const ctr : ctrs.get_reverse()) { switch (ctr->get_type()) { case constraint_type::Nonlinear: { auto nl_ctr = dynamic_pointer_cast<nonlinear_constraint>(ctr); nl_ctrs.push_back(nl_ctr); break; } case constraint_type::ODE: { auto ode_ctr = dynamic_pointer_cast<ode_constraint>(ctr); ode_ctrs_rev.push_back(ode_ctr); break; } case constraint_type::GenericForall: { auto gf_ctr = dynamic_pointer_cast<generic_forall_constraint>(ctr); generic_forall_ctrs.push_back(gf_ctr); break; } case constraint_type::ForallT: { // Do nothing break; } default: DREAL_LOG_FATAL << "Unknown Constraint Type: " << ctr->get_type() << " " << *ctr << endl; } } vector<shared_ptr<ode_constraint>> ode_ctrs(ode_ctrs_rev); reverse(ode_ctrs.begin(), ode_ctrs.end()); vector<contractor> ctcs; ctcs.reserve(ctrs.size()); // 2.0 Build Sample Contractor if (config.nra_sample > 0 && complete) { ctcs.push_back(mk_contractor_sample(box, config.nra_sample, ctrs.get_vec())); } // 2.1 Build nonlinear contractors vector<contractor> nl_ctcs; for (auto const & nl_ctr : nl_ctrs) { if (!nl_ctr->is_neq()) { nl_ctcs.push_back(mk_contractor_ibex_fwdbwd(nl_ctr, use_cache)); } else { // Case: != (not equal), do nothing } } contractor nl_ctc = mk_contractor_seq(nl_ctcs); ctcs.insert(ctcs.end(), nl_ctcs.begin(), nl_ctcs.end()); // 2.2. Build Polytope Contractor if (config.nra_polytope) { ctcs.push_back(mk_contractor_ibex_polytope(config.nra_precision, box.get_vars(), nl_ctrs)); } // 2.3. Int Contractor ctcs.push_back(mk_contractor_int(box)); // 2.4. Build generic forall contractors for (auto const & generic_forall_ctr : generic_forall_ctrs) { ctcs.push_back(mk_contractor_generic_forall(box, generic_forall_ctr)); } if (complete && ode_ctrs.size() > 0) { // Add ODE Contractors only for complete check // 2.5. Build GSL Contractors (using CAPD4) vector<contractor> ode_gsl_ctcs; if (config.nra_ODE_sampling) { // 2.5.1 Build Eval contractors vector<contractor> eval_ctcs; for (auto const & nl_ctr : nl_ctrs) { eval_ctcs.push_back(mk_contractor_eval(nl_ctr, false)); } contractor eval_ctc = mk_contractor_seq(eval_ctcs); if (config.nra_parallel) { vector<contractor> nl_ctcs2; for (auto const & nl_ctr : nl_ctrs) { if (!nl_ctr->is_neq()) { nl_ctcs2.push_back(mk_contractor_ibex_fwdbwd(nl_ctr, false)); } else { // Case: != (not equal), do nothing } } contractor nl_ctc2 = mk_contractor_seq(nl_ctcs2); for (auto const & ode_ctr : ode_ctrs) { // Add Forward ODE Pruning (Underapproximation, using GNU GSL) ode_gsl_ctcs.push_back(mk_contractor_gsl(box, ode_ctr, eval_ctc, ode_direction::FWD, false, config.nra_ODE_fwd_timeout)); ode_gsl_ctcs.push_back(nl_ctc2); } } else { for (auto const & ode_ctr : ode_ctrs) { // Add Forward ODE Pruning (Underapproximation, using GNU GSL) ode_gsl_ctcs.push_back(mk_contractor_gsl(box, ode_ctr, eval_ctc, ode_direction::FWD, use_cache, config.nra_ODE_fwd_timeout)); ode_gsl_ctcs.push_back(nl_ctc); } } } // 2.6. Build ODE Contractors (using CAPD4) vector<contractor> ode_capd4_fwd_ctcs; vector<contractor> ode_capd4_bwd_ctcs; for (auto const & ode_ctr : ode_ctrs) { // 2.6.1. Add Forward ODE Pruning (Overapproximation, using CAPD4) if (config.nra_ODE_cache) { ode_capd4_fwd_ctcs.emplace_back( mk_contractor_cache( mk_contractor_try( mk_contractor_seq(mk_contractor_capd_full(box, ode_ctr, ode_direction::FWD, config.nra_ODE_taylor_order, config.nra_ODE_grid_size, use_cache, config.nra_ODE_fwd_timeout), nl_ctc)))); } else { ode_capd4_fwd_ctcs.emplace_back( mk_contractor_try( mk_contractor_seq( mk_contractor_capd_full(box, ode_ctr, ode_direction::FWD, config.nra_ODE_taylor_order, config.nra_ODE_grid_size, use_cache, config.nra_ODE_fwd_timeout), nl_ctc))); } } if (!config.nra_ODE_forward_only) { // 2.6.2. Add Backward ODE Pruning (Overapproximation, using CAPD4) for (auto const & ode_ctr : ode_ctrs_rev) { if (config.nra_ODE_cache) { ode_capd4_bwd_ctcs.emplace_back( mk_contractor_cache( mk_contractor_try( mk_contractor_seq( mk_contractor_capd_full(box, ode_ctr, ode_direction::BWD, config.nra_ODE_taylor_order, config.nra_ODE_grid_size, use_cache, config.nra_ODE_bwd_timeout), nl_ctc)))); } else { ode_capd4_bwd_ctcs.emplace_back( mk_contractor_try( mk_contractor_seq( mk_contractor_capd_full(box, ode_ctr, ode_direction::BWD, config.nra_ODE_taylor_order, config.nra_ODE_grid_size, use_cache, config.nra_ODE_bwd_timeout), nl_ctc))); } } } if (config.nra_ODE_sampling) { if (config.nra_parallel) { ctcs.push_back(mk_contractor_parallel_any( mk_contractor_try_or(mk_contractor_throw_if_empty(mk_contractor_seq(ode_gsl_ctcs)), mk_contractor_empty()), mk_contractor_seq(mk_contractor_seq(ode_capd4_fwd_ctcs), mk_contractor_seq(ode_capd4_bwd_ctcs)))); } else { ctcs.push_back( mk_contractor_try_or( // Try Underapproximation(GSL) if it fails try Overapproximation(CAPD4) mk_contractor_throw_if_empty(mk_contractor_seq(ode_gsl_ctcs)), mk_contractor_seq(mk_contractor_seq(ode_capd4_fwd_ctcs), mk_contractor_seq(ode_capd4_bwd_ctcs)))); } } else { ctcs.insert(ctcs.end(), ode_capd4_fwd_ctcs.begin(), ode_capd4_fwd_ctcs.end()); ctcs.insert(ctcs.end(), ode_capd4_bwd_ctcs.begin(), ode_capd4_bwd_ctcs.end()); } } if (complete) { // 2.7 Build Eval contractors vector<contractor> eval_ctcs; for (auto const & nl_ctr : nl_ctrs) { eval_ctcs.push_back(mk_contractor_eval(nl_ctr, use_cache)); } return mk_contractor_seq(mk_contractor_fixpoint(default_strategy::term_cond, ctcs), mk_contractor_seq(eval_ctcs)); } else { return mk_contractor_fixpoint(default_strategy::term_cond, ctcs); } }
contractor nra_solver::build_contractor(box const & box, scoped_vec<constraint *> const &ctrs, bool const complete) { vector<nonlinear_constraint const *> nl_ctrs; vector<contractor> nl_ctcs; nl_ctcs.reserve(ctrs.size()); vector<contractor> nl_eval_ctcs; nl_eval_ctcs.reserve(ctrs.size()); vector<contractor> ode_ctcs; ode_ctcs.reserve(ctrs.size()); // Add contractor_sample if --sample option is used if (config.nra_sample > 0 && complete) { nl_ctcs.push_back(mk_contractor_sample(config.nra_sample, ctrs.get_vec())); } for (constraint * const ctr : ctrs) { if (ctr->get_type() == constraint_type::Nonlinear) { nonlinear_constraint const * const nl_ctr = dynamic_cast<nonlinear_constraint *>(ctr); if (nl_ctr->get_numctr()) { nl_ctcs.push_back(mk_contractor_ibex_fwdbwd(box, nl_ctr)); nl_ctrs.push_back(nl_ctr); } else { // This is identity, do nothing } nl_eval_ctcs.push_back(mk_contractor_eval(box, nl_ctr)); #ifdef SUPPORT_ODE } else if (ctr->get_type() == constraint_type::ODE) { // TODO(soonhok): add heuristics to choose fwd/bwd // TODO(soonhok): perform ODE only for complete check ode_ctcs.emplace_back( mk_contractor_try( mk_contractor_capd_fwd_full(box, dynamic_cast<ode_constraint *>(ctr), config.nra_ODE_taylor_order, config.nra_ODE_grid_size))); ode_ctcs.emplace_back( mk_contractor_try( mk_contractor_capd_bwd_full(box, dynamic_cast<ode_constraint *>(ctr), config.nra_ODE_taylor_order, config.nra_ODE_grid_size))); #endif } } if (config.nra_polytope) { nl_ctcs.push_back(mk_contractor_ibex_polytope(config.nra_precision, nl_ctrs)); } nl_ctcs.push_back(mk_contractor_int()); // Add contractor_sample if --sample option is used if (config.nra_aggressive > 0 && complete) { nl_ctcs.push_back(mk_contractor_sample(config.nra_aggressive, ctrs.get_vec())); } auto term_cond = [this](dreal::box const & old_box, dreal::box const & new_box) { if (new_box.max_diam() < config.nra_precision) { return true; } double const threshold = 0.01; // If there is a dimension which is improved more than // threshold, we stop the current fixed-point computation. bool is_corner_case = true; for (unsigned i = 0; i < old_box.size(); i++) { double const new_box_i = new_box[i].diam(); double const old_box_i = old_box[i].diam(); if (new_box_i == numeric_limits<double>::infinity()) { continue; } if (old_box_i == 0) { // The i-th dimension was already a point, nothing to improve. continue; } double const improvement = 1 - new_box_i / old_box_i; assert(!std::isnan(improvement)); if (improvement >= threshold) { return false; } else { is_corner_case = false; } } if (is_corner_case && new_box == old_box) { // We only do the equality check if it's a corner case // where every dimension has either [ENTIRE] or a point // value. return false; } return true; }; return mk_contractor_fixpoint(term_cond, nl_ctcs, ode_ctcs, nl_eval_ctcs); }