dlvhex  2.1.0
src/State.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 
00024 
00037 #include "dlvhex2/State.h"
00038 
00039 // activate benchmarking if activated by configure option --enable-debug
00040 #ifdef HAVE_CONFIG_H
00041 #  include "config.h"
00042 #endif
00043 
00044 #include "dlvhex2/ProgramCtx.h"
00045 #include "dlvhex2/Error.h"
00046 #include "dlvhex2/Printhelpers.h"
00047 #include "dlvhex2/Benchmarking.h"
00048 #include "dlvhex2/ASPSolverManager.h"
00049 #include "dlvhex2/ASPSolver.h"
00050 #include "dlvhex2/HexParser.h"
00051 #include "dlvhex2/Printer.h"
00052 #include "dlvhex2/Registry.h"
00053 #include "dlvhex2/PluginContainer.h"
00054 #include "dlvhex2/DependencyGraph.h"
00055 #include "dlvhex2/ComponentGraph.h"
00056 #include "dlvhex2/FinalEvalGraph.h"
00057 #include "dlvhex2/EvalGraphBuilder.h"
00058 #include "dlvhex2/DumpingEvalGraphBuilder.h"
00059 #include "dlvhex2/AnswerSetPrinterCallback.h"
00060 #include "dlvhex2/PlainAuxPrinter.h"
00061 #include "dlvhex2/SafetyChecker.h"
00062 #include "dlvhex2/MLPSyntaxChecker.h"
00063 #include "dlvhex2/MLPSolver.h"
00064 
00065 #include <boost/foreach.hpp>
00066 
00067 #include <iostream>
00068 #include <sstream>
00069 #include <fstream>
00070 #include <vector>
00071 
00072 DLVHEX_NAMESPACE_BEGIN
00073 
00074 State::State(StatePtr failureState):
00075   failureState(failureState)
00076 {
00077 }
00078 
00079 State::~State()
00080 {
00081 }
00082 
00083 namespace
00084 {
00085   std::ostream& printStatePtr(std::ostream& o, StatePtr ptr)
00086   {
00087     if( !ptr )
00088       return o << "NULL";
00089     else
00090       return o << "'" << typeid(*ptr).name() << "'";
00091   }
00092 }
00093 
00094 void State::changeState(ProgramCtx* ctx, StatePtr s)
00095 {
00096   LOG(INFO,
00097     "State::changeState from " <<
00098     print_function(boost::bind(&printStatePtr, _1, ctx->state)) <<
00099     " to " <<
00100     print_function(boost::bind(&printStatePtr, _1, s)));
00101   ctx->changeState(s);
00102 }
00103 
00104 // each of these functions skips to the "failureState" and executes the executed function on it
00105 // this is useful for having optional states
00106 // if no failureState is given, an exception is raised
00107 // this is useful for non-optional states
00108 #define STATE_FUNC_DEFAULT_IMPL(function) \
00109   void State:: function (ProgramCtx* ctx) \
00110   { \
00111     if( !!failureState ) \
00112     { \
00113       changeState(ctx, failureState); /* <-- this destructs *this */ \
00114       ctx->state-> function (ctx); \
00115     } \
00116     else \
00117     { \
00118       throw std::runtime_error("tried to skip execution of '" \
00119           #function "' in State!"); \
00120     } \
00121   }
00122 
00123 // all state methods get skipping possibility
00124 // derived classes will decide whether to set the failureState or not
00125 // if it is set, the state is skippable,
00126 // if not, execution of this state is mandatory
00127 STATE_FUNC_DEFAULT_IMPL(showPlugins);
00128 STATE_FUNC_DEFAULT_IMPL(convert);
00129 STATE_FUNC_DEFAULT_IMPL(parse);
00130 STATE_FUNC_DEFAULT_IMPL(moduleSyntaxCheck);
00131 STATE_FUNC_DEFAULT_IMPL(mlpSolver);
00132 STATE_FUNC_DEFAULT_IMPL(rewriteEDBIDB);
00133 STATE_FUNC_DEFAULT_IMPL(safetyCheck);
00134 STATE_FUNC_DEFAULT_IMPL(createDependencyGraph);
00135 STATE_FUNC_DEFAULT_IMPL(optimizeEDBDependencyGraph);
00136 STATE_FUNC_DEFAULT_IMPL(createComponentGraph);
00137 STATE_FUNC_DEFAULT_IMPL(strongSafetyCheck);
00138 STATE_FUNC_DEFAULT_IMPL(createEvalGraph);
00139 STATE_FUNC_DEFAULT_IMPL(setupProgramCtx);
00140 STATE_FUNC_DEFAULT_IMPL(evaluate);
00141 STATE_FUNC_DEFAULT_IMPL(postProcess);
00142 
00143 #define MANDATORY_STATE_CONSTRUCTOR(state) \
00144   state :: state (): State() {}
00145 
00146 #define OPTIONAL_STATE_CONSTRUCTOR(state,skiptostate) \
00147   state :: state (): State(StatePtr(new skiptostate)) {}
00148 
00149 OPTIONAL_STATE_CONSTRUCTOR(ShowPluginsState,ConvertState);
00150 
00151 void ShowPluginsState::showPlugins(ProgramCtx* ctx)
00152 {
00153   if( !ctx->config.getOption("Silent") )
00154   {
00155     BOOST_FOREACH(PluginInterfacePtr plugin, ctx->pluginContainer()->getPlugins())
00156     {
00157       LOG(INFO,"opening plugin " << plugin->getPluginName() <<
00158                " version " <<
00159                plugin->getVersionMajor() << "." <<
00160                plugin->getVersionMinor() << "." <<
00161                plugin->getVersionMicro());
00162     }
00163   }
00164 
00165   boost::shared_ptr<State> next(new ConvertState);
00166   changeState(ctx, next);
00167 }
00168 
00169 OPTIONAL_STATE_CONSTRUCTOR(ConvertState,ParseState);
00170 
00171 void ConvertState::convert(ProgramCtx* ctx)
00172 {
00173   assert(!!ctx->inputProvider && ctx->inputProvider->hasContent() && "need input provider with content for converting");
00174 
00175   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"Calling plugin converters");
00176 
00177   // get combination of input filenames for creating debug output files and for naming converted input
00178   std::string inputName;
00179   BOOST_FOREACH(const std::string& name, ctx->inputProvider->contentNames())
00180   {
00181     // only use part after last / here
00182     inputName += "_" + name.substr(name.find_last_of("/") + 1);
00183   }
00184   LOG(INFO,"inputName='" << inputName << "'");
00185 
00186   // store it
00187   ctx->config.setStringOption("DebugPrefix","dbg" + inputName);
00188   LOG(DBG,"debugFilePrefix='" << ctx->config.getStringOption("DebugPrefix") << "'");
00189 
00190   std::vector<PluginConverterPtr> converters;
00191   BOOST_FOREACH(PluginInterfacePtr plugin, ctx->pluginContainer()->getPlugins())
00192   {
00193     BOOST_FOREACH(PluginConverterPtr pc, plugin->createConverters(*ctx))
00194     {
00195       LOG(PLUGIN,"got plugin converter from plugin " << plugin->getPluginName());
00196       converters.push_back(pc);
00197     }
00198   }
00199 
00200   if( converters.size() > 1 )
00201     LOG(WARNING,"got more than one plugin converter, using arbitrary order!");
00202 
00203   BOOST_FOREACH(PluginConverterPtr converter, converters)
00204   {
00205     DBGLOG(DBG,"calling input converter");
00206     std::stringstream out;
00207     converter->convert(ctx->inputProvider->getAsStream(), out);
00208 
00209     // debug output (if requested)
00210     if( ctx->config.doVerbose(Configuration::DUMP_CONVERTED_PROGRAM) )
00211     {
00212       LOG(DBG,"input conversion result:" << std::endl << out.str() << std::endl);
00213     }
00214 
00215     // replace input provider with converted input provider
00216     ctx->inputProvider.reset(new InputProvider);
00217     ctx->inputProvider->addStringInput(out.str(), "converted" + inputName);
00218     }
00219 
00220 #warning TODO realize dlt as a plugin
00221 //    //
00222 //    // now call dlt if needed
00223 //    //
00224 //    if (optiondlt)
00225 //      {
00226 //        char tempfile[L_tmpnam];
00227 //        mkstemp(tempfile);
00228 
00229 //        std::ofstream dlttemp(tempfile);
00230 
00231 //        //
00232 //        // write program into tempfile
00233 //        //
00234 //        dlttemp << input.rdbuf();
00235 
00236 //        dlttemp.close();
00237 
00238 //        std::string execPreParser("dlt -silent -preparsing " + std::string(tempfile));
00239 
00240 //        fp = popen(execPreParser.c_str(), "r");
00241 
00242 //        if (fp == NULL)
00243 //      {
00244 //        throw GeneralError("Unable to call Preparser dlt");
00245 //      }
00246 
00247 //        __gnu_cxx::stdio_filebuf<char>* fb;
00248 //        fb = new __gnu_cxx::stdio_filebuf<char>(fp, std::ios::in);
00249 
00250 //        std::istream inpipe(fb);
00251 
00252 //        //
00253 //        // now we have a program rewriten by dlt - since it should
00254 //        // be in the stream "input", we have to delete the old
00255 //        // input-buffer and set input to the buffer from the
00256 //        // dlt-call
00257 //        //
00258 //        delete input.rdbuf();
00259 //        input.rdbuf(fb);
00260 //      }
00261 
00262   boost::shared_ptr<State> next(new ParseState);
00263   changeState(ctx, next);
00264 }
00265 
00266 MANDATORY_STATE_CONSTRUCTOR(ParseState);
00267 
00268 void ParseState::parse(ProgramCtx* ctx)
00269 {
00270   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"Parsing input");
00271 
00272   // use alternative parser from plugins, if applicable
00273   assert(!ctx->parser);
00274   BOOST_FOREACH(PluginInterfacePtr plugin, ctx->pluginContainer()->getPlugins())
00275   {
00276     HexParserPtr alternativeParser = plugin->createParser(*ctx);
00277     if( !!alternativeParser )
00278     {
00279       if( !!ctx->parser )
00280       {
00281         LOG(WARNING,"ignoring alternative parser provided by plugin " <<
00282             plugin->getPluginName() << " because parser already initialized");
00283       }
00284       else
00285       {
00286         LOG(INFO,"using alternative parser provided by plugin " <<
00287             plugin->getPluginName());
00288         ctx->parser = alternativeParser;
00289       }
00290     }
00291   }
00292 
00293   // use default parser if no alternative parsers given
00294   if( !ctx->parser )
00295   {
00296     LOG(INFO,"using default parser (no alternatives provided by plugins)");
00297     ctx->parser.reset(new ModuleHexParser);
00298   }
00299   
00300   // configure parser modules if possible
00301   {
00302     ModuleHexParserPtr mhp =
00303       boost::dynamic_pointer_cast<ModuleHexParser>(ctx->parser);
00304     BOOST_FOREACH(PluginInterfacePtr plugin, ctx->pluginContainer()->getPlugins())
00305     {
00306       std::vector<HexParserModulePtr> modules =
00307         plugin->createParserModules(*ctx);
00308       if( !modules.empty() )
00309       {
00310         if( !!mhp )
00311         {
00312           LOG(INFO,"got " << modules.size() <<
00313               " parser modules from plugin " << plugin->getPluginName());
00314           BOOST_FOREACH(HexParserModulePtr module, modules)
00315           {
00316             mhp->registerModule(module);
00317           }
00318           LOG(INFO,"registered successfully");
00319         }
00320         else
00321         {
00322           LOG(WARNING,"ignoring parser module from plugin '" <<
00323               plugin->getPluginName() << "' as ModuleHexParser is not used");
00324         }
00325       }
00326     }
00327   }
00328 
00329   // parse
00330   assert(!!ctx->parser);
00331   ctx->parser->parse(ctx->inputProvider, *ctx);
00332 
00333   // free input provider memory
00334   assert(ctx->inputProvider.use_count() == 1);
00335   ctx->inputProvider.reset();
00336 
00337     #warning namespaces were here!
00338 #if 0
00339 
00343 struct NotNCNameChar : public std::unary_function<char, bool>
00344 {
00345   bool
00346   operator() (char c)
00347   {
00348     c = std::toupper(c);
00349     return
00350       (c < 'A' || c > 'Z') &&
00351       (c < '0' || c > '9') &&
00352       c != '-' &&
00353       c != '_' &&
00354       c != '.';
00355   }
00356 };
00357 #endif
00358 
00359 // TODO implement namespaces
00360 #if 0
00361 void
00362 insertNamespaces()
00363 {
00365 
00366   if (Term::getNameSpaces().empty())
00367     return;
00368 
00369   std::string prefix;
00370 
00371   for (NamesTable<std::string>::const_iterator nm = Term::getNames().begin();
00372        nm != Term::getNames().end();
00373        ++nm)
00374     {
00375       for (std::vector<std::pair<std::string, std::string> >::iterator ns = Term::getNameSpaces().begin();
00376        ns != Term::getNameSpaces().end();
00377        ++ns)
00378     {
00379       prefix = ns->second + ':';
00380 
00381       //
00382       // prefix must occur either at beginning or right after quote
00383       //
00384       unsigned start = 0;
00385       unsigned end = (*nm).length();
00386 
00387       if ((*nm)[0] == '"')
00388         {
00389           ++start;
00390           --end;
00391         }
00392 
00393         
00394       //
00395       // accourding to http://www.w3.org/TR/REC-xml-names/ QNames
00396       // consist of a prefix followed by ':' and a LocalPart, or
00397       // just a LocalPart. In case of a single LocalPart, we would
00398       // not find prefix and leave that Term alone. If we find a
00399       // prefix in the Term, we must disallow non-NCNames in
00400       // LocalPart, otw. we get in serious troubles when replacing
00401       // proper Terms:
00402       // NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender  
00403       //
00404 
00405       std::string::size_type colon = (*nm).find(":", start);
00406                       
00407       if (colon != std::string::npos) // Prefix:LocalPart
00408         {
00409           std::string::const_iterator it =
00410         std::find_if((*nm).begin() + colon + 1, (*nm).begin() + end - 1, NotNCNameChar());
00411 
00412           // prefix starts with ns->second, LocalPart does not
00413           // contain non-NCNameChars, hence we can replace that
00414           // Term
00415           if ((*nm).find(prefix, start) == start &&
00416           (it == (*nm).begin() + end - 1)
00417           )
00418         {
00419           std::string r(*nm);
00420           
00421           r.replace(start, prefix.length(), ns->first); // replace ns->first from start to prefix + 1
00422           r.replace(0, 1, "\"<");
00423           r.replace(r.length() - 1, 1, ">\"");
00424           
00425           Term::getNames().modify(nm, r);
00426         }
00427         }
00428     }
00429     }
00430 }
00431 
00432 void
00433 removeNamespaces()
00434 {
00436 
00437   if (Term::getNameSpaces().empty())
00438     return;
00439 
00440   std::string prefix;
00441   std::string fullns;
00442 
00443   for (NamesTable<std::string>::const_iterator nm = Term::getNames().begin();
00444        nm != Term::getNames().end();
00445        ++nm)
00446     {
00447       for (std::vector<std::pair<std::string, std::string> >::iterator ns = Term::getNameSpaces().begin();
00448        ns != Term::getNameSpaces().end();
00449        ++ns)
00450     {
00451       fullns = ns->first;
00452 
00453       prefix = ns->second + ":";
00454 
00455       //
00456       // original ns must occur either at beginning or right after quote
00457       //
00458       unsigned start = 0;
00459       if ((*nm)[0] == '"')
00460         start = 1;
00461 
00462       if ((*nm).find(fullns, start) == start)
00463         {
00464           std::string r(*nm);
00465 
00466           r.replace(start, fullns.length(), prefix);
00467 
00468           Term::getNames().modify(nm, r);
00469         }
00470     }
00471     }
00472 }
00473 #endif
00474 
00475     // be verbose if requested
00476     if( ctx->config.doVerbose(Configuration::DUMP_PARSED_PROGRAM) )
00477     {
00478     LOG(INFO,"parsed IDB:");
00479     RawPrinter rp(Logger::Instance().stream(), ctx->registry());
00480       rp.printmany(ctx->idb, "\n");
00481     Logger::Instance().stream() << std::endl;
00482 
00483     LOG(INFO,"parsed EDB:");
00484     Logger::Instance().stream() << *(ctx->edb) << std::endl;
00485     }
00486   if( ctx->config.getOption("MLP") ) 
00487     {
00488       StatePtr next(new ModuleSyntaxCheckState);
00489       changeState(ctx, next);
00490     }
00491   else 
00492     {
00493       StatePtr next(new RewriteEDBIDBState);
00494       changeState(ctx, next);
00495     }
00496 }
00497 
00498 MANDATORY_STATE_CONSTRUCTOR(ModuleSyntaxCheckState);
00499 // MLPSyntaxChecker ..
00500 void ModuleSyntaxCheckState::moduleSyntaxCheck(ProgramCtx* ctx)
00501 {
00502   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"Module Syntax Check");
00503   MLPSyntaxChecker sC(*ctx);
00504   bool success = sC.verifySyntax();
00505   if (success)
00506     {
00507       StatePtr next(new MLPSolverState);
00508       changeState(ctx, next);
00509     }
00510   else
00511     {
00512       std::cout << "Does not solve the MLP because of syntax error" << std::endl;
00513       StatePtr next(new PostProcessState);
00514       changeState(ctx, next);
00515     }
00516 }
00517 
00518 MANDATORY_STATE_CONSTRUCTOR(MLPSolverState);
00519 void MLPSolverState::mlpSolver(ProgramCtx* ctx)
00520 {
00521   MLPSolver m(*ctx);
00522   m.setNASReturned(ctx->config.getOption("NumberOfModels"));
00523   m.setPrintLevel(ctx->config.getOption("Verbose"));
00524   m.setForget(ctx->config.getOption("Forget"));
00525   m.setInstSplitting(ctx->config.getOption("Split"));
00526   m.solve();
00527   StatePtr next(new PostProcessState);
00528   changeState(ctx, next);
00529 }
00530 
00531 
00532 
00533 OPTIONAL_STATE_CONSTRUCTOR(RewriteEDBIDBState,SafetyCheckState);
00534 
00535 void
00536 RewriteEDBIDBState::rewriteEDBIDB(ProgramCtx* ctx)
00537 {
00538   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"Calling plugin rewriters");
00539   DBGLOG_SCOPE(DBG,"rewrite",false);
00540 
00541   // get rewriter from each plugin
00542   BOOST_FOREACH(PluginInterfacePtr plugin, ctx->pluginContainer()->getPlugins())
00543   {
00544     PluginRewriterPtr rewriter = plugin->createRewriter(*ctx);
00545     if( !rewriter )
00546       continue;
00547 
00548     LOG(PLUGIN,"got plugin rewriter from plugin " << plugin->getPluginName());
00549 
00550       rewriter->rewrite(*ctx);
00551 
00552     // be verbose if requested
00553     if( ctx->config.doVerbose(Configuration::DUMP_REWRITTEN_PROGRAM) )
00554     {
00555       LOG(INFO,"rewritten IDB:");
00556       RawPrinter rp(Logger::Instance().stream(), ctx->registry());
00557       rp.printmany(ctx->idb, "\n");
00558       Logger::Instance().stream() << std::endl;
00559 
00560       LOG(INFO,"rewritten EDB:");
00561       Logger::Instance().stream() << *(ctx->edb) << std::endl;
00562     }
00563   }
00564       
00565   StatePtr next(new SafetyCheckState);
00566   changeState(ctx, next);
00567 }
00568 
00569 OPTIONAL_STATE_CONSTRUCTOR(SafetyCheckState,CreateDependencyGraphState);
00570 
00571 void
00572 SafetyCheckState::safetyCheck(ProgramCtx* ctx)
00573 {
00574   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"Safety checking");
00575 
00576   //
00577   // Performing the safety check
00578   //
00579   SafetyChecker schecker(*ctx);
00580   // check by calling the object
00581   schecker();
00582 
00583   StatePtr next(new CreateDependencyGraphState);
00584   changeState(ctx, next);
00585 }
00586 
00587 MANDATORY_STATE_CONSTRUCTOR(CreateDependencyGraphState);
00588 
00589 void CreateDependencyGraphState::createDependencyGraph(ProgramCtx* ctx)
00590 {
00591   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"building dependency graph");
00592 
00593   DependencyGraphPtr depgraph(new DependencyGraph(ctx->registry()));
00594   std::vector<dlvhex::ID> auxRules;
00595   depgraph->createDependencies(ctx->idb, auxRules);
00596 
00597   if( ctx->config.getOption("DumpDepGraph") )
00598   {
00599     std::string fnamev = ctx->config.getStringOption("DebugPrefix")+"_DepGraphVerbose.dot";
00600     LOG(INFO,"dumping verbose dependency graph to " << fnamev);
00601     std::ofstream filev(fnamev.c_str());
00602     depgraph->writeGraphViz(filev, true);
00603 
00604     std::string fnamet = ctx->config.getStringOption("DebugPrefix")+"_DepGraphTerse.dot";
00605     LOG(INFO,"dumping terse dependency graph to " << fnamet);
00606     std::ofstream filet(fnamet.c_str());
00607     depgraph->writeGraphViz(filet, false);
00608   }
00609 
00610   ctx->depgraph = depgraph;
00611 
00612   StatePtr next(new OptimizeEDBDependencyGraphState);
00613   changeState(ctx, next);
00614 }
00615 
00616 OPTIONAL_STATE_CONSTRUCTOR(OptimizeEDBDependencyGraphState,CreateComponentGraphState);
00617 
00618 void
00619 OptimizeEDBDependencyGraphState::optimizeEDBDependencyGraph(ProgramCtx* ctx)
00620 {
00621   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"Calling plugin optimizers");
00622 
00623   // get optimizer from each plugin
00624   bool optimized = false;
00625   BOOST_FOREACH(PluginInterfacePtr plugin, ctx->pluginContainer()->getPlugins())
00626   {
00627     PluginOptimizerPtr optimizer = plugin->createOptimizer(*ctx);
00628     if( !optimizer )
00629       continue;
00630 
00631     LOG(PLUGIN,"got plugin optimizer from plugin " << plugin->getPluginName());
00632 
00633       optimizer->optimize(ctx->edb, ctx->depgraph);
00634     optimized = true;
00635   }
00636 
00637   if( optimized && ctx->config.getOption("DumpDepGraph") )
00638   {
00639     std::string fnamev = ctx->config.getStringOption("DebugPrefix")+
00640       "_DepGraphOptimizedVerbose.dot";
00641     LOG(INFO,"dumping optimized verbose dependency graph to " << fnamev);
00642     std::ofstream filev(fnamev.c_str());
00643     ctx->depgraph->writeGraphViz(filev, true);
00644 
00645     std::string fnamet = ctx->config.getStringOption("DebugPrefix")+
00646       "_DepGraphOptimizedTerse.dot";
00647     LOG(INFO,"dumping optimized terse dependency graph to " << fnamet);
00648     std::ofstream filet(fnamet.c_str());
00649     ctx->depgraph->writeGraphViz(filet, false);
00650   }
00651 
00652   StatePtr next(new CreateComponentGraphState);
00653   changeState(ctx, next);
00654 }
00655 
00656 MANDATORY_STATE_CONSTRUCTOR(CreateComponentGraphState);
00657 
00658 void CreateComponentGraphState::createComponentGraph(ProgramCtx* ctx)
00659 {
00660   assert(!!ctx->depgraph && "need depgraph for building component graph");
00661   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"building component graph");
00662 
00663   ComponentGraphPtr compgraph(
00664       new ComponentGraph(*ctx->depgraph, ctx->registry()));
00665 
00666   if( ctx->config.getOption("DumpCompGraph") )
00667   {
00668     std::string fnamev = ctx->config.getStringOption("DebugPrefix")+"_CompGraphVerbose.dot";
00669     LOG(INFO,"dumping verbose component graph to " << fnamev);
00670     std::ofstream filev(fnamev.c_str());
00671     compgraph->writeGraphViz(filev, true);
00672 
00673     std::string fnamet = ctx->config.getStringOption("DebugPrefix")+"_CompGraphTerse.dot";
00674     LOG(INFO,"dumping terse component graph to " << fnamet);
00675     std::ofstream filet(fnamet.c_str());
00676     compgraph->writeGraphViz(filet, false);
00677   }
00678 
00679   ctx->compgraph = compgraph;
00680 
00681   StatePtr next(new StrongSafetyCheckState);
00682   changeState(ctx, next);
00683 }
00684 
00685 OPTIONAL_STATE_CONSTRUCTOR(StrongSafetyCheckState,CreateEvalGraphState);
00686 
00687 void StrongSafetyCheckState::strongSafetyCheck(ProgramCtx* ctx)
00688 {
00689   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"Strong safety checking");
00690 
00691   StrongSafetyChecker sschecker(*ctx);
00692   // check by calling the object
00693   sschecker();
00694 
00695   StatePtr next(new CreateEvalGraphState);
00696   changeState(ctx, next);
00697 }
00698 
00699 MANDATORY_STATE_CONSTRUCTOR(CreateEvalGraphState);
00700 
00701 void CreateEvalGraphState::createEvalGraph(ProgramCtx* ctx)
00702 {
00703   assert(!!ctx->compgraph &&
00704       "need component graph for creating evaluation graph");
00705   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"creating evaluation graph");
00706 
00707   FinalEvalGraphPtr evalgraph(new FinalEvalGraph);
00708     EvalGraphBuilderPtr egbuilder;
00709     if( ctx->config.getOption("DumpEvaluationPlan") )
00710     {
00711         egbuilder.reset(new DumpingEvalGraphBuilder(
00712                     *ctx, *ctx->compgraph, *evalgraph, ctx->aspsoftware,
00713                     ctx->config.getStringOption("DumpEvaluationPlanFile")));
00714     }
00715     else
00716     {
00717         egbuilder.reset(new EvalGraphBuilder(
00718                     *ctx, *ctx->compgraph, *evalgraph, ctx->aspsoftware));
00719     }
00720 
00721   // use configured eval heuristic
00722   assert(!!ctx->evalHeuristic && "need configured heuristic");
00723   DBGLOG(DBG,"invoking build() on eval heuristic");
00724   ctx->evalHeuristic->build(*egbuilder);
00725   // do not destruct heuristic because we might reuse it in evaluateSubprogram
00726   //DBGLOG(DBG,"destructing eval heuristic");
00727   //ctx->evalHeuristic.reset();
00728   // destruct eval graph builder
00729   egbuilder.reset();
00730 
00731   // setup final unit used to get full models
00732   #warning TODO if we project answer sets, or do querying, we could reduce the number of units used here!
00733   FinalEvalGraph::EvalUnit ufinal =
00734     evalgraph->addUnit(FinalEvalGraph::EvalUnitPropertyBundle());
00735   LOG(DBG,"created virtual final unit ufinal = " << ufinal);
00736 
00737   FinalEvalGraph::EvalUnitIterator it, itend;
00738   boost::tie(it, itend) = evalgraph->getEvalUnits();
00739   for(; it != itend && *it != ufinal; ++it)
00740   {
00741     DBGLOG(DBG,"adding dependency from ufinal to unit " << *it <<
00742         " join order " << *it);
00743     // we can do this because we know that eval units
00744     // (= vertices of a vecS adjacency list) are unsigned integers
00745     evalgraph->addDependency(
00746         ufinal, *it,
00747         FinalEvalGraph::EvalUnitDepPropertyBundle(*it));
00748   }
00749 
00750   ctx->ufinal = ufinal;
00751   ctx->evalgraph = evalgraph;
00752 
00753   if( ctx->config.getOption("DumpEvalGraph") )
00754   {
00755     std::string fnamev = ctx->config.getStringOption("DebugPrefix")+"_EvalGraphVerbose.dot";
00756     LOG(INFO,"dumping verbose eval graph to " << fnamev);
00757     std::ofstream filev(fnamev.c_str());
00758     ctx->evalgraph->writeGraphViz(filev, true);
00759 
00760     std::string fnamet = ctx->config.getStringOption("DebugPrefix")+"_EvalGraphTerse.dot";
00761     LOG(INFO,"dumping terse eval graph to " << fnamet);
00762     std::ofstream filet(fnamet.c_str());
00763     ctx->evalgraph->writeGraphViz(filet, false);
00764   }
00765 
00766   StatePtr next(new SetupProgramCtxState);
00767   changeState(ctx, next);
00768 }
00769 
00770 MANDATORY_STATE_CONSTRUCTOR(SetupProgramCtxState);
00771 
00772 void SetupProgramCtxState::setupProgramCtx(ProgramCtx* ctx)
00773 {
00774   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"setupProgramCtx");
00775 
00776   // default model outputting callback
00777   ModelCallbackPtr asprinter(new AnswerSetPrinterCallback(*ctx));
00778   ctx->modelCallbacks.push_back(asprinter);
00779 
00780   // setup printing of auxiliaries
00781   if( 1 == ctx->config.getOption("KeepAuxiliaryPredicates") )
00782   {
00783     AuxPrinterPtr plainAuxPrinter(new PlainAuxPrinter(ctx->registry()));
00784     ctx->registry()->registerUserDefaultAuxPrinter(plainAuxPrinter);
00785   }
00786 
00787   // let plugins setup the program ctx (removing the default hooks is permitted)
00788   ctx->setupByPlugins();
00789 
00790   StatePtr next(new EvaluateState);
00791   changeState(ctx, next);
00792 }
00793 
00794 MANDATORY_STATE_CONSTRUCTOR(EvaluateState);
00795 
00796 void
00797 EvaluateState::evaluate(ProgramCtx* ctx)
00798 {
00799   typedef ModelBuilder<FinalEvalGraph>::Model Model;
00800   typedef ModelBuilder<FinalEvalGraph>::OptionalModel OptionalModel;
00801   typedef ModelBuilder<FinalEvalGraph>::MyModelGraph MyModelGraph;
00802 
00803   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"evaluate()");
00804 
00805   do
00806   {
00807     LOG(INFO,"creating model builder");
00808     {
00809       DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidmb, "create model builder");
00810       ctx->modelBuilder = ModelBuilderPtr(ctx->modelBuilderFactory(*ctx->evalgraph));
00811     }
00812     ModelBuilder<FinalEvalGraph>& mb = *ctx->modelBuilder;
00813 
00814     // get model and call all callbacks
00815     // abort if one callback returns false
00816     DLVHEX_BENCHMARK_REGISTER(sidgetnextmodel, "evaluate::get next model");
00817     unsigned mcount = 0;
00818     bool abort = false;
00819     bool gotModel;
00820     unsigned mcountLimit = ctx->config.getOption("NumberOfModels");
00821     std::vector<AnswerSetPtr> bestModels;   // model cache for weight minimization
00822     do
00823     {
00824       gotModel = false;
00825       DBGLOG(DBG,"requesting imodel");
00826       DLVHEX_BENCHMARK_START(sidgetnextmodel);
00827       OptionalModel om = mb.getNextIModel(ctx->ufinal);
00828       DLVHEX_BENCHMARK_STOP(sidgetnextmodel);
00829       if( !!om )
00830       {
00831         Model m = om.get();
00832         InterpretationConstPtr interpretation =
00833           mb.getModelGraph().propsOf(m).interpretation;
00834 
00835         // if the program is empty, we may get a NULL interpretation
00836         if( !interpretation )
00837         {
00838           assert(mb.getModelGraph().propsOf(m).dummy == true);
00839           interpretation.reset(new Interpretation(ctx->registry()));
00840         }
00841 
00842         if( ctx->config.getOption("DumpIModelGraph") )
00843         {
00844           throw std::runtime_error("DumpIModelGraph  not implemented!");
00845           #warning TODO individual eval/model graphviz output
00846         }
00847         #ifndef NDEBUG
00848         DBGLOG(DBG,"got model#" << mcount << ":" << *interpretation);
00849         /*
00850         std::set<Model> onlyFor;
00851         onlyFor.insert(m.get());
00852         GraphVizFunc func = boost::bind(&writeEgMgGraphViz<MyModelGraph>, _1,
00853             true, boost::cref(mb.getEvalGraph()), boost::cref(mb.getModelGraph()), onlyFor);
00854         std::stringstream smodel;
00855         smodel << fname << "PlainHEXOnlineModel" << mcount;
00856         writeGraphVizFunctors(func, func, smodel.str());
00857         */
00858         #endif
00859 
00860         // model callbacks
00861         AnswerSetPtr answerset(new AnswerSet(ctx->registry()));
00862         // copy interpretation! (callbacks can modify it)
00863         answerset->interpretation->getStorage() = interpretation->getStorage();
00864         answerset->computeWeightVector();
00865 
00866         // add EDB if configured that way
00867         if( !ctx->config.getOption("NoFacts") )
00868         {
00869           answerset->interpretation->getStorage() |=
00870             ctx->edb->getStorage();
00871         }
00872 
00873         // cost check
00874         // compare the solution to the best known model
00875         gotModel = true;
00876         if (ctx->currentOptimum.size() == 0 || answerset->betterThan(ctx->currentOptimum))
00877         {
00878           ctx->currentOptimum = answerset->getWeightVector();
00879 #ifndef NDEBUG
00880           std::stringstream ss;
00881           answerset->printWeightVector(ss);
00882           DBGLOG(DBG, "New global optimum: " << ss.str());
00883 #endif
00884 
00885           if (ctx->onlyBestModels)
00886           {
00887             // cache models and decide at the end upon optimality
00888 
00889             // is the new model better than the best known one?
00890             if (bestModels.size() > 0 && !bestModels[0]->betterThan(answerset->getWeightVector()))
00891             {
00892                     bestModels.clear();
00893                     mcount = 0;
00894             }
00895             bestModels.push_back(answerset);
00896           }
00897           else
00898           {
00899             // process models directly
00900             BOOST_FOREACH(ModelCallbackPtr mcb, ctx->modelCallbacks)
00901             {
00902               bool aborthere = !(*mcb)(answerset);
00903               abort |= aborthere;
00904               if( aborthere )
00905                 LOG(DBG,"callback '" << typeid(*mcb).name() << "' signalled abort at model " << mcount);
00906             }
00907           }
00908           mcount++;
00909 
00910           #ifndef NDEBUG
00911           //mb.printEvalGraphModelGraph(std::cerr);
00912           #endif
00913           if( mcountLimit != 0 && mcount >= mcountLimit )
00914           {
00915             LOG(INFO,"breaking model enumeration loop because already enumerated " << mcount << " models!");
00916             break;
00917           }
00918         }
00919       }
00920     }
00921     while( gotModel && !abort );
00922 
00923     // process cached models
00924     if (ctx->onlyBestModels){
00925       BOOST_FOREACH (AnswerSetPtr answerset, bestModels){
00926         BOOST_FOREACH(ModelCallbackPtr mcb, ctx->modelCallbacks)
00927         {
00928           bool aborthere = !(*mcb)(answerset);
00929           abort |= aborthere;
00930           if( aborthere )
00931             LOG(DBG,"callback '" << typeid(*mcb).name() << "' signalled abort at model " << mcount);
00932         }
00933       }
00934     }
00935 
00936     LOG(INFO,"got " << mcount << " models");
00937     if( abort )
00938     {
00939       LOG(INFO,"model building was aborted by callback");
00940     }
00941     else
00942     {
00943       if( mcountLimit == 0 )
00944       {
00945         LOG(INFO,"model building finished after enumerating all models");
00946       }
00947       else
00948       {
00949         LOG(INFO,"model building finished after enumerating " << mcountLimit << " models");
00950       }
00951     }
00952 
00953     if( ctx->config.getOption("DumpModelGraph") )
00954     {
00955       throw std::runtime_error("DumpModelGraph  not implemented!");
00956       #warning TODO overall eval/model graphviz output
00957     }
00958 
00959     // call final callbacks
00960     BOOST_FOREACH(FinalCallbackPtr fcb, ctx->finalCallbacks)
00961     {
00962       DBGLOG(DBG,"calling final callback " << printptr(fcb));
00963       (*fcb)();
00964     }
00965 
00966     // if repetition counter is set, decrease it and repeat
00967     unsigned repeatEvaluation = ctx->config.getOption("RepeatEvaluation");
00968     if( repeatEvaluation > 0 )
00969     {
00970       LOG(INFO,"repeating evaluation because RepeatEvaluation=" << repeatEvaluation);
00971       ctx->config.setOption("RepeatEvaluation", repeatEvaluation-1);
00972       continue;
00973     }
00974 
00975     // default: do not repeat
00976     break;
00977   }
00978   while(true);
00979 
00980   #if 0
00981   #ifndef NDEBUG
00982   mb.printEvalGraphModelGraph(std::cerr);
00983   #endif
00984   #ifndef NDEBUG
00985   GraphVizFunc func = boost::bind(&writeEgMgGraphViz<MyModelGraph>, _1,
00986       true, boost::cref(mb.getEvalGraph()), boost::cref(mb.getModelGraph()), boost::none);
00987   writeGraphVizFunctors(func, func, fname+"PlainHEXOnlineEgMg");
00988   #endif
00989   #endif
00990   //std::cerr << __FILE__ << ":" << __LINE__ << std::endl << *ctx.registry() << std::endl;
00991 
00992 
00993   #if 0
00994 
00995   //
00996   // We don't have a depedency graph, so just dump the program to an
00997   // OrdinaryModelGenerator and see what happens
00998   //
00999 
01000   std::vector<AtomSet> models;
01001 
01002   OrdinaryModelGenerator omg(*ctx);
01003 
01004   //
01005   // The GraphProcessor starts its computation with the program's ground
01006   // facts as input.
01007   // But only if the original EDB is consistent, otherwise, we can skip it
01008   // anyway.
01009   //
01010   if (ctx->getEDB()->isConsistent())
01011     {
01012       omg.compute(*ctx->getIDB(), *ctx->getEDB(), models);
01013     }
01014 
01016 
01017   //
01018   // prepare result container
01019   //
01020   // if we had any weak constraints, we have to tell the result container the
01021   // prefix in order to be able to compute each asnwer set's costs!
01022   //
01023   std::string wcprefix;
01024 
01025   if (ctx->getIDB()->getWeakConstraints().size() > 0)
01026     {
01027       wcprefix = "wch__";
01028     }
01029 
01030   ResultContainer* result = new ResultContainer(wcprefix);
01031   ctx->setResultContainer(result);
01032 
01033   //
01034   // put GraphProcessor result into ResultContainer
01036   //
01037   for (std::vector<AtomSet>::const_iterator it = models.begin();
01038        it != models.end(); ++it)
01039     {
01040       ctx->getResultContainer()->addSet(*it);
01041     }
01042 
01043   #endif
01044 
01045   #warning TODO dlt was here
01046 
01047   //   if (optiondlt)
01048   //     {
01049   //       ctx->getResultContainer()->filterOutDLT();
01050   //     }
01051 
01052 
01053   #if 0
01054     std::cerr << "TIMING " << fname << " " << heurimode << " " << mbmode << " " << backend << " " <<
01055       ctx->evalgraph.countEvalUnits() << " evalunits " << ctx->evalgraph.countEvalUnitDeps() << " evalunitdeps " << mcount << " models ";
01056     benchmark::BenchmarkController::Instance().printDuration(std::cerr, sidoverall) << std::endl;
01057   #endif
01058 
01059   StatePtr next(new PostProcessState);
01060   changeState(ctx, next);
01061 }
01062 
01063 MANDATORY_STATE_CONSTRUCTOR(PostProcessState);
01064 
01065 void PostProcessState::postProcess(ProgramCtx* ctx)
01066 {
01067   DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"postProcess");
01068 
01069     // cleanup some stuff that is better not automatically destructed
01070     DBGLOG(DBG,"usage count of model builder before reset is " <<
01071             ctx->modelBuilder.use_count());
01072     ctx->modelBuilder.reset();
01073 
01074   // use base State class with no failureState -> calling it will always throw an exception
01075   boost::shared_ptr<State> next(new State);
01076   changeState(ctx, next);
01077 
01078   if( ctx->config.getOption("BenchmarkEAstderr") == 1 )
01079   {
01080     benchmark::BenchmarkController& bmc = benchmark::BenchmarkController::Instance();
01081     //benchmark::ID eeval = bmc.getInstrumentationID("evaluate external atom");
01082     benchmark::ID eeval = bmc.getInstrumentationID("PluginAtom retrieve");
01083     const benchmark::BenchmarkController::Stat& stat = bmc.getStat(eeval);
01084     std::cerr << stat.count << " ";
01085     bmc.printInSecs(std::cerr, stat.duration, 3);
01086     std::cerr << std::endl;
01087   }
01088 }
01089 
01090 
01091 DLVHEX_NAMESPACE_END
01092 
01093 // vim:ts=4:
01094 
01095 // Local Variables:
01096 // mode: C++
01097 // End: