├── rewriters ├── ite_rewriter.cpp ├── op_rewriter.cpp ├── rewriter.hpp ├── nnf_rewriter.hpp ├── ite_rewriter.hpp ├── let_rewriter.hpp ├── op_rewriter.hpp ├── logic_rewriter.hpp ├── eq_rewriter.hpp ├── prop_rewriter.hpp ├── poly_rewriter.hpp ├── logic_rewriter.cpp ├── comp_rewriter.hpp ├── nnf_rewriter.cpp ├── let_rewriter.cpp └── eq_rewriter.cpp ├── solvers ├── poly │ ├── poly_solver.cpp │ └── poly_solver.hpp ├── sat │ ├── sat_types.hpp │ ├── sat_solver.hpp │ └── sat_solver.cpp ├── cdcl_t │ ├── cdcl_t_solver.cpp │ └── cdcl_t_solver.hpp ├── icp │ ├── icp_solver.hpp │ └── icp_solver.cpp ├── blaster │ ├── blaster_bits.cpp │ ├── blaster_bits.hpp │ ├── blaster_transposition.cpp │ ├── blaster_types.hpp │ ├── blaster_offset.hpp │ ├── blaster_transformer.hpp │ ├── blaster_comp.cpp │ ├── blaster_logic.cpp │ ├── blaster_equal.cpp │ ├── blaster_make.cpp │ ├── blaster_slack.cpp │ ├── blaster_solver.cpp │ └── blaster_solver.hpp └── eq │ ├── eq_solver.hpp │ └── eq_solver.cpp ├── test ├── 3.smt2 ├── 2.smt2 └── 1.smt2 ├── utils ├── poly.hpp ├── search_box.hpp ├── constraint.hpp ├── box.hpp ├── logic.hpp ├── types.hpp ├── disjoint_set.hpp ├── simp_vector.hpp ├── interval.hpp ├── graph.hpp └── rational.hpp ├── qfnia ├── searcher.hpp ├── resolver.hpp ├── checker.hpp ├── qfnia.hpp ├── resolver.cpp ├── info.hpp ├── searcher.cpp ├── qfnia.cpp ├── decider.hpp └── collector.hpp ├── main.cpp ├── midend ├── message.hpp ├── preprocessor.hpp └── preprocessor.cpp ├── Makefile ├── .vscode └── settings.json ├── configure.sh ├── README.md ├── .gitignore ├── options.hpp └── frontend └── parser.hpp /rewriters/ite_rewriter.cpp: -------------------------------------------------------------------------------- 1 | /* ite_rewriter.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "rewriters/ite_rewriter.hpp" 9 | 10 | using namespace ismt; 11 | 12 | -------------------------------------------------------------------------------- /solvers/poly/poly_solver.cpp: -------------------------------------------------------------------------------- 1 | /* poly_solver.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/poly/poly_solver.hpp" 9 | 10 | using namespace ismt; 11 | 12 | -------------------------------------------------------------------------------- /test/3.smt2: -------------------------------------------------------------------------------- 1 | (set-info :smt-lib-version 2.6) 2 | (set-logic QF_NIA) 3 | (set-info :status sat) 4 | (declare-fun x () Int) 5 | (declare-fun y () Int) 6 | (declare-fun z () Int) 7 | (assert (= (- (* x y z) 4) 0)) 8 | (check-sat) 9 | ;(get-model) 10 | (exit) -------------------------------------------------------------------------------- /utils/poly.hpp: -------------------------------------------------------------------------------- 1 | /* poly.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _POLY_H 9 | #define _POLY_H 10 | 11 | #include "solvers/include/poly/poly.h" 12 | #include "solvers/include/poly/polyxx.h" 13 | #endif -------------------------------------------------------------------------------- /rewriters/op_rewriter.cpp: -------------------------------------------------------------------------------- 1 | /* op_rewriter.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "rewriters/op_rewriter.hpp" 9 | 10 | using namespace ismt; 11 | 12 | dagc* op_rewriter::rewrite(dagc* root){ 13 | 14 | } -------------------------------------------------------------------------------- /test/2.smt2: -------------------------------------------------------------------------------- 1 | (set-info :smt-lib-version 2.6) 2 | (set-logic QF_NIA) 3 | (set-info :status sat) 4 | (declare-fun x () Int) 5 | (declare-fun y () Int) 6 | (declare-fun z () Int) 7 | (assert (= 0 (+ (* x y) (* 8 y z) (- 32)))) 8 | (assert (<= y 4)) 9 | (assert (<= z 4)) 10 | (check-sat) 11 | ;(get-model) 12 | (exit) -------------------------------------------------------------------------------- /utils/search_box.hpp: -------------------------------------------------------------------------------- 1 | /* search_box.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _SEARCH_BOX_H 9 | #define _SEARCH_BOX_H 10 | 11 | #include "utils/poly.hpp" 12 | 13 | namespace ismt 14 | { 15 | // bit blasting search box 16 | typedef poly::IntervalAssignment search_box; 17 | 18 | } // namespace ismt 19 | 20 | 21 | #endif -------------------------------------------------------------------------------- /utils/constraint.hpp: -------------------------------------------------------------------------------- 1 | /* constraint.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _CONSTRAINT_H 9 | #define _CONSTRAINT_H 10 | 11 | namespace ismt 12 | { 13 | class constraint 14 | { 15 | private: 16 | /* data */ 17 | public: 18 | constraint(/* args */); 19 | ~constraint(); 20 | }; 21 | 22 | } // namespace ismt 23 | 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /solvers/sat/sat_types.hpp: -------------------------------------------------------------------------------- 1 | /* sat_types.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _SAT_TYPES_H 9 | #define _SAT_TYPES_H 10 | 11 | namespace ismt 12 | { 13 | typedef int bool_var; 14 | typedef int literal; 15 | typedef std::vector clause; 16 | typedef std::vector literals; 17 | typedef std::vector model; 18 | } // namespace ismt 19 | 20 | 21 | #endif -------------------------------------------------------------------------------- /test/1.smt2: -------------------------------------------------------------------------------- 1 | (set-info :smt-lib-version 2.6) 2 | (set-logic QF_NIA) 3 | (set-info :source |AProve team, see http://aprove.informatik.rwth-aachen.de/, submitted for SMT-COMP 2014|) 4 | (set-info :category "industrial") 5 | (set-info :status sat) 6 | (declare-fun a__6 () Int) 7 | (declare-fun a__4 () Int) 8 | (assert (and (>= (+ (* a__6 a__4) (* (- 0 1) a__4)) 0) (>= (+ a__4 (- 0 1)) 0) (>= a__6 0) (>= a__4 0))) 9 | (check-sat) 10 | ;(get-model) 11 | (exit) 12 | -------------------------------------------------------------------------------- /solvers/cdcl_t/cdcl_t_solver.cpp: -------------------------------------------------------------------------------- 1 | /* cdcl_t_solver.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/cdcl_t/cdcl_t_solver.hpp" 9 | 10 | using namespace ismt; 11 | 12 | 13 | cdcl_t_solver::cdcl_t_solver(/* args */){} 14 | cdcl_t_solver::~cdcl_t_solver(){} 15 | 16 | bool cdcl_t_solver::decide(){ 17 | 18 | } 19 | bool cdcl_t_solver::bcp(){ 20 | 21 | } 22 | int cdcl_t_solver::new_lit(constraint& lit){ 23 | 24 | } 25 | void cdcl_t_solver::add_clause(vector& c){ 26 | 27 | } 28 | void cdcl_t_solver::current_assignment(std::vector& partial_model){ 29 | 30 | } -------------------------------------------------------------------------------- /rewriters/rewriter.hpp: -------------------------------------------------------------------------------- 1 | /* rewriter.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _REWRITER_H 9 | #define _REWRITER_H 10 | 11 | #include "frontend/dag.hpp" 12 | #include "frontend/parser.hpp" 13 | 14 | namespace ismt 15 | { 16 | class rewriter 17 | { 18 | protected: 19 | DAG* data = nullptr; 20 | Parser* parser = nullptr; 21 | public: 22 | bool consistent = true; 23 | 24 | rewriter(Parser* p):parser(p){ 25 | data = &(p->dag); 26 | } 27 | ~rewriter(){} 28 | }; 29 | 30 | 31 | } // namespace ismt 32 | 33 | 34 | #endif -------------------------------------------------------------------------------- /utils/box.hpp: -------------------------------------------------------------------------------- 1 | /* box.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _BOX_HPP 9 | #define _BOX_HPP 10 | 11 | // now not support, for less memory 12 | #include "utils/interval.hpp" 13 | 14 | namespace ismt 15 | { 16 | const int mask_is_interval = 1; 17 | 18 | class box 19 | { 20 | private: 21 | int info = 0; 22 | unsigned int bits = 0; 23 | // Interval 24 | public: 25 | box(int i = 0):info(i){} 26 | ~box(); 27 | 28 | bool is_free() const { return !(info & mask_is_interval); } 29 | bool is_interval() const { return (info & mask_is_interval); } 30 | }; 31 | 32 | } // namespace ismt 33 | 34 | 35 | #endif -------------------------------------------------------------------------------- /rewriters/nnf_rewriter.hpp: -------------------------------------------------------------------------------- 1 | /* nnf_rewriter.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _NNF_REWRITER_H 9 | #define _NNF_REWRITER_H 10 | 11 | #include "rewriters/rewriter.hpp" 12 | 13 | namespace ismt 14 | { 15 | class nnf_rewriter: public rewriter 16 | { 17 | private: 18 | // convert to nnf-like tree 19 | void toNNFNode(dagc*& node, bool isNot); // convert the node 20 | bool isVar(dagc* node); 21 | public: 22 | nnf_rewriter(Parser* p): rewriter(p) {} 23 | ~nnf_rewriter(){} 24 | 25 | void rewrite(dagc*& root, bool isNot = false); 26 | void rewrite(); 27 | }; 28 | 29 | } // namespace ismt 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /solvers/cdcl_t/cdcl_t_solver.hpp: -------------------------------------------------------------------------------- 1 | /* cdcl_t_solver.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _CDCL_T_SOLVER_H 9 | #define _CDCL_T_SOLVER_H 10 | 11 | #include "solvers/sat/sat_solver.hpp" 12 | #include "utils/constraint.hpp" 13 | 14 | namespace ismt 15 | { 16 | class cdcl_t_solver 17 | { 18 | private: 19 | sat_solver* decider = nullptr; 20 | size_t lit_size = 0; 21 | public: 22 | cdcl_t_solver(/* args */); 23 | ~cdcl_t_solver(); 24 | 25 | bool decide(); 26 | bool bcp(); 27 | int new_lit(constraint& lit); 28 | void add_clause(vector& c); 29 | void current_assignment(std::vector& partial_model); 30 | }; 31 | } // namespace ismt 32 | 33 | 34 | #endif -------------------------------------------------------------------------------- /rewriters/ite_rewriter.hpp: -------------------------------------------------------------------------------- 1 | /* ite_rewriter.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _ITE_REWRITER_H 9 | #define _ITE_REWRITER_H 10 | 11 | #include "frontend/dag.hpp" 12 | #include "rewriters/rewriter.hpp" 13 | #include "utils/model.hpp" 14 | 15 | namespace ismt 16 | { 17 | class ite_rewriter: public rewriter 18 | { 19 | private: 20 | model_s* model; 21 | void rewrite(dagc* root, bool isTop, std::vector& res); 22 | bool analyze(dagc* root, std::vector& res, bool isnot = false); 23 | public: 24 | ite_rewriter(Parser* p, model_s* m): rewriter(p), model(m) { 25 | data = &(p->dag); 26 | } 27 | ~ite_rewriter(){} 28 | 29 | bool rewrite(); 30 | }; 31 | 32 | } // namespace ismt 33 | 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /qfnia/searcher.hpp: -------------------------------------------------------------------------------- 1 | /* searcher.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _SEARCHER_H 9 | #define _SEARCHER_H 10 | 11 | #include "qfnia/info.hpp" 12 | 13 | #include "solvers/blaster/blaster_solver.hpp" 14 | #include "solvers/blaster/blaster_transformer.hpp" 15 | 16 | namespace ismt 17 | { 18 | class Searcher 19 | { 20 | private: 21 | Info* info = nullptr; 22 | blaster_transformer* transformer = nullptr; 23 | blaster_solver* solver = nullptr; 24 | bool used = false; 25 | void _declare(dagc* root); 26 | int _assert(dagc* root); 27 | 28 | public: 29 | Searcher(/* args */); 30 | ~Searcher(); 31 | 32 | void init(Info* i); 33 | bool search(); 34 | void reset(); 35 | void set_model(); 36 | }; 37 | 38 | } // namespace ismt 39 | 40 | 41 | 42 | #endif -------------------------------------------------------------------------------- /rewriters/let_rewriter.hpp: -------------------------------------------------------------------------------- 1 | /* let_rewriter.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _LET_REWRITER_H 9 | #define _LET_REWRITER_H 10 | 11 | #include "frontend/dag.hpp" 12 | #include "rewriters/rewriter.hpp" 13 | #include "utils/model.hpp" 14 | 15 | namespace ismt 16 | { 17 | class let_rewriter: public rewriter 18 | { 19 | private: 20 | model_s* model; 21 | dagc* content(dagc* root); // content of letvar 22 | void analyzeOp(dagc* root); // or / eqbool / neqbool 23 | void rewrite(dagc* root, std::vector& res, bool isTop = true); 24 | bool propagate(dagc* root, std::vector& res); 25 | public: 26 | let_rewriter(Parser* p, model_s* m): rewriter(p), model(m) { 27 | data = &(p->dag); 28 | } 29 | ~let_rewriter(){} 30 | 31 | bool rewrite(); 32 | }; 33 | 34 | } // namespace ismt 35 | 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /qfnia/resolver.hpp: -------------------------------------------------------------------------------- 1 | /* resolver.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _RESOLVER_H 9 | #define _RESOLVER_H 10 | 11 | #include "qfnia/info.hpp" 12 | 13 | namespace ismt 14 | { 15 | class Resolver 16 | { 17 | private: 18 | Info* info = nullptr; 19 | Parser* parser = nullptr; 20 | poly_rewriter* polyer = nullptr; 21 | nnf_rewriter* nnfer = nullptr; 22 | std::vector core; 23 | 24 | bool is_hard(std::vector& constraints); 25 | bool is_hard(dagc* constraint); 26 | bool cad_resolve(std::vector& constraints); 27 | public: 28 | Resolver(/* args */); 29 | ~Resolver(); 30 | 31 | void init(Info* i); 32 | // mcsat use different sovlers 33 | bool resolve(); 34 | dagc* lemma(); 35 | bool has_lemma() const; 36 | }; 37 | 38 | } // namespace ismt 39 | 40 | 41 | #endif -------------------------------------------------------------------------------- /solvers/poly/poly_solver.hpp: -------------------------------------------------------------------------------- 1 | /* poly_solver.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _POLY_SOLVER_H 9 | #define _POLY_SOLVER_H 10 | 11 | #include "rewriters/poly_rewriter.hpp" 12 | 13 | namespace ismt 14 | { 15 | // an implementation of nisat ( non-linear integer mcsat solver ) 16 | class poly_solver 17 | { 18 | private: 19 | poly_rewriter* polyer = nullptr; 20 | poly::Assignment* data = nullptr; 21 | public: 22 | poly_solver(/* args */){} 23 | ~poly_solver(){} 24 | 25 | // solving functions 26 | State check(); 27 | // unsat core if failed -> lemma 28 | dagc* core(); 29 | 30 | 31 | 32 | // // add operations 33 | // void assert(dagc* constraint); 34 | // void assign(dagc* var, const poly::Integer& v); 35 | // void assign(dagc* var, const Integer& v); 36 | }; 37 | 38 | } // namespace ismt 39 | 40 | 41 | #endif -------------------------------------------------------------------------------- /qfnia/checker.hpp: -------------------------------------------------------------------------------- 1 | /* checker.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _CHECKER_HPP 9 | #define _CHECKER_HPP 10 | 11 | #include "utils/model.hpp" 12 | #include "qfnia/info.hpp" 13 | 14 | namespace ismt 15 | { 16 | // model checker 17 | class checker 18 | { 19 | private: 20 | Info* info = nullptr; 21 | // check 22 | int checkAtoms(dagc* dag); 23 | int checkMathAtoms(dagc* dag); 24 | int checkLetBoolTerms(dagc* dag); 25 | int checkLetAtoms(dagc* dag); 26 | Integer checkIteNums(dagc* dag); 27 | Integer checkMathTerms(dagc* dag); 28 | Integer checkLetNumTerms(dagc* dag); 29 | Integer getValue(dagc* dag); 30 | bool check(dagc* dag); 31 | public: 32 | checker(Info* i):info(i){} 33 | ~checker(){} 34 | 35 | bool check(); 36 | }; 37 | } // namespace ismt 38 | 39 | 40 | #endif -------------------------------------------------------------------------------- /rewriters/op_rewriter.hpp: -------------------------------------------------------------------------------- 1 | /* op_rewriter.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _OP_REWRITER_H 9 | #define _OP_REWRITER_H 10 | 11 | #include "frontend/dag.hpp" 12 | #include "utils/model.hpp" 13 | #include "utils/disjoint_set.hpp" 14 | #include "rewriters/rewriter.hpp" 15 | 16 | namespace ismt 17 | { 18 | // currently only rewrite abs 19 | // not support, inside polynomial -> explosion 20 | // abs(x+y) > 3 -> -(x + y) > 3 or (x+y) > 3 21 | // abs(x+y) > 0 -> x+y != 0 22 | // abs(x+y) >= 0 -> true 23 | // x + abs(x+y) = 3 -> x + (x+y) = 3 or x - (x+y) = 3 24 | // x + abs(x) + abs(y) + abs(z) = 3 -> 8, ... so not support 25 | // abs(abs(...(x+y))) -> abs(x+y) assumes never 26 | class op_rewriter: public rewriter 27 | { 28 | public: 29 | op_rewriter(Parser* p): rewriter(p) {} 30 | ~op_rewriter(){} 31 | 32 | dagc* rewrite(dagc* root); 33 | }; 34 | 35 | } // namespace ismt 36 | 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /rewriters/logic_rewriter.hpp: -------------------------------------------------------------------------------- 1 | /* logic_rewriter.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _LOGIC_REWRITER_H 9 | #define _LOGIC_REWRITER_H 10 | 11 | #include "frontend/dag.hpp" 12 | #include "rewriters/rewriter.hpp" 13 | 14 | namespace ismt 15 | { 16 | // split each and-constraint 17 | // 1) assert-and -> asserts, (assert (and a b c)) -> (assert a) (assert b) (assert c). 18 | // 2) and-and -> and 19 | // 3) or-or -> or 20 | // 4) and-or/or-and -> and->or/or-and 21 | class logic_rewriter: public rewriter 22 | { 23 | private: 24 | bool curIsTop = false; 25 | 26 | void andRecord(dagc* root, std::vector& res); 27 | void orRecord(dagc* root, std::vector& res); 28 | void rewrite(dagc* root); 29 | public: 30 | logic_rewriter(Parser* p): rewriter(p) {} 31 | ~logic_rewriter(){} 32 | 33 | void rewrite(); 34 | }; 35 | 36 | } // namespace ismt 37 | 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* main.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "qfnia/qfnia.hpp" 9 | #include "options.hpp" 10 | #include 11 | #include 12 | 13 | using namespace ismt; 14 | 15 | void sigalarm_handler(int){std::cout<<"unknown"<= 1){ 18 | SolverOptions* StaticOptions = new SolverOptions(); 19 | if(!StaticOptions->parse(argc, argv)){ 20 | delete StaticOptions; 21 | return 0; 22 | } 23 | // StaticOptions->print(); 24 | 25 | signal(SIGALRM, sigalarm_handler); 26 | signal(SIGINT, sigalarm_handler); 27 | 28 | // signal(SIGABRT, sigalarm_handler); 29 | // signal(SIGFPE, sigalarm_handler); 30 | // signal(SIGILL, sigalarm_handler); 31 | // signal(SIGSEGV, sigalarm_handler); 32 | // signal(SIGTERM, sigalarm_handler); 33 | alarm(StaticOptions->Time); 34 | 35 | 36 | qfnia_solver solver; 37 | solver.solve(StaticOptions); 38 | 39 | delete StaticOptions; 40 | } 41 | } -------------------------------------------------------------------------------- /utils/logic.hpp: -------------------------------------------------------------------------------- 1 | /* logic.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _LOGIC_H 9 | #define _LOGIC_H 10 | 11 | namespace ismt 12 | { 13 | 14 | enum ENUM_LOGIC { 15 | UNKNOWN_LOGIC, 16 | QF_LIA, 17 | QF_NIA, 18 | QF_LRA, 19 | QF_LIRA, 20 | QF_NRA, 21 | QF_NIRA 22 | }; 23 | 24 | enum NODE_TYPE { 25 | NT_UNKNOWN=0, NT_ERROR, 26 | // CONST 27 | NT_CONST_BOOL, NT_CONST_NUM, 28 | // VAR 29 | NT_VAR_BOOL, NT_VAR_NUM, 30 | // LOGIC 31 | NT_AND, NT_OR, NT_NOT, NT_ITE_BOOL, NT_ITE_NUM, 32 | // ARITHMATIC 33 | NT_ADD, NT_MUL, NT_DIV_INT, NT_DIV_REAL, NT_MOD, NT_ABS, NT_SUB, 34 | // COMP 35 | NT_LE, NT_EQ, NT_LT, NT_GE, NT_GT, NT_NEQ, NT_EQ_BOOL, NT_NEQ_BOOL, 36 | // INT REAL 37 | NT_TO_REAL, NT_TO_INT, NT_IS_INT, 38 | // LET 39 | NT_VAR_LET_BOOL, NT_VAR_LET_NUM, NT_LET, 40 | // DEFINE-FUN 41 | NT_FUN_BOOL, NT_FUN_INT, NT_FUN_REAL, NT_FUN_PARAM_BOOL, NT_FUN_PARAM_INT 42 | }; 43 | } // namespace ismt 44 | 45 | 46 | 47 | #endif -------------------------------------------------------------------------------- /solvers/icp/icp_solver.hpp: -------------------------------------------------------------------------------- 1 | /* icp_solver.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _ICP_SOLVER_H 9 | #define _ICP_SOLVER_H 10 | 11 | #include "utils/types.hpp" 12 | #include "utils/interval.hpp" 13 | #include "rewriters/poly_rewriter.hpp" 14 | #include "solvers/sat/sat_solver.hpp" 15 | 16 | namespace ismt 17 | { 18 | class icp_solver 19 | { 20 | private: 21 | poly_rewriter* polyer; 22 | poly::IntervalAssignment* data; 23 | sat_solver* controller; // top sat solver 24 | 25 | std::vector stored_core; 26 | bool isEasyComp(dagc* c); 27 | bool easyComp(dagc* c); 28 | 29 | public: 30 | icp_solver(poly_rewriter* p); 31 | ~icp_solver(); 32 | 33 | // solving functions 34 | bool evaluate(dagc* c); 35 | State check(std::vector& cs); 36 | // unsat core if failed -> lemma 37 | void core(std::vector& cores); 38 | 39 | // add operations 40 | void assign(dagc* var, const poly::Interval& v); 41 | void reset(); 42 | }; 43 | 44 | } // namespace ismt 45 | 46 | 47 | #endif -------------------------------------------------------------------------------- /midend/message.hpp: -------------------------------------------------------------------------------- 1 | /* message.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _MESSAGE_H 9 | #define _MESSAGE_H 10 | 11 | #include "frontend/dag.hpp" 12 | #include "utils/feasible_set.hpp" 13 | #include "utils/types.hpp" 14 | #include "utils/model.hpp" 15 | #include 16 | #include 17 | #include 18 | 19 | namespace ismt 20 | { 21 | // message from preprocessor 22 | struct Message{ 23 | // 0. DAG 24 | DAG * data; 25 | // 1. constraints: after preprocess, they may changed. 26 | std::list constraints; 27 | // 2. midend state 28 | State state = State::UNKNOWN; 29 | // 3. preprocessed model, and variables 30 | model_s* model; 31 | 32 | void print_constraints(){ 33 | auto it = constraints.begin(); 34 | while(it != constraints.end()){ 35 | data->printAST(*it); 36 | std::cout<print(); 42 | } 43 | }; 44 | } // namespace ismt 45 | 46 | 47 | #endif -------------------------------------------------------------------------------- /rewriters/eq_rewriter.hpp: -------------------------------------------------------------------------------- 1 | /* eq_rewriter.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _EQ_REWRITER_H 9 | #define _EQ_REWRITER_H 10 | 11 | #include "frontend/dag.hpp" 12 | #include "utils/model.hpp" 13 | #include "utils/disjoint_set.hpp" 14 | #include "rewriters/rewriter.hpp" 15 | 16 | namespace ismt 17 | { 18 | // inner each and, we can use equivalence_rewriter to locally propagate 19 | class eq_rewriter: public rewriter 20 | { 21 | private: 22 | bool curIsTop = false; 23 | model_s* model = nullptr; 24 | 25 | bool localAssign(boost::unordered_map& localAssigned, dagc* root, Integer val); 26 | bool localSubsitute(disjoint_set& localSubset, dagc* a, dagc* b); 27 | public: 28 | eq_rewriter(Parser* p): rewriter(p) {} 29 | ~eq_rewriter(){} 30 | 31 | void setModel(model_s* m); 32 | dagc* rewrite(dagc* root, bool isTop = true); 33 | dagc* localRewrite(dagc* root, disjoint_set& localSubset, boost::unordered_map& localAssigned); 34 | 35 | bool rewrite(); 36 | }; 37 | 38 | } // namespace ismt 39 | 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CXX = g++ 2 | CXXFLAGS = -Wall -Werror -Wextra -pedantic -std=c++11 -g -I. -fno-omit-frame-pointer -O3 3 | LBLIBS = -L solvers/include -lcadical -lgmp -lgmpxx -lpoly -lpolyxx -lpicpoly -lpicpolyxx 4 | SRC = main.cpp \ 5 | qfnia/qfnia.cpp qfnia/decider.cpp qfnia/searcher.cpp qfnia/resolver.cpp qfnia/collector.cpp qfnia/checker.cpp\ 6 | frontend/parser.cpp midend/preprocessor.cpp \ 7 | rewriters/comp_rewriter.cpp rewriters/nnf_rewriter.cpp rewriters/prop_rewriter.cpp \ 8 | rewriters/poly_rewriter.cpp rewriters/eq_rewriter.cpp rewriters/logic_rewriter.cpp rewriters/let_rewriter.cpp \ 9 | solvers/poly/poly_solver.cpp solvers/icp/icp_solver.cpp solvers/eq/eq_solver.cpp\ 10 | solvers/blaster/blaster_solver.cpp solvers/blaster/blaster_transposition.cpp solvers/blaster/blaster_slack.cpp \ 11 | solvers/blaster/blaster_recursion.cpp solvers/blaster/blaster_operations.cpp solvers/blaster/blaster_make.cpp \ 12 | solvers/blaster/blaster_logic.cpp solvers/blaster/blaster_equal.cpp solvers/blaster/blaster_comp.cpp \ 13 | solvers/blaster/blaster_transformer.cpp solvers/blaster/blaster_bits.cpp \ 14 | solvers/sat/sat_solver.cpp 15 | OBJ = $(SRC:.cpp=.o) 16 | EXEC = BLAN 17 | 18 | all: $(EXEC) 19 | 20 | $(EXEC): $(OBJ) 21 | $(CXX) -o $@ $(OBJ) $(LBLIBS) 22 | 23 | clean: 24 | rm -rf $(OBJ) $(EXEC) -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "array": "cpp", 4 | "atomic": "cpp", 5 | "*.tcc": "cpp", 6 | "cctype": "cpp", 7 | "clocale": "cpp", 8 | "cmath": "cpp", 9 | "csignal": "cpp", 10 | "cstdarg": "cpp", 11 | "cstddef": "cpp", 12 | "cstdint": "cpp", 13 | "cstdio": "cpp", 14 | "cstdlib": "cpp", 15 | "cstring": "cpp", 16 | "ctime": "cpp", 17 | "cwchar": "cpp", 18 | "cwctype": "cpp", 19 | "deque": "cpp", 20 | "list": "cpp", 21 | "unordered_map": "cpp", 22 | "vector": "cpp", 23 | "exception": "cpp", 24 | "algorithm": "cpp", 25 | "map": "cpp", 26 | "memory": "cpp", 27 | "memory_resource": "cpp", 28 | "optional": "cpp", 29 | "set": "cpp", 30 | "string": "cpp", 31 | "string_view": "cpp", 32 | "system_error": "cpp", 33 | "tuple": "cpp", 34 | "type_traits": "cpp", 35 | "utility": "cpp", 36 | "fstream": "cpp", 37 | "initializer_list": "cpp", 38 | "iosfwd": "cpp", 39 | "iostream": "cpp", 40 | "istream": "cpp", 41 | "limits": "cpp", 42 | "new": "cpp", 43 | "ostream": "cpp", 44 | "sstream": "cpp", 45 | "stdexcept": "cpp", 46 | "streambuf": "cpp", 47 | "typeinfo": "cpp" 48 | } 49 | } -------------------------------------------------------------------------------- /configure.sh: -------------------------------------------------------------------------------- 1 | # build sat solvers 2 | 3 | mkdir ./solvers/include 4 | 5 | cd ./solvers/include 6 | if [ ! -d "cadical" ]; then 7 | git clone https://github.com/arminbiere/cadical.git 8 | cd cadical 9 | make clean 10 | ./configure && make -j20 11 | cp build/libcadical.a ../ 12 | cp src/cadical.hpp ../ 13 | cd .. 14 | else 15 | cd cadical 16 | make clean 17 | ./configure && make -j20 18 | cp build/libcadical.a ../ 19 | cp src/cadical.hpp ../ 20 | cd .. 21 | fi 22 | 23 | if [ ! -d "libpoly" ]; then 24 | git clone https://github.com/SRI-CSL/libpoly.git 25 | cd libpoly/build 26 | cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$PWD/../../" 27 | make clean 28 | make -j20 29 | make install 30 | cd ../.. 31 | cp -r include/poly . 32 | cp libpoly/build/src/libpoly.a . 33 | cp libpoly/build/src/libpolyxx.a . 34 | cp libpoly/build/src/libpicpoly.a . 35 | cp libpoly/build/src/libpicpolyxx.a . 36 | else 37 | cd libpoly/build 38 | rm CMakeCache.txt 39 | cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="$PWD/../../" 40 | make clean 41 | make -j20 42 | make install 43 | cd ../.. 44 | cp -r include/poly . 45 | cp libpoly/build/src/libpoly.a . 46 | cp libpoly/build/src/libpolyxx.a . 47 | cp libpoly/build/src/libpicpoly.a . 48 | cp libpoly/build/src/libpicpolyxx.a . 49 | fi 50 | 51 | 52 | cd ../.. 53 | 54 | make clean 55 | make -j30 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BLAN 2 | BLAN: Bit-bLAsting solving Non-linear integer constraints. 3 | 4 | ### Getting Started 5 | 6 | ##### Setup 7 | Environment setup: 8 | - gcc/clang (support C++11/C++17) 9 | - cmake 10 | - make 11 | 12 | There are several dependence packages: 13 | - GMP (https://gmplib.org/) 14 | - BOOST (https://www.boost.org/) 15 | - LIBPOLY (https://github.com/SRI-CSL/libpoly) 16 | - CADICAL (https://github.com/arminbiere/cadical) 17 | 18 | Now, one can compile BLAN via: 19 | 20 | `./configure.sh` 21 | 22 | The command line will automatically build the tool (maybe `chmod +x configure.sh` first). It first builds CADICAL, the backend SAT solver, and then LIBPOLY, a library for manipulating polynomials, and finally builds BLAN. 23 | 24 | One can check parameters supported by the tool via 25 | ``` 26 | ./BLAN -h 27 | ``` 28 | The output is 29 | ``` 30 | BLAN test/1.smt2 (the smt-lib file to solve) 31 | -T:1200 (time limit (s), default 1200) 32 | -GA:true (Greedy Addtion, default true) 33 | -MA:true (Multiplication Adaptation, default true) 34 | -VO:true (Vote, default true) 35 | -Alpha:1536 (Alpha of Multiplication Adaptation, default 1536) 36 | -Beta:7 (Beta of Multiplication Adaptation, default 7) 37 | -K:16 (K of Clip, default 16) 38 | -Gamma:0.5 (Gamma of Vote, default 0.5) 39 | -DG:true (Distinct Graph, default true) 40 | -CM:true (Coefficient Matching, default true) 41 | -MaxBW:128 (Maximum Bit-Width, default 128) 42 | ``` 43 | 44 | Paper DOI 45 | ``` 46 | https://doi.org/10.1145/3597926.3598034 47 | ``` 48 | -------------------------------------------------------------------------------- /qfnia/qfnia.hpp: -------------------------------------------------------------------------------- 1 | /* qfnia.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _QFNIA_H 9 | #define _QFNIA_H 10 | 11 | // frontend 12 | #include "frontend/parser.hpp" 13 | // midend 14 | #include "midend/preprocessor.hpp" 15 | #include "midend/message.hpp" 16 | // backend 17 | #include "qfnia/info.hpp" 18 | #include "qfnia/collector.hpp" 19 | #include "qfnia/decider.hpp" 20 | #include "qfnia/resolver.hpp" 21 | #include "qfnia/searcher.hpp" 22 | 23 | // 2023-05-27 24 | #include "options.hpp" 25 | 26 | namespace ismt 27 | { 28 | // static poly::Context context(); 29 | const int maxVars = 256; 30 | class qfnia_solver{ 31 | private: 32 | DAG* data; 33 | bool used = false; 34 | std::string benchmark; 35 | State state = State::UNKNOWN; 36 | // midend 37 | preprocessor* prep = nullptr; 38 | // qfnia part 39 | Collector* collector = nullptr; 40 | Decider* decider = nullptr; 41 | Resolver* resolver = nullptr; 42 | Searcher* searcher = nullptr; 43 | public: 44 | qfnia_solver(); 45 | ~qfnia_solver(); 46 | void printModel(); 47 | // main function 48 | void init(Info* info); 49 | // int solve(const std::string& file); 50 | int solve(SolverOptions* option); 51 | }; 52 | } // namespace ismt 53 | 54 | 55 | #endif 56 | 57 | // Decide interval for variables, 58 | // if sat under ICP, then give constraints to blaster to solve, if sat then we get a model. 59 | // once unsat, try to resolve it via nlsat procedure and generate a lemma. -------------------------------------------------------------------------------- /utils/types.hpp: -------------------------------------------------------------------------------- 1 | /* types.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _TYPES_H 9 | #define _TYPES_H 10 | 11 | #include "utils/poly.hpp" 12 | #include 13 | 14 | namespace ismt 15 | { 16 | enum class State {UNKNOWN=-1, UNSAT, SAT}; 17 | // typedef poly::Integer Integer; 18 | typedef poly::Value Value; 19 | typedef mpz_class Integer; 20 | typedef mpq_class Rational; 21 | 22 | inline long to_long(const Value& v){ 23 | // assert(poly::is_integer(v)); 24 | poly::Integer i = poly::get_integer(v); 25 | return poly::to_int(i); 26 | } 27 | inline long to_long(const Integer& v){ 28 | // assert(poly::is_integer(v)); 29 | poly::Integer i(v); 30 | return poly::to_int(i); 31 | } 32 | inline Integer to_mpz(const Integer& v){ 33 | // assert(poly::is_integer(v)); 34 | poly::Integer i(v); 35 | return poly::to_int(i); 36 | } 37 | inline poly::Integer to_Integer(const Value& v){ 38 | // assert(poly::is_integer(v)); 39 | poly::Integer i = poly::get_integer(v); 40 | return i; 41 | } 42 | inline poly::Integer to_Integer(const Integer& v){ 43 | poly::Integer i(v); 44 | return i; 45 | } 46 | inline Value to_Value(const Integer& v){ 47 | poly::Integer i(v); 48 | return i; 49 | } 50 | inline Value to_Value(const poly::Integer& v){ 51 | return v; 52 | } 53 | inline Value to_Value(const long& v){ 54 | poly::Integer i(v); 55 | return i; 56 | } 57 | } // namespace ismt 58 | 59 | 60 | 61 | #endif -------------------------------------------------------------------------------- /solvers/blaster/blaster_bits.cpp: -------------------------------------------------------------------------------- 1 | /* blaster_bits.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/blaster/blaster_bits.hpp" 9 | #include 10 | using namespace ismt; 11 | 12 | 13 | // ------------bits operations------------ 14 | 15 | 16 | // operations related to bit length. 17 | namespace ismt 18 | { 19 | 20 | bool isPowerTwo(Integer num){ 21 | return getBitLength(num)!=-1; 22 | } 23 | int getBitLength(Integer num){ 24 | for(size_t i=0;icsize()csize()]; 55 | } 56 | Integer getUpBound(bvar var){ 57 | assert(var->csize()csize()]; 59 | } 60 | } // namespace ismt 61 | -------------------------------------------------------------------------------- /utils/disjoint_set.hpp: -------------------------------------------------------------------------------- 1 | /* disjoint_set.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _DISJOINT_SET_H 9 | #define _DISJOINT_SET_H 10 | 11 | #include 12 | #include 13 | 14 | namespace ismt 15 | { 16 | template 17 | class disjoint_set 18 | { 19 | private: 20 | T _st; 21 | T _ed; 22 | boost::unordered_map data; 23 | // boost::unordered_map ranks; 24 | public: 25 | disjoint_set(){} 26 | ~disjoint_set(){} 27 | 28 | void add(const T& x){ 29 | if(data.find(x)!=data.end()){ 30 | return; 31 | } 32 | else{ 33 | data[x] = x; 34 | // ranks[x] = 0; 35 | } 36 | } 37 | 38 | T find(T x){ 39 | if(data.find(x)==data.end()){ add(x); return x; } 40 | if(x == data[x]){ 41 | return x; 42 | } 43 | else{ 44 | data[x] = find(data[x]); 45 | return data[x]; 46 | } 47 | // return x == data[x]?x:data[x]=find(data[x]); 48 | } 49 | 50 | void union_set(T x, T y){ 51 | T rootx = find(x); 52 | T rooty = find(y); 53 | if(rootx!=rooty){ 54 | data[rootx] = rooty; // never changed the root node. 55 | } 56 | } 57 | 58 | bool Equal(T x, T y){ 59 | return find(x)==find(y); 60 | } 61 | 62 | void clear(){ 63 | data.clear(); 64 | } 65 | }; 66 | 67 | } // namespace ismt 68 | 69 | #endif -------------------------------------------------------------------------------- /solvers/blaster/blaster_bits.hpp: -------------------------------------------------------------------------------- 1 | /* blaster_bits.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _BLASTER_BITS_H 9 | #define _BLASTER_BITS_H 10 | #include "solvers/blaster/blaster_types.hpp" 11 | 12 | namespace ismt 13 | { 14 | const unsigned int BitsLen = 63; 15 | const Integer Bit2Data[] = { 16 | 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 17 | 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 18 | 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 19 | 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 20 | 4294967296, 8589934592, 17179869184, 34359738368, 68719476736, 137438953472, 21 | 274877906944, 549755813888, 1099511627776, 2199023255552, 4398046511104, 8796093022208, 22 | 17592186044416, 35184372088832, 70368744177664, 140737488355328, 281474976710656, 562949953421312, 23 | 1125899906842624, 2251799813685248, 4503599627370496, 9007199254740992, 18014398509481984, 36028797018963968, 24 | 72057594037927936, 144115188075855872, 288230376151711744, 576460752303423488, 1152921504606846976, 2305843009213693952, 25 | 4611686018427387904 // , 9223372036854775808 //, 18446744073709551616, 36893488147419103232 26 | }; 27 | 28 | // operations related to bit length. 29 | int getBitLength (Integer num); 30 | bool isPowerTwo (Integer num); 31 | unsigned divideZero (Integer num); 32 | unsigned compress (Integer& num); 33 | unsigned blastBitLength (Integer num); 34 | Integer getLowBound (bvar var); 35 | Integer getUpBound (bvar var); 36 | } // namespace ismt 37 | #endif -------------------------------------------------------------------------------- /utils/simp_vector.hpp: -------------------------------------------------------------------------------- 1 | /* simp_vector.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _SIMP_VECTOR_H 9 | #define _SIMP_VECTOR_H 10 | 11 | #include 12 | 13 | namespace ismt 14 | { 15 | // a vector that support minus index 16 | // once it is emplace_back zero_index ++ 17 | // a[-1] = a.data[zero_index-1] 18 | // a[1] = a.data[zero_index+1] 19 | template 20 | class simp_vector 21 | { 22 | private: 23 | T zero; 24 | std::vector positive; // +1 -> +oo 25 | std::vector negative; // -1 -> -oo 26 | size_t size = 0; 27 | public: 28 | simp_vector(){} 29 | simp_vector(size_t size){ 30 | positive.resize(size); 31 | negative.resize(size); 32 | } 33 | ~simp_vector(){} 34 | 35 | size_t size() const { return size; } 36 | void emplace_back(const T& t){ 37 | if(size == 0){ 38 | zero = t; ++size; return; 39 | } 40 | // insert front 41 | positive.emplace_back(t); 42 | // insert back 43 | negative.emplace_back(t); 44 | // duplicate the item 45 | size += 2; 46 | } 47 | 48 | T& operator[](int index){ 49 | assert(index >= -negative.size()); 50 | assert(index <= positive.size()); 51 | if(index > 0) return data[index-1]; 52 | else if(index < 0) return data[1-index]; 53 | else return zero; 54 | } 55 | 56 | T& operator[](int index) const { 57 | assert(index >= -negative.size()); 58 | assert(index <= positive.size()); 59 | if(index > 0) return data[index+1]; 60 | else if(index < 0) return data[1-index]; 61 | else zero; 62 | } 63 | }; 64 | 65 | } // namespace ismt 66 | -------------------------------------------------------------------------------- /solvers/blaster/blaster_transposition.cpp: -------------------------------------------------------------------------------- 1 | /* blaster_transposition.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/blaster/blaster_solver.hpp" 9 | 10 | using namespace ismt; 11 | 12 | 13 | // Transposition Abstraction: e.g. a > b <=> a - b > 0 14 | literal blaster_solver::TEqual(bvar var1, bvar var2){ 15 | bvar ans = Subtract(var1, var2); 16 | return EqZero(ans); 17 | } 18 | literal blaster_solver::TNotEqual(bvar var1, bvar var2){ 19 | bvar ans = Subtract(var1, var2); 20 | return NeqZero(ans); 21 | } 22 | literal blaster_solver::TGreater(bvar var1, bvar var2){ 23 | bvar ans = Subtract(var1, var2); 24 | return GtZero(ans); 25 | } 26 | literal blaster_solver::TGreaterEqual(bvar var1, bvar var2){ 27 | bvar ans = Subtract(var1, var2); 28 | return GeZero(ans); 29 | } 30 | literal blaster_solver::TEqualInt(bvar var, bvar v){ 31 | if(var->isConstant() && var->getCurValue()==0) return EqZero(v); 32 | else if(v->isConstant() && v->getCurValue()==0) return EqZero(var); 33 | bvar ans = Subtract(var, v); 34 | return EqZero(ans); 35 | } 36 | literal blaster_solver::TNotEqualInt(bvar var, bvar v){ 37 | if(var->isConstant() && var->getCurValue()==0) return NeqZero(v); 38 | else if(v->isConstant() && v->getCurValue()==0) return NeqZero(var); 39 | bvar ans = Subtract(var, v); 40 | return NeqZero(ans); 41 | } 42 | literal blaster_solver::TGreaterInt(bvar var, bvar v){ 43 | if(var->isConstant() && var->getCurValue() == 0) return LtZero(v); 44 | else if(v->isConstant() && v->getCurValue() == 0) return GtZero(var); 45 | bvar ans = Subtract(var, v); 46 | return GtZero(ans); 47 | } 48 | literal blaster_solver::TGreaterEqualInt(bvar var, bvar v){ 49 | if(var->isConstant() && var->getCurValue() == 0) return LeZero(v); 50 | else if(v->isConstant() && v->getCurValue() == 0) return GeZero(var); 51 | bvar ans = Subtract(var, v); 52 | return GeZero(ans); 53 | } -------------------------------------------------------------------------------- /qfnia/resolver.cpp: -------------------------------------------------------------------------------- 1 | /* resolver.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "qfnia/resolver.hpp" 9 | 10 | using namespace ismt; 11 | 12 | Resolver::Resolver(/* args */){} 13 | Resolver::~Resolver(){} 14 | 15 | void Resolver::init(Info* i){ 16 | info = i; 17 | parser = info->prep->parser; 18 | polyer = info->prep->polyer; 19 | nnfer = info->prep->nnfer; 20 | } 21 | 22 | dagc* Resolver::lemma(){ 23 | std::vector params; 24 | for(size_t i=0;imk_not(core[i])); 26 | } 27 | return parser->mk_or(params); 28 | } 29 | 30 | bool Resolver::is_hard(dagc* constraint){ 31 | if( constraint->isor() || constraint->isite() || 32 | constraint->isabs() || constraint->isdiv()){ 33 | return true; 34 | } 35 | else if(constraint->isvar() || constraint->isconst()) return false; 36 | else{ 37 | for(size_t i=0;ichildren.size();i++){ 38 | if(is_hard(constraint->children[i])) return true; 39 | } 40 | return false; 41 | } 42 | } 43 | bool Resolver::is_hard(std::vector& constraints){ 44 | // not an or 45 | for(size_t i=0;iconstraints)){ 60 | // cad_resolve(info->constraints); 61 | // } 62 | // else{ 63 | // auto it = info->assignment.begin(); 64 | // while(it != info->assignment.end()){ 65 | // core.emplace_back(it->first); 66 | // ++it; 67 | // } 68 | // } 69 | 70 | return true; 71 | } 72 | // bool Resolver::cad_resolve(std::vector& constraints){ 73 | // // cad projection 74 | 75 | 76 | // // make cell literals 77 | 78 | 79 | // // make backtrack level 80 | 81 | 82 | // // next check whether the conflict resolved. 83 | // return true; 84 | // } -------------------------------------------------------------------------------- /qfnia/info.hpp: -------------------------------------------------------------------------------- 1 | /* info.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _INFO_H 9 | #define _INFO_H 10 | 11 | #include "midend/message.hpp" 12 | #include "midend/preprocessor.hpp" 13 | #include "qfnia/collector.hpp" 14 | // 2023-05-27 15 | #include "options.hpp" 16 | #include 17 | 18 | namespace ismt 19 | { 20 | struct Info 21 | { 22 | State state = State::UNKNOWN; 23 | Message* message = nullptr; 24 | Collector* collector = nullptr; 25 | preprocessor* prep = nullptr; 26 | // 2023-05-27 27 | SolverOptions* options = nullptr; 28 | boost::unordered_map assignment; 29 | std::vector variables; 30 | std::vector constraints; 31 | std::vector assumptions; 32 | std::vector constraint_levels; 33 | std::vector assumption_levels; 34 | std::vector new_constraints; 35 | std::vector new_vars; 36 | 37 | // decide -> search -> unsat -> resolve -> decide 38 | // -> sat 39 | // -> unknown -> decide 40 | // -> sat 41 | bool resolve = false; // once resolve, reset the constraints and assignments 42 | 43 | Info(Message* m, Collector* c, preprocessor* pr, SolverOptions* opt): message(m), collector(c), prep(pr), options(opt){} 44 | ~Info(){} 45 | 46 | void print_constraints(){ 47 | for(size_t i=0;idata->printAST(constraints[i]); 50 | std::cout<& assumps){ 64 | // for(unsigned i=0;i 20 | #include 21 | 22 | namespace ismt 23 | { 24 | class sat_solver 25 | { 26 | private: 27 | CaDiCaL::Solver* solver = nullptr; 28 | 29 | std::string benchmark; 30 | std::string name; 31 | 32 | // solver state 33 | State state; 34 | 35 | // variable index 36 | unsigned iVars; 37 | unsigned iClauses; 38 | int SAT_False; 39 | int SAT_True; 40 | 41 | // cdcl(t) 42 | literals assumptions; 43 | 44 | // inner functions 45 | void setConst(); 46 | public: 47 | sat_solver(std::string n = "cadical"); 48 | ~sat_solver(); 49 | 50 | // get false 51 | bool_var False() const; 52 | bool_var True() const; 53 | 54 | // number of vars 55 | int nVars() const; 56 | int nClauses() const; 57 | 58 | 59 | // idx of current variables 60 | bool_var curVar() const; 61 | 62 | // add to solver 63 | int newVar(); 64 | int newVars(unsigned num); 65 | bool addClause(clause& c); 66 | 67 | // solve 68 | bool simplify(const literals& c); // means simple solve 69 | bool solve(); 70 | bool solve(const literals& aps); 71 | 72 | // state 73 | State getState() const; 74 | 75 | // model 76 | model getModel(); 77 | 78 | // reset 79 | void reset(); 80 | 81 | // benchmark setting 82 | void setBenchmark(std::string file); 83 | 84 | // cdcl(t) function 85 | bool propagate(); 86 | void partial(boost::unordered_map& m); 87 | int val(int lit); 88 | 89 | // get unsat assumptions 90 | void getConflict(literals& aps); 91 | }; 92 | 93 | } // namespace ismt 94 | 95 | 96 | #endif -------------------------------------------------------------------------------- /rewriters/prop_rewriter.hpp: -------------------------------------------------------------------------------- 1 | /* prop_rewriter.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _PROP_REWRITER_H 9 | #define _PROP_REWRITER_H 10 | 11 | #include "utils/model.hpp" 12 | #include "rewriters/nnf_rewriter.hpp" 13 | #include "rewriters/eq_rewriter.hpp" 14 | #include 15 | #include 16 | #include 17 | 18 | namespace ismt 19 | { 20 | // TODO, currently ite is not support 21 | class prop_rewriter: public rewriter 22 | { 23 | private: 24 | // rewriter 25 | nnf_rewriter* nnfer = nullptr; 26 | model_s* model; 27 | State state = State::UNKNOWN ; 28 | std::vector todo; // new assigned variables to propagate 29 | boost::unordered_set currents; // current propagating variables 30 | // boost::unordered_set top_comp; // top comp constaints, so default sat, if not it then false 31 | void rewriteComp(dagc* root, bool isTop, std::vector& res); 32 | bool evaluate(dagc* root, Integer& l, Integer& r); 33 | bool single(dagc*& rec, dagc* root, int& len); 34 | void convert(dagc* root, bool isTop, dagc* var, std::vector& res); 35 | void convertAbs(dagc* root, std::vector& res); 36 | // TODO these 3 important. 37 | void propagateTrue(dagc* root, std::vector& res); // the atom is true and propagate 38 | void propagateFalse(dagc* root, std::vector& res); // the atom is false and propagate 39 | void propagatePart(dagc* root, bool isTrue, std::vector& res); // the atom is isTrue and propagate 40 | void eval_rewrite(dagc*& root); // evaluate the atom via model and rewrite root 41 | void evaluatePoly(dagc*& root); 42 | // (= a b) -> false 43 | // if a -> false => not b -> false => b -> true 44 | // if a -> true => b -> false => b -> false 45 | // (= a c) -> false c = (...) 46 | // if a -> false => not c -> false 47 | // if a -> true => c -> true 48 | 49 | // down propagate the assigned value, up save the real value. 50 | public: 51 | prop_rewriter(Parser* p, model_s* m): rewriter(p), model(m) { 52 | data = &(p->dag); 53 | } 54 | ~prop_rewriter(){} 55 | void setNNF(nnf_rewriter* nr); 56 | void setTodo(); 57 | bool rewrite(); 58 | }; 59 | 60 | } // namespace ismt 61 | 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /midend/preprocessor.hpp: -------------------------------------------------------------------------------- 1 | /* preprocessor.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _PREPROCESSOR_H 9 | #define _PREPROCESSOR_H 10 | 11 | #include "frontend/dag.hpp" 12 | #include "frontend/parser.hpp" 13 | #include "utils/disjoint_set.hpp" 14 | #include "utils/feasible_set.hpp" 15 | 16 | #include "rewriters/nnf_rewriter.hpp" 17 | #include "rewriters/logic_rewriter.hpp" 18 | #include "rewriters/eq_rewriter.hpp" 19 | #include "rewriters/poly_rewriter.hpp" 20 | #include "rewriters/comp_rewriter.hpp" 21 | #include "rewriters/prop_rewriter.hpp" 22 | #include "rewriters/let_rewriter.hpp" 23 | 24 | #include "midend/message.hpp" 25 | #include "qfnia/collector.hpp" 26 | #include "solvers/eq/eq_solver.hpp" 27 | 28 | namespace ismt 29 | { 30 | // preprocess dag and store informations. 31 | class preprocessor 32 | { 33 | public: // now public 34 | // inner objects 35 | State state; 36 | 37 | // frontend objects 38 | DAG* data = nullptr; 39 | Parser* parser = nullptr; 40 | 41 | // rewriters 42 | nnf_rewriter* nnfer = nullptr; 43 | logic_rewriter* logicer = nullptr; 44 | eq_rewriter* eqer = nullptr; 45 | poly_rewriter* polyer = nullptr; 46 | comp_rewriter* comper = nullptr; 47 | prop_rewriter* proper = nullptr; 48 | let_rewriter* leter = nullptr; 49 | 50 | // backend theory collector 51 | Collector* thector = nullptr; 52 | 53 | // simple equal closure solver 54 | eq_solver* eqsver = nullptr; 55 | 56 | // interacting between frontend and backend. 57 | Message* message; 58 | bool simplified = false; // whether simplified. 59 | model_s* model = nullptr; 60 | 61 | void auto_set_model (); 62 | bool check(bool er); 63 | public: 64 | preprocessor(Parser* p, Collector* c, model_s* m); 65 | ~preprocessor(); 66 | 67 | // simplify: 68 | // 1. convert to nnf-like tree. 69 | // 2. eliminate logic operators. 70 | // 3. comp rewriting. 71 | // 4. model propagation rewriting. 72 | // 5. collect must, may bound and neq nodes with counting used variables. 73 | // 6. simplify unconstrainted variables. 74 | // 7. analyze each comp constraint and check bounds. 75 | // +8. leave a seat vacant for new idea. 76 | bool simplify(); 77 | void printAst(); 78 | 79 | Message* release(); // release message. 80 | }; 81 | 82 | } // namespace ismt 83 | 84 | 85 | #endif -------------------------------------------------------------------------------- /solvers/blaster/blaster_types.hpp: -------------------------------------------------------------------------------- 1 | /* blaster_types.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _BLASTER_TYPES_H 9 | #define _BLASTER_TYPES_H 10 | 11 | 12 | #include "utils/types.hpp" 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | namespace ismt 19 | { 20 | const int mask_constant = 1; 21 | const int mask_clear = 2; 22 | const int mask_zero = 4; 23 | class blast_variable 24 | { 25 | private: 26 | int info; 27 | Integer curValue; 28 | std::vector data; 29 | std::string name; 30 | public: 31 | blast_variable(const std::string& n, unsigned len, Integer v=0, bool isc=false){ 32 | setName(n); 33 | setSize(len); 34 | setCurValue(v); 35 | setKind(isc); 36 | setZero(); // default has zero. 37 | } 38 | ~blast_variable(){} 39 | 40 | // getter 41 | int signBit() const { return data[0]; } 42 | bool isConstant() const { return info & mask_constant; } 43 | bool isClean() const { return info & mask_clear; } 44 | bool hasZero() const { return info & mask_zero; } 45 | unsigned size() const { return data.size(); } 46 | unsigned csize() const { return data.size()-1; } // content size 47 | Integer getCurValue() const { return curValue; } 48 | int getAt(unsigned i) const { return data[i]; } 49 | std::string getName() const { return name; } 50 | 51 | // setter 52 | void setKind(bool isc) { if(isc) info |= mask_constant; else info &= ~mask_constant; } 53 | void setSize(unsigned len) { data.resize(len+1); } // for sign bit 54 | void setCurValue(Integer v) { curValue = v; } 55 | void setAt(size_t i, int v) { data[i] = v; } 56 | void setName(const std::string& n) { name = n; } 57 | void setZero() { info |= mask_zero; } 58 | void unsetZero() { info &= ~mask_zero; } 59 | 60 | // friend operations 61 | void reblast() { info &= ~mask_clear; } 62 | void clear() { data.clear(); info |= mask_clear; } // NEW 63 | // when staying at formula tree, once restart this of variable kind can be clear. 64 | 65 | }; 66 | 67 | typedef blast_variable* bvar; 68 | 69 | } // namespace ismt 70 | 71 | 72 | #endif -------------------------------------------------------------------------------- /solvers/eq/eq_solver.hpp: -------------------------------------------------------------------------------- 1 | /* eq_solver.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _SUB_REWRITER_H 9 | #define _SUB_REWRITER_H 10 | 11 | #include "frontend/dag.hpp" 12 | #include "rewriters/rewriter.hpp" 13 | #include "rewriters/eq_rewriter.hpp" 14 | #include "rewriters/poly_rewriter.hpp" 15 | #include "solvers/poly/poly_solver.hpp" 16 | #include "solvers/icp/icp_solver.hpp" 17 | #include "solvers/sat/sat_solver.hpp" 18 | #include "utils/model.hpp" 19 | 20 | // future use an abstract collector to isolate qfnia collector 21 | #include "qfnia/collector.hpp" 22 | 23 | namespace ismt 24 | { 25 | class eq_solver: public rewriter 26 | { 27 | private: 28 | model_s* model; 29 | State state = State::UNKNOWN; 30 | // checking 31 | boost::unordered_map*> subMap; 32 | 33 | // rewriters 34 | eq_rewriter* eqer = nullptr; 35 | poly_rewriter* polyer = nullptr; 36 | 37 | // solvers 38 | poly_solver* polyser = nullptr; 39 | icp_solver* icpser = nullptr; 40 | sat_solver* satser = nullptr; 41 | 42 | // theory collector 43 | Collector* thector = nullptr; 44 | 45 | 46 | // x + y + z / x*y*z 47 | void set(dagc* a, dagc* b); 48 | void rewrite(dagc* root); 49 | void collect(dagc* root); 50 | void collect(); 51 | bool checkEqAtoms(std::vector& closure); 52 | bool checkEqPolys(std::vector& closure); 53 | bool checkEqs(std::vector& closure); 54 | bool check(); // check the closure under equal operator 55 | public: 56 | eq_solver(Parser* p, model_s* m): rewriter(p), model(m) { 57 | data = &(p->dag); 58 | polyser = new poly_solver(); 59 | // icpser = new icp_solver(); 60 | satser = new sat_solver(); 61 | } 62 | ~eq_solver(){ 63 | auto it = subMap.begin(); 64 | while(it!=subMap.end()){ 65 | delete it->second; it->second = nullptr; 66 | ++it; 67 | } 68 | // delete icpser; icpser = nullptr; 69 | delete polyser; polyser = nullptr; 70 | } 71 | 72 | void setRewriters(eq_rewriter* eq, poly_rewriter* po); 73 | void setCollector(Collector* c); 74 | 75 | // 1. rewriting: 76 | // (= x (+ y 1)) (= z (+ x 1)) -> (= x (+ y 1)) (= z (+ y 2)) 77 | // (= x y) -> subsititute all x with y. 78 | // 2. solving: 79 | // (= x (+ y 1)) (= y (+ x 1)) -> (= y (+ y 1)) -> false 80 | // (!= y 0) (= x (* y y)) (= x (- (* y y))) -> (!= y 0) (= (* y y) (- (* y y))) -> false 81 | void rewrite(); // 1 82 | bool solve(); // 1 + 2 83 | }; 84 | 85 | } // namespace ismt 86 | 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /solvers/blaster/blaster_offset.hpp: -------------------------------------------------------------------------------- 1 | /* blaster_offset.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _BLASTER_OFFSET_H 9 | #define _BLASTER_OFFSET_H 10 | 11 | #include "utils/types.hpp" 12 | #include "utils/interval.hpp" 13 | #include "solvers/blaster/blaster_bits.hpp" 14 | 15 | namespace ismt 16 | { 17 | // if isDefault, blast(bits) -> var 18 | // else 19 | // if isLower, bound + blast(bits) -> var 20 | // else, bound - blast(bits) -> var 21 | struct offset 22 | { 23 | Integer bound; 24 | Integer width; 25 | bool isDefault; 26 | bool isLower; 27 | bool isSat; 28 | unsigned bits; 29 | offset(const Interval& interval, unsigned defaultLen){ 30 | if(isFull(interval)){ 31 | // (-oo, +oo) 32 | bound = 0; 33 | width = -1; 34 | isDefault = true; 35 | isLower = false; 36 | isSat = true; 37 | bits = defaultLen; 38 | } 39 | else if( isPoint(interval)){ 40 | // [lower, lower] 41 | bound = poly::to_int(getLower(interval)); 42 | width = 0; 43 | isDefault = false; 44 | isLower = true; 45 | isSat = true; 46 | bits = 0; 47 | } 48 | // else if(interval.isEmpty()){ 49 | // // [lower, lower] 50 | // bound = getLower(interval); 51 | // width = -1; 52 | // isDefault = false; 53 | // isLower = true; 54 | // isSat = false; 55 | // bits = 0; 56 | // } 57 | else if(ninf(interval)){ 58 | // (-oo, upper] 59 | bound = poly::to_int(getUpper(interval)); 60 | width = -1; 61 | isDefault = false; 62 | isLower = false; 63 | isSat = true; 64 | bits = defaultLen; 65 | } 66 | else if(pinf(interval)){ 67 | // [lower, +oo) 68 | bound = poly::to_int(getLower(interval)); 69 | width = -1; 70 | isDefault = false; 71 | isLower = true; 72 | isSat = true; 73 | bits = defaultLen; 74 | } 75 | else{ 76 | // [lower, upper] 77 | bound = poly::to_int(getLower(interval)); 78 | width = poly::to_int(getUpper(interval) - getLower(interval)); 79 | isDefault = false; 80 | isLower = true; 81 | isSat = true; 82 | bits = blastBitLength( poly::to_int(getUpper(interval) - getLower(interval)) ); 83 | } 84 | } 85 | }; 86 | } // namespace ismt 87 | 88 | 89 | #endif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled files 2 | *.o 3 | *.obj 4 | *.ko 5 | *.elf 6 | 7 | # linker output 8 | *.ilk 9 | *.map 10 | *.exp 11 | 12 | # executable files 13 | *.exe 14 | *.out 15 | *.app 16 | a.out 17 | 18 | # library files 19 | *.lib 20 | *.a 21 | *.la 22 | *.lo 23 | *.dll 24 | *.so 25 | *.so.* 26 | *.dylib 27 | 28 | # Qt related 29 | object_script.*.Release 30 | object_script.*.Debug 31 | *_plugin_import.cpp 32 | /.qmake.cache 33 | /.qmake.stash 34 | *.pro.user 35 | *.pro.user.* 36 | *.qbs.user 37 | *.qbs.user.* 38 | *.moc 39 | moc_*.cpp 40 | moc_*.h 41 | qrc_*.cpp 42 | ui_*.h 43 | *.qmlc 44 | *.jsc 45 | Makefile* 46 | *build-* 47 | *.qm 48 | *.prl 49 | 50 | # Qt Creator 51 | *.autosave 52 | 53 | # Qt unit tests 54 | target_wrapper.* 55 | 56 | # Visual Studio 57 | .vs/ 58 | *.vcxproj.user 59 | *.vcxproj.filters 60 | *.sln.docstates 61 | *.opensdf 62 | *.sdf 63 | *.cachefile 64 | *.VC.db 65 | *.VC.VC.opendb 66 | ipch/ 67 | *.aps 68 | *.ncb 69 | *.opendb 70 | *.opensdf 71 | *.sdf 72 | *.cachefile 73 | *.VC.db 74 | *.VC.VC.opendb 75 | 76 | # MinGW 77 | *.exe.manifest 78 | *.exe.intermediate.manifest 79 | 80 | # CMake 81 | CMakeLists.txt.user 82 | CMakeCache.txt 83 | CMakeFiles/ 84 | CMakeScripts/ 85 | Testing/ 86 | Makefile 87 | cmake_install.cmake 88 | install_manifest.txt 89 | compile_commands.json 90 | CTestTestfile.cmake 91 | _deps 92 | 93 | # Build directory 94 | build/ 95 | Build/ 96 | debug/ 97 | Debug/ 98 | release/ 99 | Release/ 100 | x64/ 101 | x86/ 102 | 103 | # Code::Blocks 104 | *.depend 105 | *.layout 106 | *.cbp 107 | 108 | # Dev-C++ 109 | *.dev 110 | 111 | # CLion 112 | .idea/ 113 | cmake-build-*/ 114 | 115 | # Conan 116 | conanfile.txt 117 | conaninfo.txt 118 | conanbuildinfo.cmake 119 | conanbuildinfo.txt 120 | 121 | # vcpkg 122 | vcpkg_installed/ 123 | 124 | # Debug and analysis files 125 | *.pdb 126 | *.pgc 127 | *.pgd 128 | *.rsp 129 | *.sbr 130 | *.tlb 131 | *.tli 132 | *.tlh 133 | *.tmp 134 | *.tmp_proj 135 | *_wpftmp.csproj 136 | *.log 137 | *.vspscc 138 | *.vssscc 139 | .builds 140 | *.pidb 141 | *.svclog 142 | *.scc 143 | 144 | # Chutzpah Test files 145 | _Chutzpah* 146 | 147 | # System generated files 148 | .DS_Store 149 | .DS_Store? 150 | ._* 151 | .Spotlight-V100 152 | .Trashes 153 | ehthumbs.db 154 | Thumbs.db 155 | 156 | # Linux 157 | *~ 158 | *.swp 159 | *.swo 160 | 161 | # Backup files 162 | *.bak 163 | *.gho 164 | *.ori 165 | *.orig 166 | *.tmp 167 | 168 | # Logs 169 | *.log 170 | 171 | # Runtime data 172 | pids 173 | *.pid 174 | *.seed 175 | *.pid.lock 176 | 177 | # Compressed files 178 | *.7z 179 | *.dmg 180 | *.gz 181 | *.iso 182 | *.jar 183 | *.rar 184 | *.tar 185 | *.zip 186 | 187 | # Test coverage 188 | coverage/ 189 | *.gcov 190 | *.gcno 191 | *.gcda 192 | 193 | # Valgrind 194 | *.memcheck 195 | 196 | # Doxygen 197 | doc/ 198 | docs/ 199 | 200 | # include solvers 201 | solvers/include/ 202 | 203 | # executable files 204 | BLAN -------------------------------------------------------------------------------- /solvers/blaster/blaster_transformer.hpp: -------------------------------------------------------------------------------- 1 | /* blaster_transformer.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _BLASTER_TRANSFORMER_H 9 | #define _BLASTER_TRANSFORMER_H 10 | 11 | #include "frontend/dag.hpp" 12 | #include "solvers/blaster/blaster_solver.hpp" 13 | 14 | // 2023-05-27 15 | #include "options.hpp" 16 | 17 | namespace ismt 18 | { 19 | // helper for transforming dag formula to bv. 20 | // it is a default transformer. blaster_solver has mkHolder/blast... 21 | class blaster_transformer 22 | { 23 | private: 24 | /* data */ 25 | blaster_solver* solver; 26 | // bool try_split = true; 27 | 28 | // map dagc* to inner representation. 29 | boost::unordered_map BoolMap; 30 | boost::unordered_map BoolLetMap; 31 | boost::unordered_map BoolFunMap; 32 | boost::unordered_map BoolOprMap; 33 | boost::unordered_map VarMap; 34 | boost::unordered_map IntMap; 35 | boost::unordered_map OprMap; 36 | boost::unordered_map NumLetMap; 37 | boost::unordered_map IntFunMap; 38 | 39 | // declare a int to blaster 40 | void declareInt(dagc* root); 41 | bvar getInt(dagc* root); 42 | bvar getLetNum(dagc* root); 43 | int getLetBool(dagc* root); 44 | int getBool(dagc* root); 45 | 46 | // declare a bool to blaster 47 | void declareBool(dagc* root); 48 | 49 | // transform 50 | int doAtoms(dagc* dag); 51 | int doMathAtoms(dagc* dag); 52 | int doLetAtoms(dagc* dag); 53 | bvar doIteNums(dagc* dag); 54 | bvar doMathTerms(dagc* dag); 55 | bvar doLetNum(dagc* dag); 56 | bool isFree(Integer lower, bool a_open, Integer upper, bool b_open); 57 | int split(Integer lower, bool a_open, Integer upper, bool b_open); 58 | int split_lower(Integer lower, bool a_open, Integer upper, bool b_open); 59 | int split_middle(Integer lower, bool a_open, Integer upper, bool b_open); 60 | void _declare(dagc* root, unsigned bit); 61 | 62 | public: 63 | blaster_transformer(blaster_solver* s){ solver = s; } 64 | ~blaster_transformer(){} 65 | 66 | // 2023-05-27 67 | bool GA = true; 68 | 69 | // transform a constraint to blaster 70 | int transform(dagc* root); 71 | 72 | // declare a var to blaster 73 | void _declare(dagc* root, Integer lower, bool a_open, Integer upper, bool b_open); 74 | void _declare(dagc* root); 75 | int _assert(dagc* root); 76 | 77 | // clear variables 78 | void reset(blaster_solver* s); 79 | void reset(); 80 | }; 81 | 82 | 83 | } // namespace ismt 84 | 85 | #endif -------------------------------------------------------------------------------- /utils/interval.hpp: -------------------------------------------------------------------------------- 1 | /* interval.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _INTERVAL_H 9 | #define _INTERVAL_H 10 | 11 | #include "utils/types.hpp" 12 | #include 13 | 14 | namespace ismt 15 | { 16 | typedef poly::Interval Interval; 17 | const Interval FullInterval(Value::minus_infty(), Value::plus_infty()); 18 | const Interval EmptyInterval(0, 0); 19 | inline bool ninf(const Interval& a){ 20 | return poly::is_minus_infinity(poly::get_lower(a)); 21 | } 22 | inline bool pinf(const Interval& b){ 23 | return poly::is_plus_infinity(poly::get_upper(b)); 24 | } 25 | inline bool isFull(const Interval& i){ 26 | return poly::is_full(i); 27 | } 28 | inline bool isPoint(const Interval& i){ 29 | return poly::is_point(i); 30 | } 31 | // inline bool isEmpty(const Interval& i){ 32 | 33 | // return false; 34 | // } 35 | inline poly::Integer getUpper(const Interval& i){ 36 | return to_Integer(poly::get_upper(i)); 37 | } 38 | inline poly::Integer getLower(const Interval& i){ 39 | // std::cout< getRealUpper(b)) return false; // [0, 3] and [-3, -2]. 51 | return true; 52 | } 53 | inline bool has(const Interval& i, const poly::Integer& k){ 54 | return ( 55 | ( ninf(i) && pinf(i) ) || 56 | ( ninf(i) && getUpper(i) >= k ) || 57 | ( pinf(i) && getLower(i) <= k ) || 58 | ( getLower(i) <= k && getUpper(i) >= k ) 59 | ); 60 | } 61 | inline poly::Integer get_inner_value(const Interval& i, bool& flag){ 62 | flag = true; 63 | if(isFull(i)){ 64 | return poly::Integer(0); 65 | } 66 | else if(ninf(i)){ 67 | poly::Integer u = getRealUpper(i); 68 | return u; 69 | } 70 | else if(pinf(i)){ 71 | poly::Integer l = getRealLower(i); 72 | return l; 73 | } 74 | poly::Integer l = getRealLower(i); 75 | poly::Integer u = getRealUpper(i); 76 | poly::Integer One = poly::Integer(1); 77 | 78 | if(l > u){ 79 | flag = false; 80 | return poly::Integer(0); 81 | } 82 | else if(l == u){ 83 | return l; 84 | } 85 | else{ 86 | return l + One; 87 | } 88 | } 89 | } // namespace ismt 90 | 91 | 92 | #endif -------------------------------------------------------------------------------- /qfnia/searcher.cpp: -------------------------------------------------------------------------------- 1 | /* searcher.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "qfnia/searcher.hpp" 9 | 10 | using namespace ismt; 11 | 12 | #define assertDebug 0 13 | #define statusDebug 0 14 | 15 | Searcher::Searcher(){ 16 | solver = new blaster_solver(); 17 | transformer = new blaster_transformer(solver); 18 | } 19 | Searcher::~Searcher(){ 20 | delete transformer; transformer = nullptr; 21 | delete solver; solver = nullptr; 22 | } 23 | 24 | void Searcher::init(Info* i){ 25 | info = i; 26 | // declare the assigned variable 27 | std::vector vars; 28 | info->message->model->getAssignedVars(vars); 29 | for(unsigned i=0;iGA = info->options->GA; 33 | } 34 | 35 | void Searcher::_declare(dagc* root){ 36 | if(root->isvnum()){ 37 | if(root->isAssigned()){ 38 | transformer->_declare(root, root->v, false, root->v, false); 39 | } 40 | else{ 41 | Interval i(info->assignment[root]); 42 | transformer->_declare(root, 43 | to_long(getLower(i)), 44 | poly::get_lower_open(i), 45 | to_long(getUpper(i)), 46 | poly::get_upper_open(i)); 47 | } 48 | } 49 | else if(root->isvbool()){ 50 | transformer->_declare(root); 51 | } 52 | } 53 | int Searcher::_assert(dagc* root){ 54 | return transformer->_assert(root); 55 | } 56 | bool Searcher::search(){ 57 | // check whether it is needed to re-transform 58 | // if not modify the former constraints and not change the assignment 59 | // i.e. append / delete constraints -> not re-transform 60 | // i.e. not resolve 61 | for(unsigned i=0;inew_vars.size();i++){ 62 | _declare(info->new_vars[i]); 63 | } 64 | if(info->new_constraints.size() == 0) return true; 65 | #if assertDebug 66 | std::cout<<"----------------------searching----------------------"<new_constraints.size();i++){ 69 | #if assertDebug 70 | info->message->data->printAST(info->new_constraints[i]); 71 | std::cout<constraints.emplace_back(info->new_constraints[i]); 74 | info->assumptions.emplace_back(_assert(info->new_constraints[i])); 75 | } 76 | info->new_vars.clear(); 77 | info->new_constraints.clear(); 78 | #if statusDebug 79 | solver->printStatus(); 80 | #endif 81 | 82 | // solve 83 | bool ans = solver->solve(info->assumptions); 84 | if(ans){ 85 | info->state = State::SAT; 86 | return true; 87 | } 88 | return false; 89 | } 90 | void Searcher::set_model(){ 91 | for(size_t i=0;ivariables.size();i++){ 92 | dagc* var = info->variables[i]; 93 | info->message->model->set(var, solver->getValue(var->name)); 94 | } 95 | } 96 | void Searcher::reset(){ 97 | solver->reset(); 98 | transformer->reset(); 99 | // declare the assigned variable 100 | std::vector vars; 101 | info->message->model->getAssignedVars(vars); 102 | for(unsigned i=0;iFalse(); 18 | if(var1->isConstant()&&var2->isConstant()){ 19 | return var1->getCurValue() < var2->getCurValue()?solver->True():solver->False(); 20 | } 21 | assert(!var1->isConstant() || !var2->isConstant()); 22 | 23 | if(var1->isConstant() || var2->isConstant()){ 24 | return viGt(var2, var1); 25 | } 26 | else{ 27 | return vvGt(var2, var1); 28 | } 29 | } 30 | literal blaster_solver::Equal(bvar var1, bvar var2){ 31 | if(var1==var2) return solver->True(); 32 | if(var1->isConstant()&&var2->isConstant()){ 33 | return var1->getCurValue() == var2->getCurValue()?solver->True():solver->False(); 34 | } 35 | assert(!var1->isConstant() || !var2->isConstant()); 36 | 37 | if(var1->isConstant() || var2->isConstant()){ 38 | return viEq(var1, var2); 39 | } 40 | else{ 41 | return vvEq(var1, var2); 42 | } 43 | } 44 | literal blaster_solver::Greater(bvar var1, bvar var2){ // var1 > var2 45 | if(var1==var2) return solver->False(); 46 | if(var1->isConstant()&&var2->isConstant()){ 47 | return var1->getCurValue() > var2->getCurValue()?solver->True():solver->False(); 48 | } 49 | assert(!var1->isConstant() || !var2->isConstant()); 50 | 51 | if(var1->isConstant() || var2->isConstant()){ 52 | return viGt(var1, var2); 53 | } 54 | else{ 55 | return vvGt(var1, var2); 56 | } 57 | } 58 | literal blaster_solver::NotEqual(bvar var1, bvar var2){ 59 | if(var1==var2) return solver->False(); 60 | if(var1->isConstant()&&var2->isConstant()){ 61 | return var1->getCurValue() != var2->getCurValue()?solver->True():solver->False(); 62 | } 63 | assert(!var1->isConstant() || !var2->isConstant()); 64 | 65 | if(var1->isConstant() || var2->isConstant()){ 66 | return viNeq(var1, var2); 67 | } 68 | else{ 69 | return vvNeq(var1, var2); 70 | } 71 | } 72 | literal blaster_solver::LessEqual(bvar var1, bvar var2){ // var1 <= var2 73 | if(var1==var2) return solver->True(); 74 | if(var1->isConstant()&&var2->isConstant()){ 75 | return var1->getCurValue() <= var2->getCurValue()?solver->True():solver->False(); 76 | } 77 | assert(!var1->isConstant() || !var2->isConstant()); 78 | 79 | if(var1->isConstant() || var2->isConstant()){ 80 | return viGe(var2, var1); 81 | } 82 | else{ 83 | return vvGe(var2, var1); 84 | } 85 | } 86 | literal blaster_solver::GreaterEqual(bvar var1, bvar var2){ 87 | if(var1==var2) return solver->True(); 88 | if(var1->isConstant()&&var2->isConstant()){ 89 | return var1->getCurValue() >= var2->getCurValue()?solver->True():solver->False(); 90 | } 91 | assert(!var1->isConstant() || !var2->isConstant()); 92 | 93 | if(var1->isConstant() || var2->isConstant()){ 94 | return viGe(var1, var2); 95 | } 96 | else{ 97 | return vvGe(var1, var2); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /utils/graph.hpp: -------------------------------------------------------------------------------- 1 | /* graph.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _GRAPH_H 9 | #define _GRAPH_H 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace ismt 17 | { 18 | 19 | class HeadNode 20 | { 21 | private: 22 | int index; 23 | public: 24 | HeadNode(int i):index(i){} 25 | ~HeadNode(){} 26 | 27 | std::list neighbors; 28 | 29 | // insertion sort 30 | void addNeighbor(int val){ 31 | std::list::iterator it = neighbors.begin(); 32 | if(*(neighbors.begin()) > val){ neighbors.insert(neighbors.begin(), val); return; } 33 | while(it!=neighbors.end()){ 34 | if((*it) == val) return; 35 | else if((*it) val){ neighbors.insert(it, val); return; } 38 | --it; 39 | } 40 | ++it; 41 | } 42 | neighbors.emplace_back(val); 43 | return; 44 | } 45 | 46 | size_t size() const { return neighbors.size(); } 47 | }; 48 | 49 | template 50 | class Graph 51 | { 52 | private: 53 | int index = 0; 54 | std::vector data; 55 | std::vector names; 56 | boost::unordered_map NameMap; 57 | public: 58 | Graph(){} 59 | ~Graph(){ 60 | for(size_t i=0;i(n, tmp)); 73 | data.emplace_back(t); 74 | names.emplace_back(n); 75 | return tmp; 76 | } 77 | } 78 | 79 | size_t size() const { return data.size(); } 80 | size_t size(int v) const { return data[v]->size(); } 81 | size_t size(const name& n) { 82 | if(NameMap.find(n)!=NameMap.end()){ 83 | int tmp = NameMap[n]; 84 | return data[tmp]->size(); 85 | } 86 | else return 0; 87 | } 88 | 89 | void addEdge(const name& n1, const name& n2){ 90 | int node1 = -1, node2 = -1; 91 | if(NameMap.find(n1)!=NameMap.end()) node1 = NameMap[n1]; 92 | else node1 = newNode(n1); 93 | if(NameMap.find(n2)!=NameMap.end()) node2 = NameMap[n2]; 94 | else node2 = newNode(n2); 95 | 96 | data[node1]->addNeighbor(node2); 97 | } 98 | 99 | void print(){ 100 | for(size_t i=0;i::iterator it = data[i]->neighbors.begin(); 103 | while(it!=data[i]->neighbors.end()){ 104 | std::cout<<*it<<" "; 105 | ++it; 106 | } 107 | std::cout< varMap; 25 | std::vector compPolyList; 26 | boost::unordered_map compPolyMap; // dagc* -> comp poly index -> poly::Polynomial 27 | 28 | std::string ite_name(dagc* root); 29 | std::string abs_name(dagc* root); 30 | 31 | void toPolynomial(dagc* root, poly::Polynomial& p); 32 | dagc* toMonomial(dagc* var, unsigned d); 33 | 34 | dagc* toConstant(Integer& c); 35 | dagc* toVar(unsigned v); 36 | dagc* toTerm(unsigned t); 37 | dagc* toMono(unsigned m); 38 | dagc* toPoly(unsigned p); 39 | 40 | // get coeff of monomial 41 | Integer coeff(dagc* root); 42 | // negate the polymomial 43 | dagc* negate(dagc* root); 44 | // split into two part 45 | void split(dagc* pres, dagc*& lres, dagc*& rres); 46 | int count_let_node(dagc* root, bool& support); 47 | public: 48 | poly_rewriter(Parser* p): rewriter(p) { 49 | zeroPolynomial = poly::Polynomial(context, 0); 50 | epm = new ep_manager(context); 51 | std::vector vars; 52 | // set integer variables 53 | for(size_t i=0;idag.vnum_int_list.size();i++){ 54 | dagc* var = parser->dag.vnum_int_list[i]; 55 | vars.emplace_back(var->name); 56 | vdagcMap.insert(std::pair(var->name, var)); 57 | } 58 | epm->set_variables(vars); 59 | } 60 | ~poly_rewriter(){} 61 | 62 | // nest polynomial 63 | bool isMonomial(poly::Polynomial& p); 64 | poly::Value monomialCoefficient(poly::Polynomial& p); 65 | poly::Value toValue(poly::Polynomial& p); 66 | 67 | poly::Polynomial zeroPoly(); 68 | poly::Polynomial constZeroPoly(); 69 | poly::Polynomial rewrite(dagc* root); 70 | 71 | // to dagc 72 | dagc* toDagc(const poly::Polynomial& p); 73 | dagc* getMainVar(const poly::Polynomial& p); 74 | void getVars(const poly::Polynomial& p, std::vector& res); 75 | void get_comp_polynomial(dagc* root, poly::Polynomial& p); 76 | 77 | // transform: both have positive coefficients 78 | // e.g. x - y > 0 -> x > y 79 | dagc* transform(dagc* root, poly::Polynomial& res); 80 | 81 | poly::Context& get_context(){ return context; } 82 | 83 | poly::Variable* get_var(dagc* var); 84 | 85 | bool not_support(dagc* root); 86 | 87 | public: 88 | boost::unordered_map polyMap; // dagc* -> poly index -> poly::Polynomial 89 | boost::unordered_map vdagcMap; // variable name -> dagc* 90 | boost::unordered_map epMap; // polynomial map 91 | boost::unordered_map epMonoMap; // monomial map 92 | boost::unordered_map epTermMap; // term map 93 | boost::unordered_map epVarMap; // variable map 94 | // boost::unordered_map spVars; // special variables (ite/abs) 95 | 96 | // expand polynomial 97 | ep_manager* epm; // for bit blasting 98 | }; 99 | 100 | } // namespace ismt 101 | 102 | 103 | #endif -------------------------------------------------------------------------------- /solvers/blaster/blaster_logic.cpp: -------------------------------------------------------------------------------- 1 | /* blaster_logic.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/blaster/blaster_solver.hpp" 9 | 10 | using namespace ismt; 11 | 12 | #include 13 | 14 | 15 | // ------------logic operations------------ 16 | literal blaster_solver::Not(const literal& l){ 17 | if(l==Lit_True()) return Lit_False(); 18 | else if(l==-Lit_True()) return Lit_True(); 19 | else if(l==Lit_False()) return Lit_True(); 20 | else if(l==-Lit_False()) return Lit_False(); 21 | return -l; 22 | } 23 | literal blaster_solver::And(const literal& lit1, const literal& lit2){ 24 | literals lits{ lit1, lit2 }; 25 | return And(lits); 26 | } 27 | literal blaster_solver::Or(const literal& lit1, const literal& lit2){ 28 | literals lits{ lit1, lit2 }; 29 | return Or(lits); 30 | } 31 | literal blaster_solver::And(const literals& lits){ 32 | assert(lits.size()>0); 33 | // simplify, except for -x and x 34 | literals copy_lits(lits); std::sort(copy_lits.begin(), copy_lits.end()); 35 | literals ans; 36 | for(size_t i=0;iTrue()) continue; 38 | else if(copy_lits[i]==-solver->False()) continue; 39 | else if(copy_lits[i]==solver->False()) return solver->False(); 40 | else if(copy_lits[i]==-solver->True()) return solver->False(); 41 | else if(i!=0&©_lits[i]==copy_lits[i-1]) continue; 42 | else ans.emplace_back(copy_lits[i]); 43 | } 44 | if(ans.size()==0) return solver->True(); 45 | else if(ans.size()==1) return ans[0]; 46 | 47 | bool_var t = newSatVar(); 48 | 49 | // t -> a /\ b <=> ~t \/ a /\ ~t \/ b 50 | for(size_t i=0;i t <=> t \/ ~a \/ ~b 58 | clause c; 59 | c.emplace_back(t); 60 | for(size_t i=0;i0); 69 | // simplify, except for -x and x 70 | literals copy_lits(lits);std::sort(copy_lits.begin(), copy_lits.end()); 71 | literals ans; 72 | for(size_t i=0;iTrue()) return solver->True(); 74 | if(copy_lits[i]==-solver->False()) return solver->True(); 75 | else if(copy_lits[i]==solver->False()) continue; 76 | else if(copy_lits[i]==-solver->True()) continue; 77 | else if(i!=0&©_lits[i]==copy_lits[i-1]) continue; 78 | else ans.emplace_back(copy_lits[i]); 79 | } 80 | if(ans.size()==0) return solver->False(); 81 | else if(ans.size()==1) return ans[0]; 82 | 83 | bool_var t = newSatVar(); 84 | 85 | // t -> a \/ b <=> ~t \/ a \/ b 86 | clause c; 87 | c.emplace_back(-t); 88 | for(size_t i=0;i t <=> ~a \/ t /\ ~b \/ t 94 | c.clear(); 95 | for(size_t i=0;iTrue()) return ifp; 107 | else if(cond==solver->False()) return elp; 108 | else if(ifp==elp) return ifp; 109 | 110 | bool_var t = newSatVar(); 111 | bool_var teqi = EqualBit(t, ifp); 112 | bool_var teqe = EqualBit(t, elp); 113 | 114 | // cond -> teqi 115 | clause c; 116 | c.emplace_back(-cond); 117 | c.emplace_back(teqi); 118 | addClause(c); 119 | 120 | // ~cond -> teqe 121 | c.clear(); 122 | c.emplace_back(cond); 123 | c.emplace_back(teqe); 124 | addClause(c); 125 | 126 | // teqi \/ teqe 127 | c.clear(); 128 | c.emplace_back(teqi); 129 | c.emplace_back(teqe); 130 | addClause(c); 131 | 132 | return t; 133 | } 134 | 135 | -------------------------------------------------------------------------------- /solvers/eq/eq_solver.cpp: -------------------------------------------------------------------------------- 1 | /* eq_solver.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/eq/eq_solver.hpp" 9 | 10 | using namespace ismt; 11 | 12 | void eq_solver::set(dagc* a, dagc* b){ 13 | if(subMap.find(a)!=subMap.end()){ 14 | std::vector* t = subMap[a]; 15 | t->emplace_back(b); 16 | } 17 | else{ 18 | std::vector* t = new std::vector(); 19 | t->emplace_back(b); 20 | subMap.insert(std::pair*>(a, t)); 21 | } 22 | } 23 | void eq_solver::collect(dagc* root){ 24 | if(root->isnumop() || root->isvar() || root->isconst()) return; 25 | else if(root->iseq() || root->iseqbool()){ 26 | dagc* a = root->children[0]; 27 | dagc* b = root->children[1]; 28 | 29 | // swap 30 | if(b->isvar()){ 31 | dagc* t = a; 32 | a = b; 33 | b = t; 34 | } 35 | 36 | if(a->isvar()){ 37 | // prop rewriter guarantees !b->isvar() 38 | assert(!b->isvar()); 39 | set(a, b); 40 | if(b->isnumop()){ 41 | set(a, b); 42 | } 43 | else if(b->isboolop()){ 44 | set(a, b); 45 | } 46 | else assert(false); 47 | } 48 | else return; // nothing to do 49 | } 50 | else{ 51 | for(size_t i=0;ichildren.size();i++){ 52 | collect(root->children[i]); 53 | } 54 | } 55 | } 56 | void eq_solver::collect(){ 57 | auto it = data->assert_list.begin(); 58 | while(it!=data->assert_list.end()){ 59 | collect(*it); 60 | ++it; 61 | } 62 | } 63 | void eq_solver::rewrite(dagc* root){ 64 | auto it = root->children.begin(); 65 | while(it!=root->children.end()){ 66 | if((*it)->isvar()){ 67 | dagc* parent = model->getSubRoot(*it); 68 | if (parent != *it){ 69 | *it = parent; 70 | } 71 | } 72 | else{ 73 | rewrite(*it); 74 | } 75 | ++it; 76 | } 77 | } 78 | void eq_solver::rewrite(){ 79 | auto it = data->assert_list.begin(); 80 | while(it!=data->assert_list.end()){ 81 | if((*it)->isvbool()){ 82 | dagc* parent = model->getSubRoot(*it); 83 | if (parent != *it){ 84 | *it = parent; 85 | } 86 | } 87 | else{ 88 | rewrite(*it); 89 | } 90 | ++it; 91 | } 92 | } 93 | 94 | 95 | void eq_solver::setRewriters(eq_rewriter* eq, poly_rewriter* po){ 96 | eqer = eq; polyer = po; 97 | } 98 | void eq_solver::setCollector(Collector* c){ thector = c; } 99 | 100 | // bool eq_solver::checkEqAtoms(std::vector& closure){ 101 | // } 102 | // bool eq_solver::checkEqPolys(std::vector& closure){ 103 | // } 104 | // bool eq_solver::checkEqs(std::vector& closure){ 105 | // if(closure[0]->isvbool()){ 106 | // if(!checkEqAtoms(closure)) return false; 107 | // else{ 108 | // satser->reset(); 109 | // return true; 110 | // } 111 | // } 112 | // else{ 113 | // // closure[0]->isvnum() 114 | // return checkEqPolys(closure); 115 | // } 116 | // } 117 | 118 | bool eq_solver::check(){ 119 | // 0) simplify 120 | // k*x == y && y == k*z 121 | // -> y == k*z && k*x == k*z 122 | // -> y == k*z && x == z (final) 123 | // prop rewriter guarantees both x, z are no constants 124 | 125 | // 1) (= x (+ y 1)) (= y (+ x 1)) -> (= y (+ y 1)) -> false 126 | // 2) (!= y 0) (= x (* y y)) (= x (- (* y y))) -> (= (* y y) (- (* y y))) -> false 127 | // use 2*y*y = 0 -> y = 0, but y=0 not in collector's feasible set. 128 | 129 | // auto it = subMap.begin(); 130 | // while(it!=subMap.end()){ 131 | // std::vector* t = it->second; 132 | // t->emplace(t->begin(), it->first); 133 | // if(checkEqs(*t)){ 134 | // state = State::UNSAT; 135 | // return false; 136 | // } 137 | // ++it; 138 | // } 139 | 140 | return true; 141 | } 142 | bool eq_solver::solve(){ 143 | collect(); 144 | if(!check()) return false; 145 | rewrite(); 146 | return true; 147 | } -------------------------------------------------------------------------------- /solvers/icp/icp_solver.cpp: -------------------------------------------------------------------------------- 1 | /* icp_solver.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/icp/icp_solver.hpp" 9 | 10 | using namespace ismt; 11 | 12 | 13 | icp_solver::icp_solver(poly_rewriter* p):polyer(p){ 14 | data = new poly::IntervalAssignment(p->get_context()); 15 | controller = new sat_solver(); 16 | } 17 | icp_solver::~icp_solver(){ 18 | delete controller; controller = nullptr; 19 | delete data; data = nullptr; 20 | } 21 | 22 | bool icp_solver::isEasyComp(dagc* c){ 23 | return c->children[0]->isvnum() && c->children[1]->isvnum(); 24 | } 25 | bool icp_solver::easyComp(dagc* c){ 26 | Interval a(data->get(*(polyer->get_var(c->children[0])))); 27 | Interval b(data->get(*(polyer->get_var(c->children[1])))); 28 | if(c->iseq()){ 29 | return overlap(a, b); 30 | } 31 | else if(c->isneq()){ 32 | return !(poly::is_point(a) && poly::is_point(b) && getRealLower(a) == getRealLower(b)); 33 | 34 | } 35 | else if(c->isge()){ 36 | // a >= b 37 | return !(!pinf(a) && !ninf(b) && getRealUpper(a) < getRealLower(b)); 38 | } 39 | else if(c->isgt()){ 40 | // a > b 41 | return !(!pinf(a) && !ninf(b) && getRealUpper(a) <= getRealLower(b)); 42 | } 43 | else if(c->isle()){ 44 | // a <= b 45 | return !(!ninf(a) && !pinf(b) && getRealLower(a) > getRealUpper(b)); 46 | } 47 | else if(c->islt()){ 48 | // a < b 49 | return !(!ninf(a) && !pinf(b) && getRealLower(a) >= getRealUpper(b)); 50 | } 51 | else assert(false); 52 | return false; 53 | } 54 | // solving functions 55 | bool icp_solver::evaluate(dagc* c){ 56 | if(c->iscomp()){ 57 | // escape this case 58 | if(polyer->not_support(c)) return true; 59 | if(isEasyComp(c)){ 60 | return easyComp(c); 61 | } 62 | poly::Polynomial pres(polyer->get_context()); 63 | polyer->get_comp_polynomial(c, pres); 64 | Interval res(poly::evaluate(pres, *data)); 65 | if(c->iseq()){ 66 | return poly::sgn(res) == 0; // contains 0 67 | } 68 | else if(c->isneq()){ 69 | // [-2, 3] or [1, 3] 70 | return (poly::sgn(res) == 0 && !poly::is_point(res)) || poly::sgn(res) != 0; 71 | } 72 | else if(c->islt()){ 73 | return (poly::sgn(res) == 0 && !poly::is_point(res)) || poly::sgn(res) < 0; 74 | } 75 | else if(c->isle()){ 76 | return poly::sgn(res) <= 0; 77 | } 78 | else if(c->isgt()){ 79 | return (poly::sgn(res) == 0 && !poly::is_point(res)) || poly::sgn(res) > 0; 80 | } 81 | else if(c->isge()){ 82 | return poly::sgn(res) >= 0; 83 | } 84 | else assert(false); 85 | } 86 | else if(c->isite()){ 87 | assert(false); 88 | } 89 | else{ 90 | if(c->isand()){ 91 | for(unsigned i=0;ichildren.size();i++){ 92 | if(!evaluate(c->children[i])) return false; 93 | } 94 | return true; 95 | } 96 | else if(c->isor()){ 97 | for(unsigned i=0;ichildren.size();i++){ 98 | if(evaluate(c->children[i])) return true; 99 | } 100 | return false; 101 | } 102 | else if(c->isnot()){ 103 | if(!evaluate(c->children[0])) return true; 104 | else return false; 105 | } 106 | else {c->print(); assert(false);} 107 | } 108 | return true; 109 | } 110 | State icp_solver::check(std::vector& cs){ 111 | stored_core.clear(); 112 | for(unsigned i=0;iiscomp() && !evaluate(cs[i])){ 114 | return State::UNSAT; 115 | } 116 | else stored_core.emplace_back(cs[i]); 117 | } 118 | return State::SAT; 119 | } 120 | // unsat core if failed -> lemma 121 | void icp_solver::core(std::vector& cores){ 122 | cores.clear(); 123 | cores.assign(stored_core.begin(), stored_core.end()); 124 | } 125 | // add operations 126 | void icp_solver::assign(dagc* var, const poly::Interval& v){ 127 | poly::Variable* variable = polyer->get_var(var); 128 | data->set(*variable, v); 129 | } 130 | 131 | void icp_solver::reset(){ 132 | data->clear(); 133 | } -------------------------------------------------------------------------------- /rewriters/logic_rewriter.cpp: -------------------------------------------------------------------------------- 1 | /* logic_rewriter.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "rewriters/logic_rewriter.hpp" 9 | 10 | using namespace ismt; 11 | 12 | void logic_rewriter::rewrite(dagc* root){ 13 | if(root->isand()){ 14 | // and-and-and-... -> and 15 | std::vector::iterator it = root->children.begin(); 16 | std::vector rep; 17 | while(it!=root->children.end()){ 18 | if( (*it)->isand() ){ 19 | std::vector lres; 20 | andRecord(*it, lres); 21 | if(lres.size()>0){ 22 | for(size_t i=0;iisor() ){ 30 | rep.emplace_back(*it); 31 | rewrite(*it); // and-or 32 | ++it; 33 | } 34 | else{ 35 | rep.emplace_back(*it); 36 | ++it; // next 37 | } 38 | } 39 | root->children.clear(); 40 | root->children.assign(rep.begin(), rep.end()); 41 | } 42 | else if(root->isor()){ 43 | // or-or-or-... -> or 44 | std::vector::iterator it = root->children.begin(); 45 | std::vector rep; 46 | while(it!=root->children.end()){ 47 | if( (*it)->isor() ){ 48 | std::vector lres; 49 | orRecord(*it, lres); 50 | if(lres.size()>0){ 51 | for(size_t i=0;iisand() ){ 59 | rep.emplace_back(*it); 60 | rewrite(*it); // or-and 61 | ++it; 62 | } 63 | else{ 64 | rep.emplace_back(*it); 65 | ++it; // next 66 | } 67 | } 68 | root->children.clear(); 69 | root->children.assign(rep.begin(), rep.end()); 70 | } 71 | else{ 72 | std::vector::iterator it = root->children.begin(); 73 | while(it!=root->children.end()){ 74 | rewrite(*it); 75 | ++it; 76 | } 77 | } 78 | } 79 | 80 | void logic_rewriter::andRecord(dagc* root, std::vector& res){ 81 | if(root->isand()){ 82 | // and-and-and-... -> and 83 | for(size_t i=0;ichildren.size();i++){ 84 | if(root->children[i]->isand()){ 85 | andRecord(root->children[i], res); 86 | } 87 | else{ 88 | res.emplace_back(root->children[i]); 89 | } 90 | } 91 | } 92 | } 93 | 94 | void logic_rewriter::orRecord(dagc* root, std::vector& res){ 95 | // or-or-or-... -> or 96 | for(size_t i=0;ichildren.size();i++){ 97 | if(root->children[i]->isor()){ 98 | orRecord(root->children[i], res); 99 | } 100 | else{ 101 | res.emplace_back(root->children[i]); 102 | } 103 | } 104 | } 105 | 106 | void logic_rewriter::rewrite(){ 107 | // 1) eliminate top and 108 | auto it = data->assert_list.begin(); 109 | std::vector rep; 110 | while(it!=data->assert_list.end()){ 111 | std::vector res; 112 | andRecord(*it, res); 113 | if(res.size()>0){ 114 | for(size_t i=0;iassert_list.clear(); 125 | data->assert_list.assign(rep.begin(), rep.end()); 126 | // 2) eliminate the others. 127 | it = data->assert_list.begin(); 128 | while(it!=data->assert_list.end()){ 129 | assert(!(*it)->isand()); // never and 130 | rewrite(*it); // rewrite all, e.g. (= x (or (or x y) z)) 131 | ++it; 132 | } 133 | } -------------------------------------------------------------------------------- /solvers/sat/sat_solver.cpp: -------------------------------------------------------------------------------- 1 | /* sat_solver.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/sat/sat_solver.hpp" 9 | #include 10 | 11 | using namespace ismt; 12 | #define printClauses 0 13 | #define printModel 0 14 | 15 | sat_solver::sat_solver(std::string n){ 16 | name = n; 17 | state = State::UNKNOWN; 18 | solver = new CaDiCaL::Solver(); 19 | 20 | setConst(); 21 | } 22 | sat_solver::~sat_solver(){ 23 | delete solver; 24 | solver = nullptr; 25 | } 26 | void sat_solver::setConst(){ 27 | solver->set("log", 1); 28 | SAT_False = 1, SAT_True = 2, iVars = 3; 29 | // false literal 30 | solver->add(-1); 31 | solver->add(0); 32 | // true literal 33 | solver->add(2); 34 | solver->add(0); 35 | iClauses = 2; 36 | } 37 | bool_var sat_solver::False() const { 38 | return SAT_False; 39 | } 40 | bool_var sat_solver::True() const { 41 | return SAT_True; 42 | } 43 | bool_var sat_solver::curVar() const{ 44 | return iVars; 45 | } 46 | 47 | // number of vars 48 | int sat_solver::nVars() const{ 49 | return iVars-1; 50 | } 51 | // number of clauses 52 | int sat_solver::nClauses() const{ 53 | return iClauses; 54 | } 55 | 56 | // add to solver 57 | int sat_solver::newVar(){ 58 | return iVars++; 59 | } 60 | int sat_solver::newVars(unsigned num){ 61 | iVars+=num; 62 | return iVars; 63 | } 64 | bool sat_solver::addClause(clause& c){ 65 | 66 | #if printClauses 67 | std::cout<<"add clause: "; 68 | for(size_t i=0;iadd(c[i]); 76 | } 77 | solver->add(0); 78 | ++iClauses; 79 | 80 | return true; 81 | } 82 | 83 | // solve 84 | bool sat_solver::simplify(const literals& c){ 85 | return solve(c); 86 | } 87 | bool sat_solver::solve(){ 88 | int ans = solver->solve(); 89 | if(ans==10) state = State::SAT; 90 | else if(ans==20) state = State::UNSAT; 91 | else state = State::UNKNOWN; 92 | return true; 93 | } 94 | bool sat_solver::solve(const literals& aps){ 95 | assumptions.clear(); 96 | for(size_t i=0;iassume(aps[i]); 99 | } 100 | return solve(); 101 | } 102 | 103 | // state 104 | State sat_solver::getState() const{ 105 | return state; 106 | } 107 | 108 | // model 109 | model sat_solver::getModel(){ 110 | model t; 111 | 112 | if(state==State::SAT){ 113 | t.emplace_back(0); // place holder for index of 0 114 | for(unsigned i=1;ival(i)>0?1:0); 116 | #if printModel 117 | std::cout<limit("decisions", 0); 149 | return solver->solve(); 150 | } 151 | 152 | void sat_solver::partial(boost::unordered_map& m){ 153 | for(size_t i=1;i(i, i)); 156 | } 157 | else if(val(i)==-(int)i){ 158 | m.insert(std::pair(i, -i)); 159 | } 160 | } 161 | } 162 | int sat_solver::val(int lit){ 163 | return solver->val(lit); 164 | } 165 | 166 | // get unsat assumptions 167 | void sat_solver::getConflict(literals& aps){ 168 | for(size_t i=0;ifailed(assumptions[i])){ 170 | aps.emplace_back(assumptions[i]); 171 | } 172 | } 173 | } -------------------------------------------------------------------------------- /utils/rational.hpp: -------------------------------------------------------------------------------- 1 | /* rational.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _RATIONAL_H 9 | #define _RATIONAL_H 10 | 11 | namespace ismt 12 | { 13 | typedef mpz_class Integer; 14 | class rational 15 | { 16 | private: 17 | /* data */ 18 | Integer numerator(0), 19 | public: 20 | // constructors 21 | rational():numerator(0), denominator(1) { } 22 | rational(const integert &i):numerator(i), denominator(1) { } 23 | rational(int i):numerator(i), denominator(1) { } 24 | 25 | integert get_numerator() const 26 | { 27 | return numerator; 28 | } 29 | 30 | integert get_denominator() const 31 | { 32 | return denominator; 33 | } 34 | 35 | rational &operator+=(const rational &n) 36 | { 37 | rational tmp(n); 38 | same_denominator(tmp); 39 | numerator+=tmp.numerator; 40 | normalize(); 41 | return *this; 42 | } 43 | 44 | rational &operator-=(const rational &n) 45 | { 46 | rational tmp(n); 47 | same_denominator(tmp); 48 | numerator-=tmp.numerator; 49 | normalize(); 50 | return *this; 51 | } 52 | 53 | rational &operator*=(const rational &n) 54 | { 55 | numerator*=n.numerator; 56 | denominator*=n.denominator; 57 | normalize(); 58 | return *this; 59 | } 60 | 61 | rational &operator/=(const rational &n) 62 | { 63 | assert(!n.numerator.is_zero()); 64 | numerator*=n.denominator; 65 | denominator*=n.numerator; 66 | normalize(); 67 | return *this; 68 | } 69 | 70 | bool operator==(const rational &n) const 71 | { 72 | rational r1(*this), r2(n); 73 | r1.same_denominator(r2); 74 | return r1.numerator==r2.numerator; 75 | } 76 | 77 | bool operator!=(const rational &n) const 78 | { 79 | rational r1(*this), r2(n); 80 | r1.same_denominator(r2); 81 | return r1.numerator!=r2.numerator; 82 | } 83 | 84 | bool operator<(const rational &n) const 85 | { 86 | rational r1(*this), r2(n); 87 | r1.same_denominator(r2); 88 | return r1.numerator=(const rational &n) const 99 | { 100 | return !(*this(const rational &n) const 104 | { 105 | return !(*this<=n); 106 | } 107 | 108 | bool is_zero() const 109 | { return numerator.is_zero(); } 110 | 111 | bool is_negative() const 112 | { return !is_zero() && numerator.is_negative(); } 113 | 114 | void invert(); 115 | void negate() { numerator.negate(); } 116 | 117 | friend rational operator+(const rational &a, const rational &b) 118 | { 119 | rational tmp(a); 120 | tmp+=b; 121 | return tmp; 122 | } 123 | 124 | friend rational operator-(const rational &a, const rational &b) 125 | { 126 | rational tmp(a); 127 | tmp-=b; 128 | return tmp; 129 | } 130 | 131 | friend rational operator-(const rational &a) 132 | { 133 | rational tmp(a); 134 | tmp.negate(); 135 | return tmp; 136 | } 137 | 138 | friend rational operator*(const rational &a, const rational &b) 139 | { 140 | rational tmp(a); 141 | tmp*=b; 142 | return tmp; 143 | } 144 | 145 | friend rational operator/(const rational &a, const rational &b) 146 | { 147 | rational tmp(a); 148 | tmp/=b; 149 | return tmp; 150 | } 151 | 152 | friend std::ostream& operator<< (std::ostream& out, const rational &a); 153 | }; 154 | 155 | } // namespace ismt 156 | 157 | 158 | #endif 159 | 160 | -------------------------------------------------------------------------------- /rewriters/comp_rewriter.hpp: -------------------------------------------------------------------------------- 1 | /* comp_rewriter.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _COMP_REWRITER_H 9 | #define _COMP_REWRITER_H 10 | 11 | #include "utils/poly.hpp" 12 | #include "utils/interval.hpp" 13 | #include "rewriters/rewriter.hpp" 14 | #include "rewriters/eq_rewriter.hpp" 15 | #include "rewriters/poly_rewriter.hpp" 16 | 17 | namespace ismt 18 | { 19 | // equal: 20 | // 1) no-add-mul: 21 | // x = 3 -> x = 3 22 | // 2) only add: 23 | // x + 1 = 3 -> x = 2 24 | // 3) only mul: 25 | // 3*x = 3 -> x = 1 26 | // 3*x = 4 -> false 27 | // 3*x*y = 0 -> x = 0 \/ y = 0 28 | // 3*x*y = 3 -> x*y = 1 // (not implement) -> (x = 1 /\ y = 1) \/ (x = -1 /\ y = -1) 29 | // 4) add-mul: (c!=0, d in (-oo, +oo)) 30 | // 3*x + 1 = 4 -> 3*x = 3 -> x = 1, 3*x + 1 = 5 -> 3*x = 4 -> false 31 | // 3*(x + 1) = 3 -> x + 1 = 1 -> x = 0 32 | // x*y + (-1)*x*y = 0 -> 0 = 0 -> true. 33 | // x*y + x*y = 0 -> 2*x*y = 0 -> x*y = 0 -> x = 0 \/ y = 0 34 | // x*y + y*z = 0 -> x*y = - y*z -> y = 0 \/ x = -z 35 | // x*y + (-1)*y*z = 0 -> x*y = y*z -> y = 0 \/ x = z 36 | // x*y + (-1)*x*y = c -> 0 = c -> false. 37 | // x*y + x*y = c -> 2*x*y = c -> x*y = c // 2 38 | // x*y + y*z = c -> x*y + y*z = c 39 | // u*v + x*y + y*z = d -> u*v + x*y + y*z = d 40 | // u*v + x*y + (-1)*y*z = d -> u*v + x*y = y*z +d (minus -> transposition) 41 | 42 | // neq: 43 | // 1) no-add-mul: 44 | // x != 3 -> x != 3 45 | // 2) only add: 46 | // x + 1 != 3 -> x != 2 47 | // 3) only mul: 48 | // 3*x = 3 -> x = 1 49 | // 3*x = 4 -> false 50 | // 3*x*y = 0 -> x = 0 \/ y = 0 51 | // 3*x*y = 3 -> x*y = 1 // (not implement) -> (x = 1 /\ y = 1) \/ (x = -1 /\ y = -1) 52 | // 4) add-mul: (c!=0, d in (-oo, +oo)) 53 | // 3*x + 1 = 4 -> 3*x = 3 -> x = 1, 3*x + 1 = 5 -> 3*x = 4 -> false 54 | // 3*(x + 1) = 3 -> x + 1 = 1 -> x = 0 55 | // x*y + (-1)*x*y = 0 -> 0 = 0 -> true. 56 | // x*y + x*y = 0 -> 2*x*y = 0 -> x*y = 0 -> x = 0 \/ y = 0 57 | // x*y + y*z = 0 -> x*y = - y*z -> y = 0 \/ x = -z 58 | // x*y + (-1)*y*z = 0 -> x*y = y*z -> y = 0 \/ x = z 59 | // x*y + (-1)*x*y = c -> 0 = c -> false. 60 | // x*y + x*y = c -> 2*x*y = c -> x*y = c // 2 61 | // x*y + y*z = c -> x*y + y*z = c 62 | // u*v + x*y + y*z = d -> u*v + x*y + y*z = d 63 | // u*v + x*y + (-1)*y*z = d -> u*v + x*y = y*z +d (minus -> transposition) 64 | 65 | 66 | // x > 3 -> x > 3 67 | // x + 1 > 3 -> x > 2 68 | // 3*x*y == 9 -> x*y = 3 69 | // 3*x*y == 0 -> x = 0 \/ y = 0 70 | // x + y + 3 > 4 -> x + y > 1 71 | // 3*x*y + 3 = 3 -> 3*x*y = 0 -> x = 0 \/ y = 0 72 | // 12 + (-1)*x < 0 -> x > 12 73 | // 12 + (-1)*x + (-1)*y < 0 -> x + y > 12 74 | 75 | class comp_rewriter: public rewriter 76 | { 77 | private: 78 | bool curIsTop = false; 79 | // bool integer = true; 80 | poly::Context context; 81 | 82 | poly_rewriter* polyer = nullptr; 83 | eq_rewriter* eqer = nullptr; 84 | 85 | private: 86 | // void transposit(poly::Polynomial& p, poly::Polynomial& ls, poly::Polynomial& rs); 87 | dagc* eq_rewrite(poly::Polynomial& lhs, poly::Polynomial& rhs); 88 | dagc* le_rewrite(poly::Polynomial& lhs, poly::Polynomial& rhs); 89 | dagc* lt_rewrite(poly::Polynomial& lhs, poly::Polynomial& rhs); 90 | dagc* ge_rewrite(poly::Polynomial& lhs, poly::Polynomial& rhs); 91 | dagc* gt_rewrite(poly::Polynomial& lhs, poly::Polynomial& rhs); 92 | dagc* neq_rewrite(poly::Polynomial& lhs, poly::Polynomial& rhs); 93 | 94 | // helper function 95 | dagc* univariate_eq(poly::Polynomial& p); 96 | dagc* univariate_comp(poly::Polynomial& p, bool g, bool e); 97 | 98 | void roots_isolate_int(poly::Polynomial& p, std::vector& rets); 99 | void roots_isolate_comp_int(poly::Polynomial& p, bool g, bool e, std::vector& rets); 100 | 101 | void roots_isolate(poly::Polynomial& p, std::vector& rets); 102 | void roots_isolate_compt(poly::Polynomial& p, bool g, bool e, std::vector& rets); 103 | 104 | bool evaluate(poly::UPolynomial& up, bool g, bool e, poly::Integer& val); 105 | 106 | bool isSimpleComp(dagc* root); 107 | bool isNormForm(dagc* root); 108 | // x*y*z = 0 -> x = 0 \/ y = 0 \/ z = 0. 109 | dagc* eqZero(dagc* var); 110 | dagc* orEqZero(std::vector vars); 111 | dagc* andEqZero(std::vector vars); 112 | dagc* rewrite(dagc* root, bool isTop = true); 113 | 114 | public: 115 | comp_rewriter(Parser* p, poly_rewriter* po, eq_rewriter* eq); 116 | ~comp_rewriter(); 117 | 118 | // make name 119 | bool rewrite(); 120 | }; 121 | 122 | } // namespace ismt 123 | 124 | 125 | #endif -------------------------------------------------------------------------------- /qfnia/qfnia.cpp: -------------------------------------------------------------------------------- 1 | /* qfnia.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "qfnia/qfnia.hpp" 9 | #include "qfnia/checker.hpp" 10 | using namespace ismt; 11 | 12 | #define doCheck 0 13 | 14 | qfnia_solver::qfnia_solver(){} 15 | qfnia_solver::~qfnia_solver(){ 16 | if(used){ 17 | delete data; data = nullptr; 18 | delete prep; prep = nullptr; 19 | delete collector; collector = nullptr; 20 | delete decider; decider = nullptr; 21 | delete resolver; resolver = nullptr; 22 | delete searcher; searcher = nullptr; 23 | } 24 | } 25 | 26 | void qfnia_solver::init(Info* info){ 27 | decider = new Decider(); 28 | searcher = new Searcher(); 29 | resolver = new Resolver(); 30 | decider->init(info); 31 | searcher->init(info); 32 | resolver->init(info); 33 | } 34 | 35 | // main function 36 | int qfnia_solver::solve(SolverOptions* option){ 37 | std::string file = option->File; 38 | used = true; 39 | data = new DAG(); 40 | 41 | benchmark = file; 42 | model_s* model = new model_s(); 43 | 44 | // parse the file 45 | // std::cout<<"new parser start"<simplify(); 54 | if(ans){ 55 | if(prep->state == State::SAT){ 56 | std::cout<<"sat"<get_model){ 58 | Message* message = prep->release(); 59 | message->print_model(); 60 | } 61 | return 0; 62 | } 63 | } 64 | else{ 65 | std::cout<<"unsat"<release(); 70 | // model->print(); 71 | // message->print_constraints(); 72 | 73 | // start to solve 74 | Info* info = new Info(message, collector, prep, option); 75 | init(info); 76 | // model->print_partial(); 77 | 78 | // main loop 79 | while(true){ 80 | while(decider->decide()){} 81 | if(decider->conflict()){ 82 | // decide with bit blasting overflow 83 | // std::cout<<"unknown"<search()){ 89 | if(!resolver->resolve()){ 90 | state = State::UNSAT; 91 | break; 92 | } 93 | else{ 94 | if(resolver->has_lemma()) message->constraints.insert(message->constraints.begin(), resolver->lemma()); // add lemma in the front 95 | // must increment 96 | decider->increment(); 97 | searcher->reset(); 98 | } 99 | } 100 | else{ 101 | if(decider->done()) break; 102 | } 103 | } 104 | 105 | // int bound = 100; 106 | // int cnt = 0; 107 | // while(true){ 108 | // if(decider->decide()){ 109 | // ++cnt; 110 | // } 111 | // if(decider->conflict()){ 112 | // // decide with bit blasting overflow 113 | // std::cout<<"to do, conflict"<= bound){ 118 | // if(!searcher->search()){ 119 | // if(!resolver->resolve()){ 120 | // state = State::UNSAT; 121 | // break; 122 | // } 123 | // else{ 124 | // if(resolver->has_lemma()) message->constraints.insert(message->constraints.begin(), resolver->lemma()); // add lemma in the front 125 | // // must increment 126 | // decider->increment(); 127 | // searcher->reset(); 128 | // } 129 | // } 130 | // else{ 131 | // if(decider->done()) break; 132 | // } 133 | // cnt = 0; 134 | // } 135 | // } 136 | 137 | 138 | if(info->state==State::SAT){ 139 | searcher->set_model(); 140 | std::cout<<"sat"<get_model) message->print_model(); 142 | #if doCheck 143 | checker ch(info); 144 | if(ch.check()){ 145 | std::cout<<"check sat"<state==State::UNKNOWN){ 153 | std::cout<<"unknown"< 15 | #include 16 | 17 | namespace ismt 18 | { 19 | // search box decider 20 | typedef unsigned dvar; 21 | 22 | struct priority{ 23 | dagc* var; 24 | unsigned value; 25 | priority(dagc* v):var(v){} 26 | ~priority(){} 27 | bool operator<(const priority& p){ 28 | return value < p.value; 29 | } 30 | }; 31 | 32 | struct watch{ 33 | dagc* atom = nullptr; 34 | int count = 0; 35 | int origin = 0; 36 | watch(dagc* a):atom(a){} 37 | ~watch(){} 38 | void assign(){ --count; } 39 | void unassign(){ ++count; } 40 | bool is_ok(){ return count == 0; } 41 | void set_origin(){ origin = count; } 42 | void reset(){ count = origin; } 43 | }; 44 | 45 | struct watchers{ 46 | priority* var = nullptr; 47 | std::vector data; 48 | watchers(dagc* v){ 49 | var = new priority(v); 50 | } 51 | ~watchers(){ 52 | delete var; var = nullptr; 53 | } 54 | bool operator<(const watchers& w){ 55 | return var->value > w.var->value; 56 | } 57 | size_t size() const { return data.size(); } 58 | }; 59 | 60 | class Decider 61 | { 62 | private: 63 | bool b_conflict = false; 64 | unsigned max_width = 32; 65 | unsigned nvars = 0; 66 | unsigned def_width = 2; // 2 2022-05-18; 3 2022-06-01 67 | unsigned re_factor = 1; 68 | int number_clip = 4; 69 | int voted = 0; // 0 -> not do; 1 -> done but not used; 2 -> done and used 70 | int bit_vote = 0; 71 | float vote_bound = 0.5; 72 | boost::unordered_map candidate_bit; 73 | boost::unordered_map phase_bit; 74 | int rephase_factor = 4; // rephase factor 75 | std::vector mul_bound; 76 | std::vector start_bit; 77 | std::vector re_factor_bit; 78 | std::vector rephase_bit; 79 | bool is_done = false; 80 | Info* info = nullptr; 81 | icp_solver* icp = nullptr; 82 | poly::IntervalAssignment* data = nullptr; 83 | std::vector atom_pool; 84 | // atom -> index 85 | boost::unordered_map atom_map; 86 | std::vector assignment; 87 | boost::unordered_map assign_index; 88 | std::vector watch_pool; 89 | // var -> watchers index 90 | boost::unordered_map watch_map; 91 | std::vector current; 92 | 93 | std::vector trail; 94 | std::vector levels; 95 | 96 | void collect (dagc* cur, dagc* top); 97 | void collect_unconstrained_vars (); 98 | void watch_atom (dagc* cur); 99 | bool assign (dagc* var); 100 | bool too_big (dagc* cur); 101 | 102 | int max_mul_esc_icp = 128; 103 | void count_mul (dagc* cur, int& val); 104 | // void find_max_var_level (std::vector& cs, int& value); 105 | 106 | int get_atom_i (dagc* atom); 107 | int get_watchers_i (dagc* var); 108 | watch* get_atom (unsigned index); 109 | watchers* get_watchers (unsigned index); 110 | watch* get_atom (dagc* atom); 111 | watchers* get_watchers (dagc* var); 112 | Interval mk_interval (unsigned i); 113 | Interval mk_interval (const poly::Integer& value, unsigned i, bool is_lower); 114 | void assign_full (dagc* xvar); 115 | void assign_bit (int bit); 116 | 117 | bool backtrack (std::vector& cs); 118 | bool re_assign (dagc* xvar); 119 | void collect_vars (dagc* cur, boost::unordered_set& vars); 120 | int get_candidate_bit(dagc* xvar, bool zero = true); 121 | 122 | // default bit width 123 | std::vector default_widths; 124 | 125 | public: 126 | Decider (); 127 | ~Decider (); 128 | 129 | bool propagate (std::vector& cs); 130 | // bool backtrack (std::vector& cs); 131 | void init (Info* i); 132 | 133 | bool decide (); 134 | bool done (); 135 | 136 | void resort (); 137 | void increment (); 138 | void vote (); 139 | void increment (const unsigned& idx); 140 | bool conflict () const; 141 | int get_bit (dagc* xvar); 142 | }; 143 | 144 | } // namespace ismt 145 | 146 | 147 | #endif 148 | 149 | // decide done. 150 | // Number of variables: 82982 151 | // Number of clauses: 246074 152 | // assert done... 153 | // literals: 234109 154 | // clauses: 930035 -------------------------------------------------------------------------------- /qfnia/collector.hpp: -------------------------------------------------------------------------------- 1 | /* collector.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _COLLECTOR_HPP 9 | #define _COLLECTOR_HPP 10 | 11 | #include "frontend/parser.hpp" 12 | #include "rewriters/rewriter.hpp" 13 | #include "utils/model.hpp" 14 | #include "utils/feasible_set.hpp" 15 | #include "utils/graph.hpp" 16 | #include "utils/disjoint_set.hpp" 17 | #include 18 | 19 | namespace ismt 20 | { 21 | class Collector: public rewriter 22 | { 23 | public: 24 | 25 | State state = State::UNKNOWN; 26 | 27 | // graph objects 28 | Graph mustNeqGraph; // must node neq-graph 29 | Graph MayNeqGraph; // may node neq-graph 30 | std::vector mustNodes; // list for must nodes. 31 | std::vector mayBNodes; // list for may bound nodes. 32 | // used times of variables 33 | boost::unordered_map used; // collect used times. 34 | 35 | // integer variables and their feasible sets 36 | boost::unordered_map variables; // must bound 37 | boost::unordered_map mvariables; // may bound 38 | // 100*x + y = 10 -> MaxNumber[x] = 0, MaxNumber[y] = 100 39 | boost::unordered_map MaxNumber; // abs max number met 40 | boost::unordered_map bits; // candidate bits (distinct graph) 41 | boost::unordered_map mul_var_count; // count linear/non-linear mul node of variable 42 | 43 | // disjoint_set of expr 44 | disjoint_set subSet; // if must sat, -n2*n6+n18 = 0 -> n18 = n2*n6. 45 | 46 | boost::unordered_set unused_vars; // record unused variables and for future set model 47 | 48 | private: 49 | model_s* model = nullptr; 50 | int max_number_bound = 32; // ignore the constraint with x nodes. 51 | // collect must, may and neq nodes + rewriting comp. 52 | bool collect(dagc* root, bool must = true); // entry of collecting must, may and neq nodes. 53 | void collectNeq(dagc* root, bool must = false); // only to find neq. 54 | void collectMax(dagc* root); // abs max number met 55 | void collectMaxC(dagc* root, boost::unordered_map& dimap); // set the max number of variable in the same constraint 56 | void collectMaxCMul(dagc* root, boost::unordered_set& vars, Integer& maximum); // set the max number of variable in mul 57 | 58 | // analyze each comp constraint 59 | bool isTrivialComp(dagc* root); 60 | bool isSimpleComp(dagc* root); 61 | bool isEasyIte(dagc* root); // ite ? 1 0 62 | bool setEasyIte(dagc* a, dagc* b); // b is easy ite 63 | // 0: false; x: the number of variables. 64 | int isOrInterval(dagc* root); 65 | void doOrInterval(dagc* root); 66 | bool setBound(dagc* d, dagc* var, 67 | Integer ans, bool must); // set bound for var 68 | bool analyze(dagc* root, bool isTop = true); // analyze each comp constraint 69 | void addInterval(dagc* var, bool must, 70 | const Interval& interval, bool neq = false); // add interval to message 71 | bool doIntervalLit(dagc* root, bool isTop = true); // deal with interval literal 72 | 73 | void collect(); 74 | bool removeVars(); 75 | bool analyze(); 76 | bool check(); // check must sat node at first. 77 | bool set_model(); 78 | unsigned int usedTimes(dagc* var); 79 | int count_node(dagc* root); 80 | int count_mul(dagc* root); 81 | int count_add(dagc* root); 82 | int count_var(dagc* root); 83 | public: 84 | 85 | Collector(Parser* p, model_s* m): rewriter(p), model(m){ 86 | // init 87 | for(size_t i=0;ivbool_list.size();i++){ 88 | used.insert(std::pair(data->vbool_list[i], 0)); 89 | } 90 | for(size_t i=0;ivnum_int_list.size();i++){ 91 | used.insert(std::pair(data->vnum_int_list[i], 0)); 92 | } 93 | for(size_t i=0;ivnum_real_list.size();i++){ 94 | used.insert(std::pair(data->vnum_real_list[i], 0)); 95 | } 96 | } 97 | ~Collector(){ 98 | // delete 99 | auto it = variables.begin(); 100 | while(it!=variables.end()){ 101 | delete it->second; 102 | it->second = nullptr; 103 | ++it; 104 | } 105 | it = mvariables.begin(); 106 | while(it!=mvariables.end()){ 107 | delete it->second; 108 | it->second = nullptr; 109 | ++it; 110 | } 111 | } 112 | // collect useful informations 113 | // 1. distinct graph 114 | // 2. must/may sat constraints 115 | bool rewrite(); 116 | int get_must_distinct_bit(dagc* var); 117 | int get_may_distinct_bit(dagc* var); 118 | int get_max_number_bit(dagc* var); 119 | int get_max_number_count(); 120 | int get_may_constraint_bit(dagc* var); 121 | int get_var_mul_count(dagc* var); 122 | int count_mul(); 123 | int count_add(); 124 | int count_node(); 125 | 126 | // print smtlib 127 | void print_feasible_set(); 128 | void update_feasible_set(); 129 | }; 130 | 131 | } // namespace ismt 132 | 133 | 134 | #endif -------------------------------------------------------------------------------- /rewriters/nnf_rewriter.cpp: -------------------------------------------------------------------------------- 1 | /* nnf_rewriter.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "rewriters/nnf_rewriter.hpp" 9 | 10 | using namespace ismt; 11 | 12 | bool nnf_rewriter::isVar(dagc* node){ 13 | return node->isvbool() || node->isletbool(); 14 | } 15 | 16 | // convert to nnf-like tree 17 | void nnf_rewriter::toNNFNode(dagc*& node, bool isNot){ 18 | // escape cases: 19 | if(node->isvnum() || node->iscnum() || node->isnumop() || node->isitenum() || 20 | node->isfunint() || node->isletvar()) return; 21 | // check cases: 22 | if(node->isnot()){ 23 | // TODO 24 | assert(node->children.size()==1); 25 | if( isVar(node->children[0]) ) return; 26 | // 2023-05-18 27 | node = node->children[0]; 28 | toNNFNode(node, !isNot); 29 | // 2023-05-18 done 30 | // node->t = NT_AND; 31 | // node->name = "and"; 32 | // toNNFNode(node->children[0], !isNot); 33 | } 34 | else if(isNot){ // isNot = true 35 | if( isVar(node) ){ 36 | std::cout<<"node->isvbool() || node->children[0]->isletbool()"<iscbool()){ 40 | // const boolean 41 | if(node->v==parser->mk_true()->v){ 42 | node->id = 0; 43 | node->v = 0; 44 | node->name = "false"; 45 | } 46 | else{ 47 | node->id = 1; 48 | node->v = 1; 49 | node->name = "true"; 50 | } 51 | return; 52 | } 53 | else if(node->iseqbool() || node->isneqbool() || node->iscomp()){ 54 | node->CompNot(); 55 | } 56 | else if(node->isand()){ 57 | node->t = NT_OR; 58 | node->name = "or"; 59 | for(size_t i=0;ichildren.size();i++){ 60 | if( isVar(node->children[i]) ){ // not lit 61 | node->children[i] = parser->mk_not(node->children[i]); 62 | } 63 | else if(node->children[i]->isnot()){ // not not lit -> lit 64 | node->children[i] = node->children[i]->children[0]; 65 | toNNFNode(node->children[i], false); 66 | } 67 | else toNNFNode(node->children[i], isNot); 68 | } 69 | } 70 | else if(node->isor()){ 71 | node->t = NT_AND; 72 | node->name = "and"; 73 | for(size_t i=0;ichildren.size();i++){ 74 | if( isVar(node->children[i]) ){ // not lit 75 | node->children[i] = parser->mk_not(node->children[i]); 76 | } 77 | else if(node->children[i]->isnot()){ // not not lit 78 | node->children[i] = node->children[i]->children[0]; 79 | toNNFNode(node->children[i], false); 80 | } 81 | else toNNFNode(node->children[i], isNot); 82 | } 83 | } 84 | else if(node->isitebool()){ 85 | assert(node->children.size()==3); 86 | if( isVar(node->children[1]) ){ // not lit 87 | node->children[1] = parser->mk_not(node->children[1]); 88 | } 89 | else if(node->children[1]->isnot()){ // not not lit 90 | node->children[1] = node->children[1]->children[0]; 91 | toNNFNode(node->children[1], false); 92 | } 93 | else toNNFNode(node->children[1], isNot); 94 | 95 | if( isVar(node->children[2]) ){ // not lit 96 | node->children[2] = parser->mk_not(node->children[2]); 97 | } 98 | else if(node->children[2]->isnot()){ // not not lit 99 | node->children[2] = node->children[2]->children[0]; 100 | toNNFNode(node->children[2], false); 101 | } 102 | else toNNFNode(node->children[2], isNot); 103 | } 104 | else if(node->islet()){ 105 | dagc* ret = node; 106 | while(ret->islet()){ 107 | // first simplify all the let bool nodes 108 | for(unsigned i=1;ichildren.size();i++){ 109 | if(ret->children[i]->isletbool()){ 110 | toNNFNode(ret->children[i]->children[0], false); 111 | } 112 | } 113 | // go on find out let content 114 | ret = ret->children[0]; 115 | } 116 | toNNFNode(ret, isNot); 117 | } 118 | else{ 119 | std::cout<<"toNNFNode error!"<print(), assert(false); 121 | } 122 | } 123 | else{ // isNot = false 124 | if(node->islet()){ 125 | // process let 126 | dagc* ret = node; 127 | while(ret->islet()){ 128 | // first simplify all the let bool nodes 129 | for(unsigned i=1;ichildren.size();i++){ 130 | if(ret->children[i]->isletbool()){ 131 | toNNFNode(ret->children[i]->children[0], false); 132 | } 133 | } 134 | // go on find out let content 135 | ret = ret->children[0]; 136 | } 137 | toNNFNode(ret, isNot); 138 | } 139 | else{ 140 | for(size_t i=0;ichildren.size();i++){ 141 | toNNFNode(node->children[i], isNot); 142 | } 143 | } 144 | } 145 | } 146 | 147 | void nnf_rewriter::rewrite(dagc*& root, bool isNot){ 148 | toNNFNode(root, isNot); 149 | } 150 | 151 | // note that finally (not letvar) is permitted. 152 | void nnf_rewriter::rewrite(){ 153 | 154 | auto it = data->assert_list.begin(); 155 | while(it!=data->assert_list.end()){ 156 | rewrite(*it); 157 | ++it; 158 | } 159 | } -------------------------------------------------------------------------------- /solvers/blaster/blaster_equal.cpp: -------------------------------------------------------------------------------- 1 | /* blaster_equal.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/blaster/blaster_solver.hpp" 9 | 10 | using namespace ismt; 11 | 12 | // ------------Equal operations------------ 13 | void blaster_solver::innerEqualVar(bvar var1, bvar var2){ 14 | clause c; 15 | unsigned len = min(var1->size(), var2->size()); 16 | for(size_t i=0;igetAt(i), var2->getAt(i)); 18 | } 19 | // if var1->size() > var2->size() 20 | for(size_t i=len;isize();i++){ 21 | innerEqualBit(var1->getAt(i), var2->signBit()); 22 | } 23 | // if var1->size() size() 24 | for(size_t i=len;isize();i++){ 25 | innerEqualBit(var1->signBit(), var2->getAt(i)); 26 | } 27 | } 28 | void blaster_solver::innerEqualBit(literal var1, literal var2){ 29 | clause c; 30 | c.emplace_back(-var1); 31 | c.emplace_back(var2); 32 | addClause(c); 33 | 34 | c.clear(); 35 | c.emplace_back(var1); 36 | c.emplace_back(-var2); 37 | addClause(c); 38 | } 39 | void blaster_solver::innerEqualInt(bvar var, bvar v){ 40 | clause c; 41 | unsigned len = min(var->size(), v->size()); 42 | // if var->size() < v->size(), check whether can equal. 43 | if(var->size() < v->size()){ 44 | literal tmp = v->getAt(len); 45 | for(size_t i=len;isize();i++){ 46 | // if v->getAt(i) != tmp means that this length of bits can not satisify the constraints. 47 | if(v->getAt(i)!=tmp){ 48 | // TODO, can early stop. 49 | // this a range constraint for the variable! 50 | // IMPORTANT. 51 | c.emplace_back(solver->False()); 52 | addClause(c); 53 | } 54 | } 55 | innerEqualBitInt(var->signBit(), tmp); 56 | } 57 | for(size_t i=0;igetAt(i), v->getAt(i)); 59 | } 60 | // if var->size() > v->size() 61 | for(size_t i=len;isize();i++){ 62 | innerEqualBitInt(var->getAt(i), v->signBit()); 63 | } 64 | } 65 | void blaster_solver::innerEqualBitInt(literal var, literal v){ 66 | // var == v 67 | clause c; 68 | c.emplace_back(v==1?var:-var); 69 | addClause(c); 70 | } 71 | literal blaster_solver::EqualVar(bvar var1, bvar var2){ 72 | literals lits; 73 | unsigned len = min(var1->size(), var2->size()); 74 | for(size_t i=0;igetAt(i), var2->getAt(i))); 76 | } 77 | for(size_t i=len;isize();i++){ 78 | // var2 extend sign bit 79 | lits.emplace_back(EqualBit(var1->getAt(i), var2->signBit())); 80 | } 81 | for(size_t i=len;isize();i++){ 82 | // var1 extend sign bit 83 | lits.emplace_back(EqualBit(var2->getAt(i), var1->signBit())); 84 | } 85 | 86 | return And(lits); 87 | } 88 | 89 | literal blaster_solver::EqualBool(const literal& lit1, const literal& lit2){ 90 | return EqualBit(lit1, lit2); 91 | } 92 | 93 | literal blaster_solver::NotEqualBool(const literal& lit1, const literal& lit2){ 94 | return NotEqualBit(lit1, lit2); 95 | } 96 | literal blaster_solver::EqualBit(literal var1, literal var2){ 97 | // t <-> var1 <-> var2 98 | bool_var t = newSatVar(); 99 | 100 | // t -> var1 -> var2 101 | clause c; 102 | c.emplace_back(-t); 103 | c.emplace_back(-var1); 104 | c.emplace_back(var2); 105 | addClause(c); 106 | 107 | // t -> var2 -> var1 108 | c.clear(); 109 | c.emplace_back(-t); 110 | c.emplace_back(var1); 111 | c.emplace_back(-var2); 112 | addClause(c); 113 | 114 | // var1 <-> var2 -> t 115 | // not (not var1 or var2 and not var2 or var1) or t 116 | // ( var1 /\ ~var2 \/ var2 /\ ~var1 ) \/ t 117 | // ( var1 \/ var2 \/ t ) /\ (~var1 \/ ~var2 \/ t) 118 | // ( var1 \/ var2 \/ t ) 119 | c.clear(); 120 | c.emplace_back(t); 121 | c.emplace_back(var1); 122 | c.emplace_back(var2); 123 | addClause(c); 124 | 125 | // (~var1 \/ ~var2 \/ t) 126 | c.clear(); 127 | c.emplace_back(t); 128 | c.emplace_back(-var1); 129 | c.emplace_back(-var2); 130 | addClause(c); 131 | return t; 132 | } 133 | literal blaster_solver::EqualInt(bvar var, bvar v){ 134 | if(v->getCurValue()==0) return EqZero(var); 135 | literals lits; 136 | unsigned len = min(var->size(), v->size()); 137 | for(size_t i=0;igetAt(i), v->getAt(i))); 139 | } 140 | for(size_t i=len;isize();i++){ 141 | // v extend sign bit 142 | lits.emplace_back(EqualBitInt(var->getAt(i), v->signBit())); 143 | } 144 | for(size_t i=len;isize();i++){ 145 | // var extend sign bit 146 | // TODO x(00) = 0100 147 | lits.emplace_back(EqualBitInt(var->signBit(), v->getAt(i))); 148 | } 149 | 150 | return And(lits); 151 | } 152 | literal blaster_solver::EqualBitInt(literal var, literal v){ 153 | // var == v 154 | if(v==1) return var; 155 | else return -var; 156 | } 157 | literal blaster_solver::NotEqualVar(bvar var1, bvar var2){ 158 | return -EqualVar(var1, var2); 159 | } 160 | literal blaster_solver::NotEqualBit(literal var1, literal var2){ 161 | return -EqualBit(var1, var2); 162 | } 163 | literal blaster_solver::NotEqualInt(bvar var, bvar v){ 164 | literals lits; 165 | unsigned len = min(var->size(), v->size()); 166 | for(size_t i=0;igetAt(i), v->getAt(i))); 168 | } 169 | for(size_t i=len;isize();i++){ 170 | // v extend sign bit 171 | lits.emplace_back(NotEqualBitInt(var->getAt(i), v->signBit())); 172 | } 173 | for(size_t i=len;isize();i++){ 174 | // var extend sign bit 175 | lits.emplace_back(NotEqualBitInt(var->signBit(), v->getAt(i))); 176 | } 177 | 178 | return Or(lits); 179 | } 180 | literal blaster_solver::NotEqualBitInt(literal var, literal v){ 181 | // var == v 182 | if(v==1) return -var; 183 | else return var; 184 | } -------------------------------------------------------------------------------- /solvers/blaster/blaster_make.cpp: -------------------------------------------------------------------------------- 1 | /* blaster_make.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/blaster/blaster_solver.hpp" 9 | 10 | using namespace ismt; 11 | 12 | // ------------make variables------------ 13 | 14 | // make blast_variables 15 | bvar blaster_solver::mkVar(const std::string& name){ 16 | return mkVar(name, default_len); 17 | } 18 | bvar blaster_solver::mkVar(const std::string& name, unsigned len){ 19 | bvar t = blast(mkHolder(name, len)); 20 | Escape(t); 21 | return t; 22 | } 23 | bvar blaster_solver::mkInnerVar(const std::string& name, unsigned len){ 24 | if(n2var.find(name)!=n2var.end()){ 25 | bvar x = n2var[name]; 26 | if(x->isClean()){ 27 | x->setSize(len); 28 | x->reblast(); 29 | blast(x); 30 | // debug: 2021-11-12, must Escape. 31 | Escape(x); 32 | return x; 33 | } 34 | else return x; 35 | } 36 | bvar t = blast(new blast_variable(name, len)); 37 | // add to map, for future delete. 38 | n2var.insert(std::pair(name, t)); 39 | Escape(t); 40 | return t; 41 | } 42 | bvar blaster_solver::mkHolder(const std::string& name, unsigned len){ 43 | if(n2var.find(name)!=n2var.end()){ 44 | bvar x = n2var[name]; 45 | if(x->isClean()){ 46 | x->setSize(len); 47 | x->reblast(); 48 | return x; 49 | } 50 | else return x; 51 | } 52 | bvar t = new blast_variable(name, len); 53 | // add to map, for future delete. 54 | n2var.insert(std::pair(name, t)); 55 | ProblemVars.emplace_back(t); 56 | return t; 57 | } 58 | bvar blaster_solver::blast(bvar var){ 59 | for(size_t i=0;isize();i++){ 60 | var->setAt(i, newSatVar()); 61 | } 62 | return var; 63 | } 64 | void blaster_solver::addVar(bvar var){ 65 | ProblemVars.emplace_back(var); 66 | } 67 | void blaster_solver::addVarMap(bvar var){ 68 | n2var.insert(std::pair(var->getName(), var)); 69 | } 70 | void blaster_solver::copy(bvar var, std::string& name, bvar& target){ 71 | if(target==nullptr){ 72 | target = new blast_variable(name, var->csize()); 73 | target->setKind(var->isConstant()); 74 | target->setCurValue(var->getCurValue()); 75 | n2var.insert(std::pair(name, target)); 76 | ProblemVars.emplace_back(target); 77 | } 78 | else target->setSize(var->csize()); 79 | target->reblast(); 80 | for(size_t i=0;isize();i++){ 81 | target->setAt(i, var->getAt(i)); 82 | } 83 | } 84 | void blaster_solver::copyInt(bvar var, bvar& target){ 85 | if(target==nullptr){ 86 | target = new blast_variable(var->getName(), var->csize()); 87 | target->setKind(var->isConstant()); 88 | target->setCurValue(var->getCurValue()); 89 | } 90 | else target->setSize(var->csize()); 91 | target->reblast(); 92 | for(size_t i=0;isize();i++){ 93 | target->setAt(i, var->getAt(i)); 94 | } 95 | } 96 | void blaster_solver::Escape(bvar var){ 97 | clause c; 98 | c.emplace_back(-var->signBit()); 99 | for(size_t i=1;isize();i++){ 100 | c.emplace_back(var->getAt(i)); 101 | } 102 | addClause(c); 103 | } 104 | bvar blaster_solver::mkInt(Integer v){ 105 | if(n2int.find(v.get_str())!=n2int.end()){ 106 | return n2int[v.get_str()]; 107 | } 108 | std::string name = v.get_str(); 109 | // special case 110 | if(v==0){ 111 | bvar t = new blast_variable(name, 1, 0, true); 112 | n2int.insert(std::pair(name, t)); 113 | t->setAt(0, v>=0?0:1); 114 | t->setAt(1, 0); 115 | return t; 116 | } 117 | // calculate value 118 | int maxBits = 0; 119 | Integer val = abs(v); 120 | std::vector answer; 121 | // true code of binary 122 | while(val!=0){ 123 | answer.emplace_back(val%2==1?1:0); 124 | val/=2; 125 | maxBits ++; 126 | } 127 | if(v<0){ 128 | // invert all bits 129 | for(size_t i=0;i0, 0->1 131 | } 132 | // add one 133 | for(size_t i=0;i(name, t)); 140 | t->setAt(0, v>=0?0:1); 141 | for(size_t i=1;isize();i++){ 142 | t->setAt(i, answer[i-1]); 143 | } 144 | 145 | return t; 146 | } 147 | bool_var blaster_solver::mkBool(const std::string& name){ 148 | bool_var t = newSatVar(); 149 | n2bool.insert(std::pair(name, t)); 150 | return t; 151 | } 152 | 153 | // auxiliary make variable functions 154 | bvar blaster_solver::mkInvertedVar(bvar var){ 155 | std::string name = "inv("+var->getName()+")"; 156 | bvar t = mkHolder(name, var->csize()); 157 | for(size_t i=0;isize();i++){ 158 | t->setAt(i, -var->getAt(i)); 159 | } 160 | n2var.insert(std::pair(t->getName(), t)); 161 | return t; 162 | } 163 | bvar blaster_solver::mkShiftedVar(bvar var, int len){ 164 | if(len==0) return var; 165 | // len>0: shift right, len<0: shift left. 166 | std::string name = "("+var->getName() + (len>0?">>":"<<") + to_string(abs(len))+")"; 167 | bvar t = mkHolder(name, var->csize()-len); 168 | t->setAt(0, var->signBit()); 169 | if(len>0){ 170 | for(size_t i=1;isize();i++){ 171 | t->setAt(i, var->getAt(i+len)); 172 | } 173 | Escape(t); 174 | } 175 | else{ 176 | len = -len; 177 | for(int i=1;i<=len;i++) t->setAt(i, solver->False()); 178 | for(size_t i=len+1;isize();i++) t->setAt(i, var->getAt(i-len)); 179 | } 180 | n2var.insert(std::pair(name, t)); 181 | return t; 182 | } 183 | bool_var blaster_solver::newSatVar(){ 184 | bool_var t = solver->curVar(); 185 | solver->newVar(); 186 | return t; 187 | } 188 | -------------------------------------------------------------------------------- /options.hpp: -------------------------------------------------------------------------------- 1 | /* options.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _OPTIONS_H 9 | #define _OPTIONS_H 10 | // 2023-05-27 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace ismt 18 | { 19 | // 2023-05-27 20 | struct SolverOptions{ 21 | std::string File = ""; 22 | int Time = 1200; 23 | // std::string Combined_Solver_Name = "none"; 24 | bool GA = true; 25 | bool MA = true; 26 | bool VO = true; 27 | int Alpha = 1536; 28 | int Beta = 7; 29 | int K = 16; 30 | double Gamma = 0.5; 31 | bool DG = true; 32 | bool CM = true; 33 | int MaxBW = 128; 34 | 35 | bool parse(int argc, char* argv[]){ 36 | for(int i=1;i 3){ 40 | if(param[1]=='T' && param[2]==':'){ 41 | // time 42 | Time = std::atoi(param.substr(3).c_str()); 43 | } 44 | // else if(param[1]=='C' && param[2]=='S' && param[3]=='N' && param[4]==':'){ 45 | // Combined_Solver_Name = param.substr(5); 46 | // } 47 | else if(param[1]=='G' && param[2]=='A' && param[3]==':'){ 48 | if(param.substr(4) == "true") GA = true; 49 | else GA = false; 50 | } 51 | else if(param[1]=='M' && param[2]=='A' && param[3]==':'){ 52 | if(param.substr(4) == "true") MA = true; 53 | else if(param.substr(4) == "false") MA = false; 54 | } 55 | else if(param[1]=='V' && param[2]=='O' && param[3]==':'){ 56 | if(param.substr(4) == "true") VO = true; 57 | else if(param.substr(4) == "false") VO = false; 58 | } 59 | else if(param[1]=='A' && param[2]=='l' && param[3]=='p' && param[4]=='h' && param[5]=='a' && param[6]==':'){ 60 | Alpha = std::atoi(param.substr(7).c_str()); 61 | } 62 | else if(param[1]=='B' && param[2]=='e' && param[3]=='t' && param[4]=='a' && param[5]==':'){ 63 | Beta = std::atoi(param.substr(6).c_str()); 64 | } 65 | else if(param[1]=='K' && param[2]==':'){ 66 | K = std::atoi(param.substr(3).c_str()); 67 | } 68 | else if(param[1]=='G' && param[2]=='a' && param[3]=='m' && param[4]=='m' && param[5]=='a' && param[6]==':'){ 69 | Gamma = std::atof(param.substr(7).c_str()); 70 | } 71 | else if(param[1]=='D' && param[2]=='G' && param[3]==':'){ 72 | if(param.substr(4) == "true") DG = true; 73 | else if(param.substr(4) == "false") DG = false; 74 | } 75 | else if(param[1]=='C' && param[2]=='M' && param[3]==':'){ 76 | if(param.substr(4) == "true") CM = true; 77 | else if(param.substr(4) == "false") CM = false; 78 | } 79 | else if(param[1]=='M' && param[2]=='a' && param[3]=='x' && param[4]=='B' && param[5]=='W' && param[6]==':'){ 80 | MaxBW = std::atoi(param.substr(7).c_str()); 81 | } 82 | } 83 | else if(param[1]=='h'){ 84 | print_help(); 85 | } 86 | else assert(false); 87 | } 88 | else{ 89 | File = std::string(argv[i]); 90 | // if multiple file, the final file is valid. 91 | } 92 | } 93 | if(File=="") return false; 94 | else return true; 95 | } 96 | 97 | void print(){ 98 | std::cout<<"Params: {"<dag); 20 | model->setVariables(data->vbool_list); 21 | model->setVariables(data->vnum_int_list); 22 | state = State::UNKNOWN; 23 | nnfer = new nnf_rewriter(p); 24 | logicer = new logic_rewriter(p); 25 | eqer = new eq_rewriter(p); 26 | eqer->setModel(m); 27 | polyer = new poly_rewriter(p); 28 | comper = new comp_rewriter(p, polyer, eqer); 29 | proper = new prop_rewriter(p, m); 30 | proper->setNNF(nnfer); 31 | leter = new let_rewriter(p, m); 32 | eqsver = new eq_solver(p, m); 33 | eqsver->setRewriters(eqer, polyer); 34 | eqsver->setCollector(thector); 35 | message = new Message(); 36 | message->data = data; 37 | message->model = model; 38 | } 39 | preprocessor::~preprocessor(){ 40 | delete message; message = nullptr; 41 | delete proper; proper = nullptr; 42 | delete comper; comper = nullptr; 43 | delete polyer; polyer = nullptr; 44 | delete eqer; eqer = nullptr; 45 | delete logicer; logicer = nullptr; 46 | delete nnfer; nnfer = nullptr; 47 | delete leter; leter = nullptr; 48 | delete eqsver; eqsver = nullptr; 49 | } 50 | 51 | void preprocessor::auto_set_model(){ 52 | // use collector to set model 53 | // all to intervals 54 | message->state = State::SAT; 55 | std::vector vars; 56 | message->model->getUnassignedVars(vars); 57 | for(size_t i=0;ivariables[vars[i]]; 59 | assert(fs != nullptr); 60 | Interval intv = fs->choose(); 61 | poly::Integer val = to_Integer(poly::pick_value(intv)); 62 | message->model->set(vars[i], to_long(val)); 63 | } 64 | } 65 | 66 | // simplify funtions 67 | 68 | bool preprocessor::check(bool er){ 69 | if(er) return true; 70 | else{ 71 | message->state = State::UNSAT; 72 | return false; 73 | } 74 | } 75 | bool preprocessor::simplify(){ 76 | simplified = true; 77 | #if preDebug 78 | std::cout<<"\noriginal formulas..."<print_constraints(); 80 | // 0. convert to nnf-like tree. 81 | std::cout<<"\nnnf rewriting..."<rewrite(); 84 | 85 | #if preDebug 86 | data->print_constraints(); 87 | // 1. eliminate top(/true) let 88 | std::cout<<"\nlet operator rewriting..."<rewrite())) return false; 91 | 92 | #if preDebug 93 | data->print_constraints(); 94 | // 2. eliminate logic operators. 95 | std::cout<<"\nlogic operation rewriting..."<rewrite(); 98 | #if preDebug 99 | data->print_constraints(); 100 | // 3. comp rewriting. 101 | // 1) add t := v to model in equivalence rewriter, 102 | // 2) add x := y to model in equivalence rewriter. 103 | std::cout<<"\ncomparision equal rewriting..."<rewrite())) return false; 106 | 107 | // data->print_smtlib(); 108 | #if preDebug 109 | data->print_constraints(); 110 | // 3) comp rewriting, 111 | std::cout<<"\ncomparision comp rewriting..."<rewrite())) return false; 114 | // data->print_constraints(); 115 | // model->print_partial(); 116 | // data->print_smtlib(); 117 | 118 | #if preDebug 119 | data->print_constraints(); 120 | // 4. model propagation rewriting. 121 | std::cout<<"\npropagation rewriting..."<rewrite())) return false; 124 | 125 | // model->print_partial(); 126 | // data->print_smtlib(); 127 | 128 | // remove true 129 | #if preDebug 130 | data->print_constraints(); 131 | std::cout<<"\nremoving sat constraints..."<assert_list.begin(); 134 | while(it!=data->assert_list.end()){ 135 | if((*it)->istrue()){ 136 | (*it)->print(); 137 | it = data->assert_list.erase(it); 138 | } 139 | else if((*it)->isfalse()){ 140 | (*it)->print(); 141 | message->state = State::UNSAT; 142 | return false; 143 | } 144 | else ++it; 145 | } 146 | // data->print_smtlib(); 147 | // model->print_partial(); 148 | if(data->assert_list.size() == 0){ 149 | state = State::SAT; 150 | return true; 151 | } 152 | 153 | #if preDebug 154 | data->print_constraints(); 155 | std::cout<<"\ncollector rewriting..."<rewrite(); 160 | // 5. collector 161 | if(!check(thector->rewrite())) return false; 162 | // new appended 06/02 163 | // x in [0, 1) -> x = 0 164 | #if preDebug 165 | data->print_constraints(); 166 | std::cout<<"\nre-propagte rewriting..."<print_partial(); 170 | if(!check(proper->rewrite())) return false; 171 | // model->print_partial(); 172 | 173 | // thector->print_feasible_set(); 174 | // data->print_smtlib(); 175 | #if preDebug 176 | data->print_constraints(); 177 | #endif 178 | 179 | 180 | if(data->assert_list.size() == 0){ 181 | // all eliminated 182 | // auto set model 183 | auto_set_model(); 184 | state = State::SAT; 185 | } 186 | // data->print_constraints(); 187 | // data->print_smtlib(); 188 | 189 | // eq solver 190 | // now only use rewrite 191 | if(!check(eqsver->solve())) return false; 192 | 193 | return true; 194 | } 195 | 196 | 197 | Message* preprocessor::release(){ 198 | // unsat 199 | if(message->state==State::UNSAT) return nullptr; 200 | // sat -> model 201 | if(message->state==State::SAT) return message; 202 | auto it = data->assert_list.begin(); 203 | while(it!=data->assert_list.end()){ 204 | message->constraints.emplace_back(*it); 205 | ++it; 206 | } 207 | // unknown 208 | message->state = State::UNKNOWN; 209 | return message; 210 | } -------------------------------------------------------------------------------- /rewriters/let_rewriter.cpp: -------------------------------------------------------------------------------- 1 | /* let_rewriter.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "rewriters/let_rewriter.hpp" 9 | 10 | using namespace ismt; 11 | 12 | 13 | // TODO, 2022-05-20, note that we left letvarnum 14 | // get pure content without letvar of letvar 15 | dagc* let_rewriter::content(dagc* root){ 16 | dagc* ret = root->children[0]; 17 | // while(ret->isletvar()){ 18 | while(ret->isletbool()){ 19 | ret = ret->children[0]; 20 | } 21 | analyzeOp(ret); 22 | return ret; 23 | } 24 | // check children of root that without letvar 25 | void let_rewriter::analyzeOp(dagc* root){ 26 | for(size_t i=0;ichildren.size();i++){ 27 | dagc* x = root->children[i]; 28 | // if(x->isletvar()){ 29 | if(x->isletbool()){ 30 | root->children[i] = content(x); 31 | } 32 | else analyzeOp(x); 33 | } 34 | } 35 | // return true -> set all values of children (so maybe res.size()==0) 36 | // return false -> without set model 37 | bool let_rewriter::propagate(dagc* root, std::vector& res){ 38 | if(root->isvbool()){ 39 | // set to model 40 | model->set(root, 1); 41 | return true; 42 | } 43 | else if(root->isletvar()){ 44 | if(root->isletbool()){ 45 | dagc* x = root->children[0]; 46 | // nodes has 2 cases: 47 | // 1. append to res 48 | // 2. set value 49 | if(propagate(x, res) && x->isAssigned()){ 50 | // if all assigned, then assign root. 51 | // $1 = and a b -> $1 = true, a = true, b = true; {} 52 | assert(x->isAssigned()); 53 | root->assign(x->v); 54 | return true; 55 | } 56 | else{ 57 | // currently, 58 | // $1 = and a>1 b -> b = true; {a>1} 59 | // $1 = or a b -> ; {(or a b)} 60 | // BoolOprMap will find out the let var content 61 | } 62 | return false; 63 | } 64 | else{ 65 | // root->isletnum() 66 | assert(false); 67 | } 68 | } 69 | else if(root->isand()){ 70 | // check (children) + propagate 71 | std::vector tmp; 72 | for(size_t i=0;ichildren.size();i++){ 73 | dagc* x = root->children[i]; 74 | if(propagate(x, res)){ 75 | // new assigned value 76 | if(x->isAssigned()){ 77 | if(x->isfalse()){ 78 | res.emplace_back(parser->mk_false()); 79 | root->assign(0); 80 | return true; 81 | } 82 | else{ 83 | // istrue() -> nothing to do 84 | } 85 | } 86 | else{ 87 | tmp.emplace_back(x); 88 | } 89 | } 90 | } 91 | // // have not assigned 92 | // if(!ans) res.emplace_back(root); 93 | root->children.clear(); 94 | if(tmp.size()==0){ 95 | root->children.emplace_back(parser->mk_true()); 96 | return true; 97 | } 98 | else{ 99 | // tmp size == 1 will erase in logic operator 100 | root->children.assign(tmp.begin(), tmp.end()); 101 | res.emplace_back(root); 102 | } 103 | } 104 | else if(root->isor()){ 105 | // only check without propagate 106 | for(size_t i=0;ichildren.size();i++){ 107 | dagc* x = root->children[i]; 108 | if(x->isAssigned()){ 109 | if(x->istrue()){ 110 | root->assign(1); 111 | res.emplace_back(parser->mk_true()); 112 | return true; 113 | } 114 | else{} 115 | } 116 | } 117 | res.emplace_back(root); 118 | } 119 | else if(root->isnot()){ 120 | if(root->children[0]->isvbool()){ 121 | model->set(root->children[0], 0); 122 | root->assign(1); 123 | return true; 124 | } 125 | else if(root->children[0]->isletbool()){ 126 | dagc* x = root->children[0]; 127 | 128 | // only check without propagate 129 | if(x->isAssigned()){ 130 | if(x->istrue()){ 131 | root->assign(0); 132 | res.emplace_back(parser->mk_false()); 133 | return true; 134 | } 135 | else{ 136 | root->assign(1); 137 | res.emplace_back(parser->mk_true()); 138 | return true; 139 | } 140 | } 141 | 142 | res.emplace_back(root); 143 | } 144 | else{ 145 | // after nnf rewriter, never (not operator) exists 146 | res.emplace_back(root); 147 | } 148 | } 149 | else{ 150 | res.emplace_back(root); 151 | } 152 | return false; 153 | } 154 | 155 | void let_rewriter::rewrite(dagc* root, std::vector& res, bool isTop){ 156 | if(!isTop) return; // nothing to do 157 | // let->children[0] = expr, e.g. x+y+1 -> a+10+b+10+1 158 | // let->children[1..n] = letvar, e.g. x (->a+10), y (->b+10) 159 | dagc* ret = root; 160 | // find content 161 | while(ret->islet()){ 162 | ret = ret->children[0]; 163 | } 164 | // try to propagate 165 | propagate(ret, res); 166 | } 167 | 168 | bool let_rewriter::rewrite(){ 169 | boost::unordered_map duplicate_atoms; 170 | auto it = data->assert_list.begin(); 171 | while(it!=data->assert_list.end()){ 172 | if((*it)->islet()){ 173 | // TODO, only top-let will be eliminated 174 | std::vector res; 175 | rewrite(*it, res); 176 | 177 | if(res.size()==1 && res[0]->isAssigned()){ 178 | if(res[0]->isfalse()){ 179 | return false; 180 | } 181 | else{ 182 | it = data->assert_list.erase(it); 183 | } 184 | } 185 | else{ 186 | it = data->assert_list.erase(it); 187 | for(unsigned i=0;i(res[i], 1)); 191 | data->assert_list.insert(it, res[i]); 192 | } 193 | } 194 | } 195 | } 196 | else ++it; 197 | } 198 | return true; 199 | } -------------------------------------------------------------------------------- /solvers/blaster/blaster_slack.cpp: -------------------------------------------------------------------------------- 1 | /* blaster_slack.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/blaster/blaster_solver.hpp" 9 | 10 | using namespace ismt; 11 | 12 | 13 | // Slack Abstraction: e.g. a > b <=> a == b + t /\ t > 0. 14 | literal blaster_solver::SEqual(bvar var1, bvar var2){ // var1 == var2 15 | bvar slack = mkInnerVar("slack_"+to_string(slackSize++), max(var1->csize(), var2->csize())); 16 | bvar ans = Add(slack, var1); 17 | innerEqualVar(var2, ans); 18 | return EqZero(slack); 19 | } 20 | literal blaster_solver::SNotEqual(bvar var1, bvar var2){ // var1 != var2 21 | bvar slack = mkInnerVar("slack_"+to_string(slackSize++), max(var1->csize(), var2->csize())); 22 | bvar ans = Add(slack, var1); 23 | innerEqualVar(var2, ans); 24 | return NeqZero(slack); 25 | } 26 | literal blaster_solver::SGreater(bvar var1, bvar var2){ // var1 > var2 27 | bvar slack = mkInnerVar("slack_"+to_string(slackSize++), max(var1->csize(), var2->csize())); 28 | bvar ans = Add(slack, var2); 29 | innerEqualVar(var1, ans); 30 | return GtZero(slack); 31 | } 32 | literal blaster_solver::SGreaterEqual(bvar var1, bvar var2){ // var1 >= var2 33 | bvar slack = mkInnerVar("slack_"+to_string(slackSize++), max(var1->csize(), var2->csize())); 34 | bvar ans = Add(slack, var2); 35 | innerEqualVar(var1, ans); 36 | return GeZero(slack); 37 | } 38 | literal blaster_solver::SEqualInt(bvar var1, bvar var2){ 39 | bvar var = var1; 40 | bvar v = var2; 41 | if(var->isConstant()) swap(var, v); 42 | if(v->getCurValue()==0){ 43 | return EqZero(var); 44 | } 45 | bvar slack = mkInnerVar("slack_"+to_string(slackSize++), max(var->csize(), v->csize())); 46 | if(add2i){ 47 | bvar ans = Add(slack, v); 48 | innerEqualVar(var, ans); 49 | return EqZero(slack); 50 | } 51 | else{ 52 | bvar ans = Add(slack, var); 53 | innerEqualInt(ans, v); 54 | return EqZero(slack); 55 | } 56 | } 57 | literal blaster_solver::SNotEqualInt(bvar var1, bvar var2){ 58 | bvar var = var1; 59 | bvar v = var2; 60 | if(var->isConstant()) swap(var, v); 61 | if(v->getCurValue()==0){ 62 | return NeqZero(var); 63 | } 64 | bvar slack = mkInnerVar("slack_"+to_string(slackSize++), max(var->csize(), v->csize())); 65 | if(add2i){ 66 | bvar ans = Add(slack, v); 67 | innerEqualVar(var, ans); 68 | return NeqZero(slack); 69 | } 70 | else{ 71 | bvar ans = Add(slack, var); 72 | innerEqualInt(ans, v); 73 | return NeqZero(slack); 74 | } 75 | } 76 | literal blaster_solver::SGreaterInt(bvar var1, bvar var2){ // var1 > var2 77 | if(var1->isConstant()){ 78 | if(var1->getCurValue()==0){ 79 | // var2 < 0 80 | return LtZero(var2); 81 | } 82 | else{ 83 | bvar slack = mkInnerVar("slack_"+to_string(slackSize++), max(var1->csize(), var2->csize())); 84 | if(add2i){ 85 | bvar ans = Add(slack, var1); 86 | innerEqualVar(var2, ans); 87 | // slack < 0. 88 | return LtZero(slack); 89 | } 90 | else{ 91 | bvar ans = Add(slack, var2); 92 | innerEqualInt(ans, var1); 93 | // slack > 0. 94 | return GtZero(slack); 95 | } 96 | } 97 | } 98 | else{ // var2->isConstant() 99 | if(var2->getCurValue()==0){ 100 | return GtZero(var1); 101 | } 102 | else{ 103 | bvar slack = mkInnerVar("slack_"+to_string(slackSize++), max(var1->csize(), var2->csize())); 104 | if(add2i){ 105 | bvar ans = Add(slack, var2); 106 | innerEqualVar(var1, ans); 107 | // slack < 0. 108 | return GtZero(slack); 109 | } 110 | else{ 111 | bvar ans = Add(slack, var1); 112 | innerEqualInt(ans, var2); 113 | // slack > 0. 114 | return LtZero(slack); 115 | } 116 | } 117 | } 118 | } 119 | literal blaster_solver::SGreaterEqualInt(bvar var1, bvar var2){ // var1 >= var2 120 | if(var1->isConstant()){ 121 | if(var1->getCurValue()==0){ 122 | // var2 <= 0 123 | return LeZero(var2); 124 | } 125 | else{ 126 | bvar slack = mkInnerVar("slack_"+to_string(slackSize++), max(var1->csize(), var2->csize())); 127 | if(add2i){ 128 | bvar ans = Add(slack, var1); 129 | innerEqualVar(var2, ans); 130 | // slack <= 0. 131 | return LeZero(slack); 132 | } 133 | else{ 134 | bvar ans = Add(slack, var2); 135 | innerEqualInt(ans, var1); 136 | // slack >= 0. 137 | return GeZero(slack); 138 | } 139 | } 140 | } 141 | else{ // var2->isConstant() 142 | if(var2->getCurValue()==0){ 143 | // vavr1 >= 0 144 | return GeZero(var1); 145 | } 146 | else{ 147 | bvar slack = mkInnerVar("slack_"+to_string(slackSize++), max(var1->csize(), var2->csize())); 148 | if(add2i){ 149 | bvar ans = Add(slack, var2); 150 | innerEqualVar(var1, ans); 151 | // slack <= 0. 152 | return GeZero(slack); 153 | } 154 | else{ 155 | bvar ans = Add(slack, var1); 156 | innerEqualInt(ans, var2); 157 | // slack >= 0. 158 | return LeZero(slack); 159 | } 160 | } 161 | } 162 | } 163 | 164 | // auxiliary functions 165 | literal blaster_solver::GtZero(bvar var){ 166 | assert(!var->isConstant()); 167 | // t <-> \/ var[i] /\ ~var[0] 168 | bool_var t = newSatVar(); 169 | // t -> \/ var[i], i>=1 170 | clause c; 171 | c.emplace_back(-t); 172 | for(size_t i=1;isize();i++){ 173 | c.emplace_back(var->getAt(i)); 174 | } 175 | addClause(c); 176 | 177 | // t -> ~var[0] 178 | c.clear(); 179 | c.emplace_back(-t); 180 | c.emplace_back(-var->signBit()); 181 | addClause(c); 182 | 183 | // var[0] \/ ~var[i] \/ tmp, i>=1 184 | for(size_t i=1;isize();i++){ 185 | c.clear(); 186 | c.emplace_back(t); 187 | c.emplace_back(var->signBit()); 188 | c.emplace_back(-var->getAt(i)); 189 | addClause(c); 190 | } 191 | 192 | return t; 193 | } 194 | literal blaster_solver::GeZero(bvar var){ 195 | assert(!var->isConstant()); 196 | // sign bit = 0 197 | return -var->signBit(); 198 | } 199 | literal blaster_solver::LtZero(bvar var){ 200 | assert(!var->isConstant()); 201 | // sign bit = 1 and Escape. 202 | return var->signBit(); 203 | } 204 | literal blaster_solver::LeZero(bvar var){ 205 | assert(!var->isConstant()); 206 | // var < 0 \/ var == 0 207 | literals lits; 208 | lits.emplace_back(LtZero(var)); 209 | lits.emplace_back(EqZero(var)); 210 | return Or(lits); 211 | } 212 | literal blaster_solver::EqZero(bvar var){ 213 | assert(!var->isConstant()); 214 | if(EqZeroMap.find(var)!=EqZeroMap.end()) return EqZeroMap[var]; 215 | // t <-> /\ ~var[i]. 216 | bool_var t = newSatVar(); 217 | // t -> /\ ~var[i] <=> ~t \/ ~var[i], i>=0 218 | for(size_t i=0;isize();i++){ 219 | clause c; 220 | c.emplace_back(-t); 221 | c.emplace_back(-var->getAt(i)); 222 | addClause(c); 223 | } 224 | 225 | // /\ ~var[i] -> t <=> \/ var[i] \/ t, i>=0 226 | clause c; 227 | c.emplace_back(t); 228 | for(size_t i=0;isize();i++){ 229 | c.emplace_back(var->getAt(i)); 230 | } 231 | addClause(c); 232 | 233 | EqZeroMap.insert(std::pair(var, t)); 234 | 235 | return t; 236 | } 237 | literal blaster_solver::NeqZero(bvar var){ 238 | assert(!var->isConstant()); 239 | // t <-> \/ var[i]. 240 | bool_var t = newSatVar(); 241 | // t -> \/ var[i] <=> ~t \/ (\/ var[i]), i>=1 242 | clause c; 243 | c.emplace_back(-t); 244 | for(size_t i=1;isize();i++){ 245 | c.emplace_back(var->getAt(i)); 246 | } 247 | addClause(c); 248 | 249 | // \/ var[i] -> t <=> ~var[i] \/ t, i>=1 250 | for(size_t i=1;isize();i++){ 251 | c.clear(); 252 | c.emplace_back(t); 253 | c.emplace_back(-var->getAt(i)); 254 | addClause(c); 255 | } 256 | 257 | return t; 258 | } -------------------------------------------------------------------------------- /frontend/parser.hpp: -------------------------------------------------------------------------------- 1 | /* parser.hpp 2 | * 3 | * Copyright (C) 2023-2026 Cunjing Ge & Minghao Liu & Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef PARSER_HEADER 9 | #define PARSER_HEADER 10 | 11 | #include "frontend/dag.hpp" 12 | 13 | #define NDEBUG 14 | 15 | // internal string length, name of inequalities and constants 16 | #define STRLEN 30 17 | 18 | 19 | namespace ismt { 20 | 21 | 22 | enum SCAN_MODE { 23 | SM_COMMON, 24 | SM_SYMBOL, 25 | SM_COMP_SYM, 26 | SM_COMMENT, 27 | SM_STRING 28 | }; 29 | 30 | 31 | enum CMD_TYPE { 32 | CT_UNKNOWN, CT_EOF, 33 | // COMMANDS 34 | CT_ASSERT, CT_CHECK_SAT, CT_CHECK_SAT_ASSUMING, 35 | CT_DECLARE_CONST, CT_DECLARE_FUN, CT_DECLARE_SORT, 36 | CT_DEFINE_FUN, CT_DEFINE_FUN_REC, CT_DEFINE_FUNS_REC, CT_DEFINE_SORT, 37 | CT_ECHO, CT_EXIT, 38 | CT_GET_ASSERTIONS, CT_GET_ASSIGNMENT, CT_GET_INFO, 39 | CT_GET_MODEL, CT_GET_OPTION, CT_GET_PROOF, 40 | CT_GET_UNSAT_ASSUMPTIONS, CT_GET_UNSAT_CORE, CT_GET_VALUE, 41 | CT_POP, CT_PUSH, CT_RESET, CT_RESET_ASSERTIONS, 42 | CT_SET_INFO, CT_SET_LOGIC, CT_SET_OPTION, 43 | }; 44 | 45 | enum ERROR_TYPE { 46 | ERR_UNEXP_EOF, 47 | ERR_SYM_MIS, 48 | ERR_UNKWN_SYM, 49 | ERR_PARAM_MIS, 50 | ERR_PARAM_NBOOL, 51 | ERR_PARAM_NNUM, 52 | ERR_PARAM_NSAME, 53 | ERR_LOGIC, 54 | ERR_MUL_DECL, 55 | ERR_MUL_DEF, 56 | ERR_NLINEAR, 57 | ERR_ZERO_DIVISOR, 58 | ERR_FUN_LOCAL_VAR 59 | }; 60 | 61 | 62 | /* 63 | Parser 64 | */ 65 | 66 | 67 | class Parser { 68 | 69 | public: 70 | 71 | DAG & dag; 72 | 73 | // Jia: store the DAG in target. 74 | Parser(std::string filename, DAG & target) : dag(target) { 75 | 76 | err_node = new dagc(NT_ERROR); 77 | 78 | dag.logic = UNKNOWN_LOGIC; 79 | dag.check_sat = false; 80 | dag.get_model = false; 81 | parse_smtlib2_file(filename); 82 | // for(size_t i=0;iassign(v); 100 | constants.insert(std::pair(name, dag.const_list.size())); 101 | dag.const_list.emplace_back(newconst); 102 | return newconst; 103 | } 104 | }; 105 | 106 | dagc * mk_bool_decl(const std::string &name); 107 | dagc * mk_var_decl(const std::string &name, bool isInt); 108 | 109 | // dagc * mk_key_bind(const std::string &key, dagc * expr); 110 | dagc * mk_let_bind(const std::string &key, dagc * expr); 111 | dagc * mk_fun_bind(const std::string &key, dagc * expr); 112 | 113 | dagc * mk_fun(dagc * fun, const std::vector & params); 114 | dagc * mk_fun_post_order(dagc * fun, std::vector& record, const std::vector & params); 115 | 116 | dagc * mk_and(dagc * l, dagc *r) { std::vector params = { l, r }; return mk_and(params); }; 117 | dagc * mk_and(const std::vector ¶ms); 118 | dagc * mk_or(dagc * l, dagc *r) { std::vector params = { l, r }; return mk_or(params); }; 119 | dagc * mk_or(const std::vector ¶ms); 120 | dagc * mk_not(dagc * param); 121 | dagc * mk_not(const std::vector ¶ms); 122 | dagc * mk_imply(dagc * l, dagc *r) { std::vector params = { l, r }; return mk_imply(params); }; 123 | dagc * mk_imply(const std::vector ¶ms); 124 | dagc * mk_xor(dagc * l, dagc *r) { return mk_not(mk_eq(l, r)); }; 125 | dagc * mk_xor(const std::vector ¶ms); 126 | 127 | dagc * mk_eq(dagc * l, dagc * r); 128 | dagc * mk_eq(const std::vector ¶ms); 129 | dagc * mk_neq(dagc * l, dagc * r); 130 | dagc * mk_distinct(dagc * l, dagc * r) { return mk_neq(l, r); }; 131 | dagc * mk_distinct(const std::vector ¶ms); 132 | 133 | dagc * mk_ite(dagc * c, dagc * l, dagc * r); 134 | dagc * mk_ite(const std::vector ¶ms); 135 | 136 | dagc * mk_add(dagc * l, dagc *r) { std::vector params = { l, r }; return mk_add(params); }; 137 | dagc * mk_add(const std::vector ¶ms); 138 | dagc * mk_neg(dagc * param); 139 | dagc * mk_minus(dagc * l, dagc *r) { std::vector params = { l, r }; return mk_minus(params); }; 140 | dagc * mk_minus(const std::vector ¶ms); 141 | dagc * mk_mul(dagc * l, dagc *r) { std::vector params = { l, r }; return mk_mul(params); }; 142 | dagc * mk_mul(const std::vector ¶ms); 143 | 144 | dagc * mk_div_int(dagc * l, dagc * r); 145 | dagc * mk_div_int(const std::vector ¶ms); 146 | dagc * mk_div_real(dagc * l, dagc * r); 147 | dagc * mk_div_real(const std::vector ¶ms); 148 | dagc * mk_mod(dagc * l, dagc * r); 149 | dagc * mk_mod(const std::vector ¶ms); 150 | 151 | dagc * mk_abs(dagc * param); 152 | dagc * mk_abs(const std::vector ¶ms); 153 | 154 | dagc * mk_le(dagc * l, dagc * r); 155 | dagc * mk_lt(dagc * l, dagc * r); 156 | dagc * mk_ge(dagc * l, dagc * r); 157 | dagc * mk_gt(dagc * l, dagc * r); 158 | dagc * mk_le(const std::vector ¶ms); 159 | dagc * mk_lt(const std::vector ¶ms); 160 | dagc * mk_ge(const std::vector ¶ms); 161 | dagc * mk_gt(const std::vector ¶ms); 162 | 163 | dagc * mk_toreal(dagc * param); 164 | dagc * mk_toreal(const std::vector ¶ms); 165 | dagc * mk_toint(dagc * param); 166 | dagc * mk_toint(const std::vector ¶ms); 167 | dagc * mk_isint(dagc * param); 168 | dagc * mk_isint(const std::vector ¶ms); 169 | 170 | // parse smt-lib2 file 171 | void parse_smtlib2_file(const std::string filename); 172 | // // parse model file 173 | void parseModel(std::string filename, boost::unordered_map& recs); 174 | 175 | private: 176 | 177 | // attributes 178 | 179 | // vars for parser 180 | char *buffer; 181 | unsigned long buflen; 182 | char *bufptr; 183 | unsigned int line_number; 184 | SCAN_MODE scan_mode; 185 | 186 | boost::unordered_map key_map; 187 | std::vector vlet_key_list; 188 | 189 | // error node 190 | dagc * err_node; 191 | // const node 192 | boost::unordered_map constants; 193 | 194 | //methods 195 | 196 | //mk 197 | dagc * mk_err(const ERROR_TYPE t) { 198 | err_node->t = NT_ERROR; err_node->id = t; return err_node; 199 | }; 200 | dagc * mk_oper(const NODE_TYPE t, dagc * p, const std::string &s = "", vType val = 0); 201 | dagc * mk_oper(const NODE_TYPE t, dagc * l, dagc * r, const std::string &s = "", vType val = 0); 202 | dagc * mk_oper(const NODE_TYPE t, std::vector &p, const std::string &s = "", vType val = 0); 203 | 204 | dagc * mk_let(const NODE_TYPE t, std::vector &p, const std::string &s = "", vType val = 0); 205 | 206 | dagc * mk_eq_bool(dagc * l, dagc * r); 207 | 208 | // parse smtlib2 file 209 | std::string get_symbol(); 210 | void scan_to_next_symbol(); 211 | void parse_lpar(); 212 | void parse_rpar(); 213 | void skip_to_rpar(); 214 | 215 | 216 | CMD_TYPE parse_command(); 217 | dagc * parse_expr(); 218 | std::vector parse_params(); 219 | dagc * parse_let(); 220 | 221 | //errors & warnings 222 | void err_all(const ERROR_TYPE e, const std::string s = "", const unsigned int ln = 0) const; 223 | void err_all(const dagc * e, const std::string s = "", const unsigned int ln = 0) const; 224 | 225 | void err_unexp_eof() const; 226 | void err_sym_mis(const std::string mis, const unsigned int ln) const; 227 | void err_sym_mis(const std::string mis, const std::string nm, const unsigned int ln) const; 228 | void err_unkwn_sym(const std::string nm, const unsigned int ln) const; 229 | void err_param_mis(const std::string nm, const unsigned int ln) const; 230 | void err_param_nbool(const std::string nm, const unsigned int ln) const; 231 | void err_param_nnum(const std::string nm, const unsigned int ln) const; 232 | void err_param_nsame(const std::string nm, const unsigned int ln) const; 233 | void err_logic(const std::string nm, const unsigned int ln) const; 234 | void err_mul_decl(const std::string nm, const unsigned int ln) const; 235 | void err_mul_def(const std::string nm, const unsigned int ln) const; 236 | void err_nlinear(const std::string nm, const unsigned int ln) const; 237 | void err_zero_divisor(const unsigned int ln) const; 238 | 239 | void err_open_file(const std::string) const; 240 | 241 | void warn_cmd_nsup(const std::string nm, const unsigned int ln) const; 242 | 243 | }; 244 | 245 | 246 | 247 | 248 | } 249 | 250 | #endif 251 | -------------------------------------------------------------------------------- /solvers/blaster/blaster_solver.cpp: -------------------------------------------------------------------------------- 1 | /* blaster_solver.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "solvers/blaster/blaster_solver.hpp" 9 | 10 | #include 11 | 12 | using namespace ismt; 13 | 14 | #define modelDebug 0 15 | 16 | // ------------init and deinit------------ 17 | blaster_solver::blaster_solver(std::string n){ 18 | solver = new sat_solver(n); 19 | default_len = 10; 20 | auxSize = 0; 21 | slackSize = 0; 22 | 23 | setvvEqMode(Recursion); 24 | setvvCompMode(Transposition); 25 | setviEqMode(Recursion); 26 | setviCompMode(Transposition); 27 | add2i = false; 28 | } 29 | 30 | blaster_solver::~blaster_solver(){ 31 | clear(); 32 | } 33 | void blaster_solver::reset(){ 34 | clearVars(); 35 | solver->reset(); 36 | } 37 | void blaster_solver::clearVars(){ 38 | boost::unordered_map::iterator viter = n2var.begin(); 39 | while(viter!=n2var.end()){ 40 | if(!viter->second->isConstant()){ 41 | viter->second->clear(); 42 | } 43 | viter++; 44 | } 45 | n2bool.clear(); 46 | EqZeroMap.clear(); 47 | } 48 | void blaster_solver::clear(){ 49 | boost::unordered_map::iterator viter = n2var.begin(); 50 | while(viter!=n2var.end()){ 51 | delete viter->second; 52 | viter->second = nullptr; 53 | viter++; 54 | } 55 | boost::unordered_map::iterator iiter = n2int.begin(); 56 | while(iiter!=n2int.end()){ 57 | delete iiter->second; 58 | iiter->second = nullptr; 59 | iiter++; 60 | } 61 | 62 | // TODO? error? 63 | delete solver; 64 | solver = nullptr; 65 | } 66 | void blaster_solver::setBenchmark(std::string file){ 67 | benchmark = file; 68 | solver->setBenchmark(file); 69 | } 70 | 71 | // ------------output errors------------ 72 | void blaster_solver::outputError(const std::string& mesg){ 73 | std::cout<True()) return; 83 | if(copy_lits[i]==-solver->False()) return; 84 | else if(copy_lits[i]==solver->False()) continue; 85 | else if(copy_lits[i]==-solver->True()) continue; 86 | else if(i!=0&©_lits[i]==copy_lits[i-1]) continue; 87 | else ans.emplace_back(copy_lits[i]); 88 | } 89 | solver->addClause(ans); 90 | } 91 | 92 | // ------------solve operations------------ 93 | int blaster_solver::Assert(literal lit){ 94 | literals lits { lit }; 95 | solver->addClause(lits); 96 | return 1; 97 | } 98 | bool blaster_solver::solve(){ 99 | solver->solve(); 100 | if(State::SAT==solver->getState()) getModel(); 101 | return State::SAT==solver->getState(); 102 | } 103 | bool blaster_solver::solve(const literals& assumptions){ 104 | if(assumptions.size() == 0) return true; 105 | solver->solve(assumptions); 106 | if(State::SAT==solver->getState()) getModel(); 107 | return State::SAT==solver->getState(); 108 | } 109 | bool blaster_solver::simplify(){ 110 | literals c; 111 | return simplify(c); 112 | } 113 | bool blaster_solver::simplify(const literals& assumptions){ 114 | solver->simplify(assumptions); 115 | if(State::SAT==solver->getState()) getModel(); 116 | return State::UNSAT!=solver->getState(); 117 | } 118 | 119 | // calculate value from bit-blasting 120 | Integer blaster_solver::calculate(bvar var){ 121 | int sign = mdl[abs(var->signBit())]?-1:1; 122 | #if modelDebug 123 | std::cout<getName()<<": 0x"<signBit())]; 124 | #endif 125 | Integer answer = 0; 126 | if(sign==-1){ 127 | for(int i=var->size()-1;i>0;i--){ 128 | answer = answer*2 + (mdl[abs(var->getAt(i))]?0:1); 129 | 130 | #if modelDebug 131 | std::cout<<(mdl[abs(var->getAt(i))]?0:1); 132 | #endif 133 | } 134 | answer += 1; 135 | } 136 | else{ 137 | for(int i=var->size()-1;i>0;i--){ 138 | answer = answer*2 + (mdl[abs(var->getAt(i))]?1:0); 139 | 140 | #if modelDebug 141 | std::cout<<(mdl[abs(var->getAt(i))]?1:0); 142 | #endif 143 | } 144 | } 145 | 146 | #if modelDebug 147 | std::cout<<"; value: "<<(sign==-1?-answer:answer)<<"."<getState()); 155 | mdl = solver->getModel(); 156 | for(size_t i=0;iisConstant()){ 158 | ProblemVars[i]->setCurValue(calculate(ProblemVars[i])); 159 | } 160 | } 161 | } 162 | 163 | // ------------get operations------------ 164 | void blaster_solver::printModel(){ 165 | std::cout<<"(model"<getName()<<" () Int "\ 168 | <getCurValue()<<")\n"; 169 | } 170 | 171 | boost::unordered_map::iterator iter; 172 | iter = n2bool.begin(); 173 | while(iter!=n2bool.end()){ 174 | std::cout<<"(define-fun "<first<<" () Bool "\ 175 | <<(mdl[iter->second]?"true":"false")<<")\n"; 176 | iter++; 177 | } 178 | std::cout<<")"<nVars()<nClauses()<getCurValue(); 186 | } 187 | Integer blaster_solver::getValue(const std::string& name){ 188 | if(n2var.find(name)!=n2var.end()){ 189 | bvar var = n2var[name]; 190 | return var->getCurValue(); 191 | } 192 | else if(n2bool.find(name)!=n2bool.end()){ 193 | return (mdl[n2bool[name]]?1:0); 194 | } 195 | else { std::cout<True(); } 255 | literal blaster_solver::Lit_False() { return solver->False(); } 256 | -------------------------------------------------------------------------------- /rewriters/eq_rewriter.cpp: -------------------------------------------------------------------------------- 1 | /* eq_rewriter.cpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #include "rewriters/eq_rewriter.hpp" 9 | 10 | using namespace ismt; 11 | 12 | void eq_rewriter::setModel(model_s* m){ model = m; } 13 | // TODO substitute 14 | // TODO not support local model 15 | dagc* eq_rewriter::rewrite(dagc* root, bool isTop){ 16 | if(root->iscbool() || root->istrue() || root->isfalse()){} 17 | else if(isTop){ 18 | if(root->iseq()){ 19 | dagc* a = root->children[0]; 20 | dagc* b = root->children[1]; 21 | if(a->iscnum() && b->iscnum()){ 22 | // a == b 23 | if(a->v!=b->v){ 24 | consistent = false; 25 | return parser->mk_false(); 26 | } 27 | else return parser->mk_true(); 28 | } 29 | else if(a->iscnum() && b->isvnum()){ 30 | // v = x 31 | if(model->set(b, a->v)) return parser->mk_true(); 32 | else{ 33 | consistent = false; 34 | return parser->mk_false(); 35 | } 36 | } 37 | else if(a->isvnum() && b->iscnum()){ 38 | // x = v 39 | if(model->set(a, b->v)) return parser->mk_true(); 40 | else{ 41 | consistent = false; 42 | return parser->mk_false(); 43 | } 44 | } 45 | else if(a->isvnum() && b->isvnum()){ 46 | // x = y 47 | 48 | // assume substitute in model and globalSubSet is the same. 49 | // so that the union sets are the same. 50 | if(model->substitute(a, b)) return parser->mk_true(); 51 | else{ 52 | consistent = false; 53 | return parser->mk_false(); 54 | } 55 | } 56 | } 57 | else if(root->iseqbool()){ 58 | dagc* a = root->children[0]; 59 | dagc* b = root->children[1]; 60 | if(a->iscbool() && b->iscbool()){ 61 | // a == b 62 | if(a->v!=b->v){ 63 | consistent = false; 64 | return parser->mk_false(); 65 | } 66 | else return parser->mk_true(); 67 | } 68 | else if(a->iscbool() && b->isvbool()){ 69 | // v = x 70 | if(model->set(b, a->v)) return parser->mk_true(); 71 | else{ 72 | consistent = false; 73 | return parser->mk_false(); 74 | } 75 | } 76 | else if(a->isvbool() && b->iscbool()){ 77 | // x = v 78 | if(model->set(a, b->v)) return parser->mk_true(); 79 | else{ 80 | consistent = false; 81 | return parser->mk_false(); 82 | } 83 | } 84 | else if(a->isvbool() && b->isvbool()){ 85 | // x = y 86 | if(model->substitute(a, b)) return parser->mk_true(); 87 | else{ 88 | consistent = false; 89 | return parser->mk_false(); 90 | } 91 | } 92 | } 93 | else{ 94 | std::vector::iterator it = root->children.begin(); 95 | if(root->isvbool()){ 96 | model->set(root, 1); 97 | return parser->mk_true(); 98 | } 99 | else if(root->isand()){ 100 | while(it!=root->children.end()){ 101 | *it = rewrite(*it, isTop); 102 | ++it; 103 | } 104 | } 105 | else if(root->isor()){ 106 | // nothing to do 107 | } 108 | else if(root->isnot()){ 109 | // data->printAST(root); 110 | // std::cout<print(); 112 | assert( (*it)->iscomp() || 113 | (*it)->isvbool() || 114 | (*it)->iseqbool() || 115 | (*it)->isneqbool() || 116 | (*it)->isletbool() 117 | ); 118 | // let bool is permitted 119 | if(!(*it)->isvbool() && !(*it)->isletbool()){ 120 | *it = rewrite(*it, true); 121 | if((*it)->istrue()){ 122 | return parser->mk_false(); 123 | } 124 | else if((*it)->isfalse()){ 125 | return parser->mk_true(); 126 | } 127 | // else nothing to do 128 | } 129 | // else (*it)->isvbool() 130 | } 131 | else if(root->iscomp()){ 132 | // not eq then nothing to do 133 | } 134 | else if(root->isletbool()){ 135 | *it = rewrite(*it, true); 136 | if((*it)->istrue()){ 137 | return parser->mk_false(); 138 | } 139 | else if((*it)->isfalse()){ 140 | return parser->mk_true(); 141 | } 142 | } 143 | else {root->print(); assert(false);} 144 | } 145 | } 146 | else{ 147 | // in and 148 | if(root->isand()){ 149 | disjoint_set localSubset; 150 | boost::unordered_map localAssigned; 151 | root = localRewrite(root, localSubset, localAssigned); 152 | } 153 | else{ 154 | for(size_t i=0;ichildren.size();i++){ 155 | rewrite(root->children[i], false); 156 | } 157 | } 158 | } 159 | return root; 160 | } 161 | // TODO local rewrite 162 | 163 | bool eq_rewriter::localAssign(boost::unordered_map& localAssigned, dagc* root, Integer val){ 164 | if(localAssigned.find(root)!=localAssigned.end()){ 165 | if(localAssigned[root]!=val) return false; 166 | else return true; 167 | } 168 | else if(model->has(root) && model->getValue(root)!=val) return false; // conflict with top assignment 169 | else localAssigned.insert(std::pair(root, val)); 170 | return true; 171 | } 172 | bool eq_rewriter::localSubsitute(disjoint_set& localSubset, dagc* a, dagc* b){ 173 | localSubset.add(a); 174 | localSubset.add(b); 175 | localSubset.union_set(a, b); 176 | return true; 177 | } 178 | dagc* eq_rewriter::localRewrite( 179 | dagc* root, 180 | disjoint_set& localSubset, 181 | boost::unordered_map& localAssigned){ 182 | // or(0) - and(1) - or(2) - and(3), we analyze starting from (1) to (3). 183 | // for example, (or ... (and (= x 3) (= x 4) (or (= (+ x y) 8) (= (+ x y) 6)))). 184 | // i.e. ... \/ (x = 3 /\ y = 4 /\ (x + y = 8 \/ x + y = 6)) -> ... \/ false -> ... 185 | // currently not supported, we implement a more powerful analysis procedure in poly solver's rewriters. 186 | 187 | // note that higher assignment will be vaild in lower assignment, 188 | // lower assignment is not available in higher assignment. 189 | 190 | auto it = root->children.begin(); 191 | if(root->iseq()){ 192 | dagc* a = root->children[0]; 193 | dagc* b = root->children[1]; 194 | if(a->iscnum() && b->iscnum()){ 195 | // a == b 196 | if(a->v!=b->v) return parser->mk_false(); 197 | *it = parser->mk_true(); 198 | } 199 | else if(a->iscnum() && b->isvnum()){ 200 | // v = x 201 | if(localAssign(localAssigned, b, a->v)){} 202 | else{ 203 | return parser->mk_false(); 204 | } 205 | } 206 | else if(a->isvnum() && b->iscnum()){ 207 | // x = v 208 | if(localAssign(localAssigned, a, b->v)){} 209 | else{ 210 | return parser->mk_false(); 211 | } 212 | } 213 | else if(a->isvnum() && b->isvnum()){ 214 | // x = y 215 | 216 | // assume substitute in model and globalSubSet is the same. 217 | // so that the union sets are the same. 218 | localSubsitute(localSubset, a, b); 219 | } 220 | } 221 | else if(root->iseqbool()){ 222 | dagc* a = root->children[0]; 223 | dagc* b = root->children[1]; 224 | if(a->iscbool() && b->iscbool()){ 225 | // a == b 226 | if(a->v!=b->v){ 227 | return parser->mk_false(); 228 | } 229 | *it = parser->mk_true(); 230 | } 231 | else if(a->iscbool() && b->isvbool()){ 232 | // v = x 233 | if(localAssign(localAssigned, b, a->v)){} 234 | else{ 235 | return parser->mk_false(); 236 | } 237 | } 238 | else if(a->isvbool() && b->iscbool()){ 239 | // x = v 240 | if(localAssign(localAssigned, a, b->v)){} 241 | else{ 242 | return parser->mk_false(); 243 | } 244 | } 245 | else if(a->isvbool() && b->isvbool()){ 246 | // x = y 247 | localSubsitute(localSubset, a, b); 248 | } 249 | } 250 | else if(root->isand()){ 251 | // first find eq / eqbool 252 | while(it!=root->children.end()){ 253 | if((*it)->iseq() && (*it)->children.size()==2){ 254 | *it = localRewrite(*it, localSubset, localAssigned); 255 | } 256 | else if((*it)->iseqbool() && (*it)->children.size()==2){ 257 | *it = localRewrite(*it, localSubset, localAssigned); 258 | } 259 | ++it; 260 | } 261 | // then check consistency at the same level 262 | it = root->children.begin(); 263 | std::vector rep; 264 | while(it!=root->children.end()){ 265 | if(localAssigned.find(*it) != localAssigned.end()){ 266 | if((*it)->istrue()){} // nothing to do 267 | else if((*it)->isfalse()) return parser->mk_false(); 268 | } 269 | rep.emplace_back(localRewrite(*it, localSubset, localAssigned)); 270 | ++it; 271 | } 272 | root->children.clear(); 273 | root->children.assign(rep.begin(), rep.end()); 274 | } 275 | else if(root->isor()){ 276 | std::vector rep; 277 | while(it!=root->children.end()){ 278 | if(localAssigned.find(*it) != localAssigned.end()){ 279 | if((*it)->istrue()) return parser->mk_true(); 280 | else if((*it)->isfalse()) {} // nothing to do 281 | } 282 | rep.emplace_back(localRewrite(*it, localSubset, localAssigned)); 283 | ++it; 284 | } 285 | root->children.clear(); 286 | root->children.assign(rep.begin(), rep.end()); 287 | } 288 | else if(root->isnot()){ 289 | if(localAssigned.find(*it) != localAssigned.end()){ 290 | if((*it)->istrue()) return parser->mk_false(); 291 | else if((*it)->isfalse()) return parser->mk_true(); 292 | } 293 | // else now not support? 294 | } 295 | else if(root->iscomp()){ 296 | // evaluate assignment 297 | // now not support? 298 | } 299 | 300 | return root; 301 | } 302 | 303 | 304 | bool eq_rewriter::rewrite(){ 305 | auto it = data->assert_list.begin(); 306 | while(it!=data->assert_list.end()){ 307 | if((*it)->isconst()){} 308 | else if((*it)->iseq() || (*it)->iseqbool()){ 309 | dagc* t = rewrite(*it, true); 310 | if(!consistent){ 311 | return false; 312 | } 313 | *it = t; 314 | } 315 | else *it = rewrite(*it); 316 | ++it; 317 | } 318 | return true; 319 | } -------------------------------------------------------------------------------- /solvers/blaster/blaster_solver.hpp: -------------------------------------------------------------------------------- 1 | /* blaster_solver.hpp 2 | * 3 | * Copyright (C) 2023-2026 Fuqi Jia. 4 | * 5 | * All rights reserved. 6 | */ 7 | 8 | #ifndef _BLASTER_H 9 | #define _BLASTER_H 10 | 11 | 12 | #include "solvers/sat/sat_solver.hpp" 13 | #include "solvers/blaster/blaster_types.hpp" 14 | 15 | #include 16 | #include 17 | #include 18 | 19 | using std::to_string; 20 | namespace ismt 21 | { 22 | typedef enum {Slack, Recursion, Transposition} ConstraintsMode; 23 | class blaster_solver 24 | { 25 | private: 26 | // solver 27 | std::string sname; 28 | std::string benchmark; 29 | sat_solver* solver = nullptr; 30 | model mdl; 31 | 32 | // map from name get variables 33 | boost::unordered_map n2var; 34 | boost::unordered_map n2int; // int uses its Integer as key, NEW 35 | boost::unordered_map n2bool; 36 | boost::unordered_map EqZeroMap; 37 | boost::unordered_map addIntScore; 38 | boost::unordered_map initIntScore; 39 | boost::unordered_map addBoolScore; 40 | boost::unordered_map initBoolScore; 41 | 42 | // cache for storing problem variables 43 | std::vector ProblemVars; 44 | 45 | // bit len 46 | unsigned default_len; 47 | 48 | // coding mode 49 | bool add2i; 50 | ConstraintsMode vvEqMode; 51 | ConstraintsMode vvCompMode; 52 | ConstraintsMode viEqMode; 53 | ConstraintsMode viCompMode; 54 | 55 | // eq and comp function pointer 56 | literal vvEq (bvar var1, bvar var2); 57 | literal vvGt (bvar var1, bvar var2); 58 | literal vvGe (bvar var1, bvar var2); 59 | literal vvNeq (bvar var1, bvar var2); 60 | literal viEq (bvar var, bvar v); 61 | literal viGt (bvar var, bvar v); 62 | literal viGe (bvar var, bvar v); 63 | literal viNeq (bvar var, bvar v); 64 | 65 | // auxiliary number 66 | unsigned auxSize; 67 | unsigned slackSize; 68 | 69 | public: 70 | blaster_solver (std::string n = "cadical"); 71 | ~blaster_solver (); 72 | 73 | 74 | // make blast_variables 75 | bvar mkVar (const std::string& name); 76 | bvar mkVar (const std::string& name, unsigned len); 77 | bvar mkInnerVar (const std::string& name, unsigned len); // inner var, not appear in model. 78 | bvar mkInt (Integer v); 79 | bvar mkHolder (const std::string& name, unsigned len); // NEW, a placeholder. 80 | bvar blast (bvar var); // NEW, holder blast to the solver. 81 | bool_var mkBool (const std::string& name); 82 | void addVar (bvar var); // add a variable to the vector. 83 | void addVarMap (bvar var); // add a variable to the map. 84 | void copy (bvar var, std::string& name, bvar& target); // deep copy for var. 85 | void copyInt (bvar var, bvar& target); // deep copy for var. 86 | 87 | // logic operations 88 | literal Not (const literal& l); 89 | literal And (const literals& lits); 90 | literal And (const literal& lit1, const literal& lit2); 91 | literal Or (const literals& lits); 92 | literal Or (const literal& lit1, const literal& lit2); 93 | literal Ite_bool (literal cond, literal ifp, literal elp); 94 | literal EqualBool (const literal& lit1, const literal& lit2); 95 | literal NotEqualBool (const literal& lit1, const literal& lit2); 96 | 97 | // math atom operations 98 | literal Less (bvar var1, bvar var2); 99 | literal Equal (bvar var1, bvar var2); 100 | literal Greater (bvar var1, bvar var2); 101 | literal NotEqual (bvar var1, bvar var2); 102 | literal LessEqual (bvar var1, bvar var2); 103 | literal GreaterEqual (bvar var1, bvar var2); 104 | 105 | // math operations 106 | bvar Negate (bvar var); 107 | bvar Absolute (bvar var); 108 | bvar Add (bvar var1, bvar var2); 109 | bvar Divide (bvar var1, bvar var2); 110 | bvar Modulo (bvar var1, bvar var2); 111 | bvar Subtract (bvar var1, bvar var2); 112 | bvar Multiply (bvar var1, bvar var2); 113 | bvar Ite_num (literal cond, bvar ifp, bvar elp); 114 | 115 | // solve operations 116 | int Assert (literal lit); 117 | bool solve (); 118 | bool solve (const literals& assumptions); 119 | bool simplify (); 120 | bool simplify (const literals& assumptions); 121 | 122 | // get operations 123 | void printModel (); 124 | void printStatus (); 125 | Integer getValue (const bvar& var); 126 | Integer getValue (const std::string& name); 127 | 128 | // set operations 129 | void setDeaultLen (unsigned len); 130 | void setSlackAddi (bool s); 131 | void setvvEqMode (ConstraintsMode c); 132 | void setvvCompMode (ConstraintsMode c); 133 | void setviEqMode (ConstraintsMode c); 134 | void setviCompMode (ConstraintsMode c); 135 | 136 | // reset: clear sat solver, and blaster variables. 137 | void reset (); 138 | void setBenchmark (std::string file); 139 | 140 | private: 141 | // auxiliary make variable functions 142 | bvar mkInvertedVar (bvar var); 143 | bvar mkShiftedVar (bvar var, int len); 144 | bool_var newSatVar (); // NEW 145 | 146 | // escape 10000... -2^n 147 | // variable has range of [1-2^n, 2^n-1] 148 | void Escape (bvar var); 149 | 150 | void swap (bvar& a, bvar& b); 151 | 152 | // auxiliary functions 153 | literal GtZero (bvar var); 154 | literal GeZero (bvar var); 155 | literal LtZero (bvar var); 156 | literal LeZero (bvar var); 157 | literal EqZero (bvar var); 158 | literal NeqZero (bvar var); 159 | // Slack Abstraction: e.g. a > b <=> a == b + t /\ t > 0. 160 | literal SEqual (bvar var1, bvar var2); 161 | literal SNotEqual (bvar var1, bvar var2); 162 | literal SGreater (bvar var1, bvar var2); 163 | literal SGreaterEqual (bvar var1, bvar var2); 164 | literal SEqualInt (bvar var1, bvar var2); 165 | literal SNotEqualInt (bvar var1, bvar var2); 166 | literal SGreaterInt (bvar var1, bvar var2); 167 | literal SGreaterEqualInt (bvar var1, bvar var2); 168 | 169 | // Recursion Abstraction: e.g. a > b <=> a[1] > a[2] or a[1] == a[2] /\ a[2:] > b[2:] 170 | literal REqual (bvar var1, bvar var2); 171 | literal RNotEqual (bvar var1, bvar var2); 172 | literal RGreater (bvar var1, bvar var2); 173 | literal RGreaterEqual (bvar var1, bvar var2); 174 | literal REqualInt (bvar var1, bvar var2); 175 | literal RNotEqualInt (bvar var1, bvar var2); 176 | literal RLessInt (bvar var, bvar v); 177 | literal RGreaterInt (bvar var, bvar v); 178 | literal RCompIntLoop (bvar var, bvar v, bool greater); 179 | literal RGreaterEqualInt (bvar var, bvar v); 180 | literal RGreaterBit (const literal& var, const literal& v); 181 | literal RLessBitInt (const literal& var, const literal& v); 182 | literal RGreaterBitInt (const literal& var, const literal& v); 183 | 184 | // Transposition Abstraction: e.g. a > b <=> a - b > 0 185 | literal TEqual (bvar var1, bvar var2); 186 | literal TNotEqual (bvar var1, bvar var2); 187 | literal TGreater (bvar var1, bvar var2); 188 | literal TGreaterEqual (bvar var1, bvar var2); 189 | literal TEqualInt (bvar var1, bvar var2); 190 | literal TNotEqualInt (bvar var1, bvar var2); 191 | literal TGreaterInt (bvar var1, bvar var2); 192 | literal TGreaterEqualInt (bvar var1, bvar var2); 193 | 194 | // equal operations 195 | void innerEqualVar (bvar var1, bvar var2); 196 | void innerEqualBit (literal var1, literal var2); 197 | void innerEqualInt (bvar var, bvar v); 198 | void innerEqualBitInt (literal var, literal v); 199 | literal EqualVar (bvar var1, bvar var2); 200 | literal EqualBit (literal var1, literal var2); 201 | literal EqualInt (bvar var, bvar v); 202 | literal EqualBitInt (literal var, literal v); 203 | literal NotEqualVar (bvar var1, bvar var2); 204 | literal NotEqualBit (literal var1, literal var2); 205 | literal NotEqualInt (bvar var, bvar v); 206 | literal NotEqualBitInt (literal var, literal v); 207 | 208 | // auxiliary functions for math operations 209 | bvar Add (bvar var1, bvar var2, bool addone); 210 | bvar Invert (bvar var); 211 | bvar AddOne (bvar var); 212 | bvar MultiplyInt (bvar var, bvar v); 213 | bvar MultiplyBit (bvar var, literal bit, unsigned len); 214 | bvar MultiplyBitInt (bvar var, literal bit, unsigned len); // NEW 215 | bvar Shift (bvar var, int len); 216 | bvar ShiftAdd (bvar subsum, bvar subans, bvar answer, unsigned idx); 217 | // bool_var MultiplySignBit (bvar var1, bvar var2); 218 | 219 | // inner auxiliary functions for math operations 220 | void doCarry (literal cry1, literal varmax, literal varmin, literal cry0); 221 | void doTarget (literal target, literal varmax, literal varmin, literal cry); 222 | void doCarryInt (literal cry1, literal var, literal ivar, literal cry0); 223 | void doTargetInt (literal target, literal var, literal ivar, literal cry); 224 | 225 | 226 | // calculate value from bit-blasting 227 | Integer calculate (bvar var); // after getModel, calculate real value. 228 | 229 | // get model 230 | void getModel (); 231 | 232 | // delete functions 233 | void clear (); 234 | void clearVars (); 235 | 236 | // add clause to sat solver 237 | void addClause (clause& c); 238 | 239 | // output error and exit 240 | void outputError (const std::string& mesg); 241 | public: 242 | // ------------information operations------------ 243 | literal Lit_True (); 244 | literal Lit_False (); 245 | }; 246 | 247 | // ------------outer auxiliary functions------------ 248 | inline int min(int a, int b) { return a>b?b:a; } 249 | inline int max(int a, int b) { return a>b?a:b; } 250 | inline int abs(int a) { return a>0?a:-a; } 251 | 252 | } // namespace ismt 253 | 254 | 255 | #endif --------------------------------------------------------------------------------