00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #if defined(_MSC_VER)
00021 #pragma warning (disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
00022 #pragma warning (disable : 4996) // 'std::_Fill_n' was declared deprecated
00023 #endif
00024
00025 #include <clasp/logic_program.h>
00026 #include <clasp/shared_context.h>
00027 #include <clasp/solver.h>
00028 #include <clasp/minimize_constraint.h>
00029 #include <clasp/util/misc_types.h>
00030 #include <clasp/asp_preprocessor.h>
00031 #include <clasp/clause.h>
00032 #include <clasp/dependency_graph.h>
00033 #include <clasp/parser.h>
00034 #include <stdexcept>
00035 #include <sstream>
00036 #include <climits>
00037 namespace Clasp { namespace Asp {
00039
00041 void LpStats::reset() {
00042 std::memset(this, 0, sizeof(LpStats));
00043 }
00044 uint32 LpStats::rules() const {
00045 uint32 sum = 0;
00046 for (uint32 i = 0; i != NUM_RULE_TYPES; ++i) { sum += rules_[i].second; }
00047 return sum;
00048 }
00049 void LpStats::accu(const LpStats& o) {
00050 bodies += o.bodies;
00051 atoms += o.atoms;
00052 auxAtoms += o.auxAtoms;
00053 ufsNodes += o.ufsNodes;
00054 if (sccs == PrgNode::noScc || o.sccs == PrgNode::noScc) {
00055 sccs = o.sccs;
00056 nonHcfs = o.nonHcfs;
00057 }
00058 else {
00059 sccs += o.sccs;
00060 nonHcfs+= o.nonHcfs;
00061 }
00062 for (int i = 0; i != sizeof(eqs_)/sizeof(eqs_[0]); ++i) {
00063 eqs_[i] += o.eqs_[i];
00064 }
00065 for (int i = 0; i != sizeof(rules_)/sizeof(rules_[0]); ++i) {
00066 rules_[i].first += o.rules_[i].first;
00067 rules_[i].second += o.rules_[i].second;
00068 }
00069 }
00070 double LpStats::operator[](const char* key) const {
00071 #define RETURN_IF(x) if (std::strcmp(key, #x) == 0) return double(x)
00072 #define MAP_IF(x, A) if (std::strcmp(key, x) == 0) return double( (A) )
00073 RETURN_IF(bodies);
00074 RETURN_IF(atoms);
00075 RETURN_IF(auxAtoms);
00076 RETURN_IF(sccs);
00077 RETURN_IF(nonHcfs);
00078 RETURN_IF(gammas);
00079 RETURN_IF(ufsNodes);
00080 MAP_IF("rules" , rules());
00081 MAP_IF("basicRules" , rules(BASICRULE).first);
00082 MAP_IF("choiceRules" , rules(CHOICERULE).first);
00083 MAP_IF("constraintRules" , rules(CONSTRAINTRULE).first);
00084 MAP_IF("weightRules" , rules(WEIGHTRULE).first);
00085 MAP_IF("disjunctiveRules" , rules(DISJUNCTIVERULE).first);
00086 MAP_IF("optimizeRules" , rules(OPTIMIZERULE).first);
00087 MAP_IF("basicRulesTr" , rules(BASICRULE).second);
00088 MAP_IF("choiceRulesTr" , rules(CHOICERULE).second);
00089 MAP_IF("constraintRulesTr" , rules(CONSTRAINTRULE).second);
00090 MAP_IF("weightRulesTr" , rules(WEIGHTRULE).second);
00091 MAP_IF("disjunctiveRulesTr", rules(DISJUNCTIVERULE).second);
00092 MAP_IF("optimizeRulesTr" , rules(OPTIMIZERULE).second);
00093 MAP_IF("eqs" , eqs());
00094 MAP_IF("atomEqs" , eqs(Var_t::atom_var));
00095 MAP_IF("bodyEqs" , eqs(Var_t::body_var));
00096 MAP_IF("otherEqs" , eqs(Var_t::atom_body_var));
00097 #undef RETURN_IF
00098 return -1.0;
00099 }
00100 const char* LpStats::keys(const char* path) {
00101 if (!path || !*path) {
00102 return "bodies\0atoms\0auxAtoms\0sccs\0nonHcfs\0gammas\0ufsNodes\0rules\0"
00103 "basicRules\0choiceRules\0constraintRules\0weightRules\0disjunctiveRules\0optimizeRules\0"
00104 "basicRulesTr\0choiceRulesTr\0constraintRulesTr\0weightRulesTr\0disjunctiveRulesTr\0optimizeRulesTr\0"
00105 "eqs\0atomEqs\0bodyEqs\0otherEqs\0";
00106 }
00107 return 0;
00108 }
00110
00112 namespace {
00113 struct LessBodySize {
00114 LessBodySize(const BodyList& bl) : bodies_(&bl) {}
00115 bool operator()(Var b1, Var b2 ) const {
00116 return (*bodies_)[b1]->size() < (*bodies_)[b2]->size()
00117 || ((*bodies_)[b1]->size() == (*bodies_)[b2]->size() && (*bodies_)[b1]->type() < (*bodies_)[b2]->type());
00118 }
00119 private:
00120 const BodyList* bodies_;
00121 };
00122
00123
00124 template <class NT>
00125 bool toConstraint(NT* node, const LogicProgram& prg, ClauseCreator& c) {
00126 if (node->value() != value_free && !prg.ctx()->addUnary(node->trueLit())) {
00127 return false;
00128 }
00129 return !node->relevant() || node->addConstraints(prg, c);
00130 }
00131 }
00132 LogicProgram::LogicProgram() : nonHcfCfg_(0), minimize_(0), incData_(0) { accu = 0; }
00133 LogicProgram::~LogicProgram() { dispose(true); }
00134 LogicProgram::Incremental::Incremental() : startAtom(1), startAux(1), startScc(0) {}
00135 void LogicProgram::dispose(bool force) {
00136
00137 std::for_each( bodies_.begin(), bodies_.end(), DestroyObject() );
00138 std::for_each( disjunctions_.begin(), disjunctions_.end(), DestroyObject() );
00139 AtomList().swap(sccAtoms_);
00140 BodyList().swap(bodies_);
00141 DisjList().swap(disjunctions_);
00142 bodyIndex_.clear();
00143 disjIndex_.clear();
00144 MinimizeRule* r = minimize_;
00145 while (r) {
00146 MinimizeRule* t = r;
00147 r = r->next_;
00148 delete t;
00149 }
00150 minimize_ = 0;
00151 for (RuleList::size_type i = 0; i != extended_.size(); ++i) {
00152 delete extended_[i];
00153 }
00154 extended_.clear();
00155 VarVec().swap(initialSupp_);
00156 rule_.clear();
00157 if (force) {
00158 std::for_each( atoms_.begin(), atoms_.end(), DeleteObject() );
00159 AtomList().swap(atoms_);
00160 delete incData_;
00161 VarVec().swap(propQ_);
00162 ruleState_.clearAll();
00163 }
00164 else if (incData_) {
00165
00166
00167 propQ_.assign(1, getFalseId());
00168 uint32 startAux = incData_->startAux;
00169 assert(startAux <= atoms_.size());
00170
00171 for (VarVec::size_type i = 1; i != startAux; ++i) {
00172 PrgAtom* a = atoms_[i];
00173
00174 a->clearSupports();
00175 a->clearDeps(PrgAtom::dep_all);
00176 a->setIgnoreScc(false);
00177 if (a->eq() && getEqAtom(i) >= startAux) {
00178
00179
00180 PrgAtom* eq = atoms_[getEqAtom(i)];
00181 assert(!eq->eq());
00182 eq->setEq(i);
00183 a->resetId(i, false);
00184 a->setLiteral(eq->literal());
00185 }
00186 if (a->relevant()) {
00187 ValueRep v = a->value();
00188 a->setValue(value_free);
00189 if (!a->frozen()) {
00190 a->resetId(i, false);
00191 if (ctx()->master()->value(a->var()) != value_free) {
00192 v = ctx()->master()->isTrue(a->literal()) ? value_true : value_false;
00193 }
00194 assert(!a->eq() || a->id() < startAux);
00195 }
00196 if (v != value_free) { assignValue(a, v); }
00197 }
00198 else if (!a->eq() && a->value() == value_false) {
00199 a->setEq(getFalseId());
00200 }
00201 }
00202
00203
00204
00205
00206 for (VarVec::size_type i = startAux; i != atoms_.size(); ++i) {
00207 delete atoms_[i];
00208 }
00209 atoms_.erase(atoms_.begin()+startAux, atoms_.end());
00210 }
00211 activeHead_.clear();
00212 activeBody_.reset();
00213 stats.reset();
00214 }
00215 bool LogicProgram::doStartProgram() {
00216 dispose(true);
00217
00218 atoms_.push_back( new PrgAtom(0, false) );
00219 assignValue(getAtom(0), value_false);
00220 getFalseAtom()->setLiteral(negLit(0));
00221 nonHcfCfg_= 0;
00222 incData_ = 0;
00223 ctx()->symbolTable().clear();
00224 ctx()->symbolTable().startInit();
00225 return true;
00226 }
00227 void LogicProgram::setOptions(const AspOptions& opts) {
00228 opts_ = opts;
00229 if (opts_.suppMod) {
00230 if (opts_.iters != 5 && ctx()) { ctx()->report(warning(Event::subsystem_prepare, "'supp-models' implies 'eq=0'")); }
00231 opts_.noEq();
00232 opts_.noScc();
00233 }
00234 }
00235 bool LogicProgram::doParse(StreamSource& prg) { return DefaultLparseParser(*this).parse(prg); }
00236 bool LogicProgram::doUpdateProgram() {
00237 CLASP_ASSERT_CONTRACT(frozen() || !incData_);
00238 if (!incData_) { incData_ = new Incremental(); }
00239 if (!frozen()) { return true; }
00240
00241 dispose(false);
00242 setFrozen(false);
00243 incData_->startAtom = (uint32)atoms_.size();
00244 incData_->startAux = (uint32)atoms_.size();
00245 incData_->update.clear();
00246 incData_->frozen.swap(incData_->update);
00247 ctx()->symbolTable().startInit();
00248
00249
00250 PrgBody* support = incData_->startAux > 1 ? getBodyFor(activeBody_) : 0;
00251 for (VarVec::size_type i = 1; i != incData_->startAux; ++i) {
00252 PrgAtom* a = atoms_[i];
00253 if (a->relevant() && !a->frozen() && a->value() != value_false) {
00254 a->setIgnoreScc(true);
00255 support->addHead(a, PrgEdge::CHOICE_EDGE);
00256 }
00257 }
00258 return true;
00259 }
00260 bool LogicProgram::doEndProgram() {
00261 if (!frozen() && ctx()->ok()) {
00262 prepareProgram(!opts_.noSCC);
00263 addConstraints();
00264 if (accu) { accu->accu(stats); }
00265 }
00266 return ctx()->ok();
00267 }
00268
00269 bool LogicProgram::clone(SharedContext& oCtx, bool shareSymbols) {
00270 assert(frozen());
00271 if (&oCtx == ctx()) {
00272 return true;
00273 }
00274 oCtx.cloneVars(*ctx(), shareSymbols ? SharedContext::init_share_symbols : SharedContext::init_copy_symbols);
00275 SharedContext* t = ctx();
00276 setCtx(&oCtx);
00277 bool r = addConstraints();
00278 setCtx(t);
00279 return r;
00280 }
00281
00282 void LogicProgram::addMinimize() {
00283 CLASP_ASSERT_CONTRACT(frozen());
00284 if (hasMinimize()) {
00285 if (opts_.iters != 0) { simplifyMinimize(); }
00286 WeightLitVec lits;
00287 for (MinimizeRule* r = minimize_; r; r = r->next_) {
00288 for (WeightLitVec::iterator it = r->lits_.begin(); it != r->lits_.end(); ++it) {
00289 PrgAtom* h = resize(it->first.var());
00290 lits.push_back(WeightLiteral(it->first.sign() ? ~h->literal() : h->literal(), it->second));
00291 }
00292 addMinRule(lits);
00293 lits.clear();
00294 }
00295 }
00296 }
00297
00298 void LogicProgram::write(std::ostream& os) {
00299 const char* const delimiter = "0";
00300
00301 PodVector<MinimizeRule*>::type mr;
00302 for (MinimizeRule* r = minimize_; r; r = r->next_) {
00303 mr.push_back(r);
00304 }
00305 std::stringstream body;
00306 for (PodVector<MinimizeRule*>::type::reverse_iterator rit = mr.rbegin(); rit != mr.rend(); ++rit) {
00307 MinimizeRule* r = *rit;
00308 transform(*r, activeBody_);
00309 writeBody(activeBody_, body);
00310 os << OPTIMIZERULE << " " << 0 << " " << body.str() << "\n";
00311 body.clear();
00312 body.str("");
00313 }
00314 std::stringstream choice;
00315 uint32 numChoice = 0;
00316 uint32 falseAtom = 0;
00317 bool oldFreeze = frozen();
00318 setFrozen(false);
00319
00320 for (BodyList::iterator it = bodies_.begin(); it != bodies_.end(); ++it) {
00321 PrgBody* b = *it;
00322 if (b->relevant() && (b->hasVar() || b->value() == value_false) && transform(*b, activeBody_)) {
00323 writeBody(activeBody_, body);
00324 if (b->hasHeads() && b->value() != value_false) {
00325 for (PrgBody::head_iterator it = b->heads_begin(); it != b->heads_end(); ++it) {
00326 PrgHead* head = getHead(*it);
00327 if (head->hasVar()) {
00328 if (it->isAtom()) {
00329 if (it->isNormal()) {
00330 os << activeBody_.ruleType() << " " << it->node() << " " << body.str() << "\n";
00331 }
00332 else if (it->isChoice()) {
00333 choice << it->node() << " ";
00334 ++numChoice;
00335 }
00336 }
00337 else if (it->isDisj()) {
00338 PrgDisj* d = static_cast<PrgDisj*>(head);
00339 os << DISJUNCTIVERULE << " " << d->size() << " ";
00340 for (PrgDisj::atom_iterator a = d->begin(), aEnd = d->end(); a != aEnd; ++a) {
00341 os << a->node() << " ";
00342 }
00343 os << body.str() << "\n";
00344 }
00345 }
00346 }
00347 if (numChoice) {
00348 os << CHOICERULE << " " << numChoice << " " << choice.str() << body.str() << "\n";
00349 }
00350 }
00351 else if (b->value() == value_false) {
00352
00353 if (falseAtom == 0 && (falseAtom = findLpFalseAtom()) == 0) {
00354 setCompute(falseAtom = newAtom(), false);
00355 }
00356 os << activeBody_.ruleType() << " " << falseAtom << " " << body.str() << "\n";
00357 }
00358 body.clear();
00359 body.str("");
00360 choice.clear(); choice.str(""); numChoice = 0;
00361 }
00362 }
00363
00364 std::stringstream bp, bm, symTab;
00365 Literal comp;
00366 SymbolTable::const_iterator sym = ctx()->symbolTable().begin();
00367 for (AtomList::size_type i = 1; i < atoms_.size(); ++i) {
00368
00369 if (atoms_[i]->eq()) {
00370 os << "1 " << i << " 1 0 " << getEqAtom(Var(i)) << " \n";
00371 }
00372 if ( (i == falseAtom || atoms_[i]->inUpper()) && atoms_[i]->value() != value_free ) {
00373 std::stringstream& str = atoms_[i]->value() == value_false ? bm : bp;
00374 str << i << "\n";
00375 }
00376 if (sym != ctx()->symbolTable().end() && Var(i) == sym->first) {
00377 if (sym->second.lit != negLit(sentVar) && !sym->second.name.empty()) {
00378 symTab << i << " " << sym->second.name.c_str() << "\n";
00379 }
00380 ++sym;
00381 }
00382 }
00383 os << delimiter << "\n";
00384 os << symTab.str();
00385 os << delimiter << "\n";
00386 os << "B+\n" << bp.str() << "0\n"
00387 << "B-\n" << bm.str() << "0\n1\n";
00388 setFrozen(oldFreeze);
00389 }
00390
00392
00394 #define check_not_frozen() CLASP_ASSERT_CONTRACT_MSG(!frozen(), "Can't update frozen program!")
00395 #define check_modular(x, atomId) (void)( (!!(x)) || (throw RedefinitionError((atomId), this->getAtomName((atomId))), 0))
00396 RedefinitionError::RedefinitionError(unsigned atomId, const char* name) : std::logic_error(clasp_format_error("Program not modular: Redefinition of atom <%u,'%s'>", atomId, name)) {
00397 }
00398
00399 Var LogicProgram::newAtom() {
00400 check_not_frozen();
00401 Var id = static_cast<Var>(atoms_.size());
00402 atoms_.push_back( new PrgAtom(id) );
00403 return id;
00404 }
00405
00406 LogicProgram& LogicProgram::setAtomName(Var atomId, const char* name) {
00407 check_not_frozen();
00408 check_modular(atomId >= startAtom(), atomId);
00409 resize(atomId);
00410 ctx()->symbolTable().addUnique(atomId, name);
00411 return *this;
00412 }
00413
00414 LogicProgram& LogicProgram::setCompute(Var atomId, bool pos) {
00415 resize(atomId);
00416 ValueRep v = pos ? value_weak_true : value_false;
00417 PrgAtom* a = atoms_[atomId];
00418 assert(!a->hasVar() || a->state() != PrgAtom::state_normal);
00419 assignValue(a, v);
00420 return *this;
00421 }
00422
00423 LogicProgram& LogicProgram::freeze(Var atomId, ValueRep value) {
00424 check_not_frozen();
00425 CLASP_ASSERT_CONTRACT_MSG(incData_, "LogicProgram::updateProgram() not called!");
00426 assert(incData_->frozen.empty());
00427 PrgAtom* a = resize(atomId);
00428 if (!a->inFlux() && (a->frozen() || (atomId >= startAtom() && !a->supports()))) {
00429 CLASP_ASSERT_CONTRACT(value == value_false || value == value_true);
00430 if (!a->frozen()) { incData_->update.push_back(atomId); }
00431 a->setState(value == value_false ? PrgAtom::state_freeze : PrgAtom::state_freeze_true);
00432 }
00433
00434 return *this;
00435 }
00436
00437 LogicProgram& LogicProgram::unfreeze(Var atomId) {
00438 check_not_frozen();
00439 CLASP_ASSERT_CONTRACT_MSG(incData_, "LogicProgram::updateProgram() not called!");
00440 PrgAtom* a = resize(atomId);
00441 if (!a->inFlux() && (atomId >= startAtom() || a->frozen())) {
00442 if (!a->frozen()) { incData_->update.push_back(atomId); }
00443 a->setState(PrgAtom::state_in_flux);
00444 }
00445
00446 return *this;
00447 }
00448
00449 LogicProgram& LogicProgram::addRule(const Rule& r) {
00450 check_not_frozen();
00451
00452 RuleType t = simplifyRule(r, activeHead_, activeBody_);
00453 if (t != ENDRULE) {
00454 upRules(t, 1);
00455 if (handleNatively(t, activeBody_)) {
00456 addRuleImpl(t, activeHead_, activeBody_);
00457 }
00458 else {
00459 bool aux = transformNoAux(t, activeBody_) == false;
00460 Rule* temp = new Rule();
00461 temp->setType(t);
00462 temp->setBound(activeBody_.bound());
00463 temp->heads.swap(activeHead_);
00464 temp->body.swap(activeBody_.lits);
00465 if (aux) {
00466
00467
00468
00469 extended_.push_back(temp);
00470 }
00471 else {
00472 RuleTransform rt;
00473 incTr(t, rt.transformNoAux(*this, *temp));
00474 delete temp;
00475 }
00476 }
00477 }
00478 activeBody_.reset();
00479 return *this;
00480 }
00481 #undef check_not_frozen
00482
00483
00485 Literal LogicProgram::getLiteral(Var atomId) const {
00486 CLASP_ASSERT_CONTRACT_MSG(atomId < atoms_.size(), "Atom out of bounds!");
00487 return getAtom(getEqAtom(atomId))->literal();
00488 }
00489 void LogicProgram::doGetAssumptions(LitVec& out) const {
00490 if (incData_) {
00491 for (VarVec::const_iterator it = incData_->frozen.begin(), end = incData_->frozen.end(); it != end; ++it) {
00492 out.push_back( getAtom(getEqAtom(*it))->assumption() );
00493 }
00494 }
00495 }
00497
00499 void LogicProgram::addRuleImpl(RuleType r, const VarVec& heads, BodyInfo& body) {
00500 if (r != OPTIMIZERULE) {
00501 assert(!heads.empty() && (r != DISJUNCTIVERULE || heads.size() > 1));
00502 PrgBody* b = getBodyFor(body);
00503
00504 if (b->value() != value_false) {
00505 EdgeType t = r != CHOICERULE ? PrgEdge::NORMAL_EDGE : PrgEdge::CHOICE_EDGE;
00506 uint32 headHash = 0;
00507 bool ignoreScc = opts_.noSCC || b->size() == 0;
00508 for (VarVec::const_iterator it = heads.begin(), end = heads.end(); it != end; ++it) {
00509 PrgAtom* a = resize(*it);
00510 if (a->frozen() && a->supports() == 0) { unfreeze(*it); }
00511 check_modular(*it >= startAtom() || a->inFlux() || a->value() == value_false, *it);
00512 if (r != DISJUNCTIVERULE) {
00513
00514 b->addHead(a, t);
00515 if (ignoreScc) { a->setIgnoreScc(ignoreScc); }
00516 }
00517 else {
00518 headHash += hashId(*it);
00519 ruleState_.addToHead(*it);
00520 }
00521 }
00522 if (r == DISJUNCTIVERULE) {
00523 assert(headHash != 0);
00524 PrgDisj* d = getDisjFor(heads, headHash);
00525 b->addHead(d, t);
00526 }
00527 }
00528 }
00529 else {
00530 CLASP_ASSERT_CONTRACT(heads.empty());
00531 LogicProgram::MinimizeRule* mr = new LogicProgram::MinimizeRule;
00532 mr->lits_ = body.lits;
00533 mr->next_ = minimize_;
00534 minimize_ = mr;
00535 }
00536 }
00537
00538 bool LogicProgram::assignValue(PrgAtom* a, ValueRep v) {
00539 if (a->eq()) { a = getAtom(getEqAtom(a->id())); }
00540 ValueRep old = a->value();
00541 if (old == value_weak_true && v != value_weak_true) old = value_free;
00542 if (!a->assignValue(v)) { setConflict(); return false; }
00543 if (old == value_free) { propQ_.push_back(a->id()); }
00544 return true;
00545 }
00546 bool LogicProgram::assignValue(PrgHead* h, ValueRep v) {
00547 return !h->isAtom() || assignValue(static_cast<PrgAtom*>(h), v);
00548 }
00549
00550 bool LogicProgram::handleNatively(RuleType r, const BodyInfo& body) const {
00551 ExtendedRuleMode m = opts_.erMode;
00552 if (r == BASICRULE || r == OPTIMIZERULE || m == mode_native) {
00553 return true;
00554 }
00555 else if (m == mode_transform_integ || m == mode_transform_scc || m == mode_transform_nhcf) {
00556 return true;
00557 }
00558 else if (m == mode_transform) {
00559 return r == DISJUNCTIVERULE;
00560 }
00561 else if (m == mode_transform_dynamic) {
00562 return (r != CONSTRAINTRULE && r != WEIGHTRULE)
00563 || transformNoAux(r, body) == false;
00564 }
00565 else if (m == mode_transform_choice) {
00566 return r != CHOICERULE;
00567 }
00568 else if (m == mode_transform_card) {
00569 return r != CONSTRAINTRULE;
00570 }
00571 else if (m == mode_transform_weight) {
00572 return r != CONSTRAINTRULE && r != WEIGHTRULE;
00573 }
00574 assert(false && "unhandled extended rule mode");
00575 return true;
00576 }
00577
00578 bool LogicProgram::transformNoAux(RuleType r, const BodyInfo& body) const {
00579 return r != CHOICERULE && (body.bound() == 1 || (body.size() <= 6 && choose(body.size(), body.bound()) <= 15));
00580 }
00581
00582 void LogicProgram::transformExtended() {
00583 uint32 a = numAtoms();
00584 if (incData_) {
00585
00586
00587 incData_->startAux = (uint32)atoms_.size();
00588 }
00589 RuleTransform tm;
00590 for (RuleList::size_type i = 0; i != extended_.size(); ++i) {
00591 incTr(extended_[i]->type(), tm.transform(*this, *extended_[i]));
00592 delete extended_[i];
00593 }
00594 extended_.clear();
00595 incTrAux(numAtoms() - a);
00596 }
00597
00598 void LogicProgram::transformIntegrity(uint32 maxAux) {
00599 if (stats.rules(CONSTRAINTRULE).second == 0) { return; }
00600
00601 BodyList integrity;
00602 for (uint32 i = 0, end = static_cast<uint32>(bodies_.size()); i != end; ++i) {
00603 PrgBody* b = bodies_[i];
00604 if (b->relevant() && b->type() == BodyInfo::COUNT_BODY && b->value() == value_false) {
00605 integrity.push_back(b);
00606 }
00607 }
00608 if (!integrity.empty() && (integrity.size() == 1 || (atoms_.size()/double(bodies_.size()) > 0.5 && integrity.size() / double(bodies_.size()) < 0.01))) {
00609 uint32 A = static_cast<uint32>(atoms_.size());
00610
00611 for (BodyList::size_type i = 0; i != integrity.size(); ++i) {
00612 PrgBody* b = integrity[i];
00613 uint32 est = b->bound()*( b->sumW()-b->bound() );
00614 if (est > maxAux) {
00615
00616 break;
00617 }
00618 maxAux -= est;
00619
00620 Rule* r;
00621 extended_.push_back(r = new Rule());
00622 r->setType(CONSTRAINTRULE);
00623 r->setBound(b->bound());
00624 r->addHead(getFalseId());
00625 for (uint32 g = 0; g != b->size(); ++g) {
00626 r->addToBody(b->goal(g).var(), !b->goal(g).sign());
00627 }
00628 setFrozen(false);
00629 transformExtended();
00630 setFrozen(true);
00631
00632 propQ_.push_back(getFalseId());
00633 propagate(true);
00634 b->markRemoved();
00635 }
00636
00637 for (uint32 i = A; i != atoms_.size(); ++i) {
00638 PrgAtom* a = atoms_[i];
00639 for (PrgAtom::sup_iterator it = a->supps_begin(); it != a->supps_end(); ++it) {
00640 PrgBody* nb = bodies_[it->node()];
00641 assert(nb->value() != value_false);
00642 nb->assignVar(*this);
00643 }
00644 a->assignVar(*this, a->supports() ? *a->supps_begin() : PrgEdge::noEdge());
00645 }
00646 }
00647 }
00648
00649
00650 void LogicProgram::simplifyMinimize() {
00651 assert(hasMinimize());
00652 for (LogicProgram::MinimizeRule* r = minimize_; r; r = r->next_) {
00653 for (WeightLitVec::iterator it = r->lits_.begin(); it != r->lits_.end(); ++it) {
00654 it->first = Literal(getEqAtom(it->first.var()), it->first.sign());
00655 }
00656 }
00657 }
00658
00659 void LogicProgram::updateFrozenAtoms() {
00660 if (!incData_) { return; }
00661 assert(incData_->frozen.empty());
00662 activeHead_.clear();
00663 activeBody_.reset();
00664 PrgBody* support = 0;
00665 VarVec::iterator j = incData_->update.begin();
00666 for (VarVec::iterator it = j, end = incData_->update.end(); it != end; ++it) {
00667 Var id = getEqAtom(*it);
00668 PrgAtom* a = getAtom(id);
00669 if (a->inFlux()) {
00670 assert(a->id() == id && a->scc() == PrgNode::noScc && !a->inUpper());
00671 a->setState(PrgAtom::state_normal);
00672 if (id < startAtom()) {
00673
00674 a->markSeen(false);
00675 a->markDirty();
00676 *j++ = id;
00677 }
00678 }
00679 else if (a->frozen()) {
00680 assert(a->relevant() && a->supports() == 0);
00681 a->resetId(id, false);
00682 if (!support) { support = getBodyFor(activeBody_); }
00683 a->setIgnoreScc(true);
00684 support->addHead(a, PrgEdge::CHOICE_EDGE);
00685 incData_->frozen.push_back(id);
00686 }
00687 }
00688 incData_->update.erase(j, incData_->update.end());
00689 }
00690
00691 void LogicProgram::prepareProgram(bool checkSccs) {
00692 assert(!frozen());
00693 transformExtended();
00694 if (opts_.normalize) { assert(false); }
00695 stats.atoms = numAtoms() - (startAtom()-1);
00696 stats.bodies= numBodies();
00697 updateFrozenAtoms();
00698 setFrozen(true);
00699 Preprocessor p;
00700 if (hasConflict() || !propagate(true) || !p.preprocess(*this, opts_.iters != 0 && !opts_.suppMod ? Preprocessor::full_eq : Preprocessor::no_eq, opts_.iters, opts_.dfOrder)) {
00701 setConflict();
00702 return;
00703 }
00704 if (opts_.erMode == mode_transform_integ || opts_.erMode == mode_transform_dynamic) {
00705 transformIntegrity(std::min(uint32(15000), uint32(numAtoms())<<1));
00706 }
00707 addMinimize();
00708 uint32 sccs = 0;
00709 if (checkSccs) {
00710 uint32 startScc = incData_ ? incData_->startScc : 0;
00711 SccChecker c(*this, sccAtoms_, startScc);
00712 sccs = c.sccs();
00713 stats.sccs = (sccs-startScc);
00714 if (incData_) { incData_->startScc = c.sccs(); }
00715 if (!disjunctions_.empty() || (opts_.erMode == mode_transform_scc && sccs)) {
00716
00717 for (uint32 i = 0; i != bodies_.size(); ++i) {
00718 if (getBody(i)->relevant()) { getBody(i)->resetId(i, true); }
00719 }
00720 for (uint32 i = 0; i != atoms_.size(); ++i) {
00721 if (getAtom(i)->relevant()) { getAtom(i)->resetId(i, true); }
00722 }
00723 }
00724 }
00725 else { stats.sccs = PrgNode::noScc; }
00726 finalizeDisjunctions(p, sccs);
00727 prepareComponents();
00728 stats.atoms = numAtoms() - (startAtom()-1);
00729 bodyIndex_.clear();
00730 disjIndex_.clear();
00731 }
00732
00733
00734 void LogicProgram::finalizeDisjunctions(Preprocessor& p, uint32 numSccs) {
00735 if (disjunctions_.empty()) { return; }
00736 VarVec head; BodyList supports;
00737 disjIndex_.clear();
00738 SccMap sccMap;
00739 sccMap.resize(numSccs, 0);
00740 enum SccFlag { seen_scc = 1u, is_scc_non_hcf = 128u };
00741
00742 DisjList temp; temp.swap(disjunctions_);
00743 setFrozen(false);
00744 uint32 shifted = 0, added = 0;
00745 stats.nonHcfs = uint32(nonHcfs_.size());
00746 for (uint32 i = 0, end = temp.size(); i != end; ++i) {
00747 PrgDisj* d = temp[i];
00748 Literal dx = d->inUpper() ? d->literal() : negLit(0);
00749 PrgEdge e = PrgEdge::newEdge(i, PrgEdge::CHOICE_EDGE, PrgEdge::DISJ_NODE);
00750 d->resetId(i, true);
00751
00752
00753 head.clear(); supports.clear();
00754 for (PrgDisj::atom_iterator it = d->begin(), end = d->end(); it != end; ++it) {
00755 PrgAtom* at = getAtom(it->node());
00756 at->removeSupport(e);
00757 if (at->inUpper()) {
00758 head.push_back(it->node());
00759 if (at->scc() != PrgNode::noScc) { sccMap[at->scc()] = seen_scc; }
00760 }
00761 }
00762 EdgeVec temp;
00763 d->clearSupports(temp);
00764 for (EdgeVec::iterator it = temp.begin(), end = temp.end(); it != end; ++it) {
00765 PrgBody* b = getBody(it->node());
00766 if (b->relevant() && b->value() != value_false) { supports.push_back(b); }
00767 b->removeHead(d, PrgEdge::NORMAL_EDGE);
00768 }
00769 d->destroy();
00770
00771 Literal supportLit = dx != negLit(0) ? getEqAtomLit(dx, supports, p, sccMap) : dx;
00772
00773 for (VarVec::iterator hIt = head.begin(), hEnd = head.end(); hIt != hEnd; ++hIt) {
00774 uint32 scc = getAtom(*hIt)->scc();
00775 if (scc == PrgNode::noScc || (sccMap[scc] & seen_scc) != 0) {
00776 if (scc != PrgNode::noScc) { sccMap[scc] &= ~seen_scc; }
00777 else { scc = UINT32_MAX; }
00778 rule_.clear(); rule_.setType(DISJUNCTIVERULE);
00779 rule_.addHead(*hIt);
00780 if (supportLit.var() != 0) { rule_.addToBody(supportLit.var(), !supportLit.sign()); }
00781 else if (supportLit.sign()){ continue; }
00782 for (VarVec::iterator oIt = head.begin(); oIt != hEnd; ++oIt) {
00783 if (oIt != hIt) {
00784 if (getAtom(*oIt)->scc() == scc) { rule_.addHead(*oIt); }
00785 else { rule_.addToBody(*oIt, false); }
00786 }
00787 }
00788 RuleType t = simplifyRule(rule_, activeHead_, activeBody_);
00789 PrgBody* B = t != ENDRULE ? assignBodyFor(activeBody_, PrgEdge::NORMAL_EDGE, true) : 0;
00790 if (!B || B->value() == value_false) { continue; }
00791 if (t == BASICRULE) {
00792 ++shifted;
00793 B->addHead(getAtom(activeHead_[0]), PrgEdge::NORMAL_EDGE);
00794 }
00795 else if (t == DISJUNCTIVERULE) {
00796 PrgDisj* x = getDisjFor(activeHead_, 0);
00797 B->addHead(x, PrgEdge::NORMAL_EDGE);
00798 x->assignVar(*this, *x->supps_begin());
00799 x->setInUpper(true);
00800 x->markSeen(true);
00801 ++added;
00802 if ((sccMap[scc] & is_scc_non_hcf) == 0) {
00803 sccMap[scc] |= is_scc_non_hcf;
00804 nonHcfs_.add(scc);
00805 }
00806 if (!options().noGamma) {
00807 rule_.setType(BASICRULE);
00808 for (uint32 i = 1; i != rule_.heads.size(); ++i) { rule_.addToBody(rule_.heads[i], false); }
00809 rule_.heads.resize(1);
00810 WeightLitVec::iterator bIt = rule_.body.end();
00811 for (uint32 i = x->size();;) {
00812 t = simplifyRule(rule_, activeHead_, activeBody_);
00813 B = t != ENDRULE ? assignBodyFor(activeBody_, PrgEdge::GAMMA_EDGE, true) : 0;
00814 if (B && B->value() != value_false) { B->addHead(getAtom(activeHead_[0]), PrgEdge::GAMMA_EDGE); ++stats.gammas; }
00815 if (--i == 0) { break; }
00816 Var h = rule_.heads[0];
00817 rule_.heads[0] = (--bIt)->first.var();
00818 *bIt = WeightLiteral(negLit(h), 1);
00819 }
00820 }
00821 }
00822 }
00823 }
00824 }
00825 stats.rules(DISJUNCTIVERULE).second = added;
00826 stats.rules(BASICRULE).second += shifted;
00827 stats.nonHcfs = uint32(nonHcfs_.size()) - stats.nonHcfs;
00828 setFrozen(true);
00829 }
00830
00831
00832 void LogicProgram::prepareComponents() {
00833 int trRec = opts_.erMode == mode_transform_scc;
00834
00835
00836 if (!disjunctions_.empty() && trRec != 1) {
00837 trRec = 2;
00838 }
00839 if (trRec != 0) {
00840 BodyList ext;
00841 EdgeVec heads;
00842 for (BodyList::const_iterator it = bodies_.begin(), end = bodies_.end(); it != end; ++it) {
00843 if ((*it)->type() != BodyInfo::NORMAL_BODY && (*it)->hasVar() && (*it)->value() != value_false) {
00844 uint32 scc = (*it)->scc(*this);
00845 if (scc != PrgNode::noScc && (trRec == 1 || nonHcfs_.find(scc))) {
00846 ext.push_back(*it);
00847 }
00848 }
00849 }
00850 if (ext.empty()) { return; }
00851 struct Tr : public RuleTransform::ProgramAdapter {
00852 Tr(LogicProgram* x) : self(x), scc(0) {}
00853 Var newAtom() {
00854 Var x = self->newAtom();
00855 PrgAtom* a = self->getAtom(x);
00856 self->sccAtoms_.push_back(a);
00857 a->setScc(scc);
00858 a->markSeen(true);
00859 atoms.push_back(x);
00860 return x;
00861 }
00862 void addRule(Rule& nr) {
00863 if (self->simplifyRule(nr, self->activeHead_, self->activeBody_) != ENDRULE) {
00864 PrgBody* B = self->assignBodyFor(self->activeBody_, PrgEdge::NORMAL_EDGE, false);
00865 if (B->value() != value_false) {
00866 B->addHead(self->getAtom(self->activeHead_[0]), PrgEdge::NORMAL_EDGE);
00867 }
00868 }
00869 }
00870 LogicProgram* self;
00871 uint32 scc;
00872 VarVec atoms;
00873 } tr(this);
00874 RuleTransform trans;
00875 setFrozen(false);
00876 if (incData_) { incData_->startAux = (uint32)atoms_.size(); }
00877 for (BodyList::const_iterator it = ext.begin(), end = ext.end(); it != end; ++it) {
00878 uint32 scc = (*it)->scc(*this);
00879 rule_.clear();
00880 rule_.setType((*it)->type() == BodyInfo::COUNT_BODY ? CONSTRAINTRULE : WEIGHTRULE);
00881 rule_.setBound((*it)->bound());
00882 tr.scc = scc;
00883 for (uint32 i = 0; i != (*it)->size(); ++i) {
00884 rule_.addToBody((*it)->goal(i).var(), (*it)->goal(i).sign() == false, (*it)->weight(i));
00885 }
00886 heads.assign((*it)->heads_begin(), (*it)->heads_end());
00887 for (EdgeVec::const_iterator hIt = heads.begin(); hIt != heads.end(); ++hIt) {
00888 assert(hIt->isAtom());
00889 if (getAtom(hIt->node())->scc() == scc) {
00890 (*it)->removeHead(getAtom(hIt->node()), hIt->type());
00891 rule_.heads.assign(1, hIt->node());
00892 if (simplifyRule(rule_, activeHead_, activeBody_) != ENDRULE) {
00893 trans.transform(tr, rule_);
00894 }
00895 }
00896 }
00897 }
00898 incTrAux(tr.atoms.size());
00899 while (!tr.atoms.empty()) {
00900 PrgAtom* ax = getAtom(tr.atoms.back());
00901 tr.atoms.pop_back();
00902 if (ax->supports()) {
00903 ax->setInUpper(true);
00904 ax->assignVar(*this, *ax->supps_begin());
00905 }
00906 else { assignValue(ax, value_false); }
00907 }
00908 setFrozen(true);
00909 }
00910 }
00911
00912
00913 bool LogicProgram::addConstraints() {
00914 ClauseCreator gc(ctx()->master());
00915 if (options().iters == 0) {
00916 gc.addDefaultFlags(ClauseCreator::clause_force_simplify);
00917 }
00918 ctx()->startAddConstraints();
00919 ctx()->symbolTable().endInit();
00920 CLASP_ASSERT_CONTRACT(ctx()->symbolTable().curBegin() == ctx()->symbolTable().end() || startAtom() <= ctx()->symbolTable().curBegin()->first);
00921
00922 if (!ctx()->ok() || !ctx()->addUnary(getFalseAtom()->trueLit())) {
00923 return false;
00924 }
00925
00926 for (BodyList::const_iterator it = bodies_.begin(); it != bodies_.end(); ++it) {
00927 if (!toConstraint((*it), *this, gc)) { return false; }
00928 }
00929
00930 for (VarIter it = unfreeze_begin(), end = unfreeze_end(); it != end; ++it) {
00931 if (!toConstraint(getAtom(*it), *this, gc)) { return false; }
00932 }
00933
00934 typedef SymbolTable::const_iterator symbol_iterator;
00935 const bool freezeAll = incData_ && ctx()->satPrepro.get() != 0;
00936 symbol_iterator sym = ctx()->symbolTable().lower_bound(ctx()->symbolTable().curBegin(), startAtom());
00937 symbol_iterator symEnd = ctx()->symbolTable().end();
00938 Var atomId = startAtom();
00939 for (AtomList::const_iterator it = atoms_.begin()+atomId, end = atoms_.end(); it != end; ++it, ++atomId) {
00940 if (!toConstraint(*it, *this, gc)) { return false; }
00941 if (freezeAll && (*it)->hasVar()) { ctx()->setFrozen((*it)->var(), true); }
00942 if (sym != symEnd && atomId == sym->first) {
00943 sym->second.lit = atoms_[getEqAtom(atomId)]->literal();
00944 ++sym;
00945 }
00946 }
00947 if (!sccAtoms_.empty()) {
00948 if (ctx()->sccGraph.get() == 0) {
00949 ctx()->sccGraph = new SharedDependencyGraph(nonHcfCfg_);
00950 }
00951 uint32 oldNodes = ctx()->sccGraph->nodes();
00952 ctx()->sccGraph->addSccs(*this, sccAtoms_, nonHcfs_);
00953 stats.ufsNodes = ctx()->sccGraph->nodes()-oldNodes;
00954 sccAtoms_.clear();
00955 }
00956 return true;
00957 }
00958 #undef check_modular
00959
00960
00962 PrgAtom* LogicProgram::resize(Var atomId) {
00963 while (atoms_.size() <= AtomList::size_type(atomId)) {
00964 newAtom();
00965 }
00966 return atoms_[getEqAtom(atomId)];
00967 }
00968
00969 bool LogicProgram::propagate(bool backprop) {
00970 assert(frozen());
00971 bool oldB = opts_.backprop;
00972 opts_.backprop = backprop;
00973 for (VarVec::size_type i = 0; i != propQ_.size(); ++i) {
00974 PrgAtom* a = getAtom(propQ_[i]);
00975 if (!a->relevant()) { continue; }
00976 if (!a->propagateValue(*this, backprop)) {
00977 setConflict();
00978 return false;
00979 }
00980 if (a->hasVar() && a->id() < startAtom() && !ctx()->addUnary(a->trueLit())) {
00981 setConflict();
00982 return false;
00983 }
00984 }
00985 opts_.backprop = oldB;
00986 propQ_.clear();
00987 return true;
00988 }
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002 RuleType LogicProgram::simplifyBody(const Rule& r, BodyInfo& info) {
01003 info.reset();
01004 WeightLitVec& sBody= info.lits;
01005 if (r.bodyHasBound() && r.bound() <= 0) {
01006 return BASICRULE;
01007 }
01008 sBody.reserve(r.body.size());
01009 RuleType resType = r.type();
01010 weight_t w = 0;
01011 weight_t BOUND = r.bodyHasBound() ? r.bound() : std::numeric_limits<weight_t>::max();
01012 weight_t bound = r.bodyHasBound() ? r.bound() : static_cast<weight_t>(r.body.size());
01013 uint32 pos = 0;
01014 uint32 hash = 0;
01015 bool dirty = r.bodyHasWeights();
01016 Literal lit;
01017 for (WeightLitVec::const_iterator it = r.body.begin(), bEnd = r.body.end(); it != bEnd; ++it) {
01018 if (it->second == 0) continue;
01019 CLASP_ASSERT_CONTRACT_MSG(it->second>0, "Positive weight expected!");
01020 PrgAtom* a = resize(it->first.var());
01021 lit = Literal(a->id(), it->first.sign());
01022 w = std::min(it->second, BOUND);
01023 if (a->value() != value_free || !a->relevant()) {
01024 bool vSign = a->value() == value_false || !a->relevant();
01025 if (vSign != lit.sign()) {
01026
01027 if (r.bodyIsSet()) { resType = ENDRULE; break; }
01028 continue;
01029 }
01030 else if (a->value() != value_weak_true && r.type() != OPTIMIZERULE) {
01031
01032 if ((bound -= w) <= 0) {
01033 while (!sBody.empty()) { ruleState_.clear(sBody.back().first.var()); sBody.pop_back(); }
01034 pos = hash = 0;
01035 break;
01036 }
01037 continue;
01038 }
01039 }
01040 if (!ruleState_.inBody(lit)) {
01041 ruleState_.addToBody(lit);
01042 sBody.push_back(WeightLiteral(lit, w));
01043 pos += !lit.sign();
01044 hash+= !lit.sign() ? hashId(lit.var()) : hashId(-lit.var());
01045 }
01046 else if (!r.bodyIsSet()) {
01047 WeightLiteral& oldLit = info[info.findLit(lit)];
01048 weight_t oldW = oldLit.second;
01049 CLASP_ASSERT_CONTRACT_MSG((INT_MAX-oldW)>= w, "Integer overflow!");
01050 w = std::min(oldW + w, BOUND);
01051 oldLit.second = w;
01052 dirty = true;
01053 if (resType == CONSTRAINTRULE) {
01054 resType = WEIGHTRULE;
01055 }
01056 }
01057 dirty |= ruleState_.inBody(~lit);
01058 }
01059 weight_t minW = 1;
01060 weight_t maxW = 1;
01061 wsum_t realSum = (wsum_t)sBody.size();
01062 wsum_t sumW = (wsum_t)sBody.size();
01063 if (dirty) {
01064 minW = std::numeric_limits<weight_t>::max();
01065 realSum = sumW = 0;
01066 for (WeightLitVec::size_type i = 0; i != sBody.size(); ++i) {
01067 lit = sBody[i].first; w = sBody[i].second;
01068 minW = std::min(minW, w);
01069 maxW = std::max(maxW, w);
01070 sumW+= w;
01071 if (!ruleState_.inBody(~lit)) { realSum += w; }
01072 else if (r.bodyIsSet()) { resType = ENDRULE; break; }
01073 else if (lit.sign()) {
01074
01075 realSum += std::max(w, info[info.findLit(~lit)].second);
01076 }
01077 }
01078 if (resType == OPTIMIZERULE) { bound = 0; }
01079 }
01080 if (resType != ENDRULE && r.bodyHasBound()) {
01081 if (bound <= 0) { resType = BASICRULE; bound = 0; }
01082 else if (realSum < bound) { resType = ENDRULE; }
01083 else if ((sumW - minW) < bound) { resType = BASICRULE; bound = (weight_t)sBody.size(); }
01084 else if (minW == maxW) { resType = CONSTRAINTRULE; bound = (bound+(minW-1))/minW; }
01085 }
01086 info.init(resType, bound, hash, pos);
01087 return resType;
01088 }
01089
01090 RuleType LogicProgram::simplifyRule(const Rule& r, VarVec& head, BodyInfo& body) {
01091 RuleType type = simplifyBody(r, body);
01092 head.clear();
01093 if (type != ENDRULE && type != OPTIMIZERULE) {
01094 bool blocked = false, taut = false;
01095 weight_t sum = -1;
01096 for (VarVec::const_iterator it = r.heads.begin(), end = r.heads.end(); it != end; ++it) {
01097 if (!ruleState_.isSet(*it, RuleState::any_flag)) {
01098 head.push_back(*it);
01099 ruleState_.addToHead(*it);
01100 }
01101 else if (!ruleState_.isSet(*it, RuleState::head_flag)) {
01102 weight_t wPos = ruleState_.inBody(posLit(*it)) ? body.weight(posLit(*it)) : 0;
01103 weight_t wNeg = ruleState_.inBody(negLit(*it)) ? body.weight(negLit(*it)) : 0;
01104 if (sum == -1) sum = body.sum();
01105 if ((sum - wPos) < body.bound()) {
01106 taut = (type != CHOICERULE);
01107 }
01108 else if ((sum - wNeg) < body.bound()) {
01109 blocked = (type != CHOICERULE);
01110 }
01111 else {
01112 head.push_back(*it);
01113 ruleState_.addToHead(*it);
01114 }
01115 }
01116 }
01117 for (VarVec::const_iterator it = head.begin(), end = head.end(); it != end; ++it) {
01118 ruleState_.clear(*it);
01119 }
01120 if (blocked && type != DISJUNCTIVERULE) {
01121 head.clear();
01122 head.push_back(0);
01123 }
01124 else if (taut && (type == DISJUNCTIVERULE || head.empty())) {
01125 head.clear();
01126 type = ENDRULE;
01127 }
01128 else if (type == DISJUNCTIVERULE && head.size() == 1) {
01129 type = BASICRULE;
01130 }
01131 else if (head.empty()) {
01132 type = ENDRULE;
01133 }
01134 }
01135 for (WeightLitVec::size_type i = 0; i != body.size(); ++i) {
01136 ruleState_.clear(body[i].first.var());
01137 }
01138 return type;
01139 }
01140
01141
01142
01143 Literal LogicProgram::getEqAtomLit(Literal lit, const BodyList& supports, Preprocessor& p, const SccMap& sccMap) {
01144 if (supports.empty() || lit == negLit(0)) { return negLit(0); }
01145 if (supports.size() == 1 && supports[0]->size() < 2) {
01146 return supports[0]->size() == 0 ? posLit(0) : supports[0]->goal(0);
01147 }
01148 if (p.getRootAtom(lit) != varMax) { return posLit(p.getRootAtom(lit)); }
01149 incTrAux(1);
01150 Var auxV = newAtom();
01151 PrgAtom* aux = getAtom(auxV);
01152 uint32 scc = PrgNode::noScc;
01153 aux->setLiteral(lit);
01154 aux->markSeen(true);
01155 p.setRootAtom(aux->literal(), auxV);
01156 for (BodyList::const_iterator sIt = supports.begin(); sIt != supports.end(); ++sIt) {
01157 PrgBody* b = *sIt;
01158 if (b->relevant() && b->value() != value_false) {
01159 for (uint32 g = 0; scc == PrgNode::noScc && g != b->size() && !b->goal(g).sign(); ++g) {
01160 uint32 aScc = getAtom(b->goal(g).var())->scc();
01161 if (aScc != PrgNode::noScc && (sccMap[aScc] & 1u)) { scc = aScc; }
01162 }
01163 b->addHead(aux, PrgEdge::NORMAL_EDGE);
01164 if (b->value() != aux->value()) { assignValue(aux, b->value()); }
01165 aux->setInUpper(true);
01166 }
01167 }
01168 if (!aux->inUpper()) {
01169 aux->setValue(value_false);
01170 return negLit(0);
01171 }
01172 else if (scc != PrgNode::noScc) {
01173 aux->setScc(scc);
01174 sccAtoms_.push_back(aux);
01175 }
01176 return posLit(auxV);
01177 }
01178
01179 PrgBody* LogicProgram::getBodyFor(BodyInfo& body, bool addDeps) {
01180 uint32 bodyId = equalBody(bodyIndex_.equal_range(body.hash), body);
01181 if (bodyId != varMax) {
01182 return getBody(bodyId);
01183 }
01184
01185 bodyId = (uint32)bodies_.size();
01186 PrgBody* b = PrgBody::create(*this, bodyId, body, addDeps);
01187 bodyIndex_.insert(IndexMap::value_type(body.hash, bodyId));
01188 bodies_.push_back(b);
01189 if (b->isSupported()) {
01190 initialSupp_.push_back(bodyId);
01191 }
01192 return b;
01193 }
01194
01195 PrgBody* LogicProgram::assignBodyFor(BodyInfo& body, EdgeType depEdge, bool simpStrong) {
01196 PrgBody* b = getBodyFor(body, depEdge != PrgEdge::GAMMA_EDGE);
01197 if (!b->hasVar() && !b->seen()) {
01198 uint32 eqId;
01199 b->markDirty();
01200 b->simplify(*this, simpStrong, &eqId);
01201 if (eqId != b->id()) {
01202 assert(b->id() == bodies_.size()-1);
01203 removeBody(b, body.hash);
01204 bodies_.pop_back();
01205 if (depEdge != PrgEdge::GAMMA_EDGE) {
01206 for (uint32 i = 0; i != b->size(); ++i) {
01207 getAtom(b->goal(i).var())->removeDep(b->id(), !b->goal(i).sign());
01208 }
01209 }
01210 b->destroy();
01211 b = bodies_[eqId];
01212 }
01213 }
01214 b->markSeen(true);
01215 b->assignVar(*this);
01216 return b;
01217 }
01218
01219 uint32 LogicProgram::equalBody(const IndexRange& range, BodyInfo& body) const {
01220 bool sorted = false;
01221 for (IndexIter it = range.first; it != range.second; ++it) {
01222 PrgBody& o = *bodies_[it->second];
01223 if (o.type() == body.type() && o.size() == body.size() && o.bound() == body.bound() && (body.posSize() == 0u || o.goal(body.posSize()-1).sign() == false)) {
01224
01225 if ((o.relevant() || (o.eq() && getBody(o.id())->relevant())) && o.eqLits(body.lits, sorted)) {
01226 assert(o.id() == it->second || o.eq());
01227 return o.id();
01228 }
01229 }
01230 }
01231 return varMax;
01232 }
01233 uint32 LogicProgram::findEqBody(PrgBody* b, uint32 hash) {
01234 LogicProgram::IndexRange eqRange = bodyIndex_.equal_range(hash);
01235
01236 if (eqRange.first != eqRange.second) {
01237 activeBody_.reset();
01238 WeightLitVec& lits = activeBody_.lits;
01239 uint32 p = 0;
01240 for (uint32 i = 0, end = b->size(); i != end; ++i) {
01241 lits.push_back(WeightLiteral(b->goal(i), b->weight(i)));
01242 p += !lits.back().first.sign();
01243 }
01244 activeBody_.init(b->type(), b->bound(), hash, p);
01245 return equalBody(eqRange, activeBody_);
01246 }
01247 return varMax;
01248 }
01249
01250 PrgDisj* LogicProgram::getDisjFor(const VarVec& heads, uint32 headHash) {
01251 PrgDisj* d = 0;
01252 if (headHash) {
01253 LogicProgram::IndexRange eqRange = disjIndex_.equal_range(headHash);
01254 for (; eqRange.first != eqRange.second; ++eqRange.first) {
01255 PrgDisj& o = *disjunctions_[eqRange.first->second];
01256 if (o.relevant() && o.size() == heads.size() && ruleState_.allMarked(heads, RuleState::head_flag)) {
01257 assert(o.id() == eqRange.first->second);
01258 d = &o;
01259 break;
01260 }
01261 }
01262 for (VarVec::const_iterator it = heads.begin(), end = heads.end(); it != end; ++it) {
01263 ruleState_.clear(*it);
01264 }
01265 }
01266 if (!d) {
01267
01268
01269 uint32 id = disjunctions_.size();
01270 d = PrgDisj::create(id, heads);
01271 disjunctions_.push_back(d);
01272 PrgEdge edge = PrgEdge::newEdge(id, PrgEdge::CHOICE_EDGE, PrgEdge::DISJ_NODE);
01273 for (VarVec::const_iterator it = heads.begin(), end = heads.end(); it != end; ++it) {
01274 getAtom(*it)->addSupport(edge);
01275 }
01276 if (headHash) {
01277 disjIndex_.insert(IndexMap::value_type(headHash, d->id()));
01278 }
01279 }
01280 return d;
01281 }
01282
01283
01284 uint32 LogicProgram::update(PrgBody* body, uint32 oldHash, uint32 newHash) {
01285 uint32 id = removeBody(body, oldHash);
01286 if (body->relevant()) {
01287 uint32 eqId = findEqBody(body, newHash);
01288 if (eqId == varMax) {
01289
01290
01291 bodyIndex_.insert(IndexMap::value_type(newHash, id));
01292 }
01293 return eqId;
01294 }
01295 return varMax;
01296 }
01297
01298
01299 uint32 LogicProgram::removeBody(PrgBody* b, uint32 hash) {
01300 IndexRange ra = bodyIndex_.equal_range(hash);
01301 uint32 id = b->id();
01302 for (; ra.first != ra.second; ++ra.first) {
01303 if (bodies_[ra.first->second] == b) {
01304 id = ra.first->second;
01305 bodyIndex_.erase(ra.first);
01306 break;
01307 }
01308 }
01309 return id;
01310 }
01311
01312 PrgAtom* LogicProgram::mergeEqAtoms(PrgAtom* a, Var rootId) {
01313 rootId = getEqAtom(rootId);
01314 PrgAtom* root = getAtom(rootId);
01315 assert(!a->eq() && !root->eq());
01316 if (a->ignoreScc()) { root->setIgnoreScc(true); }
01317 if (a->frozen()) { root->setState(std::max(a->state(), root->state())); }
01318 if (!mergeValue(a, root)) { setConflict(); return 0; }
01319 assert(a->value() == root->value() || (root->value() == value_true && a->value() == value_weak_true));
01320 a->setEq(rootId);
01321 incEqs(Var_t::atom_var);
01322 return root;
01323 }
01324
01325
01326 bool LogicProgram::positiveLoopSafe(PrgBody* body, PrgBody* root) const {
01327 uint32 i = 0, end = std::min(body->size(), root->size());
01328 while (i != end && body->goal(i).sign() == root->goal(i).sign()) { ++i; }
01329 return i == root->size() || root->goal(i).sign();
01330 }
01331
01332 PrgBody* LogicProgram::mergeEqBodies(PrgBody* b, Var rootId, bool hashEq, bool atomsAssigned) {
01333 rootId = getEqNode(bodies_, rootId);
01334 PrgBody* root = getBody(rootId);
01335 bool bp = options().backprop;
01336 if (b == root) { return root; }
01337 assert(!b->eq() && !root->eq() && (hashEq || b->literal() == root->literal()));
01338 if (!b->simplifyHeads(*this, atomsAssigned) || (b->value() != root->value() && (!mergeValue(b, root) || !root->propagateValue(*this, bp) || !b->propagateValue(*this, bp)))) {
01339 setConflict();
01340 return 0;
01341 }
01342 assert(b->value() == root->value());
01343 if (hashEq || positiveLoopSafe(b, root)) {
01344 b->setLiteral(root->literal());
01345 if (!root->mergeHeads(*this, *b, atomsAssigned, !hashEq)) {
01346 setConflict();
01347 return 0;
01348 }
01349 incEqs(Var_t::body_var);
01350 b->setEq(rootId);
01351 return root;
01352 }
01353 return b;
01354 }
01355
01356 uint32 LogicProgram::findLpFalseAtom() const {
01357 for (VarVec::size_type i = 1; i < atoms_.size(); ++i) {
01358 if (!atoms_[i]->eq() && atoms_[i]->value() == value_false) {
01359 return i;
01360 }
01361 }
01362 return 0;
01363 }
01364
01365 const char* LogicProgram::getAtomName(Var id) const {
01366 if (const SymbolTable::symbol_type* x = ctx()->symbolTable().find(id)) {
01367 return x->name.c_str();
01368 }
01369 return "";
01370 }
01371 VarVec& LogicProgram::getSupportedBodies(bool sorted) {
01372 if (sorted) {
01373 std::stable_sort(initialSupp_.begin(), initialSupp_.end(), LessBodySize(bodies_));
01374 }
01375 return initialSupp_;
01376 }
01377
01378 bool LogicProgram::transform(const PrgBody& body, BodyInfo& out) const {
01379 out.reset();
01380 out.lits.reserve(body.size());
01381 uint32 p = 0, end = body.size();
01382 while (p != end && !body.goal(p).sign()) { ++p; }
01383 uint32 R[2][2] = { {p, end}, {0, p} };
01384 weight_t sw = 0, st = 0;
01385 for (uint32 range = 0; range != 2; ++range) {
01386 for (uint32 x = R[range][0]; x != R[range][1]; ++x) {
01387 WeightLiteral wl(body.goal(x), body.weight(x));
01388 if (getAtom(wl.first.var())->hasVar()) {
01389 sw += wl.second;
01390 out.lits.push_back(wl);
01391 }
01392 else if (wl.first.sign()) {
01393 st += wl.second;
01394 }
01395 }
01396 }
01397 out.init(body.type(), std::max(body.bound() - st, weight_t(0)), 0, p);
01398 return sw >= out.bound();
01399 }
01400
01401 void LogicProgram::transform(const MinimizeRule& body, BodyInfo& out) const {
01402 out.reset();
01403 uint32 pos = 0;
01404 for (WeightLitVec::const_iterator it = body.lits_.begin(), end = body.lits_.end(); it != end; ++it) {
01405 if (it->first.sign() && getAtom(it->first.var())->hasVar()) {
01406 out.lits.push_back(*it);
01407 }
01408 }
01409 for (WeightLitVec::const_iterator it = body.lits_.begin(), end = body.lits_.end(); it != end; ++it) {
01410 if (!it->first.sign() && getAtom(it->first.var())->hasVar()) {
01411 out.lits.push_back(*it);
01412 ++pos;
01413 }
01414 }
01415 out.init(BodyInfo::SUM_BODY, -1, 0, pos);
01416 }
01417
01418 void LogicProgram::writeBody(const BodyInfo& body, std::ostream& out) const {
01419 if (body.type() == BodyInfo::SUM_BODY && body.bound() != -1) { out << body.bound() << " "; }
01420 out << body.size() << " ";
01421 out << (body.size() - body.posSize()) << " ";
01422 if (body.type() == BodyInfo::COUNT_BODY) { out << body.bound() << " "; }
01423 for (WeightLitVec::const_iterator it = body.lits.begin(), end = body.lits.end(); it != end; ++it) {
01424 out << it->first.var() << " ";
01425 }
01426 if (body.type() == BodyInfo::SUM_BODY) {
01427 for (WeightLitVec::const_iterator it = body.lits.begin(), end = body.lits.end(); it != end; ++it) {
01428 out << it->second << " ";
01429 }
01430 }
01431 }
01432
01433 } }
01434