metaSMT 2
|
00001 #pragma once 00002 00003 #include "support/SMT_Graph.hpp" 00004 #include "Graph_Context.hpp" 00005 #include "result_wrapper.hpp" 00006 #include "Features.hpp" 00007 #include "API/Assertion.hpp" 00008 #include "API/Assumption.hpp" 00009 00010 #include <boost/foreach.hpp> 00011 #include <boost/shared_ptr.hpp> 00012 #include <boost/spirit/include/phoenix_core.hpp> 00013 #include <boost/spirit/include/phoenix_bind.hpp> 00014 00015 #include <vector> 00016 00017 namespace metaSMT { 00018 00019 template <typename Callee, typename T> 00020 struct CallByTag { 00021 CallByTag(Callee * callee, std::vector<T> const & args, boost::any const & arg) 00022 : callee(callee), args(args), arg(arg) {} 00023 00024 00025 typedef typename Callee::result_type result_type; 00026 00027 template <typename TagT> 00028 result_type operator() (TagT tag) const { 00029 switch(args.size()) { 00030 case 0: 00031 //printf("call op0\n"); 00032 return (*callee)( tag, arg ); 00033 case 1: 00034 //printf("call op1\n"); 00035 return (*callee)( tag, args[0] ); 00036 case 2: 00037 //printf("call op2\n"); 00038 return (*callee)( tag, args[0], args[1] ); 00039 case 3: 00040 //printf("call op3\n"); 00041 return (*callee)( tag, args[0], args[1], args[2] ); 00042 default: 00043 assert( false && "unexpeced case" ); 00044 } 00045 throw std::runtime_error("unexpected"); 00046 } 00047 00048 result_type operator() (metaSMT::logic::QF_BV::tag::extract_tag tag) const { 00049 assert(args.size() > 0); 00050 assert(args.size() == 1); 00051 unsigned long upper, lower; 00052 boost::tie(upper, lower) 00053 = boost::any_cast<boost::tuple<unsigned long, unsigned long> >(arg); 00054 return (*callee)( tag, upper, lower, args.front() ); 00055 } 00056 00057 result_type operator() (metaSMT::logic::QF_BV::tag::zero_extend_tag tag) const { 00058 assert(args.size() > 0); 00059 assert(args.size() == 1); 00060 unsigned long width 00061 = boost::any_cast< unsigned long >(arg); 00062 return (*callee)( tag, width, args.front() ); 00063 } 00064 00065 result_type operator() (metaSMT::logic::QF_BV::tag::sign_extend_tag tag) const { 00066 assert(args.size() > 0); 00067 assert(args.size() == 1); 00068 unsigned long width 00069 = boost::any_cast< unsigned long >(arg); 00070 return (*callee)( tag, width, args.front() ); 00071 } 00072 00073 mutable Callee * callee; 00074 std::vector<T> const & args; 00075 boost::any const & arg; 00076 }; 00077 00078 template <typename Callee, typename T> 00079 CallByTag<Callee, T> make_callByTag(Callee * callee, std::vector<T> const & args, boost::any const & arg) { 00080 return CallByTag<Callee, T>(callee, args, arg); 00081 } 00082 00083 00089 template<typename SolverContext> 00090 struct GraphSolver_Context { 00091 00092 GraphSolver_Context ( ) 00093 : _gtx( new Graph_Context() ) 00094 { } 00095 00096 explicit GraphSolver_Context ( const GraphSolver_Context & ctx ) 00097 : _gtx( ctx._gtx ) // share graph 00098 , _solver() // create new solver 00099 , _lookup() // create new lookup table 00100 , _assertions( ctx._assertions ) // copy assertions 00101 , _assumptions( ctx._assumptions ) // copy assumptions 00102 { 00103 BOOST_FOREACH(SMT_Expression e, _assertions) { 00104 _solver.assertion ( _eval(e) ); 00105 } 00106 BOOST_FOREACH(SMT_Expression e, _assumptions) { 00107 _solver.assumption ( _eval(e) ); 00108 } 00109 } 00110 00111 typedef SolverContext solver_type; 00112 typedef SMT_Expression result_type; 00113 typedef typename SolverContext::result_type solver_result; 00114 00115 void assertion ( SMT_Expression e ) { 00116 namespace ph=boost::phoenix; 00117 _assertions.push_back(e); 00118 00119 Cmd f = 00120 ph::bind( &SolverContext::assertion, ph::ref(_solver), 00121 ph::bind(&GraphSolver_Context<SolverContext>::_eval, ph::ref(*this), e ) 00122 ); 00123 _cmd_queue.push_back(f); 00124 } 00125 00126 void assumption( SMT_Expression e ) { 00127 _assumptions.push_back(e); 00128 } 00129 00130 template< typename Context, typename CMD, typename Arg1 > 00131 struct Cmd_Caller1 { 00132 Cmd_Caller1( Context & ctx, CMD c, Arg1 a1) 00133 : ctx(ctx), cmd(c), arg1(a1) { } 00134 00135 void operator() (){ ctx.command(cmd, arg1); } 00136 00137 Context & ctx; 00138 CMD cmd; 00139 Arg1 arg1; 00140 }; 00141 00142 template< typename Context, typename CMD > 00143 struct Cmd_Caller0 { 00144 Cmd_Caller0( Context & ctx, CMD c) 00145 : ctx(ctx), cmd(c) { } 00146 00147 void operator() (){ ctx.command(cmd); } 00148 00149 Context & ctx; 00150 CMD cmd; 00151 }; 00152 00153 template <typename CMD, typename Arg> 00154 typename boost::enable_if< boost::is_same< typename CMD::result_type, void> >::type 00155 command (CMD const & cmd, Arg arg) 00156 { 00157 Cmd f = 00158 Cmd_Caller1<SolverContext, CMD, Arg>(_solver, cmd, arg); 00159 _cmd_queue.push_back(f); 00160 } 00161 00162 template <typename CMD> 00163 typename boost::enable_if< boost::is_same< typename CMD::result_type, void> >::type 00164 command (CMD const & cmd) 00165 { 00166 Cmd f = 00167 Cmd_Caller0<SolverContext, CMD>(_solver, cmd); 00168 _cmd_queue.push_back(f); 00169 } 00170 00171 template <typename CMD> 00172 typename CMD::result_type command(CMD const & cmd) 00173 { 00174 sync(); 00175 return _solver.command(cmd); 00176 } 00177 00178 void command( assertion_cmd const &, result_type e) { 00179 assertion(e); 00180 } 00181 void command( assumption_cmd const &, result_type e) { 00182 assumption(e); 00183 } 00184 00185 00186 void sync() { 00187 BOOST_FOREACH( Cmd const & f, _cmd_queue) { 00188 f(); 00189 } 00190 _cmd_queue.clear(); 00191 } 00192 00193 bool solve() { 00194 sync(); 00195 //BOOST_FOREACH(SMT_Expression e, _assertions) { 00196 // _solver.assertion ( _eval(e) ); 00197 //} 00198 BOOST_FOREACH(SMT_Expression e, _assumptions) { 00199 _solver.assumption ( _eval(e) ); 00200 } 00201 _assumptions.clear(); 00202 return _solver.solve(); 00203 } 00204 00205 void write_smt(std::ostream &os) { 00206 SMT_ExprContainer v; 00207 std::copy(_assertions.begin(), _assertions.end(), 00208 std::back_inserter(v)); 00209 std::copy(_assumptions.begin(), _assumptions.end(), 00210 std::back_inserter(v)); 00211 _gtx->write_smt(os, v); 00212 } 00213 00214 void write_smt(std::ostream &os, result_type r) { 00215 SMT_ExprContainer v(1,r); 00216 _gtx->write_smt(os, v); 00217 } 00218 00219 struct create_x_result : boost::static_visitor<result_wrapper> 00220 { 00221 template<typename T> 00222 result_type operator() (T) const { 00223 return result_wrapper(boost::logic::indeterminate); 00224 } 00225 00226 result_type operator() (logic::QF_BV::tag::var_tag const & var) const { 00227 std::vector<boost::logic::tribool> ret ( var.width 00228 , boost::logic::indeterminate); 00229 return result_wrapper(ret); 00230 } 00231 }; 00232 00233 result_wrapper read_value(SMT_Expression var) 00234 { 00235 typename LookupT::const_iterator ite 00236 = _lookup.find(var); 00237 if ( ite != _lookup.end() ) { 00238 return _solver.read_value( _eval( var ) ); 00239 } else { 00240 return boost::apply_visitor(create_x_result() 00241 , boost::get(boost::vertex_tag, _gtx->graph(), var)); 00242 } 00243 } 00244 00245 template <typename Expr> 00246 SMT_Expression evaluate ( Expr e ) { return ::metaSMT::evaluate(*_gtx, e); } 00247 00248 SMT_Expression evaluate ( result_type r ) { return r; } 00249 00250 private: 00251 solver_result _eval( SMT_Expression e) { 00252 typename LookupT::const_iterator ite = _lookup.find(e); 00253 if ( ite != _lookup.end() ) { 00254 return ite->second; 00255 } 00256 00257 SMT_Graph const & g = _gtx->graph(); 00258 00259 std::vector<solver_result> args; 00260 // ... fill args 00261 BOOST_FOREACH(SMT_Edge k, out_edges(e,g)) { 00262 args.push_back( _eval(target(k,g)) ); 00263 } 00264 00265 boost::any arg = boost::get(boost::vertex_arg, g, e); 00266 Tag tag = boost::get(boost::vertex_tag, g, e); 00267 00268 solver_result ret = boost::apply_visitor( make_callByTag(&_solver, args, arg), tag); 00269 _lookup.insert( std::make_pair(e, ret) ); 00270 return ret; 00271 }; 00272 00273 boost::shared_ptr<Graph_Context> _gtx; 00274 solver_type _solver; 00275 typedef typename std::map<SMT_Expression, solver_result> LookupT; 00276 typedef boost::function0<void> Cmd; 00277 typedef std::list< Cmd > Cmd_Queue; 00278 typedef std::vector<SMT_Expression> SMT_ExprContainer; 00279 LookupT _lookup; 00280 SMT_ExprContainer _assertions; 00281 SMT_ExprContainer _assumptions; 00282 Cmd_Queue _cmd_queue; 00283 }; 00284 00285 namespace features { 00286 template<typename Context, typename Feature> 00287 struct supports< GraphSolver_Context<Context>, Feature> 00288 : supports<Context, Feature>::type {}; 00289 00290 template<typename Context> 00291 struct supports< GraphSolver_Context<Context>, assertion_cmd> 00292 : boost::mpl::true_ {}; 00293 00294 template<typename Context> 00295 struct supports< GraphSolver_Context<Context>, assumption_cmd> 00296 : boost::mpl::true_ {}; 00297 } 00298 00299 template <typename SolverTypes, typename Expr> 00300 SMT_Expression evaluate( GraphSolver_Context<SolverTypes> & ctx, Expr const & e ) { 00301 return ctx.evaluate(e) ; 00302 } 00303 00304 template <typename SolverTypes> 00305 bool solve( GraphSolver_Context<SolverTypes> & ctx) { 00306 return ctx.solve(); 00307 } 00308 00309 template <typename SolverTypes> 00310 void write_smt( GraphSolver_Context<SolverTypes> & ctx, std::ostream &os ) { 00311 ctx.write_smt(os); 00312 } 00313 00314 template <typename SolverTypes> 00315 result_wrapper 00316 read_value( 00317 GraphSolver_Context<SolverTypes> & ctx 00318 , logic::QF_BV::bitvector const & var) 00319 { 00320 return ctx.read_value( evaluate(ctx, var) ); 00321 } 00322 00323 template <typename SolverTypes> 00324 result_wrapper 00325 read_value( 00326 GraphSolver_Context<SolverTypes> & ctx 00327 , logic::predicate const & var) 00328 { 00329 return ctx.read_value( evaluate(ctx, var) ); 00330 } 00331 00332 template <typename SolverTypes> 00333 result_wrapper 00334 read_value( 00335 GraphSolver_Context<SolverTypes> & ctx 00336 , SMT_Expression const & var) 00337 { 00338 return ctx.read_value( var ); 00339 } 00340 00341 } // namespace metaSMT 00342 00343 // vim: ft=cpp:ts=2:sw=2:expandtab