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