/*++ Copyright (c) 2014 Microsoft Corporation Module Name: simplex.h Abstract: Multi-precision simplex tableau. - It uses code from theory_arith where applicable. - It is detached from the theory class and ASTs. - It uses non-shared mpz/mpq's avoiding global locks and operations on rationals. - It follows the same sparse tableau layout (no LU yet). - It does not include features for non-linear arithmetic. - Branch/bound/cuts is external. Author: Nikolaj Bjorner (nbjorner) 2014-01-15 Notes: --*/ #pragma once #include "math/simplex/sparse_matrix.h" #include "util/mpq_inf.h" #include "util/heap.h" #include "util/lbool.h" #include "util/uint_set.h" namespace simplex { template class simplex { typedef unsigned var_t; typedef typename Ext::eps_numeral eps_numeral; typedef typename Ext::numeral numeral; typedef typename Ext::manager manager; typedef typename Ext::eps_manager eps_manager; typedef typename Ext::scoped_numeral scoped_numeral; typedef _scoped_numeral scoped_eps_numeral; typedef _scoped_numeral_vector scoped_eps_numeral_vector; typedef sparse_matrix matrix; struct var_lt { bool operator()(var_t v1, var_t v2) const { return v1 < v2; } }; typedef heap var_heap; struct stats { unsigned m_num_pivots; unsigned m_num_infeasible; unsigned m_num_checks; stats() { reset(); } void reset() { memset(this, 0, sizeof(*this)); } }; enum pivot_strategy_t { S_BLAND, S_GREATEST_ERROR, S_LEAST_ERROR, S_DEFAULT }; struct var_info { unsigned m_base2row:29; unsigned m_is_base:1; unsigned m_lower_valid:1; unsigned m_upper_valid:1; eps_numeral m_value; eps_numeral m_lower; eps_numeral m_upper; numeral m_base_coeff; var_info(): m_base2row(0), m_is_base(false), m_lower_valid(false), m_upper_valid(false) {} }; static const var_t null_var; reslimit& m_limit; mutable manager m; mutable eps_manager em; mutable matrix M; unsigned m_max_iterations; var_heap m_to_patch; vector m_vars; svector m_row2base; bool m_bland; unsigned m_blands_rule_threshold; random_gen m_random; uint_set m_left_basis; unsigned m_infeasible_var; unsigned_vector m_base_vars; stats m_stats; public: simplex(reslimit& lim): m_limit(lim), M(m), m_max_iterations(UINT_MAX), m_to_patch(1024), m_bland(false), m_blands_rule_threshold(1000) {} ~simplex(); typedef typename matrix::row row; typedef typename matrix::row_iterator row_iterator; typedef typename matrix::col_iterator col_iterator; void ensure_var(var_t v); row add_row(var_t base, unsigned num_vars, var_t const* vars, numeral const* coeffs); row get_infeasible_row(); var_t get_base_var(row const& r) const { return m_row2base[r.id()]; } numeral const& get_base_coeff(row const& r) const { return m_vars[m_row2base[r.id()]].m_base_coeff; } void del_row(var_t base_var); void set_lower(var_t var, eps_numeral const& b); void set_upper(var_t var, eps_numeral const& b); void get_lower(var_t var, scoped_eps_numeral& b) const { b = m_vars[var].m_lower; } void get_upper(var_t var, scoped_eps_numeral& b) const { b = m_vars[var].m_upper; } eps_numeral const& get_lower(var_t var) const { return m_vars[var].m_lower; } eps_numeral const& get_upper(var_t var) const { return m_vars[var].m_upper; } bool above_lower(var_t var, eps_numeral const& b) const; bool below_upper(var_t var, eps_numeral const& b) const; bool below_lower(var_t v) const; bool above_upper(var_t v) const; bool lower_valid(var_t var) const { return m_vars[var].m_lower_valid; } bool upper_valid(var_t var) const { return m_vars[var].m_upper_valid; } void unset_lower(var_t var); void unset_upper(var_t var); void set_value(var_t var, eps_numeral const& b); void set_max_iterations(unsigned n) { m_max_iterations = n; } void reset(); lbool make_feasible(); lbool minimize(var_t var); eps_numeral const& get_value(var_t v); void display(std::ostream& out) const; void display_row(std::ostream& out, row const& r, bool values = true); unsigned get_num_vars() const { return m_vars.size(); } row_iterator row_begin(row const& r) { return M.row_begin(r); } row_iterator row_end(row const& r) { return M.row_end(r); } void collect_statistics(::statistics & st) const; private: void del_row(row const& r); var_t select_var_to_fix(); pivot_strategy_t pivot_strategy(); var_t select_smallest_var() { return m_to_patch.empty()?null_var:m_to_patch.erase_min(); } var_t select_error_var(bool least); void check_blands_rule(var_t v, unsigned& num_repeated); bool make_var_feasible(var_t x_i); void update_and_pivot(var_t x_i, var_t x_j, numeral const& a_ij, eps_numeral const& new_value); void update_value(var_t v, eps_numeral const& delta); void update_value_core(var_t v, eps_numeral const& delta); void pivot(var_t x_i, var_t x_j, numeral const& a_ij); void move_to_bound(var_t x, bool to_lower); var_t select_pivot(var_t x_i, bool is_below, scoped_numeral& out_a_ij); var_t select_pivot_blands(var_t x_i, bool is_below, scoped_numeral& out_a_ij); var_t select_pivot_core(var_t x_i, bool is_below, scoped_numeral& out_a_ij); int get_num_non_free_dep_vars(var_t x_j, int best_so_far); var_t pick_var_to_leave(var_t x_j, bool is_pos, scoped_eps_numeral& gain, scoped_numeral& new_a_ij, bool& inc); void select_pivot_primal(var_t v, var_t& x_i, var_t& x_j, scoped_numeral& a_ij, bool& inc_x_i, bool& inc_x_j); bool at_lower(var_t v) const; bool at_upper(var_t v) const; bool above_lower(var_t v) const; bool below_upper(var_t v) const; bool outside_bounds(var_t v) const { return below_lower(v) || above_upper(v); } bool is_free(var_t v) const { return !m_vars[v].m_lower_valid && !m_vars[v].m_upper_valid; } bool is_non_free(var_t v) const { return !is_free(v); } bool is_base(var_t x) const { return m_vars[x].m_is_base; } void add_patch(var_t v); bool well_formed() const; bool well_formed_row(row const& r) const; bool is_feasible() const; }; void ensure_rational_solution(simplex& s); };