mirror of
https://github.com/Z3Prover/z3
synced 2025-04-14 21:08:46 +00:00
remove warnings in scaler and use m_cut_solver_cycle_on_var
Signed-off-by: Lev Nachmanson <levnach@hotmail.com> detect slow propagations Signed-off-by: Lev Nachmanson <levnach@hotmail.com> fiddle with the stop conditions Signed-off-by: Lev Nachmanson <levnach@hotmail.com> get rid of constraint->m_predecessors, fix a bug in push/pop with lemmas Signed-off-by: Lev Nachmanson <levnach@hotmail.com> clean detection of stale lemmas in pop Signed-off-by: Lev Nachmanson <levnach@hotmail.com> add constraints lazily to cut_solver Signed-off-by: Lev Nachmanson <levnach@hotmail.com> refactor some of cut_solver classes into include files Signed-off-by: Lev Nachmanson <levnach@hotmail.com> prepare to index constraint from 0 to to n - 1, where n is the number of constraints Signed-off-by: Lev Nachmanson <levnach@hotmail.com> prepare for constraint priority Signed-off-by: Lev Nachmanson <levnach@hotmail.com> use priorities in active_set Signed-off-by: Lev Nachmanson <levnach@hotmail.com> remove unnecesessary parameters Signed-off-by: Lev Nachmanson <levnach@hotmail.com> speedup bound propagations Signed-off-by: Lev Nachmanson <levnach@hotmail.com> restore tactics Signed-off-by: Lev Nachmanson <levnach@hotmail.com> speedup bound propagation by avoiding some calls to propagate_constraint_only_one_unlim Signed-off-by: Lev Nachmanson <levnach@hotmail.com> fixes by Nikolaj Signed-off-by: Lev Nachmanson <levnach@hotmail.com> fix print lp_core_solver Signed-off-by: Lev Nachmanson <levnach@hotmail.com> work on gomory test, subs terms indices correctly Signed-off-by: Lev Nachmanson <levnach@hotmail.com> correct const_iterator for lar_term Signed-off-by: Lev Nachmanson <levnach@hotmail.com> improve static_matrix with iterators Signed-off-by: Lev Nachmanson <levnach@hotmail.com> make row_strip a struct Signed-off-by: Lev Nachmanson <levnach@hotmail.com> move row_strip outside of static_matrix Signed-off-by: Lev Nachmanson <levnach@hotmail.com> add const_iterator to row_strip Signed-off-by: Lev Nachmanson <levnach@hotmail.com> remove the hierarchy of iterators - use std::iterators Signed-off-by: Lev Nachmanson <levnach@hotmail.com> adding gcd_test stats and taking care of for iterators Signed-off-by: Lev Nachmanson <levnach@hotmail.com> restore qflia_tactic.cpp Signed-off-by: Lev Nachmanson <levnach@hotmail.com> run gcd_test according to settings() Signed-off-by: Lev Nachmanson <levnach@hotmail.com> experiment with picking a narrow or random branch Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
This commit is contained in:
parent
6202b2f2e4
commit
2bb94ed4fe
|
@ -307,7 +307,7 @@ class theory_lra::imp {
|
|||
m_solver->settings().bound_propagation() = BP_NONE != propagation_mode();
|
||||
m_solver->set_track_pivoted_rows(lp.bprop_on_pivoted_rows());
|
||||
m_solver->settings().m_int_branch_cut_gomory_threshold = ctx().get_fparams().m_arith_branch_cut_ratio;
|
||||
m_solver->settings().m_int_branch_cut_solver = std::max(4u, ctx().get_fparams().m_arith_branch_cut_ratio);
|
||||
m_solver->settings().m_int_branch_cut_solver = std::max(8u, ctx().get_fparams().m_arith_branch_cut_ratio);
|
||||
m_solver->settings().m_run_gcd_test = ctx().get_fparams().m_arith_gcd_test;
|
||||
m_solver->settings().set_random_seed(ctx().get_fparams().m_random_seed);
|
||||
//m_solver->settings().set_ostream(0);
|
||||
|
@ -672,6 +672,10 @@ class theory_lra::imp {
|
|||
}
|
||||
|
||||
theory_var internalize_def(app* term, scoped_internalize_state& st) {
|
||||
if (ctx().e_internalized(term)) {
|
||||
IF_VERBOSE(0, verbose_stream() << "repeated term\n";);
|
||||
return mk_var(term, false);
|
||||
}
|
||||
linearize_term(term, st);
|
||||
if (is_unit_var(st)) {
|
||||
return st.vars()[0];
|
||||
|
@ -1252,17 +1256,21 @@ public:
|
|||
}
|
||||
|
||||
// create a bound atom representing term <= k
|
||||
app_ref mk_bound(lp::lar_term const& term, rational const& k) {
|
||||
app_ref mk_bound(lp::lar_term const& term, rational const& k, bool lower_bound) {
|
||||
app_ref t = mk_term(term, k.is_int());
|
||||
app_ref atom(a.mk_le(t, a.mk_numeral(k, k.is_int())), m);
|
||||
app_ref atom(m);
|
||||
if (lower_bound) {
|
||||
atom = a.mk_ge(t, a.mk_numeral(k, k.is_int()));
|
||||
}
|
||||
else {
|
||||
atom = a.mk_le(t, a.mk_numeral(k, k.is_int()));
|
||||
}
|
||||
expr_ref atom1(m);
|
||||
proof_ref atomp(m);
|
||||
ctx().get_rewriter()(atom, atom1, atomp);
|
||||
atom = to_app(atom1);
|
||||
TRACE("arith", tout << atom << "\n";
|
||||
m_solver->print_term(term, tout << "bound atom: "); tout << " <= " << k << "\n";
|
||||
display(tout);
|
||||
);
|
||||
m_solver->print_term(term, tout << "bound atom: "); tout << " <= " << k << "\n";);
|
||||
ctx().internalize(atom, true);
|
||||
ctx().mark_as_relevant(atom.get());
|
||||
return atom;
|
||||
|
@ -1276,12 +1284,15 @@ public:
|
|||
lp::lar_term term;
|
||||
lp::mpq k;
|
||||
lp::explanation ex; // TBD, this should be streamlined accross different explanations
|
||||
switch(m_lia->check(term, k, ex)) {
|
||||
bool upper;
|
||||
switch(m_lia->check(term, k, ex, upper)) {
|
||||
case lp::lia_move::ok:
|
||||
return l_true;
|
||||
case lp::lia_move::branch: {
|
||||
(void)mk_bound(term, k);
|
||||
app_ref b = mk_bound(term, k, upper);
|
||||
// branch on term >= k + 1
|
||||
// branch on term <= k
|
||||
// TBD: ctx().force_phase(ctx().get_literal(b));
|
||||
// at this point we have a new unassigned atom that the
|
||||
// SAT core assigns a value to
|
||||
return l_false;
|
||||
|
@ -1289,7 +1300,7 @@ public:
|
|||
case lp::lia_move::cut: {
|
||||
++m_stats.m_gomory_cuts;
|
||||
// m_explanation implies term <= k
|
||||
app_ref b = mk_bound(term, k);
|
||||
app_ref b = mk_bound(term, k, upper);
|
||||
m_eqs.reset();
|
||||
m_core.reset();
|
||||
m_params.reset();
|
||||
|
@ -1298,7 +1309,11 @@ public:
|
|||
set_evidence(ev.second);
|
||||
}
|
||||
}
|
||||
assign(literal(ctx().get_bool_var(b), false));
|
||||
literal lit(ctx().get_bool_var(b), false);
|
||||
TRACE("arith",
|
||||
ctx().display_lemma_as_smt_problem(tout << "new cut:\n", m_core.size(), m_core.c_ptr(), m_eqs.size(), m_eqs.c_ptr(), lit);
|
||||
display(tout););
|
||||
assign(lit);
|
||||
return l_false;
|
||||
}
|
||||
case lp::lia_move::conflict:
|
||||
|
@ -2725,6 +2740,8 @@ public:
|
|||
if (m_solver) {
|
||||
m_solver->print_constraints(out);
|
||||
m_solver->print_terms(out);
|
||||
// auto pp = lp ::core_solver_pretty_printer<lp::mpq, lp::impq>(m_solver->m_mpq_lar_core_solver.m_r_solver, out);
|
||||
// pp.print();
|
||||
}
|
||||
unsigned nv = th.get_num_vars();
|
||||
for (unsigned v = 0; v < nv; ++v) {
|
||||
|
@ -2793,6 +2810,8 @@ public:
|
|||
st.update("cut_solver-true", m_solver->settings().st().m_cut_solver_true);
|
||||
st.update("cut_solver-false", m_solver->settings().st().m_cut_solver_false);
|
||||
st.update("cut_solver-undef", m_solver->settings().st().m_cut_solver_undef);
|
||||
st.update("gcd_calls", m_solver->settings().st().m_gcd_calls);
|
||||
st.update("gcd_conflict", m_solver->settings().st().m_gcd_conflicts);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
236
src/test/lp/gomory_test.h
Normal file
236
src/test/lp/gomory_test.h
Normal file
|
@ -0,0 +1,236 @@
|
|||
namespace lp {
|
||||
struct gomory_test {
|
||||
gomory_test(
|
||||
std::function<std::string (unsigned)> name_function_p,
|
||||
std::function<mpq (unsigned)> get_value_p,
|
||||
std::function<bool (unsigned)> at_low_p,
|
||||
std::function<bool (unsigned)> at_upper_p,
|
||||
std::function<impq (unsigned) > lower_bound_p,
|
||||
std::function<impq (unsigned) > upper_bound_p,
|
||||
std::function<unsigned (unsigned) > column_lower_bound_constraint_p,
|
||||
std::function<unsigned (unsigned) > column_upper_bound_constraint_p
|
||||
) :
|
||||
m_name_function(name_function_p),
|
||||
get_value(get_value_p),
|
||||
at_low(at_low_p),
|
||||
at_upper(at_upper_p),
|
||||
lower_bound(lower_bound_p),
|
||||
upper_bound(upper_bound_p),
|
||||
column_lower_bound_constraint(column_lower_bound_constraint_p),
|
||||
column_upper_bound_constraint(column_upper_bound_constraint_p)
|
||||
{}
|
||||
|
||||
std::function<std::string (unsigned)> m_name_function;
|
||||
std::function<mpq (unsigned)> get_value;
|
||||
std::function<bool (unsigned)> at_low;
|
||||
std::function<bool (unsigned)> at_upper;
|
||||
std::function<impq (unsigned) > lower_bound;
|
||||
std::function<impq (unsigned) > upper_bound;
|
||||
std::function<unsigned (unsigned) > column_lower_bound_constraint;
|
||||
std::function<unsigned (unsigned) > column_upper_bound_constraint;
|
||||
|
||||
bool is_real(unsigned) { return false; } // todo: test real case
|
||||
void print_row(std::ostream& out, vector<std::pair<mpq, unsigned>> & row ) {
|
||||
bool first = true;
|
||||
for (const auto & it : row) {
|
||||
auto val = it.first;
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
if (numeric_traits<mpq>::is_pos(val)) {
|
||||
out << " + ";
|
||||
} else {
|
||||
out << " - ";
|
||||
val = -val;
|
||||
}
|
||||
}
|
||||
if (val == -numeric_traits<mpq>::one())
|
||||
out << " - ";
|
||||
else if (val != numeric_traits<mpq>::one())
|
||||
out << T_to_string(val);
|
||||
|
||||
out << m_name_function(it.second);
|
||||
}
|
||||
}
|
||||
|
||||
void real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& pol, explanation & expl, const mpq& f_0, const mpq& one_minus_f_0) {
|
||||
TRACE("gomory_cut_detail_real", tout << "real\n";);
|
||||
mpq new_a;
|
||||
if (at_low(x_j)) {
|
||||
if (a.is_pos()) {
|
||||
new_a = a / (1 - f_0);
|
||||
}
|
||||
else {
|
||||
new_a = a / f_0;
|
||||
new_a.neg();
|
||||
}
|
||||
k.addmul(new_a, lower_bound(x_j).x); // is it a faster operation than
|
||||
// k += lower_bound(x_j).x * new_a;
|
||||
expl.push_justification(column_lower_bound_constraint(x_j), new_a);
|
||||
}
|
||||
else {
|
||||
lp_assert(at_upper(x_j));
|
||||
if (a.is_pos()) {
|
||||
new_a = a / f_0;
|
||||
new_a.neg(); // the upper terms are inverted.
|
||||
}
|
||||
else {
|
||||
new_a = a / (mpq(1) - f_0);
|
||||
}
|
||||
k.addmul(new_a, upper_bound(x_j).x); // k += upper_bound(x_j).x * new_a;
|
||||
expl.push_justification(column_upper_bound_constraint(x_j), new_a);
|
||||
}
|
||||
TRACE("gomory_cut_detail_real", tout << a << "*v" << x_j << " k: " << k << "\n";);
|
||||
pol.add_monomial(new_a, x_j);
|
||||
}
|
||||
|
||||
void int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term & t, explanation& expl, mpq & lcm_den, const mpq& f_0, const mpq& one_minus_f_0) {
|
||||
lp_assert(is_int(x_j));
|
||||
lp_assert(!a.is_int());
|
||||
lp_assert(f_0 > zero_of_type<mpq>() && f_0 < one_of_type<mpq>());
|
||||
mpq f_j = int_solver::fractional_part(a);
|
||||
TRACE("gomory_cut_detail",
|
||||
tout << a << " x_j = " << x_j << ", k = " << k << "\n";
|
||||
tout << "f_j: " << f_j << "\n";
|
||||
tout << "f_0: " << f_0 << "\n";
|
||||
tout << "1 - f_0: " << one_minus_f_0 << "\n";
|
||||
tout << "at_low(" << x_j << ") = " << at_low(x_j) << std::endl;
|
||||
);
|
||||
lp_assert (!f_j.is_zero());
|
||||
mpq new_a;
|
||||
if (at_low(x_j)) {
|
||||
if (f_j <= one_minus_f_0) {
|
||||
new_a = f_j / one_minus_f_0;
|
||||
}
|
||||
else {
|
||||
new_a = (1 - f_j) / f_0;
|
||||
}
|
||||
k.addmul(new_a, lower_bound(x_j).x);
|
||||
expl.push_justification(column_lower_bound_constraint(x_j), new_a);
|
||||
}
|
||||
else {
|
||||
lp_assert(at_upper(x_j));
|
||||
if (f_j <= f_0) {
|
||||
new_a = f_j / f_0;
|
||||
}
|
||||
else {
|
||||
new_a = (mpq(1) - f_j) / (one_minus_f_0);
|
||||
}
|
||||
new_a.neg(); // the upper terms are inverted
|
||||
k.addmul(new_a, upper_bound(x_j).x);
|
||||
expl.push_justification(column_upper_bound_constraint(x_j), new_a);
|
||||
}
|
||||
TRACE("gomory_cut_detail", tout << "new_a: " << new_a << " k: " << k << "\n";);
|
||||
t.add_monomial(new_a, x_j);
|
||||
lcm_den = lcm(lcm_den, denominator(new_a));
|
||||
}
|
||||
|
||||
|
||||
void report_conflict_from_gomory_cut(mpq &k) {
|
||||
lp_assert(false);
|
||||
}
|
||||
|
||||
void adjust_term_and_k_for_some_ints_case_gomory(lar_term& t, mpq& k, mpq &lcm_den) {
|
||||
lp_assert(!t.is_empty());
|
||||
auto pol = t.coeffs_as_vector();
|
||||
t.clear();
|
||||
if (pol.size() == 1) {
|
||||
TRACE("gomory_cut_detail", tout << "pol.size() is 1" << std::endl;);
|
||||
unsigned v = pol[0].second;
|
||||
lp_assert(is_int(v));
|
||||
const mpq& a = pol[0].first;
|
||||
k /= a;
|
||||
if (a.is_pos()) { // we have av >= k
|
||||
if (!k.is_int())
|
||||
k = ceil(k);
|
||||
// switch size
|
||||
t.add_monomial(- mpq(1), v);
|
||||
k.neg();
|
||||
} else {
|
||||
if (!k.is_int())
|
||||
k = floor(k);
|
||||
t.add_monomial(mpq(1), v);
|
||||
}
|
||||
} else {
|
||||
TRACE("gomory_cut_detail", tout << "pol.size() > 1" << std::endl;);
|
||||
lcm_den = lcm(lcm_den, denominator(k));
|
||||
TRACE("gomory_cut_detail", tout << "k: " << k << " lcm_den: " << lcm_den << "\n";
|
||||
for (unsigned i = 0; i < pol.size(); i++) {
|
||||
tout << pol[i].first << " " << pol[i].second << "\n";
|
||||
}
|
||||
tout << "k: " << k << "\n";);
|
||||
lp_assert(lcm_den.is_pos());
|
||||
if (!lcm_den.is_one()) {
|
||||
// normalize coefficients of integer parameters to be integers.
|
||||
for (auto & pi: pol) {
|
||||
pi.first *= lcm_den;
|
||||
SASSERT(!is_int(pi.second) || pi.first.is_int());
|
||||
}
|
||||
k *= lcm_den;
|
||||
}
|
||||
TRACE("gomory_cut_detail", tout << "after *lcm\n";
|
||||
for (unsigned i = 0; i < pol.size(); i++) {
|
||||
tout << pol[i].first << " * v" << pol[i].second << "\n";
|
||||
}
|
||||
tout << "k: " << k << "\n";);
|
||||
|
||||
// negate everything to return -pol <= -k
|
||||
for (const auto & pi: pol)
|
||||
t.add_monomial(-pi.first, pi.second);
|
||||
k.neg();
|
||||
}
|
||||
TRACE("gomory_cut_detail", tout << "k = " << k << std::endl;);
|
||||
lp_assert(k.is_int());
|
||||
}
|
||||
|
||||
void print_term(lar_term & t, std::ostream & out) {
|
||||
lp_assert(is_zero(t.m_v));
|
||||
vector<std::pair<mpq, unsigned>> row;
|
||||
for (auto p : t.m_coeffs)
|
||||
row.push_back(std::make_pair(p.second, p.first));
|
||||
print_row(out, row);
|
||||
}
|
||||
|
||||
void mk_gomory_cut(lar_term& t, mpq& k, explanation & expl, unsigned inf_col, vector<std::pair<mpq, unsigned>> & row) {
|
||||
enable_trace("gomory_cut");
|
||||
enable_trace("gomory_cut_detail");
|
||||
|
||||
TRACE("gomory_cut",
|
||||
tout << "applying cut at:\n"; print_row(tout, row);
|
||||
tout << std::endl << "inf_col = " << inf_col << std::endl;
|
||||
);
|
||||
|
||||
// gomory will be t >= k
|
||||
k = 1;
|
||||
mpq lcm_den(1);
|
||||
unsigned x_j;
|
||||
mpq a;
|
||||
bool some_int_columns = false;
|
||||
mpq f_0 = int_solver::fractional_part(get_value(inf_col));
|
||||
mpq one_min_f_0 = 1 - f_0;
|
||||
for ( auto pp : row) {
|
||||
a = pp.first;
|
||||
x_j = pp.second;
|
||||
if (x_j == inf_col)
|
||||
continue;
|
||||
// make the format compatible with the format used in: Integrating Simplex with DPLL(T)
|
||||
a.neg();
|
||||
if (is_real(x_j))
|
||||
real_case_in_gomory_cut(a, x_j, k, t, expl, f_0, one_min_f_0);
|
||||
else {
|
||||
if (a.is_int()) continue; // f_j will be zero and no monomial will be added
|
||||
some_int_columns = true;
|
||||
int_case_in_gomory_cut(a, x_j, k, t, expl, lcm_den, f_0, one_min_f_0);
|
||||
}
|
||||
}
|
||||
|
||||
if (t.is_empty())
|
||||
return report_conflict_from_gomory_cut(k);
|
||||
if (some_int_columns)
|
||||
adjust_term_and_k_for_some_ints_case_gomory(t, k, lcm_den);
|
||||
|
||||
TRACE("gomory_cut", tout<<"new cut :"; print_term(t, tout); tout << " >= " << k << std::endl;);
|
||||
|
||||
}
|
||||
};
|
||||
}
|
|
@ -50,6 +50,8 @@ Revision History:
|
|||
#include "util/lp/integer_domain.h"
|
||||
#include "util/lp/stacked_map.h"
|
||||
#include <cstdlib>
|
||||
#include "test/lp/gomory_test.h"
|
||||
|
||||
namespace lp {
|
||||
unsigned seed = 1;
|
||||
|
||||
|
@ -1883,6 +1885,7 @@ void test_replace_column() {
|
|||
|
||||
|
||||
void setup_args_parser(argument_parser & parser) {
|
||||
parser.add_option_with_help_string("-gomory", "gomory");
|
||||
parser.add_option_with_help_string("-intd", "test integer_domain");
|
||||
parser.add_option_with_help_string("-xyz_sample", "run a small interactive scenario");
|
||||
parser.add_option_with_after_string_with_help("--density", "the percentage of non-zeroes in the matrix below which it is not dense");
|
||||
|
@ -3255,6 +3258,153 @@ void test_resolve(cut_solver& cs, unsigned constraint_index, unsigned i0) {
|
|||
}
|
||||
|
||||
|
||||
void test_gomory_cut_0() {
|
||||
gomory_test g(
|
||||
[](unsigned j) { return "v" + T_to_string(j);} // name_function_p
|
||||
,
|
||||
[](unsigned j) { //get_value_p
|
||||
if (j == 1)
|
||||
return mpq(2730, 1727);
|
||||
if (j == 2)
|
||||
return zero_of_type<mpq>();
|
||||
if (j == 3) return mpq(3);
|
||||
lp_assert(false);
|
||||
return zero_of_type<mpq>();
|
||||
},
|
||||
[](unsigned j) { // at_low_p
|
||||
if (j == 1)
|
||||
return false;
|
||||
if (j == 2)
|
||||
return true;
|
||||
if (j == 3)
|
||||
return true;
|
||||
lp_assert(false);
|
||||
return false;
|
||||
},
|
||||
[](unsigned j) { // at_upper
|
||||
if (j == 1)
|
||||
return false;
|
||||
if (j == 2)
|
||||
return true;
|
||||
if (j == 3)
|
||||
return false;
|
||||
lp_assert(false);
|
||||
return false;
|
||||
},
|
||||
[](unsigned j) { // lower_bound
|
||||
if (j == 1) {
|
||||
lp_assert(false); //unlimited from below
|
||||
return 0;
|
||||
}
|
||||
if (j == 2)
|
||||
return 0;
|
||||
if (j == 3)
|
||||
return 3;
|
||||
lp_assert(false);
|
||||
return 0;
|
||||
},
|
||||
[](unsigned j) { // upper
|
||||
if (j == 1) {
|
||||
lp_assert(false); //unlimited from above
|
||||
return 0;
|
||||
}
|
||||
if (j == 2)
|
||||
return 0;
|
||||
if (j == 3)
|
||||
return 10;
|
||||
lp_assert(false);
|
||||
return 0;
|
||||
},
|
||||
[] (unsigned) { return 0; },
|
||||
[] (unsigned) { return 0; }
|
||||
);
|
||||
lar_term t;
|
||||
mpq k;
|
||||
explanation expl;
|
||||
unsigned inf_col = 1;
|
||||
vector<std::pair<mpq, unsigned>> row;
|
||||
row.push_back(std::make_pair(mpq(1), 1));
|
||||
row.push_back(std::make_pair(mpq(2731, 1727), 2));
|
||||
row.push_back(std::make_pair(mpq(-910, 1727), 3));
|
||||
g.mk_gomory_cut(t, k, expl, inf_col, row);
|
||||
}
|
||||
|
||||
void test_gomory_cut_1() {
|
||||
gomory_test g(
|
||||
[](unsigned j) { return "v" + T_to_string(j);} // name_function_p
|
||||
,
|
||||
[](unsigned j) { //get_value_p
|
||||
if (j == 1)
|
||||
return mpq(-2);
|
||||
if (j == 2)
|
||||
return mpq(4363334, 2730001);
|
||||
if (j == 3)
|
||||
return mpq(1);
|
||||
lp_assert(false);
|
||||
return zero_of_type<mpq>();
|
||||
},
|
||||
[](unsigned j) { // at_low_p
|
||||
if (j == 1)
|
||||
return false;
|
||||
if (j == 2)
|
||||
return false;
|
||||
if (j == 3)
|
||||
return true;
|
||||
lp_assert(false);
|
||||
return false;
|
||||
},
|
||||
[](unsigned j) { // at_upper
|
||||
if (j == 1)
|
||||
return true;
|
||||
if (j == 2)
|
||||
return false;
|
||||
if (j == 3)
|
||||
return true;
|
||||
lp_assert(false);
|
||||
return false;
|
||||
},
|
||||
[](unsigned j) { // lower_bound
|
||||
if (j == 1) {
|
||||
lp_assert(false); //unlimited from below
|
||||
return 0;
|
||||
}
|
||||
if (j == 2)
|
||||
return 1;
|
||||
if (j == 3)
|
||||
return 1;
|
||||
lp_assert(false);
|
||||
return 0;
|
||||
},
|
||||
[](unsigned j) { // upper
|
||||
if (j == 1) {
|
||||
return -2;
|
||||
}
|
||||
if (j == 2)
|
||||
return 3333;
|
||||
if (j == 3)
|
||||
return 10000;
|
||||
lp_assert(false);
|
||||
return 0;
|
||||
},
|
||||
[] (unsigned) { return 0; },
|
||||
[] (unsigned) { return 0; }
|
||||
);
|
||||
lar_term t;
|
||||
mpq k;
|
||||
explanation expl;
|
||||
unsigned inf_col = 2;
|
||||
vector<std::pair<mpq, unsigned>> row;
|
||||
row.push_back(std::make_pair(mpq(1726667, 2730001), 1));
|
||||
row.push_back(std::make_pair(mpq(-910000, 2730001), 3));
|
||||
row.push_back(std::make_pair(mpq(1), 2));
|
||||
g.mk_gomory_cut(t, k, expl, inf_col, row);
|
||||
}
|
||||
|
||||
void test_gomory_cut() {
|
||||
test_gomory_cut_0();
|
||||
test_gomory_cut_1();
|
||||
}
|
||||
|
||||
void test_lp_local(int argn, char**argv) {
|
||||
|
||||
// initialize_util_module();
|
||||
|
@ -3270,7 +3420,10 @@ void test_lp_local(int argn, char**argv) {
|
|||
}
|
||||
|
||||
args_parser.print();
|
||||
|
||||
if (args_parser.option_is_used("-gomory")) {
|
||||
test_gomory_cut();
|
||||
return finalize(0);
|
||||
}
|
||||
if (args_parser.option_is_used("-intd")) {
|
||||
test_integer_domain();
|
||||
return finalize(0);
|
||||
|
|
76
src/util/lp/active_set.h
Normal file
76
src/util/lp/active_set.h
Normal file
|
@ -0,0 +1,76 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
Nikolaj Bjorner (nbjorner)
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
#include "util/lp/binary_heap_priority_queue.h"
|
||||
namespace lp {
|
||||
class active_set {
|
||||
std::unordered_set<constraint*, constraint_hash, constraint_equal> m_cs;
|
||||
binary_heap_priority_queue<int> m_q;
|
||||
std::unordered_map<unsigned, constraint *> m_id_to_constraint;
|
||||
public:
|
||||
std::unordered_set<constraint*, constraint_hash, constraint_equal> cs() const { return m_cs;}
|
||||
|
||||
bool contains(const constraint* c) const {
|
||||
return m_id_to_constraint.find(c->id()) != m_id_to_constraint.end();
|
||||
}
|
||||
|
||||
bool is_empty() const { return m_cs.size() == 0; }
|
||||
// low priority will be dequeued first
|
||||
void add_constraint(constraint* c, int priority) {
|
||||
if (contains(c))
|
||||
return;
|
||||
m_cs.insert(c);
|
||||
m_id_to_constraint[c->id()] = c;
|
||||
m_q.enqueue(c->id(), priority);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_cs.clear();
|
||||
m_id_to_constraint.clear();
|
||||
m_q.clear();
|
||||
}
|
||||
|
||||
|
||||
constraint* remove_constraint() {
|
||||
if (m_cs.size() == 0)
|
||||
return nullptr;
|
||||
unsigned id = m_q.dequeue();
|
||||
auto it = m_id_to_constraint.find(id);
|
||||
lp_assert(it != m_id_to_constraint.end());
|
||||
constraint* c = it->second;
|
||||
m_cs.erase(c);
|
||||
m_id_to_constraint.erase(it);
|
||||
return c;
|
||||
}
|
||||
|
||||
unsigned size() const {
|
||||
return static_cast<unsigned>(m_cs.size());
|
||||
}
|
||||
|
||||
void remove_constraint(constraint * c) {
|
||||
if (! contains(c)) return;
|
||||
|
||||
m_cs.erase(c);
|
||||
m_id_to_constraint.erase(c->id());
|
||||
m_q.remove(c->id());
|
||||
}
|
||||
};
|
||||
}
|
|
@ -45,7 +45,7 @@ public:
|
|||
unsigned size() const { return m_heap_size; }
|
||||
binary_heap_priority_queue(): m_heap(1), m_heap_size(0) {} // the empty constructror
|
||||
// n is the initial queue capacity.
|
||||
// The capacity will be enlarged two times automatically if needed
|
||||
// The capacity will be enlarged each time twice if needed
|
||||
binary_heap_priority_queue(unsigned n);
|
||||
|
||||
void clear() {
|
||||
|
|
|
@ -130,8 +130,12 @@ template <typename T> void binary_heap_priority_queue<T>::enqueue_new(unsigned o
|
|||
// In this case the priority will be changed and the queue adjusted.
|
||||
template <typename T> void binary_heap_priority_queue<T>::enqueue(unsigned o, const T & priority) {
|
||||
if (o >= m_priorities.size()) {
|
||||
resize(o << 1); // make the size twice larger
|
||||
if (o == 0)
|
||||
resize(2);
|
||||
else
|
||||
resize(o << 1); // make the size twice larger
|
||||
}
|
||||
|
||||
if (m_heap_inverse[o] == -1)
|
||||
enqueue_new(o, priority);
|
||||
else
|
||||
|
|
|
@ -19,7 +19,6 @@ Revision History:
|
|||
--*/
|
||||
#pragma once
|
||||
#include "util/vector.h"
|
||||
#include "util/lp/linear_combination_iterator.h"
|
||||
#include "implied_bound.h"
|
||||
#include "test_bound_analyzer.h"
|
||||
#include "util/lp/bound_propagator.h"
|
||||
|
@ -28,27 +27,85 @@ Revision History:
|
|||
// In a loop we drive the partial sum down, denoting the variables of this process by _u.
|
||||
// In the same loop trying to pin variables by pushing the partial sum up, denoting the variable related to it by _l
|
||||
namespace lp {
|
||||
|
||||
template <typename C> // C plays a role of a container
|
||||
class bound_analyzer_on_row {
|
||||
|
||||
linear_combination_iterator<mpq> & m_it;
|
||||
struct term_with_basis_col {
|
||||
const C & m_row;
|
||||
unsigned m_bj;
|
||||
struct ival {
|
||||
unsigned m_var;
|
||||
const mpq & m_coeff;
|
||||
ival(unsigned var, const mpq & val) : m_var(var), m_coeff(val) {
|
||||
}
|
||||
unsigned var() const { return m_var;}
|
||||
const mpq & coeff() const { return m_coeff; }
|
||||
};
|
||||
|
||||
term_with_basis_col(const C& row, unsigned bj) : m_row(row), m_bj(bj) {}
|
||||
struct const_iterator {
|
||||
// fields
|
||||
typename C::const_iterator m_it;
|
||||
unsigned m_bj;
|
||||
|
||||
|
||||
//typedefs
|
||||
|
||||
|
||||
typedef const_iterator self_type;
|
||||
typedef ival value_type;
|
||||
typedef ival reference;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
reference operator*() const {
|
||||
if (m_bj == static_cast<unsigned>(-1))
|
||||
return ival((*m_it).var(), (*m_it).coeff());
|
||||
return ival(m_bj, - 1);
|
||||
}
|
||||
self_type operator++() { self_type i = *this; operator++(1); return i; }
|
||||
|
||||
self_type operator++(int) {
|
||||
if (m_bj == static_cast<unsigned>(-1))
|
||||
m_it++;
|
||||
else
|
||||
m_bj = static_cast<unsigned>(-1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// constructor
|
||||
const_iterator(const typename C::const_iterator& it, unsigned bj) :
|
||||
m_it(it),
|
||||
m_bj(bj)
|
||||
{}
|
||||
bool operator==(const self_type &other) const {
|
||||
return m_it == other.m_it && m_bj == other.m_bj ;
|
||||
}
|
||||
bool operator!=(const self_type &other) const { return !(*this == other); }
|
||||
};
|
||||
const_iterator begin() const {
|
||||
return const_iterator( m_row.begin(), m_bj);
|
||||
}
|
||||
const_iterator end() const { return const_iterator(m_row.end(), m_bj); }
|
||||
};
|
||||
term_with_basis_col m_row;
|
||||
bound_propagator & m_bp;
|
||||
unsigned m_row_or_term_index;
|
||||
int m_column_of_u; // index of an unlimited from above monoid
|
||||
unsigned m_row_or_term_index;
|
||||
int m_column_of_u; // index of an unlimited from above monoid
|
||||
// -1 means that such a value is not found, -2 means that at least two of such monoids were found
|
||||
int m_column_of_l; // index of an unlimited from below monoid
|
||||
impq m_rs;
|
||||
int m_column_of_l; // index of an unlimited from below monoid
|
||||
impq m_rs;
|
||||
|
||||
public :
|
||||
// constructor
|
||||
bound_analyzer_on_row(
|
||||
linear_combination_iterator<mpq> &it,
|
||||
const C & it,
|
||||
unsigned bj, // basis column for the row
|
||||
const numeric_pair<mpq>& rs,
|
||||
unsigned row_or_term_index,
|
||||
bound_propagator & bp
|
||||
)
|
||||
:
|
||||
m_it(it),
|
||||
m_row(it, bj),
|
||||
m_bp(bp),
|
||||
m_row_or_term_index(row_or_term_index),
|
||||
m_column_of_u(-1),
|
||||
|
@ -59,11 +116,11 @@ public :
|
|||
|
||||
unsigned j;
|
||||
void analyze() {
|
||||
|
||||
mpq a; unsigned j;
|
||||
while (((m_column_of_l != -2) || (m_column_of_u != -2)) && m_it.next(a, j))
|
||||
analyze_bound_on_var_on_coeff(j, a);
|
||||
|
||||
for (auto c : m_row) {
|
||||
if ((m_column_of_l == -2) && (m_column_of_u == -2))
|
||||
break;
|
||||
analyze_bound_on_var_on_coeff(c.var(), c.coeff());
|
||||
}
|
||||
if (m_column_of_u >= 0)
|
||||
limit_monoid_u_from_below();
|
||||
else if (m_column_of_u == -1)
|
||||
|
@ -168,25 +225,23 @@ public :
|
|||
int strict = 0;
|
||||
mpq total;
|
||||
lp_assert(is_zero(total));
|
||||
m_it.reset();
|
||||
mpq a; unsigned j;
|
||||
while (m_it.next(a, j)) {
|
||||
for (auto p : m_row) {
|
||||
bool str;
|
||||
total -= monoid_min(a, j, str);
|
||||
total -= monoid_min(p.coeff(), p.var(), str);
|
||||
if (str)
|
||||
strict++;
|
||||
}
|
||||
|
||||
m_it.reset();
|
||||
while (m_it.next(a, j)) {
|
||||
|
||||
for (auto p : m_row) {
|
||||
bool str;
|
||||
bool a_is_pos = is_pos(a);
|
||||
mpq bound = total / a + monoid_min_no_mult(a_is_pos, j, str);
|
||||
bool a_is_pos = is_pos(p.coeff());
|
||||
mpq bound = total / p.coeff() + monoid_min_no_mult(a_is_pos, p.var(), str);
|
||||
if (a_is_pos) {
|
||||
limit_j(j, bound, true, false, strict - static_cast<int>(str) > 0);
|
||||
limit_j(p.var(), bound, true, false, strict - static_cast<int>(str) > 0);
|
||||
}
|
||||
else {
|
||||
limit_j(j, bound, false, true, strict - static_cast<int>(str) > 0);
|
||||
limit_j(p.var(), bound, false, true, strict - static_cast<int>(str) > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -195,25 +250,23 @@ public :
|
|||
int strict = 0;
|
||||
mpq total;
|
||||
lp_assert(is_zero(total));
|
||||
m_it.reset();
|
||||
mpq a; unsigned j;
|
||||
while (m_it.next(a, j)) {
|
||||
for (auto p : m_row) {
|
||||
bool str;
|
||||
total -= monoid_max(a, j, str);
|
||||
total -= monoid_max(p.coeff(), p.var(), str);
|
||||
if (str)
|
||||
strict++;
|
||||
}
|
||||
m_it.reset();
|
||||
while (m_it.next(a, j)) {
|
||||
|
||||
for (auto p : m_row) {
|
||||
bool str;
|
||||
bool a_is_pos = is_pos(a);
|
||||
mpq bound = total / a + monoid_max_no_mult(a_is_pos, j, str);
|
||||
bool a_is_pos = is_pos(p.coeff());
|
||||
mpq bound = total / p.coeff() + monoid_max_no_mult(a_is_pos, p.var(), str);
|
||||
bool astrict = strict - static_cast<int>(str) > 0;
|
||||
if (a_is_pos) {
|
||||
limit_j(j, bound, true, true, astrict);
|
||||
limit_j(p.var(), bound, true, true, astrict);
|
||||
}
|
||||
else {
|
||||
limit_j(j, bound, false, false, astrict);
|
||||
limit_j(p.var(), bound, false, false, astrict);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -222,18 +275,18 @@ public :
|
|||
void limit_monoid_u_from_below() {
|
||||
// we are going to limit from below the monoid m_column_of_u,
|
||||
// every other monoid is impossible to limit from below
|
||||
mpq u_coeff, a;
|
||||
mpq u_coeff;
|
||||
unsigned j;
|
||||
mpq bound = -m_rs.x;
|
||||
m_it.reset();
|
||||
bool strict = false;
|
||||
while (m_it.next(a, j)) {
|
||||
for (auto p : m_row) {
|
||||
j = p.var();
|
||||
if (j == static_cast<unsigned>(m_column_of_u)) {
|
||||
u_coeff = a;
|
||||
u_coeff = p.coeff();
|
||||
continue;
|
||||
}
|
||||
bool str;
|
||||
bound -= monoid_max(a, j, str);
|
||||
bound -= monoid_max(p.coeff(), j, str);
|
||||
if (str)
|
||||
strict = true;
|
||||
}
|
||||
|
@ -251,19 +304,19 @@ public :
|
|||
void limit_monoid_l_from_above() {
|
||||
// we are going to limit from above the monoid m_column_of_l,
|
||||
// every other monoid is impossible to limit from above
|
||||
mpq l_coeff, a;
|
||||
mpq l_coeff;
|
||||
unsigned j;
|
||||
mpq bound = -m_rs.x;
|
||||
bool strict = false;
|
||||
m_it.reset();
|
||||
while (m_it.next(a, j)) {
|
||||
for (auto p : m_row) {
|
||||
j = p.var();
|
||||
if (j == static_cast<unsigned>(m_column_of_l)) {
|
||||
l_coeff = a;
|
||||
l_coeff = p.coeff();
|
||||
continue;
|
||||
}
|
||||
|
||||
bool str;
|
||||
bound -= monoid_min(a, j, str);
|
||||
bound -= monoid_min(p.coeff(), j, str);
|
||||
if (str)
|
||||
strict = true;
|
||||
}
|
||||
|
@ -282,7 +335,7 @@ public :
|
|||
// bool lower_bound = be.m_lower_bound;
|
||||
// if (!coeff_is_pos)
|
||||
// lower_bound = !lower_bound;
|
||||
// auto it = m_it.clone();
|
||||
// auto it = m_row.clone();
|
||||
// mpq a; unsigned j;
|
||||
// while (it->next(a, j)) {
|
||||
// if (be.m_j == j) continue;
|
||||
|
@ -336,14 +389,16 @@ public :
|
|||
}
|
||||
}
|
||||
|
||||
static void analyze_row(linear_combination_iterator<mpq> &it,
|
||||
static void analyze_row(const C & row,
|
||||
unsigned bj, // basis column for the row
|
||||
const numeric_pair<mpq>& rs,
|
||||
unsigned row_or_term_index,
|
||||
bound_propagator & bp
|
||||
) {
|
||||
bound_analyzer_on_row a(it, rs, row_or_term_index, bp);
|
||||
bound_analyzer_on_row a(row, bj, rs, row_or_term_index, bp);
|
||||
a.analyze();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -19,31 +19,19 @@ Revision History:
|
|||
|
||||
--*/
|
||||
#include <string>
|
||||
#include "util/lp/linear_combination_iterator.h"
|
||||
#include "util/lp/static_matrix.h"
|
||||
namespace lp {
|
||||
class column_namer {
|
||||
public:
|
||||
virtual std::string get_column_name(unsigned j) const = 0;
|
||||
template <typename T>
|
||||
void print_linear_iterator(linear_combination_iterator<T>* it, std::ostream & out) const {
|
||||
void print_row(const row_strip<T> & row, std::ostream & out) const {
|
||||
vector<std::pair<T, unsigned>> coeff;
|
||||
T a;
|
||||
unsigned i;
|
||||
while (it->next(a, i)) {
|
||||
coeff.push_back(std::make_pair(a, i));
|
||||
for (auto p : row) {
|
||||
coeff.push_back(std::make_pair(p.coeff(), p.var()));
|
||||
}
|
||||
print_linear_combination_of_column_indices(coeff, out);
|
||||
}
|
||||
template <typename T>
|
||||
void print_linear_iterator_indices_only(linear_combination_iterator<T>* it, std::ostream & out) const {
|
||||
vector<std::pair<T, unsigned>> coeff;
|
||||
T a;
|
||||
unsigned i;
|
||||
while (it->next(a, i)) {
|
||||
coeff.push_back(std::make_pair(a, i));
|
||||
}
|
||||
print_linear_combination_of_column_indices_only(coeff, out);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void print_linear_combination_of_column_indices_only(const vector<std::pair<T, unsigned>> & coeffs, std::ostream & out) const {
|
||||
|
|
99
src/util/lp/constraint.h
Normal file
99
src/util/lp/constraint.h
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
Nikolaj Bjorner (nbjorner)
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
namespace lp {
|
||||
class constraint; // forward definition
|
||||
struct constraint_hash {
|
||||
size_t operator() (const constraint* c) const;
|
||||
};
|
||||
|
||||
struct constraint_equal {
|
||||
bool operator() (const constraint * a, const constraint * b) const;
|
||||
};
|
||||
|
||||
class constraint { // we only have less or equal for the inequality sign, which is enough for integral variables
|
||||
int m_id;
|
||||
bool m_is_ineq;
|
||||
polynomial m_poly;
|
||||
mpq m_d; // the divider for the case of a divisibility constraint
|
||||
std::unordered_set<constraint_index> m_assert_origins; // these indices come from the client and get collected during tightening
|
||||
public :
|
||||
unsigned id() const { return m_id; }
|
||||
const polynomial & poly() const { return m_poly; }
|
||||
polynomial & poly() { return m_poly; }
|
||||
std::unordered_set<constraint_index> & assert_origins() { return m_assert_origins;}
|
||||
const std::unordered_set<constraint_index> & assert_origins() const { return m_assert_origins;}
|
||||
bool is_lemma() const { return !is_assert(); }
|
||||
bool is_assert() const { return m_assert_origins.size() == 1; }
|
||||
bool is_ineq() const { return m_is_ineq; }
|
||||
const mpq & divider() const { return m_d; }
|
||||
public:
|
||||
constraint(
|
||||
unsigned id,
|
||||
constraint_index assert_origin,
|
||||
const polynomial & p,
|
||||
bool is_ineq):
|
||||
m_id(id),
|
||||
m_is_ineq(is_ineq),
|
||||
m_poly(p)
|
||||
{ // creates an assert
|
||||
m_assert_origins.insert(assert_origin);
|
||||
}
|
||||
constraint(
|
||||
unsigned id,
|
||||
const std::unordered_set<constraint_index>& origins,
|
||||
const polynomial & p,
|
||||
bool is_ineq):
|
||||
m_id(id),
|
||||
m_is_ineq(is_ineq),
|
||||
m_poly(p),
|
||||
m_assert_origins(origins)
|
||||
{}
|
||||
|
||||
|
||||
|
||||
constraint(
|
||||
unsigned id,
|
||||
const polynomial & p,
|
||||
bool is_ineq):
|
||||
m_id(id),
|
||||
m_is_ineq(is_ineq),
|
||||
m_poly(p) { // creates a lemma
|
||||
}
|
||||
|
||||
public:
|
||||
constraint() {}
|
||||
|
||||
const mpq & coeff(var_index j) const {
|
||||
return m_poly.coeff(j);
|
||||
}
|
||||
const vector<monomial>& coeffs() const { return m_poly.m_coeffs;}
|
||||
|
||||
bool is_tight(unsigned j) const {
|
||||
const mpq & a = m_poly.coeff(j);
|
||||
return a == 1 || a == -1;
|
||||
}
|
||||
void add_predecessor(const constraint* p) {
|
||||
lp_assert(p != nullptr);
|
||||
for (auto m : p->assert_origins())
|
||||
m_assert_origins.insert(m); }
|
||||
};
|
||||
}
|
|
@ -105,6 +105,8 @@ template <typename T, typename X> void core_solver_pretty_printer<T, X>::init_m_
|
|||
|
||||
string name = m_core_solver.column_name(column);
|
||||
for (unsigned row = 0; row < nrows(); row ++) {
|
||||
m_A[row].resize(ncols(), "");
|
||||
m_signs[row].resize(ncols(),"");
|
||||
set_coeff(
|
||||
m_A[row],
|
||||
m_signs[row],
|
||||
|
|
|
@ -19,6 +19,5 @@ namespace lp {
|
|||
c.s.print_constraint(out, c.c);
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -74,7 +74,7 @@ void eta_matrix<T, X>::apply_from_right(vector<T> & w) {
|
|||
t += w[it.first] * it.second;
|
||||
}
|
||||
w[m_column_index] = t;
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(vectors_are_equal<T>(clone_w, w, get_number_of_rows()));
|
||||
// delete clone_w;
|
||||
#endif
|
||||
|
@ -114,7 +114,7 @@ void eta_matrix<T, X>::apply_from_right(indexed_vector<T> & w) {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(w.is_OK());
|
||||
// lp_assert(vectors_are_equal<T>(wcopy, w.m_data));
|
||||
#endif
|
||||
|
@ -144,7 +144,7 @@ void eta_matrix<T, X>::conjugate_by_permutation(permutation_matrix<T, X> & p) {
|
|||
for (auto & pair : m_column_vector.m_data) {
|
||||
pair.first = p.get_rev(pair.first);
|
||||
}
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(deb == *this);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include "util/numerics/mpq.h"
|
||||
#ifdef __CLANG__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wmismatched-tags"
|
||||
#endif
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<lp::mpq> {
|
||||
inline size_t operator()(const lp::mpq & v) const {
|
||||
return v.hash();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void hash_combine(std::size_t & seed, const T & v) {
|
||||
seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template<typename S, typename T> struct hash<pair<S, T>> {
|
||||
inline size_t operator()(const pair<S, T> & v) const {
|
||||
size_t seed = 0;
|
||||
hash_combine(seed, v.first);
|
||||
hash_combine(seed, v.second);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
#ifdef __CLANG__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
|
@ -166,6 +166,55 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ival {
|
||||
unsigned m_var;
|
||||
const T & m_coeff;
|
||||
ival(unsigned var, const T & val) : m_var(var), m_coeff(val) {
|
||||
}
|
||||
unsigned var() const { return m_var;}
|
||||
const T & coeff() const { return m_coeff; }
|
||||
};
|
||||
|
||||
struct const_iterator {
|
||||
// fields
|
||||
const unsigned *m_i;
|
||||
const indexed_vector& m_v;
|
||||
|
||||
//typedefs
|
||||
|
||||
|
||||
typedef const_iterator self_type;
|
||||
typedef ival value_type;
|
||||
typedef const ival reference;
|
||||
// typedef const column_cell* pointer;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
reference operator*() const {
|
||||
return ival(*m_i, m_v[*m_i]);
|
||||
}
|
||||
self_type operator++() { self_type i = *this; m_i++; return i; }
|
||||
self_type operator++(int) { m_i++; return *this; }
|
||||
|
||||
const_iterator(const unsigned* it, const indexed_vector& v) :
|
||||
m_i(it),
|
||||
m_v(v)
|
||||
{}
|
||||
bool operator==(const self_type &other) const {
|
||||
return m_i == other.m_i;
|
||||
}
|
||||
bool operator!=(const self_type &other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
const_iterator begin() const {
|
||||
return const_iterator(m_index.begin(), *this);
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return const_iterator(m_index.end(), *this);
|
||||
}
|
||||
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
bool is_OK() const;
|
||||
|
|
45
src/util/lp/indexer_of_constraints.h
Normal file
45
src/util/lp/indexer_of_constraints.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
Nikolaj Bjorner (nbjorner)
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
#include "util/lp/binary_heap_priority_queue.h"
|
||||
namespace lp {
|
||||
|
||||
class indexer_of_constraints {
|
||||
binary_heap_priority_queue<unsigned> m_queue_of_released_indices;
|
||||
unsigned m_max;
|
||||
public:
|
||||
indexer_of_constraints() :m_max(0) {}
|
||||
unsigned get_new_index() {
|
||||
unsigned ret;
|
||||
if (m_queue_of_released_indices.is_empty()) {
|
||||
ret = m_max++;
|
||||
}
|
||||
else {
|
||||
ret = m_queue_of_released_indices.dequeue();
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
void release_index(unsigned i) {
|
||||
m_queue_of_released_indices.enqueue(i, i);
|
||||
};
|
||||
unsigned max() const { return m_max; }
|
||||
};
|
||||
}
|
|
@ -31,17 +31,17 @@ void int_solver::trace_inf_rows() const {
|
|||
}
|
||||
}
|
||||
|
||||
num = 0;
|
||||
for (unsigned i = 0; i < m_lar_solver->A_r().row_count(); i++) {
|
||||
unsigned j = m_lar_solver->m_mpq_lar_core_solver.m_r_basis[i];
|
||||
if (column_is_int_inf(j)) {
|
||||
num++;
|
||||
iterator_on_row<mpq> it(m_lar_solver->A_r().m_rows[i]);
|
||||
m_lar_solver->print_linear_iterator(&it, tout);
|
||||
tout << "\n";
|
||||
}
|
||||
}
|
||||
tout << "num of int infeasible: " << num << "\n";
|
||||
num = 0;
|
||||
for (unsigned i = 0; i < m_lar_solver->A_r().row_count(); i++) {
|
||||
unsigned j = m_lar_solver->m_mpq_lar_core_solver.m_r_basis[i];
|
||||
if (column_is_int_inf(j)) {
|
||||
num++;
|
||||
m_lar_solver->print_row(m_lar_solver->A_r().m_rows[i], tout);
|
||||
tout << "\n";
|
||||
}
|
||||
}
|
||||
tout << "num of int infeasible: " << num << "\n";
|
||||
);
|
||||
}
|
||||
|
||||
int_set& int_solver::inf_int_set() {
|
||||
|
@ -106,32 +106,29 @@ int int_solver::find_inf_int_boxed_base_column_with_smallest_range() {
|
|||
|
||||
}
|
||||
|
||||
bool int_solver::is_gomory_cut_target(linear_combination_iterator<mpq> &iter) {
|
||||
unsigned j;
|
||||
lp_assert(iter.is_reset());
|
||||
bool int_solver::is_gomory_cut_target(const row_strip<mpq>& row) {
|
||||
// All non base variables must be at their bounds and assigned to rationals (that is, infinitesimals are not allowed).
|
||||
while (iter.next(j)) {
|
||||
unsigned j;
|
||||
for (auto p : row) {
|
||||
j = p.var();
|
||||
if (is_base(j)) continue;
|
||||
if (!is_zero(get_value(j).y)) {
|
||||
TRACE("gomory_cut", tout << "row is not gomory cut target:\n";
|
||||
display_column(tout, j);
|
||||
tout << "infinitesimal: " << !is_zero(get_value(j).y) << "\n";);
|
||||
iter.reset();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
iter.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void int_solver::real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& pol, explanation & expl, unsigned gomory_cut_inf_column) {
|
||||
void int_solver::real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& pol, explanation & expl, const mpq& f_0, const mpq& one_minus_f_0) {
|
||||
TRACE("gomory_cut_detail_real", tout << "real\n";);
|
||||
mpq f_0 = fractional_part(get_value(gomory_cut_inf_column));
|
||||
mpq new_a;
|
||||
if (at_low(x_j)) {
|
||||
if (a.is_pos()) {
|
||||
new_a = a / (1 - f_0);
|
||||
new_a = a / one_minus_f_0;
|
||||
}
|
||||
else {
|
||||
new_a = a / f_0;
|
||||
|
@ -148,7 +145,7 @@ void int_solver::real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, l
|
|||
new_a.neg(); // the upper terms are inverted.
|
||||
}
|
||||
else {
|
||||
new_a = a / (mpq(1) - f_0);
|
||||
new_a = a / one_minus_f_0;
|
||||
}
|
||||
k.addmul(new_a, upper_bound(x_j).x); // k += upper_bound(x_j).x * new_a;
|
||||
expl.push_justification(column_upper_bound_constraint(x_j), new_a);
|
||||
|
@ -166,11 +163,9 @@ constraint_index int_solver::column_lower_bound_constraint(unsigned j) const {
|
|||
}
|
||||
|
||||
|
||||
void int_solver::int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term & t, explanation& expl, mpq & lcm_den, unsigned inf_column) {
|
||||
void int_solver::int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term & t, explanation& expl, mpq & lcm_den, const mpq& f_0, const mpq& one_minus_f_0) {
|
||||
lp_assert(is_int(x_j));
|
||||
lp_assert(!a.is_int());
|
||||
mpq f_0 = fractional_part(get_value(inf_column));
|
||||
lp_assert(f_0 > zero_of_type<mpq>() && f_0 < one_of_type<mpq>());
|
||||
mpq f_j = fractional_part(a);
|
||||
TRACE("gomory_cut_detail",
|
||||
tout << a << " x_j" << x_j << " k = " << k << "\n";
|
||||
|
@ -182,7 +177,6 @@ void int_solver::int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, la
|
|||
lp_assert (!f_j.is_zero());
|
||||
mpq new_a;
|
||||
if (at_low(x_j)) {
|
||||
auto one_minus_f_0 = 1 - f_0;
|
||||
if (f_j <= one_minus_f_0) {
|
||||
new_a = f_j / one_minus_f_0;
|
||||
}
|
||||
|
@ -198,7 +192,7 @@ void int_solver::int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, la
|
|||
new_a = f_j / f_0;
|
||||
}
|
||||
else {
|
||||
new_a = (mpq(1) - f_j) / (1 - f_0);
|
||||
new_a = (mpq(1) - f_j) / one_minus_f_0;
|
||||
}
|
||||
new_a.neg(); // the upper terms are inverted
|
||||
k.addmul(new_a, upper_bound(x_j).x);
|
||||
|
@ -319,18 +313,15 @@ void int_solver::adjust_term_and_k_for_some_ints_case_gomory(lar_term& t, mpq& k
|
|||
|
||||
|
||||
|
||||
lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl, unsigned inf_col, linear_combination_iterator<mpq>& iter) {
|
||||
lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl, unsigned inf_col, const row_strip<mpq> & row) {
|
||||
|
||||
lp_assert(column_is_int_inf(inf_col));
|
||||
|
||||
TRACE("gomory_cut",
|
||||
tout << "applying cut at:\n"; m_lar_solver->print_linear_iterator_indices_only(&iter, tout); tout << std::endl;
|
||||
iter.reset();
|
||||
unsigned j;
|
||||
while(iter.next(j)) {
|
||||
m_lar_solver->m_mpq_lar_core_solver.m_r_solver.print_column_info(j, tout);
|
||||
tout << "applying cut at:\n"; m_lar_solver->print_row(row, tout); tout << std::endl;
|
||||
for (auto p : row) {
|
||||
m_lar_solver->m_mpq_lar_core_solver.m_r_solver.print_column_info(p.var(), tout);
|
||||
}
|
||||
iter.reset();
|
||||
tout << "inf_col = " << inf_col << std::endl;
|
||||
);
|
||||
|
||||
|
@ -340,18 +331,21 @@ lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl, unsi
|
|||
unsigned x_j;
|
||||
mpq a;
|
||||
bool some_int_columns = false;
|
||||
lp_assert(iter.is_reset());
|
||||
while (iter.next(a, x_j)) {
|
||||
mpq f_0 = int_solver::fractional_part(get_value(inf_col));
|
||||
mpq one_min_f_0 = 1 - f_0;
|
||||
for (auto p : row) {
|
||||
x_j = p.var();
|
||||
if (x_j == inf_col)
|
||||
continue;
|
||||
// make the format compatible with the format used in: Integrating Simplex with DPLL(T)
|
||||
a = p.coeff();
|
||||
a.neg();
|
||||
if (is_real(x_j))
|
||||
real_case_in_gomory_cut(a, x_j, k, t, expl, inf_col);
|
||||
real_case_in_gomory_cut(a, x_j, k, t, expl, f_0, one_min_f_0);
|
||||
else {
|
||||
if (a.is_int()) continue; // f_j will be zero and no monomial will be added
|
||||
some_int_columns = true;
|
||||
int_case_in_gomory_cut(a, x_j, k, t, expl, lcm_den, inf_col);
|
||||
int_case_in_gomory_cut(a, x_j, k, t, expl, lcm_den, f_0, one_min_f_0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -362,6 +356,7 @@ lia_move int_solver::mk_gomory_cut(lar_term& t, mpq& k, explanation & expl, unsi
|
|||
|
||||
lp_assert(current_solution_is_inf_on_cut(t, k));
|
||||
m_lar_solver->subs_term_columns(t);
|
||||
TRACE("gomory_cut", tout<<"precut:"; m_lar_solver->print_term(t, tout); tout << ">= " << k << std::endl;);
|
||||
return lia_move::cut;
|
||||
}
|
||||
|
||||
|
@ -371,28 +366,30 @@ void int_solver::init_check_data() {
|
|||
m_old_values_data.resize(n);
|
||||
}
|
||||
|
||||
int int_solver::find_free_var_in_gomory_row(linear_combination_iterator<mpq>& iter) {
|
||||
int int_solver::find_free_var_in_gomory_row(const row_strip<mpq>& row) {
|
||||
unsigned j;
|
||||
while(iter.next(j)) {
|
||||
for (auto p : row) {
|
||||
j = p.var();
|
||||
if (!is_base(j) && is_free(j))
|
||||
return static_cast<int>(j);
|
||||
}
|
||||
iter.reset();
|
||||
return -1;
|
||||
}
|
||||
|
||||
lia_move int_solver::proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex, unsigned j) {
|
||||
lia_move int_solver::proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex, unsigned j, bool & upper) {
|
||||
lia_move ret;
|
||||
linear_combination_iterator<mpq>* iter = m_lar_solver->get_iterator_on_row(row_of_basic_column(j));
|
||||
int free_j = find_free_var_in_gomory_row(*iter);
|
||||
|
||||
const row_strip<mpq>& row = m_lar_solver->get_row(row_of_basic_column(j));
|
||||
int free_j = find_free_var_in_gomory_row(row);
|
||||
if (free_j != -1) {
|
||||
ret = create_branch_on_column(j, t, k, true);
|
||||
} else if (!is_gomory_cut_target(*iter)) {
|
||||
ret = create_branch_on_column(j, t, k, false);
|
||||
ret = create_branch_on_column(j, t, k, true, upper);
|
||||
} else if (!is_gomory_cut_target(row)) {
|
||||
bool upper;
|
||||
ret = create_branch_on_column(j, t, k, false, upper);
|
||||
} else {
|
||||
ret = mk_gomory_cut(t, k, ex, j, *iter);
|
||||
upper = false;
|
||||
ret = mk_gomory_cut(t, k, ex, j, row);
|
||||
}
|
||||
delete iter;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -478,7 +475,14 @@ void int_solver::copy_values_from_cut_solver() {
|
|||
}
|
||||
}
|
||||
|
||||
lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) {
|
||||
void int_solver::catch_up_in_adding_constraints_to_cut_solver() {
|
||||
lp_assert(m_cut_solver.number_of_asserts() <= m_lar_solver->constraints().size());
|
||||
for (unsigned j = m_cut_solver.number_of_asserts(); j < m_lar_solver->constraints().size(); j++) {
|
||||
add_constraint_to_cut_solver(j, m_lar_solver->constraints()[j]);
|
||||
}
|
||||
}
|
||||
|
||||
lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex, bool & upper) {
|
||||
init_check_data();
|
||||
lp_assert(inf_int_set_is_correct());
|
||||
// it is a reimplementation of
|
||||
|
@ -486,9 +490,16 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) {
|
|||
// from theory_arith_int.h with the addition of cut_solver
|
||||
if (!has_inf_int())
|
||||
return lia_move::ok;
|
||||
if (settings().m_run_gcd_test)
|
||||
if (!gcd_test(ex))
|
||||
if (settings().m_run_gcd_test) {
|
||||
settings().st().m_gcd_calls++;
|
||||
if (!gcd_test(ex)) {
|
||||
TRACE("gcd_test", tout << "conflict";);
|
||||
settings().st().m_gcd_conflicts++;
|
||||
return lia_move::conflict;
|
||||
}
|
||||
} else {
|
||||
TRACE("gcd_test", tout << "no test";);
|
||||
}
|
||||
pivoted_rows_tracking_control pc(m_lar_solver);
|
||||
/* if (m_params.m_arith_euclidean_solver) apply_euclidean_solver(); */
|
||||
//m_lar_solver->pivot_fixed_vars_from_basis();
|
||||
|
@ -498,20 +509,20 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) {
|
|||
|
||||
if ((++m_branch_cut_counter) % settings().m_int_branch_cut_solver == 0) {
|
||||
TRACE("check_main_int", tout<<"cut_solver";);
|
||||
catch_up_in_adding_constraints_to_cut_solver();
|
||||
auto check_res = m_cut_solver.check();
|
||||
settings().st().m_cut_solver_calls++;
|
||||
switch (check_res) {
|
||||
case lbool::l_false:
|
||||
case cut_solver::lbool::l_false:
|
||||
copy_explanations_from_cut_solver(ex);
|
||||
settings().st().m_cut_solver_false++;
|
||||
return lia_move::conflict;
|
||||
case lbool::l_true:
|
||||
case cut_solver::lbool::l_true:
|
||||
settings().st().m_cut_solver_true++;
|
||||
copy_values_from_cut_solver();
|
||||
return lia_move::ok;
|
||||
case lbool::l_undef:
|
||||
case cut_solver::lbool::l_undef:
|
||||
settings().st().m_cut_solver_undef++;
|
||||
settings().m_int_branch_cut_solver *= (settings().m_int_branch_cut_solver); // take a square
|
||||
break;
|
||||
default:
|
||||
return lia_move::give_up;
|
||||
|
@ -530,10 +541,11 @@ lia_move int_solver::check(lar_term& t, mpq& k, explanation& ex) {
|
|||
int j = find_inf_int_base_column();
|
||||
if (j == -1) return lia_move::ok;
|
||||
TRACE("arith_int", tout << "j = " << j << " does not have an integer assignment: " << get_value(j) << "\n";);
|
||||
return proceed_with_gomory_cut(t, k, ex, j);
|
||||
|
||||
return proceed_with_gomory_cut(t, k, ex, j, upper);
|
||||
}
|
||||
TRACE("check_main_int", tout << "branch"; );
|
||||
return create_branch_on_column(find_inf_int_base_column(), t, k, false);
|
||||
return create_branch_on_column(find_inf_int_base_column(), t, k, false, upper);
|
||||
}
|
||||
|
||||
bool int_solver::move_non_basic_column_to_bounds(unsigned j) {
|
||||
|
@ -668,26 +680,24 @@ void int_solver::patch_int_infeasible_nbasic_columns() {
|
|||
lp_assert(is_feasible() && inf_int_set_is_correct());
|
||||
}
|
||||
|
||||
mpq get_denominators_lcm(iterator_on_row<mpq> &it) {
|
||||
mpq get_denominators_lcm(const row_strip<mpq> & row) {
|
||||
mpq r(1);
|
||||
mpq a;
|
||||
unsigned j;
|
||||
while (it.next(a, j)) {
|
||||
r = lcm(r, denominator(a));
|
||||
for (auto c : row) {
|
||||
r = lcm(r, denominator(c.coeff()));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool int_solver::gcd_test_for_row(static_matrix<mpq, numeric_pair<mpq>> & A, unsigned i, explanation & ex) {
|
||||
iterator_on_row<mpq> it(A.m_rows[i]);
|
||||
mpq lcm_den = get_denominators_lcm(it);
|
||||
mpq lcm_den = get_denominators_lcm(A.m_rows[i]);
|
||||
mpq consts(0);
|
||||
mpq gcds(0);
|
||||
mpq least_coeff(0);
|
||||
bool least_coeff_is_bounded = false;
|
||||
mpq a;
|
||||
unsigned j;
|
||||
while (it.next(a, j)) {
|
||||
for (auto &c : A.m_rows[i]) {
|
||||
j = c.var();
|
||||
const mpq& a = c.coeff();
|
||||
if (m_lar_solver->column_is_fixed(j)) {
|
||||
mpq aux = lcm_den * a;
|
||||
consts += aux * m_lar_solver->column_lower_bound(j).x;
|
||||
|
@ -725,8 +735,11 @@ bool int_solver::gcd_test_for_row(static_matrix<mpq, numeric_pair<mpq>> & A, uns
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!(consts / gcds).is_int())
|
||||
fill_explanation_from_fixed_columns(it, ex);
|
||||
if (!(consts / gcds).is_int()) {
|
||||
TRACE("gcd_test", tout << "row failed the GCD test:\n"; display_row_info(tout, i););
|
||||
fill_explanation_from_fixed_columns(A.m_rows[i], ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (least_coeff.is_one() && !least_coeff_is_bounded) {
|
||||
SASSERT(gcds.is_one());
|
||||
|
@ -734,7 +747,7 @@ bool int_solver::gcd_test_for_row(static_matrix<mpq, numeric_pair<mpq>> & A, uns
|
|||
}
|
||||
|
||||
if (least_coeff_is_bounded) {
|
||||
return ext_gcd_test(it, least_coeff, lcm_den, consts, ex);
|
||||
return ext_gcd_test(A.m_rows[i], least_coeff, lcm_den, consts, ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -745,13 +758,11 @@ void int_solver::add_to_explanation_from_fixed_or_boxed_column(unsigned j, expla
|
|||
ex.m_explanation.push_back(std::make_pair(mpq(1), lc));
|
||||
ex.m_explanation.push_back(std::make_pair(mpq(1), uc));
|
||||
}
|
||||
void int_solver::fill_explanation_from_fixed_columns(iterator_on_row<mpq> & it, explanation & ex) {
|
||||
it.reset();
|
||||
unsigned j;
|
||||
while (it.next(j)) {
|
||||
if (!m_lar_solver->column_is_fixed(j))
|
||||
void int_solver::fill_explanation_from_fixed_columns(const row_strip<mpq> & row, explanation & ex) {
|
||||
for (const auto & c : row) {
|
||||
if (!m_lar_solver->column_is_fixed(c.var()))
|
||||
continue;
|
||||
add_to_explanation_from_fixed_or_boxed_column(j, ex);
|
||||
add_to_explanation_from_fixed_or_boxed_column(c.var(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -759,14 +770,13 @@ bool int_solver::gcd_test(explanation & ex) {
|
|||
auto & A = m_lar_solver->A_r(); // getting the matrix
|
||||
for (unsigned i = 0; i < A.row_count(); i++)
|
||||
if (!gcd_test_for_row(A, i, ex)) {
|
||||
std::cout << "false from gcd_test\n" ;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool int_solver::ext_gcd_test(iterator_on_row<mpq> & it,
|
||||
bool int_solver::ext_gcd_test(const row_strip<mpq> & row,
|
||||
mpq const & least_coeff,
|
||||
mpq const & lcm_den,
|
||||
mpq const & consts, explanation& ex) {
|
||||
|
@ -774,10 +784,11 @@ bool int_solver::ext_gcd_test(iterator_on_row<mpq> & it,
|
|||
mpq l(consts);
|
||||
mpq u(consts);
|
||||
|
||||
it.reset();
|
||||
mpq a;
|
||||
unsigned j;
|
||||
while (it.next(a, j)) {
|
||||
for (const auto & c : row) {
|
||||
j = c.var();
|
||||
const mpq & a = c.coeff();
|
||||
if (m_lar_solver->column_is_fixed(j))
|
||||
continue;
|
||||
SASSERT(!m_lar_solver->column_is_real(j));
|
||||
|
@ -817,20 +828,20 @@ bool int_solver::ext_gcd_test(iterator_on_row<mpq> & it,
|
|||
mpq u1 = floor(u/gcds);
|
||||
|
||||
if (u1 < l1) {
|
||||
fill_explanation_from_fixed_columns(it, ex);
|
||||
fill_explanation_from_fixed_columns(row, ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
linear_combination_iterator<mpq> * int_solver::get_column_iterator(unsigned j) {
|
||||
if (m_lar_solver->use_tableau())
|
||||
return new iterator_on_column<mpq, impq>(m_lar_solver->A_r().m_columns[j], m_lar_solver->A_r());
|
||||
return new iterator_on_indexed_vector<mpq>(m_lar_solver->get_column_in_lu_mode(j));
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
int_solver::int_solver(lar_solver* lar_slv) :
|
||||
m_lar_solver(lar_slv),
|
||||
|
@ -893,8 +904,7 @@ bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq
|
|||
return false;
|
||||
|
||||
impq const & xj = get_value(j);
|
||||
linear_combination_iterator<mpq> *it = get_column_iterator(j);
|
||||
|
||||
|
||||
inf_l = true;
|
||||
inf_u = true;
|
||||
l = u = zero_of_type<impq>();
|
||||
|
@ -909,7 +919,12 @@ bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq
|
|||
|
||||
mpq a; // the coefficient in the column
|
||||
unsigned row_index;
|
||||
while (it->next(a, row_index)) {
|
||||
lp_assert(settings().use_tableau());
|
||||
const auto & A = m_lar_solver->A_r();
|
||||
for (auto c : A.column(j)) {
|
||||
row_index = c.var();
|
||||
const mpq & a = c.coeff();
|
||||
|
||||
unsigned i = lcs.m_r_basis[row_index];
|
||||
impq const & xi = get_value(i);
|
||||
if (is_int(i) && is_int(j) && !a.is_int())
|
||||
|
@ -930,7 +945,6 @@ bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq
|
|||
if (!inf_l && !inf_u && l == u) break;;
|
||||
}
|
||||
|
||||
delete it;
|
||||
TRACE("freedom_interval",
|
||||
tout << "freedom variable for:\n";
|
||||
tout << m_lar_solver->get_column_name(j);
|
||||
|
@ -1062,21 +1076,16 @@ lp_settings& int_solver::settings() {
|
|||
|
||||
void int_solver::display_row_info(std::ostream & out, unsigned row_index) const {
|
||||
auto & rslv = m_lar_solver->m_mpq_lar_core_solver.m_r_solver;
|
||||
auto it = m_lar_solver->get_iterator_on_row(row_index);
|
||||
mpq a;
|
||||
unsigned j;
|
||||
while (it->next(a, j)) {
|
||||
if (numeric_traits<mpq>::is_pos(a))
|
||||
for (auto &c: rslv.m_A.m_rows[row_index]) {
|
||||
if (numeric_traits<mpq>::is_pos(c.coeff()))
|
||||
out << "+";
|
||||
out << a << rslv.column_name(j) << " ";
|
||||
out << c.coeff() << rslv.column_name(c.var()) << " ";
|
||||
}
|
||||
|
||||
it->reset();
|
||||
while(it->next(j)) {
|
||||
rslv.print_column_bound_info(j, out);
|
||||
for (auto& c: rslv.m_A.m_rows[row_index]) {
|
||||
rslv.print_column_bound_info(c.var(), out);
|
||||
}
|
||||
rslv.print_column_bound_info(rslv.m_basis[row_index], out);
|
||||
delete it;
|
||||
}
|
||||
|
||||
unsigned int_solver::random() {
|
||||
|
@ -1171,11 +1180,18 @@ const impq& int_solver::lower_bound(unsigned j) const {
|
|||
return m_lar_solver->column_lower_bound(j);
|
||||
}
|
||||
|
||||
lia_move int_solver::create_branch_on_column(int j, lar_term& t, mpq& k, bool free_column) const {
|
||||
lia_move int_solver::create_branch_on_column(int j, lar_term& t, mpq& k, bool free_column, bool & upper) {
|
||||
lp_assert(t.is_empty());
|
||||
lp_assert(j != -1);
|
||||
t.add_monomial(mpq(1), m_lar_solver->adjust_column_index_to_term_index(j));
|
||||
k = free_column? mpq(0) : floor(get_value(j));
|
||||
if (free_column) {
|
||||
upper = true;
|
||||
k = mpq(0);
|
||||
} else {
|
||||
upper = left_branch_is_more_narrow_than_right(j);
|
||||
k = upper? floor(get_value(j)) : ceil(get_value(j));
|
||||
}
|
||||
|
||||
TRACE("arith_int", tout << "branching v" << j << " = " << get_value(j) << "\n";
|
||||
display_column(tout, j);
|
||||
tout << "k = " << k << std::endl;
|
||||
|
@ -1184,6 +1200,25 @@ lia_move int_solver::create_branch_on_column(int j, lar_term& t, mpq& k, bool fr
|
|||
|
||||
}
|
||||
|
||||
bool int_solver::left_branch_is_more_narrow_than_right(unsigned j) {
|
||||
return settings().random_next() % 2;
|
||||
switch (m_lar_solver->m_mpq_lar_core_solver.m_r_solver.m_column_types[j] ) {
|
||||
case column_type::fixed:
|
||||
return false;
|
||||
case column_type::boxed:
|
||||
{
|
||||
auto k = floor(get_value(j));
|
||||
return k - lower_bound(j).x < upper_bound(j).x - (k + mpq(1));
|
||||
}
|
||||
case column_type::lower_bound:
|
||||
return true;
|
||||
case column_type::upper_bound:
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const impq& int_solver::upper_bound(unsigned j) const {
|
||||
return m_lar_solver->column_upper_bound(j);
|
||||
}
|
||||
|
@ -1205,19 +1240,14 @@ void int_solver::add_constraint_to_cut_solver(unsigned ci, const lar_base_constr
|
|||
vector<mono> coeffs;
|
||||
mpq rs;
|
||||
get_int_coeffs_from_constraint<mpq>(c, coeffs, rs);
|
||||
svector<constraint_index> explanation;
|
||||
explanation.push_back(ci);
|
||||
m_cut_solver.add_ineq(coeffs, -rs, explanation);
|
||||
}
|
||||
|
||||
void int_solver::notify_on_last_added_constraint() {
|
||||
unsigned ci = m_lar_solver->constraints().size() - 1;
|
||||
const lar_base_constraint* c = m_lar_solver->constraints()[ci];
|
||||
add_constraint_to_cut_solver(ci, c);
|
||||
m_cut_solver.add_ineq(coeffs, -rs, ci);
|
||||
}
|
||||
|
||||
void int_solver::pop(unsigned k) {
|
||||
m_cut_solver.pop(k);
|
||||
m_cut_solver.pop_trail(k);
|
||||
while (m_cut_solver.number_of_asserts() > m_lar_solver->constraints().size())
|
||||
m_cut_solver.pop_last_assert();
|
||||
m_cut_solver.pop_constraints();
|
||||
}
|
||||
|
||||
void int_solver::push() {
|
||||
|
|
|
@ -1,11 +1,25 @@
|
|||
/*
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
Author: Lev Nachmanson
|
||||
*/
|
||||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
Nikolaj Bjorner (nbjorner)
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
#include "util/lp/lp_settings.h"
|
||||
#include "util/lp/static_matrix.h"
|
||||
#include "util/lp/iterator_on_row.h"
|
||||
#include "util/lp/int_set.h"
|
||||
#include "util/lp/lar_term.h"
|
||||
#include "util/lp/cut_solver.h"
|
||||
|
@ -49,7 +63,7 @@ public:
|
|||
const int_set& inf_int_set() const;
|
||||
// main function to check that the solution provided by lar_solver is valid for integral values,
|
||||
// or provide a way of how it can be adjusted.
|
||||
lia_move check(lar_term& t, mpq& k, explanation& ex);
|
||||
lia_move check(lar_term& t, mpq& k, explanation& ex, bool & upper);
|
||||
bool move_non_basic_column_to_bounds(unsigned j);
|
||||
lia_move check_wrapper(lar_term& t, mpq& k, explanation& ex);
|
||||
private:
|
||||
|
@ -76,17 +90,16 @@ private:
|
|||
// creates a fresh inequality.
|
||||
|
||||
bool branch(const lp_constraint<mpq, mpq> & new_inequality);
|
||||
bool ext_gcd_test(iterator_on_row<mpq> & it,
|
||||
bool ext_gcd_test(const row_strip<mpq>& row,
|
||||
mpq const & least_coeff,
|
||||
mpq const & lcm_den,
|
||||
mpq const & consts,
|
||||
explanation & ex);
|
||||
void fill_explanation_from_fixed_columns(iterator_on_row<mpq> & it, explanation &);
|
||||
void fill_explanation_from_fixed_columns(const row_strip<mpq> & row, explanation &);
|
||||
void add_to_explanation_from_fixed_or_boxed_column(unsigned j, explanation &);
|
||||
void patch_int_infeasible_non_basic_column(unsigned j);
|
||||
void patch_int_infeasible_nbasic_columns();
|
||||
bool get_freedom_interval_for_column(unsigned j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m);
|
||||
linear_combination_iterator<mpq> * get_column_iterator(unsigned j);
|
||||
const impq & lower_bound(unsigned j) const;
|
||||
const impq & upper_bound(unsigned j) const;
|
||||
bool is_int(unsigned j) const;
|
||||
|
@ -112,14 +125,13 @@ private:
|
|||
lp_settings& settings();
|
||||
bool move_non_basic_columns_to_bounds();
|
||||
void branch_infeasible_int_var(unsigned);
|
||||
lia_move mk_gomory_cut(lar_term& t, mpq& k,explanation & ex, unsigned inf_col, linear_combination_iterator<mpq>& iter);
|
||||
lia_move mk_gomory_cut(lar_term& t, mpq& k,explanation & ex, unsigned inf_col, const row_strip<mpq>& row);
|
||||
lia_move report_conflict_from_gomory_cut(mpq & k);
|
||||
void adjust_term_and_k_for_some_ints_case_gomory(lar_term& t, mpq& k, mpq& lcm_den);
|
||||
void init_check_data();
|
||||
bool constrain_free_vars(linear_combination_iterator<mpq> * r);
|
||||
lia_move proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex, unsigned j);
|
||||
int find_free_var_in_gomory_row(linear_combination_iterator<mpq>& iter);
|
||||
bool is_gomory_cut_target(linear_combination_iterator<mpq> &iter);
|
||||
lia_move proceed_with_gomory_cut(lar_term& t, mpq& k, explanation& ex, unsigned j, bool & upper);
|
||||
int find_free_var_in_gomory_row(const row_strip<mpq>& );
|
||||
bool is_gomory_cut_target(const row_strip<mpq>&);
|
||||
bool at_bound(unsigned j) const;
|
||||
bool at_low(unsigned j) const;
|
||||
bool at_upper(unsigned j) const;
|
||||
|
@ -130,13 +142,15 @@ private:
|
|||
return is_zero(n.y);
|
||||
}
|
||||
|
||||
public:
|
||||
inline static
|
||||
mpq fractional_part(const impq & n) {
|
||||
lp_assert(is_rational(n));
|
||||
return n.x - floor(n.x);
|
||||
}
|
||||
void real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& t, explanation & ex, unsigned inf_column);
|
||||
void int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& t, explanation& ex, mpq & lcm_den, unsigned inf_column);
|
||||
private:
|
||||
void real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& t, explanation & ex, const mpq& f_0, const mpq& one_minus_f_0);
|
||||
void int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& t, explanation& ex, mpq & lcm_den, const mpq& f_0, const mpq& one_minus_f_0);
|
||||
constraint_index column_upper_bound_constraint(unsigned j) const;
|
||||
constraint_index column_lower_bound_constraint(unsigned j) const;
|
||||
void display_row_info(std::ostream & out, unsigned row_index) const;
|
||||
|
@ -147,7 +161,8 @@ public:
|
|||
private:
|
||||
unsigned random();
|
||||
bool has_inf_int() const;
|
||||
lia_move create_branch_on_column(int j, lar_term& t, mpq& k, bool free_column) const;
|
||||
lia_move create_branch_on_column(int j, lar_term& t, mpq& k, bool free_column, bool & upper);
|
||||
void catch_up_in_adding_constraints_to_cut_solver();
|
||||
public:
|
||||
void display_inf_or_int_inf_columns(std::ostream & out) const;
|
||||
template <typename T>
|
||||
|
@ -155,11 +170,11 @@ public:
|
|||
template <typename T>
|
||||
void get_int_coeffs_from_constraint(const lar_base_constraint* c, vector<cut_solver::monomial>& coeff, T & rs);
|
||||
bool is_term(unsigned j) const;
|
||||
void notify_on_last_added_constraint();
|
||||
void add_constraint_to_cut_solver(unsigned,const lar_base_constraint*);
|
||||
void copy_explanations_from_cut_solver(explanation &);
|
||||
void pop(unsigned);
|
||||
void push();
|
||||
void copy_values_from_cut_solver();
|
||||
bool left_branch_is_more_narrow_than_right(unsigned);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
#include "util/lp/linear_combination_iterator.h"
|
||||
#include "util/lp/static_matrix.h"
|
||||
#include "util/lp/lar_term.h"
|
||||
namespace lp {
|
||||
template <typename T, typename X>
|
||||
struct iterator_on_column:linear_combination_iterator<T> {
|
||||
const vector<column_cell>& m_column; // the offset in term coeffs
|
||||
const static_matrix<T, X> & m_A;
|
||||
int m_i; // the initial offset in the column
|
||||
unsigned size() const override { return m_column.size(); }
|
||||
iterator_on_column(const vector<column_cell>& column, const static_matrix<T,X> & A) // the offset in term coeffs
|
||||
:
|
||||
m_column(column),
|
||||
m_A(A),
|
||||
m_i(-1) {}
|
||||
|
||||
bool next(mpq & a, unsigned & i) override {
|
||||
if (++m_i >= static_cast<int>(m_column.size()))
|
||||
return false;
|
||||
|
||||
const column_cell& c = m_column[m_i];
|
||||
a = m_A.get_val(c);
|
||||
i = c.m_i;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool next(unsigned & i) override {
|
||||
if (++m_i >= static_cast<int>(m_column.size()))
|
||||
return false;
|
||||
|
||||
const column_cell& c = m_column[m_i];
|
||||
i = c.m_i;
|
||||
return true;
|
||||
}
|
||||
|
||||
void reset() override {
|
||||
m_i = -1;
|
||||
}
|
||||
|
||||
bool is_reset() const { return m_i == -1;}
|
||||
|
||||
linear_combination_iterator<mpq> * clone() {
|
||||
iterator_on_column * r = new iterator_on_column(m_column, m_A);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
#include "util/lp/linear_combination_iterator.h"
|
||||
namespace lp {
|
||||
template <typename T>
|
||||
struct iterator_on_indexed_vector:linear_combination_iterator<T> {
|
||||
const indexed_vector<T> & m_v;
|
||||
unsigned m_offset;
|
||||
iterator_on_indexed_vector(const indexed_vector<T> & v) :
|
||||
m_v(v),
|
||||
m_offset(0)
|
||||
{}
|
||||
unsigned size() const override { return m_v.m_index.size(); }
|
||||
bool next(T & a, unsigned & i) override {
|
||||
if (m_offset >= m_v.m_index.size())
|
||||
return false;
|
||||
i = m_v.m_index[m_offset++];
|
||||
a = m_v.m_data[i];
|
||||
return true;
|
||||
}
|
||||
|
||||
bool next(unsigned & i) override {
|
||||
if (m_offset >= m_v.m_index.size())
|
||||
return false;
|
||||
i = m_v.m_index[m_offset++];
|
||||
return true;
|
||||
}
|
||||
void reset() override {
|
||||
m_offset = 0;
|
||||
}
|
||||
|
||||
bool is_reset() const { return m_offset == 0;}
|
||||
|
||||
linear_combination_iterator<T>* clone() {
|
||||
return new iterator_on_indexed_vector(m_v);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
#include "util/lp/iterator_on_indexed_vector.h"
|
||||
namespace lp {
|
||||
template <typename T>
|
||||
struct iterator_on_pivot_row:linear_combination_iterator<T> {
|
||||
bool m_basis_returned;
|
||||
const indexed_vector<T> & m_v;
|
||||
unsigned m_basis_j;
|
||||
iterator_on_indexed_vector<T> m_it;
|
||||
unsigned size() const override { return m_it.size(); }
|
||||
iterator_on_pivot_row(const indexed_vector<T> & v, unsigned basis_j) :
|
||||
m_basis_returned(false),
|
||||
m_v(v), m_basis_j(basis_j), m_it(v) {}
|
||||
bool next(T & a, unsigned & i) override {
|
||||
if (m_basis_returned == false) {
|
||||
m_basis_returned = true;
|
||||
a = one_of_type<T>();
|
||||
i = m_basis_j;
|
||||
return true;
|
||||
}
|
||||
return m_it.next(a, i);
|
||||
}
|
||||
bool next(unsigned & i) override {
|
||||
if (m_basis_returned == false) {
|
||||
m_basis_returned = true;
|
||||
i = m_basis_j;
|
||||
return true;
|
||||
}
|
||||
return m_it.next(i);
|
||||
}
|
||||
void reset() override {
|
||||
m_basis_returned = false;
|
||||
m_it.reset();
|
||||
}
|
||||
|
||||
bool is_reset() const { return m_basis_returned == false && m_it.is_reset();}
|
||||
|
||||
linear_combination_iterator<T> * clone() {
|
||||
iterator_on_pivot_row * r = new iterator_on_pivot_row(m_v, m_basis_j);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
#include "util/lp/linear_combination_iterator.h"
|
||||
namespace lp {
|
||||
template <typename T>
|
||||
struct iterator_on_row:linear_combination_iterator<T> {
|
||||
const vector<row_cell<T>> & m_row;
|
||||
unsigned m_i; // offset
|
||||
iterator_on_row(const vector<row_cell<T>> & row) : m_row(row), m_i(0)
|
||||
{}
|
||||
unsigned size() const override { return m_row.size(); }
|
||||
bool next(T & a, unsigned & i) override {
|
||||
if (m_i == m_row.size())
|
||||
return false;
|
||||
auto &c = m_row[m_i++];
|
||||
i = c.m_j;
|
||||
a = c.get_val();
|
||||
return true;
|
||||
}
|
||||
bool next(unsigned & i) override {
|
||||
if (m_i == m_row.size())
|
||||
return false;
|
||||
auto &c = m_row[m_i++];
|
||||
i = c.m_j;
|
||||
return true;
|
||||
}
|
||||
void reset() override {
|
||||
m_i = 0;
|
||||
}
|
||||
|
||||
bool is_reset() const { return m_i == 0;}
|
||||
|
||||
linear_combination_iterator<T>* clone() {
|
||||
return new iterator_on_row(m_row);
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
#include "util/lp/linear_combination_iterator.h"
|
||||
#include "util/lp/numeric_pair.h"
|
||||
#include "util/lp/lar_term.h"
|
||||
namespace lp {
|
||||
struct iterator_on_term_with_basis_var:linear_combination_iterator<mpq> {
|
||||
const lar_term & m_term;
|
||||
std::unordered_map<unsigned, mpq>::const_iterator m_i; // the offset in term coeffs
|
||||
bool m_term_j_returned;
|
||||
unsigned m_term_j;
|
||||
unsigned size() const override {return static_cast<unsigned>(m_term.m_coeffs.size() + 1);}
|
||||
iterator_on_term_with_basis_var(const lar_term & t, unsigned term_j) :
|
||||
m_term(t),
|
||||
m_i(t.m_coeffs.begin()),
|
||||
m_term_j_returned(false),
|
||||
m_term_j(term_j) {}
|
||||
|
||||
bool next(mpq & a, unsigned & i) override {
|
||||
if (m_term_j_returned == false) {
|
||||
m_term_j_returned = true;
|
||||
a = - one_of_type<mpq>();
|
||||
i = m_term_j;
|
||||
return true;
|
||||
}
|
||||
if (m_i == m_term.m_coeffs.end())
|
||||
return false;
|
||||
i = m_i->first;
|
||||
a = m_i->second;
|
||||
m_i++;
|
||||
return true;
|
||||
}
|
||||
bool next(unsigned & i) override {
|
||||
if (m_term_j_returned == false) {
|
||||
m_term_j_returned = true;
|
||||
i = m_term_j;
|
||||
return true;
|
||||
}
|
||||
if (m_i == m_term.m_coeffs.end())
|
||||
return false;
|
||||
i = m_i->first;
|
||||
m_i++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_reset() const { return m_term_j_returned == false && m_i == m_term.m_coeffs.begin();}
|
||||
|
||||
void reset() {
|
||||
m_term_j_returned = false;
|
||||
m_i = m_term.m_coeffs.begin();
|
||||
}
|
||||
linear_combination_iterator<mpq> * clone() override {
|
||||
iterator_on_term_with_basis_var * r = new iterator_on_term_with_basis_var(m_term, m_term_j);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
}
|
|
@ -30,8 +30,6 @@ Revision History:
|
|||
#include "util/lp/lp_primal_core_solver.h"
|
||||
#include "util/lp/stacked_vector.h"
|
||||
#include "util/lp/lar_solution_signature.h"
|
||||
#include "util/lp/iterator_on_column.h"
|
||||
#include "util/lp/iterator_on_indexed_vector.h"
|
||||
#include "util/lp/stacked_value.h"
|
||||
namespace lp {
|
||||
|
||||
|
@ -801,15 +799,6 @@ public:
|
|||
m_r_solver.init_column_row_non_zeroes();
|
||||
}
|
||||
|
||||
linear_combination_iterator<mpq> * get_column_iterator(unsigned j) {
|
||||
if (settings().use_tableau()) {
|
||||
return new iterator_on_column<mpq, numeric_pair<mpq>>(m_r_solver.m_A.m_columns[j], m_r_solver.m_A);
|
||||
} else {
|
||||
m_r_solver.solve_Bd(j);
|
||||
return new iterator_on_indexed_vector<mpq>(m_r_solver.m_ed);
|
||||
}
|
||||
}
|
||||
|
||||
bool column_is_fixed(unsigned j) const {
|
||||
return m_column_types()[j] == column_type::fixed ||
|
||||
( m_column_types()[j] == column_type::boxed &&
|
||||
|
|
|
@ -151,9 +151,10 @@ void lar_solver::analyze_new_bounds_on_row(
|
|||
unsigned row_index,
|
||||
bound_propagator & bp) {
|
||||
lp_assert(!use_tableau());
|
||||
iterator_on_pivot_row<mpq> it(m_mpq_lar_core_solver.get_pivot_row(), m_mpq_lar_core_solver.m_r_basis[row_index]);
|
||||
|
||||
bound_analyzer_on_row ra_pos(it,
|
||||
unsigned j = m_mpq_lar_core_solver.m_r_basis[row_index]; // basis column for the row
|
||||
bound_analyzer_on_row<indexed_vector<mpq>>
|
||||
ra_pos(m_mpq_lar_core_solver.get_pivot_row(),
|
||||
j,
|
||||
zero_of_type<numeric_pair<mpq>>(),
|
||||
row_index,
|
||||
bp
|
||||
|
@ -163,14 +164,14 @@ void lar_solver::analyze_new_bounds_on_row(
|
|||
|
||||
void lar_solver::analyze_new_bounds_on_row_tableau(
|
||||
unsigned row_index,
|
||||
bound_propagator & bp
|
||||
) {
|
||||
bound_propagator & bp ) {
|
||||
|
||||
if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation)
|
||||
return;
|
||||
iterator_on_row<mpq> it(A_r().m_rows[row_index]);
|
||||
|
||||
lp_assert(use_tableau());
|
||||
bound_analyzer_on_row::analyze_row(it,
|
||||
bound_analyzer_on_row<row_strip<mpq>>::analyze_row(A_r().m_rows[row_index],
|
||||
static_cast<unsigned>(-1),
|
||||
zero_of_type<numeric_pair<mpq>>(),
|
||||
row_index,
|
||||
bp
|
||||
|
@ -200,13 +201,6 @@ void lar_solver::calculate_implied_bounds_for_row(unsigned i, bound_propagator &
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
linear_combination_iterator<mpq> * lar_solver::create_new_iter_from_term(unsigned term_index) const {
|
||||
lp_assert(false); // not implemented
|
||||
return nullptr;
|
||||
// new linear_combination_iterator_on_vector<mpq>(m_terms[adjust_term_index(term_index)]->coeffs_as_vector());
|
||||
}
|
||||
|
||||
unsigned lar_solver::adjust_column_index_to_term_index(unsigned j) const {
|
||||
unsigned ext_var_or_term = m_columns_to_ext_vars_or_term_indices[j];
|
||||
return ext_var_or_term < m_terms_start_index ? j : ext_var_or_term;
|
||||
|
@ -407,6 +401,9 @@ void lar_solver::pop(unsigned k) {
|
|||
m_constraints.resize(m_constraint_count);
|
||||
m_term_count.pop(k);
|
||||
for (unsigned i = m_term_count; i < m_terms.size(); i++) {
|
||||
#if Z3DEBUG_CHECK_UNIQUE_TERMS
|
||||
m_set_of_terms.erase(m_terms[i]);
|
||||
#endif
|
||||
delete m_terms[i];
|
||||
}
|
||||
m_terms.resize(m_term_count);
|
||||
|
@ -595,7 +592,8 @@ void lar_solver::substitute_terms_in_linear_expression(const vector<std::pair<mp
|
|||
}
|
||||
|
||||
for (auto & p : coeffs)
|
||||
left_side.push_back(std::make_pair(p.second, p.first));
|
||||
if (!is_zero(p.second))
|
||||
left_side.push_back(std::make_pair(p.second, p.first));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1023,7 +1021,7 @@ bool lar_solver::the_right_sides_do_not_sum_to_zero(const vector<std::pair<mpq,
|
|||
}
|
||||
|
||||
bool lar_solver::explanation_is_correct(const vector<std::pair<mpq, unsigned>>& explanation) const {
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
lconstraint_kind kind;
|
||||
lp_assert(the_relations_are_of_same_type(explanation, kind));
|
||||
lp_assert(the_left_sides_sum_to_zero(explanation));
|
||||
|
@ -1048,7 +1046,7 @@ bool lar_solver::explanation_is_correct(const vector<std::pair<mpq, unsigned>>&
|
|||
}
|
||||
|
||||
bool lar_solver::inf_explanation_is_correct() const {
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
vector<std::pair<mpq, unsigned>> explanation;
|
||||
get_infeasibility_explanation(explanation);
|
||||
return explanation_is_correct(explanation);
|
||||
|
@ -1190,6 +1188,7 @@ void lar_solver::print_constraint(constraint_index ci, std::ostream & out) const
|
|||
}
|
||||
|
||||
void lar_solver::print_constraints(std::ostream& out) const {
|
||||
out << "number of constraints = " << m_constraints.size() << std::endl;
|
||||
for (auto c : m_constraints) {
|
||||
print_constraint(c, out);
|
||||
}
|
||||
|
@ -1214,7 +1213,26 @@ void lar_solver::print_term(lar_term const& term, std::ostream & out) const {
|
|||
if (!numeric_traits<mpq>::is_zero(term.m_v)) {
|
||||
out << term.m_v << " + ";
|
||||
}
|
||||
print_linear_combination_of_column_indices(term.coeffs_as_vector(), out);
|
||||
bool first = true;
|
||||
for (const auto p : term) {
|
||||
mpq val = p.coeff();
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
if (is_pos(val)) {
|
||||
out << " + ";
|
||||
} else {
|
||||
out << " - ";
|
||||
val = -val;
|
||||
}
|
||||
}
|
||||
if (val == -numeric_traits<mpq>::one())
|
||||
out << " - ";
|
||||
else if (val != numeric_traits<mpq>::one())
|
||||
out << T_to_string(val);
|
||||
out << this->get_column_name(p.var());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void lar_solver::print_term_as_indices(lar_term const& term, std::ostream & out) const {
|
||||
|
@ -1584,17 +1602,59 @@ void lar_solver::add_new_var_to_core_fields_for_mpq(bool register_in_basis) {
|
|||
|
||||
var_index lar_solver::add_term_undecided(const vector<std::pair<mpq, var_index>> & coeffs,
|
||||
const mpq &m_v) {
|
||||
m_terms.push_back(new lar_term(coeffs, m_v));
|
||||
push_and_register_term(new lar_term(coeffs, m_v));
|
||||
return m_terms_start_index + m_terms.size() - 1;
|
||||
}
|
||||
|
||||
#if Z3DEBUG_CHECK_UNIQUE_TERMS
|
||||
bool lar_solver::term_coeffs_are_ok(const vector<std::pair<mpq, var_index>> & coeffs, const mpq& v) {
|
||||
if (coeffs.empty()) {
|
||||
return is_zero(v);
|
||||
}
|
||||
|
||||
for (const auto & p : coeffs) {
|
||||
if (column_is_real(p.second))
|
||||
return true;
|
||||
}
|
||||
|
||||
mpq g;
|
||||
bool g_is_set = false;
|
||||
for (const auto & p : coeffs) {
|
||||
if (!p.first.is_int()) {
|
||||
std::cout << "p.first = " << p.first << " is not an int\n";
|
||||
return false;
|
||||
}
|
||||
if (!g_is_set) {
|
||||
g_is_set = true;
|
||||
g = p.first;
|
||||
} else {
|
||||
g = gcd(g, p.first);
|
||||
}
|
||||
}
|
||||
if (g == one_of_type<mpq>())
|
||||
return true;
|
||||
|
||||
std::cout << "term is not ok: g = " << g << std::endl;
|
||||
this->print_linear_combination_of_column_indices_only(coeffs, std::cout);
|
||||
std::cout << " rs = " << v << std::endl;
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
void lar_solver::push_and_register_term(lar_term* t) {
|
||||
#if Z3DEBUG_CHECK_UNIQUE_TERMS
|
||||
lp_assert(m_set_of_terms.find(t) == m_set_of_terms.end());
|
||||
m_set_of_terms.insert(t);
|
||||
#endif
|
||||
m_terms.push_back(t);
|
||||
}
|
||||
|
||||
// terms
|
||||
var_index lar_solver::add_term(const vector<std::pair<mpq, var_index>> & coeffs,
|
||||
const mpq &m_v) {
|
||||
if (strategy_is_undecided())
|
||||
return add_term_undecided(coeffs, m_v);
|
||||
|
||||
m_terms.push_back(new lar_term(coeffs, m_v));
|
||||
push_and_register_term(new lar_term(coeffs, m_v));
|
||||
unsigned adjusted_term_index = m_terms.size() - 1;
|
||||
var_index ret = m_terms_start_index + adjusted_term_index;
|
||||
if (use_tableau() && !coeffs.empty()) {
|
||||
|
@ -1607,6 +1667,7 @@ var_index lar_solver::add_term(const vector<std::pair<mpq, var_index>> & coeffs,
|
|||
}
|
||||
|
||||
void lar_solver::add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) {
|
||||
TRACE("dump_terms", print_term(*term, tout); tout << std::endl;);
|
||||
register_new_ext_var_index(term_ext_index, term_is_int(term));
|
||||
// j will be a new variable
|
||||
unsigned j = A_r().column_count();
|
||||
|
@ -1614,8 +1675,8 @@ void lar_solver::add_row_from_term_no_constraint(const lar_term * term, unsigned
|
|||
m_columns_to_ul_pairs.push_back(ul);
|
||||
add_basic_var_to_core_fields();
|
||||
if (use_tableau()) {
|
||||
auto it = iterator_on_term_with_basis_var(*term, j);
|
||||
A_r().fill_last_row_with_pivoting(it,
|
||||
A_r().fill_last_row_with_pivoting(*term,
|
||||
j,
|
||||
m_mpq_lar_core_solver.m_r_solver.m_basis_heading);
|
||||
m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type<mpq>());
|
||||
}
|
||||
|
@ -1653,9 +1714,6 @@ constraint_index lar_solver::add_var_bound(var_index j, lconstraint_kind kind, c
|
|||
lp_assert(bound_is_integer_for_integer_column(j, right_side));
|
||||
auto vc = new lar_var_constraint(j, kind, right_side);
|
||||
m_constraints.push_back(vc);
|
||||
if (has_int_var()) {
|
||||
m_int_solver->notify_on_last_added_constraint();
|
||||
}
|
||||
update_column_type_and_bound(j, kind, right_side, ci);
|
||||
}
|
||||
else {
|
||||
|
@ -1697,8 +1755,6 @@ void lar_solver::add_var_bound_on_constraint_for_term(var_index j, lconstraint_k
|
|||
unsigned term_j = it->second.internal_j();
|
||||
mpq rs = right_side - m_terms[adjusted_term_index]->m_v;
|
||||
m_constraints.push_back(new lar_term_constraint(m_terms[adjusted_term_index], kind, right_side));
|
||||
if (has_int_var())
|
||||
m_int_solver->notify_on_last_added_constraint();
|
||||
update_column_type_and_bound(term_j, kind, rs, ci);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -37,15 +37,13 @@ Revision History:
|
|||
#include "util/lp/stacked_value.h"
|
||||
#include "util/lp/stacked_vector.h"
|
||||
#include "util/lp/stacked_unordered_set.h"
|
||||
#include "util/lp/iterator_on_pivot_row.h"
|
||||
#include "util/lp/implied_bound.h"
|
||||
#include "util/lp/bound_analyzer_on_row.h"
|
||||
#include "util/lp/iterator_on_term_with_basis_var.h"
|
||||
#include "util/lp/iterator_on_row.h"
|
||||
#include "util/lp/quick_xplain.h"
|
||||
#include "util/lp/conversion_helper.h"
|
||||
#include "util/lp/int_solver.h"
|
||||
#include "util/lp/nra_solver.h"
|
||||
#include "util/lp/bound_propagator.h"
|
||||
|
||||
namespace lp {
|
||||
|
||||
|
@ -60,30 +58,71 @@ class lar_solver : public column_namer {
|
|||
unsigned internal_j() const { return m_internal_j;}
|
||||
bool is_integer() const {return m_is_integer;}
|
||||
};
|
||||
#if Z3DEBUG_CHECK_UNIQUE_TERMS
|
||||
struct term_hasher {
|
||||
std::size_t operator()(const lar_term *t) const
|
||||
{
|
||||
using std::size_t;
|
||||
using std::hash;
|
||||
using std::string;
|
||||
size_t seed = 0;
|
||||
for (const auto& p : t->m_coeffs) {
|
||||
hash_combine(seed, p);
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
struct term_ls_comparer {
|
||||
bool operator()(const lar_term *a, const lar_term* b) const
|
||||
{
|
||||
// a is contained in b
|
||||
for (auto & p : a->m_coeffs) {
|
||||
auto t = b->m_coeffs.find(p.first);
|
||||
if (t == b->m_coeffs.end())
|
||||
return false;
|
||||
if (p.second != t->second)
|
||||
return false;
|
||||
}
|
||||
// zz is contained in b
|
||||
for (auto & p : b->m_coeffs) {
|
||||
auto t = a->m_coeffs.find(p.first);
|
||||
if (t == a->m_coeffs.end())
|
||||
return false;
|
||||
if (p.second != t->second)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
std::unordered_set<lar_term*, term_hasher, term_ls_comparer> m_set_of_terms;
|
||||
#endif
|
||||
|
||||
//////////////////// fields //////////////////////////
|
||||
lp_settings m_settings;
|
||||
lp_status m_status;
|
||||
stacked_value<simplex_strategy_enum> m_simplex_strategy;
|
||||
std::unordered_map<unsigned, ext_var_info> m_ext_vars_to_columns;
|
||||
vector<unsigned> m_columns_to_ext_vars_or_term_indices;
|
||||
stacked_vector<ul_pair> m_columns_to_ul_pairs;
|
||||
vector<lar_base_constraint*> m_constraints;
|
||||
lp_settings m_settings;
|
||||
lp_status m_status;
|
||||
stacked_value<simplex_strategy_enum> m_simplex_strategy;
|
||||
std::unordered_map<unsigned, ext_var_info> m_ext_vars_to_columns;
|
||||
vector<unsigned> m_columns_to_ext_vars_or_term_indices;
|
||||
stacked_vector<ul_pair> m_columns_to_ul_pairs;
|
||||
vector<lar_base_constraint*> m_constraints;
|
||||
private:
|
||||
stacked_value<unsigned> m_constraint_count;
|
||||
// the set of column indices j such that bounds have changed for j
|
||||
int_set m_columns_with_changed_bound;
|
||||
int_set m_rows_with_changed_bounds;
|
||||
int_set m_basic_columns_with_changed_cost;
|
||||
stacked_value<int> m_infeasible_column_index; // such can be found at the initialization step
|
||||
stacked_value<unsigned> m_term_count;
|
||||
vector<lar_term*> m_terms;
|
||||
const var_index m_terms_start_index;
|
||||
indexed_vector<mpq> m_column_buffer;
|
||||
|
||||
|
||||
public :
|
||||
const vector<lar_base_constraint*>& constraints() const {
|
||||
return m_constraints;
|
||||
}
|
||||
private:
|
||||
stacked_value<unsigned> m_constraint_count;
|
||||
// the set of column indices j such that bounds have changed for j
|
||||
int_set m_columns_with_changed_bound;
|
||||
int_set m_rows_with_changed_bounds;
|
||||
int_set m_basic_columns_with_changed_cost;
|
||||
stacked_value<int> m_infeasible_column_index; // such can be found at the initialization step
|
||||
stacked_value<unsigned> m_term_count;
|
||||
vector<lar_term*> m_terms;
|
||||
const var_index m_terms_start_index;
|
||||
indexed_vector<mpq> m_column_buffer;
|
||||
public:
|
||||
lar_core_solver m_mpq_lar_core_solver;
|
||||
private:
|
||||
std::function<void (unsigned)> m_tracker_of_x_change;
|
||||
|
@ -138,13 +177,17 @@ public:
|
|||
void add_new_var_to_core_fields_for_mpq(bool register_in_basis);
|
||||
|
||||
|
||||
var_index add_term_undecided(const vector<std::pair<mpq, var_index>> & coeffs,
|
||||
const mpq &m_v);
|
||||
|
||||
// terms
|
||||
var_index add_term(const vector<std::pair<mpq, var_index>> & coeffs,
|
||||
const mpq &m_v);
|
||||
|
||||
var_index add_term_undecided(const vector<std::pair<mpq, var_index>> & coeffs,
|
||||
const mpq &m_v);
|
||||
|
||||
bool term_coeffs_are_ok(const vector<std::pair<mpq, var_index>> & coeffs, const mpq& v);
|
||||
void push_and_register_term(lar_term* t);
|
||||
|
||||
void add_row_for_term(const lar_term * term, unsigned term_ext_index);
|
||||
|
||||
void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index);
|
||||
|
@ -218,9 +261,6 @@ public:
|
|||
|
||||
void calculate_implied_bounds_for_row(unsigned i, bound_propagator & bp);
|
||||
|
||||
|
||||
linear_combination_iterator<mpq> * create_new_iter_from_term(unsigned term_index) const;
|
||||
|
||||
unsigned adjust_column_index_to_term_index(unsigned j) const;
|
||||
|
||||
void propagate_bounds_on_a_term(const lar_term& t, bound_propagator & bp, unsigned term_offset);
|
||||
|
@ -301,8 +341,6 @@ public:
|
|||
|
||||
void detect_rows_of_bound_change_column_for_nbasic_column(unsigned j);
|
||||
|
||||
|
||||
|
||||
void detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j);
|
||||
|
||||
bool use_tableau() const;
|
||||
|
@ -479,10 +517,12 @@ public:
|
|||
}
|
||||
|
||||
bool bound_is_integer_for_integer_column(unsigned j, const mpq & right_side) const;
|
||||
linear_combination_iterator<mpq> * get_iterator_on_row(unsigned i) {
|
||||
return m_mpq_lar_core_solver.m_r_solver.get_iterator_on_row(i);
|
||||
|
||||
const row_strip<mpq> & get_row(unsigned i) {
|
||||
return A_r().m_rows[i];
|
||||
}
|
||||
|
||||
|
||||
unsigned get_base_column_in_row(unsigned row_index) const {
|
||||
return m_mpq_lar_core_solver.m_r_solver.get_base_column_in_row(row_index);
|
||||
}
|
||||
|
@ -495,17 +535,20 @@ public:
|
|||
return m_columns_to_ul_pairs()[j].lower_bound_witness();
|
||||
}
|
||||
|
||||
void subs_terms_for_debugging(lar_term& t) {
|
||||
vector<std::pair<mpq, unsigned>> pol;
|
||||
void subs_term_columns(lar_term& t) {
|
||||
vector<std::pair<unsigned,unsigned>> columns_to_subs;
|
||||
for (const auto & m : t.m_coeffs) {
|
||||
pol.push_back(std::make_pair(m.second, adjust_column_index_to_term_index(m.first)));
|
||||
unsigned tj = adjust_column_index_to_term_index(m.first);
|
||||
if (tj == m.first) continue;
|
||||
columns_to_subs.push_back(std::make_pair(m.first, tj));
|
||||
}
|
||||
for (const auto & p : columns_to_subs) {
|
||||
auto it = t.m_coeffs.find(p.first);
|
||||
lp_assert(it != t.m_coeffs.end());
|
||||
mpq v = it->second;
|
||||
t.m_coeffs.erase(it);
|
||||
t.m_coeffs[p.second] = v;
|
||||
}
|
||||
mpq v = t.m_v;
|
||||
|
||||
vector<std::pair<mpq, unsigned>> pol_after_subs;
|
||||
substitute_terms_in_linear_expression(pol, pol_after_subs, v);
|
||||
t.clear();
|
||||
t = lar_term(pol_after_subs, v);
|
||||
}
|
||||
|
||||
bool inf_int_set_is_correct_for_column(unsigned j) const {
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
Author:
|
||||
|
||||
Lev Nachmanson (levnach)
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
--*/
|
||||
#pragma once
|
||||
#include "util/lp/indexed_vector.h"
|
||||
namespace lp {
|
||||
|
@ -85,11 +85,55 @@ struct lar_term {
|
|||
t.second.neg();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T apply(const vector<T>& x) const {
|
||||
T ret = T(m_v);
|
||||
for (const auto & t : m_coeffs) {
|
||||
ret += t.second * x[t.first];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_coeffs.clear();
|
||||
m_v = zero_of_type<mpq>();
|
||||
}
|
||||
|
||||
struct ival {
|
||||
unsigned m_var;
|
||||
const mpq & m_coeff;
|
||||
ival(unsigned var, const mpq & val) : m_var(var), m_coeff(val) {
|
||||
}
|
||||
unsigned var() const { return m_var;}
|
||||
const mpq & coeff() const { return m_coeff; }
|
||||
};
|
||||
|
||||
struct const_iterator {
|
||||
//fields
|
||||
std::unordered_map<unsigned, mpq>::const_iterator m_it;
|
||||
|
||||
typedef const_iterator self_type;
|
||||
typedef ival value_type;
|
||||
typedef ival reference;
|
||||
// typedef std::pair<const unsigned, mpq>* pointer;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
reference operator*() const {
|
||||
return ival(m_it->first, m_it->second);
|
||||
}
|
||||
|
||||
self_type operator++() { self_type i = *this; m_it++; return i; }
|
||||
self_type operator++(int) { m_it++; return *this; }
|
||||
|
||||
const_iterator(std::unordered_map<unsigned, mpq>::const_iterator it) : m_it(it) {}
|
||||
bool operator==(const self_type &other) const {
|
||||
return m_it == other.m_it;
|
||||
}
|
||||
bool operator!=(const self_type &other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
const_iterator begin() const { return m_coeffs.begin();}
|
||||
const_iterator end() const { return m_coeffs.end(); }
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
namespace lp {
|
||||
template <typename T>
|
||||
struct linear_combination_iterator {
|
||||
virtual bool next(T & a, unsigned & i) = 0;
|
||||
virtual bool next(unsigned & i) = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual linear_combination_iterator * clone() = 0;
|
||||
virtual ~linear_combination_iterator(){}
|
||||
virtual unsigned size() const = 0;
|
||||
virtual bool is_reset() const = 0;
|
||||
};
|
||||
template <typename T>
|
||||
struct linear_combination_iterator_on_vector : linear_combination_iterator<T> {
|
||||
vector<std::pair<T, unsigned>> & m_vector;
|
||||
int m_offset;
|
||||
bool next(T & a, unsigned & i) {
|
||||
if(static_cast<unsigned>(m_offset) >= m_vector.size())
|
||||
return false;
|
||||
auto & p = m_vector[m_offset];
|
||||
a = p.first;
|
||||
i = p.second;
|
||||
m_offset++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool next(unsigned & i) {
|
||||
if(static_cast<unsigned>(m_offset) >= m_vector.size())
|
||||
return false;
|
||||
auto & p = m_vector[m_offset];
|
||||
i = p.second;
|
||||
m_offset++;
|
||||
return true;
|
||||
}
|
||||
bool is_reset() const { return m_offset == 0;}
|
||||
void reset() {m_offset = 0;}
|
||||
linear_combination_iterator<T> * clone() {
|
||||
return new linear_combination_iterator_on_vector(m_vector);
|
||||
}
|
||||
linear_combination_iterator_on_vector(vector<std::pair<T, unsigned>> & vec):
|
||||
m_vector(vec),
|
||||
m_offset(0)
|
||||
{}
|
||||
unsigned size() const { return m_vector.size(); }
|
||||
};
|
||||
|
||||
}
|
|
@ -1,67 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#include "util/lp/lar_solver.h"
|
||||
namespace lp {
|
||||
lp_bound_propagator::lp_bound_propagator(lar_solver & ls):
|
||||
m_lar_solver(ls) {}
|
||||
column_type lp_bound_propagator::get_column_type(unsigned j) const {
|
||||
return m_lar_solver.m_mpq_lar_core_solver.m_column_types()[j];
|
||||
}
|
||||
const impq & lp_bound_propagator::get_low_bound(unsigned j) const {
|
||||
return m_lar_solver.m_mpq_lar_core_solver.m_r_low_bounds()[j];
|
||||
}
|
||||
const impq & lp_bound_propagator::get_upper_bound(unsigned j) const {
|
||||
return m_lar_solver.m_mpq_lar_core_solver.m_r_upper_bounds()[j];
|
||||
}
|
||||
void lp_bound_propagator::try_add_bound(const mpq & v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) {
|
||||
unsigned term_j = m_lar_solver.adjust_column_index_to_term_index(j);
|
||||
mpq w = v;
|
||||
if (term_j != j) {
|
||||
j = term_j;
|
||||
w += m_lar_solver.get_term(term_j).m_v; // when terms are turned into the columns they "lose" the right side, at this moment they aquire it back
|
||||
}
|
||||
lconstraint_kind kind = is_low? GE : LE;
|
||||
if (strict)
|
||||
kind = static_cast<lconstraint_kind>(kind / 2);
|
||||
|
||||
if (!bound_is_interesting(j, kind, w))
|
||||
return;
|
||||
unsigned k; // index to ibounds
|
||||
if (is_low) {
|
||||
if (try_get_val(m_improved_low_bounds, j, k)) {
|
||||
auto & found_bound = m_ibounds[k];
|
||||
if (w > found_bound.m_bound || (w == found_bound.m_bound && found_bound.m_strict == false && strict))
|
||||
found_bound = implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
|
||||
} else {
|
||||
m_improved_low_bounds[j] = m_ibounds.size();
|
||||
m_ibounds.push_back(implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
|
||||
}
|
||||
} else { // the upper bound case
|
||||
if (try_get_val(m_improved_upper_bounds, j, k)) {
|
||||
auto & found_bound = m_ibounds[k];
|
||||
if (w < found_bound.m_bound || (w == found_bound.m_bound && found_bound.m_strict == false && strict))
|
||||
found_bound = implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
|
||||
} else {
|
||||
m_improved_upper_bounds[j] = m_ibounds.size();
|
||||
m_ibounds.push_back(implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
#include "util/lp/lp_settings.h"
|
||||
namespace lp {
|
||||
class lar_solver;
|
||||
class bound_propagator {
|
||||
std::unordered_map<unsigned, unsigned> m_improved_lower_bounds; // these maps map a column index to the corresponding index in ibounds
|
||||
std::unordered_map<unsigned, unsigned> m_improved_upper_bounds;
|
||||
lar_solver & m_lar_solver;
|
||||
public:
|
||||
vector<implied_bound> m_ibounds;
|
||||
public:
|
||||
lp_bound_propagator(lar_solver & ls);
|
||||
column_type get_column_type(unsigned) const;
|
||||
const impq & get_lower_bound(unsigned) const;
|
||||
const impq & get_upper_bound(unsigned) const;
|
||||
void try_add_bound(mpq v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict);
|
||||
virtual bool bound_is_interesting(unsigned vi,
|
||||
lp::lconstraint_kind kind,
|
||||
const rational & bval) {return true;}
|
||||
unsigned number_of_found_bounds() const { return m_ibounds.size(); }
|
||||
virtual void consume(mpq const& v, unsigned j) { std::cout << "doh\n"; }
|
||||
};
|
||||
}
|
|
@ -28,8 +28,6 @@ Revision History:
|
|||
#include "util/lp/lu.h"
|
||||
#include "util/lp/permutation_matrix.h"
|
||||
#include "util/lp/column_namer.h"
|
||||
#include "util/lp/iterator_on_row.h"
|
||||
#include "util/lp/iterator_on_pivot_row.h"
|
||||
|
||||
namespace lp {
|
||||
|
||||
|
@ -751,13 +749,6 @@ public:
|
|||
return m_iters_with_no_cost_growing;
|
||||
}
|
||||
|
||||
linear_combination_iterator<T> * get_iterator_on_row(unsigned i) {
|
||||
if (m_settings.use_tableau())
|
||||
return new iterator_on_row<T>(m_A.m_rows[i]);
|
||||
calculate_pivot_row(i);
|
||||
return new iterator_on_pivot_row<T>(m_pivot_row, m_basis[i]);
|
||||
}
|
||||
|
||||
void calculate_pivot_row(unsigned i);
|
||||
unsigned get_base_column_in_row(unsigned row_index) const {
|
||||
return m_basis[row_index];
|
||||
|
|
|
@ -159,7 +159,7 @@ solve_Bd(unsigned entering) {
|
|||
m_columns_nz[entering] = m_ed.m_index.size();
|
||||
lp_assert(m_ed.is_OK());
|
||||
lp_assert(m_w.is_OK());
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// auto B = get_B(*m_factorization, m_basis);
|
||||
// vector<T> a(m_m());
|
||||
// m_A.copy_column_to_vector(entering, a);
|
||||
|
@ -978,8 +978,8 @@ template <typename T, typename X> void lp_core_solver_base<T, X>::pivot_fixed_v
|
|||
if (get_column_type(basic_j) != column_type::fixed) continue;
|
||||
T a;
|
||||
unsigned j;
|
||||
auto * it = get_iterator_on_row(i);
|
||||
while (it->next(a, j)) {
|
||||
for (auto &c : m_A.m_rows[i]) {
|
||||
j = c.var();
|
||||
if (j == basic_j)
|
||||
continue;
|
||||
if (get_column_type(j) != column_type::fixed) {
|
||||
|
@ -987,7 +987,6 @@ template <typename T, typename X> void lp_core_solver_base<T, X>::pivot_fixed_v
|
|||
break;
|
||||
}
|
||||
}
|
||||
delete it;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@ Revision History:
|
|||
#include "util/lp/breakpoint.h"
|
||||
#include "util/lp/binary_heap_priority_queue.h"
|
||||
#include "util/lp/int_set.h"
|
||||
#include "util/lp/iterator_on_row.h"
|
||||
namespace lp {
|
||||
|
||||
// This core solver solves (Ax=b, lower_bound_values \leq x \leq upper_bound_values, maximize costs*x )
|
||||
|
|
|
@ -26,7 +26,6 @@ Revision History:
|
|||
#include "util/lp/column_info.h"
|
||||
#include "util/lp/lp_primal_core_solver.h"
|
||||
#include "util/lp/lp_solver.h"
|
||||
#include "util/lp/iterator_on_row.h"
|
||||
namespace lp {
|
||||
template <typename T, typename X>
|
||||
class lp_primal_simplex: public lp_solver<T, X> {
|
||||
|
|
|
@ -106,6 +106,8 @@ struct stats {
|
|||
unsigned m_cut_solver_true;
|
||||
unsigned m_cut_solver_false;
|
||||
unsigned m_cut_solver_undef;
|
||||
unsigned m_gcd_calls;
|
||||
unsigned m_gcd_conflicts;
|
||||
stats() { reset(); }
|
||||
void reset() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
@ -226,9 +228,8 @@ public:
|
|||
backup_costs(true),
|
||||
column_number_threshold_for_using_lu_in_lar_solver(4000),
|
||||
m_int_branch_cut_gomory_threshold(4),
|
||||
m_int_branch_cut_solver(4),
|
||||
m_int_branch_cut_solver(8),
|
||||
m_run_gcd_test(true),
|
||||
m_cut_solver_bound_propagation_factor(5),
|
||||
m_cut_solver_cycle_on_var(10)
|
||||
{}
|
||||
|
||||
|
@ -339,7 +340,6 @@ public:
|
|||
unsigned m_int_branch_cut_gomory_threshold;
|
||||
unsigned m_int_branch_cut_solver;
|
||||
bool m_run_gcd_test;
|
||||
unsigned m_cut_solver_bound_propagation_factor;
|
||||
unsigned m_cut_solver_cycle_on_var;
|
||||
}; // end of lp_settings class
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ Revision History:
|
|||
#include "util/lp/static_matrix.h"
|
||||
#include "util/lp/lp_core_solver_base.h"
|
||||
#include "util/lp/scaler.h"
|
||||
#include "util/lp/linear_combination_iterator.h"
|
||||
#include "util/lp/bound_analyzer_on_row.h"
|
||||
namespace lp {
|
||||
enum lp_relation {
|
||||
|
|
|
@ -38,7 +38,7 @@ bool contains(const std::unordered_map<A, B> & map, const A& key) {
|
|||
#ifdef lp_for_z3
|
||||
|
||||
#ifdef Z3DEBUG
|
||||
#define LEAN_DEBUG 1
|
||||
#define Z3DEBUG 1
|
||||
#endif
|
||||
|
||||
namespace lp {
|
||||
|
|
|
@ -39,7 +39,7 @@ template lp::mpq lp::dot_product<lp::mpq, lp::mpq>(vector<lp::mpq > const&, vect
|
|||
template void lp::init_factorization<double, double>(lp::lu<double, double>*&, lp::static_matrix<double, double>&, vector<unsigned int>&, lp::lp_settings&);
|
||||
template void lp::init_factorization<lp::mpq, lp::mpq>(lp::lu<lp::mpq, lp::mpq>*&, lp::static_matrix<lp::mpq, lp::mpq>&, vector<unsigned int>&, lp::lp_settings&);
|
||||
template void lp::init_factorization<lp::mpq, lp::numeric_pair<lp::mpq> >(lp::lu<lp::mpq, lp::numeric_pair<lp::mpq> >*&, lp::static_matrix<lp::mpq, lp::numeric_pair<lp::mpq> >&, vector<unsigned int>&, lp::lp_settings&);
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
template void lp::print_matrix<double, double>(lp::sparse_matrix<double, double>&, std::ostream & out);
|
||||
template void lp::print_matrix<lp::mpq, lp::mpq>(lp::static_matrix<lp::mpq, lp::mpq>&, std::ostream&);
|
||||
template void lp::print_matrix<lp::mpq, lp::numeric_pair<lp::mpq> >(lp::static_matrix<lp::mpq, lp::numeric_pair<lp::mpq> >&, std::ostream&);
|
||||
|
|
|
@ -34,7 +34,7 @@ Revision History:
|
|||
#include "util/lp/square_dense_submatrix.h"
|
||||
#include "util/lp/dense_matrix.h"
|
||||
namespace lp {
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
template <typename T, typename X> // print the nr x nc submatrix at the top left corner
|
||||
void print_submatrix(sparse_matrix<T, X> & m, unsigned mr, unsigned nc);
|
||||
|
||||
|
@ -113,7 +113,7 @@ public:
|
|||
#endif
|
||||
m_i = p.apply_reverse(m_i);
|
||||
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(*this == deb);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ Revision History:
|
|||
#include "util/debug.h"
|
||||
#include "util/lp/lu.h"
|
||||
namespace lp {
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
template <typename T, typename X> // print the nr x nc submatrix at the top left corner
|
||||
void print_submatrix(sparse_matrix<T, X> & m, unsigned mr, unsigned nc, std::ostream & out) {
|
||||
vector<vector<std::string>> A;
|
||||
|
@ -138,12 +138,12 @@ lu<T, X>::lu(static_matrix<T, X> const & A,
|
|||
m_row_eta_work_vector(A.row_count()),
|
||||
m_refactor_counter(0) {
|
||||
lp_assert(!(numeric_traits<T>::precise() && settings.use_tableau()));
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
debug_test_of_basis(A, basis);
|
||||
#endif
|
||||
++m_settings.st().m_num_factorizations;
|
||||
create_initial_factorization();
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(check_correctness());
|
||||
#endif
|
||||
}
|
||||
|
|
33
src/util/lp/monomial.h
Normal file
33
src/util/lp/monomial.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
Nikolaj Bjorner (nbjorner)
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
namespace lp {
|
||||
struct monomial {
|
||||
mpq m_coeff; // the coefficient of the monomial
|
||||
var_index m_var; // the variable index
|
||||
public:
|
||||
monomial(const mpq& coeff, var_index var) : m_coeff(coeff), m_var(var) {}
|
||||
monomial(var_index var) : monomial(one_of_type<mpq>(), var) {}
|
||||
const mpq & coeff() const { return m_coeff; }
|
||||
mpq & coeff() { return m_coeff; }
|
||||
var_index var() const { return m_var; }
|
||||
std::pair<mpq, var_index> to_pair() const { return std::make_pair(coeff(), var());}
|
||||
};
|
||||
}
|
|
@ -28,7 +28,7 @@ Revision History:
|
|||
#include "util/lp/matrix.h"
|
||||
#include "util/lp/tail_matrix.h"
|
||||
namespace lp {
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
inline bool is_even(int k) { return (k/2)*2 == k; }
|
||||
#endif
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ void permutation_matrix<T, X>::apply_from_left(vector<X> & w, lp_settings & ) {
|
|||
while (i-- > 0) {
|
||||
w[i] = m_X_buffer[i];
|
||||
}
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(vectors_are_equal<L>(deb_w, w, row_count()));
|
||||
// delete [] deb_w;
|
||||
#endif
|
||||
|
@ -109,7 +109,7 @@ template <typename T, typename X> void permutation_matrix<T, X>::apply_from_righ
|
|||
for (unsigned i = 0; i < size(); i++) {
|
||||
w[i] = m_T_buffer[i];
|
||||
}
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(vectors_are_equal<T>(deb_w, w, row_count()));
|
||||
// delete [] deb_w;
|
||||
#endif
|
||||
|
@ -133,7 +133,7 @@ template <typename T, typename X> void permutation_matrix<T, X>::apply_from_righ
|
|||
w.set_value(buffer[i], pj);
|
||||
}
|
||||
lp_assert(w.is_OK());
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
lp_assert(vectors_are_equal(wcopy, w.m_data));
|
||||
#endif
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ void permutation_matrix<T, X>::apply_reverse_from_left(indexed_vector<L> & w) {
|
|||
w[j] = t[i];
|
||||
w.m_index[i] = j;
|
||||
}
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(vectors_are_equal<L>(deb_w, w.m_data, row_count()));
|
||||
// delete [] deb_w;
|
||||
#endif
|
||||
|
|
106
src/util/lp/polynomial.h
Normal file
106
src/util/lp/polynomial.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*++
|
||||
Copyright (c) 2017 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
<name>
|
||||
|
||||
Abstract:
|
||||
|
||||
<abstract>
|
||||
|
||||
Author:
|
||||
Nikolaj Bjorner (nbjorner)
|
||||
Lev Nachmanson (levnach)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
#pragma once
|
||||
namespace lp {
|
||||
struct polynomial {
|
||||
static mpq m_local_zero;
|
||||
// the polynomial evaluates to m_coeffs + m_a
|
||||
vector<monomial> m_coeffs;
|
||||
mpq m_a; // the free coefficient
|
||||
polynomial(const vector<monomial>& p, const mpq & a) : m_coeffs(p), m_a(a) {}
|
||||
polynomial(const vector<monomial>& p) : polynomial(p, zero_of_type<mpq>()) {}
|
||||
polynomial(): m_a(zero_of_type<mpq>()) {}
|
||||
polynomial(const polynomial & p) : m_coeffs(p.m_coeffs), m_a(p.m_a) {}
|
||||
|
||||
const mpq & coeff(var_index j) const {
|
||||
for (const auto & t : m_coeffs) {
|
||||
if (j == t.var()) {
|
||||
return t.coeff();
|
||||
}
|
||||
}
|
||||
return m_local_zero;
|
||||
}
|
||||
|
||||
polynomial & operator+=(const polynomial & p) {
|
||||
m_a += p.m_a;
|
||||
for (const auto & t: p.m_coeffs)
|
||||
*this += monomial(t.coeff(), t.var());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void add(const mpq & c, const polynomial &p) {
|
||||
m_a += p.m_a * c;
|
||||
|
||||
for (const auto & t: p.m_coeffs)
|
||||
*this += monomial(c * t.coeff(), t.var());
|
||||
}
|
||||
|
||||
void clear() {
|
||||
m_coeffs.clear();
|
||||
m_a = zero_of_type<mpq>();
|
||||
}
|
||||
|
||||
bool is_empty() const { return m_coeffs.size() == 0 && numeric_traits<mpq>::is_zero(m_a); }
|
||||
|
||||
unsigned number_of_monomials() const { return m_coeffs.size();}
|
||||
|
||||
void add(const monomial &m ){
|
||||
if (is_zero(m.coeff())) return;
|
||||
for (unsigned k = 0; k < m_coeffs.size(); k++) {
|
||||
auto & l = m_coeffs[k];
|
||||
if (m.var() == l.var()) {
|
||||
l.coeff() += m.coeff();
|
||||
if (l.coeff() == 0)
|
||||
m_coeffs.erase(m_coeffs.begin() + k);
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_coeffs.push_back(m);
|
||||
lp_assert(is_correct());
|
||||
}
|
||||
|
||||
polynomial & operator+=(const monomial &m ){
|
||||
add(m);
|
||||
return *this;
|
||||
}
|
||||
|
||||
polynomial & operator+=(const mpq &c ){
|
||||
m_a += c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
bool is_correct() const {
|
||||
std::unordered_set<var_index> s;
|
||||
for (auto & l : m_coeffs) {
|
||||
if (l.coeff() == 0)
|
||||
return false;
|
||||
s.insert(l.var());
|
||||
}
|
||||
return m_coeffs.size() == s.size();
|
||||
}
|
||||
|
||||
bool var_coeff_is_unit(unsigned j) const {
|
||||
const mpq & a = coeff(j);
|
||||
return a == 1 || a == -1;
|
||||
}
|
||||
const vector<monomial> & coeffs() const { return m_coeffs; }
|
||||
};
|
||||
}
|
|
@ -25,7 +25,6 @@ Revision History:
|
|||
#include <string>
|
||||
#include <algorithm>
|
||||
#include "util/lp/lp_settings.h"
|
||||
#include "util/lp/linear_combination_iterator.h"
|
||||
// see http://research.microsoft.com/projects/z3/smt07.pdf
|
||||
// The class searches for a feasible solution with as many different values of variables as it can find
|
||||
namespace lp {
|
||||
|
|
|
@ -83,7 +83,7 @@ void random_updater::add_column_to_sets(unsigned j) {
|
|||
add_value(m_lar_solver.get_core_solver().m_r_x[j]);
|
||||
} else {
|
||||
unsigned row = m_lar_solver.get_core_solver().m_r_heading[j];
|
||||
for (auto row_c : m_lar_solver.get_core_solver().m_r_A.m_rows[row]) {
|
||||
for (auto & row_c : m_lar_solver.get_core_solver().m_r_A.m_rows[row]) {
|
||||
unsigned cj = row_c.m_j;
|
||||
if (m_lar_solver.get_core_solver().m_r_heading[cj] < 0) {
|
||||
m_var_set.insert(cj);
|
||||
|
|
|
@ -33,7 +33,7 @@ void row_eta_matrix<T, X>::apply_from_left(vector<X> & w, lp_settings &) {
|
|||
w_at_row += w[it.first] * it.second;
|
||||
}
|
||||
// w[m_row] = w_at_row;
|
||||
// #ifdef LEAN_DEBUG
|
||||
// #ifdef Z3DEBUG
|
||||
// lp_assert(vectors_are_equal<T>(clone_w, w, m_dimension));
|
||||
// delete [] clone_w;
|
||||
// #endif
|
||||
|
@ -95,7 +95,7 @@ void row_eta_matrix<T, X>::apply_from_right(vector<T> & w) {
|
|||
for (auto & it : m_row_vector.m_data) {
|
||||
w[it.first] += w_row * it.second;
|
||||
}
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(vectors_are_equal<T>(clone_w, w, m_dimension));
|
||||
// delete clone_w;
|
||||
#endif
|
||||
|
@ -144,7 +144,7 @@ void row_eta_matrix<T, X>::apply_from_right(indexed_vector<T> & w) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(vectors_are_equal(wcopy, w.m_data));
|
||||
|
||||
#endif
|
||||
|
@ -165,7 +165,7 @@ void row_eta_matrix<T, X>::conjugate_by_permutation(permutation_matrix<T, X> & p
|
|||
columns.push_back(it.first);
|
||||
for (unsigned i = static_cast<unsigned>(columns.size()); i-- > 0;)
|
||||
m_row_vector.m_data[i].first = p.get_rev(columns[i]);
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(deb == *this);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -220,18 +220,18 @@ template <typename T, typename X> void scaler<T, X>::scale_row(unsigned i) {
|
|||
if (numeric_traits<T>::is_zero(row_max)) {
|
||||
return;
|
||||
}
|
||||
if (numeric_traits<T>::get_double(row_max) < m_scaling_minimum) {
|
||||
if (row_max < m_scaling_minimum) {
|
||||
do {
|
||||
alpha *= 2;
|
||||
row_max *= 2;
|
||||
} while (numeric_traits<T>::get_double(row_max) < m_scaling_minimum);
|
||||
} while (row_max < m_scaling_minimum);
|
||||
m_A.multiply_row(i, alpha);
|
||||
m_b[i] *= alpha;
|
||||
} else if (numeric_traits<T>::get_double(row_max) > m_scaling_maximum) {
|
||||
} else if (row_max > m_scaling_maximum) {
|
||||
do {
|
||||
alpha /= 2;
|
||||
row_max /= 2;
|
||||
} while (numeric_traits<T>::get_double(row_max) > m_scaling_maximum);
|
||||
} while (row_max > m_scaling_maximum);
|
||||
m_A.multiply_row(i, alpha);
|
||||
m_b[i] *= alpha;
|
||||
}
|
||||
|
@ -245,16 +245,16 @@ template <typename T, typename X> void scaler<T, X>::scale_column(unsigned i)
|
|||
return; // the column has zeros only
|
||||
}
|
||||
std::cout << "f";
|
||||
if (numeric_traits<T>::get_double(column_max) < m_scaling_minimum) {
|
||||
if (column_max < m_scaling_minimum) {
|
||||
do {
|
||||
alpha *= 2;
|
||||
column_max *= 2;
|
||||
} while (numeric_traits<T>::get_double(column_max) < m_scaling_minimum);
|
||||
} else if (numeric_traits<T>::get_double(column_max) > m_scaling_maximum) {
|
||||
} while (column_max < m_scaling_minimum);
|
||||
} else if (column_max > m_scaling_maximum) {
|
||||
do {
|
||||
alpha /= 2;
|
||||
column_max /= 2;
|
||||
} while (numeric_traits<T>::get_double(column_max) > m_scaling_maximum);
|
||||
} while (column_max > m_scaling_maximum);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ template void sparse_matrix<mpq, numeric_pair<mpq>>::double_solve_U_y<mpq>(index
|
|||
template void sparse_matrix<mpq, numeric_pair<mpq> >::double_solve_U_y<numeric_pair<mpq> >(indexed_vector<numeric_pair<mpq>>&, const lp_settings&);
|
||||
template void lp::sparse_matrix<double, double>::solve_U_y_indexed_only<double>(lp::indexed_vector<double>&, const lp_settings&, vector<unsigned> &);
|
||||
template void lp::sparse_matrix<lp::mpq, lp::mpq>::solve_U_y_indexed_only<lp::mpq>(lp::indexed_vector<lp::mpq>&, const lp_settings &, vector<unsigned> &);
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
template bool sparse_matrix<double, double>::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const;
|
||||
template bool sparse_matrix<mpq, mpq>::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const;
|
||||
template bool sparse_matrix<mpq, numeric_pair<mpq> >::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const;
|
||||
|
|
|
@ -490,7 +490,7 @@ void sparse_matrix<T, X>::solve_y_U_indexed(indexed_vector<T> & y, const lp_sett
|
|||
}
|
||||
|
||||
lp_assert(y.is_OK());
|
||||
#if 0 && LEAN_DEBUG
|
||||
#if 0 && Z3DEBUG
|
||||
if (numeric_traits<T>::precise() == false)
|
||||
lp_assert(vectors_are_equal(ycopy, y.m_data));
|
||||
#endif
|
||||
|
@ -700,7 +700,7 @@ void sparse_matrix<T, X>::solve_U_y_indexed_only(indexed_vector<L> & y, const lp
|
|||
}
|
||||
|
||||
lp_assert(y.is_OK());
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// dense_matrix<T,X> deb(this);
|
||||
// vector<T> clone_y(y.m_data);
|
||||
// deb.apply_from_left(clone_y);
|
||||
|
|
|
@ -300,7 +300,7 @@ void square_dense_submatrix<T, X>::apply_from_left_to_vector(vector<L> & w) {
|
|||
}
|
||||
|
||||
template <typename T, typename X> bool square_dense_submatrix<T, X>::is_L_matrix() const {
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
lp_assert(m_row_permutation.is_identity());
|
||||
for (unsigned i = 0; i < m_parent->dimension(); i++) {
|
||||
if (i < m_index_start) {
|
||||
|
@ -341,7 +341,7 @@ template <typename T, typename X> void square_dense_submatrix<T, X>::apply_from_
|
|||
t[adjust_column_inverse(j)] = column_by_vector_product(j, w);
|
||||
}
|
||||
w = t;
|
||||
#ifdef LEAN_DEBUG
|
||||
#ifdef Z3DEBUG
|
||||
// lp_assert(vector_are_equal<T>(deb_w, w));
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ Revision History:
|
|||
#include "util/lp/sparse_vector.h"
|
||||
#include "util/lp/indexed_vector.h"
|
||||
#include "util/lp/permutation_matrix.h"
|
||||
#include "util/lp/linear_combination_iterator.h"
|
||||
#include <stack>
|
||||
namespace lp {
|
||||
|
||||
|
@ -35,20 +34,26 @@ struct column_cell {
|
|||
unsigned m_offset; // the offset of the element in the matrix row
|
||||
column_cell(unsigned i, unsigned offset) : m_i(i), m_offset(offset) {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct row_cell {
|
||||
unsigned m_j; // points to the column
|
||||
unsigned m_offset; // offset in column
|
||||
T m_value;
|
||||
row_cell(unsigned j, unsigned offset, T const & val) : m_j(j), m_offset(offset), m_value(val) {
|
||||
}
|
||||
const T & get_val() const { return m_value;}
|
||||
T & get_val() { return m_value;}
|
||||
void set_val(const T& v) { m_value = v; }
|
||||
T m_value;
|
||||
unsigned var() const { return m_j;}
|
||||
const T & coeff() const { return m_value;}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using row_strip = vector<row_cell<T>>;
|
||||
|
||||
// each assignment for this matrix should be issued only once!!!
|
||||
template <typename T, typename X>
|
||||
class static_matrix
|
||||
|
@ -63,11 +68,10 @@ class static_matrix
|
|||
};
|
||||
std::stack<dim> m_stack;
|
||||
public:
|
||||
typedef vector<row_cell<T>> row_strip;
|
||||
typedef vector<column_cell> column_strip;
|
||||
vector<int> m_vector_of_row_offsets;
|
||||
indexed_vector<T> m_work_vector;
|
||||
vector<row_strip> m_rows;
|
||||
vector<row_strip<T>> m_rows;
|
||||
vector<column_strip> m_columns;
|
||||
// starting inner classes
|
||||
class ref {
|
||||
|
@ -97,10 +101,6 @@ public:
|
|||
return m_rows[c.m_i][c.m_offset].get_val();
|
||||
}
|
||||
|
||||
row_cell<T> & get_row_cell(const column_cell & c) {
|
||||
return m_rows[c.m_i][c.m_offset];
|
||||
}
|
||||
|
||||
column_cell & get_column_cell(const row_cell<T> &rc) {
|
||||
return m_columns[rc.m_j][rc.m_offset];
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ public:
|
|||
void add_columns_at_the_end(unsigned delta);
|
||||
void add_new_element(unsigned i, unsigned j, const T & v);
|
||||
|
||||
void add_row() {m_rows.push_back(row_strip());}
|
||||
void add_row() {m_rows.push_back(row_strip<T>());}
|
||||
void add_column() {
|
||||
m_columns.push_back(column_strip());
|
||||
m_vector_of_row_offsets.push_back(-1);
|
||||
|
@ -195,7 +195,7 @@ public:
|
|||
//
|
||||
void fix_row_indices_in_each_column_for_crossed_row(unsigned k);
|
||||
|
||||
void cross_out_row_from_columns(unsigned k, row_strip & row);
|
||||
void cross_out_row_from_columns(unsigned k, row_strip<T> & row);
|
||||
|
||||
void cross_out_row_from_column(unsigned col, unsigned k);
|
||||
|
||||
|
@ -294,7 +294,7 @@ public:
|
|||
|
||||
// pivot row i to row ii
|
||||
bool pivot_row_to_row_given_cell(unsigned i, column_cell& c, unsigned);
|
||||
void scan_row_ii_to_offset_vector(const row_strip & rvals);
|
||||
void scan_row_ii_to_offset_vector(const row_strip<T> & rvals);
|
||||
|
||||
void transpose_rows(unsigned i, unsigned ii) {
|
||||
auto t = m_rows[i];
|
||||
|
@ -313,46 +313,54 @@ public:
|
|||
}
|
||||
|
||||
}
|
||||
void fill_last_row_with_pivoting_loop_block(unsigned j, const vector<int> & basis_heading) {
|
||||
int row_index = basis_heading[j];
|
||||
if (row_index < 0)
|
||||
return;
|
||||
T & alpha = m_work_vector[j]; // the pivot alpha
|
||||
if (is_zero(alpha))
|
||||
return;
|
||||
|
||||
for (const auto & c : m_rows[row_index]) {
|
||||
if (c.m_j == j) {
|
||||
continue;
|
||||
}
|
||||
T & wv = m_work_vector.m_data[c.m_j];
|
||||
bool was_zero = is_zero(wv);
|
||||
wv -= alpha * c.m_value;
|
||||
if (was_zero)
|
||||
m_work_vector.m_index.push_back(c.m_j);
|
||||
else {
|
||||
if (is_zero(wv)) {
|
||||
m_work_vector.erase_from_index(c.m_j);
|
||||
}
|
||||
}
|
||||
}
|
||||
alpha = zero_of_type<T>();
|
||||
m_work_vector.erase_from_index(j);
|
||||
}
|
||||
|
||||
void fill_last_row_with_pivoting(linear_combination_iterator<T> & it, const vector<int> & basis_heading) {
|
||||
|
||||
|
||||
template <typename term>
|
||||
void fill_last_row_with_pivoting(const term& row,
|
||||
unsigned bj, // the index of the basis column
|
||||
const vector<int> & basis_heading) {
|
||||
lp_assert(numeric_traits<T>::precise());
|
||||
lp_assert(row_count() > 0);
|
||||
m_work_vector.resize(column_count());
|
||||
T a;
|
||||
unsigned j;
|
||||
while (it.next(a, j)) {
|
||||
m_work_vector.set_value(-a, j); // we use the form -it + 1 = 0
|
||||
// we use the form -it + 1 = 0
|
||||
m_work_vector.set_value(one_of_type<T>(), bj);
|
||||
for (auto p : row) {
|
||||
m_work_vector.set_value(-p.coeff(), p.var());
|
||||
// but take care of the basis 1 later
|
||||
}
|
||||
|
||||
it.reset();
|
||||
// not iterate with pivoting
|
||||
while (it.next(j)) {
|
||||
int row_index = basis_heading[j];
|
||||
if (row_index < 0)
|
||||
continue;
|
||||
|
||||
T & alpha = m_work_vector[j]; // the pivot alpha
|
||||
if (is_zero(alpha))
|
||||
continue;
|
||||
|
||||
for (const auto & c : m_rows[row_index]) {
|
||||
if (c.m_j == j) {
|
||||
continue;
|
||||
}
|
||||
T & wv = m_work_vector.m_data[c.m_j];
|
||||
bool was_zero = is_zero(wv);
|
||||
wv -= alpha * c.m_value;
|
||||
if (was_zero)
|
||||
m_work_vector.m_index.push_back(c.m_j);
|
||||
else {
|
||||
if (is_zero(wv)) {
|
||||
m_work_vector.erase_from_index(c.m_j);
|
||||
}
|
||||
}
|
||||
}
|
||||
alpha = zero_of_type<T>();
|
||||
m_work_vector.erase_from_index(j);
|
||||
// now iterate with pivoting
|
||||
fill_last_row_with_pivoting_loop_block(bj, basis_heading);
|
||||
for (auto p : row) {
|
||||
fill_last_row_with_pivoting_loop_block(p.var(), basis_heading);
|
||||
}
|
||||
lp_assert(m_work_vector.is_OK());
|
||||
unsigned last_row = row_count() - 1;
|
||||
|
@ -382,5 +390,66 @@ public:
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct column_cell_plus {
|
||||
const column_cell & m_c;
|
||||
const static_matrix& m_A;
|
||||
// constructor
|
||||
column_cell_plus(const column_cell & c, const static_matrix& A) :
|
||||
m_c(c), m_A(A) {}
|
||||
unsigned var() const { return m_c.m_i; }
|
||||
const T & coeff() const { return m_A.m_rows[var()][m_c.m_offset].get_val(); }
|
||||
|
||||
};
|
||||
|
||||
struct column_container {
|
||||
unsigned m_j; // the column index
|
||||
const static_matrix & m_A;
|
||||
column_container(unsigned j, const static_matrix& A) : m_j(j), m_A(A) {
|
||||
}
|
||||
struct const_iterator {
|
||||
// fields
|
||||
const column_cell *m_c;
|
||||
const static_matrix& m_A;
|
||||
|
||||
//typedefs
|
||||
|
||||
|
||||
typedef const_iterator self_type;
|
||||
typedef column_cell_plus value_type;
|
||||
typedef const column_cell_plus reference;
|
||||
// typedef const column_cell* pointer;
|
||||
typedef int difference_type;
|
||||
typedef std::forward_iterator_tag iterator_category;
|
||||
|
||||
reference operator*() const {
|
||||
return column_cell_plus(*m_c, m_A);
|
||||
}
|
||||
self_type operator++() { self_type i = *this; m_c++; return i; }
|
||||
self_type operator++(int) { m_c++; return *this; }
|
||||
|
||||
const_iterator(const column_cell* it, const static_matrix& A) :
|
||||
m_c(it),
|
||||
m_A(A)
|
||||
{}
|
||||
bool operator==(const self_type &other) const {
|
||||
return m_c == other.m_c;
|
||||
}
|
||||
bool operator!=(const self_type &other) const { return !(*this == other); }
|
||||
};
|
||||
|
||||
const_iterator begin() const {
|
||||
return const_iterator(m_A.m_columns[m_j].begin(), m_A);
|
||||
}
|
||||
|
||||
const_iterator end() const {
|
||||
return const_iterator(m_A.m_columns[m_j].end(), m_A);
|
||||
}
|
||||
};
|
||||
|
||||
column_container column(unsigned j) const {
|
||||
return column_container(j, *this);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ template <typename T, typename X>
|
|||
void static_matrix<T, X>::init_row_columns(unsigned m, unsigned n) {
|
||||
lp_assert(m_rows.size() == 0 && m_columns.size() == 0);
|
||||
for (unsigned i = 0; i < m; i++){
|
||||
m_rows.push_back(row_strip());
|
||||
m_rows.push_back(row_strip<T>());
|
||||
}
|
||||
for (unsigned j = 0; j < n; j++){
|
||||
m_columns.push_back(column_strip());
|
||||
|
@ -35,7 +35,7 @@ void static_matrix<T, X>::init_row_columns(unsigned m, unsigned n) {
|
|||
}
|
||||
|
||||
|
||||
template <typename T, typename X> void static_matrix<T, X>::scan_row_ii_to_offset_vector(const row_strip & rvals) {
|
||||
template <typename T, typename X> void static_matrix<T, X>::scan_row_ii_to_offset_vector(const row_strip<T> & rvals) {
|
||||
for (unsigned j = 0; j < rvals.size(); j++)
|
||||
m_vector_of_row_offsets[rvals[j].m_j] = j;
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ template <typename T, typename X>
|
|||
std::set<std::pair<unsigned, unsigned>> static_matrix<T, X>::get_domain() {
|
||||
std::set<std::pair<unsigned, unsigned>> ret;
|
||||
for (unsigned i = 0; i < m_rows.size(); i++) {
|
||||
for (auto it : m_rows[i]) {
|
||||
for (auto &it : m_rows[i]) {
|
||||
ret.insert(std::make_pair(i, it.m_j));
|
||||
}
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ template <typename T, typename X> void static_matrix<T, X>::fix_row_indices_i
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T, typename X> void static_matrix<T, X>::cross_out_row_from_columns(unsigned k, row_strip & row) {
|
||||
template <typename T, typename X> void static_matrix<T, X>::cross_out_row_from_columns(unsigned k, row_strip<T> & row) {
|
||||
for (auto & t : row) {
|
||||
cross_out_row_from_column(t.m_j, k);
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@ Revision History:
|
|||
|
||||
|
||||
--*/
|
||||
#if 0
|
||||
#pragma once
|
||||
#include "util/vector.h"
|
||||
#include "util/lp/linear_combination_iterator.h"
|
||||
#include "util/lp/implied_bound.h"
|
||||
#include "util/lp/lp_settings.h"
|
||||
#include <functional>
|
||||
|
@ -273,3 +273,4 @@ public :
|
|||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue