DLVHEX_NAMESPACE_USE BOOST_AUTO_TEST_CASE(testDisj) { ProgramCtx ctx; ctx.setupRegistry(RegistryPtr(new Registry)); std::stringstream ss; ss << // a <-(+)-> a (head/head = disjunctive) "a v b." << std::endl << "a v c." << std::endl; InputProviderPtr ip(new InputProvider); ip->addStreamInput(ss, "testinput"); ModuleHexParser parser; BOOST_REQUIRE_NO_THROW(parser.parse(ip, ctx)); LOG_REGISTRY_PROGRAM(ctx); ID ida = ctx.registry()->ogatoms.getIDByString("a"); ID idb = ctx.registry()->ogatoms.getIDByString("b"); ID idc = ctx.registry()->ogatoms.getIDByString("c"); BOOST_REQUIRE((ida | idb | idc) != ID_FAIL); // smaller more efficient dependency graph { DependencyGraph depgraph(ctx, ctx.registry()); std::vector<ID> auxRules; depgraph.createDependencies(ctx.idb, auxRules); BOOST_CHECK_EQUAL(depgraph.countNodes(), 2); BOOST_CHECK_EQUAL(depgraph.countDependencies(), 2); // TODO test dependencies (will do manually with graphviz at the moment) const char* fnamev = "testDependencyGraphDisjVerbose.dot"; LOG(INFO,"dumping verbose graph to " << fnamev); std::ofstream filev(fnamev); depgraph.writeGraphViz(filev, true); makeGraphVizPdf(fnamev); const char* fnamet = "testDependencyGraphDisjTerse.dot"; LOG(INFO,"dumping terse graph to " << fnamet); std::ofstream filet(fnamet); depgraph.writeGraphViz(filet, false); makeGraphVizPdf(fnamet); } }
int main(int argn, char** argv) { try { DLVHEX_BENCHMARK_REGISTER_AND_START(sidoverall, "overall timing"); if( argn != 5 ) { std::cerr << "usage: " << argv[0] << " <heurimode> <mbmode> <backend> <inputfile>" << std::endl; return -1; } // // setup benchmarking // benchmark::BenchmarkController& ctr = benchmark::BenchmarkController::Instance(); ctr.setOutput(&std::cerr); // for continuous statistics output, display every 1000'th output ctr.setPrintInterval(999); // deconstruct benchmarking (= output results) at scope exit int dummy; // this is needed, as SCOPE_EXIT is not defined for no arguments BOOST_SCOPE_EXIT( (dummy) ) { (void)dummy; benchmark::BenchmarkController::finish(); } BOOST_SCOPE_EXIT_END // // preprocess arguments // const std::string heurimode(argv[1]); const std::string mbmode(argv[2]); const std::string backend(argv[3]); const std::string fname(argv[4]); // get input InputProviderPtr ip(new InputProvider); ip->addFileInput(fname); // don't rewrite // prepare program context ProgramCtx ctx; { RegistryPtr registry(new Registry); ctx.setupRegistry(registry); PluginContainerPtr pluginContainer(new PluginContainer); ctx.setupPluginContainer(pluginContainer); } // create all testing plugin atoms ctx.addPluginAtom(PluginAtomPtr(new AbovePluginAtom)); ctx.addPluginAtom(PluginAtomPtr(new SenseNotArmed1PluginAtom)); ctx.addPluginAtom(PluginAtomPtr(new SenseNotArmed2PluginAtom)); ctx.addPluginAtom(PluginAtomPtr(new GenPluginAtom2("gen2",2))); // parse HEX program LOG(INFO,"parsing HEX program"); DLVHEX_BENCHMARK_REGISTER_AND_START(sidhexparse, "HexParser::parse"); ModuleHexParser parser; parser.parse(ip, ctx); DLVHEX_BENCHMARK_STOP(sidhexparse); ctx.associateExtAtomsWithPluginAtoms(ctx.idb,true); //LOG_REGISTRY_PROGRAM(ctx); // create dependency graph LOG(INFO,"creating dependency graph"); DLVHEX_BENCHMARK_REGISTER_AND_START(siddepgraph, "create dependencygraph"); std::vector<dlvhex::ID> auxRules; dlvhex::DependencyGraph depgraph(ctx, ctx.registry()); depgraph.createDependencies(ctx.idb, auxRules); DLVHEX_BENCHMARK_STOP(siddepgraph); #ifndef NDEBUG writeGraphViz(depgraph, fname+"PlainHEXDepGraph"); #endif // create component graph LOG(INFO,"creating component graph"); DLVHEX_BENCHMARK_REGISTER_AND_START(sidcompgraph, "create componentgraph"); dlvhex::ComponentGraph compgraph(depgraph, ctx.registry()); DLVHEX_BENCHMARK_STOP(sidcompgraph); #ifndef NDEBUG writeGraphViz(compgraph, fname+"PlainHEXCompGraph"); #endif // manage external evaluation configuration / backend ASPSolverManager::SoftwareConfigurationPtr externalEvalConfig; if( backend == "dlv" ) { externalEvalConfig.reset(new ASPSolver::DLVSoftware::Configuration); } else if( backend == "libdlv" ) { #ifdef HAVE_LIBDLV externalEvalConfig.reset(new ASPSolver::DLVLibSoftware::Configuration); #else std::cerr << "sorry, libdlv not compiled in" << std::endl; return -1; #endif // HAVE_LIBDLV } else if( backend == "libclingo" ) { #ifdef HAVE_LIBCLINGO externalEvalConfig.reset(new ASPSolver::ClingoSoftware::Configuration); #else std::cerr << "sorry, libclingo not compiled in" << std::endl; return -1; #endif // HAVE_LIBCLINGO } else { std::cerr << "usage: <backend> must be one of 'dlv','libdlv','libclingo'" << std::endl; return -1; } // create eval graph LOG(INFO,"creating eval graph"); DLVHEX_BENCHMARK_REGISTER_AND_START(sidevalgraph, "create evalgraph"); FinalEvalGraph evalgraph; EvalGraphBuilder egbuilder(ctx, compgraph, evalgraph, externalEvalConfig); // use one of several heuristics if( heurimode == "old" ) { // old DLVHEX heuristic LOG(INFO,"building eval graph with old heuristics"); EvalHeuristicOldDlvhex heuristicOldDlvhex; heuristicOldDlvhex.build(egbuilder); } else if( heurimode == "trivial" ) { // trivial heuristic: just take component graph // (maximum number of eval units, probably large overhead) LOG(INFO,"building eval graph with trivial heuristics"); EvalHeuristicTrivial heuristic; heuristic.build(egbuilder); } else if( heurimode == "easy" ) { // easy heuristic: just make some easy adjustments to improve on the trivial heuristics LOG(INFO,"building eval graph with easy heuristics"); EvalHeuristicEasy heuristic; heuristic.build(egbuilder); } else { std::cerr << "usage: <heurimode> must be one of 'old','trivial','easy'" << std::endl; return -1; } DLVHEX_BENCHMARK_STOP(sidevalgraph); #ifndef NDEBUG writeGraphViz(compgraph, fname+"PlainHEXEvalGraph"); #endif // setup final unit LOG(INFO,"setting up final unit"); DLVHEX_BENCHMARK_REGISTER_AND_START(sidfinalunit, "creating final unit"); EvalUnit ufinal; { ufinal = evalgraph.addUnit(FinalEvalGraph::EvalUnitPropertyBundle()); LOG(INFO,"ufinal = " << ufinal); FinalEvalGraph::EvalUnitIterator it, itend; boost::tie(it, itend) = evalgraph.getEvalUnits(); for(; it != itend && *it != ufinal; ++it) { DBGLOG(DBG,"adding dependency from ufinal to unit " << *it << " join order " << *it); // we can do this because we know that eval units (= vertices of a vecS adjacency list) are unsigned integers evalgraph.addDependency(ufinal, *it, FinalEvalGraph::EvalUnitDepPropertyBundle(*it)); } } DLVHEX_BENCHMARK_STOP(sidfinalunit); // prepare for output //GenericOutputBuilder ob; #warning reactivate and redesign outputbuilder //std::cerr << __FILE__ << ":" << __LINE__ << std::endl << *ctx.registry() << std::endl; // evaluate LOG(INFO,"evaluating"); DLVHEX_BENCHMARK_REGISTER(sidoutputmodel, "output model"); dlvhex::ModelBuilderConfig<FinalEvalGraph> mbcfg(evalgraph); if( mbmode == "online" ) { typedef FinalOnlineModelBuilder::Model Model; typedef FinalOnlineModelBuilder::OptionalModel OptionalModel; typedef FinalOfflineModelBuilder::MyModelGraph MyModelGraph; LOG(INFO,"creating model builder"); DLVHEX_BENCHMARK_REGISTER_AND_START(sidonlinemb, "create online mb"); FinalOnlineModelBuilder mb(mbcfg); DLVHEX_BENCHMARK_STOP(sidonlinemb); // get and print all models OptionalModel m; DLVHEX_BENCHMARK_REGISTER(sidgetnextonlinemodel, "get next online model"); unsigned mcount = 0; do { DBGLOG(DBG,"requesting model"); DLVHEX_BENCHMARK_START(sidgetnextonlinemodel); m = mb.getNextIModel(ufinal); DLVHEX_BENCHMARK_STOP(sidgetnextonlinemodel); if( !!m ) { InterpretationConstPtr interpretation = mb.getModelGraph().propsOf(m.get()).interpretation; #ifndef NDEBUG DBGLOG(DBG,"got model#" << mcount << ":" << *interpretation); std::set<Model> onlyFor; onlyFor.insert(m.get()); GraphVizFunc func = boost::bind(&writeEgMgGraphViz<MyModelGraph>, _1, true, boost::cref(mb.getEvalGraph()), boost::cref(mb.getModelGraph()), onlyFor); std::stringstream smodel; smodel << fname << "PlainHEXOnlineModel" << mcount; writeGraphVizFunctors(func, func, smodel.str()); #endif mcount++; // output model { std::cout << *interpretation << std::endl; } //std::cerr << __FILE__ << ":" << __LINE__ << std::endl << *ctx.registry() << std::endl; #ifndef NDEBUG mb.printEvalGraphModelGraph(std::cerr); #endif } } while( !!m ); #ifndef NDEBUG mb.printEvalGraphModelGraph(std::cerr); #endif #ifndef NDEBUG GraphVizFunc func = boost::bind(&writeEgMgGraphViz<MyModelGraph>, _1, true, boost::cref(mb.getEvalGraph()), boost::cref(mb.getModelGraph()), boost::none); writeGraphVizFunctors(func, func, fname+"PlainHEXOnlineEgMg"); #endif //std::cerr << __FILE__ << ":" << __LINE__ << std::endl << *ctx.registry() << std::endl; DLVHEX_BENCHMARK_STOP(sidoverall); std::cerr << "TIMING " << fname << " " << heurimode << " " << mbmode << " " << backend << " " << evalgraph.countEvalUnits() << " evalunits " << evalgraph.countEvalUnitDeps() << " evalunitdeps " << mcount << " models "; benchmark::BenchmarkController::Instance().printDuration(std::cerr, sidoverall) << std::endl; } else if( mbmode == "offline" ) { typedef FinalOfflineModelBuilder::Model Model; typedef FinalOfflineModelBuilder::OptionalModel OptionalModel; typedef FinalOfflineModelBuilder::MyModelGraph MyModelGraph; LOG(INFO,"creating model builder"); DLVHEX_BENCHMARK_REGISTER_AND_START(sidofflinemb, "create offline mb"); FinalOfflineModelBuilder mb(mbcfg); DLVHEX_BENCHMARK_STOP(sidofflinemb); LOG(INFO,"creating all final imodels"); DLVHEX_BENCHMARK_REGISTER_AND_START(sidofflinemodels, "create offline models"); mb.buildIModelsRecursively(ufinal); DLVHEX_BENCHMARK_STOP(sidofflinemodels); #ifndef NDEBUG mb.printEvalGraphModelGraph(std::cerr); #endif LOG(INFO,"printing models"); DLVHEX_BENCHMARK_REGISTER_AND_START(sidprintoffmodels, "print offline models"); MyModelGraph& mg = mb.getModelGraph(); const MyModelGraph::ModelList& models = mg.modelsAt(ufinal, MT_IN); unsigned mcount = 0; BOOST_FOREACH(Model m, models) { InterpretationConstPtr interpretation = mg.propsOf(m).interpretation; #ifndef NDEBUG DBGLOG(DBG,"got model#" << mcount << ":" << *interpretation); std::set<Model> onlyFor; onlyFor.insert(m); GraphVizFunc func = boost::bind(&writeEgMgGraphViz<MyModelGraph>, _1, true, boost::cref(mb.getEvalGraph()), boost::cref(mb.getModelGraph()), onlyFor); std::stringstream smodel; smodel << fname << "PlainHEXOfflineModel" << mcount; writeGraphVizFunctors(func, func, smodel.str()); #endif mcount++; // output model { std::cout << *interpretation << std::endl; } } DLVHEX_BENCHMARK_STOP(sidprintoffmodels); #ifndef NDEBUG GraphVizFunc func = boost::bind(&writeEgMgGraphViz<MyModelGraph>, _1, true, boost::cref(mb.getEvalGraph()), boost::cref(mb.getModelGraph()), boost::none); writeGraphVizFunctors(func, func, fname+"PlainHEXOfflineEgMg"); #endif DLVHEX_BENCHMARK_STOP(sidoverall); std::cerr << "TIMING " << fname << " " << heurimode << " " << mbmode << " " << backend << " " << evalgraph.countEvalUnits() << " evalunits " << evalgraph.countEvalUnitDeps() << " evalunitdeps " << mcount << " models "; benchmark::BenchmarkController::Instance().printDuration(std::cerr, sidoverall) << "s" << std::endl; } else { std::cerr << "usage: <mbmode> must be one of 'online','offline'" << std::endl; return -1; } return 0; }
void SimulatorAtom::retrieve(const Query& query, Answer& answer) throw (PluginError){ RegistryPtr reg = query.interpretation->getRegistry(); const Tuple& params = query.input; // get ASP filename std::string programpath = reg->terms.getByID(params[0]).getUnquotedString(); // if we access this file for the first time, parse the content if (programs.find(programpath) == programs.end()){ DBGLOG(DBG, "Parsing simulation program"); InputProviderPtr ip(new InputProvider()); ip->addFileInput(programpath); Logger::Levels l = Logger::Instance().getPrintLevels(); // workaround: verbose causes the parse call below to fail (registry pointer is 0) Logger::Instance().setPrintLevels(0); programs[programpath].changeRegistry(reg); ModuleHexParser hp; hp.parse(ip, programs[programpath]); Logger::Instance().setPrintLevels(l); } ProgramCtx& pc = programs[programpath]; // construct edb DBGLOG(DBG, "Constructing EDB"); InterpretationPtr edb = InterpretationPtr(new Interpretation(*pc.edb)); // go through all input atoms DBGLOG(DBG, "Rewriting input"); for(Interpretation::Storage::enumerator it = query.interpretation->getStorage().first(); it != query.interpretation->getStorage().end(); ++it){ ID ogid(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG, *it); const OrdinaryAtom& ogatom = reg->ogatoms.getByID(ogid); // check if the predicate matches any of the input parameters to simulator atom bool found = false; for (int inp = 1; inp < params.size(); ++inp){ if (ogatom.tuple[0] == params[inp]){ // replace the predicate by "in[inp]" std::stringstream inPredStr; inPredStr << "in" << inp; Term inPredTerm(ID::MAINKIND_TERM | ID::SUBKIND_TERM_CONSTANT, inPredStr.str()); ID inPredID = reg->storeTerm(inPredTerm); OrdinaryAtom oareplace = ogatom; oareplace.tuple[0] = inPredID; // get ID of replaced atom ID oareplaceID = reg->storeOrdinaryGAtom(oareplace); // set this atom in the input interpretation edb->getStorage().set_bit(oareplaceID.address); found = true; break; } } assert(found); } DBGLOG(DBG, "Grounding simulation program"); OrdinaryASPProgram program(pc.registry(), pc.idb, edb); InternalGrounderPtr ig = InternalGrounderPtr(new InternalGrounder(pc, program)); OrdinaryASPProgram gprogram = ig->getGroundProgram(); DBGLOG(DBG, "Evaluating simulation program"); GenuineSolverPtr igas = GenuineSolver::getInstance(pc, gprogram); InterpretationPtr as = igas->getNextModel(); if (as != InterpretationPtr()){ // extract parameters from all atoms over predicate "out" DBGLOG(DBG, "Rewrting output"); Term outPredTerm(ID::MAINKIND_TERM | ID::SUBKIND_TERM_CONSTANT, "out"); ID outPredID = reg->storeTerm(outPredTerm); for(Interpretation::Storage::enumerator it = as->getStorage().first(); it != as->getStorage().end(); ++it){ ID ogid(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG, *it); const OrdinaryAtom& ogatom = reg->ogatoms.getByID(ogid); if (ogatom.tuple[0] == outPredID){ Tuple t; for (int ot = 1; ot < ogatom.tuple.size(); ++ot){ t.push_back(ogatom.tuple[ot]); } answer.get().push_back(t); } } } }
void ArgSemExtAtom::retrieve(const Query& query, Answer& answer) throw (PluginError) { assert(query.input.size() == 6); RegistryPtr reg = getRegistry(); // check if pspoil is true { // id of constant of saturate/spoil predicate ID saturate_pred = query.input[4]; // get id of 0-ary atom OrdinaryAtom saturate_oatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG); saturate_oatom.tuple.push_back(saturate_pred); ID saturate_atom = reg->storeOrdinaryGAtom(saturate_oatom); DBGLOG(DBG,"got saturate_pred=" << saturate_pred << " and saturate_atom=" << saturate_atom); // check if atom <saturate_pred> is true in interpretation bool saturate = query.interpretation->getFact(saturate_atom.address); LOG(DBG,"ArgSemExtAtom called with pos saturate=" << saturate); if( saturate ) { // always return true answer.get().push_back(Tuple()); return; } } // check if nspoil is true { // id of constant of saturate/spoil predicate ID saturate_pred = query.input[5]; // get id of 0-ary atom OrdinaryAtom saturate_oatom(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG); saturate_oatom.tuple.push_back(saturate_pred); ID saturate_atom = reg->storeOrdinaryGAtom(saturate_oatom); DBGLOG(DBG,"got saturate_pred=" << saturate_pred << " and saturate_atom=" << saturate_atom); // check if atom <saturate_pred> is true in interpretation bool saturate = query.interpretation->getFact(saturate_atom.address); LOG(DBG,"ArgSemExtAtom called with neg saturate=" << saturate); if( saturate ) { // always return false answer.use(); return; } } // get arguments const std::string& semantics = reg->getTermStringByID(query.input[0]); ID argRelId = query.input[1]; ID attRelId = query.input[2]; ID extRelId = query.input[3]; // assemble facts from input std::stringstream s; { // add argumentation framework (att, arg) as predicates att/2 and arg/1 // (ignore predicate name of given atoms) // TODO: we could do this more efficiently using extctx.edb->setFact(...); and not by parsing // arguments { PredicateMask& argMask = getPredicateMask(argRelId, reg); argMask.updateMask(); InterpretationPtr argInt(new Interpretation(*query.interpretation)); argInt->bit_and(*argMask.mask()); for(auto begend = argInt->trueBits(); begend.first != begend.second; ++begend.first++) { auto bit_it = begend.first; const OrdinaryAtom& atom = argInt->getAtomToBit(bit_it); assert(atom.tuple.size() == 2); s << "arg(" << printToString<RawPrinter>(atom.tuple[1], reg) << ").\n"; } } // attacks { PredicateMask& attMask = getPredicateMask(attRelId, reg); attMask.updateMask(); InterpretationPtr attInt(new Interpretation(*query.interpretation)); attInt->bit_and(*attMask.mask()); for(auto begend = attInt->trueBits(); begend.first != begend.second; ++begend.first++) { auto bit_it = begend.first; const OrdinaryAtom& atom = attInt->getAtomToBit(bit_it); assert(atom.tuple.size() == 3); s << "att(" << printToString<RawPrinter>(atom.tuple[1], reg) << "," << printToString<RawPrinter>(atom.tuple[2], reg) << ").\n"; } } // extension to check { PredicateMask& extMask = getPredicateMask(extRelId, reg); extMask.updateMask(); InterpretationPtr extInt(new Interpretation(*query.interpretation)); extInt->bit_and(*extMask.mask()); for(auto begend = extInt->trueBits(); begend.first != begend.second; ++begend.first++) { auto bit_it = begend.first; const OrdinaryAtom& atom = extInt->getAtomToBit(bit_it); assert(atom.tuple.size() == 2); s << "ext(" << printToString<RawPrinter>(atom.tuple[1], reg) << ").\n"; } } // add check s << "%% check if ext/1 is an extension\n" ":- arg(X), ext(X), out(X).\n" ":- arg(X), not ext(X), in(X).\n"; } // build program InputProviderPtr input(new InputProvider); input->addStringInput(s.str(),"facts_from_predicate_input"); input->addFileInput(semantics + ".encoding"); #if 0 // we use an extra registry for an external program ProgramCtx extctx; extctx.setupRegistry(RegistryPtr(new Registry)); // parse ModuleHexParser parser; parser.parse(input, extctx); DBGLOG(DBG,"after parsing input: idb and edb are" << std::endl << std::endl << printManyToString<RawPrinter>(extctx.idb,"\n",extctx.registry()) << std::endl << *extctx.edb << std::endl); // check if there is one answer set, if yes return true, false otherwise { typedef ASPSolverManager::SoftwareConfiguration<ASPSolver::DLVSoftware> DLVConfiguration; DLVConfiguration dlv; OrdinaryASPProgram program(extctx.registry(), extctx.idb, extctx.edb, extctx.maxint); ASPSolverManager mgr; ASPSolverManager::ResultsPtr res = mgr.solve(dlv, program); AnswerSet::Ptr firstAnswerSet = res->getNextAnswerSet(); if( firstAnswerSet != 0 ) { LOG(DBG,"got answer set " << *firstAnswerSet->interpretation); // true answer.get().push_back(Tuple()); } else { LOG(DBG,"got no answer set!"); // false (-> mark as used) answer.use(); } } #else ProgramCtx subctx = ctx; subctx.changeRegistry(RegistryPtr(new Registry)); subctx.edb.reset(new Interpretation(subctx.registry())); subctx.inputProvider = input; input.reset(); // parse into subctx, but do not call converters if( !subctx.parser ) { subctx.parser.reset(new ModuleHexParser); } subctx.parser->parse(subctx.inputProvider, subctx); std::vector<InterpretationPtr> subas = ctx.evaluateSubprogram(subctx, false); if( !subas.empty() ) { LOG(DBG,"got answer set " << *subas.front()); // true answer.get().push_back(Tuple()); } else { LOG(DBG,"got no answer set!"); // false (-> mark as used) answer.use(); } #endif }