dlvhex  2.5.0
src/WellfoundedModelGenerator.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/WellfoundedModelGenerator.h"
00041 #include "dlvhex2/Logger.h"
00042 #include "dlvhex2/Registry.h"
00043 #include "dlvhex2/Printer.h"
00044 #include "dlvhex2/ASPSolver.h"
00045 #include "dlvhex2/ProgramCtx.h"
00046 #include "dlvhex2/PluginInterface.h"
00047 #include "dlvhex2/Benchmarking.h"
00048 
00049 #include <boost/foreach.hpp>
00050 
00051 DLVHEX_NAMESPACE_BEGIN
00052 
00053 WellfoundedModelGeneratorFactory::WellfoundedModelGeneratorFactory(
00054 ProgramCtx& ctx,
00055 const ComponentInfo& ci,
00056 ASPSolverManager::SoftwareConfigurationPtr externalEvalConfig):
00057 BaseModelGeneratorFactory(),
00058 externalEvalConfig(externalEvalConfig),
00059 ctx(ctx),
00060 outerEatoms(ci.outerEatoms),
00061 innerEatoms(ci.innerEatoms),
00062 idb(),
00063 xidb()
00064 {
00065     RegistryPtr reg = ctx.registry();
00066 
00067     // this model generator can handle:
00068     // components with outer eatoms
00069     // components with inner eatoms
00070     // components with inner rules
00071     // components with inner constraints
00072     // iff all inner eatoms are monotonic and there are no negative dependencies within idb
00073 
00074     // copy rules and constraints to idb
00075     // TODO we do not really need this except for debugging (tiny optimization possibility)
00076     idb.reserve(ci.innerRules.size() + ci.innerConstraints.size());
00077     idb.insert(idb.end(), ci.innerRules.begin(), ci.innerRules.end());
00078     idb.insert(idb.end(), ci.innerConstraints.begin(), ci.innerConstraints.end());
00079 
00080     // transform original innerRules and innerConstraints to xidb with only auxiliaries
00081     xidb.reserve(ci.innerRules.size() + ci.innerConstraints.size());
00082     std::back_insert_iterator<std::vector<ID> > inserter(xidb);
00083     std::transform(ci.innerRules.begin(), ci.innerRules.end(),
00084         inserter, boost::bind(
00085         &WellfoundedModelGeneratorFactory::convertRule, this, ctx, _1));
00086     std::transform(ci.innerConstraints.begin(), ci.innerConstraints.end(),
00087         inserter, boost::bind(
00088         &WellfoundedModelGeneratorFactory::convertRule, this, ctx, _1));
00089 
00090     // this calls print()
00091     DBGLOG(DBG,"WellfoundedModelGeneratorFactory(): " << *this);
00092 }
00093 
00094 
00095 std::ostream& WellfoundedModelGeneratorFactory::print(
00096 std::ostream& o) const
00097 {
00098     RawPrinter printer(o, ctx.registry());
00099     if( !outerEatoms.empty() ) {
00100         o << " outer Eatoms={";
00101         printer.printmany(outerEatoms,"\n");
00102         o << "}";
00103     }
00104     if( !innerEatoms.empty() ) {
00105         o << " inner Eatoms={";
00106         printer.printmany(innerEatoms,"\n");
00107         o << "}";
00108     }
00109     if( !idb.empty() ) {
00110         o << " idb={";
00111         printer.printmany(idb,"\n");
00112         o << "}";
00113     }
00114     if( !xidb.empty() ) {
00115         o << " xidb={";
00116         printer.printmany(xidb,"\n");
00117         o << "}";
00118     }
00119     return o;
00120 }
00121 
00122 
00123 WellfoundedModelGenerator::WellfoundedModelGenerator(
00124 Factory& factory,
00125 InterpretationConstPtr input):
00126 BaseModelGenerator(input),
00127 factory(factory)
00128 {
00129 }
00130 
00131 
00132 WellfoundedModelGenerator::InterpretationPtr
00133 WellfoundedModelGenerator::generateNextModel()
00134 {
00135     RegistryPtr reg = factory.ctx.registry();
00136 
00137     if( currentResults == 0 ) {
00138         // we need to create currentResults
00139 
00140         // create new interpretation as copy
00141         Interpretation::Ptr postprocessedInput;
00142         if( input == 0 ) {
00143             // empty construction
00144             postprocessedInput.reset(new Interpretation(reg));
00145         }
00146         else {
00147             // copy construction
00148             postprocessedInput.reset(new Interpretation(*input));
00149         }
00150 
00151         // augment input with edb
00152         postprocessedInput->add(*factory.ctx.edb);
00153 
00154         // remember which facts we have to remove from each output interpretation
00155         InterpretationConstPtr mask(new Interpretation(*postprocessedInput));
00156 
00157         // manage outer external atoms
00158         if( !factory.outerEatoms.empty() ) {
00159             // augment input with result of external atom evaluation
00160             // use newint as input and as output interpretation
00161             IntegrateExternalAnswerIntoInterpretationCB cb(postprocessedInput);
00162             evaluateExternalAtoms(factory.ctx, factory.outerEatoms, postprocessedInput, cb);
00163             DLVHEX_BENCHMARK_REGISTER(sidcountexternalatomcomps,
00164                 "outer eatom computations");
00165             DLVHEX_BENCHMARK_COUNT(sidcountexternalatomcomps,1);
00166 
00167             assert(!factory.xidb.empty() && "the wellfounded model generator is not required for non-idb components! (use plain)");
00168         }
00169 
00170         // now we have postprocessed input in postprocessedInput
00171         DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidwfsolve, "wellfounded solver loop");
00172 
00173         WARNING("make wellfounded iteration limit configurable")
00174             unsigned limit = 1000;
00175         bool inconsistent = false;
00176 
00177         // we store two interpretations "ints" and
00178         // one "src" integer for the current source interpretation
00179         //
00180         // the loop below uses ints[current] as source and stores into ints[1-current]
00181         // then current = 1 - current
00182         std::vector<InterpretationPtr> ints(2);
00183         unsigned current = 0;
00184         // the following creates a copy! (we need the postprocessedInput later)
00185         ints[0] = InterpretationPtr(new Interpretation(*postprocessedInput));
00186         // the following creates a copy!
00187         ints[1] = InterpretationPtr(new Interpretation(*postprocessedInput));
00188         do {
00189             InterpretationPtr src = ints[current];
00190             InterpretationPtr dst = ints[1-current];
00191             DBGLOG(DBG,"starting loop with source" << *src);
00192             DBGLOG(DBG,"starting loop with dst" << *dst);
00193 
00194             // evaluate inner external atoms
00195             IntegrateExternalAnswerIntoInterpretationCB cb(dst);
00196             evaluateExternalAtoms(factory.ctx, factory.innerEatoms, src, cb);
00197             DBGLOG(DBG,"after evaluateExternalAtoms: dst is " << *dst);
00198 
00199             // solve program
00200             {
00201                 // we don't use a mask here!
00202                 // -> we receive all facts
00203                 OrdinaryASPProgram program(reg,
00204                     factory.xidb, dst, factory.ctx.maxint);
00205                 ASPSolverManager mgr;
00206                 ASPSolverManager::ResultsPtr thisres =
00207                     mgr.solve(*factory.externalEvalConfig, program);
00208 
00209                 // get answer sets
00210                 AnswerSet::Ptr thisret1 = thisres->getNextAnswerSet();
00211                 if( !thisret1 ) {
00212                     LOG(DBG,"got no answer set -> inconsistent");
00213                     inconsistent = true;
00214                     break;
00215                 }
00216                 AnswerSet::Ptr thisret2 = thisres->getNextAnswerSet();
00217                 if( thisret2 )
00218                     throw FatalError("got more than one model in Wellfounded model generator -> use other model generator!");
00219 
00220                 // cheap exchange -> thisret1 will then be free'd
00221                 dst->getStorage().swap(thisret1->interpretation->getStorage());
00222                 DBGLOG(DBG,"after evaluating ASP: dst is " << *dst);
00223             }
00224 
00225             // check whether new interpretation is superset of old one
00226             // break if they are equal (i.e., if the fixpoint is reached)
00227             // error if new one is smaller (i.e., fixpoint is not allowed)
00228             // (TODO do this error check, and do it only in debug mode)
00229             int cmpresult = dst->getStorage().compare(src->getStorage());
00230             if( cmpresult == 0 ) {
00231                 DBGLOG(DBG,"reached fixpoint");
00232                 break;
00233             }
00234 
00235             // switch interpretations
00236             current = 1 - current;
00237             limit--;
00238             // loop if limit is not reached
00239         }
00240         while( limit != 0 && !inconsistent );
00241 
00242         if( limit == 0 )
00243             throw FatalError("reached wellfounded limit!");
00244 
00245         if( inconsistent ) {
00246             DBGLOG(DBG,"leaving loop with result 'inconsistent'");
00247             currentResults.reset(new PreparedResults);
00248         }
00249         else {
00250             // does not matter which one we take, they are equal
00251             InterpretationPtr result = ints[0];
00252             DBGLOG(DBG,"leaving loop with result " << *result);
00253 
00254             // remove mask from result!
00255             result->getStorage() -= mask->getStorage();
00256             DBGLOG(DBG,"after removing input facts: result is " << *result);
00257 
00258             // store as single answer set (there can only be one)
00259             PreparedResults* pr = new PreparedResults;
00260             currentResults.reset(pr);
00261             pr->add(AnswerSetPtr(new AnswerSet(result)));
00262         }
00263     }
00264 
00265     assert(currentResults != 0);
00266     AnswerSet::Ptr ret = currentResults->getNextAnswerSet();
00267     if( ret == 0 ) {
00268         currentResults.reset();
00269         return InterpretationPtr();
00270     }
00271     DLVHEX_BENCHMARK_REGISTER(sidcountwfanswersets,
00272         "WellFoundedMG answer sets");
00273     DLVHEX_BENCHMARK_COUNT(sidcountwfanswersets,1);
00274 
00275     return ret->interpretation;
00276 }
00277 
00278 
00279 DLVHEX_NAMESPACE_END
00280 
00281 // vim:expandtab:ts=4:sw=4:
00282 // mode: C++
00283 // End: