mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-03 21:09:11 +00:00 
			
		
		
		
	Add array, model value, and user sort plugins to SLS module with enhancements in array propagation logic
This commit is contained in:
		
							parent
							
								
									f9ec6b45c4
								
							
						
					
					
						commit
						2f2559d670
					
				
					 8 changed files with 435 additions and 58 deletions
				
			
		| 
						 | 
				
			
			@ -15,6 +15,7 @@ z3_add_component(ast_sls
 | 
			
		|||
    sls_context.cpp
 | 
			
		||||
    sls_euf_plugin.cpp
 | 
			
		||||
    sls_smt_solver.cpp
 | 
			
		||||
    sls_user_sort_plugin.cpp
 | 
			
		||||
  COMPONENT_DEPENDENCIES
 | 
			
		||||
    ast
 | 
			
		||||
    euf
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,10 +16,11 @@ Author:
 | 
			
		|||
--*/
 | 
			
		||||
 | 
			
		||||
#include "ast/sls/sls_array_plugin.h"
 | 
			
		||||
#include "ast/ast_ll_pp.h"
 | 
			
		||||
#include "ast/ast_pp.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace sls {
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
    array_plugin::array_plugin(context& ctx):
 | 
			
		||||
        plugin(ctx),
 | 
			
		||||
| 
						 | 
				
			
			@ -28,12 +29,180 @@ namespace sls {
 | 
			
		|||
        m_fid = a.get_family_id();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    bool array_plugin::is_sat() {
 | 
			
		||||
        euf::egraph g(m);
 | 
			
		||||
        init_egraph(g);
 | 
			
		||||
        m_g = alloc(euf::egraph, m);
 | 
			
		||||
        m_kv = nullptr;
 | 
			
		||||
        init_egraph(*m_g);
 | 
			
		||||
        saturate_store(*m_g);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    // b ~ a[i -> v]
 | 
			
		||||
    // ensure b[i] ~ v
 | 
			
		||||
    // ensure b[j] ~ a[j] for j != i
 | 
			
		||||
 | 
			
		||||
    void array_plugin::saturate_store(euf::egraph& g) {
 | 
			
		||||
        unsigned sz = 0;
 | 
			
		||||
        while (sz < g.nodes().size()) {
 | 
			
		||||
            sz = g.nodes().size();
 | 
			
		||||
            for (unsigned i = 0; i < sz; ++i) {
 | 
			
		||||
                auto n = g.nodes()[i];
 | 
			
		||||
                if (!a.is_store(n->get_expr()))
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                force_store_axiom1(g, n);
 | 
			
		||||
 | 
			
		||||
                for (auto p : euf::enode_parents(n->get_root())) 
 | 
			
		||||
                    if (a.is_select(p->get_expr()))
 | 
			
		||||
                        force_store_axiom2_down(g, n, p);
 | 
			
		||||
                
 | 
			
		||||
                auto arr = n->get_arg(0);
 | 
			
		||||
                for (auto p : euf::enode_parents(arr->get_root())) 
 | 
			
		||||
                    if (a.is_select(p->get_expr()))
 | 
			
		||||
                        force_store_axiom2_up(g, n, p);                
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        display(verbose_stream() << "saturated\n");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    euf::enode* array_plugin::mk_select(euf::egraph& g, euf::enode* b, euf::enode* sel) {
 | 
			
		||||
        auto arity = get_array_arity(b->get_sort());
 | 
			
		||||
        ptr_buffer<expr> args;
 | 
			
		||||
        ptr_buffer<euf::enode> eargs;
 | 
			
		||||
        args.push_back(b->get_expr());
 | 
			
		||||
        eargs.push_back(b);
 | 
			
		||||
        for (unsigned i = 1; i <= arity; ++i) {
 | 
			
		||||
            auto idx = sel->get_arg(i);
 | 
			
		||||
            eargs.push_back(idx);
 | 
			
		||||
            args.push_back(idx->get_expr());
 | 
			
		||||
        }
 | 
			
		||||
        expr_ref esel(a.mk_select(args), m);
 | 
			
		||||
        auto n = g.find(esel);
 | 
			
		||||
        return n ? n : g.mk(esel, 0, eargs.size(), eargs.data());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // ensure a[i->v][i] = v exists in the e-graph
 | 
			
		||||
    void array_plugin::force_store_axiom1(euf::egraph& g, euf::enode* n) {
 | 
			
		||||
        SASSERT(a.is_store(n->get_expr()));
 | 
			
		||||
        auto val = n->get_arg(n->num_args() - 1);
 | 
			
		||||
        auto nsel = mk_select(g, n, n);
 | 
			
		||||
        if (are_distinct(nsel, val))
 | 
			
		||||
            add_store_axiom1(n->get_app());
 | 
			
		||||
        else 
 | 
			
		||||
            g.merge(nsel, val, nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // i /~ j, b ~ a[i->v], b[j] occurs -> a[j] = b[j] 
 | 
			
		||||
    void array_plugin::force_store_axiom2_down(euf::egraph& g, euf::enode* sto, euf::enode* sel) {
 | 
			
		||||
        SASSERT(a.is_store(sto->get_expr()));
 | 
			
		||||
        SASSERT(a.is_select(sel->get_expr()));
 | 
			
		||||
        if (sel->get_arg(0)->get_root() != sto->get_root())
 | 
			
		||||
            return;
 | 
			
		||||
        if (eq_args(sto, sel))
 | 
			
		||||
            return; 
 | 
			
		||||
        auto nsel = mk_select(g, sto->get_arg(0), sel);
 | 
			
		||||
        if (are_distinct(nsel, sel))
 | 
			
		||||
            add_store_axiom2(sto->get_app(), sel->get_app());
 | 
			
		||||
        else
 | 
			
		||||
            g.merge(nsel, sel, nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // a ~ b, i /~ j, b[j] occurs -> a[i -> v][j] = b[j] 
 | 
			
		||||
    void array_plugin::force_store_axiom2_up(euf::egraph& g, euf::enode* sto, euf::enode* sel) {
 | 
			
		||||
        SASSERT(a.is_store(sto->get_expr()));
 | 
			
		||||
        SASSERT(a.is_select(sel->get_expr()));
 | 
			
		||||
        if (sel->get_arg(0)->get_root() != sto->get_arg(0)->get_root())
 | 
			
		||||
            return;
 | 
			
		||||
        if (eq_args(sto, sel))
 | 
			
		||||
            return;
 | 
			
		||||
        auto nsel = mk_select(g, sto, sel);
 | 
			
		||||
        if (are_distinct(nsel, sel))
 | 
			
		||||
            add_store_axiom2(sto->get_app(), sel->get_app());
 | 
			
		||||
        else
 | 
			
		||||
            g.merge(nsel, sel, nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool array_plugin::are_distinct(euf::enode* a, euf::enode* b) {
 | 
			
		||||
        a = a->get_root();
 | 
			
		||||
        b = b->get_root();
 | 
			
		||||
        return a->interpreted() && b->interpreted() && a != b; // TODO work with nested arrays?
 | 
			
		||||
    }    
 | 
			
		||||
 | 
			
		||||
    bool array_plugin::eq_args(euf::enode* sto, euf::enode* sel) {
 | 
			
		||||
        SASSERT(a.is_store(sto->get_expr()));
 | 
			
		||||
        SASSERT(a.is_select(sel->get_expr()));
 | 
			
		||||
        unsigned arity = get_array_arity(sto->get_sort());
 | 
			
		||||
        for (unsigned i = 1; i < arity; ++i) {
 | 
			
		||||
            if (sto->get_arg(i)->get_root() != sel->get_arg(i)->get_root())
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void array_plugin::add_store_axiom1(app* sto) {
 | 
			
		||||
        if (!m_add_conflicts)
 | 
			
		||||
            return;
 | 
			
		||||
        ptr_vector<expr> args;
 | 
			
		||||
        args.push_back(sto);
 | 
			
		||||
        for (unsigned i = 1; i < sto->get_num_args() - 1; ++i)
 | 
			
		||||
            args.push_back(sto->get_arg(i));
 | 
			
		||||
        expr_ref sel(a.mk_select(args), m);
 | 
			
		||||
        expr_ref eq(m.mk_eq(sel, to_app(sto)->get_arg(sto->get_num_args() - 1)), m);
 | 
			
		||||
        verbose_stream() << "add store axiom 1 " << mk_bounded_pp(sto, m) << "\n";
 | 
			
		||||
        ctx.add_clause(eq);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void array_plugin::add_store_axiom2(app* sto, app* sel) {
 | 
			
		||||
        if (!m_add_conflicts)
 | 
			
		||||
            return;
 | 
			
		||||
        ptr_vector<expr> args1, args2;
 | 
			
		||||
        args1.push_back(sto);
 | 
			
		||||
        args2.push_back(sto->get_arg(0));
 | 
			
		||||
        for (unsigned i = 1; i < sel->get_num_args() - 1; ++i) {
 | 
			
		||||
            args1.push_back(sel->get_arg(i));
 | 
			
		||||
            args2.push_back(sel->get_arg(i));
 | 
			
		||||
        }
 | 
			
		||||
        expr_ref sel1(a.mk_select(args1), m);
 | 
			
		||||
        expr_ref sel2(a.mk_select(args2), m);
 | 
			
		||||
        expr_ref eq(m.mk_eq(sel1, sel2), m);
 | 
			
		||||
        expr_ref_vector ors(m);
 | 
			
		||||
        ors.push_back(eq);
 | 
			
		||||
        for (unsigned i = 1; i < sel->get_num_args() - 1; ++i) 
 | 
			
		||||
            ors.push_back(m.mk_eq(sel->get_arg(i), sto->get_arg(i)));     
 | 
			
		||||
        verbose_stream() << "add store axiom 2 " << mk_bounded_pp(sto, m) << " " << mk_bounded_pp(sel, m) << "\n";
 | 
			
		||||
        ctx.add_clause(m.mk_or(ors));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void array_plugin::init_egraph(euf::egraph& g) {
 | 
			
		||||
        ptr_vector<euf::enode> args;
 | 
			
		||||
        for (auto t : ctx.subterms()) {
 | 
			
		||||
            args.reset();
 | 
			
		||||
            if (is_app(t)) 
 | 
			
		||||
                for (auto* arg : *to_app(t)) 
 | 
			
		||||
                    args.push_back(g.find(arg));
 | 
			
		||||
                            
 | 
			
		||||
            euf::enode* n1, * n2;
 | 
			
		||||
            n1 = g.find(t);
 | 
			
		||||
            n1 = n1 ? n1 : g.mk(t, 0, args.size(), args.data());
 | 
			
		||||
            if (a.is_array(t))
 | 
			
		||||
                continue;
 | 
			
		||||
            auto v = ctx.get_value(t);
 | 
			
		||||
            verbose_stream() << "init " << mk_bounded_pp(t, m) << " := " << mk_bounded_pp(v, m) << "\n";
 | 
			
		||||
            n2 = g.find(v);
 | 
			
		||||
            n2 = n2 ? n2: g.mk(v, 0, 0, nullptr);
 | 
			
		||||
            g.merge(n1, n2, nullptr);
 | 
			
		||||
        }
 | 
			
		||||
        for (auto lit : ctx.root_literals()) {
 | 
			
		||||
            if (!ctx.is_true(lit))
 | 
			
		||||
                continue;
 | 
			
		||||
            auto e = ctx.atom(lit.var());
 | 
			
		||||
            expr* x, * y;
 | 
			
		||||
            if (e && m.is_eq(e, x, y))
 | 
			
		||||
                g.merge(g.find(x), g.find(y), nullptr);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        display(verbose_stream());
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void array_plugin::init_kv(euf::egraph& g, kv& kv) {
 | 
			
		||||
| 
						 | 
				
			
			@ -44,61 +213,56 @@ namespace sls {
 | 
			
		|||
            for (auto p : euf::enode_parents(n)) {
 | 
			
		||||
                if (!a.is_select(p->get_expr()))
 | 
			
		||||
                    continue;
 | 
			
		||||
                SASSERT(n->num_args() == 2);
 | 
			
		||||
                SASSERT(p->num_args() == 2);
 | 
			
		||||
                if (p->get_arg(0)->get_root() != n->get_root())
 | 
			
		||||
                    continue;
 | 
			
		||||
                auto idx = n->get_arg(1)->get_root();
 | 
			
		||||
                auto idx = p->get_arg(1)->get_root();
 | 
			
		||||
                auto val = p->get_root();
 | 
			
		||||
                kv[n].insert(idx, val);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        display(verbose_stream());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void array_plugin::saturate_store(euf::egraph& g, kv& kv) {
 | 
			
		||||
        for (auto n : g.nodes()) {
 | 
			
		||||
            if (!a.is_store(n->get_expr()))
 | 
			
		||||
                continue;
 | 
			
		||||
            SASSERT(n->num_args() == 3);
 | 
			
		||||
            auto idx = n->get_arg(1)->get_root();
 | 
			
		||||
            auto val = n->get_arg(2)->get_root();
 | 
			
		||||
            auto arr = n->get_arg(0)->get_root();
 | 
			
		||||
#if 0
 | 
			
		||||
            auto it = kv.find(arr);
 | 
			
		||||
            if (it == kv.end())
 | 
			
		||||
                continue;
 | 
			
		||||
            auto it2 = it->get_value().find(idx);
 | 
			
		||||
            if (it2 == nullptr)
 | 
			
		||||
                continue;
 | 
			
		||||
            g.merge(val, it2->get_value(), nullptr);
 | 
			
		||||
#endif
 | 
			
		||||
    expr_ref array_plugin::get_value(expr* e)  { 
 | 
			
		||||
        SASSERT(a.is_array(e));
 | 
			
		||||
        if (!m_g) {
 | 
			
		||||
            m_g = alloc(euf::egraph, m);
 | 
			
		||||
            init_egraph(*m_g);
 | 
			
		||||
            flet<bool> _strong(m_add_conflicts, false);
 | 
			
		||||
            saturate_store(*m_g);
 | 
			
		||||
        }
 | 
			
		||||
        if (!m_kv) {
 | 
			
		||||
            m_kv = alloc(kv);
 | 
			
		||||
            init_kv(*m_g, *m_kv);
 | 
			
		||||
        }
 | 
			
		||||
        auto& kv = *m_kv;
 | 
			
		||||
        auto n = m_g->find(e)->get_root();
 | 
			
		||||
        expr_ref r(n->get_expr(), m);
 | 
			
		||||
        for (auto [k, v] : kv[n]) {
 | 
			
		||||
            ptr_vector<expr> args;
 | 
			
		||||
            args.push_back(r);
 | 
			
		||||
            args.push_back(k->get_expr());
 | 
			
		||||
            args.push_back(v->get_expr());
 | 
			
		||||
            r = a.mk_store(args);
 | 
			
		||||
        }
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void array_plugin::init_egraph(euf::egraph& g) {
 | 
			
		||||
        ptr_vector<euf::enode> args;
 | 
			
		||||
        for (auto t : ctx.subterms()) {
 | 
			
		||||
            args.reset();
 | 
			
		||||
            if (is_app(t)) {
 | 
			
		||||
                for (auto* arg : *to_app(t)) {
 | 
			
		||||
                    args.push_back(g.find(arg));
 | 
			
		||||
    std::ostream& array_plugin::display(std::ostream& out) const {
 | 
			
		||||
        if (m_g)
 | 
			
		||||
            m_g->display(out);
 | 
			
		||||
        if (m_kv) {
 | 
			
		||||
            for (auto& [n, kvs] : *m_kv) {
 | 
			
		||||
                out << m_g->pp(n) << " -> {";
 | 
			
		||||
                char const* sp = "";
 | 
			
		||||
                for (auto& [k, v] : kvs) {
 | 
			
		||||
                    out << sp << m_g->pp(k) << " -> " << m_g->pp(v);
 | 
			
		||||
                    sp = " ";
 | 
			
		||||
                }
 | 
			
		||||
                out << "}\n";
 | 
			
		||||
            }
 | 
			
		||||
            auto n = g.mk(t, 0, args.size(), args.data());
 | 
			
		||||
            if (a.is_array(t))
 | 
			
		||||
                continue;
 | 
			
		||||
            auto v = ctx.get_value(t);
 | 
			
		||||
            auto n2 = g.mk(v, 0, 0, nullptr);
 | 
			
		||||
            g.merge(n, n2, nullptr);
 | 
			
		||||
        }
 | 
			
		||||
        for (auto lit : ctx.root_literals()) {
 | 
			
		||||
            if (!ctx.is_true(lit))
 | 
			
		||||
                continue;
 | 
			
		||||
            auto e = ctx.atom(lit.var());
 | 
			
		||||
            expr* x, * y;
 | 
			
		||||
            if (e && m.is_eq(e, x, y))
 | 
			
		||||
                g.merge(g.find(x), g.find(y), nullptr);
 | 
			
		||||
        }
 | 
			
		||||
        return out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,31 +22,42 @@ Author:
 | 
			
		|||
 | 
			
		||||
namespace sls {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    class array_plugin : public plugin {
 | 
			
		||||
        array_util     a;
 | 
			
		||||
 | 
			
		||||
        typedef obj_map<euf::enode, obj_map<euf::enode, euf::enode*>> kv;
 | 
			
		||||
 | 
			
		||||
        array_util     a;
 | 
			
		||||
        scoped_ptr<euf::egraph> m_g;
 | 
			
		||||
        scoped_ptr<kv> m_kv;
 | 
			
		||||
        bool m_add_conflicts = true;
 | 
			
		||||
 | 
			
		||||
        void init_egraph(euf::egraph& g);
 | 
			
		||||
        void init_kv(euf::egraph& g, kv& kv);
 | 
			
		||||
        void saturate_store(euf::egraph& g, kv& kv);
 | 
			
		||||
        void saturate_store(euf::egraph& g);
 | 
			
		||||
        void force_store_axiom1(euf::egraph& g, euf::enode* n);
 | 
			
		||||
        void force_store_axiom2_down(euf::egraph& g, euf::enode* sto, euf::enode* sel);
 | 
			
		||||
        void force_store_axiom2_up(euf::egraph& g, euf::enode* sto, euf::enode* sel);
 | 
			
		||||
        void add_store_axiom1(app* sto);
 | 
			
		||||
        void add_store_axiom2(app* sto, app* sel);
 | 
			
		||||
        bool are_distinct(euf::enode* a, euf::enode* b);
 | 
			
		||||
        bool eq_args(euf::enode* sto, euf::enode* sel);
 | 
			
		||||
        euf::enode* mk_select(euf::egraph& g, euf::enode* b, euf::enode* sel);
 | 
			
		||||
        
 | 
			
		||||
    public:
 | 
			
		||||
        array_plugin(context& ctx);
 | 
			
		||||
        ~array_plugin() override {}
 | 
			
		||||
        void register_term(expr* e) override { }
 | 
			
		||||
        expr_ref get_value(expr* e) override { return expr_ref(m); }
 | 
			
		||||
        void initialize() override {}
 | 
			
		||||
        void propagate_literal(sat::literal lit) override {}
 | 
			
		||||
        expr_ref get_value(expr* e) override;
 | 
			
		||||
        void initialize() override { m_g = nullptr; }
 | 
			
		||||
        void propagate_literal(sat::literal lit) override { m_g = nullptr; }
 | 
			
		||||
        bool propagate() override { return false; }
 | 
			
		||||
        bool repair_down(app* e) override { return false; }
 | 
			
		||||
        bool repair_down(app* e) override { return true; }
 | 
			
		||||
        void repair_up(app* e) override {}
 | 
			
		||||
        void repair_literal(sat::literal lit) override {}
 | 
			
		||||
        void repair_literal(sat::literal lit) override { m_g = nullptr; }
 | 
			
		||||
        bool is_sat() override;
 | 
			
		||||
 | 
			
		||||
        void on_rescale() override {}
 | 
			
		||||
        void on_restart() override {}
 | 
			
		||||
        std::ostream& display(std::ostream& out) const override { return out; }
 | 
			
		||||
        std::ostream& display(std::ostream& out) const override;
 | 
			
		||||
        void mk_model(model& mdl) override {}
 | 
			
		||||
        bool set_value(expr* e, expr* v) override { return false; }
 | 
			
		||||
        void collect_statistics(statistics& st) const override {}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,8 +18,11 @@ Author:
 | 
			
		|||
#include "ast/sls/sls_context.h"
 | 
			
		||||
#include "ast/sls/sls_euf_plugin.h"
 | 
			
		||||
#include "ast/sls/sls_arith_plugin.h"
 | 
			
		||||
#include "ast/sls/sls_array_plugin.h"
 | 
			
		||||
#include "ast/sls/sls_bv_plugin.h"
 | 
			
		||||
#include "ast/sls/sls_basic_plugin.h"
 | 
			
		||||
#include "ast/sls/sls_model_value_plugin.h"
 | 
			
		||||
#include "ast/sls/sls_user_sort_plugin.h"
 | 
			
		||||
#include "ast/ast_ll_pp.h"
 | 
			
		||||
#include "ast/ast_pp.h"
 | 
			
		||||
#include "smt/params/smt_params_helper.hpp"
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +45,9 @@ namespace sls {
 | 
			
		|||
        register_plugin(alloc(arith_plugin, *this));
 | 
			
		||||
        register_plugin(alloc(bv_plugin, *this));
 | 
			
		||||
        register_plugin(alloc(basic_plugin, *this));
 | 
			
		||||
        register_plugin(alloc(array_plugin, *this));
 | 
			
		||||
        register_plugin(alloc(user_sort_plugin, *this));
 | 
			
		||||
        register_plugin(alloc(model_value_plugin, *this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void context::updt_params(params_ref const& p) {
 | 
			
		||||
| 
						 | 
				
			
			@ -205,6 +211,7 @@ namespace sls {
 | 
			
		|||
        auto p = m_plugins.get(fid, nullptr);
 | 
			
		||||
        if (p) 
 | 
			
		||||
            return p->get_value(e);      
 | 
			
		||||
        verbose_stream() << fid << " " << m.get_family_name(fid) << " " << mk_pp(e, m) << "\n";
 | 
			
		||||
        UNREACHABLE();
 | 
			
		||||
        return expr_ref(e, m);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										47
									
								
								src/ast/sls/sls_model_value_plugin.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/ast/sls/sls_model_value_plugin.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2024 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    sls_model_value_plugin.h
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    Theory plugin for model values
 | 
			
		||||
    
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Nikolaj Bjorner (nbjorner) 2024-07-06
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "ast/sls/sls_context.h"
 | 
			
		||||
 | 
			
		||||
namespace sls {
 | 
			
		||||
 | 
			
		||||
    class model_value_plugin : public plugin {
 | 
			
		||||
        
 | 
			
		||||
    public:
 | 
			
		||||
        model_value_plugin(context& ctx) : plugin(ctx) { m_fid = m.get_family_id("model-value"); }
 | 
			
		||||
        ~model_value_plugin() override {}
 | 
			
		||||
        void register_term(expr* e) override { }
 | 
			
		||||
        expr_ref get_value(expr* e) override { return expr_ref(e, m); }
 | 
			
		||||
        void initialize() override { }
 | 
			
		||||
        void propagate_literal(sat::literal lit) override {  }
 | 
			
		||||
        bool propagate() override { return false; }
 | 
			
		||||
        bool repair_down(app* e) override { return true; }
 | 
			
		||||
        void repair_up(app* e) override {}
 | 
			
		||||
        void repair_literal(sat::literal lit) override {  }
 | 
			
		||||
        bool is_sat() override { return true; }
 | 
			
		||||
 | 
			
		||||
        void on_rescale() override {}
 | 
			
		||||
        void on_restart() override {}
 | 
			
		||||
        std::ostream& display(std::ostream& out) const override { return out;}
 | 
			
		||||
        void mk_model(model& mdl) override {}
 | 
			
		||||
        bool set_value(expr* e, expr* v) override { return false; }
 | 
			
		||||
        void collect_statistics(statistics& st) const override {}
 | 
			
		||||
        void reset_statistics() override {}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										92
									
								
								src/ast/sls/sls_user_sort_plugin.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								src/ast/sls/sls_user_sort_plugin.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,92 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2020 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    sls_user_sort_plugin.cpp
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    Theory plugin for user sort local search
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Nikolaj Bjorner (nbjorner) 2024-07-06
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
 | 
			
		||||
#include "ast/sls/sls_user_sort_plugin.h"
 | 
			
		||||
#include "ast/ast_ll_pp.h"
 | 
			
		||||
#include "ast/ast_pp.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace sls {
 | 
			
		||||
        
 | 
			
		||||
    user_sort_plugin::user_sort_plugin(context& ctx):
 | 
			
		||||
        plugin(ctx)
 | 
			
		||||
    {
 | 
			
		||||
        m_fid = user_sort_family_id;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void user_sort_plugin::init_egraph(euf::egraph& g) {
 | 
			
		||||
        ptr_vector<euf::enode> args;
 | 
			
		||||
        for (auto t : ctx.subterms()) {
 | 
			
		||||
            args.reset();
 | 
			
		||||
            if (is_app(t)) {
 | 
			
		||||
                for (auto* arg : *to_app(t)) {
 | 
			
		||||
                    args.push_back(g.find(arg));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            g.mk(t, 0, args.size(), args.data());
 | 
			
		||||
        }
 | 
			
		||||
        for (auto lit : ctx.root_literals()) {
 | 
			
		||||
            if (!ctx.is_true(lit) || lit.sign())
 | 
			
		||||
                continue;
 | 
			
		||||
            auto e = ctx.atom(lit.var());
 | 
			
		||||
            expr* x, * y;
 | 
			
		||||
            if (e && m.is_eq(e, x, y))
 | 
			
		||||
                g.merge(g.find(x), g.find(y), nullptr);
 | 
			
		||||
        }
 | 
			
		||||
        display(verbose_stream());     
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        typedef obj_map<sort, unsigned> map1;
 | 
			
		||||
        typedef obj_map<euf::enode, expr*> map2;
 | 
			
		||||
 | 
			
		||||
        m_num_elems = alloc(map1);
 | 
			
		||||
        m_root2value = alloc(map2);
 | 
			
		||||
        m_pinned = alloc(expr_ref_vector, m);
 | 
			
		||||
 | 
			
		||||
        for (auto n : g.nodes()) {
 | 
			
		||||
            if (n->is_root() && is_user_sort(n->get_sort())) {
 | 
			
		||||
                unsigned num = 0;
 | 
			
		||||
                m_num_elems->find(n->get_sort(), num);
 | 
			
		||||
                expr* v = m.mk_model_value(num, n->get_sort());
 | 
			
		||||
                m_pinned->push_back(v);
 | 
			
		||||
                m_root2value->insert(n, v);
 | 
			
		||||
                m_num_elems->insert(n->get_sort(), num + 1);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    expr_ref user_sort_plugin::get_value(expr* e) {
 | 
			
		||||
        if (m.is_model_value(e))
 | 
			
		||||
            return expr_ref(e, m);
 | 
			
		||||
 | 
			
		||||
        if (!m_g) {
 | 
			
		||||
            m_g = alloc(euf::egraph, m);
 | 
			
		||||
            init_egraph(*m_g);
 | 
			
		||||
        }
 | 
			
		||||
        auto n = m_g->find(e)->get_root();
 | 
			
		||||
        VERIFY(m_root2value->find(n, e));
 | 
			
		||||
        return expr_ref(e, m);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::ostream& user_sort_plugin::display(std::ostream& out) const {
 | 
			
		||||
        if (m_g)
 | 
			
		||||
            m_g->display(out);
 | 
			
		||||
        return out;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										55
									
								
								src/ast/sls/sls_user_sort_plugin.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/ast/sls/sls_user_sort_plugin.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,55 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2024 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    sls_user_sort_plugin.h
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    Theory plugin for arrays local search
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Nikolaj Bjorner (nbjorner) 2024-07-06
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "ast/sls/sls_context.h"
 | 
			
		||||
#include "ast/euf/euf_egraph.h"
 | 
			
		||||
 | 
			
		||||
namespace sls {
 | 
			
		||||
 | 
			
		||||
    class user_sort_plugin : public plugin {
 | 
			
		||||
        scoped_ptr<euf::egraph> m_g;
 | 
			
		||||
        scoped_ptr<obj_map<sort, unsigned>> m_num_elems;
 | 
			
		||||
        scoped_ptr<obj_map<euf::enode, expr*>> m_root2value;
 | 
			
		||||
        scoped_ptr<expr_ref_vector> m_pinned;
 | 
			
		||||
 | 
			
		||||
        void init_egraph(euf::egraph& g);
 | 
			
		||||
        bool is_user_sort(sort* s) { return s->get_family_id() == user_sort_family_id; }
 | 
			
		||||
        
 | 
			
		||||
    public:
 | 
			
		||||
        user_sort_plugin(context& ctx);
 | 
			
		||||
        ~user_sort_plugin() override {}
 | 
			
		||||
        void register_term(expr* e) override { }
 | 
			
		||||
        expr_ref get_value(expr* e) override;
 | 
			
		||||
        void initialize() override { m_g = nullptr; }
 | 
			
		||||
        void propagate_literal(sat::literal lit) override { m_g = nullptr; }
 | 
			
		||||
        bool propagate() override { return false; }
 | 
			
		||||
        bool repair_down(app* e) override { return true; }
 | 
			
		||||
        void repair_up(app* e) override {}
 | 
			
		||||
        void repair_literal(sat::literal lit) override { m_g = nullptr; }
 | 
			
		||||
        bool is_sat() override { return true; }
 | 
			
		||||
 | 
			
		||||
        void on_rescale() override {}
 | 
			
		||||
        void on_restart() override {}
 | 
			
		||||
        std::ostream& display(std::ostream& out) const override;
 | 
			
		||||
        void mk_model(model& mdl) override {}
 | 
			
		||||
        bool set_value(expr* e, expr* v) override { return false; }
 | 
			
		||||
        void collect_statistics(statistics& st) const override {}
 | 
			
		||||
        void reset_statistics() override {}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue