dlvhex  2.5.0
testsuite/TestPlainHEX.cpp
Go to the documentation of this file.
00001 /* dlvhex -- Answer-Set Programming with external interfaces.
00002  * Copyright (C) 2005, 2006, 2007 Roman Schindlauer
00003  * Copyright (C) 2006, 2007, 2008, 2009, 2010 Thomas Krennwallner
00004  * Copyright (C) 2009, 2010 Peter Schüller
00005  * 
00006  * This file is part of dlvhex.
00007  *
00008  * dlvhex is free software; you can redistribute it and/or modify it
00009  * under the terms of the GNU Lesser General Public License as
00010  * published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * dlvhex is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with dlvhex; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00021  * 02110-1301 USA.
00022  */
00023 
00031 #ifdef HAVE_CONFIG_H
00032 #include "config.h"
00033 #endif // HAVE_CONFIG_H
00034 
00035 // dlvhex
00036 #define DLVHEX_BENCHMARK
00037 
00038 #include "dlvhex2/HexParser.h"
00039 #include "dlvhex2/PlatformDefinitions.h"
00040 #include "dlvhex2/Logger.h"
00041 #include "dlvhex2/ID.h"
00042 #include "dlvhex2/Table.h"
00043 #include "dlvhex2/TermTable.h"
00044 #include "dlvhex2/OrdinaryAtomTable.h"
00045 #include "dlvhex2/BuiltinAtomTable.h"
00046 #include "dlvhex2/AggregateAtomTable.h"
00047 #include "dlvhex2/ExternalAtomTable.h"
00048 #include "dlvhex2/RuleTable.h"
00049 #include "dlvhex2/ASPSolverManager.h"
00050 #include "dlvhex2/ASPSolver.h"
00051 #include "dlvhex2/Registry.h"
00052 #include "dlvhex2/Printer.h"
00053 #include "dlvhex2/ProgramCtx.h"
00054 #include "dlvhex2/PluginInterface.h"
00055 #include "dlvhex2/EvalGraphBuilder.h"
00056 #include "dlvhex2/EvalHeuristicOldDlvhex.h"
00057 #include "dlvhex2/EvalHeuristicTrivial.h"
00058 #include "dlvhex2/EvalHeuristicEasy.h"
00059 #include "dlvhex2/InputProvider.h"
00060 #include "dlvhex2/DependencyGraph.h"
00061 #include "dlvhex2/ComponentGraph.h"
00062 #include "dlvhex2/ModelGenerator.h"
00063 #include "dlvhex2/Benchmarking.h"
00064 #include "dlvhex2/OnlineModelBuilder.h"
00065 #include "dlvhex2/OfflineModelBuilder.h"
00066 
00067 // other
00068 
00069 #include <boost/algorithm/string/replace.hpp>
00070 #include <boost/bind.hpp>
00071 #include <boost/ref.hpp>
00072 #include <iostream>
00073 #include <fstream>
00074 #include <cstdlib>
00075 
00076 #include "graphviz.h"
00077 
00078 LOG_INIT(Logger::ERROR | Logger::WARNING)
00079 
00080 #ifndef NDEBUG
00081 # define LOG_REGISTRY_PROGRAM(ctx) \
00082   DBGLOG(DBG,*ctx.registry()); \
00083     RawPrinter printer(std::cerr, ctx.registry()); \
00084     std::cerr << "edb = " << *ctx.edb << std::endl; \
00085     DBGLOG(DBG,"idb"); \
00086     printer.printmany(ctx.idb,"\n"); \
00087     std::cerr << std::endl; \
00088     DBGLOG(DBG,"idb end");
00089 #else
00090 # define LOG_REGISTRY_PROGRAM(ctx) \
00091   do {} while(false);
00092 #endif
00093 
00094 using dlvhex::MT_IN;
00095 using dlvhex::MT_OUT;
00096 
00097 typedef boost::function<void (std::ostream&)> GraphVizFunc;
00098 
00099 inline void writeGraphVizFunctors(GraphVizFunc vfunc, GraphVizFunc tfunc, const std::string& fnamestart)
00100 {
00101   std::string fnamev(fnamestart);
00102   fnamev += "Verbose.dot";
00103   LOG(INFO,"dumping verbose graph to " << fnamev);
00104   std::ofstream filev(fnamev.c_str());
00105     vfunc(filev);
00106   makeGraphVizPdf(fnamev.c_str());
00107 
00108   std::string fnamet(fnamestart);
00109   fnamet += "Terse.dot";
00110   LOG(INFO,"dumping terse graph to " << fnamet);
00111   std::ofstream filet(fnamet.c_str());
00112   tfunc(filet);
00113   makeGraphVizPdf(fnamet.c_str());
00114 }
00115 
00116 template<typename GraphVizzyT>
00117 inline void writeGraphViz(const GraphVizzyT& gv, const std::string& fnamestart)
00118 {
00119     GraphVizFunc vfunc = boost::bind(&GraphVizzyT::writeGraphViz, boost::cref(gv), _1, true);
00120     GraphVizFunc tfunc = boost::bind(&GraphVizzyT::writeGraphViz, boost::cref(gv), _1, false);
00121     writeGraphVizFunctors(vfunc, tfunc, fnamestart);
00122 }
00123 
00124 DLVHEX_NAMESPACE_USE
00125 
00126 void breakLinesAndGraphViz(const std::string& str, std::ostream& o)
00127 {
00128   unsigned at = 0;
00129   for(std::string::const_iterator it = str.begin(); it != str.end(); ++it)
00130   {
00131     char c = *it;
00132     if( c == '\\' ) // assume this is a newline
00133       at = 0;
00134     if( c == '\"' )
00135       o << "\\\"";
00136     else
00137       o << c;
00138     // make a new line at least all 25 characters if there is a ','
00139     at++;
00140     if( at > 25 && c == ',' )
00141     {
00142       at = 0;
00143       o << "\\n";
00144     }
00145   }
00146 }
00147 
00148 typedef FinalEvalGraph::EvalUnit EvalUnit;
00149 
00150 //
00151 // model graph printing: putting this into ModelGraph is insane (modelgraph has a too abstract view of the model)
00152 // TODO think about improving the above situation
00153 //
00154 
00155 /* graphviz schema:
00156 digraph G {
00157     compound=true;
00158     subgraph evalunit1 {
00159       model1 [label1];
00160     }
00161     subgraph cluster1 {
00162       ...
00163     }
00164     ...
00165     model1 -> model2;
00166     ...
00167 }
00168 */
00169 // output graph as graphviz source
00170 template<typename ModelGraphT>
00171 void writeEgMgGraphViz(
00172         std::ostream& o, bool verbose,
00173         const FinalEvalGraph& eg, const ModelGraphT& mg,
00174     boost::optional<std::set<typename ModelGraphT::Model> > onlyForModels = boost::none)
00175 {
00176     typedef typename ModelGraphT::ModelList ModelList;
00177     typedef typename ModelGraphT::Model Model;
00178     typedef typename ModelGraphT::PredecessorIterator ModelPredecessorIterator;
00179     typedef typename ModelGraphT::ModelIterator ModelIterator;
00180   typedef std::set<typename ModelGraphT::Model> ModelSet;
00181 
00182   ModelSet printModels;
00183   if( !!onlyForModels )
00184   {
00185     // we need a hash map, as component graph is no graph with vecS-storage
00186     typedef boost::unordered_map<Model, boost::default_color_type> ColorHashMap;
00187     typedef boost::associative_property_map<ColorHashMap> ColorMap;
00188     ColorHashMap whiteHashMap;
00189 
00190     // fill white hash map
00191     ModelIterator mit, mit_end;
00192     for(boost::tie(mit, mit_end) = mg.getModels();
00193         mit != mit_end; ++mit)
00194     {
00195       whiteHashMap[*mit] = boost::white_color;
00196     }
00197 
00198     // one hash map for all!
00199     ColorHashMap myHashMap(whiteHashMap);
00200     ColorMap myColorMap(myHashMap);
00201     for(typename ModelSet::const_iterator it = onlyForModels.get().begin();
00202         it != onlyForModels.get().end(); ++it)
00203     {
00204       //LOG(INFO,"doing dfs visit for " << *it);
00205       boost::depth_first_visit(
00206           mg.getInternalGraph(),
00207           *it, 
00208           boost::default_dfs_visitor(),
00209           myColorMap);
00210     }
00211     for(boost::tie(mit, mit_end) = mg.getModels();
00212         mit != mit_end; ++mit)
00213     {
00214       if( myHashMap[*mit] == boost::white_color )
00215       {
00216         //LOG(INFO,"model " << *mit << " still white");
00217       }
00218       else
00219       {
00220         //LOG(INFO,"model " << *mit << " not white -> printing");
00221         printModels.insert(*mit);
00222       }
00223     }
00224   }
00225   else
00226   {
00227     // include all
00228     ModelIterator mit, mit_end;
00229     for(boost::tie(mit, mit_end) = mg.getModels();
00230         mit != mit_end; ++mit)
00231     {
00232       printModels.insert(*mit);
00233     }
00234   }
00235 
00236   // boost::graph::graphviz is horribly broken!
00237   // therefore we print it ourselves
00238 
00239   o << "digraph G {" << std::endl <<
00240     "rankdir=BT;" << std::endl << // print root nodes at bottom, leaves at top!
00241     "concentrate=true;" << std::endl <<
00242     //"center=false;" << std::endl <<
00243     "pagedir=BL;" << std::endl <<
00244     //"ranksep=\"0.5\";" << std::endl <<
00245     //"nodesep=\"0.5\";" << std::endl <<
00246     //"page=\"44,35\";" << std::endl <<
00247     "compound=true;" << std::endl; // print clusters = eval units, inside nodes = models
00248 
00249     // stream deps into this stream
00250     std::stringstream odeps;
00251 
00252   FinalEvalGraph::EvalUnitIterator uit, ubegin, uend;
00253   boost::tie(ubegin, uend) = eg.getEvalUnits();
00254   for(uit = ubegin; uit != uend; ++uit)
00255   {
00256     EvalUnit u = *uit;
00257     o << "subgraph clusteru" << u << "{" << std::endl;
00258     o << "node [shape=box];" << std::endl;
00259     o << "label=\"";
00260     {
00261       std::stringstream s;
00262             if( eg.propsOf(u).mgf != 0 )
00263             {
00264                 s << *eg.propsOf(u).mgf;
00265             }
00266             else
00267             {
00268                 s << "NULL";
00269             }
00270       // escape " into \"
00271       breakLinesAndGraphViz(s.str(), o);
00272     }
00273         o << "\";" << std::endl;
00274 
00275     // models in this subgraph
00276         {
00277             for(ModelType t = MT_IN; t <= MT_OUTPROJ; t = static_cast<ModelType>(static_cast<unsigned>(t)+1))
00278             {
00279                 const ModelList& modelsAt = mg.modelsAt(u, t);
00280                 typename ModelList::const_iterator mit;
00281                 for(mit = modelsAt.begin(); mit != modelsAt.end(); ++mit)
00282                 {
00283           if( printModels.find(*mit) == printModels.end() )
00284             continue;
00285 
00286                     Model m = *mit;
00287                     o << "m" << m << "[label=\"";
00288                     {
00289                         std::stringstream s;
00290                         s << toString(mg.propsOf(m).type) << " " << m << " @" << mg.propsOf(m).location << "\\n";
00291             if( mg.propsOf(m).interpretation != 0 )
00292               s << *mg.propsOf(m).interpretation;
00293             breakLinesAndGraphViz(s.str(), o);
00294                     }
00295                     o << "\"];" << std::endl;
00296 
00297                     // model dependencies (preds)
00298                     ModelPredecessorIterator pit, pbegin, pend;
00299                     boost::tie(pbegin, pend) = mg.getPredecessors(m);
00300                     for(pit = pbegin; pit != pend; ++pit)
00301                     {
00302                         odeps <<
00303                             "m" << m << " -> m" << mg.targetOf(*pit) <<
00304                             "[label=\"" << mg.propsOf(*pit).joinOrder << "\"];" << std::endl;
00305                     }
00306                 } // through all models
00307             }
00308         }
00309         o << "}" << std::endl;
00310 
00311         /*
00312     // unit dependencies
00313     typename EvalGraphT::PredecessorIterator pit, pbegin, pend;
00314     boost::tie(pbegin, pend) = eg.getPredecessors(u);
00315     for(pit = pbegin; pit != pend; ++pit)
00316     {
00317       LOG(INFO,"-> depends on unit " << eg.targetOf(*pit) << "/join order " << eg.propsOf(*pit).joinOrder);
00318     }
00319         */
00320 
00321   }
00322 
00323     // deps between models
00324     o << odeps.str() << std::endl;
00325     o << "}" << std::endl;
00326 }
00327 
00328 typedef OnlineModelBuilder<FinalEvalGraph> FinalOnlineModelBuilder;
00329 typedef OfflineModelBuilder<FinalEvalGraph> FinalOfflineModelBuilder;
00330 
00331 class AbovePluginAtom:
00332     public dlvhex::PluginAtom
00333 {
00334 public:
00335     AbovePluginAtom():
00336     dlvhex::PluginAtom("above", true)
00337     {
00338     addInputPredicate();
00339     addInputConstant();
00340         outputSize = 1;
00341     }
00342 
00343     virtual void retrieve(const Query& q, Answer& a) throw (dlvhex::PluginError)
00344   {
00345     // get inputs
00346     assert(q.input.size() == 2);
00347     ID pred = q.input[0];
00348     ID cmp = q.input[1];
00349     LOG(INFO,"calculating above extatom for predicate " << pred << " and symbol " << cmp);
00350     const Term& cmpt = registry->terms.getByID(cmp);
00351 
00352     // get query
00353     assert(q.pattern.size() == 1);
00354     ID out = q.pattern.front();
00355 
00356     // build set of found targets
00357     assert(q.interpretation != 0);
00358     dlvhex::OrdinaryAtomTable::PredicateIterator it, it_end;
00359     assert(registry != 0);
00360     for(boost::tie(it, it_end) = registry->ogatoms.getRangeByPredicateID(pred);
00361         it != it_end; ++it)
00362     {
00363       const dlvhex::OrdinaryAtom& oatom = *it;
00364 
00365       // skip ogatoms not present in interpretation
00366       if( !q.interpretation->getFact(registry->ogatoms.getIDByStorage(oatom).address) )
00367         continue;
00368 
00369       // the edge predicate must be unary
00370       assert(oatom.tuple.size() == 2);
00371       const Term& t = registry->terms.getByID(oatom.tuple[1]);
00372       if( t.symbol >= cmpt.symbol )
00373       {
00374         if( (out.isTerm() && out.isVariableTerm()) ||
00375             (out == oatom.tuple[1]) )
00376         {
00377           Tuple t;
00378           t.push_back(oatom.tuple[1]);
00379           a.get().push_back(t);
00380         }
00381       }
00382     }
00383   }
00384 };
00385 
00386 class SenseNotArmed1PluginAtom:
00387     public dlvhex::PluginAtom
00388 {
00389 public:
00390     SenseNotArmed1PluginAtom():
00391     dlvhex::PluginAtom("senseNotArmed1", false)
00392     {
00393     addInputPredicate();
00394     addInputPredicate();
00395     addInputConstant();
00396     addInputConstant();
00397         outputSize = 0;
00398     }
00399 
00400     virtual void retrieve(const Query& q, Answer& a) throw (dlvhex::PluginError)
00401   {
00402     #if 0
00403     // get inputs
00404     assert(q.input.size() == 2);
00405     ID pred = q.input[0];
00406     ID cmp = q.input[1];
00407     LOG(INFO,"calculating above extatom for predicate " << pred << " and symbol " << cmp);
00408     const Term& cmpt = registry->terms.getByID(cmp);
00409 
00410     // get query
00411     assert(q.pattern.size() == 1);
00412     ID out = q.pattern.front();
00413 
00414     // build set of found targets
00415     assert(q.interpretation != 0);
00416     dlvhex::OrdinaryAtomTable::PredicateIterator it, it_end;
00417     assert(registry != 0);
00418     for(boost::tie(it, it_end) = registry->ogatoms.getRangeByPredicateID(pred);
00419         it != it_end; ++it)
00420     {
00421       const dlvhex::OrdinaryAtom& oatom = *it;
00422 
00423       // skip ogatoms not present in interpretation
00424       if( !q.interpretation->getFact(registry->ogatoms.getIDByStorage(oatom).address) )
00425         continue;
00426 
00427       // the edge predicate must be unary
00428       assert(oatom.tuple.size() == 2);
00429       const Term& t = registry->terms.getByID(oatom.tuple[1]);
00430       if( t.symbol >= cmpt.symbol )
00431       {
00432         if( (out.isTerm() && out.isVariableTerm()) ||
00433             (out == oatom.tuple[1]) )
00434         {
00435           Tuple t;
00436           t.push_back(oatom.tuple[1]);
00437           a.get().push_back(t);
00438         }
00439       }
00440     }
00441     #endif
00442     throw std::runtime_error("todo implement SenseNotArmed1PluginAtom::retrieve");
00443   }
00444 };
00445 
00446 class SenseNotArmed2PluginAtom:
00447     public dlvhex::PluginAtom
00448 {
00449 public:
00450     SenseNotArmed2PluginAtom():
00451     dlvhex::PluginAtom("senseNotArmed2", false)
00452     {
00453         outputSize = 0;
00454     addInputPredicate();
00455     addInputPredicate();
00456     addInputConstant();
00457     }
00458 
00459     virtual void retrieve(const Query& q, Answer& a) throw (dlvhex::PluginError)
00460   {
00461     // get inputs
00462     assert(q.input.size() == 3);
00463     ID preddisarm = q.input[0];
00464     ID predlook = q.input[1];
00465     ID time = q.input[2];
00466     LOG(INFO,"calculating senseNotArmed2 extatom for " << preddisarm << "/" << predlook << "/" << time);
00467 
00468     // get outputs
00469     assert(q.pattern.size() == 0);
00470 
00471     // check if <preddisarm>(time) and <predlook>(time) part of interpretation
00472     Tuple tdisarm;
00473     tdisarm.push_back(preddisarm);
00474     tdisarm.push_back(time);
00475     ID iddisarm = registry->ogatoms.getIDByTuple(tdisarm);
00476 
00477     Tuple tlook;
00478     tlook.push_back(predlook);
00479     tlook.push_back(time);
00480     ID idlook = registry->ogatoms.getIDByTuple(tlook);
00481 
00482     if( iddisarm == ID_FAIL || idlook == ID_FAIL )
00483     {
00484       // cannot be part of interpretation -> return no tuple as condition not true
00485       return;
00486     }
00487 
00488     // check interpretation
00489     assert(q.interpretation != 0);
00490     if( q.interpretation->getFact(iddisarm.address) &&
00491         q.interpretation->getFact(idlook.address) )
00492     {
00493       // found both facts
00494       Tuple t;
00495       a.get().push_back(t);
00496     }
00497   }
00498 };
00499 
00500 class GenPluginAtom1:
00501     public dlvhex::PluginAtom
00502 {
00503 public:
00504     GenPluginAtom1(const std::string& name, unsigned arity):
00505     dlvhex::PluginAtom(name, false)
00506     {
00507     addInputPredicate();
00508         outputSize = arity;
00509     }
00510 
00511     virtual void retrieve(const Query& q, Answer& a) throw (dlvhex::PluginError)
00512   {
00513     // get input
00514     assert(q.input.size() == 1);
00515     ID pred = q.input[0];
00516 
00517     // get outputs
00518     assert(q.pattern.size() == outputSize);
00519 
00520     // build unifier
00521     OrdinaryAtom unifier(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYN);
00522     unifier.tuple.push_back(pred);
00523     unifier.tuple.insert(unifier.tuple.begin(), q.pattern.begin(), q.pattern.end());
00524 
00525     // check if <pred>(pattern) part of interpretation (=forward <pred> via external atom)
00526     assert(q.interpretation != 0);
00527     const Interpretation::Storage& bits = q.interpretation->getStorage();
00528     for(Interpretation::Storage::enumerator it = bits.first();
00529         it != bits.end(); ++it)
00530     {
00531       const OrdinaryAtom& ogatom = registry->ogatoms.getByID(ID(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG, *it));
00532       if( ogatom.unifiesWith(unifier) )
00533       {
00534         Tuple partial;
00535         partial.insert(partial.begin(), ogatom.tuple.begin()+1, ogatom.tuple.end());
00536         a.get().push_back(partial);
00537       }
00538     }
00539   }
00540 };
00541 
00542 class GenPluginAtom2:
00543     public dlvhex::PluginAtom
00544 {
00545 public:
00546     GenPluginAtom2(const std::string& name, unsigned arity):
00547     dlvhex::PluginAtom(name, false)
00548     {
00549         outputSize = 0;
00550     addInputPredicate();
00551     for(unsigned u = 0; u < arity; ++u)
00552       addInputPredicate();
00553     }
00554 
00555     virtual void retrieve(const Query& q, Answer& a) throw (dlvhex::PluginError)
00556   {
00557     // get input
00558     assert(checkInputArity(q.input.size()));
00559     assert(checkOutputArity(getExtSourceProperties(), q.pattern.size()));
00560 
00561     ID idoutput = registry->ogatoms.getIDByTuple(q.input);
00562     // no ogatom -> cannot be in interpretation
00563     if( idoutput == ID_FAIL )
00564       return;
00565 
00566     assert(q.interpretation != 0);
00567     if( q.interpretation->getFact(idoutput.address) )
00568     {
00569       // success = found = true!
00570       a.get().push_back(Tuple());
00571     }
00572   }
00573 };
00574 
00575 int main(int argn, char** argv)
00576 {
00577   try
00578   {
00579 
00580   DLVHEX_BENCHMARK_REGISTER_AND_START(sidoverall, "overall timing");
00581   
00582   if( argn != 5 )
00583   {
00584     std::cerr << "usage: " << argv[0] << " <heurimode> <mbmode> <backend> <inputfile>" << std::endl;
00585     return -1;
00586   }
00587 
00588   //
00589   // setup benchmarking
00590   //
00591   benchmark::BenchmarkController& ctr =
00592     benchmark::BenchmarkController::Instance();
00593   ctr.setOutput(&std::cerr);
00594   // for continuous statistics output, display every 1000'th output
00595   ctr.setPrintInterval(999);
00596   // deconstruct benchmarking (= output results) at scope exit 
00597   int dummy; // this is needed, as SCOPE_EXIT is not defined for no arguments
00598   BOOST_SCOPE_EXIT( (dummy) ) {
00599       (void)dummy;
00600       benchmark::BenchmarkController::finish();
00601   }
00602   BOOST_SCOPE_EXIT_END
00603 
00604   //
00605   // preprocess arguments
00606   //
00607   const std::string heurimode(argv[1]);
00608   const std::string mbmode(argv[2]);
00609   const std::string backend(argv[3]);
00610   const std::string fname(argv[4]);
00611 
00612   // get input
00613   InputProviderPtr ip(new InputProvider);
00614   ip->addFileInput(fname);
00615 
00616   // don't rewrite
00617 
00618   // prepare program context
00619   ProgramCtx ctx;
00620   {
00621     RegistryPtr registry(new Registry);
00622     ctx.setupRegistry(registry);
00623     PluginContainerPtr pluginContainer(new PluginContainer);
00624     ctx.setupPluginContainer(pluginContainer);
00625   }
00626 
00627   // create all testing plugin atoms
00628   ctx.addPluginAtom(PluginAtomPtr(new AbovePluginAtom));
00629   ctx.addPluginAtom(PluginAtomPtr(new SenseNotArmed1PluginAtom));
00630   ctx.addPluginAtom(PluginAtomPtr(new SenseNotArmed2PluginAtom));
00631   ctx.addPluginAtom(PluginAtomPtr(new GenPluginAtom2("gen2",2)));
00632 
00633   // parse HEX program
00634   LOG(INFO,"parsing HEX program");
00635   DLVHEX_BENCHMARK_REGISTER_AND_START(sidhexparse, "HexParser::parse");
00636   ModuleHexParser parser;
00637   parser.parse(ip, ctx);
00638   DLVHEX_BENCHMARK_STOP(sidhexparse);
00639 
00640   ctx.associateExtAtomsWithPluginAtoms(ctx.idb,true);
00641 
00642   //LOG_REGISTRY_PROGRAM(ctx);
00643 
00644   // create dependency graph
00645   LOG(INFO,"creating dependency graph");
00646   DLVHEX_BENCHMARK_REGISTER_AND_START(siddepgraph, "create dependencygraph");
00647   std::vector<dlvhex::ID> auxRules;
00648   dlvhex::DependencyGraph depgraph(ctx, ctx.registry());
00649   depgraph.createDependencies(ctx.idb, auxRules);
00650   DLVHEX_BENCHMARK_STOP(siddepgraph);
00651   #ifndef NDEBUG
00652   writeGraphViz(depgraph, fname+"PlainHEXDepGraph");
00653   #endif
00654 
00655   // create component graph
00656   LOG(INFO,"creating component graph");
00657   DLVHEX_BENCHMARK_REGISTER_AND_START(sidcompgraph, "create componentgraph");
00658   dlvhex::ComponentGraph compgraph(depgraph, ctx, ctx.registry());
00659   DLVHEX_BENCHMARK_STOP(sidcompgraph);
00660   #ifndef NDEBUG
00661   writeGraphViz(compgraph, fname+"PlainHEXCompGraph");
00662   #endif
00663 
00664   // manage external evaluation configuration / backend
00665   ASPSolverManager::SoftwareConfigurationPtr externalEvalConfig;
00666   if( backend == "dlv" )
00667   {
00668     externalEvalConfig.reset(new ASPSolver::DLVSoftware::Configuration);
00669   }
00670   else if( backend == "libdlv" )
00671   {
00672     #ifdef HAVE_LIBDLV
00673     externalEvalConfig.reset(new ASPSolver::DLVLibSoftware::Configuration);
00674     #else
00675     std::cerr << "sorry, libdlv not compiled in" << std::endl;
00676     return -1;
00677     #endif // HAVE_LIBDLV
00678   }
00679   else if( backend == "libclingo" )
00680   {
00681     #ifdef HAVE_LIBCLINGO
00682     externalEvalConfig.reset(new ASPSolver::ClingoSoftware::Configuration);
00683     #else
00684     std::cerr << "sorry, libclingo not compiled in" << std::endl;
00685     return -1;
00686     #endif // HAVE_LIBCLINGO
00687   }
00688   else
00689   {
00690     std::cerr << "usage: <backend> must be one of 'dlv','libdlv','libclingo'" << std::endl;
00691     return -1;
00692   }
00693 
00694   // create eval graph
00695   LOG(INFO,"creating eval graph");
00696   DLVHEX_BENCHMARK_REGISTER_AND_START(sidevalgraph, "create evalgraph");
00697   FinalEvalGraph evalgraph;
00698   EvalGraphBuilder egbuilder(ctx, compgraph, evalgraph, externalEvalConfig);
00699 
00700   // use one of several heuristics
00701   if( heurimode == "old" )
00702   {
00703     // old DLVHEX heuristic
00704     LOG(INFO,"building eval graph with old heuristics");
00705     EvalHeuristicOldDlvhex heuristicOldDlvhex;
00706     heuristicOldDlvhex.build(egbuilder);
00707   }
00708   else if( heurimode == "trivial" )
00709   {
00710     // trivial heuristic: just take component graph
00711     // (maximum number of eval units, probably large overhead)
00712     LOG(INFO,"building eval graph with trivial heuristics");
00713     EvalHeuristicTrivial heuristic;
00714     heuristic.build(egbuilder);
00715   }
00716   else if( heurimode == "easy" )
00717   {
00718     // easy heuristic: just make some easy adjustments to improve on the trivial heuristics
00719     LOG(INFO,"building eval graph with easy heuristics");
00720     EvalHeuristicEasy heuristic;
00721     heuristic.build(egbuilder);
00722   }
00723   else
00724   {
00725     std::cerr << "usage: <heurimode> must be one of 'old','trivial','easy'" << std::endl;
00726     return -1;
00727   }
00728   DLVHEX_BENCHMARK_STOP(sidevalgraph);
00729 
00730   #ifndef NDEBUG
00731   writeGraphViz(compgraph, fname+"PlainHEXEvalGraph");
00732   #endif
00733 
00734   // setup final unit
00735   LOG(INFO,"setting up final unit");
00736   DLVHEX_BENCHMARK_REGISTER_AND_START(sidfinalunit, "creating final unit");
00737   EvalUnit ufinal;
00738   {
00739     ufinal = evalgraph.addUnit(FinalEvalGraph::EvalUnitPropertyBundle());
00740     LOG(INFO,"ufinal = " << ufinal);
00741 
00742     FinalEvalGraph::EvalUnitIterator it, itend;
00743     boost::tie(it, itend) = evalgraph.getEvalUnits();
00744     for(; it != itend && *it != ufinal; ++it)
00745     {
00746       DBGLOG(DBG,"adding dependency from ufinal to unit " << *it << " join order " << *it);
00747       // we can do this because we know that eval units (= vertices of a vecS adjacency list) are unsigned integers
00748       evalgraph.addDependency(ufinal, *it, FinalEvalGraph::EvalUnitDepPropertyBundle(*it));
00749     }
00750   }
00751   DLVHEX_BENCHMARK_STOP(sidfinalunit);
00752 
00753   // prepare for output
00754   //GenericOutputBuilder ob;
00755   #warning reactivate and redesign outputbuilder
00756 
00757   //std::cerr << __FILE__ << ":" << __LINE__ << std::endl << *ctx.registry() << std::endl;
00758 
00759   // evaluate
00760   LOG(INFO,"evaluating");
00761   DLVHEX_BENCHMARK_REGISTER(sidoutputmodel, "output model");
00762   dlvhex::ModelBuilderConfig<FinalEvalGraph> mbcfg(evalgraph);
00763   if( mbmode == "online" )
00764   {
00765     typedef FinalOnlineModelBuilder::Model Model;
00766     typedef FinalOnlineModelBuilder::OptionalModel OptionalModel;
00767     typedef FinalOfflineModelBuilder::MyModelGraph MyModelGraph;
00768     LOG(INFO,"creating model builder");
00769     DLVHEX_BENCHMARK_REGISTER_AND_START(sidonlinemb, "create online mb");
00770 
00771     FinalOnlineModelBuilder mb(mbcfg);
00772     DLVHEX_BENCHMARK_STOP(sidonlinemb);
00773 
00774     // get and print all models
00775     OptionalModel m;
00776     DLVHEX_BENCHMARK_REGISTER(sidgetnextonlinemodel, "get next online model");
00777     unsigned mcount = 0;
00778     do
00779     {
00780       DBGLOG(DBG,"requesting model");
00781       DLVHEX_BENCHMARK_START(sidgetnextonlinemodel);
00782       m = mb.getNextIModel(ufinal);
00783       DLVHEX_BENCHMARK_STOP(sidgetnextonlinemodel);
00784       if( !!m )
00785       {
00786         InterpretationConstPtr interpretation =
00787           mb.getModelGraph().propsOf(m.get()).interpretation;
00788         #ifndef NDEBUG
00789         DBGLOG(DBG,"got model#" << mcount << ":" << *interpretation);
00790         std::set<Model> onlyFor;
00791         onlyFor.insert(m.get());
00792         GraphVizFunc func = boost::bind(&writeEgMgGraphViz<MyModelGraph>, _1,
00793             true, boost::cref(mb.getEvalGraph()), boost::cref(mb.getModelGraph()), onlyFor);
00794         std::stringstream smodel;
00795         smodel << fname << "PlainHEXOnlineModel" << mcount;
00796         writeGraphVizFunctors(func, func, smodel.str());
00797         #endif
00798         mcount++;
00799 
00800         // output model
00801         {
00802           std::cout << *interpretation << std::endl;
00803         }
00804         //std::cerr << __FILE__ << ":" << __LINE__ << std::endl << *ctx.registry() << std::endl;
00805 
00806         #ifndef NDEBUG
00807         mb.printEvalGraphModelGraph(std::cerr);
00808         #endif
00809       }
00810     }
00811     while( !!m );
00812     #ifndef NDEBUG
00813     mb.printEvalGraphModelGraph(std::cerr);
00814     #endif
00815     #ifndef NDEBUG
00816         GraphVizFunc func = boost::bind(&writeEgMgGraphViz<MyModelGraph>, _1,
00817                 true, boost::cref(mb.getEvalGraph()), boost::cref(mb.getModelGraph()), boost::none);
00818         writeGraphVizFunctors(func, func, fname+"PlainHEXOnlineEgMg");
00819     #endif
00820     //std::cerr << __FILE__ << ":" << __LINE__ << std::endl << *ctx.registry() << std::endl;
00821 
00822     DLVHEX_BENCHMARK_STOP(sidoverall);
00823     std::cerr << "TIMING " << fname << " " << heurimode << " " << mbmode << " " << backend << " " <<
00824       evalgraph.countEvalUnits() << " evalunits " << evalgraph.countEvalUnitDeps() << " evalunitdeps " << mcount << " models ";
00825     benchmark::BenchmarkController::Instance().printDuration(std::cerr, sidoverall) << std::endl;
00826   }
00827   else if( mbmode == "offline" )
00828   {
00829     typedef FinalOfflineModelBuilder::Model Model;
00830     typedef FinalOfflineModelBuilder::OptionalModel OptionalModel;
00831     typedef FinalOfflineModelBuilder::MyModelGraph MyModelGraph;
00832 
00833     LOG(INFO,"creating model builder");
00834     DLVHEX_BENCHMARK_REGISTER_AND_START(sidofflinemb, "create offline mb");
00835     FinalOfflineModelBuilder mb(mbcfg);
00836     DLVHEX_BENCHMARK_STOP(sidofflinemb);
00837 
00838     LOG(INFO,"creating all final imodels");
00839     DLVHEX_BENCHMARK_REGISTER_AND_START(sidofflinemodels, "create offline models");
00840     mb.buildIModelsRecursively(ufinal);
00841     DLVHEX_BENCHMARK_STOP(sidofflinemodels);
00842     #ifndef NDEBUG
00843     mb.printEvalGraphModelGraph(std::cerr);
00844     #endif
00845 
00846     LOG(INFO,"printing models");
00847     DLVHEX_BENCHMARK_REGISTER_AND_START(sidprintoffmodels, "print offline models");
00848     MyModelGraph& mg = mb.getModelGraph();
00849     const MyModelGraph::ModelList& models = mg.modelsAt(ufinal, MT_IN);
00850     unsigned mcount = 0;
00851 
00852     BOOST_FOREACH(Model m, models)
00853     {
00854       InterpretationConstPtr interpretation =
00855         mg.propsOf(m).interpretation;
00856       #ifndef NDEBUG
00857       DBGLOG(DBG,"got model#" << mcount << ":" << *interpretation);
00858       std::set<Model> onlyFor;
00859       onlyFor.insert(m);
00860       GraphVizFunc func = boost::bind(&writeEgMgGraphViz<MyModelGraph>, _1,
00861           true, boost::cref(mb.getEvalGraph()), boost::cref(mb.getModelGraph()), onlyFor);
00862       std::stringstream smodel;
00863       smodel << fname << "PlainHEXOfflineModel" << mcount;
00864       writeGraphVizFunctors(func, func, smodel.str());
00865       #endif
00866       mcount++;
00867 
00868       // output model
00869       {
00870         std::cout << *interpretation << std::endl;
00871       }
00872     }
00873     DLVHEX_BENCHMARK_STOP(sidprintoffmodels);
00874     #ifndef NDEBUG
00875         GraphVizFunc func = boost::bind(&writeEgMgGraphViz<MyModelGraph>, _1,
00876                 true, boost::cref(mb.getEvalGraph()), boost::cref(mb.getModelGraph()), boost::none);
00877         writeGraphVizFunctors(func, func, fname+"PlainHEXOfflineEgMg");
00878     #endif
00879 
00880     DLVHEX_BENCHMARK_STOP(sidoverall);
00881     std::cerr << "TIMING " << fname << " " << heurimode << " " << mbmode << " " << backend << " " <<
00882       evalgraph.countEvalUnits() << " evalunits " << evalgraph.countEvalUnitDeps() << " evalunitdeps " << mcount << " models ";
00883     benchmark::BenchmarkController::Instance().printDuration(std::cerr, sidoverall) << "s" << std::endl;
00884   }
00885   else
00886   {
00887     std::cerr << "usage: <mbmode> must be one of 'online','offline'" << std::endl;
00888     return -1;
00889   }
00890   return 0;
00891   
00892   }
00893   catch(const std::exception& e)
00894   {
00895     std::cerr << "exception: " << e.what() << std::endl;
00896     return -1;
00897   }
00898 }
00899