dlvhex  2.5.0
src/WeakConstraintPlugin.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 //#define BOOST_SPIRIT_DEBUG
00039 
00040 #include "dlvhex2/WeakConstraintPlugin.h"
00041 #include "dlvhex2/PlatformDefinitions.h"
00042 #include "dlvhex2/ProgramCtx.h"
00043 #include "dlvhex2/Registry.h"
00044 #include "dlvhex2/Printer.h"
00045 #include "dlvhex2/Printhelpers.h"
00046 #include "dlvhex2/PredicateMask.h"
00047 #include "dlvhex2/Logger.h"
00048 #include "dlvhex2/HexParser.h"
00049 #include "dlvhex2/HexParserModule.h"
00050 #include "dlvhex2/HexGrammar.h"
00051 
00052 #include <boost/algorithm/string/predicate.hpp>
00053 #include <boost/lexical_cast.hpp>
00054 
00055 DLVHEX_NAMESPACE_BEGIN
00056 
00057 WeakConstraintPlugin::CtxData::CtxData():
00058 enabled(false)
00059 {
00060 }
00061 
00062 
00063 WeakConstraintPlugin::WeakConstraintPlugin():
00064 PluginInterface()
00065 {
00066     setNameVersion("dlvhex-weakconstraintplugin[internal]", 2, 0, 0);
00067 }
00068 
00069 
00070 WeakConstraintPlugin::~WeakConstraintPlugin()
00071 {
00072 }
00073 
00074 
00075 // output help message for this plugin
00076 void WeakConstraintPlugin::printUsage(std::ostream& o) const
00077 {
00078     //    123456789-123456789-123456789-123456789-123456789-123456789-123456789-123456789-
00079     o << "     --weak-enable[=true,false]" << std::endl
00080         << "                      Enable or disable weak constraint plugin (default is enabled)."
00081         << "     --weak-allmodels Display all models also under weak constraints.";
00082 }
00083 
00084 
00085 // accepted options: --weak-enable
00086 //
00087 // processes options for this plugin, and removes recognized options from pluginOptions
00088 // (do not free the pointers, the const char* directly come from argv)
00089 void WeakConstraintPlugin::processOptions(
00090 std::list<const char*>& pluginOptions,
00091 ProgramCtx& ctx)
00092 {
00093     DBGLOG(DBG, "WeakConstraintPlugin::processOptions");
00094     WeakConstraintPlugin::CtxData& ctxdata = ctx.getPluginData<WeakConstraintPlugin>();
00095     ctxdata.enabled = true;
00096     ctxdata.allmodels = false;
00097 
00098     typedef std::list<const char*>::iterator Iterator;
00099     Iterator it;
00100     WARNING("create (or reuse, maybe from potassco?) cmdline option processing facility")
00101         it = pluginOptions.begin();
00102     while( it != pluginOptions.end() ) {
00103         bool processed = false;
00104         const std::string str(*it);
00105         if( boost::starts_with(str, "--weak-enable" ) ) {
00106             std::string m = str.substr(std::string("--weak-enable").length());
00107             if (m == "" || m == "=true") {
00108                 ctxdata.enabled = true;
00109             }
00110             else if (m == "=false") {
00111                 ctxdata.enabled = false;
00112             }
00113             else {
00114                 std::stringstream ss;
00115                 ss << "Unknown --weak-enable option: " << m;
00116                 throw PluginError(ss.str());
00117             }
00118             processed = true;
00119                                  // --allmodels is for backwards compatibility (option was renamed)
00120         }else if( str == "--weak-allmodels" || str == "--allmodels" )
00121         {
00122             ctxdata.allmodels = true;
00123             processed = true;
00124         }
00125 
00126         if( processed ) {
00127             // return value of erase: element after it, maybe end()
00128             DBGLOG(DBG,"WeakConstraintPlugin successfully processed option " << str);
00129             it = pluginOptions.erase(it);
00130         }
00131         else {
00132             it++;
00133         }
00134     }
00135 }
00136 
00137 
00138 namespace
00139 {
00140 
00141     typedef WeakConstraintPlugin::CtxData CtxData;
00142 
00143     class WeakRewriter:
00144     public PluginRewriter
00145     {
00146         private:
00147             WeakConstraintPlugin::CtxData& ctxdata;
00148             std::vector<ID> newIdb;
00149             void rewriteRule(ProgramCtx& ctx, std::vector<ID>& idb, ID ruleID);
00150 
00151         public:
00152             WeakRewriter(WeakConstraintPlugin::CtxData& ctxdata) : ctxdata(ctxdata) {}
00153             virtual ~WeakRewriter() {}
00154 
00155             virtual void rewrite(ProgramCtx& ctx);
00156     };
00157 
00158     void WeakRewriter::rewriteRule(ProgramCtx& ctx, std::vector<ID>& idb, ID ruleID) {
00159 
00160         // if it is a weak constraint, add a head atom
00161         if (ruleID.isWeakConstraint()) {
00162             RegistryPtr reg = ctx.registry();
00163             const Rule& rule = reg->rules.getByID(ruleID);
00164 
00165             // take the rule as it is, but change the rule type
00166             Rule newRule = rule;
00167             newRule.kind &= (ID::ALL_ONES ^ ID::SUBKIND_RULE_WEAKCONSTRAINT);
00168             newRule.kind |= ID::SUBKIND_RULE_REGULAR;
00169             //  newRule.kind = ID::MAINKIND_RULE | ID::SUBKIND_RULE_REGULAR;
00170             //  if (ruleID.doesRuleContainExtatoms()) newRule.kind |= ID::PROPERTY_RULE_EXTATOMS;
00171             //  if (ruleID.doesRuleContainModatoms()) newRule.kind |= ID::PROPERTY_RULE_MODATOMS;
00172 
00173             std::set<ID> bodyVars;
00174             BOOST_FOREACH (ID b, rule.body) {
00175                 reg->getVariablesInID(b, bodyVars, false, false);
00176             }
00177 
00178             bool ground = bodyVars.size() == 0 && !rule.weight.isVariableTerm() && !rule.level.isVariableTerm();
00179             OrdinaryAtom oatom(ID::MAINKIND_ATOM | ID::PROPERTY_AUX);
00180             if (ground) oatom.kind |= ID::SUBKIND_ATOM_ORDINARYG;
00181             else oatom.kind |= ID::SUBKIND_ATOM_ORDINARYN;
00182             oatom.tuple.push_back(reg->getAuxiliaryConstantSymbol('w', ruleID));
00183             // add weight and level
00184             oatom.tuple.push_back(rule.weight);
00185             oatom.tuple.push_back(rule.level);
00186             if (rule.weakconstraintVector.size() > 0 && rule.weakconstraintVector[0] == ID_FAIL){
00187                 // DLV-style
00188                 BOOST_FOREACH (ID v, bodyVars) {
00189                     oatom.tuple.push_back(v);
00190                 }
00191             }else{
00192                 // ASP-Core-2-style
00193                 BOOST_FOREACH (ID v, rule.weakconstraintVector) {
00194                     oatom.tuple.push_back(v);
00195                 }
00196             }
00197 
00198             ID hid = ground ? reg->storeOrdinaryGAtom(oatom) : reg->storeOrdinaryNAtom(oatom);
00199             newRule.head.push_back(hid);
00200 
00201             // add the new rule to the IDB
00202             ID newRuleID = reg->storeRule(newRule);
00203             idb.push_back(newRuleID);
00204 
00205             // we have at least one weak constraint --> enable optimization! (for performance reasons, do not enable it if not necessary!)
00206             // let both dlvhex and the solver backend optimize (dlvhex is required for soundness wrt. minimality semantics, backend is for efficiency reasons)
00207 
00208             // note that we need to do some kind of optimization (influences EvaluateState)
00209             ctx.config.setOption("Optimization", 1);
00210             if (!ctxdata.allmodels) ctx.config.setOption("OptimizationByDlvhex", 1);
00211             if (!ctxdata.allmodels) ctx.config.setOption("OptimizationByBackend", 1);
00212             // suppress non-optimal models preceeding the optimal ones
00213             if (!ctxdata.allmodels) ctx.config.setOption("OptimizationFilterNonOptimal", 1);
00214 //ctx.config.setOption("OptimizationFilterNonOptimal", 0);
00215 //ctx.config.setOption("OptimizationByBackend", 1);
00216 //ctx.config.setOption("OptimizationByDlvhex", 0);
00217             if( ctx.config.getOption("OptimizationTwoStep") == 0 )
00218                 LOG(WARNING,"optimization might be slow because it cannot be done in a strictly decreasing manner"
00219                     "(TODO perhaps it could be done but we currently cannot detect if weight constraints are in single unit)");
00220             LOG(INFO,"WeakRewriter activated Optimization");
00221         }
00222         else {
00223             idb.push_back(ruleID);
00224         }
00225     }
00226 
00227     void WeakRewriter::rewrite(ProgramCtx& ctx) {
00228         BOOST_FOREACH (ID rid, ctx.idb) {
00229             rewriteRule(ctx, newIdb, rid);
00230         }
00231         ctx.idb = newIdb;
00232 
00233         #ifndef NDEBUG
00234         std::stringstream programstring;
00235         RawPrinter printer(programstring, ctx.registry());
00236         BOOST_FOREACH (ID ruleId, newIdb) {
00237             printer.print(ruleId);
00238             programstring << std::endl;
00239         }
00240         DBGLOG(DBG, "weak-constraint-free rewritten program:" << std::endl << programstring.str());
00241         #endif
00242     }
00243 
00244 }                                // anonymous namespace
00245 
00246 
00247 // rewrite program
00248 PluginRewriterPtr WeakConstraintPlugin::createRewriter(ProgramCtx& ctx)
00249 {
00250     WeakConstraintPlugin::CtxData& ctxdata = ctx.getPluginData<WeakConstraintPlugin>();
00251     DBGLOG(DBG, "WeakConstraintPlugin::createRewriter: enabled=" << ctxdata.enabled);
00252     if( !ctxdata.enabled )
00253         return PluginRewriterPtr();
00254 
00255     return PluginRewriterPtr(new WeakRewriter(ctxdata));
00256 }
00257 
00258 
00259 // register auxiliary printer for strong negation auxiliaries
00260 void WeakConstraintPlugin::setupProgramCtx(ProgramCtx& ctx)
00261 {
00262     WeakConstraintPlugin::CtxData& ctxdata = ctx.getPluginData<WeakConstraintPlugin>();
00263     DBGLOG(DBG, "WeakConstraintPlugin::setupProgramCtx: enabled=" << ctxdata.enabled);
00264     if( !ctxdata.enabled )
00265         return;
00266 }
00267 
00268 
00269 std::vector<PluginAtomPtr> WeakConstraintPlugin::createAtoms(ProgramCtx& ctx) const
00270 {
00271     std::vector<PluginAtomPtr> ret;
00272     return ret;
00273 }
00274 
00275 
00276 DLVHEX_NAMESPACE_END
00277 
00278 // this would be the code to use this plugin as a "real" plugin in a .so file
00279 // but we directly use it in dlvhex.cpp
00280 #if 0
00281 WeakConstraintPlugin theWeakConstraintPlugin;
00282 
00283 // return plain C type s.t. all compilers and linkers will like this code
00284 extern "C"
00285 void * PLUGINIMPORTFUNCTION()
00286 {
00287     return reinterpret_cast<void*>(& DLVHEX_NAMESPACE theWeakConstraintPlugin);
00288 }
00289 #endif
00290 
00291 
00292 // vim:expandtab:ts=4:sw=4:
00293 // mode: C++
00294 // End: