mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 13:29:11 +00:00 
			
		
		
		
	fix build break (debug assertion) and isolate gomory functionality
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									b253db2c0a
								
							
						
					
					
						commit
						894fb836e2
					
				
					 5 changed files with 208 additions and 139 deletions
				
			
		| 
						 | 
				
			
			@ -619,7 +619,7 @@ void cmd_context::set_produce_unsat_cores(bool f) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void cmd_context::set_produce_proofs(bool f) {
 | 
			
		||||
    SASSERT(!has_assertions());
 | 
			
		||||
    SASSERT(!has_assertions() || m_params.m_proof == f);
 | 
			
		||||
    if (has_manager()) 
 | 
			
		||||
        m().toggle_proof_mode(f ? PGM_ENABLED : PGM_DISABLED);
 | 
			
		||||
    m_params.m_proof = f;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,8 +31,7 @@ core::core(lp::lar_solver& s, reslimit & lim) :
 | 
			
		|||
    m_intervals(this, lim),
 | 
			
		||||
    m_monomial_bounds(this),
 | 
			
		||||
    m_horner(this),
 | 
			
		||||
    m_pdd_manager(s.number_of_vars()),
 | 
			
		||||
    m_pdd_grobner(lim, m_pdd_manager),
 | 
			
		||||
    m_grobner(this),
 | 
			
		||||
    m_emons(m_evars),
 | 
			
		||||
    m_reslim(lim),
 | 
			
		||||
    m_use_nra_model(false),
 | 
			
		||||
| 
						 | 
				
			
			@ -1506,7 +1505,7 @@ lbool core::check(vector<lemma>& l_vec) {
 | 
			
		|||
        m_horner.horner_lemmas();
 | 
			
		||||
 | 
			
		||||
    if (l_vec.empty() && !done() && need_run_grobner()) 
 | 
			
		||||
        run_grobner();                
 | 
			
		||||
        m_grobner();                
 | 
			
		||||
 | 
			
		||||
    if (l_vec.empty() && !done()) 
 | 
			
		||||
        m_basics.basic_lemma(true); 
 | 
			
		||||
| 
						 | 
				
			
			@ -1661,51 +1660,15 @@ std::unordered_set<lpvar> core::get_vars_of_expr_with_opening_terms(const nex *e
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void core::set_active_vars_weights(nex_creator& nc) {
 | 
			
		||||
    nc.set_number_of_vars(m_lar_solver.column_count());
 | 
			
		||||
    for (lpvar j : active_var_set()) 
 | 
			
		||||
        nc.set_var_weight(j, get_var_weight(j));
 | 
			
		||||
bool core::is_nl_var(lpvar j) const {
 | 
			
		||||
    return is_monic_var(j) || m_emons.is_used_in_monic(j);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void core::set_level2var_for_grobner() {
 | 
			
		||||
    unsigned n = m_lar_solver.column_count();
 | 
			
		||||
    unsigned_vector sorted_vars(n), weighted_vars(n);
 | 
			
		||||
    for (unsigned j = 0; j < n; j++) {
 | 
			
		||||
        sorted_vars[j] = j;
 | 
			
		||||
        weighted_vars[j] = get_var_weight(j);
 | 
			
		||||
    }
 | 
			
		||||
#if 1
 | 
			
		||||
    // potential update to weights
 | 
			
		||||
    for (unsigned j = 0; j < n; j++) {
 | 
			
		||||
        if (is_monic_var(j) && m_to_refine.contains(j)) {
 | 
			
		||||
            for (lpvar k : m_emons[j].vars()) {
 | 
			
		||||
                weighted_vars[k] += 6;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    std::sort(sorted_vars.begin(), sorted_vars.end(), [&](unsigned a, unsigned b) {
 | 
			
		||||
                                                      unsigned wa = weighted_vars[a];
 | 
			
		||||
                                                      unsigned wb = weighted_vars[b];
 | 
			
		||||
                                                      return wa < wb || (wa == wb && a < b); });
 | 
			
		||||
 | 
			
		||||
    unsigned_vector l2v(n);
 | 
			
		||||
    for (unsigned j = 0; j < n; j++)
 | 
			
		||||
        l2v[j] = sorted_vars[j];
 | 
			
		||||
 | 
			
		||||
    m_pdd_manager.reset(l2v);
 | 
			
		||||
 | 
			
		||||
    TRACE("grobner",
 | 
			
		||||
          for (auto v : sorted_vars)
 | 
			
		||||
              tout << "j" << v << " w:" << weighted_vars[v] << " ";
 | 
			
		||||
          tout << "\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned core::get_var_weight(lpvar j) const {
 | 
			
		||||
    unsigned k;
 | 
			
		||||
    switch (m_lar_solver.get_column_type(j)) {
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
    case lp::column_type::fixed:
 | 
			
		||||
        k = 0;
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			@ -1725,14 +1688,17 @@ unsigned core::get_var_weight(lpvar j) const {
 | 
			
		|||
    }
 | 
			
		||||
    if (is_monic_var(j)) {
 | 
			
		||||
        k++;
 | 
			
		||||
        if (m_to_refine.contains(j)) 
 | 
			
		||||
        if (m_to_refine.contains(j))
 | 
			
		||||
            k++;
 | 
			
		||||
    }
 | 
			
		||||
    return k;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool core::is_nl_var(lpvar j) const {
 | 
			
		||||
    return is_monic_var(j) || m_emons.is_used_in_monic(j);
 | 
			
		||||
 | 
			
		||||
void core::set_active_vars_weights(nex_creator& nc) {
 | 
			
		||||
    nc.set_number_of_vars(m_lar_solver.column_count());
 | 
			
		||||
    for (lpvar j : active_var_set()) 
 | 
			
		||||
        nc.set_var_weight(j, get_var_weight(j));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool core::influences_nl_var(lpvar j) const {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,13 +18,13 @@
 | 
			
		|||
#include "math/lp/nla_basics_lemmas.h"
 | 
			
		||||
#include "math/lp/nla_order_lemmas.h"
 | 
			
		||||
#include "math/lp/nla_monotone_lemmas.h"
 | 
			
		||||
#include "math/lp/nla_grobner.h"
 | 
			
		||||
#include "math/lp/emonics.h"
 | 
			
		||||
#include "math/lp/nla_settings.h"
 | 
			
		||||
#include "math/lp/nex.h"
 | 
			
		||||
#include "math/lp/horner.h"
 | 
			
		||||
#include "math/lp/monomial_bounds.h"
 | 
			
		||||
#include "math/lp/nla_intervals.h"
 | 
			
		||||
#include "math/grobner/pdd_solver.h"
 | 
			
		||||
#include "nlsat/nlsat_solver.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -139,6 +139,9 @@ struct pp_factorization {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
class core {
 | 
			
		||||
    friend class new_lemma;
 | 
			
		||||
    friend class grobner;
 | 
			
		||||
 | 
			
		||||
    struct stats {
 | 
			
		||||
        unsigned m_nla_explanations;
 | 
			
		||||
        unsigned m_nla_lemmas;
 | 
			
		||||
| 
						 | 
				
			
			@ -148,11 +151,11 @@ class core {
 | 
			
		|||
            memset(this, 0, sizeof(*this));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    stats                    m_stats;
 | 
			
		||||
    friend class new_lemma;
 | 
			
		||||
 | 
			
		||||
    unsigned m_nlsat_delay { 50 };
 | 
			
		||||
    unsigned m_nlsat_fails { 0 };
 | 
			
		||||
    stats    m_stats;
 | 
			
		||||
    unsigned m_nlsat_delay = 50;
 | 
			
		||||
    unsigned m_nlsat_fails = 0;
 | 
			
		||||
 | 
			
		||||
    bool should_run_bounded_nlsat();
 | 
			
		||||
    lbool bounded_nlsat();
 | 
			
		||||
public:
 | 
			
		||||
| 
						 | 
				
			
			@ -168,13 +171,12 @@ public:
 | 
			
		|||
    monomial_bounds          m_monomial_bounds;
 | 
			
		||||
    horner                   m_horner;
 | 
			
		||||
    nla_settings             m_nla_settings;    
 | 
			
		||||
    dd::pdd_manager          m_pdd_manager;
 | 
			
		||||
    dd::solver               m_pdd_grobner;
 | 
			
		||||
    grobner                  m_grobner;
 | 
			
		||||
private:
 | 
			
		||||
    emonics                  m_emons;
 | 
			
		||||
    svector<lpvar>           m_add_buffer;
 | 
			
		||||
    mutable lp::u_set        m_active_var_set;
 | 
			
		||||
    lp::u_set                m_rows;
 | 
			
		||||
 | 
			
		||||
    reslimit                 m_nra_lim;
 | 
			
		||||
public:
 | 
			
		||||
    reslimit&                m_reslim;
 | 
			
		||||
| 
						 | 
				
			
			@ -205,6 +207,8 @@ public:
 | 
			
		|||
        m_active_var_set.resize(m_lar_solver.number_of_vars());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    unsigned get_var_weight(lpvar) const;
 | 
			
		||||
 | 
			
		||||
    reslimit& reslim() { return m_reslim; }  
 | 
			
		||||
    emonics& emons() { return m_emons; }
 | 
			
		||||
    const emonics& emons() const { return m_emons; }
 | 
			
		||||
| 
						 | 
				
			
			@ -249,6 +253,9 @@ public:
 | 
			
		|||
    bool need_run_grobner() const { 
 | 
			
		||||
        return m_nla_settings.run_grobner && lp_settings().stats().m_nla_calls % m_nla_settings.grobner_frequency == 0; 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void set_active_vars_weights(nex_creator&);
 | 
			
		||||
    std::unordered_set<lpvar> get_vars_of_expr_with_opening_terms(const nex* e);
 | 
			
		||||
    
 | 
			
		||||
    void incremental_linearization(bool);
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -450,33 +457,16 @@ public:
 | 
			
		|||
    lpvar map_to_root(lpvar) const;
 | 
			
		||||
    std::ostream& print_terms(std::ostream&) const;
 | 
			
		||||
    std::ostream& print_term(const lp::lar_term&, std::ostream&) const;
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    std::ostream& print_row(const T & row , std::ostream& out) const {
 | 
			
		||||
    std::ostream& print_row(const T& row, std::ostream& out) const {
 | 
			
		||||
        vector<std::pair<rational, lpvar>> v;
 | 
			
		||||
        for (auto p : row) {
 | 
			
		||||
            v.push_back(std::make_pair(p.coeff(), p.var()));
 | 
			
		||||
        }
 | 
			
		||||
        return lp::print_linear_combination_customized(v, [this](lpvar j) { return var_str(j); }, out);        
 | 
			
		||||
        return lp::print_linear_combination_customized(v, [this](lpvar j) { return var_str(j); }, out);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    void run_grobner();
 | 
			
		||||
    void find_nl_cluster();
 | 
			
		||||
    void prepare_rows_and_active_vars();
 | 
			
		||||
    void add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j,  svector<lpvar>& q);
 | 
			
		||||
    std::unordered_set<lpvar> get_vars_of_expr_with_opening_terms(const nex* e);
 | 
			
		||||
    void display_matrix_of_m_rows(std::ostream & out) const;
 | 
			
		||||
    void set_active_vars_weights(nex_creator&);
 | 
			
		||||
    unsigned get_var_weight(lpvar) const;
 | 
			
		||||
    void add_row_to_grobner(const vector<lp::row_cell<rational>> & row);
 | 
			
		||||
    void add_fixed_monic_to_grobner(unsigned j);
 | 
			
		||||
    bool is_solved(dd::pdd const& p, unsigned& v, dd::pdd& r);
 | 
			
		||||
    void add_eq_to_grobner(dd::pdd& p, u_dependency* dep);
 | 
			
		||||
    bool check_pdd_eq(const dd::solver::equation*);
 | 
			
		||||
    const rational& val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep);
 | 
			
		||||
    dd::pdd pdd_expr(const rational& c, lpvar j, u_dependency*&);
 | 
			
		||||
    void set_level2var_for_grobner();
 | 
			
		||||
    void configure_grobner();
 | 
			
		||||
    bool influences_nl_var(lpvar) const;
 | 
			
		||||
    bool is_nl_var(lpvar) const;
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,16 +20,28 @@ Author:
 | 
			
		|||
 | 
			
		||||
namespace nla {
 | 
			
		||||
 | 
			
		||||
    void core::run_grobner() {
 | 
			
		||||
        unsigned& quota = m_nla_settings.grobner_quota;
 | 
			
		||||
    grobner::grobner(core* c):
 | 
			
		||||
        common(c),
 | 
			
		||||
        m_pdd_manager(m_core.m_lar_solver.number_of_vars()),
 | 
			
		||||
        m_pdd_grobner(m_core.m_reslim, m_pdd_manager),
 | 
			
		||||
        m_lar_solver(m_core.m_lar_solver)
 | 
			
		||||
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    lp::lp_settings& grobner::lp_settings() {
 | 
			
		||||
        return c().lp_settings();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void grobner::operator()() {
 | 
			
		||||
        unsigned& quota = c().m_nla_settings.grobner_quota;
 | 
			
		||||
        if (quota == 1) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        clear_and_resize_active_var_set(); 
 | 
			
		||||
        c().clear_and_resize_active_var_set(); 
 | 
			
		||||
        find_nl_cluster();
 | 
			
		||||
 | 
			
		||||
        lp_settings().stats().m_grobner_calls++;
 | 
			
		||||
        configure_grobner();
 | 
			
		||||
        c().lp_settings().stats().m_grobner_calls++;
 | 
			
		||||
        configure();
 | 
			
		||||
        m_pdd_grobner.saturate();
 | 
			
		||||
        bool conflict = false;
 | 
			
		||||
        unsigned n = m_pdd_grobner.number_of_conflicts_to_report();
 | 
			
		||||
| 
						 | 
				
			
			@ -47,6 +59,20 @@ namespace nla {
 | 
			
		|||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (propagate_bounds())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (propagate_eqs())
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (quota > 1)
 | 
			
		||||
            quota--;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        IF_VERBOSE(2, verbose_stream() << "grobner miss, quota " << quota << "\n");
 | 
			
		||||
        IF_VERBOSE(4, diagnose_pdd_miss(verbose_stream()));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
        // diagnostics: did we miss something
 | 
			
		||||
        vector<dd::pdd> eqs;
 | 
			
		||||
| 
						 | 
				
			
			@ -81,29 +107,33 @@ namespace nla {
 | 
			
		|||
            return;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        if (quota > 1)
 | 
			
		||||
            quota--;
 | 
			
		||||
        IF_VERBOSE(2, verbose_stream() << "grobner miss, quota " << quota <<  "\n");
 | 
			
		||||
        IF_VERBOSE(4, diagnose_pdd_miss(verbose_stream()));
 | 
			
		||||
    
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void core::configure_grobner() {
 | 
			
		||||
    bool grobner::propagate_bounds() {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool grobner::propagate_eqs() {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void grobner::configure() {
 | 
			
		||||
        m_pdd_grobner.reset();
 | 
			
		||||
        try {
 | 
			
		||||
            set_level2var_for_grobner();
 | 
			
		||||
            set_level2var();
 | 
			
		||||
            TRACE("grobner",
 | 
			
		||||
                  tout << "base vars: ";
 | 
			
		||||
                  for (lpvar j : active_var_set())
 | 
			
		||||
                      if (m_lar_solver.is_base(j))
 | 
			
		||||
                  for (lpvar j : c().active_var_set())
 | 
			
		||||
                      if (c().m_lar_solver.is_base(j))
 | 
			
		||||
                          tout << "j" << j << " ";
 | 
			
		||||
                  tout << "\n");
 | 
			
		||||
            for (lpvar j : active_var_set()) {
 | 
			
		||||
                if (m_lar_solver.is_base(j))
 | 
			
		||||
                    add_row_to_grobner(m_lar_solver.basic2row(j));
 | 
			
		||||
            for (lpvar j : c().active_var_set()) {
 | 
			
		||||
                if (c().m_lar_solver.is_base(j))
 | 
			
		||||
                    add_row(c().m_lar_solver.basic2row(j));
 | 
			
		||||
                
 | 
			
		||||
                if (is_monic_var(j) && var_is_fixed(j))
 | 
			
		||||
                    add_fixed_monic_to_grobner(j);
 | 
			
		||||
                if (c().is_monic_var(j) && c().var_is_fixed(j))
 | 
			
		||||
                    add_fixed_monic(j);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        catch (...) {
 | 
			
		||||
| 
						 | 
				
			
			@ -127,17 +157,17 @@ namespace nla {
 | 
			
		|||
   
 | 
			
		||||
        struct dd::solver::config cfg;
 | 
			
		||||
        cfg.m_max_steps = m_pdd_grobner.equations().size();
 | 
			
		||||
        cfg.m_max_simplified = m_nla_settings.grobner_max_simplified;
 | 
			
		||||
        cfg.m_eqs_growth = m_nla_settings.grobner_eqs_growth;
 | 
			
		||||
        cfg.m_expr_size_growth = m_nla_settings.grobner_expr_size_growth;
 | 
			
		||||
        cfg.m_expr_degree_growth = m_nla_settings.grobner_expr_degree_growth;
 | 
			
		||||
        cfg.m_number_of_conflicts_to_report = m_nla_settings.grobner_number_of_conflicts_to_report;
 | 
			
		||||
        cfg.m_max_simplified = c().m_nla_settings.grobner_max_simplified;
 | 
			
		||||
        cfg.m_eqs_growth = c().m_nla_settings.grobner_eqs_growth;
 | 
			
		||||
        cfg.m_expr_size_growth = c().m_nla_settings.grobner_expr_size_growth;
 | 
			
		||||
        cfg.m_expr_degree_growth = c().m_nla_settings.grobner_expr_degree_growth;
 | 
			
		||||
        cfg.m_number_of_conflicts_to_report = c().m_nla_settings.grobner_number_of_conflicts_to_report;
 | 
			
		||||
        m_pdd_grobner.set(cfg);
 | 
			
		||||
        m_pdd_grobner.adjust_cfg();
 | 
			
		||||
        m_pdd_manager.set_max_num_nodes(10000); // or something proportional to the number of initial nodes.
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::ostream& core::diagnose_pdd_miss(std::ostream& out) {
 | 
			
		||||
    std::ostream& grobner::diagnose_pdd_miss(std::ostream& out) {
 | 
			
		||||
 | 
			
		||||
        // m_pdd_grobner.display(out);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -163,12 +193,12 @@ namespace nla {
 | 
			
		|||
        return out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool core::check_pdd_eq(const dd::solver::equation* e) {
 | 
			
		||||
        auto& di = m_intervals.get_dep_intervals();
 | 
			
		||||
    bool grobner::check_pdd_eq(const dd::solver::equation* e) {
 | 
			
		||||
        auto& di = c().m_intervals.get_dep_intervals();
 | 
			
		||||
        dd::pdd_interval eval(di);
 | 
			
		||||
        eval.var2interval() = [this](lpvar j, bool deps, scoped_dep_interval& a) {
 | 
			
		||||
            if (deps) m_intervals.set_var_interval<dd::w_dep::with_deps>(j, a);
 | 
			
		||||
            else m_intervals.set_var_interval<dd::w_dep::without_deps>(j, a);
 | 
			
		||||
            if (deps) c().m_intervals.set_var_interval<dd::w_dep::with_deps>(j, a);
 | 
			
		||||
            else c().m_intervals.set_var_interval<dd::w_dep::without_deps>(j, a);
 | 
			
		||||
        };
 | 
			
		||||
        scoped_dep_interval i(di), i_wd(di);
 | 
			
		||||
        eval.get_interval<dd::w_dep::without_deps>(e->poly(), i);    
 | 
			
		||||
| 
						 | 
				
			
			@ -178,8 +208,8 @@ namespace nla {
 | 
			
		|||
                  tout << "separated from 0: " << di.separated_from_zero(i) << "\n";
 | 
			
		||||
                  for (auto j : e->poly().free_vars()) {
 | 
			
		||||
                      scoped_dep_interval a(di);
 | 
			
		||||
                      m_intervals.set_var_interval<dd::w_dep::without_deps>(j, a);
 | 
			
		||||
                      m_intervals.display(tout << "j" << j << " ", a); tout << " ";
 | 
			
		||||
                      c().m_intervals.set_var_interval<dd::w_dep::without_deps>(j, a);
 | 
			
		||||
                      c().m_intervals.display(tout << "j" << j << " ", a); tout << " ";
 | 
			
		||||
                  }
 | 
			
		||||
                  tout << "\n");
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -187,7 +217,7 @@ namespace nla {
 | 
			
		|||
        }
 | 
			
		||||
        eval.get_interval<dd::w_dep::with_deps>(e->poly(), i_wd);  
 | 
			
		||||
        std::function<void (const lp::explanation&)> f = [this](const lp::explanation& e) {
 | 
			
		||||
            new_lemma lemma(*this, "pdd");
 | 
			
		||||
            new_lemma lemma(m_core, "pdd");
 | 
			
		||||
            lemma &= e;
 | 
			
		||||
        };
 | 
			
		||||
        if (di.check_interval_for_conflict_on_zero(i_wd, e->dep(), f)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -201,18 +231,18 @@ namespace nla {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void core::add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector<lpvar> & q) {
 | 
			
		||||
        if (active_var_set_contains(j))
 | 
			
		||||
    void grobner::add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector<lpvar> & q) {
 | 
			
		||||
        if (c().active_var_set_contains(j))
 | 
			
		||||
            return;
 | 
			
		||||
        insert_to_active_var_set(j);
 | 
			
		||||
        if (is_monic_var(j)) {
 | 
			
		||||
            const monic& m = emons()[j];
 | 
			
		||||
            for (auto fcn : factorization_factory_imp(m, *this)) 
 | 
			
		||||
        c().insert_to_active_var_set(j);
 | 
			
		||||
        if (c().is_monic_var(j)) {
 | 
			
		||||
            const monic& m = c().emons()[j];
 | 
			
		||||
            for (auto fcn : factorization_factory_imp(m, m_core)) 
 | 
			
		||||
                for (const factor& fc: fcn) 
 | 
			
		||||
                    q.push_back(var(fc));        
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (var_is_fixed(j))
 | 
			
		||||
        if (c().var_is_fixed(j))
 | 
			
		||||
            return;
 | 
			
		||||
        const auto& matrix = m_lar_solver.A_r();
 | 
			
		||||
        for (auto & s : matrix.m_columns[j]) {
 | 
			
		||||
| 
						 | 
				
			
			@ -223,9 +253,9 @@ namespace nla {
 | 
			
		|||
            unsigned k = m_lar_solver.get_base_column_in_row(row);
 | 
			
		||||
            if (m_lar_solver.column_is_free(k) && k != j)
 | 
			
		||||
                continue;
 | 
			
		||||
            CTRACE("grobner", matrix.m_rows[row].size() > m_nla_settings.grobner_row_length_limit,
 | 
			
		||||
            CTRACE("grobner", matrix.m_rows[row].size() > c().m_nla_settings.grobner_row_length_limit,
 | 
			
		||||
                   tout << "ignore the row " << row << " with the size " << matrix.m_rows[row].size() << "\n";); 
 | 
			
		||||
            if (matrix.m_rows[row].size() > m_nla_settings.grobner_row_length_limit) 
 | 
			
		||||
            if (matrix.m_rows[row].size() > c().m_nla_settings.grobner_row_length_limit)
 | 
			
		||||
                continue;
 | 
			
		||||
            for (auto& rc : matrix.m_rows[row]) 
 | 
			
		||||
                add_var_and_its_factors_to_q_and_collect_new_rows(rc.var(), q);
 | 
			
		||||
| 
						 | 
				
			
			@ -234,33 +264,33 @@ namespace nla {
 | 
			
		|||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const rational& core::val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep) {
 | 
			
		||||
    const rational& grobner::val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep) {
 | 
			
		||||
        unsigned lc, uc;
 | 
			
		||||
        m_lar_solver.get_bound_constraint_witnesses_for_column(j, lc, uc);
 | 
			
		||||
        dep = m_intervals.mk_join(dep, m_intervals.mk_leaf(lc));
 | 
			
		||||
        dep = m_intervals.mk_join(dep, m_intervals.mk_leaf(uc));
 | 
			
		||||
        dep = c().m_intervals.mk_join(dep, c().m_intervals.mk_leaf(lc));
 | 
			
		||||
        dep = c().m_intervals.mk_join(dep, c().m_intervals.mk_leaf(uc));
 | 
			
		||||
        return m_lar_solver.column_lower_bound(j).x;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    dd::pdd core::pdd_expr(const rational& c, lpvar j, u_dependency*& dep) {
 | 
			
		||||
        dd::pdd r = m_pdd_manager.mk_val(c);
 | 
			
		||||
    dd::pdd grobner::pdd_expr(const rational& coeff, lpvar j, u_dependency*& dep) {
 | 
			
		||||
        dd::pdd r = m_pdd_manager.mk_val(coeff);
 | 
			
		||||
        sbuffer<lpvar> vars;
 | 
			
		||||
        vars.push_back(j);
 | 
			
		||||
        u_dependency* zero_dep = dep;
 | 
			
		||||
        while (!vars.empty()) {
 | 
			
		||||
            j = vars.back();
 | 
			
		||||
            vars.pop_back();
 | 
			
		||||
            if (m_nla_settings.grobner_subs_fixed > 0 && var_is_fixed_to_zero(j)) {
 | 
			
		||||
            if (c().m_nla_settings.grobner_subs_fixed > 0 && c().var_is_fixed_to_zero(j)) {
 | 
			
		||||
                r = m_pdd_manager.mk_val(val_of_fixed_var_with_deps(j, zero_dep));
 | 
			
		||||
                dep = zero_dep;
 | 
			
		||||
                return r;
 | 
			
		||||
            }
 | 
			
		||||
            if (m_nla_settings.grobner_subs_fixed == 1 && var_is_fixed(j))
 | 
			
		||||
            if (c().m_nla_settings.grobner_subs_fixed == 1 && c().var_is_fixed(j))
 | 
			
		||||
                r *= val_of_fixed_var_with_deps(j, dep);
 | 
			
		||||
            else if (!is_monic_var(j))
 | 
			
		||||
            else if (!c().is_monic_var(j))
 | 
			
		||||
                r *= m_pdd_manager.mk_var(j);
 | 
			
		||||
            else
 | 
			
		||||
                for (lpvar k : emons()[j].vars())
 | 
			
		||||
                for (lpvar k : c().emons()[j].vars())
 | 
			
		||||
                    vars.push_back(k);        
 | 
			
		||||
        }
 | 
			
		||||
        return r;
 | 
			
		||||
| 
						 | 
				
			
			@ -277,7 +307,7 @@ namespace nla {
 | 
			
		|||
       we prefer to solve z == -x - y instead of x == -z - y
 | 
			
		||||
       because the solution -z - y has neither an upper, nor a lower bound.
 | 
			
		||||
    */
 | 
			
		||||
    bool core::is_solved(dd::pdd const& p, unsigned& v, dd::pdd& r) {
 | 
			
		||||
    bool grobner::is_solved(dd::pdd const& p, unsigned& v, dd::pdd& r) {
 | 
			
		||||
        if (!p.is_linear())
 | 
			
		||||
            return false;
 | 
			
		||||
        r = p;
 | 
			
		||||
| 
						 | 
				
			
			@ -325,7 +355,7 @@ namespace nla {
 | 
			
		|||
    /**
 | 
			
		||||
       \brief add an equality to grobner solver, convert it to solved form if available.
 | 
			
		||||
    */    
 | 
			
		||||
    void core::add_eq_to_grobner(dd::pdd& p, u_dependency* dep) {
 | 
			
		||||
    void grobner::add_eq(dd::pdd& p, u_dependency* dep) {
 | 
			
		||||
        unsigned v;
 | 
			
		||||
        dd::pdd q(m_pdd_manager);
 | 
			
		||||
        m_pdd_grobner.simplify(p, dep);
 | 
			
		||||
| 
						 | 
				
			
			@ -335,32 +365,32 @@ namespace nla {
 | 
			
		|||
            m_pdd_grobner.add(p, dep);    
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void core::add_fixed_monic_to_grobner(unsigned j) {
 | 
			
		||||
    void grobner::add_fixed_monic(unsigned j) {
 | 
			
		||||
        u_dependency* dep = nullptr;
 | 
			
		||||
        dd::pdd r = m_pdd_manager.mk_val(rational(1));
 | 
			
		||||
        for (lpvar k : emons()[j].vars()) 
 | 
			
		||||
        for (lpvar k : c().emons()[j].vars())
 | 
			
		||||
            r *= pdd_expr(rational::one(), k, dep);
 | 
			
		||||
        r -= val_of_fixed_var_with_deps(j, dep);
 | 
			
		||||
        add_eq_to_grobner(r, dep);
 | 
			
		||||
        add_eq(r, dep);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void core::add_row_to_grobner(const vector<lp::row_cell<rational>> & row) {
 | 
			
		||||
    void grobner::add_row(const vector<lp::row_cell<rational>> & row) {
 | 
			
		||||
        u_dependency *dep = nullptr;
 | 
			
		||||
        rational val;
 | 
			
		||||
        dd::pdd sum = m_pdd_manager.mk_val(rational(0));
 | 
			
		||||
        for (const auto &p : row) 
 | 
			
		||||
            sum += pdd_expr(p.coeff(), p.var(), dep);
 | 
			
		||||
        TRACE("grobner", print_row(row, tout) << " " << sum << "\n");
 | 
			
		||||
        add_eq_to_grobner(sum, dep);
 | 
			
		||||
        TRACE("grobner", c().print_row(row, tout) << " " << sum << "\n");
 | 
			
		||||
        add_eq(sum, dep);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void core::find_nl_cluster() {
 | 
			
		||||
    void grobner::find_nl_cluster() {
 | 
			
		||||
        prepare_rows_and_active_vars();
 | 
			
		||||
        svector<lpvar> q;
 | 
			
		||||
        TRACE("grobner", for (lpvar j : m_to_refine) print_monic(emons()[j], tout) << "\n";);
 | 
			
		||||
        TRACE("grobner", for (lpvar j : c().m_to_refine) print_monic(c().emons()[j], tout) << "\n";);
 | 
			
		||||
          
 | 
			
		||||
        for (lpvar j : m_to_refine) 
 | 
			
		||||
        for (lpvar j : c().m_to_refine)
 | 
			
		||||
            q.push_back(j);
 | 
			
		||||
    
 | 
			
		||||
        while (!q.empty()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -369,25 +399,59 @@ namespace nla {
 | 
			
		|||
            add_var_and_its_factors_to_q_and_collect_new_rows(j, q);
 | 
			
		||||
        }
 | 
			
		||||
        TRACE("grobner", tout << "vars in cluster: ";
 | 
			
		||||
              for (lpvar j : active_var_set()) tout << "j" << j << " "; tout << "\n";
 | 
			
		||||
              for (lpvar j : c().active_var_set()) tout << "j" << j << " "; tout << "\n";
 | 
			
		||||
              display_matrix_of_m_rows(tout);
 | 
			
		||||
              );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void core::prepare_rows_and_active_vars() {
 | 
			
		||||
    void grobner::prepare_rows_and_active_vars() {
 | 
			
		||||
        m_rows.clear();
 | 
			
		||||
        m_rows.resize(m_lar_solver.row_count());
 | 
			
		||||
        clear_and_resize_active_var_set();
 | 
			
		||||
        c().clear_and_resize_active_var_set();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void core::display_matrix_of_m_rows(std::ostream & out) const {
 | 
			
		||||
    void grobner::display_matrix_of_m_rows(std::ostream & out) const {
 | 
			
		||||
        const auto& matrix = m_lar_solver.A_r();
 | 
			
		||||
        out << m_rows.size() << " rows" << "\n";
 | 
			
		||||
        out << "the matrix\n";          
 | 
			
		||||
        for (const auto & r : matrix.m_rows) 
 | 
			
		||||
            print_row(r, out) << std::endl;
 | 
			
		||||
            c().print_row(r, out) << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void grobner::set_level2var() {
 | 
			
		||||
        unsigned n = m_lar_solver.column_count();
 | 
			
		||||
        unsigned_vector sorted_vars(n), weighted_vars(n);
 | 
			
		||||
        for (unsigned j = 0; j < n; j++) {
 | 
			
		||||
            sorted_vars[j] = j;
 | 
			
		||||
            weighted_vars[j] = c().get_var_weight(j);
 | 
			
		||||
        }
 | 
			
		||||
#if 1
 | 
			
		||||
        // potential update to weights
 | 
			
		||||
        for (unsigned j = 0; j < n; j++) {
 | 
			
		||||
            if (c().is_monic_var(j) && c().m_to_refine.contains(j)) {
 | 
			
		||||
                for (lpvar k : c().m_emons[j].vars()) {
 | 
			
		||||
                    weighted_vars[k] += 6;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        std::sort(sorted_vars.begin(), sorted_vars.end(), [&](unsigned a, unsigned b) {
 | 
			
		||||
            unsigned wa = weighted_vars[a];
 | 
			
		||||
            unsigned wb = weighted_vars[b];
 | 
			
		||||
            return wa < wb || (wa == wb && a < b); });
 | 
			
		||||
 | 
			
		||||
        unsigned_vector l2v(n);
 | 
			
		||||
        for (unsigned j = 0; j < n; j++)
 | 
			
		||||
            l2v[j] = sorted_vars[j];
 | 
			
		||||
 | 
			
		||||
        m_pdd_manager.reset(l2v);
 | 
			
		||||
 | 
			
		||||
        TRACE("grobner",
 | 
			
		||||
            for (auto v : sorted_vars)
 | 
			
		||||
                tout << "j" << v << " w:" << weighted_vars[v] << " ";
 | 
			
		||||
        tout << "\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										49
									
								
								src/math/lp/nla_grobner.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								src/math/lp/nla_grobner.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,49 @@
 | 
			
		|||
/*++
 | 
			
		||||
  Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
  Author:
 | 
			
		||||
  Nikolaj Bjorner (nbjorner)
 | 
			
		||||
  Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
  --*/
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "math/lp/nla_common.h"
 | 
			
		||||
#include "math/lp/nla_intervals.h"
 | 
			
		||||
#include "math/lp/nex.h"
 | 
			
		||||
#include "math/lp/cross_nested.h"
 | 
			
		||||
#include "math/lp/u_set.h"
 | 
			
		||||
#include "math/grobner/pdd_solver.h"
 | 
			
		||||
 | 
			
		||||
namespace nla {
 | 
			
		||||
    class core;
 | 
			
		||||
 | 
			
		||||
    class grobner : common {
 | 
			
		||||
        dd::pdd_manager          m_pdd_manager;
 | 
			
		||||
        dd::solver               m_pdd_grobner;
 | 
			
		||||
        lp::lar_solver&          m_lar_solver;
 | 
			
		||||
        lp::u_set                m_rows;
 | 
			
		||||
 | 
			
		||||
        bool propagate_bounds();
 | 
			
		||||
        bool propagate_eqs();
 | 
			
		||||
        lp::lp_settings& lp_settings();
 | 
			
		||||
        void find_nl_cluster();
 | 
			
		||||
        void prepare_rows_and_active_vars();
 | 
			
		||||
        void add_var_and_its_factors_to_q_and_collect_new_rows(lpvar j, svector<lpvar>& q);
 | 
			
		||||
        void display_matrix_of_m_rows(std::ostream& out) const;        
 | 
			
		||||
        void add_row(const vector<lp::row_cell<rational>>& row);
 | 
			
		||||
        void add_fixed_monic(unsigned j);
 | 
			
		||||
        bool is_solved(dd::pdd const& p, unsigned& v, dd::pdd& r);
 | 
			
		||||
        void add_eq(dd::pdd& p, u_dependency* dep);
 | 
			
		||||
        bool check_pdd_eq(const dd::solver::equation*);
 | 
			
		||||
        const rational& val_of_fixed_var_with_deps(lpvar j, u_dependency*& dep);
 | 
			
		||||
        dd::pdd pdd_expr(const rational& c, lpvar j, u_dependency*&);
 | 
			
		||||
        void set_level2var();
 | 
			
		||||
        void configure();
 | 
			
		||||
        std::ostream& diagnose_pdd_miss(std::ostream& out);
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        grobner(core *core);        
 | 
			
		||||
        void operator()();
 | 
			
		||||
    }; 
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue