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 #include "dlvhex2/ComfortPluginInterface.h" 00035 WARNING("TODO how to implement strong negation (StrongNegationPlugin) with ComfortPluginInterface?") 00036 00037 #ifdef HAVE_CONFIG_H 00038 # include "config.h" 00039 #endif 00040 00041 #include "dlvhex2/Benchmarking.h" 00042 #include "dlvhex2/Printer.h" 00043 #include "dlvhex2/ProgramCtx.h" 00044 #include "dlvhex2/Registry.h" 00045 00046 #include <sstream> 00047 00048 DLVHEX_NAMESPACE_BEGIN 00049 00050 namespace 00051 { 00052 typedef std::set<ComfortAtom> IntBase; 00053 } 00054 00055 00056 std::ostream& ComfortTerm::print(std::ostream& o) const 00057 { 00058 if( isInteger() ) 00059 return o << intval; 00060 else 00061 return o << strval; 00062 } 00063 00064 00065 // see OrdinaryAtom::unifiesWith 00066 bool ComfortAtom::unifiesWith( 00067 const ComfortAtom& a) const 00068 { 00069 if( tuple.size() != a.tuple.size() ) 00070 return false; 00071 00072 DBGLOG_SCOPE(DBG,"CA::uw",false); 00073 DBGLOG(DBG,"= ComfortAtom::unifiesWith"); 00074 00075 // unify from left to right 00076 ComfortTuple result1(this->tuple); 00077 ComfortTuple result2(a.tuple); 00078 // if both tuples have a variable, assign result1 variable to result2 for all occurences to the end 00079 // if one tuple has constant, assign this constant into the other tuple for all occurences to the end 00080 ComfortTuple::iterator it1, it2; 00081 DBGLOG(DBG,"starting with result1 tuple " << printvector(result1)); 00082 DBGLOG(DBG,"starting with result2 tuple " << printvector(result2)); 00083 for(it1 = result1.begin(), it2 = result2.begin(); 00084 it1 != result1.end(); 00085 ++it1, ++it2) { 00086 DBGLOG(DBG,"at position " << static_cast<unsigned>(it1 - result1.begin()) << 00087 ": checking " << *it1 << " vs " << *it2); 00088 if( *it1 != *it2 ) { 00089 // different terms 00090 if( it1->isVariable() ) { 00091 // it1 is variable 00092 if( it2->isVariable() ) { 00093 // it2 is variable 00094 00095 // assign *it1 variable to all occurances of *it2 in result2 00096 ComfortTuple::iterator it3(it2); it3++; 00097 for(;it3 != result2.end(); ++it3) { 00098 if( *it3 == *it2 ) 00099 *it3 = *it1; 00100 } 00101 } 00102 else { 00103 // it2 is nonvariable 00104 00105 // assign *it2 nonvariable to all occurances of *it1 in result1 00106 ComfortTuple::iterator it3(it1); it3++; 00107 for(;it3 != result1.end(); ++it3) { 00108 if( *it3 == *it1 ) 00109 *it3 = *it2; 00110 } 00111 } 00112 } 00113 else { 00114 // it1 is nonvariable 00115 if( it2->isVariable() ) { 00116 // it2 is variable 00117 00118 // assign *it1 nonvariable to all occurances of *it2 in result2 00119 ComfortTuple::iterator it3(it2); it3++; 00120 for(;it3 != result2.end(); ++it3) { 00121 if( *it3 == *it2 ) 00122 *it3 = *it1; 00123 } 00124 } 00125 else { 00126 // it2 is nonvariable 00127 return false; 00128 } 00129 } 00130 DBGLOG(DBG,"after propagation of difference (look only after current position!):"); 00131 DBGLOG(DBG,"result1 tuple " << printvector(result1)); 00132 DBGLOG(DBG,"result2 tuple " << printvector(result2)); 00133 } 00134 } 00135 return true; 00136 } 00137 00138 00139 void ComfortAtom::calculateStrVal() const 00140 { 00141 ComfortTuple::const_iterator it = tuple.begin(); 00142 assert(it != tuple.end()); 00143 00144 std::ostringstream os; 00145 os << *it; 00146 it++; 00147 if( it != tuple.end() ) { 00148 os << "(" << *it; 00149 it++; 00150 while(it != tuple.end()) { 00151 os << "," << *it; 00152 it++; 00153 } 00154 os << ")"; 00155 } 00156 strval = os.str(); 00157 } 00158 00159 00160 std::ostream& ComfortAtom::print(std::ostream& o) const 00161 { 00162 return o << toString(); 00163 } 00164 00165 00166 // insert one atom 00167 void ComfortInterpretation::insert(const ComfortAtom& atm) 00168 { 00169 IntBase::insert(atm); 00170 } 00171 00172 00173 // insert all atoms from other interpretation 00174 void ComfortInterpretation::insert(const ComfortInterpretation& other) 00175 { 00176 IntBase::insert(other.begin(), other.end()); 00177 } 00178 00179 00180 namespace 00181 { 00182 struct MatchPred 00183 { 00184 const std::set<ComfortTerm>& predicates; 00185 MatchPred(const std::set<ComfortTerm>& predicates): 00186 predicates(predicates) {} 00187 bool operator()(const ComfortAtom& atm) const 00188 { 00189 if( atm.tuple.empty() ) 00190 throw std::runtime_error("MatchPred: atom tuple must not be empty!"); 00191 // remove if found 00192 return predicates.find(atm.tuple.front()) != predicates.end(); 00193 } 00194 }; 00195 } 00196 00197 00198 // remove atoms whose predicate matches a string in the given set 00199 void ComfortInterpretation::remove(const std::set<std::string>& predicates) 00200 { 00201 std::set<ComfortTerm> pred_constant_terms; 00202 BOOST_FOREACH(const std::string& pred, predicates) { 00203 pred_constant_terms.insert(ComfortTerm::createConstant(pred)); 00204 } 00205 00206 IntBase::iterator it = IntBase::begin(); 00207 do { 00208 assert( !it->tuple.empty() && "tuple of ComfortAtom must contain at least a predicate"); 00209 if( pred_constant_terms.find(it->tuple[0]) != pred_constant_terms.end() ) { 00210 // remove this one 00211 IntBase::iterator prev = it; 00212 IntBase::erase(prev); 00213 ++it; 00214 } 00215 else { 00216 ++it; 00217 } 00218 } 00219 while( it != IntBase::end() ); 00220 } 00221 00222 00223 // remove atoms whose predicate does not match any string in the given set 00224 void ComfortInterpretation::keep(const std::set<std::string>& predicates) 00225 { 00226 std::set<ComfortTerm> pred_constant_terms; 00227 BOOST_FOREACH(const std::string& pred, predicates) { 00228 pred_constant_terms.insert(ComfortTerm::createConstant(pred)); 00229 } 00230 00231 IntBase::iterator it = IntBase::begin(); 00232 do { 00233 assert( !it->tuple.empty() && "tuple of ComfortAtom must contain at least a predicate"); 00234 if( pred_constant_terms.find(it->tuple[0]) == pred_constant_terms.end() ) { 00235 // remove this one 00236 IntBase::iterator prev = it; 00237 IntBase::erase(prev); 00238 ++it; 00239 } 00240 else { 00241 ++it; 00242 } 00243 } 00244 while( it != IntBase::end() ); 00245 } 00246 00247 00248 // copy all atoms that match the specified predicate into destination interpretation 00249 void ComfortInterpretation::matchPredicate(const std::string& predicate, ComfortInterpretation& destination) const 00250 { 00251 ComfortTerm pred = ComfortTerm::createConstant(predicate); 00252 00253 for(IntBase::iterator it = IntBase::begin(); 00254 it != IntBase::end(); ++it) { 00255 assert( !it->tuple.empty() && "tuple of ComfortAtom must contain at least a predicate"); 00256 if( pred == it->tuple[0] ) { 00257 // add to destination 00258 destination.insert(*it); 00259 } 00260 } 00261 } 00262 00263 00264 // copy all atoms that unify with the specified predicate into destination interpretation 00265 void ComfortInterpretation::matchAtom(const ComfortAtom& atom, ComfortInterpretation& destination) const 00266 { 00267 for(IntBase::iterator it = IntBase::begin(); 00268 it != IntBase::end(); ++it) { 00269 assert( !it->tuple.empty() && "tuple of ComfortAtom must contain at least a predicate"); 00270 if( it->unifiesWith(atom) ) { 00271 // add to destination 00272 destination.insert(*it); 00273 } 00274 } 00275 } 00276 00277 00278 // return set difference *this \ subtractThis 00279 ComfortInterpretation ComfortInterpretation::difference(const ComfortInterpretation& subtractThis) const 00280 { 00281 ComfortInterpretation ret; 00282 std::insert_iterator<IntBase> inserter(ret, ret.begin()); 00283 std::set_difference( 00284 IntBase::begin(), IntBase::end(), 00285 subtractThis.begin(), subtractThis.end(), 00286 inserter); 00287 return ret; 00288 } 00289 00290 00291 std::ostream& ComfortInterpretation::print(std::ostream& o) const 00292 { 00293 return o << printrange(*this, "{", "}", ","); 00294 } 00295 00296 00297 bool ComfortInterpretation::operator==(const ComfortInterpretation& c2) const 00298 { 00299 return this->difference(c2).size() == 0 && c2.difference(*this).size() == 0; 00300 } 00301 00302 00303 namespace 00304 { 00305 ComfortTerm convertTerm(RegistryPtr reg, ID tid) { 00306 assert(tid.isTerm()); 00307 if( tid.isVariableTerm() ) { 00308 return ComfortTerm::createVariable(reg->getTermStringByID(tid)); 00309 } 00310 else if( tid.isConstantTerm() ) { 00311 return ComfortTerm::createConstant(reg->getTermStringByID(tid)); 00312 } 00313 else { 00314 assert(tid.isIntegerTerm()); 00315 return ComfortTerm::createInteger(tid.address); 00316 } 00317 } 00318 00319 void convertTuple(RegistryPtr reg, const Tuple& in, ComfortTuple& out) { 00320 assert(out.empty()); 00321 BOOST_FOREACH(ID id, in) { 00322 out.push_back( convertTerm(reg, id) ); 00323 } 00324 } 00325 00326 ID convertTerm(RegistryPtr reg, const ComfortTerm& ct) { 00327 if( ct.isConstant() ) { 00328 Term t(ID::MAINKIND_TERM | ID::SUBKIND_TERM_CONSTANT, ct.strval); 00329 WARNING("TODO check here(?) whether ct.strval has correct constant syntax") 00330 return reg->storeTerm(t); 00331 } 00332 else if( ct.isInteger() ) { 00333 return ID::termFromInteger(ct.intval); 00334 } 00335 else { 00336 throw PluginError( 00337 "plugins must not return variables in answer tuples " 00338 "(got '" + ct.strval + "'"); 00339 } 00340 } 00341 00342 void convertTuple(RegistryPtr reg, const ComfortTuple& in, Tuple& out) { 00343 assert(out.empty()); 00344 BOOST_FOREACH(const ComfortTerm& ct, in) { 00345 out.push_back( convertTerm(reg, ct) ); 00346 } 00347 } 00348 } 00349 00350 00356 void ComfortPluginAtom::retrieve(const Query& query, Answer& answer) 00357 { 00358 DBGLOG_SCOPE(DBG,"CPA::r",false); 00359 DBGLOG(DBG,"= ComfortPluginAtom::retrieve()"); 00360 00361 RegistryPtr reg = getRegistry(); 00362 assert(!!reg && "registry must be set for ComfortPluginAtom::retrieve(...)"); 00363 00364 // convert query 00365 ComfortQuery cq; 00366 convertTuple(reg, query.input, cq.input); 00367 convertTuple(reg, query.pattern, cq.pattern); 00368 for(Interpretation::Storage::enumerator it = 00369 query.interpretation->getStorage().first(); 00370 it != query.interpretation->getStorage().end(); ++it) { 00371 ID ogid(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG, *it); 00372 const OrdinaryAtom& ogatom = reg->ogatoms.getByID(ogid); 00373 ComfortAtom cogatom; 00374 convertTuple(reg, ogatom.tuple, cogatom.tuple); 00375 DBGLOG(DBG,"converted ogatom " << ogatom << 00376 " to " << printrange(cogatom.tuple)); 00377 cq.interpretation.insert(cogatom); 00378 } 00379 DBGLOG(DBG,"query conversion result before calling comfort-retrieve:"); 00380 DBGLOG(DBG," input=" << printrange(cq.input)); 00381 DBGLOG(DBG," pattern=" << printrange(cq.pattern)); 00382 DBGLOG(DBG," interpretation=" << printset(cq.interpretation)); 00383 00384 // call comfort retrieve method 00385 ComfortAnswer ca; 00386 retrieve(cq, ca); 00387 00388 #ifndef NDEBUG 00389 if( ca.empty() ) { 00390 DBGLOG(DBG,"comfort-retrieve returned no answer tuples"); 00391 } 00392 else { 00393 DBGLOG(DBG,"comfort-retrieve returned " << ca.size() << " answer tuples:"); 00394 BOOST_FOREACH(const ComfortTuple& at, ca) { 00395 DBGLOG(DBG," " << printrange(at)); 00396 } 00397 } 00398 #endif 00399 00400 // convert back 00401 BOOST_FOREACH(const ComfortTuple& at, ca) { 00402 // avoid copying: first create, than directly convert into it 00403 answer.get().push_back(Tuple()); 00404 convertTuple(reg, at, answer.get().back()); 00405 } 00406 } 00407 00408 00409 DLVHEX_NAMESPACE_END 00410 00411 // vim:expandtab:ts=4:sw=4: 00412 // mode: C++ 00413 // End: