metaSMT git
|
00001 #pragma once 00002 00003 #include "../tags/QF_BV.hpp" 00004 #include "../tags/Array.hpp" 00005 #include "../support/SMT_Tag_Mapping.hpp" 00006 #include "../support/find_executable.hpp" 00007 00008 #include "../result_wrapper.hpp" 00009 00010 #include <iostream> 00011 #include <fstream> 00012 #include <boost/mpl/map/map40.hpp> 00013 #include <boost/any.hpp> 00014 #include <boost/format.hpp> 00015 #include <boost/tuple/tuple.hpp> 00016 #include <boost/iostreams/device/file_descriptor.hpp> 00017 #include <boost/iostreams/stream.hpp> 00018 #include <boost/iostreams/tee.hpp> 00019 00020 #include <boost/spirit/include/qi.hpp> 00021 #include <boost/tuple/tuple_io.hpp> 00022 #include <boost/fusion/adapted/boost_tuple.hpp> 00023 #include <boost/fusion/adapted/std_pair.hpp> 00024 00025 namespace metaSMT { 00026 00027 struct write_comment; 00028 namespace features { 00029 struct comment_api; 00030 } /* features */ 00031 namespace solver { 00032 00033 namespace predtags = ::metaSMT::logic::tag; 00034 namespace bvtags = ::metaSMT::logic::QF_BV::tag; 00035 namespace arraytags = ::metaSMT::logic::Array::tag; 00036 00037 struct lazy_string { 00038 00039 lazy_string () 00040 : dirty(false), _str(), _concats() 00041 {} 00042 00043 lazy_string (std::string const & s) 00044 : dirty(false), _str(s), _concats() 00045 {} 00046 00047 //operator std::string { 00048 // _eval(); 00049 // return _str; 00050 //} 00051 00052 size_t size() const { 00053 size_t ret = _str.size(); 00054 BOOST_FOREACH( lazy_string const & ls, _concats ) { 00055 ret += ls.size(); 00056 } 00057 return ret; 00058 } 00059 00060 void _eval( std::string & str) { 00061 if( dirty ) { 00062 str.reserve(size()); 00063 BOOST_FOREACH( lazy_string const & ls, _concats ) { 00064 //str += (std::string) ls; 00065 } 00066 } 00067 dirty = false; 00068 } 00069 00070 bool dirty; 00071 std::string _str; 00072 std::list<lazy_string> _concats; 00073 }; 00074 00075 struct smt2_solver_pipe { 00076 smt2_solver_pipe(std::ofstream &os, std::ofstream &solution_os) 00077 : os_(os) 00078 , solution_os_(solution_os) 00079 , _solver(NULL) 00080 , _result(NULL) 00081 { 00082 int toSolver[2]; 00083 int fromSolver[2]; 00084 if ( pipe(toSolver) == -1 || pipe(fromSolver) == -1 ) { 00085 throw std::runtime_error("opening pipe failed"); 00086 } 00087 int cpid = fork(); 00088 if( cpid == -1) { 00089 close(toSolver[0]); 00090 close(toSolver[1]); 00091 close(fromSolver[0]); 00092 close(fromSolver[1]); 00093 throw std::runtime_error("fork failed"); 00094 } 00095 00096 if(cpid == 0 ) { 00097 // solver process 00098 close(toSolver[1]); // unused 00099 close(fromSolver[0]); // unused 00100 00101 dup2(toSolver[0],0); 00102 dup2(fromSolver[1],1); 00103 //execlp("cat", "cat", NULL); 00104 std::string z3 = support::find_executable("z3", "Z3_EXECUTABLE"); 00105 //std::cerr << "using Z3: " << z3 << std::endl; 00106 execlp(z3.c_str(), z3.c_str(), "-smt2", "-in", NULL); 00107 perror("exec"); 00108 exit(1); 00109 } else { 00110 // parent writes solution 00111 close(toSolver[0]); // unused 00112 close(fromSolver[1]); // unused 00113 00114 _solver = new solver_stream(toSolver[1], boost::iostreams::close_handle); 00115 _result = new result_stream(fromSolver[0], boost::iostreams::close_handle); 00116 } 00117 } 00118 00119 void command ( write_comment const &, std::string const & message) { 00120 os_ << ";; " << message << '\n'; 00121 } 00122 00123 ~smt2_solver_pipe() { 00124 delete _solver; 00125 delete _result; 00126 } 00127 00128 std::ostream & solver() { 00129 assert( _solver->is_open()); 00130 return *_solver; 00131 } 00132 00133 std::istream & result() { 00134 assert( _result->is_open()); 00135 return *_result; 00136 } 00137 00138 void get_response(std::string & response) 00139 { 00140 //std::cout << "; " << _result->rdbuf()->in_avail() << std::endl; 00141 std::getline(*_result, response); 00142 os_ << ";; " << response << std::endl; 00143 if (response == "sat" || response == "unsat") { 00144 solution_os_ << response << std::endl; 00145 } 00146 } 00147 00148 void check_response() { 00149 std::string response; 00150 std::getline(*_result, response); 00151 os_ << ";; " << response << std::endl; 00152 if( response != "success" ) { 00153 00154 throw std::runtime_error( 00155 boost::str(boost::format("expected successful responsem instead got '%s'") % response).c_str()); 00156 } 00157 } 00158 00159 void print_response() 00160 { 00161 //std::cout << "; " << _result->rdbuf()->in_avail() << std::endl; 00162 std::string response; 00163 std::getline(*_result, response); 00164 os_ << ";; " << response << std::endl; 00165 } 00166 00167 private: 00168 std::ofstream &os_; 00169 std::ofstream &solution_os_; 00170 00171 typedef boost::iostreams::stream<boost::iostreams::file_descriptor_sink> solver_stream; 00172 solver_stream *_solver; 00173 00174 typedef boost::iostreams::stream<boost::iostreams::file_descriptor_source> result_stream; 00175 result_stream *_result; 00176 00177 00178 template<typename Obj> 00179 friend 00180 smt2_solver_pipe & operator<< (smt2_solver_pipe & smt, Obj const & o) { 00181 smt.os_ << o; 00182 smt.solver() << o << std::flush; 00183 return smt; 00184 } 00185 }; 00186 00192 class SMT2 { 00193 00194 public: 00195 typedef std::string result_type; 00196 00197 SMT2 () 00198 : _pushed(false) 00199 , _outfile("meta.smt2") 00200 , _solution_file("meta.sol") 00201 , out(_outfile, _solution_file) 00202 { 00203 //out << "(set-option interactive-mode true)\n"; 00204 out << "(set-logic QF_BV)\n"; 00205 out.check_response(); 00206 00207 // for Z3 00208 out << "(set-option MODEL true)\n"; 00209 out.check_response(); 00210 00211 out << ";; Generated by metaSMT\n"; 00212 } 00213 00214 ~SMT2() { 00215 out << "(exit)\n"; 00216 out.print_response(); 00217 _outfile.close(); 00218 } 00219 00220 void command ( write_comment const &, std::string message) { 00221 out << ";; " << message << '\n'; 00222 } 00223 00224 void assertion( result_type e ) { 00225 restore_stack(); 00226 out << "(assert " << e << ")\n"; 00227 out.check_response(); 00228 } 00229 00230 void assumption( result_type e ) { 00231 _assumptions.push_back(e); 00232 } 00233 00234 void restore_stack () { 00235 if (_pushed) { 00236 out << "(pop 1)\n"; 00237 out.check_response(); 00238 _pushed = false; 00239 } 00240 } 00241 00242 bool solve() { 00243 restore_stack(); 00244 out << "(push 1)\n"; 00245 _pushed = true; 00246 out.check_response(); 00247 BOOST_FOREACH( result_type const & r, _assumptions) { 00248 out << "(assert " << r << ")\n"; 00249 out.check_response(); 00250 00251 } 00252 _assumptions.clear(); 00253 out << "(check-sat)\n"; 00254 std::string s; 00255 out.get_response(s); 00256 00257 if ( s!= "sat" && s != "unsat" ) { 00258 std::string message ="unknown solver result: "; 00259 message += s; 00260 throw std::runtime_error(message); 00261 } 00262 00263 return s== "sat"; 00264 } 00265 00266 result_wrapper read_value(result_type var) 00267 { 00268 out << boost::format("(get-value (%s))\n") % var; 00269 std::string s; 00270 out.get_response(s); 00271 00272 // predicate 00273 if (s == "(true)") { 00274 return result_wrapper(true); 00275 } else if (s == "(false)") { 00276 return result_wrapper(false); 00277 } 00278 00279 // bitvector 00280 typedef std::string::const_iterator ConstIterator; 00281 typedef boost::tuple<unsigned, unsigned> BitvectorTuple; 00282 static boost::spirit::qi::rule<ConstIterator, BitvectorTuple()> bitvector_rule 00283 = "((_ bv" >> boost::spirit::qi::uint_ >> " " >> boost::spirit::qi::uint_ >> "))" 00284 ; 00285 00286 BitvectorTuple bv; 00287 ConstIterator it = s.begin(); 00288 ConstIterator ie = s.end(); 00289 00290 if (boost::spirit::qi::parse(it, ie, bitvector_rule, bv)) { 00291 assert( it == ie && "Expression not completely consumed" ); 00292 return result_wrapper(bv.get<0>(), bv.get<1>()); 00293 } 00294 00295 // else 00296 return result_wrapper("X"); 00297 } 00298 00299 result_type operator() (predtags::var_tag const & var, boost::any args ) 00300 { 00301 char buf[64]; 00302 sprintf(buf, "var_%u", var.id); 00303 00304 restore_stack(); 00305 out << boost::format( "(declare-fun %s () Bool)\n") % buf; 00306 out.check_response(); 00307 return buf; 00308 } 00309 00310 result_type operator() (predtags::false_tag , boost::any arg ) { 00311 return "false"; 00312 } 00313 00314 result_type operator() (predtags::true_tag , boost::any arg ) { 00315 return "true"; 00316 } 00317 00318 result_type operator() (bvtags::var_tag const & var, boost::any args ) 00319 { 00320 assert ( var.width != 0 ); 00321 char buf[64]; 00322 sprintf(buf, "bitv_%u", var.id); 00323 00324 restore_stack(); 00325 out << boost::format( "(declare-fun %s () (_ BitVec %d))\n") % buf % var.width; 00326 out.check_response(); 00327 return buf; 00328 } 00329 00330 //result_type operator() (bvtags::bit0_tag , boost::any arg ) { 00331 // //return boolector_false(_btor); 00332 // return "#b0"; 00333 //} 00334 00335 //result_type operator() (bvtags::bit1_tag , boost::any arg ) { 00336 // //return boolector_true(_btor); 00337 // return "#b1"; 00338 //} 00339 00340 result_type operator() (bvtags::bvuint_tag , boost::any arg ) { 00341 typedef boost::tuple<unsigned long, unsigned long> P; 00342 P p = boost::any_cast<P>(arg); 00343 unsigned value = boost::get<0>(p); 00344 unsigned width = boost::get<1>(p); 00345 return boost::str( boost::format("bv%u[%u]")%value%width); 00346 } 00347 00348 result_type operator() (bvtags::bvsint_tag , boost::any arg ) { 00349 typedef boost::tuple<long, unsigned long> P; 00350 P p = boost::any_cast<P>(arg); 00351 long value = boost::get<0>(p); 00352 unsigned width = boost::get<1>(p); 00353 return boost::str( boost::format("bv%u[%u]") 00354 % static_cast<unsigned long>(value) 00355 % width 00356 ); 00357 } 00358 00359 result_type operator() (bvtags::bvbin_tag , boost::any arg ) { 00360 std::string val = boost::any_cast<std::string>(arg); 00361 return boost::str( boost::format("bvbin%s")%val); 00362 //return boost::str( boost::format("#b%s")%val); 00363 } 00364 00365 result_type operator() (bvtags::bvhex_tag , boost::any arg ) { 00366 std::string hex = boost::any_cast<std::string>(arg); 00367 return boost::str( boost::format("bvhex%s")%hex); 00368 //return boost::str( boost::format("#x%s")%hex); 00369 } 00370 00371 result_type operator() (bvtags::extract_tag const & 00372 , unsigned long upper, unsigned long lower 00373 , result_type e) 00374 { 00375 return boost::str( boost::format( 00376 "( (_ extract %u %u) %s )") %upper %lower %e ); 00377 } 00378 00379 result_type operator() (bvtags::zero_extend_tag const & 00380 , unsigned long width 00381 , result_type e) 00382 { 00383 return boost::str( boost::format( 00384 "( (_ zero_extend %u) %s )") % width% e); 00385 } 00386 00387 result_type operator() (bvtags::sign_extend_tag const & 00388 , unsigned long width 00389 , result_type e) 00390 { 00391 return boost::str( boost::format( 00392 "( (_ sign_extend %u) %s )") % width% e); 00393 } 00394 00395 result_type operator() (arraytags::array_var_tag const & var 00396 , boost::any args ) 00397 { 00398 //return boolector_array(_btor, var.elem_width, var.index_width, NULL); 00399 return "not_implemented"; 00400 } 00401 00402 result_type operator() (arraytags::select_tag const & 00403 , result_type array 00404 , result_type index) { 00405 //return boolector_read(_btor, array, index); 00406 return "not_implemented"; 00407 } 00408 00409 result_type operator() (arraytags::store_tag const & 00410 , result_type array 00411 , result_type index 00412 , result_type value) { 00413 //return boolector_write(_btor, array, index, value); 00414 return "not_implemented"; 00415 } 00416 00418 // Fallback operators // 00420 00421 template <typename TagT> 00422 result_type operator() (TagT tag, boost::any args ) { 00423 //return boolector_false(_btor); 00424 return get_tag_name(tag); 00425 } 00426 00427 00428 template <typename TagT> 00429 result_type operator() (TagT tag, result_type a ) { 00430 //return boolector_false(_btor); 00431 return std::string("(") + get_tag_name(tag) + " " + a + ")"; 00432 } 00433 00434 template <typename TagT> 00435 typename boost::enable_if< 00436 typename mpl::has_key< SMT_Negated_Map, TagT>::type 00437 , result_type 00438 >::type 00439 operator() (TagT tag, result_type a, result_type b) { 00440 typedef typename mpl::at< SMT_Negated_Map, TagT >::type p; 00441 00442 return (*this)( typename p::first(), (*this)( typename p::second(), a, b)); 00443 } 00444 00445 template <typename TagT> 00446 typename boost::disable_if< 00447 typename mpl::has_key< SMT_Negated_Map, TagT>::type 00448 , result_type 00449 >::type 00450 operator() (TagT tag, result_type a, result_type b) { 00451 return std::string("(") + get_tag_name(tag) + " " + a + " " + b + ")"; 00452 } 00453 00454 00455 template <typename TagT> 00456 result_type operator() (TagT tag, result_type a, result_type b, result_type c) { 00457 return std::string("(") + get_tag_name(tag) + " " + a 00458 + " " + b + " " + c + ")"; 00459 } 00460 00461 private: 00462 bool _pushed; 00463 std::ofstream _outfile; 00464 std::ofstream _solution_file; 00465 smt2_solver_pipe out; 00466 std::list<result_type> _assumptions; 00467 }; 00470 } // namespace solver 00471 00472 namespace features { 00473 template<> 00474 struct supports< solver::SMT2, features::comment_api> 00475 : boost::mpl::true_ {}; 00476 } /* features */ 00477 } // namespace metaSMT 00478 00479 // vim: ft=cpp:ts=2:sw=2:expandtab