diff --git a/contrib/cmake/src/test/CMakeLists.txt b/contrib/cmake/src/test/CMakeLists.txt index f504760e0..427cedcdb 100644 --- a/contrib/cmake/src/test/CMakeLists.txt +++ b/contrib/cmake/src/test/CMakeLists.txt @@ -61,6 +61,7 @@ add_executable(test-z3 "${CMAKE_CURRENT_BINARY_DIR}/mem_initializer.cpp" memory.cpp model2expr.cpp + model_based_opt.cpp model_evaluator.cpp model_retrieval.cpp mpbq.cpp diff --git a/src/math/simplex/model_based_opt.cpp b/src/math/simplex/model_based_opt.cpp index 10008345a..d96c12302 100644 --- a/src/math/simplex/model_based_opt.cpp +++ b/src/math/simplex/model_based_opt.cpp @@ -22,6 +22,13 @@ Revision History: namespace opt { + + model_based_opt::model_based_opt(): + m_objective_id(0) + { + m_rows.push_back(row()); + } + bool model_based_opt::invariant() { // variables in each row are sorted. @@ -30,12 +37,13 @@ namespace opt { return false; } } - return invariant(m_objective); + return true; } bool model_based_opt::invariant(row const& r) { rational val = r.m_coeff; vector const& vars = r.m_vars; + SASSERT(!vars.empty()); for (unsigned i = 0; i < vars.size(); ++i) { var const& v = vars[i]; SASSERT(i + 1 == vars.size() || v.m_id < vars[i+1].m_id); @@ -72,40 +80,40 @@ namespace opt { // then replace a3*x + t3 by t3/a3 - t2/a2 <= 0 // bound_type model_based_opt::maximize(rational& value) { - // tbd SASSERT(invariant()); - vector & vars = m_objective.m_vars; unsigned_vector other; - while (!vars.empty()) { - var const& v = vars.back(); + while (!objective().m_vars.empty()) { + var const& v = objective().m_vars.back(); unsigned x = v.m_id; rational const& coeff = v.m_coeff; rational const& x_val = m_var2value[x]; unsigned_vector const& row_ids = m_var2row_ids[x]; unsigned bound_index; other.reset(); - if (find_bound(x, bound_index, other, coeff.is_pos())) { + if (find_bound(x, bound_index, other, coeff.is_pos())) { rational bound_coeff = m_rows[bound_index].m_coeff; for (unsigned i = 0; i < other.size(); ++i) { resolve(other[i], bound_coeff, bound_index, x); } // coeff*x + objective -> coeff*(bound) + objective - // tbd: multiply(coeff/bound_coeff, bound_index); - //add(m_objective_id, bound_index); + SASSERT(invariant(m_rows[bound_index])); + objective().m_vars.back().m_coeff.reset(); + add(m_objective_id, bound_index); + SASSERT(invariant(objective())); m_rows[bound_index].m_alive = false; } else { return unbounded; } } - value = m_objective.m_coeff; - switch (m_objective.m_type) { - case t_lt: return strict; - case t_le: return non_strict; - case t_eq: return non_strict; + value = objective().m_coeff; + if (objective().m_type == t_lt) { + return strict; + } + else { + return non_strict; } - return non_strict; } bool model_based_opt::find_bound(unsigned x, unsigned& bound_index, unsigned_vector& other, bool is_pos) { @@ -143,6 +151,7 @@ namespace opt { rational model_based_opt::get_coefficient(unsigned row_id, unsigned var_id) { row const& r = m_rows[row_id]; + SASSERT(!r.m_vars.empty()); unsigned lo = 0, hi = r.m_vars.size(); while (lo < hi) { unsigned mid = lo + (hi - lo)/2; @@ -228,7 +237,9 @@ namespace opt { else if (i == r1.m_vars.size()) { for (; j < r2.m_vars.size(); ++j) { m_new_vars.push_back(r2.m_vars[j]); - m_var2row_ids[r2.m_vars[j].m_id].push_back(row_id1); + if (row_id1 != m_objective_id) { + m_var2row_ids[r2.m_vars[j].m_id].push_back(row_id1); + } } } else { @@ -249,7 +260,9 @@ namespace opt { } else { m_new_vars.push_back(r2.m_vars[j]); - m_var2row_ids[r2.m_vars[j].m_id].push_back(row_id1); + if (row_id1 != m_objective_id) { + m_var2row_ids[r2.m_vars[j].m_id].push_back(row_id1); + } ++j; } } @@ -260,6 +273,7 @@ namespace opt { if (r2.m_type == t_lt) { r1.m_type = t_lt; } + SASSERT(invariant(r1)); } void model_based_opt::display(std::ostream& out) const { @@ -291,16 +305,41 @@ namespace opt { } unsigned model_based_opt::add_var(rational const& value) { - NOT_IMPLEMENTED_YET(); - return 0; + unsigned v = m_var2value.size(); + m_var2value.push_back(value); + m_var2row_ids.push_back(unsigned_vector()); + return v; } - void model_based_opt::add_constraint(vector const& coeffs, rational const& c, ineq_type r) { - NOT_IMPLEMENTED_YET(); + void model_based_opt::set_row(row& r, vector const& coeffs, rational const& c, ineq_type rel) { + rational val(c); + SASSERT(r.m_vars.empty()); + r.m_vars.append(coeffs.size(), coeffs.c_ptr()); + std::sort(r.m_vars.begin(), r.m_vars.end(), var::compare()); + for (unsigned i = 0; i < coeffs.size(); ++i) { + val += m_var2value[coeffs[i].m_id] * coeffs[i].m_coeff; + } + r.m_alive = true; + r.m_coeff = c; + r.m_value = val; + r.m_type = rel; + SASSERT(invariant(r)); + } + + void model_based_opt::add_constraint(vector const& coeffs, rational const& c, ineq_type rel) { + rational val(c); + row r0; + unsigned row_id = m_rows.size(); + m_rows.push_back(r0); + row& r = m_rows.back(); + set_row(r, coeffs, c, rel); + for (unsigned i = 0; i < coeffs.size(); ++i) { + m_var2row_ids[coeffs[i].m_id].push_back(row_id); + } } void model_based_opt::set_objective(vector const& coeffs, rational const& c) { - NOT_IMPLEMENTED_YET(); + set_row(objective(), coeffs, c, t_le); } } diff --git a/src/math/simplex/model_based_opt.h b/src/math/simplex/model_based_opt.h index d881d3caa..44e3d44bb 100644 --- a/src/math/simplex/model_based_opt.h +++ b/src/math/simplex/model_based_opt.h @@ -44,23 +44,32 @@ namespace opt { unsigned m_id; rational m_coeff; var(unsigned id, rational const& c): m_id(id), m_coeff(c) {} + struct compare { + bool operator()(var x, var y) { + return x.m_id < y.m_id; + } + }; }; private: struct row { + row(): m_type(t_le), m_value(0), m_alive(false) {} vector m_vars; // variables with coefficients rational m_coeff; // constant in inequality ineq_type m_type; // inequality type rational m_value; // value of m_vars + m_coeff under interpretation of m_var2value. bool m_alive; // rows can be marked dead if they have been processed. }; + vector m_rows; + unsigned m_objective_id; vector m_var2row_ids; vector m_var2value; - row m_objective; vector m_new_vars; bool invariant(); bool invariant(row const& r); + + row& objective() { return m_rows[0]; } bool find_bound(unsigned x, unsigned& bound_index, unsigned_vector& other, bool is_pos); @@ -73,8 +82,12 @@ namespace opt { void add(unsigned row_id1, unsigned row_id2); + void set_row(row& r, vector const& coeffs, rational const& c, ineq_type rel); + public: + model_based_opt(); + // add a fresh variable with value 'value'. unsigned add_var(rational const& value); diff --git a/src/test/main.cpp b/src/test/main.cpp index 875f7bed0..8fc0a2de6 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -186,6 +186,7 @@ int main(int argc, char ** argv) { TST(smt_context); TST(theory_dl); TST(model_retrieval); + TST(model_based_opt); TST(factor_rewriter); TST(smt2print_parse); TST(substitution); diff --git a/src/test/model_based_opt.cpp b/src/test/model_based_opt.cpp new file mode 100644 index 000000000..f21627b2d --- /dev/null +++ b/src/test/model_based_opt.cpp @@ -0,0 +1,49 @@ +#include "model_based_opt.h" + +static void test1() { + opt::model_based_opt mbo; + typedef opt::model_based_opt::var var; + vector vars; + unsigned x = mbo.add_var(rational(2)); + unsigned y = mbo.add_var(rational(3)); + unsigned z = mbo.add_var(rational(4)); + unsigned u = mbo.add_var(rational(5)); + + vars.reset(); + vars.push_back(var(x, rational(1))); + vars.push_back(var(y, rational(-1))); + mbo.add_constraint(vars, rational(0), opt::t_le); + + vars.reset(); + vars.push_back(var(x, rational(1))); + vars.push_back(var(z, rational(-1))); + mbo.add_constraint(vars, rational(0), opt::t_le); + + vars.reset(); + vars.push_back(var(y, rational(1))); + vars.push_back(var(u, rational(-1))); + mbo.add_constraint(vars, rational(0), opt::t_le); + + vars.reset(); + vars.push_back(var(z, rational(1))); + vars.push_back(var(u, rational(-1))); + mbo.add_constraint(vars, rational(-1), opt::t_le); + + vars.reset(); + vars.push_back(var(u, rational(1))); + mbo.add_constraint(vars, rational(4), opt::t_le); + + vars.reset(); + vars.push_back(var(x, rational(2))); + mbo.set_objective(vars, rational(0)); + + rational value; + opt::bound_type bound = mbo.maximize(value); + + std::cout << bound << ": " << value << "\n"; + +} + +void tst_model_based_opt() { + test1(); +}