dlvhex  2.5.0
src/Atoms.cpp
Go to the documentation of this file.
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: