4
4
#include " math/lp/lp_utils.h"
5
5
#include < list>
6
6
#include < queue>
7
- # include < util/heap.h >
7
+
8
8
namespace lp {
9
9
// This class represents a term with an added constant number c, in form sum {x_i*a_i} + c.
10
10
class dioph_eq ::imp {
@@ -136,7 +136,7 @@ namespace lp {
136
136
std::list<unsigned > m_f; // F = {λ(t):t in m_f}
137
137
// set S
138
138
std::list<unsigned > m_s; // S = {λ(t): t in m_s}
139
- vector<std::pair< unsigned , unsigned > > m_k2s; // k is substituted by using equation in m_eprime[m_k2s[k].first] and m_k2s[k].second
139
+ vector<unsigned > m_k2s; // k is substituted by using equation in m_eprime[m_k2s[k].first] and m_k2s[k].second
140
140
// gives the order of substitution
141
141
142
142
unsigned m_conflict_index = -1 ; // m_eprime[m_conflict_index] gives the conflict
@@ -159,7 +159,7 @@ namespace lp {
159
159
m_report_branch = false ;
160
160
unsigned n_of_rows = lra.A_r ().row_count ();
161
161
m_k2s.clear ();
162
- m_k2s.resize (lra.column_count (), std::make_pair (- 1 ,- 1 ) );
162
+ m_k2s.resize (lra.column_count (), - 1 );
163
163
m_conflict_index = -1 ;
164
164
m_infeas_explanation.clear ();
165
165
lia.get_term ().clear ();
@@ -226,69 +226,60 @@ namespace lp {
226
226
std::string var_str (unsigned j) {
227
227
return std::string (is_fresh_var (j)? " ~" :" " ) + std::to_string (j);
228
228
}
229
+
230
+ bool has_fresh_var (const term_o & t) const {
231
+ for (const auto & p: t) {
232
+ if (is_fresh_var (p.j ()))
233
+ return true ;
234
+ }
235
+ return false ;
236
+ }
237
+
238
+ void prepare_lia_branch_report (const term_o & e, const mpq& g, const mpq new_c) {
239
+ /* We have ep.m_e/g = 0, or sum((coff_i/g)*x_i) + new_c = 0,
240
+ or sum((coeff_i/g)*x_i) = -new_c, where new_c is not an integer
241
+ Then sum((coeff_i/g)*x_i) <= floor(-new_c) or sum((coeff_i/g)*x_i) >= ceil(-new_c)
242
+ */
243
+ lar_term& t = lia.get_term ();
244
+ for (const auto & p: e) {
245
+ t.add_monomial (p.coeff ()/g, p.j ());
246
+ }
247
+ lia.offset () = floor (-new_c);
248
+ lia.is_upper () = true ;
249
+ m_report_branch = true ;
250
+ TRACE (" dioph_eq" , tout << " prepare branch:" ; print_lar_term_L (t, tout) << " <= " << lia.offset () << std::endl;);
251
+ }
252
+
229
253
// returns true if no conflict is found and false otherwise
230
- // this function devides all cooficients, and the free constant, of the ep.m_e by the gcd of all coefficients,
254
+ // this function devides all cooficients, and the free constant, of the ep.m_e by the gcd of all coefficients,
231
255
// it is needed by the next steps
256
+ // the conflict can be used to report "cuts from proofs"
232
257
bool normalize_e_by_gcd (eprime_pair& ep) {
233
- TRACE (" dioph_eq" , print_term_o (ep.m_e , tout << " m_e:" ) << std::endl;
234
- print_dep (tout << " m_l:" , ep.m_l ) << std::endl;
235
- );
258
+ TRACE (" dioph_eq" , print_eprime_entry (ep, tout) << std::endl;);
236
259
mpq g = gcd_of_coeffs (ep.m_e );
237
- if (g.is_zero ()) {
238
- SASSERT (ep.m_e .c ().is_zero ());
260
+ if (g.is_zero () || g. is_one () ) {
261
+ SASSERT (g. is_one () || ep.m_e .c ().is_zero ());
239
262
return true ;
240
263
}
241
- if (g.is_one ())
242
- return true ;
243
264
TRACE (" dioph_eq" , tout << " g:" << g << std::endl;);
244
- mpq new_c = ep.m_e .c () / g;
245
- if (!new_c.is_int ()) {
246
- TRACE (" dioph_eq" ,
247
- print_term_o (ep.m_e , tout << " conflict m_e:" ) << std::endl;
248
- tout << " g:" << g << std::endl;
249
- print_dep (tout << " m_l:" , ep.m_l ) << std::endl;
250
- tout << " S:\n " ;
251
- for (const auto & t : m_sigma) {
252
- tout << " x" << var_str (t.m_key ) << " -> " ;
253
- print_term_o (t.m_value , tout) << std::endl;
254
- }
255
- );
256
- /* We have ep.m_e/g = 0, or sum((coff_i/g)*x_i) + new_c = 0,
257
- or sum((coeff_i/g)*x_i) = -new_c, where new_c is not an integer
258
- Then sum((coeff_i/g)*x_i) <= floor(-new_c) or sum((coeff_i/g)*x_i) >= ceil(-new_c)
259
- */
260
- if (lra.settings ().stats ().m_dio_conflicts % lra.settings ().dio_cut_from_proof_period () == 0 ) {
261
- bool has_fresh = false ;
262
- for (const auto & p : ep.m_e )
263
- if ((has_fresh = is_fresh_var (p.j ())))
264
- break ;
265
- if (!has_fresh) { // consider remove all fresh variables in a copy of m_e and report the conflict
266
- // prepare int_solver for reporting
267
- lar_term& t = lia.get_term ();
268
- for (const auto & p: ep.m_e ) {
269
- t.add_monomial (p.coeff ()/g, p.j ());
270
- }
271
- lia.offset () = floor (-new_c);
272
- lia.is_upper () = true ;
273
- m_report_branch = true ;
274
- TRACE (" dioph_eq" , tout << " prepare branch:" ; print_lar_term_L (t, tout) << " <= " << lia.offset () << std::endl;);
275
- }
276
- }
277
- return false ;
278
- } else {
265
+ mpq c_g = ep.m_e .c () / g;
266
+ if (c_g.is_int ()) {
279
267
for (auto & p: ep.m_e .coeffs ()) {
280
268
p.m_value /= g;
281
269
}
282
- ep.m_e .c () = new_c ;
270
+ ep.m_e .c () = c_g ;
283
271
// ep.m_l *= (1/g);
284
- TRACE (" dioph_eq" ,
285
- tout << " ep_m_e:" ; print_term_o (ep.m_e , tout) << std::endl;
286
- tout << " ep.ml:" ;
287
- print_dep (tout, ep.m_l ) << std::endl;);
288
-
272
+ TRACE (" dioph_eq" , tout << " ep_m_e:" ; print_eprime_entry (ep, tout) << std::endl;);
273
+ return true ;
289
274
}
290
- return true ;
275
+ // c_g is not integral
276
+ if (lra.settings ().stats ().m_dio_conflicts % lra.settings ().dio_cut_from_proof_period () == 0 &&
277
+ !has_fresh_var (ep.m_e ))
278
+ prepare_lia_branch_report (ep.m_e , g, c_g);
279
+ return false ;
280
+
291
281
}
282
+
292
283
// returns true if no conflict is found and false otherwise
293
284
bool normalize_by_gcd () {
294
285
for (unsigned l: m_f) {
@@ -330,18 +321,18 @@ namespace lp {
330
321
if (is_fresh_var (p.j ())) {
331
322
continue ;
332
323
}
333
- if (m_k2s[p.j ()]. first != null_lpvar)
324
+ if (m_k2s[p.j ()] != null_lpvar)
334
325
q.push (p.j ());
335
326
}
336
327
337
328
}
338
329
339
330
const eprime_pair& k_th_entry (unsigned k) const {
340
- return m_eprime[m_k2s[k]. first ];
331
+ return m_eprime[m_k2s[k]];
341
332
}
342
333
343
334
const unsigned sub_index (unsigned k) const {
344
- return m_k2s[k]. first ;
335
+ return m_k2s[k];
345
336
}
346
337
347
338
void substitude_term_on_q_with_S_for_tightening (std::queue<unsigned > &q, term_o& t, u_dependency* &dep) {
@@ -387,13 +378,15 @@ namespace lp {
387
378
}
388
379
return lia_move::undef;
389
380
}
390
- void print_queue (std::queue<unsigned > q, std::ostream& out) {
381
+
382
+ std::ostream& print_queue (std::queue<unsigned > q, std::ostream& out) {
391
383
out << " qu: " ;
392
384
while (!q.empty ()) {
393
385
out << q.front () << " " ;
394
386
q.pop ();
395
387
}
396
388
out<< std::endl;
389
+ return out;
397
390
}
398
391
// j is the index of the column representing a term
399
392
// return true if there is a change
@@ -512,7 +505,7 @@ namespace lp {
512
505
tout << " bound_dep:\n " ;print_dep (tout, dep) << std::endl;);
513
506
}
514
507
515
- lia_move check () {
508
+ lia_move check () {
516
509
init ();
517
510
while (m_f.size ()) {
518
511
if (!normalize_by_gcd ()) {
@@ -624,7 +617,7 @@ namespace lp {
624
617
auto & eh = e_pair.m_e ;
625
618
// xt is the fresh variable
626
619
unsigned xt = m_last_fresh_x_var++;
627
- TRACE (" dioph_eq" , tout << " introduce fresh xt:" << " ~ x" << fresh_index (xt) << std::endl;
620
+ TRACE (" dioph_eq" , tout << " introduce fresh xt:" << " x" << var_str (xt) << std::endl;
628
621
tout << " eh:" ; print_term_o (eh,tout) << std::endl;);
629
622
/* Let eh = sum (a_i*x_i) + c
630
623
For each i != k, let a_i = a_qi*ahk + a_ri, and let c = c_q * ahk + c_r
@@ -665,26 +658,31 @@ namespace lp {
665
658
// the term to eliminate the fresh variable
666
659
term_o xt_subs = xt_term.clone ();
667
660
xt_subs.add_monomial (mpq (1 ), xt);
668
- TRACE (" dioph_eq" , tout << " xt_subs: x~ " << fresh_index (xt) << " -> " ; print_term_o (xt_subs, tout) << std::endl;);
661
+ TRACE (" dioph_eq" , tout << " xt_subs: x" << var_str (xt) << " -> " ; print_term_o (xt_subs, tout) << std::endl;);
669
662
m_sigma.insert (xt, xt_subs);
670
663
}
671
664
672
665
std::ostream& print_eprime_entry (unsigned i, std::ostream& out) {
673
- out << " m_eprime[" << i << " ]:{\n " ;
674
- print_term_o (m_eprime[i].m_e , out << " \t m_e:" ) << " ," << std::endl;
675
- // print_dep(out<< "\tm_l:", m_eprime[i].m_l) << "\n"
666
+ out << " m_eprime[" << i << " ]:" ;
667
+ return print_eprime_entry (m_eprime[i], out);
668
+ }
669
+
670
+ std::ostream& print_eprime_entry (const eprime_pair& e, std::ostream& out) {
671
+ out << " {\n " ;
672
+ print_term_o (e.m_e , out << " \t m_e:" ) << " ," << std::endl;
673
+ print_dep (out<< " \t m_l:" , e.m_l ) << " \n " ;
676
674
out << " }" << std::endl;
677
675
return out;
678
676
}
679
677
680
678
// k is the index of the index of the variable with the coefficient +-1 that is being substituted
681
679
void move_entry_from_f_to_s (unsigned k, std::list<unsigned >::iterator it) {
682
680
if (k >= m_k2s.size ()) { // k is a fresh variable
683
- m_k2s.resize (k+1 , std::make_pair (- 1 ,- 1 ) );
681
+ m_k2s.resize (k+1 , - 1 );
684
682
}
685
683
m_s.push_back (*it);
686
684
TRACE (" dioph_eq" , tout << " removed " << *it << " th entry from F" << std::endl;);
687
- m_k2s[k] = std::make_pair ( *it, static_cast < unsigned >(m_s. size ()));
685
+ m_k2s[k] = *it;
688
686
m_f.erase (it);
689
687
}
690
688
@@ -731,36 +729,6 @@ namespace lp {
731
729
TRACE (" dioph_eq" , lra.print_expl (tout, ex););
732
730
}
733
731
734
- unsigned fresh_index (unsigned j) const {return UINT_MAX - j;}
735
- struct subs_lt {
736
- const vector<std::pair<unsigned , unsigned >> & m_order;
737
- subs_lt (const vector<std::pair<unsigned , unsigned >>& order) : m_order(order){}
738
- bool operator ()(unsigned v1, unsigned v2) const {
739
- return m_order[v1].second < m_order[v2].second ;
740
- }
741
- };
742
-
743
- void remove_fresh_variables (term_o& t) {
744
- heap<subs_lt> q (static_cast <int >(lra.column_count ()), subs_lt (m_k2s));
745
- for (auto p : t) {
746
- if (is_fresh_var (p.j ())) {
747
- q.insert (p.j ());
748
- }
749
- }
750
- CTRACE (" dioph_eq_fresh" , q.empty () == false , print_term_o (t, tout)<< std::endl);
751
- while (!q.empty ()) {
752
- unsigned j = q.erase_min ();
753
- const term_o& sub_t = m_sigma.find (j);
754
- TRACE (" dioph_eq_fresh" , tout << " x~" << fresh_index (j) << " ; sub_t:" ; print_term_o (sub_t , tout) << std::endl;);
755
- t.substitute_var_with_term (sub_t , j);
756
- TRACE (" dioph_eq_fresh" , tout << " sub_t:" ; print_term_o (sub_t , tout) << std::endl;
757
- tout << " after sub:" ;print_term_o (t, tout) << std::endl;);
758
- for (auto p : sub_t )
759
- if (is_fresh_var (p.j ()))
760
- q.insert (p.j ());
761
- }
762
- }
763
-
764
732
bool is_fresh_var (unsigned j) const {
765
733
return j >= lra.column_count ();
766
734
}
0 commit comments