void contractor_throw_if_empty::prune(contractor_status & cs) { DREAL_LOG_DEBUG << "contractor_throw_if_empty::prune"; m_c.prune(cs); if (cs.m_box.is_empty()) { throw contractor_exception("throw if empty"); } }
void contractor_cache::prune(contractor_status & cs) { // extract i-th interval where `m_input[i] == 1` vector<ibex::Interval> const in = extract_from_box_using_bitset(cs.m_box, m_input); auto const it = m_cache.find(in); if (it == m_cache.end()) { // not found in cache, run m_ctc ++m_num_nohit; { contractor_status_guard csg(cs); assert(cs.m_output.empty()); assert(cs.m_used_constraints.empty()); try { // run contractor m_ctc.prune(cs); // extract out from box. vector<ibex::Interval> const out = extract_from_box_using_bitset(cs.m_box, cs.m_output); // save the result to the cache m_cache.emplace(in, make_tuple(out, cs.m_output, cs.m_used_constraints, false)); } catch (exception & e) { m_cache.emplace(in, make_tuple(vector<ibex::Interval>(), cs.m_output, cs.m_used_constraints, true)); throw contractor_exception(e.what()); } } } else { ++m_num_hit; // found in cache, use it auto const & m_cached_content = it->second; vector<ibex::Interval> const & out = get<0>(m_cached_content); auto const & output_bitset = get<1>(m_cached_content); auto const & used_constraints = get<2>(m_cached_content); bool const was_exception_thrown = get<3>(m_cached_content); cs.m_used_constraints.insert(used_constraints.begin(), used_constraints.end()); if (was_exception_thrown) { cs.m_output.union_with(output_bitset); throw contractor_exception("previously there was an exception in the cached computation"); } else { // project out to box; update_box_using_bitset(cs.m_box, out, output_bitset); cs.m_output.union_with(output_bitset); } } }
void contractor_parallel_all::prune(box & b, SMTConfig & config) { DREAL_LOG_DEBUG << "contractor_parallel_all::prune"; DREAL_LOG_FATAL << "-------------------------------------------------------------"; // TODO(soonhok): implement this if (m_vec.size() == 0) { // Do nothing for empty vec return; } // 1. Make n copies of box b vector<box> boxes(m_vec.size(), b); vector<pruning_thread_status> statuses(m_vec.size(), pruning_thread_status::READY); m_index = -1; // DREAL_LOG_FATAL << "parallel: Boxes are copied"; // 2. Trigger execution with each contractor and a copied box vector<interruptible_thread> threads; atomic_int tasks_to_run(m_vec.size()); // DREAL_LOG_FATAL << "parallel: tasks to run = " << tasks_to_run.load(); for (unsigned i = 0; i < m_vec.size(); ++i) { DREAL_LOG_FATAL << "parallel : thread " << i << " / " << (tasks_to_run.load() - 1) << " spawning..."; threads.emplace_back(parallel_helper_fn, i, m_vec[i], boxes[i], config, statuses[i], m_mutex, m_cv, m_index, tasks_to_run); DREAL_LOG_FATAL << "parallel : thread " << i << " / " << (tasks_to_run.load() - 1) << " spawned..."; } DREAL_LOG_FATAL << "parallel : " << m_vec.size() << " thread(s) got created"; while (true) { DREAL_LOG_FATAL << "parallel: waiting for the lock"; unique_lock<mutex> lk(m_mutex); DREAL_LOG_FATAL << "parallel: get a lock. " << tasks_to_run.load() << " tasks to go"; if (tasks_to_run.load() == 0) { break; } DREAL_LOG_FATAL << "parallel: WAIT for CV." << tasks_to_run.load() << " tasks to go";; m_index = -1; m_cv.wait(lk, [&]() { return m_index != -1; }); DREAL_LOG_FATAL << "parallel: wake up" << tasks_to_run.load(); pruning_thread_status const & s = statuses[m_index]; // DREAL_LOG_FATAL << "parallel: thread " << m_index << " " << s; if (s == pruning_thread_status::UNSAT || s == pruning_thread_status::EXCEPTION) { // Interrupt all the rest threads for (unsigned i = 0; i < statuses.size(); i++) { if (i - m_index != 0 && (statuses[i] == pruning_thread_status::READY || statuses[i] == pruning_thread_status::RUNNING)) { threads[i].interrupt(); } } if (s == pruning_thread_status::UNSAT) { DREAL_LOG_FATAL << "parallel: " << m_index << " got UNSAT"; b.set_empty(); m_input.union_with(m_vec[m_index].input()); m_output.union_with(m_vec[m_index].output()); unordered_set<shared_ptr<constraint>> const & used_ctrs = m_vec[m_index].used_constraints(); m_used_constraints.insert(used_ctrs.begin(), used_ctrs.end()); lk.unlock(); for (unsigned i = 0; i < m_vec.size(); i++) { threads[i].join(); } DREAL_LOG_FATAL << "parallel: return UNSAT"; return; } if (s == pruning_thread_status::EXCEPTION) { DREAL_LOG_FATAL << "parallel: " << m_index << " got EXCEPTION"; lk.unlock(); for (unsigned i = 0; i < m_vec.size(); i++) { threads[i].join(); } DREAL_LOG_FATAL << "parallel: throw exception"; throw contractor_exception("exception during parallel contraction"); } } else { // if (s != pruning_thread_status::SAT) { // // DREAL_LOG_FATAL << "parallel: " << m_index << " got " << s; // // DREAL_LOG_FATAL << "parallel: " << m_index << " got " << statuses[m_index]; assert(s == pruning_thread_status::SAT); // } // if (threads[m_index].joinable()) { // threads[m_index].join(); // } // DREAL_LOG_FATAL << "parallel: " << m_index << " got SAT"; // Why? // - Not READY/RUNNING: It's a job already done. // - Not UNSAT/EXCEPTION: already handled above. // - Not KILLED: There must be one which kill the killed // job, and this loop stops after handling // the first one } } // Assertion: All of them got SAT // for (pruning_thread_status const & s : statuses) { // assert(s == pruning_thread_status::SAT); // } // DREAL_LOG_FATAL << "All of them are SAT"; b = boxes[0]; for (unsigned i = 0; i < m_vec.size(); i++) { contractor const & c = m_vec[i]; b.intersect(boxes[i]); m_input.union_with(c.input()); m_output.union_with(c.output()); unordered_set<shared_ptr<constraint>> const & used_ctrs = c.used_constraints(); m_used_constraints.insert(used_ctrs.begin(), used_ctrs.end()); if (b.is_empty()) { // DREAL_LOG_FATAL << "Found an empty while intersecting..."; for (unsigned i = 0; i < m_vec.size(); i++) { // if (threads[i].joinable()) { // DREAL_LOG_FATAL << "Try to join " << i << "..."; threads[i].join(); // DREAL_LOG_FATAL << "Try to join " << i << "... done"; // } } // DREAL_LOG_FATAL << "parallel: return UNSAT"; return; } } // DREAL_LOG_FATAL << "Intersection is nonempty exiting..."; for (unsigned i = 0; i < m_vec.size(); i++) { // if (threads[i].joinable()) { threads[i].join(); // } } // DREAL_LOG_FATAL << "parallel: return SAT"; return; }
void contractor_gsl::prune(box & b, SMTConfig & config) { // TODO(soonhok): add timeout fesetround(FE_TONEAREST); // Without this, GSL might cause a segmentation fault due to problems in floating point lib gsl_odeiv2_step_reset(m_step); gsl_odeiv2_evolve_reset(m_evolve); double const T_lb = b[m_time_t].lb(); double const T_ub = b[m_time_t].ub(); double t = 0.0, old_t = 0.0; /* initialize t */ double T_next = 0.0; double h = 1e-10; /* starting step size for ode solver */ DREAL_LOG_INFO << "GSL: prune begin " << m_time_t << " = [" << T_lb << ", " << T_ub << "]" << "\t" << b.max_diam(); DREAL_LOG_INFO << m_ctr->get_ic(); if (b.max_diam() < config.nra_precision) { return; } bool need_to_run = false; for (Enode * e : m_vars_0) { if (b[e].diam() > config.nra_precision) { need_to_run = true; break; } } if (b[m_time_t].diam() > config.nra_precision) { need_to_run = true; } if (!need_to_run) { return; } extract_sample_point(b, m_vars_0, m_values); extract_sample_point(b, m_pars_0, m_params); for (unsigned i = 0; i < m_vars_0.size(); i++) { b[m_vars_0[i]] = m_values[i]; } for (unsigned i = 0; i < m_pars_0.size(); i++) { b[m_pars_0[i]] = m_params[i]; } // First move to T_lb without checking m_values while (t < T_lb) { interruption_point(); T_next = T_lb; // T_next = min(t + config.nra_precision, T_lb); int status = gsl_odeiv2_evolve_apply(m_evolve, m_control, m_step, &m_system, &t, T_next, &h, m_values); if (status != GSL_SUCCESS) { DREAL_LOG_INFO << "GSL: error, return value " << status; throw contractor_exception("GSL FAILED"); } } // Now we're in the range in [T_lb, T_ub], need to check m_values. while (t < T_ub) { interruption_point(); T_next = min(t + config.nra_precision, T_ub); // T_next = T_ub; // Copy m_values to m_old_values, and t to old_t for (unsigned i = 0; i < m_dim; i++) { m_old_values[i] = m_values[i]; } old_t = t; int status = gsl_odeiv2_evolve_apply(m_evolve, m_control, m_step, &m_system, &t, T_next, &h, m_values); if (status != GSL_SUCCESS) { DREAL_LOG_INFO << "GSL: error, return value " << status; throw contractor_exception("GSL FAILED"); } // print_values(t, m_values, m_dim); /* print at t */ bool values_good = true; unsigned i = 0; for (Enode * e : m_vars_t) { double const old_v_i = m_old_values[i]; double const v_i = m_values[i]; auto iv = (old_v_i < v_i) ? ibex::Interval(old_v_i, v_i) : ibex::Interval(v_i, old_v_i); auto const & iv_X_t = b[e]; iv &= iv_X_t; if (iv.is_empty()) { values_good = false; DREAL_LOG_INFO << "GSL Not in Range: " << e << " : " << m_values[i] << " not in " << b[e] << " at t = " << t; break; } i++; } if (values_good) { thread_local static box old_box(b); old_box = b; // Update X_t with m_values i = 0; for (Enode * e : m_vars_t) { double const old_v_i = m_old_values[i]; double const v_i = m_values[i]; auto iv = (old_v_i < v_i) ? ibex::Interval(old_v_i, v_i) : ibex::Interval(v_i, old_v_i); auto const & iv_X_t = b[e]; iv &= iv_X_t; DREAL_LOG_INFO << "GSL Update: " << e << " : " << b[e] << " ==> " << iv; b[e] = iv; i++; } // Update Time with T double const new_t = t/2.0 + old_t/2.0; DREAL_LOG_INFO << "GSL Update: time: " << b[m_time_t] << " ==> " << new_t; b[m_time_t] = new_t; m_eval_ctc.prune(b, config); if (!b.is_empty()) { DREAL_LOG_INFO << "This box satisfies other non-linear constraints"; return; } else { DREAL_LOG_INFO << "This box failed to satisfy other non-linear constraints"; b = old_box; } } } DREAL_LOG_INFO << "GSL failed in the end"; throw contractor_exception("GSL failed"); }