metaSMT 2
metaSMT/GraphSolver_Context.hpp
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines