dlvhex  2.5.0
src/UnfoundedSetCheckHeuristicsInterface.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 
00035 #include "dlvhex2/UnfoundedSetCheckHeuristicsInterface.h"
00036 #include "dlvhex2/Interpretation.h"
00037 #include "dlvhex2/Printer.h"
00038 
00039 #include <boost/foreach.hpp>
00040 
00041 DLVHEX_NAMESPACE_BEGIN
00042 
00043 // ============================== Base ==============================
00044 
00045 UnfoundedSetCheckHeuristics::UnfoundedSetCheckHeuristics(const AnnotatedGroundProgram& groundProgram, RegistryPtr reg) : groundProgram(groundProgram), reg(reg)
00046 {
00047 
00048     // prepare data structures for maintaining the skip program
00049     previouslyAssignedAndVerifiedAtoms = InterpretationPtr(new Interpretation(reg));
00050     notYetVerifiedExternalAtoms = InterpretationPtr(new Interpretation(reg));
00051 
00052     // make an index of ID addresses to rules
00053     atomsInRule.resize(groundProgram.getGroundProgram().idb.size(), 0);
00054     assignedAndVerifiedAtomsInRule.resize(groundProgram.getGroundProgram().idb.size(), 0);
00055     int ruleNr = 0;
00056     InterpretationPtr nodupAtom(new Interpretation(reg));
00057     InterpretationPtr nodupRule(new Interpretation(reg));
00058 
00059     #ifndef NDEBUG
00060     std::stringstream programstring;
00061     #endif
00062     BOOST_FOREACH (ID ruleID, groundProgram.getGroundProgram().idb) {
00063         const Rule& rule = reg->rules.getByID(ruleID);
00064         if (rule.isEAGuessingRule() || nodupRule->getFact(ruleID.address)) {
00065             ruleNr++;
00066             continue;
00067         }
00068         else {
00069             BOOST_FOREACH (ID h, rule.head) {
00070                 if (!nodupAtom->getFact(h.address)) {
00071                     rulesOfAtom[h.address].insert(ruleNr);
00072                     nodupAtom->setFact(h.address);
00073                 }
00074             }
00075             BOOST_FOREACH (ID b, rule.body) {
00076                 if (!nodupAtom->getFact(b.address)) {
00077                     rulesOfAtom[b.address].insert(ruleNr);
00078                     nodupAtom->setFact(b.address);
00079                 }
00080                 if (b.isExternalAuxiliary()){
00081                     notYetVerifiedExternalAtoms->setFact(b.address);
00082                 }
00083             }
00084             atomsInRule[ruleNr] = nodupAtom->getStorage().count();
00085             nodupAtom->clear();
00086 
00087             // at the beginning, skipProgram is the whole program
00088             skipProgram.insert(ruleID);
00089             nodupRule->setFact(ruleID.address);
00090             ruleNr++;
00091         }
00092         #ifndef NDEBUG
00093         programstring << std::endl << RawPrinter::toString(reg, ruleID);
00094         #endif
00095     }
00096     #ifndef NDEBUG
00097     DBGLOG(DBG, "Initializing UFS check heuristics for the following program:" << programstring.str());
00098     #endif
00099 }
00100 
00101 
00102 void UnfoundedSetCheckHeuristics::notify(InterpretationConstPtr verifiedAuxes, InterpretationConstPtr partialAssignment, InterpretationConstPtr assigned, InterpretationConstPtr changed)
00103 {
00104 }
00105 
00106 
00107 void UnfoundedSetCheckHeuristics::updateSkipProgram(InterpretationConstPtr verifiedAuxes, InterpretationConstPtr partialAssignment, InterpretationConstPtr assigned, InterpretationConstPtr changed)
00108 {
00109 
00110     DBGLOG(DBG, "UnfoundedSetCheckHeuristics::updateSkipProgram");
00111     assert (!!verifiedAuxes && !!partialAssignment && !!partialAssignment && !!changed);
00112 
00113     DBGLOG(DBG, "verifiedAuxes: " << *verifiedAuxes);
00114     DBGLOG(DBG, "partialAssignment: " << *partialAssignment);
00115     DBGLOG(DBG, "assigned: " << *assigned);
00116     DBGLOG(DBG, "changed: " << *changed);
00117     DBGLOG(DBG, "notYetVerifiedExternalAtoms: " << *notYetVerifiedExternalAtoms);
00118 
00119     const std::vector<ID>& idb = groundProgram.getGroundProgram().idb;
00120 
00121     // incrementally update the skipped program, i.e., the program part which was not yet fully assigned
00122     // go through atoms which changed or (for external atom replacement atoms) which have already been assigned but not verified yet
00123     std::vector<InterpretationConstPtr> intrs;
00124     intrs.push_back(changed);
00125     intrs.push_back(notYetVerifiedExternalAtoms);
00126 
00127     #ifndef NDEBUG
00128     bool processingChanged = true;
00129     #endif
00130 
00131     BOOST_FOREACH (InterpretationConstPtr intr, intrs) {
00132         DBGLOG(DBG, "Updating status of " << (processingChanged ? "changed" : "unverified external atom replacement") << " atoms");
00133         #ifndef NDEBUG
00134         processingChanged = false;
00135         #endif
00136 
00137         bm::bvector<>::enumerator en = intr->getStorage().first();
00138         bm::bvector<>::enumerator en_end = intr->getStorage().end();
00139         while (en < en_end) {
00140             DBGLOG(DBG, "Processing atom " << RawPrinter::toString(reg, reg->ogatoms.getIDByAddress(*en)));
00141             // update the number of assigned atoms in this rule according to current and previous assignment status
00142             if (previouslyAssignedAndVerifiedAtoms->getFact(*en) && !assigned->getFact(*en)) {
00143                 DBGLOG(DBG, "Atom " << RawPrinter::toString(reg, reg->ogatoms.getIDByAddress(*en)) << " was previously assigned but is not anymore");
00144                 BOOST_FOREACH (int ruleNr, rulesOfAtom[*en]) {
00145                     assert(assignedAndVerifiedAtomsInRule[ruleNr] > 0);
00146                     // if previously all atoms in the rule were assigned and verified, then the rule must be excluded from the UFS check, i.e., it must be added to skipProgram
00147                     if (assignedAndVerifiedAtomsInRule[ruleNr] == atomsInRule[ruleNr]) {
00148                         assert(skipProgram.count(idb[ruleNr]) == 0);
00149                         skipProgram.insert(idb[ruleNr]);
00150                         DBGLOG(DBG, "Adding rule " << RawPrinter::toString(reg, idb[ruleNr]) << " to skip program");
00151                     }
00152                     assignedAndVerifiedAtomsInRule[ruleNr]--;
00153                 }
00154                 previouslyAssignedAndVerifiedAtoms->clearFact(*en);
00155                 notYetVerifiedExternalAtoms->clearFact(*en);
00156             }
00157             else if (!previouslyAssignedAndVerifiedAtoms->getFact(*en) && assigned->getFact(*en)) {
00158                 // if it is an external atom replacement, then it must also be verified
00159                 ID id = reg->ogatoms.getIDByAddress(*en);
00160                 bool assignedAndVerified;
00161                 if (id.isExternalAuxiliary() && !id.isExternalInputAuxiliary()) {
00162                     if (verifiedAuxes->getFact(*en)) {
00163                         DBGLOG(DBG, "External atom replacement " << RawPrinter::toString(reg, reg->ogatoms.getIDByAddress(*en)) << " was previously unassigned but is now assigned and verified");
00164                         assignedAndVerified = true;
00165                     }
00166                     else {
00167                         DBGLOG(DBG, "External atom replacement " << RawPrinter::toString(reg, reg->ogatoms.getIDByAddress(*en)) << " was previously unassigned and is now assigned, but not verified; remember it for later verification");
00168                         notYetVerifiedExternalAtoms->setFact(*en);
00169                         assignedAndVerified = false;
00170                     }
00171                 }
00172                 else {
00173                     DBGLOG(DBG, "Ordinary atom " << RawPrinter::toString(reg, reg->ogatoms.getIDByAddress(*en)) << " was previously unassigned and is now assigned (and trivially verified)");
00174                     assignedAndVerified = true;
00175                 }
00176 
00177                 if (assignedAndVerified) {
00178                     BOOST_FOREACH (int ruleNr, rulesOfAtom[*en]) {
00179                         assignedAndVerifiedAtomsInRule[ruleNr]++;
00180                         assert(assignedAndVerifiedAtomsInRule[ruleNr] <= atomsInRule[ruleNr]);
00181                         // if all atoms are assigned, then the rule can be included in the UFS check, i.e., it can be removed from the skipProgram
00182                         if (assignedAndVerifiedAtomsInRule[ruleNr] == atomsInRule[ruleNr]) {
00183                             assert(skipProgram.count(idb[ruleNr]) == 1);
00184                             skipProgram.erase(skipProgram.find(idb[ruleNr]));
00185                             DBGLOG(DBG, "Removing rule " << RawPrinter::toString(reg, idb[ruleNr]) << " from skip program");
00186                         }
00187                     }
00188                     previouslyAssignedAndVerifiedAtoms->setFact(*en);
00189                 }
00190             }
00191             else if (previouslyAssignedAndVerifiedAtoms->getFact(*en) && assigned->getFact(*en)) {
00192                 // the number of assigned atoms stayed the same, but it might be that *en is a replacement atom
00193                 // which is not verified anymore.
00194                 // this needs to checked here
00195                 ID id = reg->ogatoms.getIDByAddress(*en);
00196                 if (id.isExternalAuxiliary() && !id.isExternalInputAuxiliary()) {
00197                     if (!verifiedAuxes->getFact(*en)) {
00198                         DBGLOG(DBG, "External atom replacement " << RawPrinter::toString(reg, reg->ogatoms.getIDByAddress(*en)) << " was previously assigned, is still assigned but is not verified anymore");
00199                         notYetVerifiedExternalAtoms->setFact(*en);
00200                         BOOST_FOREACH (int ruleNr, rulesOfAtom[*en]) {
00201                             // indeed it is not verfied anymore
00202                             assert(assignedAndVerifiedAtomsInRule[ruleNr] > 0);
00203                             // if previously all atoms in the rule were assigned and verified, then the rule must be excluded from the UFS check, i.e., it must be added to skipProgram
00204                             if (assignedAndVerifiedAtomsInRule[ruleNr] == atomsInRule[ruleNr]) {
00205                                 assert(skipProgram.count(idb[ruleNr]) == 0);
00206                                 skipProgram.insert(idb[ruleNr]);
00207                                 DBGLOG(DBG, "Adding rule " << RawPrinter::toString(reg, idb[ruleNr]) << " to skip program");
00208                             }
00209                             assignedAndVerifiedAtomsInRule[ruleNr]--;
00210                             previouslyAssignedAndVerifiedAtoms->clearFact(*en);
00211                         }
00212                     }
00213                     else {
00214                         DBGLOG(DBG, "External atom replacement " << RawPrinter::toString(reg, reg->ogatoms.getIDByAddress(*en)) << " was previously assigned, is still assigned and still verified");
00215                     }
00216                 }
00217             }
00218             #ifndef NDEBUG
00219             if (!previouslyAssignedAndVerifiedAtoms->getFact(*en)) {
00220                 BOOST_FOREACH (int ruleNr, rulesOfAtom[*en]) {
00221                     assert(idb[ruleNr].isRule());
00222                     DBGLOG(DBG, "Checking rule " << RawPrinter::toString(reg, idb[ruleNr]));
00223                     assert(skipProgram.count(idb[ruleNr]) == 1 && "rule with unsatisfied/unverified atoms does not belong to the skip program");
00224                 }
00225             }
00226             #endif
00227             en++;
00228         }
00229     }
00230 
00231     #ifndef NDEBUG
00232     // compute the skipProgram from scratch
00233     // this should give the same result as the incrementally updated version above
00234 
00235     // partial UFS check
00236     std::set<ID> skipProgramFromScratch;
00237     BOOST_FOREACH (ID ruleID, idb) {
00238         // check if all atoms in the rule have been assigned
00239         const Rule& rule = reg->rules.getByID(ruleID);
00240         if (rule.isEAGuessingRule()) continue;
00241         bool allassigned = true;
00242         BOOST_FOREACH (ID h, rule.head) {
00243             if (!assigned->getFact(h.address)) {
00244                 allassigned = false;
00245                 break;
00246             }
00247         }
00248         BOOST_FOREACH (ID b, rule.body) {
00249             if (!assigned->getFact(b.address)) {
00250                 allassigned = false;
00251                 break;
00252             }
00253             if (b.isExternalAuxiliary()) {
00254                 allassigned &= verifiedAuxes->getFact(b.address);
00255                 if (!allassigned) break;
00256             }
00257         }
00258         if (!allassigned) {
00259             skipProgramFromScratch.insert(ruleID);
00260         }
00261     }
00262 
00263     std::stringstream programstring;
00264     RawPrinter printer(programstring, reg);
00265     programstring << "Skipped program:" << std::endl;
00266     BOOST_FOREACH (ID ruleId, skipProgram) {
00267         printer.print(ruleId);
00268         programstring << std::endl;
00269     }
00270     programstring << std::endl << "Skipped program from scratch:" << std::endl;
00271     BOOST_FOREACH (ID ruleId, skipProgramFromScratch) {
00272         printer.print(ruleId);
00273         programstring << std::endl;
00274     }
00275     DBGLOG(DBG, programstring.str());
00276 
00277     BOOST_FOREACH (ID id, skipProgram) {
00278         assert(skipProgramFromScratch.count(id) == 1 && "incrementally updated skipped program is wrong");
00279     }
00280     BOOST_FOREACH (ID id, skipProgramFromScratch) {
00281         assert(skipProgram.count(id) == 1 && "incrementally updated skipped program is wrong");
00282     }
00283     #endif
00284 }
00285 
00286 
00287 DLVHEX_NAMESPACE_END
00288 
00289 // vim:expandtab:ts=4:sw=4:
00290 // mode: C++
00291 // End: