metaSMT git

metaSMT/backend/Z3_Context.hpp

Go to the documentation of this file.
00001 #pragma once
00002 
00003 #include "../tags/QF_BV.hpp"
00004 #include "../tags/Array.hpp"
00005 #include "../result_wrapper.hpp"
00006 #include "../Features.hpp"
00007 
00008 extern "C" {
00009 #include <z3.h>
00010 }
00011 
00012 #include <iostream>
00013 #include <string>
00014 #include <map>
00015 #include <boost/mpl/map.hpp>
00016 #include <boost/mpl/map/map40.hpp>
00017 #include <boost/dynamic_bitset.hpp>
00018 #include <boost/any.hpp>
00019 
00020 #include <boost/spirit/include/qi.hpp>
00021 #include <boost/tuple/tuple.hpp>
00022 #include <boost/tuple/tuple_io.hpp>
00023 #include <boost/fusion/adapted/boost_tuple.hpp>
00024 #include <boost/fusion/adapted/std_pair.hpp>
00025 // #include <boost/spirit/debug.hpp>
00026 
00027 namespace metaSMT {
00028 
00029   // forward declare stack api
00030   struct stack_pop;
00031   struct stack_push;
00032   namespace features {
00033     struct stack_api;
00034   } /* features */
00035 
00036 
00037   namespace solver {
00038 
00039     namespace predtags = ::metaSMT::logic::tag;
00040     namespace bvtags = ::metaSMT::logic::QF_BV::tag;
00041     namespace arraytags = ::metaSMT::logic::Array::tag;
00042     namespace qi = boost::spirit::qi;
00043     namespace ascii = boost::spirit::ascii;
00044 
00051     class Z3_Context {
00052     public:
00053       typedef Z3_ast result_type;
00054 
00055       Z3_Context () {
00056         Z3_config cfg;
00057         cfg = Z3_mk_config();
00058         z3_ = Z3_mk_context(cfg);
00059         Z3_del_config(cfg);
00060         m_ = 0;
00061         assumption_ = (*this)(predtags::true_tag(), boost::any());
00062       }
00063 
00064       ~Z3_Context() {
00065         if (m_) {
00066           Z3_del_model(z3_, m_);
00067           m_ = 0;
00068         }
00069         if (z3_) {
00070           Z3_del_context(z3_);
00071           z3_ = 0;
00072         }
00073       }
00074 
00075       void assertion( result_type e ) {
00076         Z3_assert_cnstr(z3_, e);
00077       }
00078 
00079       void assumption( result_type e ) {
00080         Z3_ast args[2] = { assumption_, e };
00081         assumption_ = Z3_mk_and(z3_, 2, args);
00082       }
00083 
00084       void command ( stack_push const &, unsigned howmany) {
00085         while (howmany > 0) {
00086           Z3_push(z3_);
00087           --howmany;
00088         }
00089       }
00090 
00091       void command ( stack_pop const &, unsigned howmany) {
00092         Z3_pop(z3_, howmany);
00093       }
00094 
00095       bool solve() {
00096         if (m_) {
00097           Z3_del_model(z3_, m_);
00098           m_ = 0;
00099           model_map_.clear();
00100         }
00101         Z3_push(z3_);
00102         assertion(assumption_);
00103         Z3_lbool sat = Z3_check_and_get_model(z3_, &m_);
00104         Z3_pop(z3_, 1);
00105         assumption_ = (*this)(predtags::true_tag(), boost::any());
00106         // Z3_trace_to_file(z3_, "z3_trace_log.txt");
00107         return (sat == Z3_L_TRUE);
00108       }
00109 
00110       result_wrapper read_value(result_type var) {
00111         if (model_map_.empty()) {
00112           std::string model_str = Z3_model_to_string(z3_, m_);
00113           // std::cout << model_str << '\n';
00114           build_model_map(model_str);
00115         }
00116         std::string var_name = Z3_ast_to_string(z3_, var);
00117 
00118         model_map::const_iterator it = model_map_.find(var_name);
00119         if (it != model_map_.end()) {
00120 
00121           unsigned value = it->second.get<0>();
00122           unsigned width = it->second.get<1>();
00123 
00124           if (width == 0) {
00125             return result_wrapper(value == 1);
00126           }
00127 
00128           boost::dynamic_bitset<> bv(width, value);
00129           std::string str; to_string(bv, str);
00130           return result_wrapper(str);
00131         }
00132 
00133         // XXX: determinate size?
00134         // return result_wrapper(boost::logic::indeterminate);
00135         return result_wrapper(false);
00136       }
00137 
00138       result_type operator() (predtags::false_tag , boost::any arg) {
00139         return Z3_mk_false(z3_);
00140       }
00141 
00142       result_type operator() (predtags::true_tag , boost::any arg) {
00143         return Z3_mk_true(z3_);
00144       }
00145 
00146       result_type operator() (predtags::nor_tag ,
00147                               result_type a,
00148                               result_type b) {
00149         Z3_ast args[2] = { a, b };
00150         return Z3_mk_not(z3_, Z3_mk_or(z3_, 2, args));
00151       }
00152 
00153       result_type operator() (predtags::nand_tag ,
00154                               result_type a,
00155                               result_type b) {
00156         Z3_ast args[2] = { a, b };
00157         return Z3_mk_not(z3_, Z3_mk_and(z3_, 2, args));
00158       }
00159 
00160       result_type operator() (predtags::xnor_tag ,
00161                               result_type a,
00162                               result_type b) {
00163         return Z3_mk_not(z3_, Z3_mk_xor(z3_, a, b));
00164       }
00165 
00166       result_type operator() (predtags::ite_tag ,
00167                               result_type a,
00168                               result_type b,
00169                               result_type c) {
00170         return Z3_mk_ite(z3_, a, b, c);
00171       }
00172 
00173       result_type operator() (predtags::var_tag const & var, boost::any args) {
00174         Z3_sort ty = Z3_mk_bool_sort(z3_);
00175         char buf[64];
00176         sprintf(buf, "var_%u", var.id);
00177         Z3_symbol s = Z3_mk_string_symbol(z3_, buf);
00178         return Z3_mk_const(z3_, s, ty);
00179       }
00180 
00181       result_type operator() (bvtags::bvcomp_tag ,
00182                               result_type a,
00183                               result_type b) {
00184         return Z3_mk_ite(z3_, Z3_mk_eq(z3_, a, b),
00185                          (*this)(bvtags::bit1_tag(), boost::any()),
00186                          (*this)(bvtags::bit0_tag(), boost::any()));
00187       }
00188 
00189       result_type operator() (bvtags::extract_tag const &,
00190                               unsigned long upper, unsigned long lower,
00191                               result_type e) {
00192         return Z3_mk_extract(z3_, upper, lower, e);
00193       }
00194 
00195         result_type operator() (bvtags::zero_extend_tag const & 
00196             , unsigned long width
00197             , result_type e)
00198         {
00199           return Z3_mk_zero_ext(z3_, width, e);
00200         }
00201 
00202         result_type operator() (bvtags::sign_extend_tag const & 
00203             , unsigned long width
00204             , result_type e)
00205         {
00206           return Z3_mk_sign_ext(z3_, width, e);
00207         }
00208 
00209       result_type operator() (bvtags::var_tag const & var, boost::any args) {
00210         Z3_sort ty = Z3_mk_bv_sort(z3_, var.width);
00211         char buf[64];
00212         sprintf(buf, "var_%u", var.id);
00213         Z3_symbol s = Z3_mk_string_symbol(z3_, buf);
00214         return Z3_mk_const(z3_, s, ty);
00215       }
00216 
00217       result_type operator() (bvtags::bit0_tag , boost::any arg) {
00218         Z3_sort ty = Z3_mk_bv_sort(z3_, 1);
00219         return Z3_mk_unsigned_int(z3_, 0, ty);
00220       }
00221 
00222       result_type operator() (bvtags::bit1_tag , boost::any arg) {
00223         Z3_sort ty = Z3_mk_bv_sort(z3_, 1);
00224         return Z3_mk_unsigned_int(z3_, 1, ty);
00225       }
00226 
00227       result_type operator() (bvtags::bvuint_tag , boost::any arg) {
00228         typedef boost::tuple<unsigned long, unsigned long> P;
00229         P p = boost::any_cast<P>(arg);
00230         unsigned value = boost::get<0>(p);
00231         unsigned width = boost::get<1>(p);
00232         Z3_sort ty = Z3_mk_bv_sort(z3_, width);
00233         return Z3_mk_unsigned_int(z3_, value, ty);
00234       }
00235 
00236       result_type operator() (bvtags::bvsint_tag , boost::any arg) {
00237         typedef boost::tuple<long, unsigned long> P;
00238         P p = boost::any_cast<P>(arg);
00239         unsigned value = boost::get<0>(p);
00240         unsigned width = boost::get<1>(p);
00241         Z3_sort ty = Z3_mk_bv_sort(z3_, width);
00242         return Z3_mk_int(z3_, value, ty);
00243       }
00244 
00245       result_type operator() (bvtags::bvbin_tag , boost::any arg) {
00246         std::string s = boost::any_cast<std::string>(arg);
00247         boost::dynamic_bitset<> bv(s);
00248         Z3_sort ty = Z3_mk_bv_sort(z3_, bv.size());
00249         return Z3_mk_unsigned_int(z3_, bv.to_ulong(), ty);
00250       }
00251 
00252       // XXX will be removed in a later revision
00253       result_type operator() (bvtags::bvhex_tag , boost::any arg) {
00254         std::string hex = boost::any_cast<std::string>(arg);
00255         std::string bin (hex.size()*4,'\0');
00256 
00257         for (unsigned i = 0; i < hex.size(); ++i) {
00258           switch ( tolower(hex[i]) ) {
00259           case '0':
00260             bin.replace(4*i,4, "0000");
00261             break;
00262           case '1':
00263             bin.replace(4*i,4, "0001");
00264             break;
00265           case '2':
00266             bin.replace(4*i,4, "0010");
00267             break;
00268           case '3':
00269             bin.replace(4*i,4, "0011");
00270             break;
00271           case '4':
00272             bin.replace(4*i,4, "0100");
00273             break;
00274           case '5':
00275             bin.replace(4*i,4, "0101");
00276             break;
00277           case '6':
00278             bin.replace(4*i,4, "0110");
00279             break;
00280           case '7':
00281             bin.replace(4*i,4, "0111");
00282             break;
00283           case '8':
00284             bin.replace(4*i,4, "1000");
00285             break;
00286           case '9':
00287             bin.replace(4*i,4, "1001");
00288             break;
00289           case 'a':
00290             bin.replace(4*i,4, "1010");
00291             break;
00292           case 'b':
00293             bin.replace(4*i,4, "1011");
00294             break;
00295           case 'c':
00296             bin.replace(4*i,4, "1100");
00297             break;
00298           case 'd':
00299             bin.replace(4*i,4, "1101");
00300             break;
00301           case 'e':
00302             bin.replace(4*i,4, "1110");
00303             break;
00304           case 'f':
00305             bin.replace(4*i,4, "1111");
00306             break;
00307           }
00308         }
00310         return (*this)(bvtags::bvbin_tag(), bin);
00311       }
00312 
00313       result_type operator() (arraytags::array_var_tag const & var, boost::any const & ) 
00314       {
00315         if(var.id == 0 ) {
00316           throw std::runtime_error("uninitialized array used");
00317         }
00318         Z3_sort indexT = Z3_mk_bv_sort(z3_, var.index_width );
00319         Z3_sort elemT  = Z3_mk_bv_sort(z3_, var.elem_width );
00320 
00321         Z3_sort ty = Z3_mk_array_sort(z3_, indexT, elemT);
00322 
00323         char buf[64];
00324         sprintf(buf, "var_%u", var.id);
00325         Z3_symbol s = Z3_mk_string_symbol(z3_, buf);
00326         return  Z3_mk_const(z3_, s, ty);
00327       }
00328 
00329       result_type operator() (arraytags::select_tag const &
00330                               , result_type array
00331                               , result_type index) {
00332         //return boolector_read(_btor, array, index);
00333         return Z3_mk_select(z3_, array, index);
00334       }
00335 
00336       result_type operator() (arraytags::store_tag const &
00337                               , result_type array
00338                               , result_type index
00339                               , result_type value) {
00340         //return boolector_write(_btor, array, index, value);
00341         return Z3_mk_store(z3_, array, index, value);
00342       }
00343 
00345       // Fallback operators //
00347 
00348       template <typename TagT>
00349       result_type operator() (TagT tag, boost::any args ) {
00350         return (*this)(predtags::false_tag(), boost::any());
00351       }
00352 
00353       template< Z3_ast (*FN) (Z3_context, Z3_ast) >
00354       struct Z3_F1 {
00355         static Z3_ast exec(Z3_context c, Z3_ast x) {
00356           return (*FN)(c, x);
00357         }
00358       };
00359 
00360       template <typename TagT>
00361       result_type operator() (TagT tag, result_type a) {
00362         namespace mpl = boost::mpl;
00363 
00364         typedef mpl::map<
00365           mpl::pair<predtags::not_tag,      Z3_F1<&Z3_mk_not> >
00366         , mpl::pair<bvtags::bvneg_tag,      Z3_F1<&Z3_mk_bvneg> >
00367         , mpl::pair<bvtags::bvnot_tag,      Z3_F1<&Z3_mk_bvnot> >
00368         > UnaryOpcodeMap;
00369 
00370         typedef
00371           typename mpl::has_key< UnaryOpcodeMap, TagT >::type
00372           _has_key;
00373         if  ( _has_key::value ) {
00374           typedef typename mpl::eval_if<
00375           _has_key
00376           , mpl::at< UnaryOpcodeMap, TagT >
00377           , mpl::identity< Z3_F1<Z3_mk_not> >
00378           >::type opcode;
00379           return opcode::exec(z3_, a);
00380         } else {
00381           std::cout << "unknown operator: " << tag << std::endl;
00382           assert(false && "unknown operator");
00383           return (*this)(predtags::false_tag(), boost::any());
00384         }
00385       }
00386 
00387       template< Z3_ast (*FN) (Z3_context, Z3_ast, Z3_ast) >
00388       struct Z3_F2 {
00389         static Z3_ast exec(Z3_context c, Z3_ast x, Z3_ast y) {
00390           return (*FN)(c, x, y);
00391         }
00392       };
00393 
00394       template< Z3_ast (*FN) (Z3_context, unsigned, Z3_ast const []) >
00395       struct Z3_F2_MULTI_ARG {
00396         static Z3_ast exec(Z3_context c, Z3_ast x, Z3_ast y) {
00397           Z3_ast args[2] = { x, y };
00398           return (*FN)(c, 2, args);
00399         }
00400       };
00401 
00402       template <typename TagT>
00403       result_type operator() (TagT tag, result_type a, result_type b) {
00404         namespace mpl = boost::mpl;
00405 
00406         typedef mpl::map31<
00407           mpl::pair<bvtags::bvand_tag,      Z3_F2<&Z3_mk_bvand> >
00408         , mpl::pair<bvtags::bvnand_tag,     Z3_F2<&Z3_mk_bvnand> >
00409         , mpl::pair<bvtags::bvor_tag,       Z3_F2<&Z3_mk_bvor> >
00410         , mpl::pair<bvtags::bvxor_tag,      Z3_F2<&Z3_mk_bvxor> >
00411         , mpl::pair<bvtags::bvnor_tag,      Z3_F2<&Z3_mk_bvnor> >
00412         , mpl::pair<bvtags::bvxnor_tag,     Z3_F2<&Z3_mk_bvxnor> >
00413         , mpl::pair<bvtags::bvsub_tag,      Z3_F2<&Z3_mk_bvsub> >
00414         , mpl::pair<bvtags::bvadd_tag,      Z3_F2<&Z3_mk_bvadd> >
00415         , mpl::pair<bvtags::bvmul_tag,      Z3_F2<&Z3_mk_bvmul> >
00416         , mpl::pair<bvtags::bvsle_tag,      Z3_F2<&Z3_mk_bvsle> >
00417 
00418         , mpl::pair<bvtags::bvslt_tag,      Z3_F2<&Z3_mk_bvslt> >
00419         , mpl::pair<bvtags::bvsge_tag,      Z3_F2<&Z3_mk_bvsge> >
00420         , mpl::pair<bvtags::bvsgt_tag,      Z3_F2<&Z3_mk_bvsgt> >
00421         , mpl::pair<bvtags::bvule_tag,      Z3_F2<&Z3_mk_bvule> >
00422         , mpl::pair<bvtags::bvult_tag,      Z3_F2<&Z3_mk_bvult> >
00423         , mpl::pair<bvtags::bvuge_tag,      Z3_F2<&Z3_mk_bvuge> >
00424         , mpl::pair<bvtags::bvugt_tag,      Z3_F2<&Z3_mk_bvugt> >
00425         , mpl::pair<predtags::implies_tag,  Z3_F2<&Z3_mk_implies> >
00426         , mpl::pair<predtags::xor_tag,      Z3_F2<&Z3_mk_xor> >
00427         , mpl::pair<predtags::and_tag,      Z3_F2_MULTI_ARG<&Z3_mk_and> >
00428 
00429         , mpl::pair<predtags::or_tag,       Z3_F2_MULTI_ARG<&Z3_mk_or> >
00430         , mpl::pair<predtags::equal_tag,    Z3_F2<&Z3_mk_eq> >
00431         , mpl::pair<predtags::nequal_tag,   Z3_F2_MULTI_ARG<&Z3_mk_distinct> >
00432         , mpl::pair<bvtags::concat_tag,     Z3_F2<&Z3_mk_concat> >
00433         , mpl::pair<bvtags::bvudiv_tag,     Z3_F2<&Z3_mk_bvudiv> >
00434         , mpl::pair<bvtags::bvurem_tag,     Z3_F2<&Z3_mk_bvurem> >
00435         , mpl::pair<bvtags::bvsdiv_tag,     Z3_F2<&Z3_mk_bvsdiv> >
00436         , mpl::pair<bvtags::bvsrem_tag,     Z3_F2<&Z3_mk_bvsrem> >
00437         , mpl::pair<bvtags::bvshl_tag,      Z3_F2<&Z3_mk_bvshl> >
00438         , mpl::pair<bvtags::bvshr_tag,      Z3_F2<&Z3_mk_bvlshr> >
00439 
00440         , mpl::pair<bvtags::bvashr_tag,     Z3_F2<&Z3_mk_bvashr> >
00441         > BinaryOpcodeMap;
00442 
00443         typedef
00444           typename mpl::has_key< BinaryOpcodeMap, TagT >::type
00445           _has_key;
00446         if ( _has_key::value ) {
00447           typedef typename mpl::eval_if<
00448             _has_key
00449             , mpl::at< BinaryOpcodeMap, TagT >
00450             , mpl::identity< Z3_F2<Z3_mk_bvand> >
00451             >::type opcode;
00452           return opcode::exec(z3_, a, b);
00453         } else {
00454           std::cout << "unknown operator: " << tag << std::endl;
00455           assert(false && "unknown operator");
00456           return (*this)(predtags::false_tag(), boost::any());
00457         }
00458       }
00459 
00460       template <typename TagT, typename T1, typename T2, typename T3>
00461       result_type operator() (TagT tag, T1 a, T2 b, T3 c) {
00462         return (*this)(predtags::false_tag(), boost::any());
00463       }
00464 
00465     protected:
00466       typedef std::string::const_iterator ConstIterator;
00467       typedef boost::tuple<unsigned, unsigned> BitvectorTuple;
00468       typedef std::pair<std::string, BitvectorTuple> NamedTuple;
00469 
00470       void build_model_map(std::string const &assign_str) {
00471         ConstIterator it = assign_str.begin();
00472         ConstIterator ie = assign_str.end();
00473 
00474         //std::cout << assign_str << std::endl;
00475 
00476         static qi::rule<ConstIterator, std::string() > name_rule
00477           = +(qi::char_ - ' ')
00478           ;
00479 
00480         static qi::rule<ConstIterator, BitvectorTuple() > true_rule
00481           = "true" >> qi::attr(1u) >> qi::attr(0u)
00482           ;
00483 
00484         static qi::rule<ConstIterator, BitvectorTuple() > false_rule
00485           = "false" >> qi::attr(0u) >> qi::attr(0u)
00486           ;
00487 
00488         static qi::rule<ConstIterator, BitvectorTuple() > bitvector_rule
00489           = "bv" >> qi::uint_ >> '[' >> qi::uint_ >> ']'
00490           ;
00491         static qi::rule<ConstIterator, BitvectorTuple() > value_rule
00492           = ( true_rule | false_rule | bitvector_rule );
00493           
00494         static qi::rule<ConstIterator, NamedTuple() > line_2_15
00495           = name_rule >> qi::lit(" -> ")  
00496             >> ( true_rule | false_rule | bitvector_rule ) 
00497           ;
00498 
00499         static qi::rule<ConstIterator> sexpr
00500           = qi::lit("(")
00501           >> *(~qi::char_("("))
00502           >> *sexpr
00503           >> *(~qi::char_(")"))
00504           >> qi::lit(")")
00505           ;
00506 
00507         // tested with for 2.18 and 2.19
00508         static qi::rule<ConstIterator, NamedTuple() > line_2_18
00509           = qi::lit("(define ") >> name_rule >> qi::lit(" ")
00510             >> value_rule >> ')'
00511           ;
00512         static qi::rule<ConstIterator, model_map() > rule
00513           = *((
00514                 line_2_18 
00515               | line_2_15
00516               | sexpr
00517               ) >> -qi::eol )
00518           ;
00519 
00520         rule.name("rule");
00521         true_rule.name("true_rule");
00522         false_rule.name("false_rule");
00523         bitvector_rule.name("bitvector_rule");
00524         name_rule.name("name_rule");
00525 
00526         //debug(rule); // requires implementation of operator <<(.) for model_map
00527         //debug(name_rule);
00528         //debug(true_rule);
00529         //debug(false_rule);
00530         //debug(bitvector_rule);
00531 
00532         if (qi::parse(it, ie, rule, model_map_)) {
00533           assert( it == ie && "Expression not completely consumed" );
00534           return;
00535         }
00536 
00537         assert(false && "Parsing failed");
00538       }
00539 
00540     private:
00541       typedef std::map<std::string, BitvectorTuple> model_map;
00542       model_map model_map_;
00543 
00544       Z3_context z3_;
00545       Z3_model m_;
00546       Z3_ast assumption_;
00547     };
00548   } // namespace solver
00549 
00550   namespace features {
00551     template<>
00552     struct supports< solver::Z3_Context, features::stack_api>
00553     : boost::mpl::true_ {};
00554   } /* features */
00555 
00556 } // namespace metaSMT
00557 
00558 //  vim: ft=cpp:ts=2:sw=2:expandtab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines