/*++
Copyright (c) 2012 Microsoft Corporation

Module Name:

    smt_strategic_solver.h

Abstract:

    Create a strategic solver with tactic for all main logics
    used in SMT.

Author:

    Leonardo (leonardo) 2012-02-19

Notes:

--*/
#include "cmd_context/cmd_context.h"
#include "solver/combined_solver.h"
#include "solver/tactic2solver.h"
#include "tactic/smtlogics/qfbv_tactic.h"
#include "tactic/smtlogics/qflia_tactic.h"
#include "tactic/smtlogics/qfnia_tactic.h"
#include "tactic/smtlogics/qfnra_tactic.h"
#include "tactic/smtlogics/qfuf_tactic.h"
#include "tactic/smtlogics/qflra_tactic.h"
#include "tactic/smtlogics/quant_tactics.h"
#include "tactic/smtlogics/qfauflia_tactic.h"
#include "tactic/smtlogics/qfaufbv_tactic.h"
#include "tactic/smtlogics/qfufbv_tactic.h"
#include "tactic/smtlogics/qfidl_tactic.h"
#include "tactic/smtlogics/nra_tactic.h"
#include "tactic/portfolio/default_tactic.h"
#include "tactic/portfolio/fd_solver.h"
#include "tactic/ufbv/ufbv_tactic.h"
#include "tactic/fpa/qffp_tactic.h"
#include "tactic/smtlogics/qfufnra_tactic.h"
#include "muz/fp/horn_tactic.h"
#include "smt/smt_solver.h"
#include "sat/sat_solver/inc_sat_solver.h"
#include "ast/rewriter/bv_rewriter.h"
#include "solver/solver2tactic.h"


tactic * mk_tactic_for_logic(ast_manager & m, params_ref const & p, symbol const & logic) {
    if (logic=="QF_UF")
        return mk_qfuf_tactic(m, p);
    else if (logic=="QF_BV")
        return mk_qfbv_tactic(m, p);        
    else if (logic=="QF_IDL")
        return mk_qfidl_tactic(m, p);
    else if (logic=="QF_LIA")
        return mk_qflia_tactic(m, p);
    else if (logic=="QF_LRA")
        return mk_qflra_tactic(m, p);
    else if (logic=="QF_NIA")
        return mk_qfnia_tactic(m, p);
    else if (logic=="QF_NRA")
        return mk_qfnra_tactic(m, p);
    else if (logic=="QF_AUFLIA")
        return mk_qfauflia_tactic(m, p);
    else if (logic=="QF_AUFBV")
        return mk_qfaufbv_tactic(m, p);
    else if (logic=="QF_ABV")
        return mk_qfaufbv_tactic(m, p);
    else if (logic=="QF_UFBV")
        return mk_qfufbv_tactic(m, p);
    else if (logic=="AUFLIA")
        return mk_auflia_tactic(m, p);
    else if (logic=="AUFLIRA")
        return mk_auflira_tactic(m, p);
    else if (logic=="AUFNIRA")
        return mk_aufnira_tactic(m, p);
    else if (logic=="UFNIA")
        return mk_ufnia_tactic(m, p);
    else if (logic=="UFLRA")
        return mk_uflra_tactic(m, p);
    else if (logic=="LRA")
        return mk_lra_tactic(m, p);
    else if (logic=="NRA")
        return mk_nra_tactic(m, p);
    else if (logic=="LIA")
        return mk_lia_tactic(m, p);
    else if (logic=="UFBV")
        return mk_ufbv_tactic(m, p);
    else if (logic=="BV")
        return mk_ufbv_tactic(m, p);
    else if (logic=="QF_FP")
        return mk_qffp_tactic(m, p);
    else if (logic == "QF_FPBV" || logic == "QF_BVFP")
        return mk_qffpbv_tactic(m, p);
    else if (logic=="HORN")
        return mk_horn_tactic(m, p);
    else if (logic == "QF_FD" || logic == "SAT")
        return mk_solver2tactic(mk_fd_solver(m, p));
    //else if (logic=="QF_UFNRA")
    //    return mk_qfufnra_tactic(m, p);
    else 
        return mk_default_tactic(m, p);
}

static solver* mk_special_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) {
    if (logic == "QF_FD" || logic == "SAT") 
        return mk_fd_solver(m, p);
    return 0;
}

static solver* mk_solver_for_logic(ast_manager & m, params_ref const & p, symbol const& logic) {
    bv_rewriter rw(m);
    solver* s = mk_special_solver_for_logic(m, p, logic);
    if (!s && logic == "QF_BV" && rw.hi_div0()) 
        s = mk_inc_sat_solver(m, p);
    if (!s) 
        s = mk_smt_solver(m, p, logic);
    return s;
}

class smt_strategic_solver_factory : public solver_factory {
    symbol m_logic;
public:
    smt_strategic_solver_factory(symbol const & logic):m_logic(logic) {}
    
    virtual ~smt_strategic_solver_factory() {}
    virtual solver * operator()(ast_manager & m, params_ref const & p, bool proofs_enabled, bool models_enabled, bool unsat_core_enabled, symbol const & logic) {
        symbol l;
        if (m_logic != symbol::null)
            l = m_logic;
        else
            l = logic;
        solver* s = mk_special_solver_for_logic(m, p, l);
        if (s) return s;
        tactic * t = mk_tactic_for_logic(m, p, l);
        return mk_combined_solver(mk_tactic2solver(m, t, p, proofs_enabled, models_enabled, unsat_core_enabled, l),
                                  mk_solver_for_logic(m, p, l), 
                                  p);
    }
};

solver_factory * mk_smt_strategic_solver_factory(symbol const & logic) {
    return alloc(smt_strategic_solver_factory, logic);
}

