#include "math/simplex/model_based_opt.h" #include "util/util.h" #include "util/uint_set.h" typedef opt::model_based_opt::var var; static void add_ineq(opt::model_based_opt& mbo, unsigned x, int a, int k, opt::ineq_type rel) { vector vars; vars.push_back(var(x, rational(a))); mbo.add_constraint(vars, rational(k), rel); } static void add_ineq(opt::model_based_opt& mbo, unsigned x, int a, unsigned y, int b, int k, opt::ineq_type rel) { vector vars; vars.push_back(var(x, rational(a))); vars.push_back(var(y, rational(b))); mbo.add_constraint(vars, rational(k), rel); } #if 0 static void add_ineq(opt::model_based_opt& mbo, unsigned x, int a, unsigned y, int b, unsigned z, int c, int k, opt::ineq_type rel) { vector vars; vars.push_back(var(x, rational(a))); vars.push_back(var(y, rational(b))); vars.push_back(var(z, rational(c))); mbo.add_constraint(vars, rational(k), rel); } #endif static void add_random_ineq(opt::model_based_opt& mbo, random_gen& r, svector const& values, unsigned max_vars, unsigned max_coeff) { unsigned num_vars = values.size(); uint_set used_vars; vector vars; int value = 0; for (unsigned i = 0; i < max_vars; ++i) { unsigned x = r(num_vars); if (used_vars.contains(x)) { continue; } used_vars.insert(x); int coeff = r(max_coeff + 1); if (coeff == 0) { continue; } unsigned sign = r(2); coeff = sign == 0 ? coeff : -coeff; vars.push_back(var(x, rational(coeff))); value += coeff*values[x]; } unsigned abs_value = value < 0 ? - value : value; // value + k <= 0 // k <= - value // range for k is 2*|value| // k <= - value - range opt::ineq_type rel = opt::t_le; int coeff = 0; if (r(4) == 0) { rel = opt::t_eq; coeff = -value; } else { if (abs_value > 0) { coeff = -value - r(2*abs_value); } else { coeff = 0; } if (coeff != -value && r(3) == 0) { rel = opt::t_lt; } } mbo.add_constraint(vars, rational(coeff), rel); } static void check_random_ineqs(random_gen& r, unsigned num_vars, unsigned max_value, unsigned num_ineqs, unsigned max_vars, unsigned max_coeff) { opt::model_based_opt mbo; svector values; for (unsigned i = 0; i < num_vars; ++i) { values.push_back(r(max_value + 1)); mbo.add_var(rational(values.back())); } for (unsigned i = 0; i < num_ineqs; ++i) { add_random_ineq(mbo, r, values, max_vars, max_coeff); } vector vars; vars.reset(); vars.push_back(var(0, rational(2))); vars.push_back(var(1, rational(-2))); mbo.set_objective(vars, rational(0)); mbo.display(std::cout); opt::inf_eps value = mbo.maximize(); std::cout << "optimal: " << value << "\n"; mbo.display(std::cout); for (unsigned i = 0; i < values.size(); ++i) { std::cout << i << ": " << values[i] << " -> " << mbo.get_value(i) << "\n"; } } static void check_random_ineqs() { random_gen r(1); for (unsigned i = 0; i < 1009; ++i) { check_random_ineqs(r, 4, 5, 5, 3, 6); } } // test with upper bounds static void test1() { opt::model_based_opt mbo; 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)); add_ineq(mbo, x, 1, y, -1, 0, opt::t_le); add_ineq(mbo, x, 1, z, -1, 0, opt::t_le); add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); add_ineq(mbo, z, 1, u, -1, 1, opt::t_le); add_ineq(mbo, u, 1, -6, opt::t_le); vars.reset(); vars.push_back(var(x, rational(2))); mbo.set_objective(vars, rational(0)); opt::inf_eps value = mbo.maximize(); std::cout << value << "\n"; std::cout << "x: " << mbo.get_value(x) << "\n"; std::cout << "y: " << mbo.get_value(y) << "\n"; std::cout << "z: " << mbo.get_value(z) << "\n"; std::cout << "u: " << mbo.get_value(u) << "\n"; } // test with lower bounds static void test2() { opt::model_based_opt mbo; vector vars; unsigned x = mbo.add_var(rational(5)); unsigned y = mbo.add_var(rational(4)); unsigned z = mbo.add_var(rational(3)); unsigned u = mbo.add_var(rational(2)); add_ineq(mbo, x, -1, y, 1, 0, opt::t_le); add_ineq(mbo, x, -1, z, 1, 0, opt::t_le); add_ineq(mbo, y, -1, u, 1, 0, opt::t_le); add_ineq(mbo, z, -1, u, 1, 1, opt::t_le); add_ineq(mbo, u, -1, -6, opt::t_le); vars.reset(); vars.push_back(var(x, rational(-2))); mbo.set_objective(vars, rational(0)); opt::inf_eps value = mbo.maximize(); std::cout << value << "\n"; } // test unbounded static void test3() { opt::model_based_opt mbo; 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)); add_ineq(mbo, x, 1, y, -1, 0, opt::t_le); add_ineq(mbo, x, 1, z, -1, 0, opt::t_le); add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); add_ineq(mbo, z, 1, u, -1, 1, opt::t_le); vars.reset(); vars.push_back(var(x, rational(2))); mbo.set_objective(vars, rational(0)); opt::inf_eps value = mbo.maximize(); std::cout << value << "\n"; } // test strict static void test4() { opt::model_based_opt mbo; 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)); add_ineq(mbo, x, 1, y, -1, 0, opt::t_lt); add_ineq(mbo, x, 1, z, -1, 0, opt::t_lt); add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); add_ineq(mbo, z, 1, u, -1, 1, opt::t_le); add_ineq(mbo, u, 1, -6, opt::t_le); vars.reset(); vars.push_back(var(x, rational(2))); mbo.set_objective(vars, rational(0)); opt::inf_eps value = mbo.maximize(); std::cout << value << "\n"; std::cout << "x: " << mbo.get_value(x) << "\n"; std::cout << "y: " << mbo.get_value(y) << "\n"; std::cout << "z: " << mbo.get_value(z) << "\n"; std::cout << "u: " << mbo.get_value(u) << "\n"; } static void display_project(vector const& defs) { for (auto const& d : defs) { std::cout << d << "\n"; } } static void test5() { opt::model_based_opt mbo; 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)); add_ineq(mbo, x, 1, y, -1, 0, opt::t_le); add_ineq(mbo, x, 1, z, -1, 0, opt::t_le); add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); add_ineq(mbo, z, 1, u, -1, 1, opt::t_le); unsigned vars[2] = { y, z }; display_project(mbo.project(1, vars, true)); mbo.display(std::cout); display_project(mbo.project(1, vars, true)); mbo.display(std::cout); display_project(mbo.project(1, vars+1, true)); mbo.display(std::cout); vector rows; mbo.get_live_rows(rows); } static void test6() { opt::model_based_opt mbo; unsigned x0 = mbo.add_var(rational(1)); 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)); unsigned v = mbo.add_var(rational(6)); unsigned w = mbo.add_var(rational(6)); add_ineq(mbo, x0, 1, y, -1, 0, opt::t_le); add_ineq(mbo, x, 1, y, -1, 0, opt::t_le); add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); add_ineq(mbo, y, 1, z, -1, 1, opt::t_le); add_ineq(mbo, y, 1, v, -1, 1, opt::t_le); add_ineq(mbo, y, 1, w, -1, 1, opt::t_le); mbo.display(std::cout); display_project(mbo.project(1, &y, true)); mbo.display(std::cout); } static void test7() { opt::model_based_opt mbo; unsigned x0 = mbo.add_var(rational(2)); unsigned x = mbo.add_var(rational(1)); unsigned y = mbo.add_var(rational(3)); unsigned z = mbo.add_var(rational(4)); unsigned u = mbo.add_var(rational(5)); unsigned v = mbo.add_var(rational(6)); unsigned w = mbo.add_var(rational(6)); add_ineq(mbo, x0, 1, y, -1, 0, opt::t_le); add_ineq(mbo, x, 1, y, -1, 0, opt::t_lt); add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); add_ineq(mbo, y, 1, z, -1, 1, opt::t_le); add_ineq(mbo, y, 1, v, -1, 1, opt::t_le); add_ineq(mbo, y, 1, w, -1, 1, opt::t_lt); mbo.display(std::cout); display_project(mbo.project(1, &y, true)); mbo.display(std::cout); } static void test8() { opt::model_based_opt mbo; unsigned x0 = mbo.add_var(rational(2)); unsigned x = mbo.add_var(rational(1)); unsigned y = mbo.add_var(rational(3)); unsigned z = mbo.add_var(rational(4)); unsigned u = mbo.add_var(rational(5)); unsigned v = mbo.add_var(rational(6)); // unsigned w = mbo.add_var(rational(6)); add_ineq(mbo, x0, 1, y, -1, 0, opt::t_le); add_ineq(mbo, x, 1, y, -1, 0, opt::t_lt); add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); add_ineq(mbo, y, 1, z, -1, 1, opt::t_le); add_ineq(mbo, y, 1, v, -1, 1, opt::t_le); mbo.display(std::cout); display_project(mbo.project(1, &y, true)); mbo.display(std::cout); } static void test9() { opt::model_based_opt mbo; unsigned x0 = mbo.add_var(rational(2), true); unsigned x = mbo.add_var(rational(1), true); unsigned y = mbo.add_var(rational(3), true); unsigned z = mbo.add_var(rational(4), true); unsigned u = mbo.add_var(rational(5), true); unsigned v = mbo.add_var(rational(6), true); add_ineq(mbo, x0, 1, y, -1, 0, opt::t_le); add_ineq(mbo, x, 1, y, -1, 0, opt::t_lt); add_ineq(mbo, y, 1, u, -1, 0, opt::t_le); add_ineq(mbo, y, 1, z, -1, 1, opt::t_le); add_ineq(mbo, y, 1, v, -1, 1, opt::t_le); mbo.display(std::cout); display_project(mbo.project(1, &y, true)); mbo.display(std::cout); } static void test10() { opt::model_based_opt mbo; unsigned x0 = mbo.add_var(rational(2), true); unsigned x = mbo.add_var(rational(1), true); unsigned y = mbo.add_var(rational(3), true); unsigned z = mbo.add_var(rational(4), true); unsigned u = mbo.add_var(rational(5), true); unsigned v = mbo.add_var(rational(6), true); add_ineq(mbo, x0, 1, y, -2, 0, opt::t_le); add_ineq(mbo, x, 1, y, -2, 0, opt::t_lt); add_ineq(mbo, y, 3, u, -4, 0, opt::t_le); add_ineq(mbo, y, 3, z, -5, 1, opt::t_le); add_ineq(mbo, y, 3, v, -6, 1, opt::t_le); mbo.display(std::cout); display_project(mbo.project(1, &y, true)); mbo.display(std::cout); display_project(mbo.project(1, &x0, true)); mbo.display(std::cout); } static void test11() { { opt::model_based_opt mbo; unsigned s = mbo.add_var(rational(2), true); unsigned a = mbo.add_var(rational(1), true); unsigned t = mbo.add_var(rational(3), true); add_ineq(mbo, s, 1, a, -2, 0, opt::t_le); // s - 2a <= 0 add_ineq(mbo, a, 2, t, -1, 0, opt::t_le); // 2a - t <= 0 mbo.display(std::cout); display_project(mbo.project(1, &a, true)); mbo.display(std::cout); } { opt::model_based_opt mbo; unsigned s = mbo.add_var(rational(3), true); unsigned a = mbo.add_var(rational(2), true); unsigned t = mbo.add_var(rational(4), true); add_ineq(mbo, s, 1, a, -2, 0, opt::t_le); // s - 2a <= 0 add_ineq(mbo, a, 2, t, -1, 0, opt::t_le); // 2a - t <= 0 mbo.display(std::cout); display_project(mbo.project(1, &a, true)); mbo.display(std::cout); } } // test with mix of upper and lower bounds void tst_model_based_opt() { test10(); check_random_ineqs(); test1(); test2(); test3(); test4(); test5(); test6(); test7(); test8(); test9(); test11(); }