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;
    }
  }
}
예제 #3
0
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;
}