metaSMT git

metaSMT/backend/SMT2.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 "../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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines