dlvhex
2.5.0
|
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: