dlvhex  2.5.0
src/GuessAndCheckModelGenerator.cpp
Go to the documentation of this file.
00001 /* dlvhex -- Answer-Set Programming with external interfaces.
00002  * Copyright (C) 2005-2007 Roman Schindlauer
00003  * Copyright (C) 2006-2015 Thomas Krennwallner
00004  * Copyright (C) 2009-2016 Peter Schüller
00005  * Copyright (C) 2011-2016 Christoph Redl
00006  * Copyright (C) 2015-2016 Tobias Kaminski
00007  * Copyright (C) 2015-2016 Antonius Weinzierl
00008  *
00009  * This file is part of dlvhex.
00010  *
00011  * dlvhex is free software; you can redistribute it and/or modify it
00012  * under the terms of the GNU Lesser General Public License as
00013  * published by the Free Software Foundation; either version 2.1 of
00014  * the License, or (at your option) any later version.
00015  *
00016  * dlvhex is distributed in the hope that it will be useful, but
00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with dlvhex; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00024  * 02110-1301 USA.
00025  */
00026 
00034 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif                           // HAVE_CONFIG_H
00037 
00038 #define DLVHEX_BENCHMARK
00039 
00040 #include "dlvhex2/GuessAndCheckModelGenerator.h"
00041 #include "dlvhex2/Logger.h"
00042 #include "dlvhex2/Registry.h"
00043 #include "dlvhex2/Printer.h"
00044 #include "dlvhex2/OrdinaryASPProgram.h"
00045 #include "dlvhex2/OrdinaryASPSolver.h"
00046 #include "dlvhex2/ASPSolver.h"
00047 #include "dlvhex2/ASPSolverManager.h"
00048 #include "dlvhex2/ProgramCtx.h"
00049 #include "dlvhex2/PluginInterface.h"
00050 #include "dlvhex2/Benchmarking.h"
00051 
00052 #include <bm/bmalgo.h>
00053 
00054 #include <boost/foreach.hpp>
00055 
00056 DLVHEX_NAMESPACE_BEGIN
00057 
00095 namespace
00096 {
00097 
00098     class ASMOrdinaryASPSolver;
00099     typedef boost::shared_ptr<ASMOrdinaryASPSolver>
00100         ASMOrdinaryASPSolverPtr;
00101 
00102     class ASMOrdinaryASPSolver:
00103     public OrdinaryASPSolver
00104     {
00105         protected:
00106             ASPSolverManager::ResultsPtr results;
00107             InterpretationConstPtr mask;
00108 
00109             ASMOrdinaryASPSolver(ProgramCtx& ctx, OrdinaryASPProgram& program):
00110             mask(program.mask) {
00111                 ASPSolverManager mgr;
00112                 results = mgr.solve(*ctx.aspsoftware, program);
00113             }
00114 
00115         public:
00116             static ASMOrdinaryASPSolverPtr getInstance(ProgramCtx& ctx, OrdinaryASPProgram& program) {
00117                 return ASMOrdinaryASPSolverPtr(new ASMOrdinaryASPSolver(ctx, program));
00118             }
00119 
00120             // get next model
00121             virtual InterpretationPtr getNextModel() {
00122                 AnswerSetPtr as = results->getNextAnswerSet();
00123                 if( !!as ) {
00124                     InterpretationPtr answer = InterpretationPtr(new Interpretation(*(as->interpretation)));
00125                     if (mask != InterpretationConstPtr()) {
00126                         answer->getStorage() -= mask->getStorage();
00127                     }
00128                     return answer;
00129                 }
00130                 else {
00131                     return InterpretationPtr();
00132                 }
00133             }
00134     };
00135 
00136 }
00137 
00138 
00139 //
00140 // the factory
00141 //
00142 
00143 WARNING("ASPSolverManager::SoftwareConfigurationPtr externalEvalConfig is already stored in ProgramCtx ... reuse it and remove parameters?")
00144 GuessAndCheckModelGeneratorFactory::GuessAndCheckModelGeneratorFactory(
00145 ProgramCtx& ctx,
00146 const ComponentInfo& ci,
00147 ASPSolverManager::SoftwareConfigurationPtr externalEvalConfig):
00148 FLPModelGeneratorFactoryBase(ctx),
00149 externalEvalConfig(externalEvalConfig),
00150 ctx(ctx),
00151 ci(ci),
00152 outerEatoms(ci.outerEatoms)
00153 {
00154     // this model generator can handle any components
00155     // (and there is quite some room for more optimization)
00156 
00157     // just copy all rules and constraints to idb
00158     idb.reserve(ci.innerRules.size() + ci.innerConstraints.size());
00159     idb.insert(idb.end(), ci.innerRules.begin(), ci.innerRules.end());
00160     idb.insert(idb.end(), ci.innerConstraints.begin(), ci.innerConstraints.end());
00161 
00162     innerEatoms = ci.innerEatoms;
00163     // create guessing rules "gidb" for innerEatoms in all inner rules and constraints
00164     createEatomGuessingRules(ctx);
00165     // transform original innerRules and innerConstraints to xidb with only auxiliaries
00166     xidb.reserve(ci.innerRules.size() + ci.innerConstraints.size());
00167     std::back_insert_iterator<std::vector<ID> > inserter(xidb);
00168     std::transform(ci.innerRules.begin(), ci.innerRules.end(),
00169         inserter, boost::bind(&GuessAndCheckModelGeneratorFactory::convertRule, this, ctx, _1));
00170     std::transform(ci.innerConstraints.begin(), ci.innerConstraints.end(),
00171         inserter, boost::bind(&GuessAndCheckModelGeneratorFactory::convertRule, this, ctx, _1));
00172 
00173     // transform xidb for flp calculation
00174     if (ctx.config.getOption("FLPCheck")) createFLPRules();
00175 
00176     // output rules
00177     {
00178         std::ostringstream s;
00179         print(s, true);
00180         LOG(DBG,"GuessAndCheckModelGeneratorFactory(): " << s.str());
00181     }
00182 }
00183 
00184 
00185 GuessAndCheckModelGeneratorFactory::ModelGeneratorPtr
00186 GuessAndCheckModelGeneratorFactory::createModelGenerator(InterpretationConstPtr input)
00187 {
00188     return ModelGeneratorPtr(new GuessAndCheckModelGenerator(*this, input));
00189 }
00190 
00191 
00192 std::ostream& GuessAndCheckModelGeneratorFactory::print(
00193 std::ostream& o) const
00194 {
00195     return print(o, false);
00196 }
00197 
00198 
00199 std::ostream& GuessAndCheckModelGeneratorFactory::print(
00200 std::ostream& o, bool verbose) const
00201 {
00202     // item separator
00203     std::string isep("\n");
00204     // group separator
00205     std::string gsep("\n");
00206     if( verbose ) {
00207         isep = "\n";
00208         gsep = "\n";
00209     }
00210     RawPrinter printer(o, ctx.registry());
00211     if( !outerEatoms.empty() ) {
00212         o << "outer Eatoms={" << gsep;
00213         printer.printmany(outerEatoms,isep);
00214         o << gsep << "}" << gsep;
00215     }
00216     if( !innerEatoms.empty() ) {
00217         o << "inner Eatoms={" << gsep;
00218         printer.printmany(innerEatoms,isep);
00219         o << gsep << "}" << gsep;
00220     }
00221     if( !gidb.empty() ) {
00222         o << "gidb={" << gsep;
00223         printer.printmany(gidb,isep);
00224         o << gsep << "}" << gsep;
00225     }
00226     if( !idb.empty() ) {
00227         o << "idb={" << gsep;
00228         printer.printmany(idb,isep);
00229         o << gsep << "}" << gsep;
00230     }
00231     if( !xidb.empty() ) {
00232         o << "xidb={" << gsep;
00233         printer.printmany(xidb,isep);
00234         o << gsep << "}" << gsep;
00235     }
00236     if( !xidbflphead.empty() ) {
00237         o << "xidbflphead={" << gsep;
00238         printer.printmany(xidbflphead,isep);
00239         o << gsep << "}" << gsep;
00240     }
00241     if( !xidbflpbody.empty() ) {
00242         o << "xidbflpbody={" << gsep;
00243         printer.printmany(xidbflpbody,isep);
00244         o << gsep << "}" << gsep;
00245     }
00246     return o;
00247 }
00248 
00249 
00250 //
00251 // the model generator
00252 //
00253 
00254 GuessAndCheckModelGenerator::GuessAndCheckModelGenerator(
00255 Factory& factory,
00256 InterpretationConstPtr input):
00257 FLPModelGeneratorBase(factory, input),
00258 factory(factory)
00259 {
00260     DBGLOG(DBG, "GnC-ModelGenerator is instantiated for a " << (factory.ci.disjunctiveHeads ? "" : "non-") << "disjunctive component");
00261 
00262     RegistryPtr reg = factory.reg;
00263 
00264     // create new interpretation as copy
00265     InterpretationPtr postprocInput;
00266     if( input == 0 ) {
00267         // empty construction
00268         postprocInput.reset(new Interpretation(reg));
00269     }
00270     else {
00271         // copy construction
00272         postprocInput.reset(new Interpretation(*input));
00273     }
00274 
00275     // augment input with edb
00276     WARNING("perhaps we can pass multiple partially preprocessed input edb's to the external solver and save a lot of processing here")
00277         postprocInput->add(*factory.ctx.edb);
00278 
00279     // remember which facts we must remove
00280     mask.reset(new Interpretation(*postprocInput));
00281 
00282     // manage outer external atoms
00283     if( !factory.outerEatoms.empty() ) {
00284         // augment input with result of external atom evaluation
00285         // use newint as input and as output interpretation
00286         IntegrateExternalAnswerIntoInterpretationCB cb(postprocInput);
00287         evaluateExternalAtoms(factory.ctx,
00288             factory.outerEatoms, postprocInput, cb);
00289         DLVHEX_BENCHMARK_REGISTER(sidcountexternalatomcomps,
00290             "outer eatom computations");
00291         DLVHEX_BENCHMARK_COUNT(sidcountexternalatomcomps,1);
00292 
00293         assert(!factory.xidb.empty() &&
00294             "the guess and check model generator is not required for "
00295             "non-idb components! (use plain)");
00296     }
00297 
00298     // assign to const member -> stays the same from here no!
00299     postprocessedInput = postprocInput;
00300 
00301     // start evaluate edb+xidb+gidb
00302     {
00303         DBGLOG(DBG,"evaluating guessing program");
00304         // no mask
00305         OrdinaryASPProgram program(reg, factory.xidb, postprocessedInput, factory.ctx.maxint);
00306         // append gidb to xidb
00307         program.idb.insert(program.idb.end(), factory.gidb.begin(), factory.gidb.end());
00308         ASPSolverManager mgr;
00309         guessres = mgr.solve(*factory.externalEvalConfig, program);
00310     }
00311 }
00312 
00313 
00314 InterpretationPtr GuessAndCheckModelGenerator::generateNextModel()
00315 {
00316     RegistryPtr reg = factory.reg;
00317 
00318     // now we have postprocessed input in postprocessedInput
00319     DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidgcsolve, "guess and check loop");
00320 
00321     InterpretationPtr modelCandidate;
00322     do {
00323         AnswerSetPtr guessas = guessres->getNextAnswerSet();
00324         if( !guessas )
00325             return InterpretationPtr();
00326         modelCandidate = guessas->interpretation;
00327 
00328         DBGLOG_SCOPE(DBG,"gM", false);
00329         DBGLOG(DBG,"= got guess model " << *modelCandidate);
00330 
00331         DBGLOG(DBG, "doing compatibility check for model candidate " << *modelCandidate);
00332         assert(!factory.ctx.config.getOption("ExternalLearning") &&
00333             "cannot use external learning in (non-genuine) GuessAndCheckModelGenerator");
00334         bool compatible = isCompatibleSet(
00335             modelCandidate, postprocessedInput, factory.ctx,
00336             SimpleNogoodContainerPtr());
00337         DBGLOG(DBG, "Compatible: " << compatible);
00338         if (!compatible) continue;
00339 
00340         // FLP check
00341         if (factory.ctx.config.getOption("FLPCheck")) {
00342             DBGLOG(DBG, "FLP Check");
00343             if( !isSubsetMinimalFLPModel<ASMOrdinaryASPSolver>(
00344                 modelCandidate, postprocessedInput, factory.ctx) )
00345                 continue;
00346         }
00347         else {
00348             DBGLOG(DBG, "Skipping FLP Check");
00349         }
00350 
00351         // remove edb and the guess (from here we don't need the guess anymore)
00352         modelCandidate->getStorage() -= factory.gpMask.mask()->getStorage();
00353         modelCandidate->getStorage() -= factory.gnMask.mask()->getStorage();
00354 
00355         modelCandidate->getStorage() -= mask->getStorage();
00356 
00357         DBGLOG(DBG,"= final model candidate " << *modelCandidate);
00358         return modelCandidate;
00359     }
00360     while(true);
00361 }
00362 
00363 
00364 DLVHEX_NAMESPACE_END
00365 
00366 
00367 // vim:expandtab:ts=4:sw=4:
00368 // mode: C++
00369 // End: