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 #include "dlvhex2/Atoms.h" 00039 #include "dlvhex2/Logger.h" 00040 #include "dlvhex2/Printhelpers.h" 00041 #include "dlvhex2/Interpretation.h" 00042 #include "dlvhex2/Registry.h" 00043 #include "dlvhex2/Printer.h" 00044 #include "dlvhex2/PluginInterface.h" 00045 #include "dlvhex2/OrdinaryAtomTable.h" 00046 00047 #include <boost/foreach.hpp> 00048 #include <map> 00049 00050 #define DEBUG_UNIFICATION 00051 00052 DLVHEX_NAMESPACE_BEGIN 00053 00054 bool OrdinaryAtom::unifiesWith(const OrdinaryAtom& a) const 00055 { 00056 if( tuple.size() != a.tuple.size() ) 00057 return false; 00058 00059 #ifdef DEBUG_UNIFICATION 00060 DBGLOG_SCOPE(DBG,"unifiesWith",true); 00061 #endif 00062 // unify from left to right 00063 Tuple result1(this->tuple); 00064 Tuple result2(a.tuple); 00065 // if both tuples have a variable, assign result1 variable to result2 for all occurences to the end 00066 // if one tuple has constant, assign this constant into the other tuple for all occurences to the end 00067 Tuple::iterator it1, it2; 00068 #ifdef DEBUG_UNIFICATION 00069 DBGLOG(DBG,"starting with result1 tuple " << printvector(result1)); 00070 DBGLOG(DBG,"starting with result2 tuple " << printvector(result2)); 00071 #endif 00072 for(it1 = result1.begin(), it2 = result2.begin(); 00073 it1 != result1.end(); 00074 ++it1, ++it2) { 00075 #ifdef DEBUG_UNIFICATION 00076 DBGLOG(DBG,"at position " << static_cast<unsigned>(it1 - result1.begin()) << 00077 ": checking " << *it1 << " vs " << *it2); 00078 #endif 00079 if( *it1 != *it2 ) { 00080 // different terms 00081 if( it1->isVariableTerm() ) { 00082 // it1 is variable 00083 if( it2->isVariableTerm() ) { 00084 // it2 is variable 00085 00086 // assign *it1 variable to all occurances of *it2 in result2 00087 Tuple::iterator it3(it2); it3++; 00088 for(;it3 != result2.end(); ++it3) { 00089 if( *it3 == *it2 ) 00090 *it3 = *it1; 00091 } 00092 } 00093 else { 00094 // it2 is nonvariable 00095 00096 // assign *it2 nonvariable to all occurances of *it1 in result1 00097 Tuple::iterator it3(it1); it3++; 00098 for(;it3 != result1.end(); ++it3) { 00099 if( *it3 == *it1 ) 00100 *it3 = *it2; 00101 } 00102 } 00103 } 00104 else { 00105 // it1 is nonvariable 00106 if( it2->isVariableTerm() ) { 00107 // it2 is variable 00108 00109 // assign *it1 nonvariable to all occurances of *it2 in result2 00110 Tuple::iterator it3(it2); it3++; 00111 for(;it3 != result2.end(); ++it3) { 00112 if( *it3 == *it2 ) 00113 *it3 = *it1; 00114 } 00115 } 00116 else { 00117 // it2 is nonvariable 00118 return false; 00119 } 00120 } 00121 #ifdef DEBUG_UNIFICATION 00122 DBGLOG(DBG,"after propagation of difference (look only after current position!):"); 00123 DBGLOG(DBG,"result1 tuple " << printvector(result1)); 00124 DBGLOG(DBG,"result2 tuple " << printvector(result2)); 00125 #endif 00126 } 00127 } 00128 return true; 00129 } 00130 00131 00132 bool OrdinaryAtom::unifiesWith(const OrdinaryAtom& a, RegistryPtr reg) const 00133 { 00134 if( tuple.size() != a.tuple.size() ) 00135 return false; 00136 00137 typedef std::pair<ID, ID> Pair; 00138 std::vector<Pair> diff; 00139 00140 Tuple result1(this->tuple); 00141 Tuple result2(a.tuple); 00142 00143 // for atoms without nested terms we can apply the more efficient algorithm from above 00144 bool nestedTerms = false; 00145 BOOST_FOREACH (ID id, result1) { 00146 if (id.isNestedTerm()) { 00147 nestedTerms = true; 00148 break; 00149 } 00150 } 00151 BOOST_FOREACH (ID id, result2) { 00152 if (id.isNestedTerm()) { 00153 nestedTerms = true; 00154 break; 00155 } 00156 } 00157 if (!nestedTerms) return unifiesWith(a); 00158 00159 // use unique variable for result1 and result2 00160 #ifdef DEBUG_UNIFICATION 00161 DBGLOG(DBG, "Standardizing variables"); 00162 #endif 00163 std::set<ID> vars1; 00164 reg->getVariablesInTuple(result1, vars1); 00165 int i = 0; 00166 BOOST_FOREACH (ID v, vars1) { 00167 std::stringstream ss; 00168 ss << "X" << i; 00169 ID var = ID_FAIL; 00170 do { 00171 ss << "X"; 00172 }while(vars1.count(reg->storeVariableTerm(ss.str())) > 0); 00173 for (uint32_t t = 0; t < result1.size(); ++t) { 00174 result1[t] = reg->replaceVariablesInTerm(result1[t], v, reg->storeVariableTerm(ss.str())); 00175 } 00176 i++; 00177 } 00178 std::set<ID> vars2; 00179 reg->getVariablesInTuple(result2, vars2); 00180 i = 0; 00181 BOOST_FOREACH (ID v, vars2) { 00182 std::stringstream ss; 00183 ss << "Y" << i; 00184 ID var = ID_FAIL; 00185 do { 00186 ss << "Y"; 00187 }while(vars2.count(reg->storeVariableTerm(ss.str())) > 0); 00188 for (uint32_t t = 0; t < result2.size(); ++t) { 00189 result2[t] = reg->replaceVariablesInTerm(result2[t], v, reg->storeVariableTerm(ss.str())); 00190 } 00191 i++; 00192 } 00193 00194 // construct difference set 00195 #ifdef DEBUG_UNIFICATION 00196 DBGLOG(DBG, "Constructing difference set"); 00197 #endif 00198 for (uint32_t i = 0; i < result1.size(); ++i) { 00199 diff.push_back(Pair(result1[i], result2[i])); 00200 } 00201 00202 bool restart = true; 00203 while (diff.size() > 0 && restart) { 00204 restart = false; 00205 00206 #ifdef DEBUG_UNIFICATION 00207 DBGLOG(DBG, "Iteration starts; set of corresponding irreducible pairs:"); 00208 BOOST_FOREACH (Pair p, diff) { 00209 std::stringstream ss; 00210 RawPrinter printer(ss, reg); 00211 printer.print(p.first); 00212 ss << " - "; 00213 printer.print(p.second); 00214 DBGLOG(DBG, ss.str()); 00215 } 00216 #endif 00217 00218 // reduce pairs 00219 #ifdef DEBUG_UNIFICATION 00220 DBGLOG(DBG, "Reducing pairs"); 00221 #endif 00222 int nr = 0; 00223 BOOST_FOREACH (Pair p, diff) { 00224 if (p.first.isNestedTerm() && p.second.isNestedTerm()) { 00225 Term t1 = reg->terms.getByID(p.first); 00226 Term t2 = reg->terms.getByID(p.second); 00227 00228 if (t1.arguments[0] != t2.arguments[0] || t1.arguments.size() != t2.arguments.size()) return false; 00229 00230 #ifdef DEBUG_UNIFICATION 00231 { 00232 std::stringstream ss; 00233 ss << "Reducing pair "; 00234 RawPrinter printer(ss, reg); 00235 printer.print(p.first); 00236 ss << " - "; 00237 printer.print(p.second); 00238 DBGLOG(DBG, ss.str()); 00239 } 00240 #endif 00241 00242 for (uint32_t i = 0; i < t1.arguments.size(); ++i) { 00243 diff.push_back(Pair(t1.arguments[0], t2.arguments[0])); 00244 } 00245 diff.erase(diff.begin() + nr); 00246 restart = true; 00247 break; 00248 } 00249 nr++; 00250 } 00251 if (restart) continue; 00252 00253 // take the first irreducible pair and check unifiability 00254 Pair p = diff[0]; 00255 #ifdef DEBUG_UNIFICATION 00256 { 00257 std::stringstream ss; 00258 ss << "Processing pair "; 00259 RawPrinter printer(ss, reg); 00260 printer.print(p.first); 00261 ss << " - "; 00262 printer.print(p.second); 00263 DBGLOG(DBG, ss.str()); 00264 } 00265 #endif 00266 diff.erase(diff.begin()); 00267 if (p.first.isVariableTerm()) { 00268 #ifdef DEBUG_UNIFICATION 00269 DBGLOG(DBG, "First component is a variable"); 00270 #endif 00271 if (p.first != p.second) { 00272 // occurs check 00273 if (reg->getVariablesInID(p.second).count(p.first) > 0) { 00274 DBGLOG(DBG, "Not unifiable due to occurs check"); 00275 return false; 00276 } 00277 00278 // replace in all pairs in diff p.first by p.second 00279 #ifdef DEBUG_UNIFICATION 00280 DBGLOG(DBG, "Unifying"); 00281 #endif 00282 BOOST_FOREACH (Pair pp, diff) { 00283 pp.first = reg->replaceVariablesInTerm(pp.first, p.first, p.second); 00284 pp.second = reg->replaceVariablesInTerm(pp.second, p.first, p.second); 00285 } 00286 } 00287 } 00288 else if (p.second.isVariableTerm()) { 00289 #ifdef DEBUG_UNIFICATION 00290 DBGLOG(DBG, "Second component is a variable"); 00291 #endif 00292 if (p.first != p.second) { 00293 // occurs check 00294 if (reg->getVariablesInID(p.first).count(p.second) > 0) { 00295 DBGLOG(DBG, "Not unifiable due to occurs check"); 00296 return false; 00297 } 00298 00299 // replace in all pairs in diff p.first by p.second 00300 #ifdef DEBUG_UNIFICATION 00301 DBGLOG(DBG, "Unifying"); 00302 #endif 00303 BOOST_FOREACH (Pair pp, diff) { 00304 pp.first = reg->replaceVariablesInTerm(pp.first, p.second, p.first); 00305 pp.second = reg->replaceVariablesInTerm(pp.second, p.second, p.first); 00306 } 00307 } 00308 } 00309 else { 00310 // non-variable and non-nested terms (i.e., constants) are unifiable iff they are equal 00311 if (p.first != p.second) { 00312 #ifdef DEBUG_UNIFICATION 00313 DBGLOG(DBG, "Not unifiable"); 00314 #endif 00315 return false; 00316 } 00317 } 00318 } 00319 return true; 00320 } 00321 00322 00323 bool OrdinaryAtom::existsHomomorphism(RegistryPtr reg, const OrdinaryAtom& a) const 00324 { 00325 if( tuple.size() != a.tuple.size() ) 00326 return false; 00327 #define DEBUG_HOMOMORPHISM 00328 #ifdef DEBUG_HOMOMORPHISM 00329 DBGLOG_SCOPE(DBG,"existsHomomorphism",true); 00330 #endif 00331 // unify from left to right 00332 Tuple result1(this->tuple); 00333 Tuple result2(a.tuple); 00334 // if both tuples have a null value, assign result1 null to result2 for all occurences to the end 00335 // if one tuple has constant, assign this constant into the other tuple for all occurences to the end 00336 Tuple::iterator it1, it2; 00337 #ifdef DEBUG_HOMOMORPHISM 00338 DBGLOG(DBG,"starting with result1 tuple " << printvector(result1)); 00339 DBGLOG(DBG,"starting with result2 tuple " << printvector(result2)); 00340 #endif 00341 for(it1 = result1.begin(), it2 = result2.begin(); 00342 it1 != result1.end(); 00343 ++it1, ++it2) { 00344 #ifdef DEBUG_HOMOMORPHISM 00345 DBGLOG(DBG,"at position " << static_cast<unsigned>(it1 - result1.begin()) << 00346 ": checking " << *it1 << " vs " << *it2); 00347 #endif 00348 if( *it1 != *it2 ) { 00349 // different terms 00350 if( reg->isNullTerm(*it1) ) { 00351 // it1 is null 00352 if( reg->isNullTerm(*it2) ) { 00353 // it2 is null 00354 00355 // assign *it1 variable to all occurances of *it2 in result2 00356 Tuple::iterator it3(it2); it3++; 00357 for(;it3 != result2.end(); ++it3) { 00358 if( *it3 == *it2 ) 00359 *it3 = *it1; 00360 } 00361 } 00362 else { 00363 // it2 is nonnull 00364 00365 // assign *it2 nonvariable to all occurances of *it1 in result1 00366 Tuple::iterator it3(it1); it3++; 00367 for(;it3 != result1.end(); ++it3) { 00368 if( *it3 == *it1 ) 00369 *it3 = *it2; 00370 } 00371 } 00372 } 00373 else { 00374 // it1 is nonnull 00375 if( reg->isNullTerm(*it2) ) { 00376 // it2 is null 00377 00378 // assign *it1 nonnull to all occurances of *it2 in result2 00379 Tuple::iterator it3(it2); it3++; 00380 for(;it3 != result2.end(); ++it3) { 00381 if( *it3 == *it2 ) 00382 *it3 = *it1; 00383 } 00384 } 00385 else { 00386 // it2 is nonnull 00387 return false; 00388 } 00389 } 00390 #ifdef DEBUG_HOMOMORPHISM 00391 DBGLOG(DBG,"after propagation of difference (look only after current position!):"); 00392 DBGLOG(DBG,"result1 tuple " << printvector(result1)); 00393 DBGLOG(DBG,"result2 tuple " << printvector(result2)); 00394 #endif 00395 } 00396 } 00397 return true; 00398 } 00399 00400 00401 ExternalAtom::~ExternalAtom() 00402 { 00403 } 00404 00405 00406 const ExtSourceProperties& ExternalAtom::getExtSourceProperties() const 00407 { 00408 return prop; 00409 } 00410 00411 00412 std::ostream& ExternalAtom::print(std::ostream& o) const 00413 { 00414 if( pluginAtom == NULL ) { 00415 // raw 00416 return o << 00417 "ExternalAtom(&" << predicate << "[" << printvector(inputs) << 00418 "](" << printvector(Atom::tuple) << ")" << 00419 " pluginAtom=" << printptr(pluginAtom) << 00420 " auxInputPredicate=" << auxInputPredicate; 00421 } 00422 else { 00423 // pretty 00424 RegistryPtr reg = pluginAtom->getRegistry(); 00425 o << "&" << pluginAtom->getPredicate() << 00426 "[" << printManyToString<RawPrinter>(inputs, ",", reg) << 00427 "](" << printManyToString<RawPrinter>(Atom::tuple, ",", reg) << ") "; 00428 if( auxInputPredicate == ID_FAIL ) { 00429 return o << " (aux=ID_FAIL)"; 00430 } 00431 else { 00432 return o << " (aux=" << printToString<RawPrinter>(auxInputPredicate, reg) << ")"; 00433 } 00434 } 00435 } 00436 00437 00438 std::ostream& ModuleAtom::print(std::ostream& o) const 00439 { 00440 return o << 00441 "ModuleAtom(&" << predicate << "[" << printvector(inputs) << 00442 "]::" << outputAtom; 00443 } 00444 00445 00446 //TODO rename this method to updateMasks() 00447 void ExternalAtom::updatePredicateInputMask() const 00448 { 00449 DBGLOG_VSCOPE(DBG,"EA::uM",this,true); 00450 00451 if( !inputMask->mask() ) { 00452 // initially configure mask 00453 00454 assert(!!pluginAtom); 00455 RegistryPtr reg = pluginAtom->getRegistry(); 00456 00457 inputMask->setRegistry(reg); 00458 } 00459 inputMask->updateMask(); 00460 00461 if( auxInputPredicate != ID_FAIL ) { 00462 if( !auxInputMask->mask() ) { 00463 // initially configure mask 00464 00465 assert(!!pluginAtom); 00466 RegistryPtr reg = pluginAtom->getRegistry(); 00467 00468 auxInputMask->setRegistry(reg); 00469 } 00470 auxInputMask->updateMask(); 00471 } 00472 } 00473 00474 00475 DLVHEX_NAMESPACE_END 00476 00477 00478 // vim:expandtab:ts=4:sw=4: 00479 // mode: C++ 00480 // End: