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