asp_preprocessor.cpp
Go to the documentation of this file.
00001 // 
00002 // Copyright (c) 2006-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 #include <clasp/asp_preprocessor.h>
00021 #include <clasp/logic_program.h>
00022 #include <clasp/shared_context.h>
00023 namespace Clasp { namespace Asp {
00025 // simple preprocessing
00026 //
00027 // Simplifies the program by computing max consequences.
00028 // Then assign variables to non-trivial supported bodies and atoms.
00030 bool Preprocessor::preprocessSimple() {
00031         if (!prg_->propagate(true)) { return false; }
00032         uint32 startVar = prg_->ctx()->numVars() + 1;
00033         // start with initially supported bodies
00034         VarVec& supported = prg_->getSupportedBodies(true);
00035         for (VarVec::size_type i = 0; i < supported.size(); ++i) {
00036                 PrgBody* b = prg_->getBody(supported[i]);
00037                 // set up body
00038                 if (!b->simplify(*prg_, false)) { return false; }
00039                 if (b->var() < startVar)        { b->assignVar(*prg_); }
00040                 // add all heads of b to the "upper"-closure
00041                 if (!addHeadsToUpper(b))        { return false; }
00042         }
00043         return prg_->propagate();
00044 }
00045 
00046 bool Preprocessor::addHeadToUpper(PrgHead* head, PrgEdge h, PrgEdge support) {
00047         assert(head->relevant() && !head->inUpper());
00048         head->simplifySupports(*prg_, false);
00049         head->assignVar(*prg_, support);
00050         head->clearSupports();
00051         head->setInUpper(true);
00052         if (head->isAtom()) {
00053                 return propagateAtomVar(h.node(), static_cast<PrgAtom*>(head), support);
00054         }
00055         // add all unseen atoms of disjunction to upper
00056         assert(h.isDisj());
00057         PrgDisj* d  = static_cast<PrgDisj*>(head);
00058         support     = PrgEdge::newEdge(h.node(), PrgEdge::CHOICE_EDGE, PrgEdge::DISJ_NODE);
00059         bool ok     = true;
00060         for (PrgDisj::atom_iterator it = d->begin(), end = d->end(); it != end && ok; ++it) {
00061                 assert(it->isChoice() && it->isAtom());
00062                 PrgAtom* at = prg_->getAtom(it->node());
00063                 if (!at->relevant()) { continue; }
00064                 if (!at->inUpper())  { ok = addHeadToUpper(at, *it, support); }
00065                 at->addSupport(support);
00066         }
00067         return ok;
00068 }
00070 // equivalence preprocessing
00071 //
00072 // Computes max consequences and minimizes the number of necessary variables 
00073 // by computing equivalence-classes.
00075 bool Preprocessor::preprocessEq(uint32 maxIters) {
00076         uint32 startVar = prg_->ctx()->numVars() + 1;
00077         ValueRep res    = value_true;
00078         pass_           = 0;
00079         maxPass_        = maxIters;
00080         HeadRange atoms = HeadRange(prg_->atom_begin() + prg_->startAtom(), prg_->atom_end());
00081         bodyInfo_.resize( prg_->numBodies() + 1 );
00082         do {
00083                 if (++pass_ > 1) {
00084                         for (HeadIter it = prg_->atom_begin(), end = atoms.second; it != end; ) {
00085                                 while (it != atoms.first){ (*it)->setInUpper(false); ++it; }
00086                                 while (it != end)        { (*it)->clearLiteral(false); (*it)->setInUpper(false); ++it; }
00087                         }
00088                         for (HeadIter it = prg_->disj_begin(), end = prg_->disj_end(); it != end; ++it) {
00089                                 (*it)->clearLiteral(false);
00090                                 (*it)->setInUpper(false);
00091                         }
00092                         prg_->ctx()->resizeVars(startVar);
00093                         litToNode_.clear();
00094                 }
00095                 VarVec& supported = prg_->getSupportedBodies(true);
00096                 if (!classifyProgram(supported)) { return false; }
00097                 res = simplifyClassifiedProgram(atoms, pass_ != maxPass_, supported);
00098         } while (res == value_free && pass_ != maxPass_);
00099         return res != value_false;
00100 }
00101 
00102 // Computes necessary equivalence-classes starting from the supported bodies
00103 // of a program.
00104 bool Preprocessor::classifyProgram(const VarVec& supported) {
00105         Var bodyId; PrgBody* body;
00106         VarVec::size_type index = 0;
00107         follow_.clear();
00108         if (!prg_->propagate(true)) { return false; }
00109         for (VarVec::size_type i = 0;;) {
00110                 while ( (bodyId = nextBodyId(index)) != varMax ) {
00111                         body        = addBodyVar(bodyId);
00112                         if (prg_->hasConflict())    { return false; }
00113                         if (!addHeadsToUpper(body)) { return false; }
00114                 }
00115                 follow_.clear();
00116                 index = 0;
00117                 // select next unclassified supported body
00118                 for (; i < supported.size(); ++i) {
00119                         bodyId  = supported[i];
00120                         body    = prg_->getBody(bodyId);
00121                         if (bodyInfo_[bodyId].bSeen == 0 && body->relevant()) {
00122                                 follow_.push_back(bodyId);
00123                                 break;
00124                         }
00125                         else if (!body->relevant() && body->hasVar()) {
00126                                 body->clearLiteral(false);
00127                         }
00128                 }
00129                 if (follow_.empty()) break;
00130         }
00131         return !prg_->hasConflict();
00132 }
00133 
00134 ValueRep Preprocessor::simplifyClassifiedProgram(const HeadRange& atoms, bool more, VarVec& supported) {
00135         ValueRep res = value_true, simp;
00136         if (!prg_->propagate()) { return value_false; }
00137         supported.clear();
00138         // simplify supports
00139         for (uint32 i = 0; i != prg_->numBodies(); ++i) {
00140                 PrgBody* b = prg_->getBody(i);
00141                 if (bodyInfo_[i].bSeen == 0 || !b->relevant()) {
00142                         // !bodyInfo_[i].bSeen: body is unsupported
00143                         // !b->relevant()     : body is eq to other body or was derived to false
00144                         // In either case, body is no longer relevant and can be ignored.
00145                         b->clearLiteral(true); 
00146                         b->markRemoved();
00147                 }
00148                 else if ( (simp = simplifyBody(b, more, supported)) != value_true ) {
00149                         if (simp == value_false) { return simp; }
00150                         res = value_free;
00151                 }
00152         }
00153         if (!prg_->propagate()) { return value_false; }
00154         for (LogicProgram::VarIter it = prg_->unfreeze_begin(), end = prg_->unfreeze_end(); it != end; ++it) {
00155                 PrgAtom* a = prg_->getAtom(*it);
00156                 ValueRep v = a->value();
00157                 if      (!a->simplifySupports(*prg_, true)){ return value_false; }
00158                 else if (!a->inUpper() && v != value_false){
00159                         if (!prg_->assignValue(a, value_false))  { return value_false; }
00160                         if (more && a->hasDep(PrgAtom::dep_all)) { res = value_free; }
00161                 }
00162         }
00163         if (!prg_->propagate()) { return value_false; }
00164         bool strong = more && res == value_true;
00165         HeadRange heads[2] = { HeadRange(prg_->disj_begin(), prg_->disj_end()), atoms };
00166         for (const HeadRange* range = heads, *endR = heads+2; range != endR; ++range) {
00167                 for (HeadIter it = range->first, end = range->second; it != end; ++it) {
00168                         PrgHead* head = *it;
00169                         if ((simp = simplifyHead(head, strong)) != value_true) {
00170                                 if      (simp == value_false){ return simp; }
00171                                 else if (strong)             { strong = false; res = value_free; }
00172                         }
00173                 }
00174         }
00175         if (!prg_->propagate()) { res = value_false; }
00176         return res;
00177 }
00178 
00179 // associates a variable with the body if necessary
00180 PrgBody* Preprocessor::addBodyVar(Var bodyId) {
00181         // make sure we don't add an irrelevant body
00182         PrgBody* body = prg_->getBody(bodyId);
00183         assert((body->isSupported() && !body->eq()) || body->hasVar());
00184         body->clearLiteral(false);    // clear var in case we are iterating
00185         bodyInfo_[bodyId].bSeen = 1;  // mark as seen, so we don't classify the body again
00186         bool   known = bodyInfo_[bodyId].known == body->size();
00187         uint32 eqId;
00188         if (!body->simplifyBody(*prg_, known, &eqId) || !body->simplifyHeads(*prg_, false)) {
00189                 prg_->setConflict();
00190                 return body;
00191         }
00192         if ((!body->hasHeads() && body->value() != value_false) || !body->relevant()) {
00193                 body->markRemoved();
00194                 return body;
00195         }
00196         if (eqId == bodyId) {
00197                 // The body is unique
00198                 body->assignVar(*prg_);
00199                 if      (!known)            { body->markDirty(); }
00200                 else if (body->size() == 1) {
00201                         // Body is equivalent to an atom or its negation
00202                         // Check if the atom is itself equivalent to a body. 
00203                         // If so, the body is equivalent to the atom's body.
00204                         PrgAtom* a = prg_->getAtom(body->goal(0).var()); // eq-Atom
00205                         PrgBody* r = 0; // possible eq-body
00206                         uint32 rId = varMax;
00207                         assert(a->var() == body->var());
00208                         if (body->goal(0).sign()) {
00209                                 Var dualAtom = getRootAtom(body->literal());
00210                                 a = dualAtom != varMax ? prg_->getAtom(dualAtom) : 0;
00211                         }
00212                         if (a && a->supps_begin()->isBody()) {
00213                                 rId = a->supps_begin()->node();
00214                                 r   = prg_->getBody(rId);       
00215                                 if (r && r->var() == a->var()) {
00216                                         mergeEqBodies(body, rId, false);
00217                                 }
00218                         }
00219                 }
00220         }
00221         else {
00222                 // body is eq to eq body
00223                 mergeEqBodies(body, eqId, true);
00224         }
00225         return body;
00226 }
00227 
00228 // Adds all heads of body to the upper closure if not yet present and
00229 // associates variables with the heads if necessary.
00230 // The body b is the supported body that provides a support for the heads.
00231 // RETURN: true if no conflict
00232 // POST  : the addition of atoms to the closure was propagated
00233 bool Preprocessor::addHeadsToUpper(PrgBody* body) {
00234         PrgHead* head;
00235         PrgEdge  support;
00236         bool ok  = !prg_->hasConflict();
00237         int dirty= 0;
00238         for (PrgBody::head_iterator it = body->heads_begin(), end = body->heads_end(); it != end && ok; ++it) {
00239                 head   = prg_->getHead(*it);
00240                 support= PrgEdge::newEdge(body->id(), it->type(), PrgEdge::BODY_NODE);
00241                 if (head->relevant() && head->value() != value_false) {
00242                         if (body->value() == value_true && head->isAtom()) {
00243                                 // Since b is true, it is always a valid support for head, head can never become unfounded. 
00244                                 // So ignore it during SCC check and unfounded set computation.
00245                                 head->setIgnoreScc(true);
00246                                 if (support.isNormal() && head->isAtom()) {
00247                                         ok = propagateAtomValue(static_cast<PrgAtom*>(head), value_true);
00248                                 }
00249                         }
00250                         if (!head->inUpper()) {
00251                                 // first time we see this head - assign var...
00252                                 ok = addHeadToUpper(head, *it, support);
00253                         }
00254                         else if (head->supports() && head->supps_begin()->isNormal()) {
00255                                 PrgEdge source = *head->supps_begin();
00256                                 assert(source.isBody());
00257                                 if (prg_->getBody(source.node())->var() == body->var()) {
00258                                         // Check if we really need a new variable for head.
00259                                         head->markDirty();
00260                                 }
00261                         }
00262                         head->addSupport(support, PrgHead::no_simplify);
00263                 }
00264                 dirty += (head->eq() || head->value() == value_false);
00265         }
00266         if (dirty) {
00267                 // remove eq atoms from head
00268                 prg_->getBody(body->id())->markHeadsDirty();
00269         }
00270         return ok;
00271 }
00272 
00273 // Propagates that a was added to the "upper"-closure.
00274 // If atom a has a truth-value or is eq to a', we'll remove
00275 // it from all bodies. If there is an atom x, s.th. a.lit == ~x.lit, we mark all
00276 // bodies containing both a and x for simplification in order to detect
00277 // duplicates/contradictory body-literals.
00278 // In case that a == a', we also mark all bodies containing a
00279 // for head simplification in order to detect rules like: a' :- a,B. and a' :- B,not a.
00280 bool Preprocessor::propagateAtomVar(Var atomId, PrgAtom* a, PrgEdge source) {
00281         PrgAtom* comp     = 0;
00282         bool fullEq       = eq();
00283         bool removeAtom   = a->value() == value_true || a->value() == value_false;
00284         bool removeNeg    = removeAtom  || a->value() == value_weak_true;
00285         Literal aLit      = a->literal();
00286         if (fullEq) {
00287                 if (getRootAtom(aLit) == varMax) {
00288                         setRootAtom(aLit, atomId);
00289                 }
00290                 else if (prg_->mergeEqAtoms(a, getRootAtom(aLit))) {
00291                         assert(source.isBody());
00292                         removeAtom = true;
00293                         removeNeg  = true;
00294                         PrgBody* B = prg_->getBody(source.node());
00295                         a->setEqGoal(posLit(a->id()));
00296                         // set positive eq goal - replace if a == {not a'}, replace a with not a' in bodies
00297                         if (getRootAtom(~aLit) != varMax && B->literal() == aLit && B->size() == 1 && B->goal(0).sign()) {
00298                                 a->setEqGoal(B->goal(0));
00299                         }
00300                         a->clearLiteral(true); // equivalent atoms don't need vars
00301                 }
00302                 else { return false; }
00303         }
00304         if (getRootAtom(~aLit) != varMax) {
00305                 PrgAtom* negA = prg_->getAtom(getRootAtom(~aLit));
00306                 assert(aLit == ~negA->literal());
00307                 // propagate any truth-value to complementary eq-class
00308                 ValueRep cv   = value_free;
00309                 uint32   mark = 0;
00310                 if (a->value() != value_free && (cv = (value_false | (a->value()^value_true))) != negA->value()) {
00311                         mark        = 1;
00312                         if (!propagateAtomValue(negA, cv)) {
00313                                 return false;
00314                         }
00315                 }
00316                 if ( !removeAtom ) {
00317                         for (PrgAtom::dep_iterator it = (comp=negA)->deps_begin(); it != comp->deps_end(); ++it) {
00318                                 bodyInfo_[it->var()].mBody = 1;
00319                                 if (mark) { prg_->getBody(it->var())->markDirty(); }
00320                         }
00321                 }
00322         }
00323         for (PrgAtom::dep_iterator it = a->deps_begin(), end = a->deps_end(); it != end; ++it) {
00324                 Var bodyId  = it->var();
00325                 PrgBody* bn = prg_->getBody(bodyId);
00326                 if (bn->relevant()) {
00327                         bool wasSup = bn->isSupported();        
00328                         bool isSup  = wasSup || (a->value() != value_false && !it->sign() && bn->propagateSupported(atomId));
00329                         bool seen   = false;
00330                         bool dirty  = removeAtom || (removeNeg && it->sign());
00331                         if (fullEq) {
00332                                 seen      = bodyInfo_[bodyId].bSeen != 0;
00333                                 dirty    |= bodyInfo_[bodyId].mBody == 1;
00334                                 if (++bodyInfo_[bodyId].known == bn->size() && !seen && isSup) {
00335                                         follow_.push_back( bodyId );
00336                                         seen    = true;
00337                                 }
00338                         }
00339                         if (!seen && isSup && !wasSup) {
00340                                 prg_->getSupportedBodies(false).push_back(bodyId);
00341                         }
00342                         if (dirty) {
00343                                 bn->markDirty();
00344                                 if (a->eq()) {
00345                                         bn->markHeadsDirty();
00346                                 }
00347                         }
00348                 }
00349         }
00350         if      (removeAtom) { a->clearDeps(PrgAtom::dep_all); }
00351         else if (removeNeg)  { a->clearDeps(PrgAtom::dep_neg); }
00352         if (comp) {
00353                 for (PrgAtom::dep_iterator it = comp->deps_begin(), end = comp->deps_end(); it != end; ++it) {
00354                         bodyInfo_[it->var()].mBody = 0;
00355                 }
00356         }
00357         return true;
00358 }
00359 
00360 // Propagates the assignment of val to a.
00361 bool Preprocessor::propagateAtomValue(PrgAtom* atom, ValueRep val) {
00362         // No backpropagation possible because supports are not yet fully established.
00363         return prg_->assignValue(atom, val) && prg_->propagate(false);
00364 }
00365 
00366 bool Preprocessor::mergeEqBodies(PrgBody* body, Var rootId, bool equalLits) {
00367         PrgBody* root = prg_->mergeEqBodies(body, rootId, equalLits, false);
00368         if (root && root != body && bodyInfo_[root->id()].bSeen == 0) {
00369                 // If root is not yet classified, we can ignore body.
00370                 // The heads of body are added to the "upper"-closure
00371                 // once root is eventually classified.
00372                 body->clearHeads();
00373                 body->markRemoved();
00374         }
00375         return root != 0;
00376 }
00377 
00378 bool Preprocessor::hasRootLiteral(PrgBody* body) const {
00379         return body->size() >= 1
00380                 && getRootAtom(body->literal()) == varMax
00381                 && getRootAtom(~body->literal())== varMax;
00382 }
00383 
00384 // Simplify the classified body with the given id.
00385 // Return:
00386 //  value_false    : conflict
00387 //  value_true     : ok
00388 //  value_weak_true: ok but program should be reclassified
00389 ValueRep Preprocessor::simplifyBody(PrgBody* b, bool reclass, VarVec& supported) {
00390         assert(b->relevant() && bodyInfo_[b->id()].bSeen == 1);
00391         bodyInfo_[b->id()].bSeen = 0;
00392         bodyInfo_[b->id()].known = 0;
00393         bool   hadHeads = b->hasHeads();
00394         uint32 eqId     = b->id();
00395         if (!b->simplify(*prg_, true, &eqId)) {
00396                 return value_false;
00397         }
00398         ValueRep ret = value_true;
00399         if (reclass) {
00400                 if (hadHeads && b->value() == value_false) {
00401                         assert(b->hasHeads() == false);
00402                         // New false body. If it was derived to false, we can ignore the body.
00403                         // Otherwise, we have a new integrity constraint. 
00404                         if (!b->relevant()) {
00405                                 b->clearLiteral(true);
00406                         }
00407                 }
00408                 else if (!b->hasHeads() && b->value() != value_false && b->var() != 0) {
00409                         // Body is no longer needed. All heads are either superfluous or equivalent
00410                         // to other atoms. 
00411                         // Reclassify only if var is not used
00412                         if (getRootAtom(b->literal()) == varMax) { ret = value_weak_true; }
00413                         b->clearLiteral(true);
00414                         b->markRemoved();
00415                 }
00416                 else if (b->value() == value_true && b->var() != 0) {
00417                         // New fact body
00418                         for (PrgBody::head_iterator it = b->heads_begin(), end = b->heads_end(); it != end; ++it) {
00419                                 if (it->isNormal() && prg_->getHead(*it)->var() != 0) {
00420                                         ret = value_weak_true;
00421                                         break;
00422                                 }
00423                         }
00424                         b->markDirty();
00425                 }
00426         }
00427         if (b->relevant() && eqId != b->id() && (reclass || prg_->getBody(eqId)->var() == b->var())) {
00428                 // Body is now eq to some other body - reclassify if body var is not needed
00429                 Var  bVar       = b->var();
00430                 bool rootVar    = hasRootLiteral(b);
00431                 PrgBody* eqBody = prg_->mergeEqBodies(b, eqId, true, true);
00432                 if (eqBody && rootVar && bVar != eqBody->var()) {
00433                         ret = value_weak_true;
00434                 }
00435         }
00436         if (b->relevant() && b->resetSupported()) {
00437                 supported.push_back(b->id());
00438         }
00439         return ret;
00440 }
00441 
00442 // Simplify the classified head h.
00443 // Update list of bodies defining this head and check
00444 // if atom or disjunction has a distinct var although it is eq to some body.
00445 // Return:
00446 //  value_false    : conflict
00447 //  value_true     : ok
00448 //  value_weak_true: ok but atom should be reclassified
00449 ValueRep Preprocessor::simplifyHead(PrgHead* h, bool more) {
00450         if (!h->hasVar() || !h->relevant()) {
00451                 // unsupported or eq
00452                 h->clearLiteral(false);
00453                 h->markRemoved();
00454                 h->clearSupports();
00455                 h->setInUpper(false);
00456                 return value_true;
00457         }
00458         assert(h->inUpper());
00459         ValueRep v       = h->value();
00460         ValueRep ret     = value_true;
00461         PrgEdge support  = h->supports() ? *h->supps_begin() : PrgEdge::noEdge();
00462         uint32 numSuppLits= 0;
00463         if (!h->simplifySupports(*prg_, true, &numSuppLits)) {
00464                 return value_false;
00465         }
00466         if (v != h->value() && (h->value() == value_false || (h->value() == value_true && h->var() != 0))) {
00467                 ret = value_weak_true;
00468         }
00469         if (more) {
00470                 if (numSuppLits == 0 && h->hasVar()) {
00471                         // unsupported head does not need a variable
00472                         ret = value_weak_true;
00473                 }
00474                 else if (h->supports() > 0 && h->supps_begin()->rep != support.rep) {
00475                         // support for head has changed
00476                         ret = value_weak_true;
00477                 }
00478                 else if ((support.isNormal() && h->supports() == 1) || (h->supports() > 1 && numSuppLits == 1 && h->isAtom())) {
00479                         assert(support.isBody());
00480                         PrgBody* supBody = prg_->getBody(support.node());
00481                         if (supBody->literal() != h->literal()) {
00482                                 if (h->supports() > 1) {
00483                                         // atom is equivalent to one of its bodies
00484                                         EdgeVec temp(h->supps_begin(), h->supps_end());
00485                                         h->clearSupports();
00486                                         support = temp[0];
00487                                         for (EdgeIterator it = temp.begin(), end = temp.end(); it != end; ++it) {
00488                                                 assert(!it->isDisj());
00489                                                 PrgBody* B = prg_->getBody(it->node());
00490                                                 if (it->isNormal() && B->size() == 1 && B->goal(0).sign()) {
00491                                                         support = *it;
00492                                                 }
00493                                                 B->removeHead(h, it->type());
00494                                         }
00495                                         supBody = prg_->getBody(support.node());
00496                                         supBody->addHead(h, support.type());
00497                                         if (!supBody->simplifyHeads(*prg_, true)) {
00498                                                 return value_false;
00499                                         }
00500                                 }
00501                                 ret = value_weak_true;
00502                                 if (h->value() == value_weak_true || h->value() == value_true) {
00503                                         supBody->assignValue(h->value());
00504                                         supBody->propagateValue(*prg_, true);
00505                                 }
00506                         }
00507                 }
00508         }
00509         return ret;
00510 }
00511 
00512 } }


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