dlvhex
2.5.0
|
00001 /* dlvhex -- Answer-Set Programming with external interfaces. 00002 * Copyright (C) 2005-2007 Roman Schindlauer 00003 * Copyright (C) 2006-2015 Thomas Krennwallner 00004 * Copyright (C) 2009-2016 Peter Schüller 00005 * Copyright (C) 2011-2016 Christoph Redl 00006 * Copyright (C) 2015-2016 Tobias Kaminski 00007 * Copyright (C) 2015-2016 Antonius Weinzierl 00008 * 00009 * This file is part of dlvhex. 00010 * 00011 * dlvhex is free software; you can redistribute it and/or modify it 00012 * under the terms of the GNU Lesser General Public License as 00013 * published by the Free Software Foundation; either version 2.1 of 00014 * the License, or (at your option) any later version. 00015 * 00016 * dlvhex is distributed in the hope that it will be useful, but 00017 * WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 * Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with dlvhex; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00024 * 02110-1301 USA. 00025 */ 00026 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: