unfounded_check.cpp
Go to the documentation of this file.
00001 // 
00002 // Copyright (c) 2010, Benjamin Kaufmann
00003 // 
00004 // This file is part of Clasp. See http://www.cs.uni-potsdam.de/clasp/ 
00005 // 
00006 // Clasp is free software; you can redistribute it and/or modify
00007 // it under the terms of the GNU General Public License as published by
00008 // the Free Software Foundation; either version 2 of the License, or
00009 // (at your option) any later version.
00010 // 
00011 // Clasp is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 // 
00016 // You should have received a copy of the GNU General Public License
00017 // along with Clasp; if not, write to the Free Software
00018 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019 //
00020 #ifdef _MSC_VER
00021 #pragma warning(disable : 4996) // std::copy was declared deprecated
00022 #endif
00023 
00024 #include <clasp/unfounded_check.h>
00025 #include <clasp/clause.h>
00026 #include <algorithm>
00027 #include <cmath>
00028 namespace Clasp { 
00030 // DefaultUnfoundedCheck - Construction/Destruction
00032 // Choice rules are handled like normal rules with one exception:
00033 //  Since BFA does not apply to choice rules, we manually trigger the removal of source pointers
00034 //  whenever an atom sourced by a choice rule becomes false.
00035 //
00036 // The major problems with card/weight-rules are:
00037 //  1. subgoals can circularly depend on the body
00038 //  2. subgoal false -> body false, does not hold
00039 // 
00040 // Regarding the first point, consider: {b}. a:- 1{a,b}.
00041 // Since b is external to 1{a,b}, the body is a valid source for a. Therefore, 1{a,b} can source a.
00042 // After a's source pointer is set to 1{a,b}, both subgoals of 1{a,b} have a source. Nevertheless,
00043 // we must not count a because it (circularly) depends on the body. I.e. as soon as b 
00044 // becomes false, a is unfounded, because the loop {a} no longer has external bodies.
00045 //
00046 // The second point means that we have to watch *all* subgoals because we 
00047 // may need to trigger source pointer removal whenever one of the subgoals becomes false.
00048 // Consider: {a,b,c}. t :- 2 {b,t,x}. x :- t,c. x :- a.
00049 // Now assume {t,c} is true and a becomes false. In this case, both x and t lose their
00050 // source pointer and we get the (conflicting) unfounded set {x, t}.
00051 // Further assume that after some backtracking we have that both {t,c} and a
00052 // become false. Therefore x is false, too. Since we do not update source pointers on
00053 // conflicts, x and t still have no source. Thus no removal of source pointers is triggered.
00054 // If we would not watch x in 2 {b,t,x}, we could not add t to the todo queue and 
00055 // we would therefore miss the unfounded set {t}.
00056 //
00057 // The implementation for extended bodies works as follows:
00058 // - It distinguishes between internal literals, those that are in the same SCC as B
00059 //   and external literals, those that are not.
00060 // - Let W(l) be the weight of literal l in B and W(WS) be the sum of W(l) for each l in a set WS. 
00061 // - The goal is to maintain a set WS of literals l, s.th l in Body and hasSource(l) AND W(WS) >= bound.
00062 // - Initially WS contains all non-false external literals of B.
00063 // - Whenever one of the internal literals of B becomes sourced, it is added to WS 
00064 //   *only if* W(WS) < bound. In that case, it is guaranteed that the literal
00065 //   currently does not circularly depend on the body.
00066 // - As soon as W(WS) >= bound, we declare the body as valid source for its heads.
00067 // - Whenever one of the literals l in WS loses its source, it is removed from WS.
00068 //   If l is an external literal, new valid external literals are searched and added to WS 
00069 //   until the source condition holds again.
00070 // - If the condition cannot be restored, the body is marked as invalid source.
00071 
00072 DefaultUnfoundedCheck::DefaultUnfoundedCheck()
00073         : solver_(0) 
00074         , graph_(0)
00075         , mini_(0)
00076         , reasons_(0)
00077         , strategy_(common_reason) {
00078         mini_.release();
00079 }
00080 DefaultUnfoundedCheck::~DefaultUnfoundedCheck() { 
00081         for (ExtVec::size_type i = 0; i != extended_.size(); ++i) {
00082                 ::operator delete(extended_[i]);
00083         }
00084         delete [] reasons_;
00085 }
00087 // DefaultUnfoundedCheck - Initialization
00089 void DefaultUnfoundedCheck::addWatch(Literal p, uint32 data, WatchType type) {
00090         assert(data < varMax);
00091         solver_->addWatch(p, this, static_cast<uint32>((data << 2) | type));
00092 }
00093 
00094 // inits unfounded set checker with graph, i.e.
00095 // - creates data objects for bodies and atoms
00096 // - adds necessary watches to the solver
00097 // - initializes source pointers
00098 bool DefaultUnfoundedCheck::init(Solver& s) {
00099         assert(!graph_ || s.sharedContext()->sccGraph.get() == graph_);
00100         if (s.sharedContext()->sccGraph.get() == 0) { 
00101                 s.removePost(this);
00102                 return true; 
00103         }
00104         solver_      = &s;
00105         graph_       = s.sharedContext()->sccGraph.get();
00106         strategy_    = s.strategy.search != SolverStrategies::no_learning ? static_cast<ReasonStrategy>(s.configuration().loopRep) : no_reason;
00107         if (strategy_ == only_reason) {
00108                 delete [] reasons_;
00109                 reasons_ = new LitVec[solver_->numVars()];
00110         }
00111         // process any leftovers from previous steps
00112         while (findUfs(s, false) != ufs_none) {
00113                 while (!ufs_.empty()) {
00114                         if (!s.force(~graph_->getAtom(ufs_.front()).lit, 0)) { return false; }
00115                         atoms_[ufs_.pop_ret()].ufs = 0;
00116                 }
00117         }
00118         AtomVec::size_type startAtom = atoms_.size();
00119         // set up new atoms
00120         atoms_.resize(graph_->numAtoms());
00121         AtomData& sentinel = atoms_[SharedDependencyGraph::sentinel_atom];
00122         sentinel.resurrectSource();
00123         sentinel.todo = 1;
00124         sentinel.ufs  = 1;
00125         // set up new bodies
00126         for (uint32 i = (uint32)bodies_.size(); i != graph_->numBodies(); ++i) {
00127                 bodies_.push_back(BodyData());
00128                 BodyPtr n(getBody(i));
00129                 if (!n.node->extended()) {
00130                         initBody(n);
00131                 }
00132                 else {
00133                         initExtBody(n);
00134                 }
00135                 // when a body becomes false, it can no longer be used as source
00136                 addWatch(~n.node->lit, n.id, watch_source_false);
00137         }
00138         // check for initially unfounded atoms
00139         propagateSource();
00140         for (AtomVec::size_type i = startAtom, end = atoms_.size(); i != end; ++i) {
00141                 const AtomNode& a = graph_->getAtom(NodeId(i));
00142                 if (!atoms_[i].hasSource() && !solver_->force(~a.lit, 0)) {
00143                         return false;
00144                 }
00145                 if (a.inChoice()) {
00146                         addWatch(~a.lit, NodeId(i), watch_head_false);
00147                 }
00148         }
00149         if (graph_->numNonHcfs() != 0) {
00150                 mini_ = new MinimalityCheck(s.searchConfig().fwdCheck);
00151         }
00152         return true;
00153 }
00154 
00155 // initializes a "normal" body, i.e. a body where lower(B) == size(B)
00156 void DefaultUnfoundedCheck::initBody(const BodyPtr& n) {
00157         assert(n.id < bodies_.size());
00158         BodyData& data = bodies_[n.id];
00159         // initialize lower to the number of predecessors from same scc that currently
00160         // have no source. One lower is 0, the body can source successors in its scc
00161         data.lower_or_ext  = n.node->num_preds();
00162         initSuccessors(n, data.lower_or_ext);
00163 }
00164 
00165 // initializes an "extended" body, i.e. a count/sum
00166 // creates & populates WS and adds watches to all subgoals
00167 void DefaultUnfoundedCheck::initExtBody(const BodyPtr& n) {
00168         assert(n.id < bodies_.size() && n.node->extended());
00169         BodyData& data = bodies_[n.id];
00170         uint32 preds   = n.node->num_preds();
00171         ExtData* extra = new (::operator new(sizeof(ExtData) + (ExtData::flagSize(preds)*sizeof(uint32)))) ExtData(n.node->ext_bound(), preds);
00172 
00173         InitExtWatches addWatches = { this, &n, extra };
00174         graph_->visitBodyLiterals(*n.node, addWatches);
00175         
00176         data.lower_or_ext = (uint32)extended_.size();
00177         extended_.push_back(extra);
00178         initSuccessors(n, extra->lower);
00179 }
00180 
00181 // set n as source for its heads if possible and necessary
00182 void DefaultUnfoundedCheck::initSuccessors(const BodyPtr& n, weight_t lower) {
00183         if (!solver_->isFalse(n.node->lit)) {
00184                 for (const NodeId* x = n.node->heads_begin(); x != n.node->heads_end(); ++x) {
00185                         const AtomNode& a = graph_->getAtom(*x);
00186                         if (a.scc != n.node->scc || lower <= 0) {
00187                                 setSource(*x, n);
00188                         }
00189                 }
00190         }
00191 }
00192 
00193 // watches needed to implement extended rules
00194 void DefaultUnfoundedCheck::addExtWatch(Literal p, const BodyPtr& B, uint32 data) {
00195         addWatch(p, static_cast<uint32>(watches_.size()), watch_subgoal_false);
00196         ExtWatch w = { B.id, data };
00197         watches_.push_back(w);
00198 }
00200 // DefaultUnfoundedCheck - Base interface
00202 void DefaultUnfoundedCheck::reason(Solver&, Literal p, LitVec& r) {
00203         LitVec::const_iterator it, end;
00204         if (!activeClause_.empty() && activeClause_[0] == p) {
00205                 it  = activeClause_.begin()+1;
00206                 end = activeClause_.end();
00207         }
00208         else {
00209                 assert(strategy_ == only_reason && reasons_);
00210                 it  = reasons_[p.var()-1].begin();
00211                 end = reasons_[p.var()-1].end();
00212         }
00213         for (; it != end; ++it) r.push_back( ~*it );
00214 }
00215 
00216 bool DefaultUnfoundedCheck::propagateFixpoint(Solver& s, PostPropagator* ctx) {
00217         bool checkMin = ctx == 0 && mini_.get() && mini_->partialCheck(s.decisionLevel());
00218         for (UfsType t; (t = findUfs(s, checkMin)) != ufs_none; ) {
00219                 if (!falsifyUfs(t)) { 
00220                         resetTodo(); 
00221                         return false;
00222                 }
00223         }
00224         return true;
00225 }
00226 
00227 void DefaultUnfoundedCheck::reset() {
00228         assert(loopAtoms_.empty() && sourceQ_.empty() && ufs_.empty() && todo_.empty());
00229         // remember assignments from top-level -
00230         // the reset may come from a stop request and we might
00231         // want to continue later
00232         if (solver_->decisionLevel()) {
00233                 invalidQ_.clear();
00234         }
00235 }
00236 bool DefaultUnfoundedCheck::valid(Solver& s) {
00237         if (!mini_.get() || findNonHcfUfs(s) == ufs_none) { return true; }
00238         falsifyUfs(ufs_non_poly);
00239         return false;
00240 }
00241 bool DefaultUnfoundedCheck::isModel(Solver& s) {
00242         return DefaultUnfoundedCheck::valid(s);
00243 }
00245 // DefaultUnfoundedCheck - source pointer propagation
00247 // propagates recently set source pointers within one strong component.
00248 void DefaultUnfoundedCheck::propagateSource() {
00249         for (LitVec::size_type i = 0; i < sourceQ_.size(); ++i) {
00250                 NodeId atom = sourceQ_[i];
00251                 if (atoms_[atom].hasSource()) {
00252                         // propagate a newly added source-pointer
00253                         graph_->getAtom(atom).visitSuccessors(AddSource(this));
00254                 }
00255                 else {
00256                         graph_->getAtom(atom).visitSuccessors(RemoveSource(this));
00257                 }
00258         }
00259         sourceQ_.clear();
00260 }
00261 
00262 // replaces current source of atom with n
00263 void DefaultUnfoundedCheck::updateSource(AtomData& atom, const BodyPtr& n) {
00264         if (atom.watch() != AtomData::nill_source) {
00265                 --bodies_[atom.watch()].watches;
00266         }
00267         atom.setSource(n.id);
00268         ++bodies_[n.id].watches;
00269 }
00270 
00271 // an atom in extended body n has a new source, check if n is now a valid source
00272 void DefaultUnfoundedCheck::AddSource::operator()(NodeId bodyId, uint32 idx) const {
00273         BodyPtr n(self->getBody(bodyId));
00274         ExtData* ext = self->extended_[self->bodies_[bodyId].lower_or_ext];
00275         if (ext->lower > 0 || self->bodies_[n.id].watches == 0) {
00276                 // currently not a source - safely add pred to our watch set
00277                 ext->addToWs(idx, n.node->pred_weight(idx, false));
00278         }
00279         if (!self->solver_->isFalse(n.node->lit) && ext->lower <= 0) {
00280                 // valid source - propagate to heads
00281                 self->forwardSource(n);
00282         }
00283 }
00284 // an atom in extended body n has lost its source, check if n is no longer a valid source
00285 void DefaultUnfoundedCheck::RemoveSource::operator()(NodeId bodyId, uint32 idx) const {
00286         BodyPtr n(self->getBody(bodyId));
00287         ExtData* ext = self->extended_[self->bodies_[bodyId].lower_or_ext];
00288         ext->removeFromWs(idx, n.node->pred_weight(idx, false));
00289         if (ext->lower > 0 && self->bodies_[n.id].watches > 0) {
00290                 // extended bodies don't always become false if a predecessor becomes false
00291                 // eagerly enqueue all successors watching this body
00292                 self->forwardUnsource(n, true);
00293         }
00294 }
00295 
00296 // n is a valid source again, forward propagate this information to its heads
00297 void DefaultUnfoundedCheck::forwardSource(const BodyPtr& n) {
00298         for (const NodeId* x = n.node->heads_begin(); x != n.node->heads_end(); ++x) {
00299                 setSource(*x, n);
00300         }
00301 }
00302 
00303 // n is no longer a valid source, forward propagate this information to its heads
00304 void DefaultUnfoundedCheck::forwardUnsource(const BodyPtr& n, bool add) {
00305         for (const NodeId* x = n.node->heads_begin(); x != n.node->heads_end() && graph_->getAtom(*x).scc == n.node->scc; ++x) {
00306                 if (atoms_[*x].hasSource() && atoms_[*x].watch() == n.id) {
00307                         atoms_[*x].markSourceInvalid();
00308                         sourceQ_.push_back(*x);
00309                 }
00310                 if (add && atoms_[*x].watch() == n.id) {
00311                         pushTodo(*x);
00312                 }
00313         }
00314 }
00315 
00316 // sets body as source for head if necessary.
00317 // PRE: value(body) != value_false
00318 // POST: source(head) != 0
00319 void DefaultUnfoundedCheck::setSource(NodeId head, const BodyPtr& body) {
00320         assert(!solver_->isFalse(body.node->lit));
00321         // For normal rules from not false B follows not false head, but
00322         // for choice rules this is not the case. Therefore, the 
00323         // check for isFalse(head) is needed so that we do not inadvertantly
00324         // source a head that is currently false.
00325         if (!atoms_[head].hasSource() && !solver_->isFalse(graph_->getAtom(head).lit)) {
00326                 updateSource(atoms_[head], body);
00327                 sourceQ_.push_back(head);
00328         }
00329 }
00330 
00331 // This function is called for each body that became invalid during propagation.
00332 // Heads having the body as source have their source invalidated and are added
00333 // to the todo queue. Furthermore, source pointer removal is propagated forward
00334 void DefaultUnfoundedCheck::removeSource(NodeId bodyId) {
00335         const BodyNode& body = graph_->getBody(bodyId);
00336         for (const NodeId* x = body.heads_begin(); x != body.heads_end(); ++x) {
00337                 if (atoms_[*x].watch() == bodyId) {
00338                         if (atoms_[*x].hasSource()) {
00339                                 atoms_[*x].markSourceInvalid();
00340                                 sourceQ_.push_back(*x);
00341                         }
00342                         pushTodo(*x);
00343                 }
00344         }
00345         propagateSource();
00346 } 
00347 
00349 // DefaultUnfoundedCheck - Finding & propagating unfounded sets
00351 void DefaultUnfoundedCheck::updateAssignment(Solver& s) {
00352         assert(sourceQ_.empty() && ufs_.empty() && pickedExt_.empty());
00353         for (VarVec::const_iterator it = invalidQ_.begin(), end = invalidQ_.end(); it != end; ++it) {
00354                 uint32 index = (*it) >> 2;
00355                 uint32 type  = (*it) & 3u;
00356                 if (type == watch_source_false) { 
00357                         // a body became false - update atoms having the body as source
00358                         removeSource(index);
00359                 }
00360                 else if (type == watch_head_false) {
00361                         // an atom in the head of a choice rule became false
00362                         // normally head false -> body false and hence the head has its source autmatically removed
00363                         // for choice rules we must force source removal explicity
00364                         if (atoms_[index].hasSource() && !s.isFalse(graph_->getBody(atoms_[index].watch()).lit)) {
00365                                 atoms_[index].markSourceInvalid();
00366                                 graph_->getAtom(index).visitSuccessors(RemoveSource(this, true));
00367                                 propagateSource();
00368                         }
00369                 }
00370                 else if (type == watch_head_true) { 
00371                         // TODO: approx. ufs for disjunctive lp
00372                 }
00373                 else if (type == watch_subgoal_false) { // a literal p relevant to an extended body became false
00374                         assert(index < watches_.size());
00375                         const ExtWatch& w    = watches_[index];
00376                         const BodyNode& body = graph_->getBody(w.bodyId);
00377                         ExtData*        ext  = extended_[bodies_[w.bodyId].lower_or_ext];
00378                         ext->removeFromWs(w.data>>1, body.pred_weight(w.data>>1, test_bit(w.data, 0) != 0));
00379                         if (ext->lower > 0 && bodies_[w.bodyId].watches && !bodies_[w.bodyId].picked && !s.isFalse(body.lit)) {
00380                                 // The body is not a valid source but at least one head atom 
00381                                 // still depends on it: mark body as invalid source
00382                                 removeSource(w.bodyId);
00383                                 pickedExt_.push_back(w.bodyId);
00384                                 bodies_[w.bodyId].picked = 1;
00385                         }
00386                 }
00387         }
00388         for (VarVec::size_type i = 0, end = pickedExt_.size(); i != end; ++i) {
00389                 bodies_[pickedExt_[i]].picked = 0;
00390         }
00391         pickedExt_.clear();
00392         invalidQ_.clear();
00393 }
00394 
00395 DefaultUnfoundedCheck::UfsType DefaultUnfoundedCheck::findUfs(Solver& s, bool checkMin) {
00396         // first: remove all sources that were recently falsified
00397         updateAssignment(s);
00398         // second: try to re-establish sources.
00399         while (!todo_.empty()) {
00400                 NodeId head       = todo_.pop_ret();
00401                 atoms_[head].todo = 0;
00402                 if (!atoms_[head].hasSource() && !s.isFalse(graph_->getAtom(head).lit) && !findSource(head)) {
00403                         return ufs_poly;  // found an unfounded set - contained in unfounded_
00404                 }
00405                 assert(sourceQ_.empty());
00406         }
00407         todo_.clear();
00408         return !checkMin ? ufs_none : findNonHcfUfs(s);
00409 }
00410 
00411 // searches a new source for the atom node head.
00412 // If a new source is found the function returns true.
00413 // Otherwise the function returns false and unfounded_ contains head
00414 // as well as atoms with no source that circularly depend on head.
00415 bool DefaultUnfoundedCheck::findSource(NodeId headId) {
00416         assert(ufs_.empty() && invalidQ_.empty());
00417         const NodeId* bodyIt, *bodyEnd;
00418         uint32 newSource = 0;
00419         pushUfs(headId); // unfounded, unless we find a new source
00420         while (!ufs_.empty()) {
00421                 headId         = ufs_.pop_ret(); // still marked and in vector!
00422                 AtomData& head = atoms_[headId];
00423                 if (!head.hasSource()) {
00424                         const AtomNode& headNode = graph_->getAtom(headId);
00425                         for (bodyIt = headNode.bodies_begin(), bodyEnd = headNode.bodies_end(); bodyIt != bodyEnd; ++bodyIt) {
00426                                 BodyPtr bodyNode(getBody(*bodyIt));
00427                                 if (!solver_->isFalse(bodyNode.node->lit)) {
00428                                         if (bodyNode.node->scc != headNode.scc || isValidSource(bodyNode)) {
00429                                                 head.ufs = 0;               // found a new source,
00430                                                 setSource(headId, bodyNode);// set the new source
00431                                                 propagateSource();          // and propagate it forward
00432                                                 ++newSource;
00433                                                 break;
00434                                         }
00435                                         else { addUnsourced(bodyNode); }
00436                                 }
00437                         }
00438                         if (!head.hasSource()) { // still no source - check again once we are done
00439                                 invalidQ_.push_back(headId); 
00440                         }
00441                 }
00442                 else {  // head has a source and is thus not unfounded
00443                         ++newSource;
00444                         head.ufs = 0;
00445                 }
00446         } // while unfounded_.emtpy() == false
00447         ufs_.rewind();
00448         if (newSource != 0) {
00449                 // some atoms in unfounded_ have a new source
00450                 // clear queue and check possible candidates for atoms that are still unfounded
00451                 uint32 visited = ufs_.vec.size();
00452                 ufs_.clear();
00453                 if (visited != newSource) {
00454                         // add elements that are still unfounded
00455                         for (VarVec::iterator it = invalidQ_.begin(), end = invalidQ_.end(); it != end; ++it) {
00456                                 if ( (atoms_[*it].ufs = (1u - atoms_[*it].validS)) == 1 ) { ufs_.push(*it); }
00457                         }
00458                 }
00459         }
00460         invalidQ_.clear();
00461         return ufs_.empty();
00462 }
00463 
00464 // checks whether the body can source its heads
00465 bool DefaultUnfoundedCheck::isValidSource(const BodyPtr& n) {
00466         if (!n.node->extended()) {
00467                 return bodies_[n.id].lower_or_ext == 0;
00468         }
00469         ExtData* ext = extended_[bodies_[n.id].lower_or_ext];
00470         if (ext->lower > 0) {
00471                 // Since n is currently not a source, 
00472                 // we here know that no literal with a source can depend on this body.
00473                 // Hence, we can safely add all those literals to WS.
00474                 
00475                 // We check all internal literals here because there may be atoms
00476                 // that were sourced *after* we established the watch set.
00477                 const uint32 inc = n.node->pred_inc();
00478                 const NodeId* x  = n.node->preds();
00479                 uint32       p   = 0;
00480                 for (; *x != idMax; x += inc, ++p) {
00481                         if (atoms_[*x].hasSource() && !ext->inWs(p) && !solver_->isFalse(graph_->getAtom(*x).lit)) {
00482                                 ext->addToWs(p, n.node->pred_weight(p, false));
00483                         }
00484                 }
00485                 // We check all external literals here because we do not update
00486                 // the body on backtracking. Therefore some external literals that were false
00487                 // may now be true/free.
00488                 for (++x; *x != idMax; x += inc, ++p) {
00489                         if (!solver_->isFalse(Literal::fromRep(*x)) && !ext->inWs(p)) {
00490                                 ext->addToWs(p, n.node->pred_weight(p, true));
00491                         }
00492                 }
00493         }
00494         return ext->lower <= 0;
00495 }
00496 
00497 // enqueues all predecessors of this body that currently lack a source
00498 // PRE: isValidSource(n) == false
00499 void DefaultUnfoundedCheck::addUnsourced(const BodyPtr& n) {
00500         const uint32 inc = n.node->pred_inc();
00501         for (const NodeId* x = n.node->preds(); *x != idMax; x += inc) {
00502                 if (!atoms_[*x].hasSource() && !solver_->isFalse(graph_->getAtom(*x).lit)) {
00503                         pushUfs(*x);
00504                 }
00505         }
00506 }
00507 
00508 // falsifies the atoms one by one from the unfounded set stored in unfounded_
00509 bool DefaultUnfoundedCheck::falsifyUfs(UfsType t) {
00510         activeClause_.clear();
00511         while (!ufs_.empty()) {
00512                 Literal a = graph_->getAtom(ufs_.front()).lit;
00513                 if (!solver_->isFalse(a) && !(assertAtom(a, t) && solver_->propagateUntil(this))) {
00514                         if (t == ufs_non_poly) {
00515                                 mini_->schedNext(solver_->decisionLevel(), false);
00516                         }
00517                         break;
00518                 }
00519                 assert(solver_->isFalse(a));
00520                 atoms_[ufs_.pop_ret()].ufs = 0;
00521         }
00522         if (!loopAtoms_.empty()) {
00523                 createLoopFormula();
00524         }
00525         resetUfs();
00526         activeClause_.clear();
00527         return !solver_->hasConflict();
00528 }
00529 
00530 // asserts an unfounded atom using the selected reason strategy
00531 bool DefaultUnfoundedCheck::assertAtom(Literal a, UfsType t) {
00532         if (solver_->isTrue(a) || strategy_ == distinct_reason || activeClause_.empty()) {
00533                 // Conflict, first atom of unfounded set, or distinct reason for each atom requested -
00534                 // compute reason for a being unfounded.
00535                 // We must flush any not yet created loop formula here - the
00536                 // atoms in loopAtoms_ depend on the current reason which is about to be replaced. 
00537                 if (!loopAtoms_.empty()) { 
00538                         createLoopFormula(); 
00539                 }
00540                 activeClause_.assign(1, ~a);
00541                 computeReason(t);
00542         }
00543         activeClause_[0] = ~a;
00544         bool noClause = solver_->isTrue(a) || strategy_ == no_reason || strategy_ == only_reason || (strategy_ == shared_reason && activeClause_.size() > 3);
00545         if (noClause) {
00546                 if (!solver_->force(~a, this))  { return false; }
00547                 if (strategy_ == only_reason)   { reasons_[a.var()-1].assign(activeClause_.begin()+1, activeClause_.end()); }
00548                 else if (strategy_ != no_reason){ loopAtoms_.push_back(~a); }
00549                 return true;
00550         }
00551         else { // learn nogood and assert ~a
00552                 return ClauseCreator::create(*solver_, activeClause_, ClauseCreator::clause_no_prepare, info_).ok();
00553         }
00554 }
00555 void DefaultUnfoundedCheck::createLoopFormula() {
00556         assert(activeClause_.size() > 3);
00557         if (loopAtoms_.size() == 1) {
00558                 activeClause_[0] = loopAtoms_[0];
00559                 Constraint* ante = ClauseCreator::create(*solver_, activeClause_, ClauseCreator::clause_no_prepare, info_).local;
00560                 assert(ante != 0 && solver_->isTrue(loopAtoms_[0]) && solver_->reason(loopAtoms_[0]) == this);
00561                 solver_->setReason(loopAtoms_[0], ante);
00562         }
00563         else {
00564                 Activity act(info_.activity(), info_.lbd());
00565                 LoopFormula* lf = LoopFormula::newLoopFormula(*solver_, &activeClause_[1], (uint32)activeClause_.size() - 1, (uint32)0, (uint32)loopAtoms_.size(), act); 
00566                 solver_->addLearnt(lf, lf->size(), Constraint_t::learnt_loop);
00567                 for (VarVec::size_type i = 0; i < loopAtoms_.size(); ++i) {
00568                         assert(solver_->isTrue(loopAtoms_[i]) && solver_->reason(loopAtoms_[i]) == this);
00569                         solver_->setReason(loopAtoms_[i], lf);
00570                         lf->addAtom(loopAtoms_[i], *solver_);
00571                 }
00572                 lf->updateHeuristic(*solver_);
00573         }
00574         loopAtoms_.clear();
00575 }
00576 
00577 // computes the reason why a set of atoms is unfounded
00578 void DefaultUnfoundedCheck::computeReason(UfsType t) {
00579         if (strategy_ == no_reason) { return; }
00580         uint32 ufsScc = graph_->getAtom(ufs_.front()).scc;
00581         for (VarVec::size_type i = ufs_.qFront; i != ufs_.vec.size(); ++i) {
00582                 const AtomNode& atom = graph_->getAtom(ufs_.vec[i]);
00583                 if (!solver_->isFalse(atom.lit)) {
00584                         assert(atom.scc == ufsScc);
00585                         for (const NodeId* x = atom.bodies_begin(); x != atom.bodies_end(); ++x) {
00586                                 BodyPtr body(getBody(*x));
00587                                 if (t == ufs_poly || !body.node->delta()){ addIfReason(body, ufsScc); }
00588                                 else                                     { addDeltaReason(body, ufsScc); }
00589                         }
00590                 }
00591         }
00592         for (VarVec::size_type i = 0; i != pickedExt_.size(); ++i) { bodies_[pickedExt_[i]].picked = 0; }
00593         pickedExt_.clear();
00594         info_     = ClauseInfo(Constraint_t::learnt_loop);
00595         uint32 rc = !solver_->isFalse(activeClause_[0]) && activeClause_.size() > 100 && activeClause_.size() > (solver_->decisionLevel() * 10);
00596         uint32 dl = solver_->finalizeConflictClause(activeClause_, info_, rc);
00597         uint32 cDL= solver_->decisionLevel();
00598         assert((t == ufs_non_poly || dl == cDL) && "Loop nogood must contain a literal from current DL!");
00599         if (dl < cDL && (dl = solver_->undoUntil(dl, false)) < cDL) {
00600                 // cancel any active propagation on cDL
00601                 invalidQ_.clear();
00602                 for (PostPropagator* n = this->next; n; n = n->next) { n->reset(); }
00603         }
00604 }
00605 
00606 void DefaultUnfoundedCheck::addDeltaReason(const BodyPtr& n, uint32 uScc) {
00607         if (bodies_[n.id].picked != 0) return;
00608         uint32 bodyAbst = solver_->isFalse(n.node->lit) ? solver_->level(n.node->lit.var()) : solver_->decisionLevel() + 1;
00609         for (const NodeId* x = n.node->heads_begin(); x != n.node->heads_end(); ++x) {
00610                 if (*x != SharedDependencyGraph::sentinel_atom) { // normal head
00611                         if (graph_->getAtom(*x).scc == uScc) {
00612                                 addIfReason(n, uScc);
00613                         }
00614                         continue;
00615                 }
00616                 else { // disjunctive head
00617                         uint32  reasonAbst= bodyAbst;
00618                         Literal reasonLit = n.node->lit;
00619                         bool    inUfs     = false;
00620                         Literal aLit;
00621                         for (++x; *x; ++x) {
00622                                 if (atoms_[*x].ufs == 1) {
00623                                         inUfs = true;
00624                                 }
00625                                 else if (solver_->isTrue(aLit = graph_->getAtom(*x).lit) && solver_->level(aLit.var()) < reasonAbst) {
00626                                         reasonLit  = ~aLit;
00627                                         reasonAbst = solver_->level(reasonLit.var());
00628                                 }
00629                         }
00630                         if (inUfs && reasonAbst && reasonAbst <= solver_->decisionLevel()) {
00631                                 addReasonLit(reasonLit);
00632                         }
00633                 }
00634         }
00635         bodies_[n.id].picked = 1;
00636         pickedExt_.push_back(n.id);
00637 }
00638 // check if n is part of the reason for the current unfounded set
00639 void DefaultUnfoundedCheck::addIfReason(const BodyPtr& n, uint32 uScc) {
00640         if (solver_->isFalse(n.node->lit)) {
00641                 if (n.node->scc != uScc) {
00642                         addReasonLit(n.node->lit);
00643                 }
00644                 else if (!solver_->seen(n.node->lit)) {
00645                         if (!n.node->extended()) {
00646                                 // body is only a reason if it does not depend on the atoms from the unfounded set
00647                                 for (const NodeId* x = n.node->preds(); *x != idMax; ++x) {
00648                                         if (atoms_[*x].ufs && !solver_->isFalse(graph_->getAtom(*x).lit)) {
00649                                                 // TODO: add to picked?
00650                                                 return;
00651                                         }
00652                                 }
00653                                 addReasonLit(n.node->lit);
00654                         }
00655                         else if (bodies_[n.id].picked == 0) {
00656                                 bodies_[n.id].picked = 1;
00657                                 pickedExt_.push_back(n.id);
00658                                 // Check if the body depends on the atoms from the unfounded set. I.e.
00659                                 // would the body still be false if all but its unfounded literals would be true?
00660                                 ExtData* ext     = extended_[bodies_[n.id].lower_or_ext];
00661                                 weight_t temp    = ext->lower;
00662                                 const NodeId* x  = n.node->preds();
00663                                 const uint32 inc = n.node->pred_inc();
00664                                 uint32       p   = 0;
00665                                 for (; *x != idMax; x += inc, ++p) {
00666                                         if (!ext->inWs(p) && (atoms_[*x].ufs == 0 || solver_->isFalse(graph_->getAtom(*x).lit))) {
00667                                                 if ( (temp -= n.node->pred_weight(p, false)) <= 0 ) {
00668                                                         addReasonLit(n.node->lit);
00669                                                         return;
00670                                                 }
00671                                         }
00672                                 }
00673                                 for (++x; *x != idMax; x += inc, ++p) {
00674                                         if (!ext->inWs(p) && (temp -= n.node->pred_weight(p, true)) <= 0) {
00675                                                 addReasonLit(n.node->lit);
00676                                                 return;
00677                                         }
00678                                 }
00679                         }
00680                 }
00681         }
00682         else if (n.node->scc == uScc && n.node->extended() && bodies_[n.id].picked == 0) {
00683                 bodies_[n.id].picked = 1;
00684                 pickedExt_.push_back(n.id);
00685                 // body is neither false nor a valid source - add all false lits to reason set
00686                 AddReasonLit addFalseLits = { this };
00687                 graph_->visitBodyLiterals(*n.node, addFalseLits);
00688         }
00689 }
00690 
00691 void DefaultUnfoundedCheck::addReasonLit(Literal p) {
00692         if (!solver_->seen(p)) {
00693                 solver_->markSeen(p);
00694                 solver_->markLevel(solver_->level(p.var()));
00695                 activeClause_.push_back(p);
00696                 if (solver_->level(p.var()) > solver_->level(activeClause_[1].var())) {
00697                         std::swap(activeClause_[1], activeClause_.back());
00698                 }
00699         }
00700 }
00701 
00703 // DefaultUnfoundedCheck - Minimality check for disjunctive logic programs
00705 DefaultUnfoundedCheck::UfsType DefaultUnfoundedCheck::findNonHcfUfs(Solver& s) {
00706         assert(invalidQ_.empty() && loopAtoms_.empty());
00707         for (SharedDependencyGraph::NonHcfIter it = graph_->nonHcfBegin(), end = graph_->nonHcfEnd(); it != end; ++it) {
00708                 s.stats.addTest(s.numFreeVars() != 0);
00709                 it->second->assumptionsFromAssignment(s, loopAtoms_);
00710                 if (!it->second->test(it->first, s, loopAtoms_, invalidQ_) || s.hasConflict()) {
00711                         uint32 pos = 0, minDL = 0;
00712                         for (VarVec::const_iterator it = invalidQ_.begin(), end = invalidQ_.end(); it != end; ++it) {
00713                                 if (s.isTrue(graph_->getAtom(*it).lit) && s.level(graph_->getAtom(*it).lit.var()) < minDL) {
00714                                         minDL = s.level(graph_->getAtom(*it).lit.var());
00715                                         pos   = (uint32)ufs_.vec.size();
00716                                 }
00717                                 pushUfs(*it);
00718                         }
00719                         if (pos) {
00720                                 std::swap(ufs_.vec.front(), ufs_.vec[pos]);
00721                         }
00722                         invalidQ_.clear();
00723                         loopAtoms_.clear();
00724                         return ufs_non_poly;
00725                 }
00726                 loopAtoms_.clear();
00727         }
00728         mini_->schedNext(s.decisionLevel(), true);
00729         return ufs_none;
00730 }
00731 
00732 DefaultUnfoundedCheck::MinimalityCheck::MinimalityCheck(const FwdCheck& afwd) : fwd(afwd), high(UINT32_MAX), low(0), next(0) {  
00733         if (fwd.highPct > 100) { fwd.highPct = 100; }
00734         if (fwd.initHigh != 0) { high        = fwd.initHigh; }
00735 }
00736 
00737 bool DefaultUnfoundedCheck::MinimalityCheck::partialCheck(uint32 level) { 
00738         if (level < low) {
00739                 next -= (low - level);
00740                 low   = level;
00741         }
00742         return !next || next == level;
00743 }
00744 
00745 void DefaultUnfoundedCheck::MinimalityCheck::schedNext(uint32 level, bool ok) {
00746         low  = 0;
00747         next = UINT32_MAX;
00748         if (!ok) {
00749                 high = level;
00750                 next = 0;
00751         }
00752         else if (fwd.highPct != 0) {
00753                 double p = fwd.highPct / 100.0;
00754                 high     = std::max(high, level);
00755                 low      = level;
00756                 if (low >= high && fwd.incHigh) {
00757                         high   = (uint32)std::ceil(low + (low * p));
00758                 }
00759                 next     = low + (uint32)std::ceil((high - low) * p);
00760         }
00761 }
00762 }


clasp
Author(s): Benjamin Kaufmann
autogenerated on Thu Aug 27 2015 12:41:40