1. Arlen Cox
  2. z3

Source

z3 / src / smt / ni_solver.cpp

/*++
Copyright (c) 2011 Microsoft Corporation

Module Name:

    ni_solver.cpp

Abstract:
    Wrappers for smt::kernel that are non-incremental & (quasi-incremental).

Author:

    Leonardo (leonardo) 2011-03-30

Notes:

--*/
#include"ni_solver.h"
#include"smt_kernel.h"
#include"cmd_context.h"
#include"solver_na2as.h"

class ni_smt_solver : public solver_na2as {
protected:
    cmd_context &       m_cmd_ctx;
    smt::kernel *       m_context;
    progress_callback * m_callback;
public:
    ni_smt_solver(cmd_context & ctx):m_cmd_ctx(ctx), m_context(0), m_callback(0) {}

    virtual ~ni_smt_solver() {
        if (m_context != 0)
            dealloc(m_context);
    }

    virtual void init_core(ast_manager & m, symbol const & logic) {
        // do nothing
    }

    virtual void collect_statistics(statistics & st) const {
        if (m_context == 0) {
            return;
        }
        else {
            m_context->collect_statistics(st);
        }
    }

    virtual void reset_core() {
        if (m_context != 0) {
            #pragma omp critical (ni_solver) 
            {
                dealloc(m_context);
                m_context = 0;
            }
        }
    }

    virtual void assert_expr(expr * t) {
        // do nothing
    }

    virtual void push_core() {
        // do nothing
    }

    virtual void pop_core(unsigned n) {
        // do nothing
    }

    void assert_exprs() {
        ptr_vector<expr>::const_iterator it  = m_cmd_ctx.begin_assertions();
        ptr_vector<expr>::const_iterator end = m_cmd_ctx.end_assertions();
        for (; it != end; ++it) {
            m_context->assert_expr(*it);
        }
    }

    void init_solver() {
        reset_core();
        #pragma omp critical (ni_solver)
        {
            m_context = alloc(smt::kernel, m_cmd_ctx.m(), m_cmd_ctx.params());
        }
        if (m_cmd_ctx.has_logic())
            m_context->set_logic(m_cmd_ctx.get_logic());
        if (m_callback)
            m_context->set_progress_callback(m_callback);
        assert_exprs();
    }

    virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) {
        // erase current solver, and create a new one.
        init_solver();

        if (num_assumptions == 0) {
            return m_context->setup_and_check();
        }
        else {
            return m_context->check(num_assumptions, assumptions); 
        }
    }

    virtual void get_unsat_core(ptr_vector<expr> & r) {
        SASSERT(m_context);
        unsigned sz = m_context->get_unsat_core_size();
        for (unsigned i = 0; i < sz; i++)
            r.push_back(m_context->get_unsat_core_expr(i));
    }

    virtual void get_model(model_ref & m) {
        SASSERT(m_context);
        m_context->get_model(m);
    }

    virtual proof * get_proof() {
        SASSERT(m_context);
        return m_context->get_proof();
    }

    virtual std::string reason_unknown() const {
        SASSERT(m_context);
        return m_context->last_failure_as_string();
    }

    virtual void get_labels(svector<symbol> & r) {
        SASSERT(m_context);
        buffer<symbol> tmp;
        m_context->get_relevant_labels(0, tmp);
        r.append(tmp.size(), tmp.c_ptr());
    }

    virtual void set_cancel(bool f) {
        #pragma omp critical (ni_solver)
        {
            if (m_context)
                m_context->set_cancel(f);
        }
    }

    virtual void set_progress_callback(progress_callback * callback) {
        m_callback = callback;
        if (m_context)
            m_context->set_progress_callback(callback);
    }


    virtual void collect_param_descrs(param_descrs & r) {
        smt::kernel::collect_param_descrs(r);
    }

};

solver * mk_non_incremental_smt_solver(cmd_context & ctx) {
    return alloc(ni_smt_solver, ctx);
}

class qi_smt_solver : public ni_smt_solver {
    bool            m_inc_mode;   
public:
    qi_smt_solver(cmd_context & ctx):ni_smt_solver(ctx), m_inc_mode(false) {}
    
    virtual ~qi_smt_solver() {}

    virtual void init_core(ast_manager & m, symbol const & logic) {
        if (m_inc_mode) {
            init_solver();
            m_inc_mode = true;
        }
    }

    virtual void reset_core() {
        ni_smt_solver::reset_core();
        m_inc_mode = false;
    }

    void switch_to_inc() {
        if (!m_inc_mode) {
            init_solver();
            m_inc_mode = true;
        }
        SASSERT(m_inc_mode);
    }

    virtual void assert_expr(expr * t) {
        if (m_context != 0 && !m_inc_mode) {
            // solver was already created to solve a check_sat query...
            switch_to_inc();
        }
        if (m_inc_mode) {
            SASSERT(m_context);
            m_context->assert_expr(t);
        }
    }

    virtual void push_core() {
        switch_to_inc();
        SASSERT(m_context);
        m_context->push();
        SASSERT(m_inc_mode);
    }

    virtual void pop_core(unsigned n) {
        switch_to_inc();
        SASSERT(m_context);
        m_context->pop(n);
        SASSERT(m_inc_mode);
    }

    virtual lbool check_sat_core(unsigned num_assumptions, expr * const * assumptions) {
        if (!m_inc_mode) {
            lbool r = ni_smt_solver::check_sat_core(num_assumptions, assumptions);
            SASSERT(!m_inc_mode);
            return r;
        }
        else {
            return m_context->check(num_assumptions, assumptions); 
        }
    }
};


solver * mk_quasi_incremental_smt_solver(cmd_context & ctx) {
    return alloc(qi_smt_solver, ctx);
}