mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 13:29:11 +00:00 
			
		
		
		
	working on hilbert basis
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
		
							parent
							
								
									0c0fe40446
								
							
						
					
					
						commit
						6e7d04f94e
					
				
					 3 changed files with 412 additions and 367 deletions
				
			
		| 
						 | 
				
			
			@ -26,364 +26,219 @@ typedef u_map<unsigned> offset_refs_t;
 | 
			
		|||
template<typename Value>
 | 
			
		||||
class rational_map : public map<rational, Value, rational::hash_proc, rational::eq_proc> {};
 | 
			
		||||
 | 
			
		||||
class rational_abs_lt {
 | 
			
		||||
    vector<rational> & m_values;
 | 
			
		||||
public:
 | 
			
		||||
    rational_abs_lt(vector<rational> & values):
 | 
			
		||||
        m_values(values) {
 | 
			
		||||
    }
 | 
			
		||||
    bool operator()(int v1, int v2) const {
 | 
			
		||||
        return m_values[v1] < m_values[v2];
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class hilbert_basis::rational_heap {
 | 
			
		||||
    vector<numeral>          m_u2r;     // [index |-> weight]
 | 
			
		||||
    rational_map<unsigned>   m_r2u;     // [weight |-> index]
 | 
			
		||||
    rational_abs_lt          m_lt;      // less_than on indices
 | 
			
		||||
    heap<rational_abs_lt>    m_heap;    // binary heap over weights
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    rational_heap(): m_lt(m_u2r), m_heap(10, m_lt) {}
 | 
			
		||||
 | 
			
		||||
    vector<numeral>& u2r() { return m_u2r; }
 | 
			
		||||
 | 
			
		||||
    void insert(unsigned v) {
 | 
			
		||||
        m_heap.insert(v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void reset() {
 | 
			
		||||
        m_u2r.reset();
 | 
			
		||||
        m_r2u.reset();
 | 
			
		||||
        m_heap.reset();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_declared(numeral const& r, unsigned& val) const {
 | 
			
		||||
        return m_r2u.find(r, val);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned declare(numeral const& r) {
 | 
			
		||||
        SASSERT(!m_r2u.contains(r));
 | 
			
		||||
        unsigned val = m_u2r.size();
 | 
			
		||||
        m_u2r.push_back(r);
 | 
			
		||||
        m_r2u.insert(r, val);
 | 
			
		||||
        m_heap.set_bounds(val+1);
 | 
			
		||||
        return val;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void find_le(unsigned val, int_vector & result) {
 | 
			
		||||
        m_heap.find_le(val, result);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class hilbert_basis::weight_map {
 | 
			
		||||
class hilbert_basis::value_index {
 | 
			
		||||
    struct stats {
 | 
			
		||||
        unsigned m_num_comparisons;
 | 
			
		||||
        unsigned m_num_hit;
 | 
			
		||||
        unsigned m_num_miss;
 | 
			
		||||
 | 
			
		||||
        stats() { reset(); }
 | 
			
		||||
        void reset() { memset(this, 0, sizeof(*this)); }
 | 
			
		||||
    };    
 | 
			
		||||
 | 
			
		||||
    rational_heap            m_heap;         
 | 
			
		||||
    vector<unsigned_vector>  m_offsets;      // [index |-> offset-list]
 | 
			
		||||
    int_vector               m_le;           // recycled set of indices with lesser weights
 | 
			
		||||
    stats                    m_stats;
 | 
			
		||||
    svector<offset_t>&       m_found;
 | 
			
		||||
    offset_refs_t&           m_refs;
 | 
			
		||||
    unsigned                 m_cost;
 | 
			
		||||
    typedef int_hashtable<int_hash, default_eq<int> > int_table;
 | 
			
		||||
    hilbert_basis&     hb;
 | 
			
		||||
    int_table          m_table;
 | 
			
		||||
    stats              m_stats;
 | 
			
		||||
 | 
			
		||||
    unsigned get_value(numeral const& w) {
 | 
			
		||||
        numeral r = abs(w);
 | 
			
		||||
        unsigned val;
 | 
			
		||||
        if (!m_heap.is_declared(r, val)) {
 | 
			
		||||
            val = m_heap.declare(r);
 | 
			
		||||
            SASSERT(val == m_offsets.size());
 | 
			
		||||
            if (r.is_nonneg()) {
 | 
			
		||||
                m_heap.insert(val);
 | 
			
		||||
            }
 | 
			
		||||
            m_offsets.push_back(unsigned_vector());
 | 
			
		||||
        }
 | 
			
		||||
        return val;
 | 
			
		||||
    }
 | 
			
		||||
public:
 | 
			
		||||
    weight_map(svector<offset_t>& found, offset_refs_t& refs): m_found(found), m_refs(refs) {}
 | 
			
		||||
    
 | 
			
		||||
    void insert(offset_t idx, numeral const& w) {
 | 
			
		||||
        unsigned val = get_value(w);
 | 
			
		||||
        m_offsets[val].push_back(idx.m_offset);
 | 
			
		||||
    value_index(hilbert_basis& hb):
 | 
			
		||||
        hb(hb)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    void insert(offset_t idx, values const& vs) {
 | 
			
		||||
        m_table.insert(idx.m_offset);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void remove(offset_t idx, numeral const& w) {
 | 
			
		||||
        unsigned val = get_value(w);
 | 
			
		||||
        m_offsets[val].erase(idx.m_offset);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned get_size() const {
 | 
			
		||||
        unsigned sz = 0;
 | 
			
		||||
        for (unsigned i = 0; i < m_offsets.size(); ++i) {
 | 
			
		||||
            sz += m_offsets[i].size();
 | 
			
		||||
        }
 | 
			
		||||
        return sz;
 | 
			
		||||
    void remove(offset_t idx, values const& vs) {
 | 
			
		||||
        m_table.remove(idx.m_offset);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void reset() {
 | 
			
		||||
        m_offsets.reset();
 | 
			
		||||
        m_heap.reset();
 | 
			
		||||
        m_le.reset();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    unsigned get_cost() const { return m_cost; }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       retrieve 
 | 
			
		||||
     */
 | 
			
		||||
    bool init_find(numeral const& w, offset_t idx) {
 | 
			
		||||
        m_le.reset();
 | 
			
		||||
        m_found.reset();
 | 
			
		||||
        m_cost = 0;
 | 
			
		||||
        unsigned val = get_value(w);
 | 
			
		||||
        // for positive values, the weights should be less or equal.
 | 
			
		||||
        // for non-positive values, the weights have to be the same.
 | 
			
		||||
        if (w.is_pos()) {
 | 
			
		||||
            m_heap.find_le(val, m_le);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            m_le.push_back(val);
 | 
			
		||||
        }
 | 
			
		||||
        for (unsigned i = 0; i < m_le.size(); ++i) {
 | 
			
		||||
            if (m_heap.u2r()[m_le[i]].is_zero() && !w.is_zero()) {
 | 
			
		||||
                continue;
 | 
			
		||||
            } 
 | 
			
		||||
            unsigned_vector const& offsets = m_offsets[m_le[i]];
 | 
			
		||||
            for (unsigned j = 0; j < offsets.size(); ++j) {
 | 
			
		||||
                unsigned offs = offsets[j];
 | 
			
		||||
                ++m_stats.m_num_comparisons;
 | 
			
		||||
                ++m_cost;
 | 
			
		||||
                if (offs != idx.m_offset) {
 | 
			
		||||
                    m_refs.insert(offs, 0);
 | 
			
		||||
                    m_found.push_back(offset_t(offs));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return !m_found.empty();
 | 
			
		||||
        m_table.reset();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned get_find_cost(numeral const& w) {
 | 
			
		||||
        m_le.reset();
 | 
			
		||||
        unsigned cost = 0;
 | 
			
		||||
        unsigned val = get_value(w);
 | 
			
		||||
        m_heap.find_le(val, m_le);
 | 
			
		||||
        for (unsigned i = 0; i < m_le.size(); ++i) {
 | 
			
		||||
            cost += m_offsets[m_le[i]].size();
 | 
			
		||||
        }
 | 
			
		||||
        return cost;        
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    bool update_find(unsigned round, numeral const& w, offset_t idx) {
 | 
			
		||||
        m_found.reset();
 | 
			
		||||
        m_le.reset();
 | 
			
		||||
        m_cost = 0;
 | 
			
		||||
        unsigned vl = get_value(w);
 | 
			
		||||
        m_heap.find_le(vl, m_le);
 | 
			
		||||
        for (unsigned i = 0; i < m_le.size(); ++i) {
 | 
			
		||||
            unsigned_vector const& offsets = m_offsets[m_le[i]];
 | 
			
		||||
            for (unsigned j = 0; j < offsets.size(); ++j) {
 | 
			
		||||
                unsigned offs = offsets[j];
 | 
			
		||||
                ++m_stats.m_num_comparisons;
 | 
			
		||||
                ++m_cost;
 | 
			
		||||
                if (offs != idx.m_offset && m_refs.find(offs, vl) && vl == round) {
 | 
			
		||||
                    m_refs.insert(offs, round + 1);
 | 
			
		||||
                    m_found.push_back(offset_t(offs));
 | 
			
		||||
                }
 | 
			
		||||
    bool find(offset_t idx, values const& vs, offset_t& found_idx) {
 | 
			
		||||
        // display_profile(idx, std::cout);
 | 
			
		||||
        int_table::iterator it = m_table.begin(), end = m_table.end();
 | 
			
		||||
        for (; it != end; ++it) {
 | 
			
		||||
            offset_t offs(*it);
 | 
			
		||||
            ++m_stats.m_num_comparisons;
 | 
			
		||||
            if (*it != idx.m_offset && hb.is_subsumed(idx, offs)) {
 | 
			
		||||
                found_idx = offs;
 | 
			
		||||
                ++m_stats.m_num_hit;
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return !m_found.empty();
 | 
			
		||||
    }    
 | 
			
		||||
        ++m_stats.m_num_miss;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void collect_statistics(statistics& st) const {
 | 
			
		||||
        st.update("hb.index.num_comparisons", m_stats.m_num_comparisons);
 | 
			
		||||
        st.update("hb.index.num_hit", m_stats.m_num_hit);
 | 
			
		||||
        st.update("hb.index.num_miss", m_stats.m_num_miss);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void reset_statistics() {
 | 
			
		||||
        m_stats.reset();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned size() const {
 | 
			
		||||
        return m_table.size();
 | 
			
		||||
    }
 | 
			
		||||
private:
 | 
			
		||||
    void display_profile(offset_t idx, std::ostream& out) {
 | 
			
		||||
        unsigned_vector leq;
 | 
			
		||||
        unsigned nv = hb.get_num_vars();
 | 
			
		||||
        values const& vs = hb.vec(idx);
 | 
			
		||||
        leq.resize(nv+1);
 | 
			
		||||
        numeral maxw(0);
 | 
			
		||||
        for (unsigned i = 0; i < nv; ++i) {
 | 
			
		||||
            if (!hb.is_abs_geq(maxw, vs[i])) {
 | 
			
		||||
                maxw = vs[i];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        unsigned num_below_max = 0;
 | 
			
		||||
        int_table::iterator it = m_table.begin(), end = m_table.end();
 | 
			
		||||
        for (; it != end; ++it) {
 | 
			
		||||
            offset_t offs(*it);
 | 
			
		||||
            values const& ws = hb.vec(offs);
 | 
			
		||||
            if (ws.weight() <= vs.weight()) {
 | 
			
		||||
                leq[0]++;
 | 
			
		||||
            }
 | 
			
		||||
            bool filtered = false;
 | 
			
		||||
            for (unsigned i = 0; i < nv; ++i) {
 | 
			
		||||
                if (hb.is_abs_geq(vs[i], ws[i])) {
 | 
			
		||||
                    leq[i+1]++;
 | 
			
		||||
                }
 | 
			
		||||
                if (!hb.is_abs_geq(maxw, ws[i])) {
 | 
			
		||||
                    filtered = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (!filtered) {
 | 
			
		||||
                ++num_below_max;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        out << vs.weight() << ":" << leq[0] << " ";
 | 
			
		||||
        for (unsigned i = 0; i < nv; ++i) {
 | 
			
		||||
            out << vs[i] << ":" << leq[i+1] << " ";
 | 
			
		||||
        }
 | 
			
		||||
        out << " max<= " << num_below_max;
 | 
			
		||||
        out << "\n";
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class hilbert_basis::index {
 | 
			
		||||
    // for each index, a heap of weights.
 | 
			
		||||
    // for each weight a list of offsets
 | 
			
		||||
    // for each non-positive weight a separate index.
 | 
			
		||||
    // for positive weights a shared value index.
 | 
			
		||||
 | 
			
		||||
    struct stats {
 | 
			
		||||
        unsigned m_num_comparisons;
 | 
			
		||||
        unsigned m_num_find;
 | 
			
		||||
        unsigned m_num_insert;
 | 
			
		||||
        stats() { reset(); }
 | 
			
		||||
        void reset() { memset(this, 0, sizeof(*this)); }
 | 
			
		||||
    };    
 | 
			
		||||
    
 | 
			
		||||
    hilbert_basis&     hb;
 | 
			
		||||
    offset_refs_t      m_refs;
 | 
			
		||||
    svector<offset_t>  m_found;
 | 
			
		||||
    ptr_vector<weight_map> m_values;
 | 
			
		||||
    weight_map         m_weight;
 | 
			
		||||
    stats              m_stats;
 | 
			
		||||
    typedef rational_map<value_index*> value_map;
 | 
			
		||||
    hilbert_basis&   hb;
 | 
			
		||||
    value_map        m_neg;
 | 
			
		||||
    value_index      m_pos;
 | 
			
		||||
    value_index      m_zero;
 | 
			
		||||
    stats            m_stats;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    index(hilbert_basis& hb): hb(hb), m_weight(m_found, m_refs) {}
 | 
			
		||||
 | 
			
		||||
    ~index() {
 | 
			
		||||
        for (unsigned i = 0; i < m_values.size(); ++i) {
 | 
			
		||||
            dealloc(m_values[i]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void init(unsigned num_vars) {
 | 
			
		||||
        if (m_values.empty()) {
 | 
			
		||||
            for (unsigned i = 0; i < num_vars; ++i) {
 | 
			
		||||
                m_values.push_back(alloc(weight_map, m_found, m_refs));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(m_values.size() == num_vars);
 | 
			
		||||
    }
 | 
			
		||||
    index(hilbert_basis& hb): hb(hb), m_pos(hb), m_zero(hb) {}
 | 
			
		||||
    
 | 
			
		||||
    void insert(offset_t idx, values const& vs) {
 | 
			
		||||
        ++m_stats.m_num_insert;
 | 
			
		||||
#if 0
 | 
			
		||||
        for (unsigned i = 0; i < m_values.size(); ++i) {
 | 
			
		||||
            m_values[i]->insert(idx, vs[i]);
 | 
			
		||||
        if (vs.weight().is_pos()) {
 | 
			
		||||
            m_pos.insert(idx, vs);
 | 
			
		||||
        }
 | 
			
		||||
        else if (vs.weight().is_zero()) {
 | 
			
		||||
            m_zero.insert(idx, vs);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            value_index* map = 0;
 | 
			
		||||
            if (!m_neg.find(vs.weight(), map)) {
 | 
			
		||||
                map = alloc(value_index, hb);
 | 
			
		||||
                m_neg.insert(vs.weight(), map);
 | 
			
		||||
            }
 | 
			
		||||
            map->insert(idx, vs);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
        m_weight.insert(idx, vs.value());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void remove(offset_t idx, values const& vs) {
 | 
			
		||||
#if 0
 | 
			
		||||
        for (unsigned i = 0; i < m_values.size(); ++i) {
 | 
			
		||||
            m_values[i]->remove(idx, vs[i]);
 | 
			
		||||
        if (vs.weight().is_pos()) {
 | 
			
		||||
            m_pos.remove(idx, vs);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
        m_weight.remove(idx, vs.value());
 | 
			
		||||
        else if (vs.weight().is_zero()) {
 | 
			
		||||
            m_zero.remove(idx, vs);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            m_neg.find(vs.weight())->remove(idx, vs);
 | 
			
		||||
        }        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool find(values const& vs, offset_t idx, offset_t& found_idx) {
 | 
			
		||||
    bool find(offset_t idx, values const& vs, offset_t& found_idx) {
 | 
			
		||||
        ++m_stats.m_num_find;
 | 
			
		||||
        m_refs.reset();
 | 
			
		||||
        bool found = m_weight.init_find(vs.value(), idx);
 | 
			
		||||
        TRACE("hilbert_basis", tout << "init: " << m_found.size() << " cost: " << m_weight.get_cost() << "\n";);
 | 
			
		||||
#if 0
 | 
			
		||||
        std::cout << vs.value() << " " << m_found.size() << " ";
 | 
			
		||||
        for (unsigned i = 0; i < m_values.size(); ++i) {
 | 
			
		||||
            std::cout << vs[i] << ": " << m_values[i]->get_find_cost(vs[i]) << " ";
 | 
			
		||||
        if (vs.weight().is_pos()) {
 | 
			
		||||
            return m_pos.find(idx,  vs, found_idx); 
 | 
			
		||||
        }
 | 
			
		||||
        std::cout << "\n";
 | 
			
		||||
#endif
 | 
			
		||||
#if 0
 | 
			
		||||
        for (unsigned i = 0; found && i < m_values.size(); ++i) {
 | 
			
		||||
            found = m_values[i]->update_find(i, vs[i], idx);
 | 
			
		||||
            std::cout << vs[i] << ": " << m_found.size() << " ";
 | 
			
		||||
            TRACE("hilbert_basis", tout << "update " << i << ": " << m_found.size() << " cost: " << m_values[i]->get_cost() << "\n";);
 | 
			
		||||
        else if (vs.weight().is_zero()) {
 | 
			
		||||
            return m_zero.find(idx, vs, found_idx);
 | 
			
		||||
        }
 | 
			
		||||
#else
 | 
			
		||||
        for (unsigned i = 0; i < m_found.size(); ++i) {
 | 
			
		||||
            if (is_subsumed(idx, m_found[i])) {
 | 
			
		||||
                found_idx = m_found[i];
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
        if (found) {
 | 
			
		||||
            found_idx = m_found[0];
 | 
			
		||||
        }
 | 
			
		||||
        return found;
 | 
			
		||||
    }
 | 
			
		||||
        else {
 | 
			
		||||
            value_index* map;
 | 
			
		||||
            return
 | 
			
		||||
                m_neg.find(vs.weight(), map) && 
 | 
			
		||||
                map->find(idx, vs, found_idx);
 | 
			
		||||
        }        
 | 
			
		||||
    }    
 | 
			
		||||
 | 
			
		||||
    void reset() {
 | 
			
		||||
        for (unsigned i = 0; i < m_values.size(); ++i) {
 | 
			
		||||
            m_values[i]->reset();
 | 
			
		||||
        m_pos.reset();
 | 
			
		||||
        m_neg.reset();
 | 
			
		||||
        value_map::iterator it = m_neg.begin(), end = m_neg.end();
 | 
			
		||||
        for (; it != end; ++it) {
 | 
			
		||||
            it->m_value->reset();
 | 
			
		||||
        }
 | 
			
		||||
        m_weight.reset();
 | 
			
		||||
        m_refs.reset();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void collect_statistics(statistics& st) const {
 | 
			
		||||
        m_weight.collect_statistics(st);
 | 
			
		||||
        for (unsigned i = 0; i < m_values.size(); ++i) {
 | 
			
		||||
            m_values[i]->collect_statistics(st);
 | 
			
		||||
        }        
 | 
			
		||||
        st.update("hb.index.num_find", m_stats.m_num_find);
 | 
			
		||||
        m_pos.collect_statistics(st);
 | 
			
		||||
        m_zero.collect_statistics(st);
 | 
			
		||||
        value_map::iterator it = m_neg.begin(), end = m_neg.end();
 | 
			
		||||
        for (; it != end; ++it) {
 | 
			
		||||
            it->m_value->collect_statistics(st);
 | 
			
		||||
        }
 | 
			
		||||
        st.update("hb.index.num_find",   m_stats.m_num_find);
 | 
			
		||||
        st.update("hb.index.num_insert", m_stats.m_num_insert);
 | 
			
		||||
        st.update("hb.index.size", m_weight.get_size());
 | 
			
		||||
        st.update("hb.index.size",       size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void reset_statistics() {
 | 
			
		||||
        m_stats.reset();
 | 
			
		||||
        m_weight.reset_statistics();
 | 
			
		||||
        for (unsigned i = 0; i < m_values.size(); ++i) {
 | 
			
		||||
            m_values[i]->reset_statistics();
 | 
			
		||||
        }        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
       Vector v is subsumed by vector w if
 | 
			
		||||
       
 | 
			
		||||
       v[i] >= w[i] for each index i.
 | 
			
		||||
       
 | 
			
		||||
       a*v >= a*w  for the evaluation of vectors with respect to a.
 | 
			
		||||
       
 | 
			
		||||
       a*v < 0 => a*v = a*w
 | 
			
		||||
       
 | 
			
		||||
 | 
			
		||||
       Justification:
 | 
			
		||||
       
 | 
			
		||||
       let u := v - w, then
 | 
			
		||||
       
 | 
			
		||||
       u[i] >= 0  for each index i
 | 
			
		||||
       
 | 
			
		||||
       a*u = a*(v-w) >= 0
 | 
			
		||||
       
 | 
			
		||||
       So v = u + w, where a*u >= 0, a*w >= 0.
 | 
			
		||||
       
 | 
			
		||||
       If a*v >= a*w >= 0 then v and w are linear 
 | 
			
		||||
       solutions of e_i, and also v-w is a solution.
 | 
			
		||||
 | 
			
		||||
       If a*v = a*w < 0, then a*(v-w) = 0, so v can be obtained from w + (v - w).
 | 
			
		||||
       
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    bool is_subsumed(offset_t i, offset_t j) const {
 | 
			
		||||
        values v = hb.vec(i);
 | 
			
		||||
        values w = hb.vec(j);
 | 
			
		||||
        numeral const& n = v.value();
 | 
			
		||||
        numeral const& m = w.value();
 | 
			
		||||
        bool r = 
 | 
			
		||||
            i.m_offset != j.m_offset &&         
 | 
			
		||||
            n >= m && (!m.is_neg() || n == m) &&
 | 
			
		||||
            is_geq(v, w);
 | 
			
		||||
        CTRACE("hilbert_basis", r, 
 | 
			
		||||
               hb.display(tout, i);
 | 
			
		||||
               tout << " <= \n";
 | 
			
		||||
               hb.display(tout, j);
 | 
			
		||||
               tout << "\n";);
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_geq(values v, values w) const {
 | 
			
		||||
        unsigned nv = hb.get_num_vars();
 | 
			
		||||
        for (unsigned i = 0; i < nv; ++i) {
 | 
			
		||||
            if (v[i] < w[i]) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        m_pos.reset_statistics();
 | 
			
		||||
        m_zero.reset_statistics();
 | 
			
		||||
        value_map::iterator it = m_neg.begin(), end = m_neg.end();
 | 
			
		||||
        for (; it != end; ++it) {
 | 
			
		||||
            it->m_value->reset_statistics();
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
    unsigned size() const {
 | 
			
		||||
        unsigned sz = m_pos.size();
 | 
			
		||||
        sz += m_zero.size();
 | 
			
		||||
        value_map::iterator it = m_neg.begin(), end = m_neg.end();
 | 
			
		||||
        for (; it != end; ++it) {
 | 
			
		||||
            sz += it->m_value->size();
 | 
			
		||||
        }        
 | 
			
		||||
        return sz;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			@ -391,18 +246,25 @@ public:
 | 
			
		|||
*/
 | 
			
		||||
 | 
			
		||||
class hilbert_basis::passive {
 | 
			
		||||
    struct lt {
 | 
			
		||||
        passive& p;
 | 
			
		||||
        lt(passive& p): p(p) {}
 | 
			
		||||
 | 
			
		||||
        bool operator()(int v1, int v2) const {
 | 
			
		||||
            return p(v1, v2);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    hilbert_basis&         hb;
 | 
			
		||||
    svector<offset_t>      m_passive;
 | 
			
		||||
    vector<numeral>        m_weights;
 | 
			
		||||
    unsigned_vector        m_free_list;
 | 
			
		||||
    rational_abs_lt        m_lt;      // less_than on indices
 | 
			
		||||
    heap<rational_abs_lt>  m_heap;    // binary heap over weights
 | 
			
		||||
    lt                     m_lt;
 | 
			
		||||
    heap<lt>               m_heap;    // binary heap over weights
 | 
			
		||||
 | 
			
		||||
    numeral get_weight(offset_t idx) {
 | 
			
		||||
    numeral get_value(offset_t idx) const {
 | 
			
		||||
        numeral w(0);
 | 
			
		||||
        unsigned nv = hb.get_num_vars();
 | 
			
		||||
        for (unsigned i = 0; i < nv; ++i) {
 | 
			
		||||
            w += hb.vec(idx)[i];
 | 
			
		||||
            w += abs(hb.vec(idx)[i]);
 | 
			
		||||
        }
 | 
			
		||||
        return w;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -411,14 +273,13 @@ public:
 | 
			
		|||
    
 | 
			
		||||
    passive(hilbert_basis& hb): 
 | 
			
		||||
        hb(hb) ,
 | 
			
		||||
        m_lt(m_weights),
 | 
			
		||||
        m_lt(*this),
 | 
			
		||||
        m_heap(10, m_lt)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    void reset() {
 | 
			
		||||
        m_heap.reset();
 | 
			
		||||
        m_free_list.reset();
 | 
			
		||||
        m_weights.reset();
 | 
			
		||||
        m_passive.reset();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -440,14 +301,12 @@ public:
 | 
			
		|||
        if (m_free_list.empty()) {
 | 
			
		||||
            v = m_passive.size();
 | 
			
		||||
            m_passive.push_back(idx);
 | 
			
		||||
            m_weights.push_back(get_weight(idx));
 | 
			
		||||
            m_heap.set_bounds(v+1);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            v = m_free_list.back();
 | 
			
		||||
            m_free_list.pop_back();
 | 
			
		||||
            m_passive[v] = idx;
 | 
			
		||||
            m_weights[v] = get_weight(idx);
 | 
			
		||||
        }
 | 
			
		||||
        m_heap.insert(v);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -478,6 +337,43 @@ public:
 | 
			
		|||
    iterator end() {
 | 
			
		||||
        return iterator(*this, m_passive.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    /**
 | 
			
		||||
       Prefer positive weights to negative.
 | 
			
		||||
       If both weights are positive, prefer the smallest weight.
 | 
			
		||||
       If weights are the same, prefer the one that has smallest sum of values.
 | 
			
		||||
     */
 | 
			
		||||
    bool operator()(int v1, int v2) const {
 | 
			
		||||
        offset_t idx1 = m_passive[v1];
 | 
			
		||||
        offset_t idx2 = m_passive[v2];
 | 
			
		||||
        return get_value(idx1) < get_value(idx2);
 | 
			
		||||
#if 0
 | 
			
		||||
        values const& vec1 = hb.vec(idx1);
 | 
			
		||||
        values const& vec2 = hb.vec(idx2);
 | 
			
		||||
        numeral const& w1 = vec1.weight();
 | 
			
		||||
        numeral const& w2 = vec2.weight();
 | 
			
		||||
        SASSERT(!w1.is_zero());
 | 
			
		||||
        SASSERT(!w2.is_zero());
 | 
			
		||||
 | 
			
		||||
        if (w1.is_pos()) {
 | 
			
		||||
            if (w2.is_neg()) {
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            if (w1 != w2) {
 | 
			
		||||
                return w1 < w2;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            if (w2.is_pos()) {
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(w1 == w2);
 | 
			
		||||
        return get_value(idx1) < get_value(idx2);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
hilbert_basis::hilbert_basis(): 
 | 
			
		||||
| 
						 | 
				
			
			@ -529,9 +425,6 @@ void hilbert_basis::add_ge(num_vector const& v, numeral const& b) {
 | 
			
		|||
    num_vector w;
 | 
			
		||||
    w.push_back(-b);
 | 
			
		||||
    w.append(v);
 | 
			
		||||
    if (m_ineqs.empty()) {
 | 
			
		||||
        m_index->init(w.size());
 | 
			
		||||
    }
 | 
			
		||||
    m_ineqs.push_back(w);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -561,6 +454,14 @@ void hilbert_basis::add_eq(num_vector const& v) {
 | 
			
		|||
    add_ge(v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hilbert_basis::set_is_int(unsigned var_index) {
 | 
			
		||||
    //
 | 
			
		||||
    // The 0't index is reserved for the constant
 | 
			
		||||
    // coefficient. Shift indices by 1.
 | 
			
		||||
    //
 | 
			
		||||
    m_ints.push_back(var_index+1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned hilbert_basis::get_num_vars() const {
 | 
			
		||||
    if (m_ineqs.empty()) {
 | 
			
		||||
        return 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -580,26 +481,34 @@ void hilbert_basis::init_basis() {
 | 
			
		|||
    m_free_list.reset();
 | 
			
		||||
    unsigned num_vars = get_num_vars();
 | 
			
		||||
    for (unsigned i = 0; i < num_vars; ++i) {
 | 
			
		||||
        num_vector w(num_vars, numeral(0));
 | 
			
		||||
        w[i] = numeral(1);
 | 
			
		||||
        offset_t idx = alloc_vector();
 | 
			
		||||
        values v = vec(idx);
 | 
			
		||||
        for (unsigned i = 0; i < num_vars; ++i) {
 | 
			
		||||
            v[i] = w[i];
 | 
			
		||||
        }
 | 
			
		||||
        m_basis.push_back(idx);
 | 
			
		||||
        add_unit_vector(i, numeral(1));
 | 
			
		||||
    }
 | 
			
		||||
    for (unsigned i = 0; i < m_ints.size(); ++i) {
 | 
			
		||||
        add_unit_vector(m_ints[i], numeral(-1));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
void hilbert_basis::add_unit_vector(unsigned i, numeral const& e) {
 | 
			
		||||
    unsigned num_vars = get_num_vars();
 | 
			
		||||
    num_vector w(num_vars, numeral(0));
 | 
			
		||||
    w[i] = e;
 | 
			
		||||
    offset_t idx = alloc_vector();
 | 
			
		||||
    values v = vec(idx);
 | 
			
		||||
    for (unsigned j = 0; j < num_vars; ++j) {
 | 
			
		||||
        v[j] = w[j];
 | 
			
		||||
    }
 | 
			
		||||
    m_basis.push_back(idx);            
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
lbool hilbert_basis::saturate() {
 | 
			
		||||
    init_basis();    
 | 
			
		||||
    init_basis();        
 | 
			
		||||
    for (unsigned i = 0; !m_cancel && i < m_ineqs.size(); ++i) {
 | 
			
		||||
        select_inequality(i);
 | 
			
		||||
        lbool r = saturate(m_ineqs[i]);
 | 
			
		||||
        ++m_stats.m_num_saturations;
 | 
			
		||||
        if (r != l_true) {
 | 
			
		||||
            return r;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        }        
 | 
			
		||||
    }
 | 
			
		||||
    if (m_cancel) {
 | 
			
		||||
        return l_undef;
 | 
			
		||||
| 
						 | 
				
			
			@ -619,7 +528,7 @@ lbool hilbert_basis::saturate(num_vector const& ineq) {
 | 
			
		|||
        values v = vec(*it);
 | 
			
		||||
        set_eval(v, ineq);
 | 
			
		||||
        add_goal(*it);
 | 
			
		||||
        if (v.value().is_nonneg()) {
 | 
			
		||||
        if (v.weight().is_nonneg()) {
 | 
			
		||||
            has_non_negative = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -652,7 +561,7 @@ lbool hilbert_basis::saturate(num_vector const& ineq) {
 | 
			
		|||
    m_basis.append(m_zero);
 | 
			
		||||
    for (unsigned i = 0; i < m_active.size(); ++i) {
 | 
			
		||||
        offset_t idx = m_active[i];
 | 
			
		||||
        if (vec(idx).value().is_pos()) {
 | 
			
		||||
        if (vec(idx).weight().is_pos()) {
 | 
			
		||||
            m_basis.push_back(idx);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
| 
						 | 
				
			
			@ -666,6 +575,51 @@ lbool hilbert_basis::saturate(num_vector const& ineq) {
 | 
			
		|||
    return l_true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hilbert_basis::select_inequality(unsigned i) {
 | 
			
		||||
    SASSERT(i < m_ineqs.size());
 | 
			
		||||
    unsigned best = i;
 | 
			
		||||
    unsigned non_zeros = get_num_nonzeros(m_ineqs[i]);
 | 
			
		||||
    unsigned prod      = get_ineq_product(m_ineqs[i]);
 | 
			
		||||
    for (unsigned j = i+1; prod != 0 && j < m_ineqs.size(); ++j) {
 | 
			
		||||
        unsigned non_zeros2 = get_num_nonzeros(m_ineqs[j]);
 | 
			
		||||
        unsigned prod2 = get_ineq_product(m_ineqs[j]);
 | 
			
		||||
        if (prod2 < prod || (prod2 == prod && non_zeros2 < non_zeros)) {
 | 
			
		||||
            prod = prod2;
 | 
			
		||||
            non_zeros = non_zeros2;
 | 
			
		||||
            best = j;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (best != i) {
 | 
			
		||||
        std::swap(m_ineqs[i], m_ineqs[best]);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned hilbert_basis::get_num_nonzeros(num_vector const& ineq) {
 | 
			
		||||
    unsigned count = 0;
 | 
			
		||||
    for (unsigned i = 0; i < ineq.size(); ++i) {
 | 
			
		||||
        if (!ineq[i].is_zero()) {
 | 
			
		||||
            ++count;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned hilbert_basis::get_ineq_product(num_vector const& ineq) {
 | 
			
		||||
    unsigned num_pos = 0, num_neg = 0;
 | 
			
		||||
    iterator it = begin();
 | 
			
		||||
    for (; it != end(); ++it) {
 | 
			
		||||
        values v = vec(*it);
 | 
			
		||||
        set_eval(v, ineq);
 | 
			
		||||
        if (v.weight().is_pos()) {
 | 
			
		||||
            ++num_pos;
 | 
			
		||||
        }
 | 
			
		||||
        else if (v.weight().is_neg()) {
 | 
			
		||||
            ++num_neg;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return num_pos * num_neg;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hilbert_basis::recycle(offset_t idx) {
 | 
			
		||||
    m_index->remove(idx, vec(idx));
 | 
			
		||||
    m_free_list.push_back(idx);
 | 
			
		||||
| 
						 | 
				
			
			@ -680,8 +634,8 @@ void hilbert_basis::resolve(offset_t i, offset_t j, offset_t r) {
 | 
			
		|||
    for (unsigned k = 0; k < nv; ++k) {
 | 
			
		||||
        u[k] = v[k] + w[k];
 | 
			
		||||
    }
 | 
			
		||||
    u.value() = v.value() + w.value();
 | 
			
		||||
    // std::cout << "resolve: " << v.value() << " + " << w.value() << " = " << u.value() << "\n";
 | 
			
		||||
    u.weight() = v.weight() + w.weight();
 | 
			
		||||
    // std::cout << "resolve: " << v.weight() << " + " << w.weight() << " = " << u.weight() << "\n";
 | 
			
		||||
    TRACE("hilbert_basis_verbose",
 | 
			
		||||
          display(tout, i); 
 | 
			
		||||
          display(tout, j); 
 | 
			
		||||
| 
						 | 
				
			
			@ -694,7 +648,7 @@ hilbert_basis::offset_t hilbert_basis::alloc_vector() {
 | 
			
		|||
    if (m_free_list.empty()) {
 | 
			
		||||
        unsigned num_vars = get_num_vars();
 | 
			
		||||
        unsigned idx =  m_store.size();
 | 
			
		||||
        m_store.resize(idx + 1 + get_num_vars());
 | 
			
		||||
        m_store.resize(idx + 1 + num_vars);
 | 
			
		||||
        return offset_t(idx);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
| 
						 | 
				
			
			@ -710,7 +664,7 @@ void hilbert_basis::add_goal(offset_t idx) {
 | 
			
		|||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    m_index->insert(idx, v);
 | 
			
		||||
    if (v.value().is_zero()) {
 | 
			
		||||
    if (v.weight().is_zero()) {
 | 
			
		||||
        m_zero.push_back(idx);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
| 
						 | 
				
			
			@ -721,12 +675,7 @@ void hilbert_basis::add_goal(offset_t idx) {
 | 
			
		|||
bool hilbert_basis::is_subsumed(offset_t idx)  {
 | 
			
		||||
 | 
			
		||||
    offset_t found_idx;
 | 
			
		||||
    if (m_index->find(vec(idx), idx, found_idx)) {        
 | 
			
		||||
        TRACE("hilbert_basis",  
 | 
			
		||||
           display(tout, idx);
 | 
			
		||||
           tout << " <= \n";
 | 
			
		||||
           display(tout, found_idx);
 | 
			
		||||
           tout << "\n";);
 | 
			
		||||
    if (m_index->find(idx, vec(idx), found_idx)) {        
 | 
			
		||||
        ++m_stats.m_num_subsumptions;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -734,13 +683,30 @@ bool hilbert_basis::is_subsumed(offset_t idx)  {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
bool hilbert_basis::can_resolve(offset_t i, offset_t j) const {
 | 
			
		||||
    sign_t s1 = get_sign(i);
 | 
			
		||||
    sign_t s2 = get_sign(j);
 | 
			
		||||
    return s1 != s2 && abs(vec(i)[0] + vec(j)[0]) <= numeral(1);
 | 
			
		||||
    if (get_sign(i) == get_sign(j)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    values const& v1 = vec(i);
 | 
			
		||||
    values const& v2 = vec(j);
 | 
			
		||||
    // index 0 is reserved for the constant coefficient. 
 | 
			
		||||
    // The value of it should either be 0 or 1.
 | 
			
		||||
    if (abs(v1[0] + v2[0]) > numeral(1)) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    for (unsigned i = 0; i < m_ints.size(); ++i) {
 | 
			
		||||
        unsigned j = m_ints[i];
 | 
			
		||||
        if (v1[j].is_pos() && v2[j].is_neg()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (v1[j].is_neg() && v2[j].is_pos()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
hilbert_basis::sign_t hilbert_basis::get_sign(offset_t idx) const {
 | 
			
		||||
    numeral val = vec(idx).value();
 | 
			
		||||
    numeral val = vec(idx).weight();
 | 
			
		||||
    if (val.is_pos()) {
 | 
			
		||||
        return pos;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -756,7 +722,7 @@ void hilbert_basis::set_eval(values& val, num_vector const& ineq) const {
 | 
			
		|||
    for (unsigned i = 0; i < num_vars; ++i) {
 | 
			
		||||
        result += val[i]*ineq[i];
 | 
			
		||||
    }
 | 
			
		||||
    val.value() = result;
 | 
			
		||||
    val.weight() = result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hilbert_basis::display(std::ostream& out) const {
 | 
			
		||||
| 
						 | 
				
			
			@ -796,7 +762,7 @@ void hilbert_basis::display(std::ostream& out) const {
 | 
			
		|||
 | 
			
		||||
void hilbert_basis::display(std::ostream& out, offset_t o) const {
 | 
			
		||||
    display(out, vec(o));
 | 
			
		||||
    out << " -> " << vec(o).value() << "\n";    
 | 
			
		||||
    out << " -> " << vec(o).weight() << "\n";    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hilbert_basis::display(std::ostream& out, values const& v) const {
 | 
			
		||||
| 
						 | 
				
			
			@ -842,3 +808,68 @@ void hilbert_isl_basis::add_le(num_vector const& v, numeral bound) {
 | 
			
		|||
    }
 | 
			
		||||
    m_basis.add_le(w);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
   Vector v is subsumed by vector w if
 | 
			
		||||
       
 | 
			
		||||
       v[i] >= w[i] for each index i.
 | 
			
		||||
       
 | 
			
		||||
       a*v >= a*w  for the evaluation of vectors with respect to a.
 | 
			
		||||
       
 | 
			
		||||
       . a*v < 0 => a*v = a*w
 | 
			
		||||
       . a*v > 0 => a*w > 0
 | 
			
		||||
       . a*v = 0 => a*w = 0
 | 
			
		||||
 | 
			
		||||
   Justification:
 | 
			
		||||
       
 | 
			
		||||
       let u := v - w, then
 | 
			
		||||
       
 | 
			
		||||
       u[i] >= 0  for each index i
 | 
			
		||||
       
 | 
			
		||||
       a*u = a*(v-w) >= 0
 | 
			
		||||
       
 | 
			
		||||
       So v = u + w, where a*u >= 0, a*w >= 0.
 | 
			
		||||
       
 | 
			
		||||
       If a*v >= a*w >= 0 then v and w are linear 
 | 
			
		||||
       solutions of e_i, and also v-w is a solution.
 | 
			
		||||
 | 
			
		||||
       If a*v = a*w < 0, then a*(v-w) = 0, so v can be obtained from w + (v - w).
 | 
			
		||||
       
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
bool hilbert_basis::is_subsumed(offset_t i, offset_t j) const {
 | 
			
		||||
    values v = vec(i);
 | 
			
		||||
    values w = vec(j);
 | 
			
		||||
    numeral const& n = v.weight();
 | 
			
		||||
    numeral const& m = w.weight();
 | 
			
		||||
    bool r = 
 | 
			
		||||
        i.m_offset != j.m_offset &&         
 | 
			
		||||
        n >= m && (!m.is_nonpos() || n == m) &&
 | 
			
		||||
        is_geq(v, w);
 | 
			
		||||
    CTRACE("hilbert_basis", r, 
 | 
			
		||||
           display(tout, i);
 | 
			
		||||
           tout << " <= \n";
 | 
			
		||||
           display(tout, j);
 | 
			
		||||
           tout << "\n";);
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool hilbert_basis::is_geq(values const& v, values const& w) const {
 | 
			
		||||
    unsigned nv = get_num_vars();
 | 
			
		||||
    for (unsigned i = 0; i < nv; ++i) {
 | 
			
		||||
        if (!is_abs_geq(v[i], w[i])) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool hilbert_basis::is_abs_geq(numeral const& v, numeral const& w) const {
 | 
			
		||||
    if (w.is_neg()) {
 | 
			
		||||
        return v <= w;
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        return v >= w;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,10 +34,9 @@ public:
 | 
			
		|||
    typedef rational numeral;
 | 
			
		||||
    typedef vector<numeral> num_vector;
 | 
			
		||||
private:
 | 
			
		||||
    class rational_heap;
 | 
			
		||||
    class value_index;
 | 
			
		||||
    class index;
 | 
			
		||||
    class passive;
 | 
			
		||||
    class weight_map;
 | 
			
		||||
    struct offset_t { 
 | 
			
		||||
        unsigned m_offset; 
 | 
			
		||||
        offset_t(unsigned o) : m_offset(o) {} 
 | 
			
		||||
| 
						 | 
				
			
			@ -58,25 +57,26 @@ private:
 | 
			
		|||
        numeral* m_values;
 | 
			
		||||
    public:
 | 
			
		||||
        values(numeral* v):m_values(v) {}
 | 
			
		||||
        numeral& value() { return m_values[0]; } // value of a*x 
 | 
			
		||||
        numeral& weight() { return m_values[0]; } // value of a*x 
 | 
			
		||||
        numeral& operator[](unsigned i) { return m_values[i+1]; } // value of x_i
 | 
			
		||||
        numeral const& value() const { return m_values[0]; } // value of a*x 
 | 
			
		||||
        numeral const& weight() const { return m_values[0]; } // value of a*x 
 | 
			
		||||
        numeral const& operator[](unsigned i) const { return m_values[i+1]; } // value of x_i
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    vector<num_vector> m_ineqs;
 | 
			
		||||
    num_vector         m_store;
 | 
			
		||||
    svector<offset_t>  m_basis;
 | 
			
		||||
    svector<offset_t>  m_free_list;
 | 
			
		||||
    svector<offset_t>  m_active;
 | 
			
		||||
    svector<offset_t>  m_zero;
 | 
			
		||||
    volatile bool      m_cancel;
 | 
			
		||||
    vector<num_vector> m_ineqs;      // set of asserted inequalities
 | 
			
		||||
    num_vector         m_store;      // store of vectors
 | 
			
		||||
    svector<offset_t>  m_basis;      // vector of current basis
 | 
			
		||||
    svector<offset_t>  m_free_list;  // free list of unused storage
 | 
			
		||||
    svector<offset_t>  m_active;     // active set
 | 
			
		||||
    svector<offset_t>  m_zero;       // zeros
 | 
			
		||||
    passive*           m_passive;    // passive set
 | 
			
		||||
    volatile bool      m_cancel;     
 | 
			
		||||
    stats              m_stats;
 | 
			
		||||
    index*             m_index;
 | 
			
		||||
    passive*           m_passive;
 | 
			
		||||
    index*             m_index;      // index of generated vectors
 | 
			
		||||
    unsigned_vector    m_ints;       // indices that can be both positive and negative
 | 
			
		||||
    class iterator {
 | 
			
		||||
        hilbert_basis const& hb;
 | 
			
		||||
        unsigned   m_idx;
 | 
			
		||||
        unsigned             m_idx;
 | 
			
		||||
    public:
 | 
			
		||||
        iterator(hilbert_basis const& hb, unsigned idx): hb(hb), m_idx(idx) {}
 | 
			
		||||
        offset_t operator*() const { return hb.m_basis[m_idx]; }
 | 
			
		||||
| 
						 | 
				
			
			@ -90,8 +90,15 @@ private:
 | 
			
		|||
    static bool     is_invalid_offset(offset_t offs);
 | 
			
		||||
    lbool saturate(num_vector const& ineq);
 | 
			
		||||
    void init_basis();
 | 
			
		||||
    void select_inequality(unsigned i);
 | 
			
		||||
    unsigned get_num_nonzeros(num_vector const& ineq);
 | 
			
		||||
    unsigned get_ineq_product(num_vector const& ineq);
 | 
			
		||||
 | 
			
		||||
    void add_unit_vector(unsigned i, numeral const& e);
 | 
			
		||||
    unsigned get_num_vars() const;
 | 
			
		||||
    void set_eval(values& val, num_vector const& ineq) const;
 | 
			
		||||
    bool is_geq(values const& v, values const& w) const;
 | 
			
		||||
    bool is_abs_geq(numeral const& v, numeral const& w) const;
 | 
			
		||||
    bool is_subsumed(offset_t idx);
 | 
			
		||||
    bool is_subsumed(offset_t i, offset_t j) const;
 | 
			
		||||
    void recycle(offset_t idx);
 | 
			
		||||
| 
						 | 
				
			
			@ -130,6 +137,8 @@ public:
 | 
			
		|||
    void add_le(num_vector const& v, numeral const& b);
 | 
			
		||||
    void add_eq(num_vector const& v, numeral const& b);
 | 
			
		||||
 | 
			
		||||
    void set_is_int(unsigned var_index);
 | 
			
		||||
 | 
			
		||||
    lbool saturate();
 | 
			
		||||
 | 
			
		||||
    void set_cancel(bool f) { m_cancel = f; }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -245,23 +245,28 @@ static void tst11() {
 | 
			
		|||
 | 
			
		||||
void tst_hilbert_basis() {
 | 
			
		||||
    std::cout << "hilbert basis test\n";
 | 
			
		||||
#if 0
 | 
			
		||||
    tst1();
 | 
			
		||||
    tst2();
 | 
			
		||||
    tst3();
 | 
			
		||||
    tst4();
 | 
			
		||||
    tst5();
 | 
			
		||||
    tst6();
 | 
			
		||||
    tst7();
 | 
			
		||||
    tst8();
 | 
			
		||||
    tst9();
 | 
			
		||||
    tst10();
 | 
			
		||||
    tst11();
 | 
			
		||||
    gorrila_test(0, 4, 3, 20, 5);
 | 
			
		||||
    gorrila_test(1, 4, 3, 20, 5);
 | 
			
		||||
    gorrila_test(2, 4, 3, 20, 5);
 | 
			
		||||
    gorrila_test(0, 4, 2, 20, 5);
 | 
			
		||||
    gorrila_test(0, 4, 2, 20, 5);
 | 
			
		||||
#endif
 | 
			
		||||
    gorrila_test(0, 10, 7, 20, 11);
 | 
			
		||||
    return;
 | 
			
		||||
 | 
			
		||||
    if (true) {
 | 
			
		||||
        tst1();
 | 
			
		||||
        tst2();
 | 
			
		||||
        tst3();
 | 
			
		||||
        tst4();
 | 
			
		||||
        tst5();
 | 
			
		||||
        tst6();
 | 
			
		||||
        tst7();
 | 
			
		||||
        tst8();
 | 
			
		||||
        tst9();
 | 
			
		||||
        tst10();
 | 
			
		||||
        tst11();
 | 
			
		||||
        gorrila_test(0, 4, 3, 20, 5);
 | 
			
		||||
        gorrila_test(1, 4, 3, 20, 5);
 | 
			
		||||
        gorrila_test(2, 4, 3, 20, 5);
 | 
			
		||||
        gorrila_test(0, 4, 2, 20, 5);
 | 
			
		||||
        gorrila_test(0, 4, 2, 20, 5);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        gorrila_test(0, 10, 7, 20, 11);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue