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 00034 #define DLVHEX_BENCHMARK 00035 00036 #include "dlvhex2/GenuineWellfoundedModelGenerator.h" 00037 #include "dlvhex2/Logger.h" 00038 #include "dlvhex2/Registry.h" 00039 #include "dlvhex2/Printer.h" 00040 #include "dlvhex2/ASPSolver.h" 00041 #include "dlvhex2/ProgramCtx.h" 00042 #include "dlvhex2/PluginInterface.h" 00043 #include "dlvhex2/Benchmarking.h" 00044 #include "dlvhex2/GenuineSolver.h" 00045 00046 #include <boost/foreach.hpp> 00047 00048 DLVHEX_NAMESPACE_BEGIN 00049 00050 GenuineWellfoundedModelGeneratorFactory::GenuineWellfoundedModelGeneratorFactory( 00051 ProgramCtx& ctx, 00052 const ComponentInfo& ci, 00053 ASPSolverManager::SoftwareConfigurationPtr externalEvalConfig): 00054 BaseModelGeneratorFactory(), 00055 externalEvalConfig(externalEvalConfig), 00056 ctx(ctx), 00057 ci(ci), 00058 outerEatoms(ci.outerEatoms), 00059 innerEatoms(ci.innerEatoms), 00060 idb(), 00061 xidb() 00062 { 00063 RegistryPtr reg = ctx.registry(); 00064 00065 // this model generator can handle: 00066 // components with outer eatoms 00067 // components with inner eatoms 00068 // components with inner rules 00069 // components with inner constraints 00070 // iff all inner eatoms are monotonic and there are no negative dependencies within idb 00071 00072 // copy rules and constraints to idb 00073 // TODO we do not really need this except for debugging (tiny optimization possibility) 00074 idb.reserve(ci.innerRules.size() + ci.innerConstraints.size()); 00075 idb.insert(idb.end(), ci.innerRules.begin(), ci.innerRules.end()); 00076 idb.insert(idb.end(), ci.innerConstraints.begin(), ci.innerConstraints.end()); 00077 00078 // create program for domain exploration 00079 if (ctx.config.getOption("LiberalSafety")) { 00080 // add domain predicates for all external atoms which are necessary to establish liberal domain-expansion safety 00081 // and extract the domain-exploration program from the IDB 00082 addDomainPredicatesAndCreateDomainExplorationProgram(ci, ctx, idb, deidb, deidbInnerEatoms, outerEatoms); 00083 } 00084 00085 // transform original innerRules and innerConstraints to xidb with only auxiliaries 00086 xidb.reserve(idb.size()); 00087 std::back_insert_iterator<std::vector<ID> > inserter(xidb); 00088 std::transform(idb.begin(), idb.end(), 00089 inserter, boost::bind( 00090 &GenuineWellfoundedModelGeneratorFactory::convertRule, this, ctx, _1)); 00091 00092 // this calls print() 00093 DBGLOG(DBG,"GenuineWellfoundedModelGeneratorFactory(): " << *this); 00094 } 00095 00096 00097 std::ostream& GenuineWellfoundedModelGeneratorFactory::print( 00098 std::ostream& o) const 00099 { 00100 RawPrinter printer(o, ctx.registry()); 00101 if( !outerEatoms.empty() ) { 00102 o << " outer Eatoms={"; 00103 printer.printmany(outerEatoms,","); 00104 o << "}"; 00105 } 00106 if( !innerEatoms.empty() ) { 00107 o << " inner Eatoms={"; 00108 printer.printmany(innerEatoms,","); 00109 o << "}"; 00110 } 00111 if( !idb.empty() ) { 00112 o << " idb={"; 00113 printer.printmany(idb,"\n"); 00114 o << "}"; 00115 } 00116 if( !xidb.empty() ) { 00117 o << " xidb={"; 00118 printer.printmany(xidb,"\n"); 00119 o << "}"; 00120 } 00121 return o; 00122 } 00123 00124 00125 GenuineWellfoundedModelGenerator::GenuineWellfoundedModelGenerator( 00126 Factory& factory, 00127 InterpretationConstPtr input): 00128 BaseModelGenerator(input), 00129 factory(factory), firstcall(true) 00130 { 00131 } 00132 00133 00134 GenuineWellfoundedModelGenerator::~GenuineWellfoundedModelGenerator() 00135 { 00136 } 00137 00138 00139 GenuineWellfoundedModelGenerator::InterpretationPtr 00140 GenuineWellfoundedModelGenerator::generateNextModel() 00141 { 00142 RegistryPtr reg = factory.ctx.registry(); 00143 00144 if( !firstcall ) { 00145 return InterpretationPtr(); 00146 } 00147 else { 00148 // we need to create currentResults 00149 firstcall = false; 00150 00151 // create new interpretation as copy 00152 Interpretation::Ptr postprocessedInput; 00153 if( input == 0 ) { 00154 // empty construction 00155 postprocessedInput.reset(new Interpretation(reg)); 00156 } 00157 else { 00158 // copy construction 00159 postprocessedInput.reset(new Interpretation(*input)); 00160 } 00161 00162 // augment input with edb 00163 postprocessedInput->add(*factory.ctx.edb); 00164 00165 // remember which facts we have to remove from each output interpretation 00166 InterpretationConstPtr mask(new Interpretation(*postprocessedInput)); 00167 00168 // manage outer external atoms 00169 if( !factory.outerEatoms.empty() ) { 00170 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidhexground, "HEX grounder time (GenuineWfMG)"); 00171 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidhexground2, "HEX grounder time"); 00172 // augment input with result of external atom evaluation 00173 // use newint as input and as output interpretation 00174 IntegrateExternalAnswerIntoInterpretationCB cb(postprocessedInput); 00175 evaluateExternalAtoms(factory.ctx, factory.outerEatoms, postprocessedInput, cb); 00176 DLVHEX_BENCHMARK_REGISTER(sidcountexternalatomcomps, 00177 "outer eatom computations"); 00178 DLVHEX_BENCHMARK_COUNT(sidcountexternalatomcomps,1); 00179 00180 assert(!factory.xidb.empty() && "the wellfounded model generator is not required for non-idb components! (use plain)"); 00181 } 00182 00183 // compute extensions of domain predicates and add it to the input 00184 if (factory.ctx.config.getOption("LiberalSafety")) { 00185 InterpretationConstPtr domPredictaesExtension = computeExtensionOfDomainPredicates(factory.ci, factory.ctx, postprocessedInput, factory.deidb, factory.deidbInnerEatoms); 00186 postprocessedInput->add(*domPredictaesExtension); 00187 } 00188 00189 // now we have postprocessed input in postprocessedInput 00190 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidwfsolve, "wellfounded solver loop"); 00191 00192 WARNING("make wellfounded iteration limit configurable") 00193 unsigned limit = 1000; 00194 bool inconsistent = false; 00195 00196 // we store two interpretations "ints" and 00197 // one "src" integer for the current source interpretation 00198 // 00199 // the loop below uses ints[current] as source and stores into ints[1-current] 00200 // then current = 1 - current 00201 std::vector<InterpretationPtr> ints(2); 00202 unsigned current = 0; 00203 // the following creates a copy! (we need the postprocessedInput later) 00204 ints[0] = InterpretationPtr(new Interpretation(*postprocessedInput)); 00205 // the following creates a copy! 00206 ints[1] = InterpretationPtr(new Interpretation(*postprocessedInput)); 00207 00208 //for (int k = 0; k < 10; k++){ 00209 do { 00210 InterpretationPtr src = ints[current]; 00211 InterpretationPtr dst = ints[1-current]; 00212 DBGLOG(DBG,"starting loop with source" << *src); 00213 DBGLOG(DBG,"starting loop with dst" << *dst); 00214 00215 // evaluate inner external atoms 00216 IntegrateExternalAnswerIntoInterpretationCB cb(dst); 00217 { 00218 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidhexsolve, "HEX solver time (inner EAs GenuineWfMG)"); 00219 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidhexsolve2, "HEX solver time"); 00220 evaluateExternalAtoms(factory.ctx, factory.innerEatoms, src, cb); 00221 } 00222 DBGLOG(DBG,"after evaluateExternalAtoms: dst is " << *dst); 00223 00224 // solve program 00225 { 00226 // we don't use a mask here! 00227 // -> we receive all facts 00228 OrdinaryASPProgram program(reg, factory.xidb, dst, factory.ctx.maxint); 00229 GenuineSolverPtr solver = GenuineSolver::getInstance(factory.ctx, program); 00230 00231 // Search space pruning: the idea is to set the current global optimum as upper limit in the solver instance (of this unit) to eliminate interpretations with higher costs. 00232 // Note that this optimization is conservative such that the algorithm remains complete even when the program is split. Because costs can be only positive, 00233 // if the costs of a partial model are greater than the current global optimum then also any completion of this partial model (by combining it with other units) 00234 // would be non-optimal. 00235 if (factory.ctx.config.getOption("OptimizationByBackend")) solver->setOptimum(factory.ctx.currentOptimum); 00236 00237 // there must be either no or exactly one answer set 00238 InterpretationConstPtr model = solver->getNextModel(); 00239 00240 if( model == InterpretationPtr() ) { 00241 LOG(DBG,"got no answer set -> inconsistent"); 00242 inconsistent = true; 00243 break; 00244 } 00245 InterpretationConstPtr model2 = solver->getNextModel(); 00246 if( model2 != InterpretationConstPtr() ) 00247 throw FatalError("got more than one model in Wellfounded model generator -> use other model generator!"); 00248 00249 // cheap exchange -> thisret1 will then be free'd 00250 { 00251 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidhexsolve, "HEX solver time (cp mdl GenuineWfMG)"); 00252 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidhexsolve2, "HEX solver time"); 00253 dst->getStorage() = model->getStorage(); 00254 } 00255 DBGLOG(DBG,"after evaluating ASP: dst is " << *dst); 00256 DBGLOG(DBG, "Final Statistics:" << std::endl << solver->getStatistics()); 00257 } 00258 00259 // reg->eliminateHomomorphicAtoms(dst, src); 00260 00261 // check whether new interpretation is superset of old one 00262 // break if they are equal (i.e., if the fixpoint is reached) 00263 // error if new one is smaller (i.e., fixpoint is not allowed) 00264 // (TODO do this error check, and do it only in debug mode) 00265 { 00266 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidhexsolve, "HEX solver time (fp check GenuineWfMG)"); 00267 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidhexsolve2, "HEX solver time"); 00268 int cmpresult = dst->getStorage().compare(src->getStorage()); 00269 if( cmpresult == 0 ) { 00270 DBGLOG(DBG,"reached fixpoint"); 00271 break; 00272 } 00273 } 00274 00275 // switch interpretations 00276 current = 1 - current; 00277 limit--; 00278 // loop if limit is not reached 00279 }while( limit != 0 && !inconsistent ); 00280 /* 00281 if (inconsistent) break; 00282 current=0; 00283 reg->freezeNullTerms(ints[0]); 00284 reg->freezeNullTerms(ints[1]); 00285 } 00286 */ 00287 if( limit == 0 ) 00288 throw FatalError("reached wellfounded limit!"); 00289 00290 if( inconsistent ) { 00291 DBGLOG(DBG,"leaving loop with result 'inconsistent'"); 00292 return InterpretationPtr(); 00293 } 00294 else { 00295 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidhexsolve, "HEX solver time (make result GenuineWfMG)"); 00296 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidhexsolve2, "HEX solver time"); 00297 // does not matter which one we take, they are equal 00298 InterpretationPtr result = ints[0]; 00299 DBGLOG(DBG,"leaving loop with result " << *result); 00300 00301 // remove mask from result! 00302 result->getStorage() -= mask->getStorage(); 00303 DBGLOG(DBG,"after removing input facts: result is " << *result); 00304 00305 // return single answer set (there can only be one) 00306 return result; 00307 } 00308 } 00309 } 00310 00311 00312 DLVHEX_NAMESPACE_END 00313 00314 // vim:expandtab:ts=4:sw=4: 00315 // mode: C++ 00316 // End: