mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	add accounting for integrality
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									fd1758ffab
								
							
						
					
					
						commit
						8cd1ddf445
					
				
					 2 changed files with 51 additions and 11 deletions
				
			
		| 
						 | 
				
			
			@ -70,6 +70,7 @@ namespace polysat {
 | 
			
		|||
        };
 | 
			
		||||
 | 
			
		||||
        struct row_info {
 | 
			
		||||
            bool    m_integral { true };
 | 
			
		||||
            var_t   m_base;
 | 
			
		||||
            numeral m_value;
 | 
			
		||||
            numeral m_base_coeff;            
 | 
			
		||||
| 
						 | 
				
			
			@ -80,6 +81,7 @@ namespace polysat {
 | 
			
		|||
        mutable manager             m;
 | 
			
		||||
        mutable matrix              M;
 | 
			
		||||
        unsigned                    m_max_iterations { UINT_MAX };
 | 
			
		||||
        unsigned                    m_num_non_integral { 0 };
 | 
			
		||||
        var_heap                    m_to_patch;
 | 
			
		||||
        vector<var_info>            m_vars;
 | 
			
		||||
        vector<row_info>            m_rows;
 | 
			
		||||
| 
						 | 
				
			
			@ -150,6 +152,12 @@ namespace polysat {
 | 
			
		|||
        bool is_free(var_t v) const { return lo(v) == hi(v); }
 | 
			
		||||
        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; }
 | 
			
		||||
        unsigned base2row(var_t x) const { return m_vars[x].m_base2row; }
 | 
			
		||||
        numeral const& row2value(row const& r) const { return m_rows[r.id()].m_value; }
 | 
			
		||||
        numeral const& row2base_coeff(row const& r) const { return m_rows[r.id()].m_base_coeff; }
 | 
			
		||||
        var_t row2base(row const& r) const { return m_rows[r.id()].m_base; }
 | 
			
		||||
        bool row2integral(row const& r) const { return m_rows[r.id()].m_integral; }
 | 
			
		||||
        void set_base_value(var_t x); 
 | 
			
		||||
        bool is_feasible() const;
 | 
			
		||||
        int get_num_non_free_dep_vars(var_t x_j, int best_so_far);
 | 
			
		||||
        void add_patch(var_t v);
 | 
			
		||||
| 
						 | 
				
			
			@ -158,6 +166,9 @@ namespace polysat {
 | 
			
		|||
        pivot_strategy_t pivot_strategy() { return m_bland ? S_BLAND : S_DEFAULT; }
 | 
			
		||||
        var_t select_error_var(bool least);
 | 
			
		||||
 | 
			
		||||
        bool is_solved(row const& r) const;
 | 
			
		||||
        bool is_solved(var_t v) const { SASSERT(is_base(v)); return is_solved(base2row(v)); }
 | 
			
		||||
 | 
			
		||||
        bool well_formed() const;                 
 | 
			
		||||
        bool well_formed_row(row const& r) const;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -114,7 +114,7 @@ namespace polysat {
 | 
			
		|||
        m_rows[r.id()].m_value = value;
 | 
			
		||||
        m_vars[base_var].m_base2row = r.id();
 | 
			
		||||
        m_vars[base_var].m_is_base = true;
 | 
			
		||||
        m_vars[base_var].m_value = 0 - (value / base_coeff);
 | 
			
		||||
        set_base_value(base_var);
 | 
			
		||||
        // TBD: record when base_coeff does not divide value
 | 
			
		||||
        add_patch(base_var);
 | 
			
		||||
        if (!m_base_vars.empty()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -148,7 +148,7 @@ namespace polysat {
 | 
			
		|||
            row_info& ri = m_rows[r.id()];
 | 
			
		||||
            var_t s = ri.m_base;
 | 
			
		||||
            ri.m_value += delta * c.get_row_entry().m_coeff;
 | 
			
		||||
            m_vars[s].m_value = 0 - (ri.m_value / ri.m_base_coeff);
 | 
			
		||||
            set_base_value(s);
 | 
			
		||||
            add_patch(s);
 | 
			
		||||
        }            
 | 
			
		||||
    }    
 | 
			
		||||
| 
						 | 
				
			
			@ -234,7 +234,7 @@ namespace polysat {
 | 
			
		|||
        SASSERT(is_base(x));
 | 
			
		||||
        var_t max    = get_num_vars();
 | 
			
		||||
        var_t result = max;
 | 
			
		||||
        row r = row(m_vars[x].m_base2row);
 | 
			
		||||
        row r(base2row(x));
 | 
			
		||||
        int n = 0;
 | 
			
		||||
        unsigned best_col_sz = UINT_MAX;
 | 
			
		||||
        int best_so_far    = INT_MAX;
 | 
			
		||||
| 
						 | 
				
			
			@ -378,7 +378,7 @@ namespace polysat {
 | 
			
		|||
    template<typename Ext>
 | 
			
		||||
    bool fixplex<Ext>::is_infeasible_row(var_t x) {
 | 
			
		||||
        SASSERT(is_base(x));
 | 
			
		||||
        auto r = m_vars[x].m_base2row;
 | 
			
		||||
        auto r = base2row(x);
 | 
			
		||||
        numeral lo_sum = 0, hi_sum = 0, diff = 0;
 | 
			
		||||
        for (auto const& e : M.row_entries(row(r))) {
 | 
			
		||||
            var_t v = e.m_var;
 | 
			
		||||
| 
						 | 
				
			
			@ -444,7 +444,7 @@ namespace polysat {
 | 
			
		|||
        row_x.m_base_coeff = b;
 | 
			
		||||
        yI.m_base2row = rx;
 | 
			
		||||
        yI.m_is_base = true;
 | 
			
		||||
        yI.m_value = 0 - row_x.m_value / b;
 | 
			
		||||
        set_base_value(y);
 | 
			
		||||
        xI.m_is_base = false;
 | 
			
		||||
        xI.m_value = new_value;
 | 
			
		||||
        row r_x(rx);
 | 
			
		||||
| 
						 | 
				
			
			@ -458,8 +458,9 @@ namespace polysat {
 | 
			
		|||
            unsigned rz = r_z.id();
 | 
			
		||||
            if (rz == rx)
 | 
			
		||||
                continue;
 | 
			
		||||
            auto z = row2base(r_z);
 | 
			
		||||
            auto& row_z = m_rows[rz];
 | 
			
		||||
            var_info& zI = m_vars[rz];
 | 
			
		||||
            var_info& zI = m_vars[z];
 | 
			
		||||
            numeral c = col.get_row_entry().m_coeff;
 | 
			
		||||
            unsigned tz2 = trailing_zeros(c);
 | 
			
		||||
            SASSERT(tz1 <= tz2);
 | 
			
		||||
| 
						 | 
				
			
			@ -469,7 +470,7 @@ namespace polysat {
 | 
			
		|||
            M.add(r_z, c1, r_x);
 | 
			
		||||
            row_z.m_value = (b1 * (row_z.m_value - old_value_y)) + c1 * row_x.m_value;
 | 
			
		||||
            row_z.m_base_coeff *= b1;
 | 
			
		||||
            zI.m_value = 0 - row_z.m_value / row_z.m_base_coeff;
 | 
			
		||||
            set_base_value(z);
 | 
			
		||||
            SASSERT(well_formed_row(r_z));
 | 
			
		||||
            add_patch(row_z.m_base);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -488,7 +489,7 @@ namespace polysat {
 | 
			
		|||
    typename fixplex<Ext>::row 
 | 
			
		||||
    fixplex<Ext>::get_infeasible_row() {
 | 
			
		||||
        SASSERT(is_base(m_infeasible_var));
 | 
			
		||||
        return row(m_vars[m_infeasible_var].m_base2row);
 | 
			
		||||
        return row(base2row(m_infeasible_var));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
| 
						 | 
				
			
			@ -513,7 +514,10 @@ namespace polysat {
 | 
			
		|||
    void fixplex<Ext>::add_patch(var_t v) {
 | 
			
		||||
        SASSERT(is_base(v));
 | 
			
		||||
        CTRACE("polysat", !in_bounds(v), tout << "Add patch: v" << v << "\n";);
 | 
			
		||||
        if (!in_bounds(v)) 
 | 
			
		||||
        if (in_bounds(v)) {
 | 
			
		||||
            
 | 
			
		||||
        }
 | 
			
		||||
        else 
 | 
			
		||||
            m_to_patch.insert(v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -569,6 +573,30 @@ namespace polysat {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Check if row is solved with respect to integrality constraints.
 | 
			
		||||
     * The value of the row is allowed to be off by the base coefficient
 | 
			
		||||
     * representing the case where there is a rational, but not integer solution.
 | 
			
		||||
     */
 | 
			
		||||
    template<typename Ext>                                     
 | 
			
		||||
    bool fixplex<Ext>::is_solved(row const& r) const {
 | 
			
		||||
        return (value(row2base(r)) * row2base_coeff(r)) + row2value(r) == 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename Ext>                                     
 | 
			
		||||
    void fixplex<Ext>::set_base_value(var_t x) {
 | 
			
		||||
        SASSERT(is_base(x));
 | 
			
		||||
        auto r = base2row(x);
 | 
			
		||||
        m_vars[x].m_value = 0 - (m_rows[r].m_value / m_rows[r].m_base_coeff);
 | 
			
		||||
        bool was_integral = m_rows[r].m_integral;
 | 
			
		||||
        m_rows[r].m_integral = is_solved(row(r));
 | 
			
		||||
        if (was_integral && !row2integral(row(r)))
 | 
			
		||||
            ++m_num_non_integral;
 | 
			
		||||
        else if (!was_integral && row2integral(row(r)))
 | 
			
		||||
            --m_num_non_integral;                 
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    template<typename Ext>    
 | 
			
		||||
    std::ostream& fixplex<Ext>::display(std::ostream& out) const {
 | 
			
		||||
        M.display(out);
 | 
			
		||||
| 
						 | 
				
			
			@ -601,7 +629,7 @@ namespace polysat {
 | 
			
		|||
            var_t s = m_rows[i].m_base;
 | 
			
		||||
            if (s == null_var) 
 | 
			
		||||
                continue;
 | 
			
		||||
            SASSERT(i == m_vars[s].m_base2row); 
 | 
			
		||||
            SASSERT(i == base2row(s));
 | 
			
		||||
            VERIFY(well_formed_row(row(i)));            
 | 
			
		||||
        }
 | 
			
		||||
        for (unsigned i = 0; i < m_vars.size(); ++i) {
 | 
			
		||||
| 
						 | 
				
			
			@ -614,7 +642,7 @@ namespace polysat {
 | 
			
		|||
    bool fixplex<Ext>::well_formed_row(row const& r) const { 
 | 
			
		||||
        var_t s = m_rows[r.id()].m_base;
 | 
			
		||||
        (void)s;
 | 
			
		||||
        SASSERT(m_vars[s].m_base2row == r.id());
 | 
			
		||||
        SASSERT(base2row(s) == r.id());
 | 
			
		||||
        SASSERT(m_vars[s].m_is_base);
 | 
			
		||||
        numeral sum = 0;
 | 
			
		||||
        numeral base_coeff = m_rows[r.id()].m_base_coeff;
 | 
			
		||||
| 
						 | 
				
			
			@ -636,5 +664,6 @@ namespace polysat {
 | 
			
		|||
        st.update("fixplex num pivots", m_stats.m_num_pivots);
 | 
			
		||||
        st.update("fixplex num infeasible", m_stats.m_num_infeasible);
 | 
			
		||||
        st.update("fixplex num checks", m_stats.m_num_checks);
 | 
			
		||||
        st.update("fixplex num non-integral", m_num_non_integral);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue