dlvhex  2.5.0
include/dlvhex2/FLPModelGeneratorBase.tcc
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 
00035 #ifndef DLVHEX_FLPMODELGENERATORBASE_TCC_INCLUDED
00036 #define DLVHEX_FLPMODELGENERATORBASE_TCC_INCLUDED
00037 
00038 #ifdef HAVE_CONFIG_H
00039 #include "config.h"
00040 #endif                           // HAVE_CONFIG_H
00041 
00042 #include "dlvhex2/FLPModelGeneratorBase.h"
00043 #include "dlvhex2/Printer.h"
00044 #include "dlvhex2/Nogood.h"
00045 #include "dlvhex2/Benchmarking.h"
00046 
00047 #include <fstream>
00048 
00049 DLVHEX_NAMESPACE_BEGIN
00050 
00051 namespace
00052 {
00053 
00054     // this is the naive external solver without nogoods
00055     template<typename AnyOrdinaryASPSolverT>
00056         struct ExternalSolverHelper
00057     {
00058         static NogoodContainerPtr getNogoodContainer(
00059             boost::shared_ptr<AnyOrdinaryASPSolverT> solverPtr)
00060             { return NogoodContainerPtr(); }
00061 
00062         static int addNogood(
00063             boost::shared_ptr<AnyOrdinaryASPSolverT> solverPtr, Nogood ng)
00064             { throw std::runtime_error("nogoods not supported with this solver!"); }
00065     };
00066 
00067     // this is GenuineSolver from which we know it supports nogoods
00068     // (create specializations for further nogood-capable external solvers)
00069     template<>
00070         struct ExternalSolverHelper<GenuineSolver>
00071     {
00072         static NogoodContainerPtr getNogoodContainer(
00073             boost::shared_ptr<GenuineSolver> solverPtr)
00074             { return solverPtr; }
00075         static void addNogood(
00076             boost::shared_ptr<GenuineSolver> solverPtr, Nogood ng)
00077             { solverPtr->addNogood(ng); }
00078     };
00079 
00080 }
00081 
00082 
00083 template<typename OrdinaryASPSolverT>
00084 bool FLPModelGeneratorBase::isSubsetMinimalFLPModel(
00085 InterpretationConstPtr compatibleSet,
00086 InterpretationConstPtr postprocessedInput,
00087 ProgramCtx& ctx,
00088 SimpleNogoodContainerPtr ngc)
00089 {
00090     DLVHEX_BENCHMARK_REGISTER_AND_SCOPE_TPL(sidflpcheck, "Explicit FLP Check");
00091 
00092     typedef boost::shared_ptr<OrdinaryASPSolverT> OrdinaryASPSolverTPtr;
00093 
00094     RegistryPtr& reg = factory.reg;
00095     std::vector<ID>& innerEatoms = factory.innerEatoms;
00096     PredicateMask& gpMask = factory.gpMask;
00097     PredicateMask& gnMask = factory.gnMask;
00098     PredicateMask& fMask = factory.fMask;
00099     std::vector<ID>& xidbflphead = factory.xidbflphead;
00100     std::vector<ID>& xidbflpbody = factory.xidbflpbody;
00101     std::vector<ID>& gidb = factory.gidb;
00102 
00103     /*
00104      * FLP check:
00105      * Check if the flp reduct of the program has a model which is a proper subset of modelCandidate
00106      *
00107      * This check is done as follows:
00108      * 1. evaluate edb + xidbflphead + M
00109      *    -> yields singleton answer set containing flp heads F for non-blocked rules
00110      * 2. evaluate edb + xidbflpbody + gidb + F
00111      *    -> yields candidate compatible models Cand[1], ..., Cand[n] of the reduct
00112      * 3. check each Cand[i] for compatibility (just as the check above for modelCandidate)
00113      *    -> yields compatible reduct models Comp[1], ...,, Comp[m], m <= n
00114      * 4. for all i: project modelCandidate and Comp[i] to ordinary atoms (remove flp and replacement atoms)
00115      * 5. if for some i, projected Comp[i] is a proper subset of projected modelCandidate, modelCandidate is rejected,
00116      *    otherwise it is a subset-minimal model of the flp reduct
00117      */
00118     InterpretationPtr flpas;
00119     {
00120         DBGLOG(DBG,"evaluating flp head program");
00121 
00122         // here we can mask, we won't lose FLP heads
00123         OrdinaryASPProgram flpheadprogram(reg, xidbflphead, compatibleSet, ctx.maxint);
00124         OrdinaryASPSolverTPtr flpheadsolver = OrdinaryASPSolverT::getInstance(ctx, flpheadprogram);
00125 
00126         flpas = flpheadsolver->getNextModel();
00127         if( flpas == InterpretationPtr() ) {
00128             DBGLOG(DBG, "FLP head program yielded no answer set");
00129             assert(false);
00130         }
00131         else {
00132             DBGLOG(DBG, "FLP head program yielded at least one answer set");
00133         }
00134     }
00135     DBGLOG(DBG,"got FLP head model " << *flpas);
00136 
00137     // evaluate xidbflpbody+gidb+edb+flp
00138     std::stringstream ss;
00139     RawPrinter printer(ss, ctx.registry());
00140     int flpm = 0;
00141     {
00142         DBGLOG(DBG, "evaluating flp body program");
00143 
00144         // build edb+flp
00145         Interpretation::Ptr reductEDB(new Interpretation(reg));
00146         fMask.updateMask();
00147         reductEDB->getStorage() |= flpas->getStorage() & fMask.mask()->getStorage();
00148         reductEDB->add(*postprocessedInput);
00149 
00150         std::vector<ID> simulatedReduct = xidbflpbody;
00151         // add guessing program to flpbody program
00152         BOOST_FOREACH (ID rid, gidb) {
00153             simulatedReduct.push_back(rid);
00154         }
00155 
00156         static const bool encodeMinimalityCheckIntoReduct = true;
00157 
00158         std::map<ID, std::pair<int, ID> > shadowPredicates, unfoundedPredicates;
00159         // predicate postfix for shadow and unfounded predicates
00160         std::string shadowpostfix, unfoundedpostfix;
00161         computeShadowAndUnfoundedPredicates(reg, postprocessedInput, simulatedReduct, shadowPredicates, unfoundedPredicates, shadowpostfix, unfoundedpostfix);
00162         Interpretation::Ptr shadowInterpretation(new Interpretation(reg));
00163         addShadowInterpretation(reg, shadowPredicates, compatibleSet, shadowInterpretation);
00164         if (encodeMinimalityCheckIntoReduct) {
00165             // add minimality rules to flpbody program
00166             createMinimalityRules(reg, shadowPredicates, shadowpostfix, simulatedReduct);
00167         }
00168         createFoundingRules(reg, shadowPredicates, unfoundedPredicates, simulatedReduct);
00169                                  // make the FLP check know the compatible set in order to search for subsets
00170         reductEDB->add(*shadowInterpretation);
00171         if (postprocessedInput) {
00172                                  // facts are always in the reduct
00173             reductEDB->add(*postprocessedInput);
00174         }
00175 
00176         ss << "simulatedReduct: IDB={";
00177         printer.printmany(simulatedReduct, "\n");
00178         ss << "}\nEDB=" << *reductEDB;
00179         LOG(DBG, "Evaluating simulated reduct: " << ss.str());
00180 
00181         OrdinaryASPProgram flpbodyprogram(reg, simulatedReduct, reductEDB, ctx.maxint);
00182         OrdinaryASPSolverTPtr flpbodysolver = OrdinaryASPSolverT::getInstance(ctx, flpbodyprogram);
00183 
00184         // transfer learned nogoods to new solver
00185         if (ngc != NogoodContainerPtr()) {
00186             for (int i = 0; i < ngc->getNogoodCount(); ++i) {
00187                 if (ngc->getNogood(i).isGround()) {
00188                     ExternalSolverHelper<OrdinaryASPSolverT>::addNogood(flpbodysolver, ngc->getNogood(i));
00189                 }
00190             }
00191         }
00192 
00193         DLVHEX_BENCHMARK_REGISTER(sidflpenum, "FLP-Reduct Solving");
00194         DLVHEX_BENCHMARK_START(sidflpenum);
00195         InterpretationPtr flpbodyas = flpbodysolver->getNextModel();
00196         DLVHEX_BENCHMARK_STOP(sidflpenum);
00197         DLVHEX_BENCHMARK_REGISTER(flpcandidates, "Checked FLP reduct models");
00198         while(flpbodyas != InterpretationPtr()) {
00199             DLVHEX_BENCHMARK_COUNT(flpcandidates,1);
00200 
00201             // compatibility check
00202             DBGLOG(DBG, "doing compatibility check for reduct model candidate " << *flpbodyas);
00203             NogoodContainerPtr bodySolverNogoods =
00204                 ExternalSolverHelper<OrdinaryASPSolverT>::getNogoodContainer(flpbodysolver);
00205             bool compatible;
00206             int ngCount = ngc ? ngc->getNogoodCount() : 0;
00207             compatible = isCompatibleSet(flpbodyas, postprocessedInput, ctx, ngc);
00208             if (ngc) {
00209                 for (int i = ngCount; i < ngc->getNogoodCount(); ++i) {
00210                     if (ngc->getNogood(i).isGround()) {
00211                         bodySolverNogoods->addNogood(ngc->getNogood(i));
00212                     }
00213                 }
00214             }
00215             DBGLOG(DBG, "Compatibility: " << compatible);
00216 
00217             // remove input and shadow input (because it not contained in modelCandidate neither)
00218             flpbodyas->getStorage() -= postprocessedInput->getStorage();
00219             DBGLOG(DBG, "Removed input facts: " << *flpbodyas);
00220 
00221             if (compatible) {
00222                 // check if the reduct model is smaller than modelCandidate
00223                 if (encodeMinimalityCheckIntoReduct) {
00224                     // reduct model is a proper subset (this was already ensured by the program encoding)
00225                     DBGLOG(DBG, "Model candidate " << *compatibleSet << " failed FLP check");
00226                     DBGLOG(DBG, "Enumerated " << flpm << " FLP models");
00227                     /*
00228                               {
00229                                 InterpretationPtr candidate(new Interpretation(*compatibleSet));
00230                                 candidate->getStorage() -= gpMask.mask()->getStorage();
00231                                 candidate->getStorage() -= gnMask.mask()->getStorage();
00232                                 candidate->getStorage() -= postprocessedInput->getStorage();
00233 
00234                                 flpbodyas->getStorage() -= gpMask.mask()->getStorage();
00235                                 flpbodyas->getStorage() -= gnMask.mask()->getStorage();
00236                                 flpbodyas->getStorage() -= fMask.mask()->getStorage();
00237 
00238                                 constructFLPNogood(ctx, groundProgram, compatibleSet, candidate, flpbodyas);
00239                               }
00240                     */
00241                     DLVHEX_BENCHMARK_REGISTER_AND_COUNT(sidfailedflpchecks, "Failed FLP Checks", 1);
00242                     return false;
00243                 }
00244                 else {
00245                     // project both the model candidate and the reduct model to ordinary atoms
00246                     InterpretationPtr candidate(new Interpretation(*compatibleSet));
00247                     candidate->getStorage() -= gpMask.mask()->getStorage();
00248                     candidate->getStorage() -= gnMask.mask()->getStorage();
00249                     candidate->getStorage() -= postprocessedInput->getStorage();
00250 
00251                     flpbodyas->getStorage() -= gpMask.mask()->getStorage();
00252                     flpbodyas->getStorage() -= gnMask.mask()->getStorage();
00253                     flpbodyas->getStorage() -= fMask.mask()->getStorage();
00254 
00255                     DBGLOG(DBG, "Checking if reduct model " << *flpbodyas << " is a subset of model candidate " << *candidate);
00256 
00257                                  // subset property
00258                     if ((candidate->getStorage() & flpbodyas->getStorage()).count() == flpbodyas->getStorage().count() &&
00259                                  // proper subset property
00260                     candidate->getStorage().count() > flpbodyas->getStorage().count()) {
00261                         // found a smaller model of the reduct
00262                         flpm++;
00263                         DBGLOG(DBG, "Model candidate " << *candidate << " failed FLP check");
00264                         DBGLOG(DBG, "Enumerated " << flpm << " FLP models");
00265 
00266                         DLVHEX_BENCHMARK_REGISTER_AND_COUNT(sidfailedflpchecks, "Failed FLP Checks", 1);
00267                         return false;
00268                     }
00269                     else {
00270                         DBGLOG(DBG, "Reduct model is no proper subset");
00271                         flpm++;
00272                     }
00273                 }
00274             }
00275 
00276             DBGLOG(DBG, "Go to next model of reduct");
00277             DLVHEX_BENCHMARK_START(sidflpenum);
00278             flpbodyas = flpbodysolver->getNextModel();
00279             DLVHEX_BENCHMARK_STOP(sidflpenum);
00280         }
00281     }
00282 
00283     DBGLOG(DBG, "Model candidate " << *compatibleSet << " passed FLP check");
00284     DBGLOG(DBG, "Enumerated " << flpm << " FLP models");
00285 
00286     return true;
00287 }
00288 
00289 
00290 DLVHEX_NAMESPACE_END
00291 #endif                           // DLVHEX_FLPMODELGENERATORBASE_TCC_INCLUDED
00292 
00293 
00294 // vim:expandtab:ts=4:sw=4:
00295 // mode: C++
00296 // End: