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 #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: