GuessAndCheckModelGenerator::GuessAndCheckModelGenerator( Factory& factory, InterpretationConstPtr input): FLPModelGeneratorBase(factory, input), factory(factory) { DBGLOG(DBG, "GnC-ModelGenerator is instantiated for a " << (factory.ci.disjunctiveHeads ? "" : "non-") << "disjunctive component"); RegistryPtr reg = factory.reg; // create new interpretation as copy InterpretationPtr postprocInput; if( input == 0 ) { // empty construction postprocInput.reset(new Interpretation(reg)); } else { // copy construction postprocInput.reset(new Interpretation(*input)); } // augment input with edb WARNING("perhaps we can pass multiple partially preprocessed input edb's to the external solver and save a lot of processing here") postprocInput->add(*factory.ctx.edb); // remember which facts we must remove mask.reset(new Interpretation(*postprocInput)); // manage outer external atoms if( !factory.outerEatoms.empty() ) { // augment input with result of external atom evaluation // use newint as input and as output interpretation IntegrateExternalAnswerIntoInterpretationCB cb(postprocInput); evaluateExternalAtoms(factory.ctx, factory.outerEatoms, postprocInput, cb); DLVHEX_BENCHMARK_REGISTER(sidcountexternalatomcomps, "outer eatom computations"); DLVHEX_BENCHMARK_COUNT(sidcountexternalatomcomps,1); assert(!factory.xidb.empty() && "the guess and check model generator is not required for " "non-idb components! (use plain)"); } // assign to const member -> stays the same from here no! postprocessedInput = postprocInput; // start evaluate edb+xidb+gidb { DBGLOG(DBG,"evaluating guessing program"); // no mask OrdinaryASPProgram program(reg, factory.xidb, postprocessedInput, factory.ctx.maxint); // append gidb to xidb program.idb.insert(program.idb.end(), factory.gidb.begin(), factory.gidb.end()); ASPSolverManager mgr; guessres = mgr.solve(*factory.externalEvalConfig, program); } }
void DiagRewritingFinalCallback:: operator()() { typedef MinimalNotionCollector::MinimalNotion MinimalNotion; typedef std::list<MinimalNotion>::const_iterator MinimalNotionIterator; std::ostream& o = std::cout; RegistryPtr reg = pcd.reg; if( pcd.isminDiag() ) { // print minimal diagnosis notions for(MinimalNotionIterator it = pcd.mindcollector->getMinimals().begin(); it != pcd.mindcollector->getMinimals().end(); ++it) { if( pcd.isprintOPEQ() ) { for(std::list<InterpretationPtr>::const_iterator itl = it->full.begin(); itl != it->full.end(); ++itl) { o << "Dm:EQ:"; nprinter.print(o, *itl); o << ":"; eqprinter.print(o,*itl); o << std::endl; } } else { o << "Dm:"; nprinter.print(o, it->full.front()); o << std::endl; } } } if( !pcd.isminExp() && !pcd.isExp() ) return; // else do conversion minimal diagnoses -> explanations // (if we need to convert to explanations, we already collected // minimal diagnoses during model enumeration!) std::string prog; { std::stringstream ss; ss << "e1(R) v ne1(R) :- rule(R)." << std::endl; ss << "e2(R) v ne2(R) :- rule(R)." << std::endl; // for every bridge rule we create a predicate rule(br). for(BridgeRuleIterator it = pcd.mcs().rules.begin(); it != pcd.mcs().rules.end(); ++it) { ss << "rule(" << it->Id() << ").\n"; } // for each minimal diagnosis for(MinimalNotionIterator itn = pcd.mindcollector->getMinimals().begin(); itn != pcd.mindcollector->getMinimals().end(); ++itn) { { bool first = true; Interpretation::TrueBitIterator it, it_end; for(boost::tie(it, it_end) = itn->projected1->trueBits(); it != it_end; ++it) { const OrdinaryAtom& a = itn->projected1->getAtomToBit(it); assert(a.tuple.size() == 2); const std::string& ruleid = reg->getTermStringByID(a.tuple[1]); if( first ) first = false; else ss << " v "; ss << "e1(" << ruleid << ")"; } for(boost::tie(it, it_end) = itn->projected2->trueBits(); it != it_end; ++it) { const OrdinaryAtom& a = itn->projected2->getAtomToBit(it); assert(a.tuple.size() == 2); const std::string& ruleid = reg->getTermStringByID(a.tuple[1]); if( first ) first = false; else ss << " v "; ss << "e2(" << ruleid << ")"; } if( first ) { // empty diagnosis -> system is consistent -> make this program inconsistent ss << "true. :- true.\n"; } else { ss << ".\n"; } } } prog = ss.str(); } DBGLOG(DBG,"conversion from diagnoses to explanations uses program:\n" << prog); InputProviderPtr inp(new InputProvider()); inp->addStringInput(prog,"mcsie_conv_diag_expl"); ASPSolverManager mgr; ASPSolverManager::ResultsPtr results = mgr.solve(*software, *inp, reg); // prepare notion printer for explanations NotionPrinter eprinter(pcd, pcd.ide1, pcd.ide2, pcd.bremask); // retrieve all answer sets // and feed them into minimal diagnosis notion collector (unused so far in --iemode=expl) AnswerSetPtr as = results->getNextAnswerSet(); while( !!as ) { DBGLOG(DBG,"Dm->Em converter got answer set " << *as->interpretation); if( pcd.isExp() ) { o << "E:"; eprinter.print(o, as->interpretation); o << std::endl; } if( pcd.isminExp() ) { pcd.minecollector->record(as->interpretation); } as = results->getNextAnswerSet(); } if( pcd.isminExp() ) { // get minimal notions and print them for(std::list<MinimalNotion>::const_iterator it = pcd.minecollector->getMinimals().begin(); it != pcd.minecollector->getMinimals().end(); ++it) { assert(it->full.size() == 1 && "should only have one answer set for converted notions"); o << "Em:"; eprinter.print(o, it->full.front()); o << std::endl; } } }
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 }
void ExplRewritingFinalCallback:: operator()() { typedef MinimalNotionCollector::MinimalNotion MinimalNotion; typedef std::list<MinimalNotion>::const_iterator MinimalNotionIterator; std::ostream& o = std::cout; RegistryPtr reg = pcd.reg; if( pcd.isminExp() ) { // print minimal explanation notions for(MinimalNotionIterator it = pcd.minecollector->getMinimals().begin(); it != pcd.minecollector->getMinimals().end(); ++it) { o << "Em:"; nprinter.print(o, it->full.front()); o << std::endl; } } assert(!pcd.isDiag() && "convertion from explanation to diagnosis not possible!"); if( !pcd.isminDiag() ) return; // else do conversion minimal explanations -> minimal diagnoses // (if we need to convert to diagnoses, we already collected // minimal explanations during model enumeration!) std::string prog; { std::stringstream ss; ss << "d1(R) v nd1(R) :- rule(R)." << std::endl; ss << "d2(R) v nd2(R) :- rule(R)." << std::endl; ss << ":- d1(R), d2(R)." << std::endl; // this is not necessary, but not wrong either // (we only use the subset-minimal result of this, which never contains d1 and d2 for a rule) // for every bridge rule we create a predicate rule(br). for(BridgeRuleIterator it = pcd.mcs().rules.begin(); it != pcd.mcs().rules.end(); ++it) { ss << "rule(" << it->Id() << ").\n"; } // for each minimal explanation for(MinimalNotionIterator itn = pcd.minecollector->getMinimals().begin(); itn != pcd.minecollector->getMinimals().end(); ++itn) { { bool first = true; Interpretation::TrueBitIterator it, it_end; for(boost::tie(it, it_end) = itn->projected1->trueBits(); it != it_end; ++it) { const OrdinaryAtom& a = itn->projected1->getAtomToBit(it); assert(a.tuple.size() == 2); const std::string& ruleid = reg->getTermStringByID(a.tuple[1]); if( first ) first = false; else ss << " v "; ss << "d1(" << ruleid << ")"; } for(boost::tie(it, it_end) = itn->projected2->trueBits(); it != it_end; ++it) { const OrdinaryAtom& a = itn->projected2->getAtomToBit(it); assert(a.tuple.size() == 2); const std::string& ruleid = reg->getTermStringByID(a.tuple[1]); if( first ) first = false; else ss << " v "; ss << "d2(" << ruleid << ")"; } if( !first ) { // nonempty explanation -> finish disjunction ss << ".\n"; } } } prog = ss.str(); } DBGLOG(DBG,"conversion from explanations to diagnoses uses program:\n" << prog); InputProviderPtr inp(new InputProvider()); inp->addStringInput(prog,"mcsie_conv_expl_diag"); ASPSolverManager mgr; ASPSolverManager::ResultsPtr results = mgr.solve(*software, *inp, reg); // retrieve all answer sets // and feed them into minimal diagnosis notion collector (unused so far in --iemode=expl) AnswerSetPtr as = results->getNextAnswerSet(); while( !!as ) { DBGLOG(DBG,"Em->Dm converter got answer set " << *as->interpretation); pcd.mindcollector->record(as->interpretation); as = results->getNextAnswerSet(); } // get minimal notions and print them NotionPrinter dmprinter(pcd, pcd.idd1, pcd.idd2, pcd.brdmask); for(std::list<MinimalNotion>::const_iterator it = pcd.mindcollector->getMinimals().begin(); it != pcd.mindcollector->getMinimals().end(); ++it) { assert(!pcd.isprintOPEQ() && "cannot print output projected equilibria when converting explanations to diagnoses"); assert(it->full.size() == 1 && "should only have one answer set for converted notions"); o << "Dm:"; dmprinter.print(o, it->full.front()); o << std::endl; } }
PlainModelGenerator::InterpretationPtr PlainModelGenerator::generateNextModel() { RegistryPtr reg = factory.ctx.registry(); if( currentResults == 0 ) { do // breakout possibility { // we need to create currentResults // create new interpretation as copy Interpretation::Ptr newint; if( input == 0 ) { // empty construction newint.reset(new Interpretation(reg)); } else { // copy construction newint.reset(new Interpretation(*input)); } // augment input with edb newint->add(*factory.ctx.edb); // remember facts so far (we have to remove these from any output) InterpretationConstPtr mask(new Interpretation(*newint)); // manage outer external atoms if( !factory.eatoms.empty() ) { // augment input with result of external atom evaluation // use newint as input and as output interpretation IntegrateExternalAnswerIntoInterpretationCB cb(newint); evaluateExternalAtoms(factory.ctx, factory.eatoms, newint, cb); DLVHEX_BENCHMARK_REGISTER(sidcountexternalanswersets, "outer eatom computations"); DLVHEX_BENCHMARK_COUNT(sidcountexternalanswersets,1); if( factory.xidb.empty() ) { // we only have eatoms -> return singular result // remove EDB and direct input from newint // (keep local models as small as possible) newint->getStorage() -= mask->getStorage(); PreparedResults* pr = new PreparedResults; currentResults.reset(pr); pr->add(AnswerSetPtr(new AnswerSet(newint))); break; } } // store in model generator and store as const postprocessedInput = newint; DLVHEX_BENCHMARK_REGISTER_AND_START(sidaspsolve, "initiating external solver"); OrdinaryASPProgram program(reg, factory.xidb, postprocessedInput, factory.ctx.maxint, mask); ASPSolverManager mgr; currentResults = mgr.solve(*factory.externalEvalConfig, program); DLVHEX_BENCHMARK_STOP(sidaspsolve); } while(false); // end of breakout possibility } assert(currentResults != 0); AnswerSet::Ptr ret = currentResults->getNextAnswerSet(); if( ret == 0 ) { currentResults.reset(); // the following is just for freeing memory early postprocessedInput.reset(); return InterpretationPtr(); } DLVHEX_BENCHMARK_REGISTER(sidcountplainanswersets, "PlainMG answer sets"); DLVHEX_BENCHMARK_COUNT(sidcountplainanswersets,1); return ret->interpretation; }