@@ -30,7 +30,7 @@ namespace lp {
30
30
};
31
31
32
32
class int_solver ::imp {
33
- public:
33
+ public:
34
34
int_solver& lia;
35
35
lar_solver& lra;
36
36
lar_core_solver& lrac;
@@ -196,6 +196,8 @@ namespace lp {
196
196
return lia.settings ().dio_eqs () && m_number_of_calls % m_dioph_eq_period == 0 ;
197
197
}
198
198
199
+ // HNF
200
+
199
201
bool should_hnf_cut () {
200
202
return (!settings ().dio_eqs () || settings ().dio_enable_hnf_cuts ())
201
203
&& settings ().enable_hnf () && m_number_of_calls % settings ().hnf_cut_period () == 0 ;
@@ -210,6 +212,83 @@ namespace lp {
210
212
return r;
211
213
}
212
214
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
+
213
292
214
293
lia_move check (lp::explanation * e) {
215
294
SASSERT (lra.ax_is_correct ());
@@ -236,6 +315,7 @@ namespace lp {
236
315
if (r == lia_move::undef) r = patch_basic_columns ();
237
316
if (r == lia_move::undef && should_find_cube ()) r = int_cube (lia)();
238
317
if (r == lia_move::undef) lra.move_non_basic_columns_to_bounds ();
318
+ // if (r == lia_move::undef) r = tighten_bounds();
239
319
if (r == lia_move::undef && should_hnf_cut ()) r = hnf_cut ();
240
320
if (r == lia_move::undef && should_gomory_cut ()) r = gomory (lia).get_gomory_cuts (2 );
241
321
if (r == lia_move::undef && should_solve_dioph_eq ()) r = solve_dioph_eq ();
0 commit comments