dlvhex  2.5.0
src/AnswerSet.cpp
Go to the documentation of this file.
00001 /* dlvhex -- Answer-Set Programming with external interfaces.
00002  * Copyright (C) 2005-2007 Roman Schindlauer
00003  * Copyright (C) 2006-2015 Thomas Krennwallner
00004  * Copyright (C) 2009-2016 Peter Schüller
00005  * Copyright (C) 2011-2016 Christoph Redl
00006  * Copyright (C) 2015-2016 Tobias Kaminski
00007  * Copyright (C) 2015-2016 Antonius Weinzierl
00008  *
00009  * This file is part of dlvhex.
00010  *
00011  * dlvhex is free software; you can redistribute it and/or modify it
00012  * under the terms of the GNU Lesser General Public License as
00013  * published by the Free Software Foundation; either version 2.1 of
00014  * the License, or (at your option) any later version.
00015  *
00016  * dlvhex is distributed in the hope that it will be useful, but
00017  * WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  * Lesser General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU Lesser General Public
00022  * License along with dlvhex; if not, write to the Free Software
00023  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00024  * 02110-1301 USA.
00025  */
00026 
00034 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif                           // HAVE_CONFIG_H
00037 
00038 #include "dlvhex2/AnswerSet.h"
00039 #include "dlvhex2/Benchmarking.h"
00040 
00041 DLVHEX_NAMESPACE_BEGIN
00042 
00043 void AnswerSet::computeWeightVector()
00044 {
00045     DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"AnswerSet::computeWeightVector");
00046 
00047     weightVector = std::vector<int>();
00048     weightVector.push_back(0);
00049 
00050     RegistryPtr reg = interpretation->getRegistry();
00051 
00052     // go through all atoms
00053     bm::bvector<>::enumerator en = interpretation->getStorage().first();
00054     bm::bvector<>::enumerator en_end = interpretation->getStorage().end();
00055 
00056     while (en < en_end) {
00057         ID id = reg->ogatoms.getIDByAddress(*en);
00058         const OrdinaryAtom oatom = reg->ogatoms.getByAddress(*en);
00059         if (id.isAuxiliary()) {
00060             if (reg->getTypeByAuxiliaryConstantSymbol(oatom.tuple[0]) == 'w') {
00061                 // tuple[1] and tuple[2] encode weight and level
00062                 assert (oatom.tuple[1].isIntegerTerm());
00063                 assert (oatom.tuple[2].isIntegerTerm());
00064 
00065                 // make sure that the weight vector is long enough
00066                 while (weightVector.size() < oatom.tuple[2].address + 1 || weightVector.size() == 0) weightVector.push_back(0);
00067 
00068                 weightVector[oatom.tuple[2].address] += oatom.tuple[1].address;
00069             }
00070         }
00071         en++;
00072     }
00073 }
00074 
00075 
00076 std::vector<int>& AnswerSet::getWeightVector()
00077 {
00078     return weightVector;
00079 }
00080 
00081 
00082 bool AnswerSet::betterThan(std::vector<int>& cwv)
00083 {
00084     return weightVector == cwv || strictlyBetterThan(cwv);
00085 }
00086 
00087 
00088 bool AnswerSet::strictlyBetterThan(std::vector<int>& cwv)
00089 {
00090     DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"AnswerSet::strictlyBetterThan");
00091 
00092     // check if one of the vectors has cost values on higher levels
00093     if (weightVector.size() < cwv.size()) {
00094         for (uint32_t j = weightVector.size(); j < cwv.size(); ++j)
00095             if (cwv[j] > 0) return true;
00096     }
00097     if (cwv.size() < weightVector.size()) {
00098         for (uint32_t j = cwv.size(); j < weightVector.size(); ++j)
00099             if (weightVector[j] > 0) return false;
00100     }
00101 
00102     // compare the costs on all levels which are present in both weight vectors
00103     int i = (weightVector.size() < cwv.size() ? weightVector.size() : cwv.size()) - 1;
00104     while (i >= 0) {
00105         if (weightVector[i] < cwv[i]) return true;
00106         if (cwv[i] < weightVector[i]) return false;
00107         i--;
00108     }
00109 
00110     // same solution quality
00111     return false;
00112 }
00113 
00114 
00115 std::ostream& AnswerSet::printWeightVector(std::ostream& o) const
00116 {
00117     DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"AnswerSet::printWeightVector");
00118 
00119     if (weightVector.size() > 0) {
00120         bool first = true;
00121         for (uint32_t level = 0; level < weightVector.size(); ++level) {
00122             if (weightVector[level] > 0) {
00123                 o << (first ? " <" : ",");
00124                 o << "[" << weightVector[level] << ":" << level << "]";
00125                 first = false;
00126             }
00127         }
00128         if (!first) o << ">";
00129     }
00130     return o;
00131 }
00132 
00133 
00134 std::ostream& AnswerSet::print(std::ostream& o) const
00135 {
00136     DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"AnswerSet::print");
00137 
00138     // use ", " with space here! (compatibility)
00139     interpretation->print(o, "{", ", ", "}");
00140     if (weightVector.size() > 0) {
00141         printWeightVector(o);
00142     }
00143     return o;
00144 }
00145 
00146 
00147 #if 0
00148 unsigned AnswerSet::maxLevel = 1;
00149 unsigned AnswerSet::maxWeight = 0;
00150 
00151 AnswerSet::AnswerSet(const std::string& wcpr)
00152 : WCprefix(wcpr)
00153 {
00154 }
00155 
00156 
00157 void
00158 AnswerSet::setSet(const AtomSet& atomset)
00159 {
00160     // set atoms
00161     this->atoms = atomset.atoms;
00162 
00163     // check if we have a prefix for weak constraints
00164     if (!this->WCprefix.empty()) {
00165         AtomSet wcatoms;
00166 
00167         for (AtomSet::const_iterator asit = this->atoms.begin();
00168             asit != this->atoms.end();
00169         ++asit) {
00170             if (asit->getPredicate().getString().substr(0, WCprefix.length()) == WCprefix) {
00171                 AtomPtr wca(new Atom(*asit));
00172                 wcatoms.insert(wca);
00173             }
00174         }
00175 
00176         //
00177         // this answer set has no weight atoms
00178         //
00179         if (wcatoms.size() == 0) {
00180             this->weights.push_back(0);
00181         }
00182         else {
00183             for (AtomSet::const_iterator asit = wcatoms.begin(); asit != wcatoms.end(); ++asit) {
00184                 Tuple args = asit->getArguments();
00185 
00186                 Term tlevel(*(args.end() - 1));
00187                 Term tweight(*(args.end() - 2));
00188 
00189                 if (!tlevel.isInt())
00190                     throw GeneralError("Weak constraint level instantiated with non-integer!");
00191 
00192                 unsigned l = tlevel.getInt();
00193 
00194                 if (!tweight.isInt())
00195                     throw GeneralError("Weak constraint weight instantiated with non-integer!");
00196 
00197                 unsigned w = tweight.getInt();
00198 
00199                 this->addWeight(w, l);
00200             }
00201         }
00202     }
00203 }
00204 
00205 
00206 bool
00207 AnswerSet::hasWeights() const
00208 {
00209     return !this->WCprefix.empty();
00210 }
00211 
00212 
00213 unsigned
00214 AnswerSet::getWeightLevels() const
00215 {
00216     return this->weights.size();
00217 }
00218 
00219 
00220 void
00221 AnswerSet::addWeight(unsigned weight,
00222 unsigned level)
00223 {
00224     assert(level > 0);
00225 
00226     setMaxLevelWeight(level, weight);
00227 
00228     //
00229     // create new levels if necessary
00230     //
00231     if (this->weights.size() < level) {
00232         for (unsigned ws = this->weights.size(); ws < level; ++ws)
00233             this->weights.push_back(0);
00234     }
00235 
00236     //
00237     // levels start from one, the std::vector starts from 0, hence level - 1
00238     //
00239     this->weights[level - 1] += weight;
00240 }
00241 
00242 
00243 unsigned
00244 AnswerSet::getWeight(unsigned level) const
00245 {
00246     //
00247     // unspecified levels have weight 0
00248     //
00249     if (level > this->weights.size())
00250         return 0;
00251 
00252     return this->weights.at(level - 1);
00253 }
00254 
00255 
00256 bool
00257 AnswerSet::cheaperThan(const AnswerSet& answerset2) const
00258 {
00259     if (WCprefix.empty())
00260         return 0;
00261 
00262     int ret = 0;
00263 
00264     unsigned maxlevel = this->weights.size();
00265 
00266     if (answerset2.weights.size() > maxlevel)
00267         maxlevel = answerset2.weights.size();
00268 
00269     //
00270     // higher levels have higher priority
00271     //
00272     //for (unsigned currlevel = 1; currlevel <= maxlevel; ++currlevel)
00273     for (unsigned currlevel = maxlevel; currlevel >= 1; --currlevel) {
00274         if (this->getWeight(currlevel) < answerset2.getWeight(currlevel)) {
00275             ret = !Globals::Instance()->getOption("ReverseOrder");
00276             break;
00277         }
00278 
00279         if (this->getWeight(currlevel) > answerset2.getWeight(currlevel)) {
00280             ret = Globals::Instance()->getOption("ReverseOrder");
00281             break;
00282         }
00283     }
00284 
00285     return ret;
00286 }
00287 
00288 
00289 bool
00290 AnswerSet::moreExpensiveThan(const weights_t& weights) const
00291 {
00292     if (WCprefix.empty())
00293         return 0;
00294 
00295     int ret = 0;
00296     //int ret = Globals::Instance()->getOption("ReverseOrder");
00297 
00298     unsigned maxlevel = this->weights.size();
00299 
00300     //
00301     // find out the maximum of both levels
00302     //
00303     if (weights.size() > maxlevel)
00304         maxlevel = weights.size();
00305 
00306     //
00307     // go through all levels
00308     //
00309     //for (unsigned currlevel = 1; currlevel <= maxlevel; ++currlevel)
00310     for (unsigned currlevel = maxlevel; currlevel >= 1; --currlevel) {
00311         unsigned w = 0;
00312 
00313         //
00314         // only take weight from existing levels of the specified weight
00315         // vector - otherwise w is still 0 (nonspecified levels have 0 weight)
00316         //
00317         if (currlevel <= weights.size())
00318             w = weights.at(currlevel - 1);
00319 
00320         //
00321         // compare with weight from *this - getWeight ensures that we don't read
00322         // from unspecified levels (see getWeight)
00323         // if *this weighs more than the specified vector, it is more expensive,
00324         // return 1
00325         //
00326         if (this->getWeight(currlevel) > w) {
00327             ret = !Globals::Instance()->getOption("ReverseOrder");
00328             break;
00329         }
00330 
00331         //
00332         // if this weighs less than the specified vector, it is cheaper, return
00333         // 0
00334         //
00335         if (this->getWeight(currlevel) < w) {
00336             ret = Globals::Instance()->getOption("ReverseOrder");
00337             break;
00338         }
00339     }
00340 
00341     //
00342     // if weights at all levels were equal, *this is not more expensive than the
00343     // specified vector; ret is still at 0
00344     //
00345 
00346     return ret;
00347 }
00348 
00349 
00350 int
00351 AnswerSet::operator< (const AnswerSet& answerset2) const
00352 {
00353     //
00354     // with weak constraints, we order the AnswerSets according to their
00355     // weights
00356     //
00357     if (!WCprefix.empty()) {
00358         bool isCheaper(1);
00359 
00360         //
00361         // if we use reverse order, we simply toggle the return value:
00362         //
00363         //if (Globals::Instance()->getOption("ReverseOrder"))
00364         //  isCheaper = 0;
00365 
00366         if (this->cheaperThan(answerset2))
00367             return isCheaper;
00368 
00369         if (answerset2.cheaperThan(*this))
00370             return !isCheaper;
00371     }
00372 
00373     //
00374     // if the answersets have equal costs in weak constraint-mode, we have to
00375     // check for normal equality, otherwise two equal-cost answer sets would be
00376     // already considered as equal and only one of them could be inserted in a
00377     // container<AnswerSet>!
00378     //
00379 
00380     //
00381     // in normal mode, we use the AtomSet::< comparison
00382     //
00383     return AtomSet::operator< (answerset2);
00384 }
00385 
00386 
00387 void
00388 AnswerSet::setMaxLevelWeight(unsigned l, unsigned w)
00389 {
00390     if (l > maxLevel)
00391         maxLevel = l;
00392     if (w > maxWeight)
00393         maxWeight = w;
00394 }
00395 
00396 
00397 unsigned
00398 AnswerSet::getMaxLevel()
00399 {
00400     return maxLevel;
00401 }
00402 
00403 
00404 std::ostream&
00405 operator<< (std::ostream& out, const AnswerSet& atomset)
00406 {
00408     RawPrintVisitor rpv(out);
00409     const_cast<AnswerSet*>(&atomset)->accept(rpv);
00410     return out;
00411 }
00412 #endif
00413 
00414 DLVHEX_NAMESPACE_END
00415 
00416 
00417 // vim:expandtab:ts=4:sw=4:
00418 // mode: C++
00419 // End: