Skip to content

Commit 9e8b17b

Browse files
committed
do not use conflicts with fresh vars to create branches
Signed-off-by: Lev Nachmanson <[email protected]>
1 parent eaf2f7f commit 9e8b17b

File tree

2 files changed

+64
-95
lines changed

2 files changed

+64
-95
lines changed

src/math/lp/dioph_eq.cpp

+63-95
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include "math/lp/lp_utils.h"
55
#include <list>
66
#include <queue>
7-
#include <util/heap.h>
7+
88
namespace lp {
99
// This class represents a term with an added constant number c, in form sum {x_i*a_i} + c.
1010
class dioph_eq::imp {
@@ -136,7 +136,7 @@ namespace lp {
136136
std::list<unsigned> m_f; // F = {λ(t):t in m_f}
137137
// set S
138138
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
140140
// gives the order of substitution
141141

142142
unsigned m_conflict_index = -1; // m_eprime[m_conflict_index] gives the conflict
@@ -159,7 +159,7 @@ namespace lp {
159159
m_report_branch = false;
160160
unsigned n_of_rows = lra.A_r().row_count();
161161
m_k2s.clear();
162-
m_k2s.resize(lra.column_count(), std::make_pair(-1,-1));
162+
m_k2s.resize(lra.column_count(), -1);
163163
m_conflict_index = -1;
164164
m_infeas_explanation.clear();
165165
lia.get_term().clear();
@@ -226,69 +226,60 @@ namespace lp {
226226
std::string var_str(unsigned j) {
227227
return std::string(is_fresh_var(j)? "~":"") + std::to_string(j);
228228
}
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+
229253
// 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,
231255
// it is needed by the next steps
256+
// the conflict can be used to report "cuts from proofs"
232257
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;);
236259
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());
239262
return true;
240263
}
241-
if (g.is_one())
242-
return true;
243264
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()) {
279267
for (auto& p: ep.m_e.coeffs()) {
280268
p.m_value /= g;
281269
}
282-
ep.m_e.c() = new_c;
270+
ep.m_e.c() = c_g;
283271
// 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;
289274
}
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+
291281
}
282+
292283
// returns true if no conflict is found and false otherwise
293284
bool normalize_by_gcd() {
294285
for (unsigned l: m_f) {
@@ -330,18 +321,18 @@ namespace lp {
330321
if (is_fresh_var(p.j())) {
331322
continue;
332323
}
333-
if (m_k2s[p.j()].first != null_lpvar)
324+
if (m_k2s[p.j()] != null_lpvar)
334325
q.push(p.j());
335326
}
336327

337328
}
338329

339330
const eprime_pair& k_th_entry(unsigned k) const {
340-
return m_eprime[m_k2s[k].first];
331+
return m_eprime[m_k2s[k]];
341332
}
342333

343334
const unsigned sub_index(unsigned k) const {
344-
return m_k2s[k].first;
335+
return m_k2s[k];
345336
}
346337

347338
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 {
387378
}
388379
return lia_move::undef;
389380
}
390-
void print_queue(std::queue<unsigned> q, std::ostream& out) {
381+
382+
std::ostream& print_queue(std::queue<unsigned> q, std::ostream& out) {
391383
out << "qu: ";
392384
while (!q.empty()) {
393385
out << q.front() << " ";
394386
q.pop();
395387
}
396388
out<< std::endl;
389+
return out;
397390
}
398391
// j is the index of the column representing a term
399392
// return true if there is a change
@@ -512,7 +505,7 @@ namespace lp {
512505
tout << "bound_dep:\n";print_dep(tout, dep) << std::endl;);
513506
}
514507

515-
lia_move check() {
508+
lia_move check() {
516509
init();
517510
while(m_f.size()) {
518511
if (!normalize_by_gcd()) {
@@ -624,7 +617,7 @@ namespace lp {
624617
auto & eh = e_pair.m_e;
625618
// xt is the fresh variable
626619
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;
628621
tout << "eh:"; print_term_o(eh,tout) << std::endl;);
629622
/* Let eh = sum (a_i*x_i) + c
630623
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 {
665658
// the term to eliminate the fresh variable
666659
term_o xt_subs = xt_term.clone();
667660
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;);
669662
m_sigma.insert(xt, xt_subs);
670663
}
671664

672665
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 << "\tm_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 << "\tm_e:") << "," << std::endl;
673+
print_dep(out<< "\tm_l:", e.m_l) << "\n";
676674
out << "}"<< std::endl;
677675
return out;
678676
}
679677

680678
// k is the index of the index of the variable with the coefficient +-1 that is being substituted
681679
void move_entry_from_f_to_s(unsigned k, std::list<unsigned>::iterator it) {
682680
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 );
684682
}
685683
m_s.push_back(*it);
686684
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;
688686
m_f.erase(it);
689687
}
690688

@@ -731,36 +729,6 @@ namespace lp {
731729
TRACE("dioph_eq", lra.print_expl(tout, ex););
732730
}
733731

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-
764732
bool is_fresh_var(unsigned j) const {
765733
return j >= lra.column_count();
766734
}

src/math/lp/lp_settings.h

+1
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ struct statistics {
161161
st.update("arith-nla-lemmas", m_nla_lemmas);
162162
st.update("arith-nra-calls", m_nra_calls);
163163
st.update("arith-bounds-improvements", m_nla_bounds_improvements);
164+
st.update("arith-lp-dio-conflicts", m_dio_conflicts);
164165
st.copy(m_st);
165166
}
166167
};

0 commit comments

Comments
 (0)