@@ -30,7 +30,7 @@ namespace lp {
3030 };
3131
3232 class int_solver ::imp {
33- public:
33+ public:
3434 int_solver& lia;
3535 lar_solver& lra;
3636 lar_core_solver& lrac;
@@ -196,6 +196,8 @@ namespace lp {
196196 return lia.settings ().dio_eqs () && m_number_of_calls % m_dioph_eq_period == 0 ;
197197 }
198198
199+ // HNF
200+
199201 bool should_hnf_cut () {
200202 return (!settings ().dio_eqs () || settings ().dio_enable_hnf_cuts ())
201203 && settings ().enable_hnf () && m_number_of_calls % settings ().hnf_cut_period () == 0 ;
@@ -210,6 +212,83 @@ namespace lp {
210212 return r;
211213 }
212214
215+ // Tighten bounds
216+ // expose at level of lar_solver so it can be invoked by theory_lra after back-jumping
217+ // consider multi-round bound tightnening as well and deal with divergence issues.
218+ lia_move tighten_bounds () {
219+
220+ struct bound_consumer {
221+ imp& i;
222+ bound_consumer (imp& i) : i(i) {}
223+ lar_solver& lp () { return i.lra ; }
224+ bool bound_is_interesting (unsigned vi, lp::lconstraint_kind kind, const rational& bval) const { return true ; }
225+ bool add_eq (lpvar u, lpvar v, lp::explanation const & e, bool is_fixed) { return false ; }
226+ };
227+ bound_consumer bc (*this );
228+ std_vector<implied_bound> ibounds;
229+ lp_bound_propagator<bound_consumer> bp (bc, ibounds);
230+ bp.init ();
231+
232+ unsigned num_refined_bounds = 0 ;
233+
234+ auto set_conflict = [&](unsigned j, u_dependency * d1, u_dependency * d2) {
235+ ++settings ().stats ().m_bounds_tightening_conflicts ;
236+ for (auto e : lra.flatten (d1))
237+ m_ex->push_back (e);
238+ for (auto e : lra.flatten (d2))
239+ m_ex->push_back (e);
240+ };
241+
242+ auto refine_bound = [&](implied_bound const & ib) {
243+ unsigned j = ib.m_j ;
244+ auto const & bound = ib.m_bound ;
245+ if (!lra.column_is_int (j)) // for now, ignore non-integers.
246+ return l_undef;
247+ if (ib.m_is_lower_bound ) {
248+ if (lra.column_has_lower_bound (j) && lra.column_lower_bound (j) >= bound)
249+ return l_undef;
250+ auto d = ib.explain_implied ();
251+ if (lra.column_has_upper_bound (j) && lra.column_upper_bound (j) < ceil (bound)) {
252+ set_conflict (j, d, lra.get_column_upper_bound_witness (j));
253+ return l_false;
254+ }
255+
256+ lra.update_column_type_and_bound (j, lconstraint_kind::GE, ceil (bound), d);
257+ ++num_refined_bounds;
258+ } else {
259+ if (lra.column_has_upper_bound (j) && lra.column_upper_bound (j) <= bound)
260+ return l_undef;
261+ auto d = ib.explain_implied ();
262+ if (lra.column_has_lower_bound (j) && lra.column_lower_bound (j) > floor (bound)) {
263+ set_conflict (j, d, lra.get_column_lower_bound_witness (j));
264+ return l_false;
265+ }
266+
267+ lra.update_column_type_and_bound (j, lconstraint_kind::LE, floor (bound), d);
268+ ++num_refined_bounds;
269+ }
270+ return l_true;
271+ };
272+
273+ for (unsigned row_index = 0 ; row_index < lra.row_count (); ++row_index) {
274+ auto nb = bound_analyzer_on_row<row_strip<mpq>, lp_bound_propagator<bound_consumer>>::analyze_row (
275+ lra.A_r ().m_rows [row_index],
276+ null_ci,
277+ zero_of_type<numeric_pair<mpq>>(),
278+ row_index,
279+ bp);
280+
281+ settings ().stats ().m_bounds_tightenings += static_cast <unsigned >(ibounds.size ());
282+ for (auto const & ib : ibounds)
283+ if (l_false == refine_bound (ib))
284+ return lia_move::conflict;
285+ ibounds.clear ();
286+ }
287+
288+ verbose_stream () << num_refined_bounds << " \n " ;
289+ return num_refined_bounds > 0 ? lia_move::continue_with_check : lia_move::undef;
290+ }
291+
213292
214293 lia_move check (lp::explanation * e) {
215294 SASSERT (lra.ax_is_correct ());
@@ -236,6 +315,7 @@ namespace lp {
236315 if (r == lia_move::undef) r = patch_basic_columns ();
237316 if (r == lia_move::undef && should_find_cube ()) r = int_cube (lia)();
238317 if (r == lia_move::undef) lra.move_non_basic_columns_to_bounds ();
318+ // if (r == lia_move::undef) r = tighten_bounds();
239319 if (r == lia_move::undef && should_hnf_cut ()) r = hnf_cut ();
240320 if (r == lia_move::undef && should_gomory_cut ()) r = gomory (lia).get_gomory_cuts (2 );
241321 if (r == lia_move::undef && should_solve_dioph_eq ()) r = solve_dioph_eq ();
0 commit comments