metaSMT 2
|
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