|
dlvhex
2.1.0
|
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: