dlvhex  2.5.0
include/dlvhex2/OfflineModelBuilder.h
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 #ifndef OFFLINE_MODEL_BUILDER_HPP_INCLUDED__28092010
00035 #define OFFLINE_MODEL_BUILDER_HPP_INCLUDED__28092010
00036 
00037 #include "dlvhex2/PlatformDefinitions.h"
00038 #include "dlvhex2/OnlineModelBuilder.h"
00039 #include "dlvhex2/CAUAlgorithms.h"
00040 
00041 DLVHEX_NAMESPACE_BEGIN
00042 
00044 template<typename EvalGraphT>
00045 class OfflineModelBuilder:
00046 public OnlineModelBuilder<EvalGraphT>
00047 {
00048     // types
00049     protected:
00050         typedef OnlineModelBuilder<EvalGraphT> Base;
00051 
00052     public:
00053         typedef OfflineModelBuilder<EvalGraphT> Self;
00054 
00055         typedef typename Base::EvalUnit EvalUnit;
00056         typedef typename Base::EvalUnitDep EvalUnitDep;
00057         typedef typename Base::EvalUnitPropertyBundle EvalUnitPropertyBundle;
00058         typedef typename Base::MyModelGraph MyModelGraph;
00059         typedef typename Base::Model Model;
00060         typedef typename Base::ModelPropertyBundle ModelPropertyBundle;
00061         typedef typename Base::OptionalModel OptionalModel;
00062         typedef typename MyModelGraph::ModelList ModelList;
00063         typedef typename ModelList::const_iterator ModelListIterator;
00064         typedef boost::optional<ModelListIterator> OptionalModelListIterator;
00065 
00066     protected:
00068         struct OfflineModelBuildingProperties
00069         {
00071             bool builtIModels;
00073             bool builtOModels;
00074 
00075             // for non-joining iteration, we need this
00077             OptionalModelListIterator currentIModel;
00079             OptionalModelListIterator currentOModel;
00080 
00082             OfflineModelBuildingProperties():
00083             builtIModels(false), builtOModels(false),
00084                 currentIModel(), currentOModel() {}
00085         };
00086         typedef boost::vector_property_map<OfflineModelBuildingProperties>
00087             OfflineModelBuildingPropertyMap;
00088 
00089         // storage
00090     protected:
00092         OfflineModelBuildingPropertyMap offmbp;
00094         boost::optional<CAUAlgorithms::JoinRelevancePropertyMap> currentjrp;
00095 
00096         // methods
00097     public:
00100         OfflineModelBuilder(ModelBuilderConfig<EvalGraphT>& cfg):
00101         Base(cfg), offmbp() {
00102             // allocate full mbp (plus one unit, as we will likely get an additional vertex)
00103             EvalGraphT& eg = cfg.eg;
00104             OfflineModelBuildingProperties& offmbproptemp = offmbp[eg.countEvalUnits()];
00105             (void)offmbproptemp;
00106 
00107             // (defaults for properties are ok)
00108         }
00110         virtual ~OfflineModelBuilder() { }
00111 
00112         inline EvalGraphT& getEvalGraph() { return Base::getEvalGraph(); }
00113         inline MyModelGraph& getModelGraph() { return Base::getModelGraph(); }
00114         void printEvalGraphModelGraph(std::ostream& o) { Base::printEvalGraphModelGraph(o); }
00115         void printModelBuildingPropertyMap(std::ostream& o) { Base::printModelBuildingPropertyMap(o); }
00116 
00119         virtual unsigned buildIModels(EvalUnit u);
00122         virtual unsigned buildOModels(EvalUnit u);
00123 
00124         // automatically calls buildOModelsRecursively on any non-calculated predecessor
00125         virtual unsigned buildIModelsRecursively(EvalUnit u);
00126         // automatically calls buildIModelsRecursively if imodels are not calculated yet
00127         virtual unsigned buildOModelsRecursively(EvalUnit u);
00128 
00129     protected:
00130         // get next input model (projected if projection is configured) at unit u
00131         virtual OptionalModel getNextIModel(EvalUnit u);
00132 };
00133 
00134 template<typename EvalGraphT>
00135 unsigned OfflineModelBuilder<EvalGraphT>::buildIModels(
00136 typename OfflineModelBuilder<EvalGraphT>::EvalUnit u)
00137 {
00138     LOG_VSCOPE(MODELB,"bIM",u,true);
00139     DBGLOG(DBG,"=OfflineModelBuilder<...>::buildIModels(" << u << ")");
00140     //const EvalUnitPropertyBundle& uprops = Base::eg.propsOf(u);
00141     //LOG("rules: " << uprops.ctx.rules);
00142 
00143     typename EvalGraphT::PredecessorIterator pbegin, pend;
00144     boost::tie(pbegin, pend) = Base::eg.getPredecessors(u);
00145 
00146     #ifndef NDEBUG
00147     typename EvalGraphT::PredecessorIterator pit;
00148     for(pit = pbegin; pit != pend; ++pit) {
00149         EvalUnit upred = Base::eg.targetOf(*pit);
00150         assert(offmbp[upred].builtOModels == true);
00151     }
00152     #endif
00153 
00154     assert(offmbp[u].builtIModels == false);
00155 
00156     // if no predecessors
00157     //   call Base::getNextIModel while it returns (dummy) models
00158     // if 1 predecessor
00159     //   call Self::getNextIModel with limit where nothing is relevant
00160     //   (this returns (simply linked) models without backtracking in the model graph)
00161     // otherwise
00162     //   calculate CAUs from u
00163     //   calculate join-relevant units
00164     //   call Self::getNextIModel while it returns models
00165     // mark u as calculated
00166     // return number of generated models
00167 
00168     unsigned modelcounter = 0;
00169     if( pbegin == pend ) {
00170         // no predecessors -> create dummy models using base class functionality
00171         LOG(MODELB,"asking for (dummy) models");
00172         while(Base::getNextIModel(u) != boost::none)
00173             modelcounter++;
00174     }
00175     else if( (pbegin+1) == pend ) {
00176         // one predecessor -> create jrp directly (no CAUAlgorithms required, although they would do the job)
00177         LOG(MODELB,"one predecessor, manually creating join relevance");
00178         assert(!currentjrp);
00179 
00180         CAUAlgorithms::JoinRelevancePropertyMap jr;
00181         CAUAlgorithms::initJoinRelevance(jr, Base::eg);
00182         currentjrp = jr;
00183 
00184         DBGLOG(DBG,"asking for imodels");
00185         while(Base::getNextIModel(u) != boost::none)
00186             modelcounter++;
00187         LOG(MODELB,"created " << modelcounter << " imodels");
00188 
00189         currentjrp = boost::none;
00190     }
00191     else {
00192         LOG(MODELB,"more than one predecessor -> using CAUAlgorithms");
00193         assert(!currentjrp);
00194 
00195         CAUAlgorithms::AncestryPropertyMap apm;
00196         std::set<EvalUnit> caus;
00197         CAUAlgorithms::findCAUs(caus, Base::eg, u, apm);
00198         CAUAlgorithms::logAPM(apm);
00199         CAUAlgorithms::JoinRelevancePropertyMap jr;
00200         CAUAlgorithms::markJoinRelevance(jr, Base::eg, u, caus, apm);
00201         CAUAlgorithms::logJRPM(jr);
00202         currentjrp = jr;
00203 
00204         DBGLOG(DBG,"asking for imodels");
00205         while(Base::getNextIModel(u) != boost::none)
00206             modelcounter++;
00207         LOG(MODELB,"created " << modelcounter << " imodels");
00208 
00209         currentjrp = boost::none;
00210     }
00211 
00212     offmbp[u].builtIModels = true;
00213     return modelcounter;
00214 }
00215 
00216 
00217 template<typename EvalGraphT>
00218 unsigned OfflineModelBuilder<EvalGraphT>::buildOModels(
00219 EvalUnit u)
00220 {
00221     LOG_VSCOPE(MODELB,"bOM",u,true);
00222     DBGLOG(DBG,"=OfflineModelBuilder<...>::buildOModels(" << u << ")");
00223     //const EvalUnitPropertyBundle& uprops = Base::eg.propsOf(u);
00224     //LOG("rules: " << uprops.ctx.rules);
00225 
00226     assert(offmbp[u].builtIModels == true);
00227     assert(offmbp[u].builtOModels == false);
00228 
00229     // for all imodels present
00230     //   call Base::getNextOModel while it returns models
00231     // mark u as calculated
00232     // return number of generated models
00233 
00234     unsigned modelcounter = 0;
00235 
00236     assert(!currentjrp);
00237     CAUAlgorithms::JoinRelevancePropertyMap jr;
00238     CAUAlgorithms::initJoinRelevance(jr, Base::eg);
00239     currentjrp = jr;
00240 
00241     DBGLOG(DBG,"asking for omodels");
00242     while(Base::getNextOModel(u) != boost::none)
00243         modelcounter++;
00244     LOG(MODELB,"created " << modelcounter << " omodels");
00245 
00246     currentjrp = boost::none;
00247     offmbp[u].builtOModels = true;
00248     return modelcounter;
00249 }
00250 
00251 
00252 // automatically calls buildOModelsRecursively on any non-calculated predecessor
00253 template<typename EvalGraphT>
00254 unsigned OfflineModelBuilder<EvalGraphT>::buildIModelsRecursively(
00255 EvalUnit u)
00256 {
00257     LOG_VSCOPE(MODELB,"bIMR",u,true);
00258     DBGLOG(DBG,"=OfflineModelBuilder<...>::buildIModelsRecursively(" << u << ")@" << printptr(this));
00259 
00260     // no assertions here, we succeed if we already built the models
00261     if( offmbp[u].builtIModels == true ) {
00262                                  // TODO: how about iproject?
00263         unsigned count = Base::mg.modelsAt(u,MT_IN).size();
00264         LOG(MODELB,"already built -> counting " << count << " imodels");
00265         return count;
00266     }
00267 
00268     typename EvalGraphT::PredecessorIterator pbegin, pend;
00269     boost::tie(pbegin, pend) = Base::eg.getPredecessors(u);
00270 
00271     typename EvalGraphT::PredecessorIterator pit;
00272     for(pit = pbegin; pit != pend; ++pit) {
00273         EvalUnit upred = Base::eg.targetOf(*pit);
00274         if( offmbp[upred].builtOModels == false ) {
00275             LOG(MODELB,"predecessor " << upred << " has no built omodels");
00276             unsigned count = buildOModelsRecursively(upred);
00277             LOG(MODELB,"built " << count << " models in predecessor");
00278         }
00279         else {
00280             LOG(MODELB,"predecessor " << upred << " has omodels");
00281         }
00282     }
00283 
00284     unsigned count = buildIModels(u);
00285     LOG(MODELB,"built " << count << " imodels here");
00286     return count;
00287 }
00288 
00289 
00290 template<typename EvalGraphT>
00291 // automatically calls buildIModelsRecursively if imodels are not calculated yet
00292 unsigned OfflineModelBuilder<EvalGraphT>::buildOModelsRecursively(
00293 EvalUnit u)
00294 {
00295     LOG_VSCOPE(MODELB,"bOMR",u,true);
00296     DBGLOG(DBG,"=OfflineModelBuilder<...>::buildOModelsRecursively(" << u << ")@" << printptr(this));
00297 
00298     // no assertions here, we succeed if we already built the models
00299     if( offmbp[u].builtOModels == true ) {
00300                                  // TODO: how about oproject?
00301         unsigned count = Base::mg.modelsAt(u,MT_OUT).size();
00302         LOG(MODELB,"already built -> counting " << count << " omodels");
00303         return count;
00304     }
00305 
00306     if( offmbp[u].builtIModels == false ) {
00307         LOG(MODELB,"have no imodels");
00308         unsigned count = buildIModelsRecursively(u);
00309         LOG(MODELB,"built " << count << " imodels here");
00310     }
00311     else {
00312         LOG(MODELB,"already have imodels");
00313     }
00314 
00315     unsigned count = buildOModels(u);
00316     LOG(MODELB,"built " << count << " omodels here");
00317     return count;
00318 }
00319 
00320 
00321 template<typename EvalGraphT>
00322 typename OfflineModelBuilder<EvalGraphT>::OptionalModel
00323 OfflineModelBuilder<EvalGraphT>::getNextIModel(
00324 EvalUnit u)
00325 {
00326     LOG_VSCOPE(MODELB,"offgnIM",u,true);
00327     DBGLOG(DBG,"=OfflineModelBuilder<...>::getNextIModel(" << u << ")");
00328     //logEvalGraphModelGraph();
00329 
00330     assert(!!currentjrp);
00331     if( currentjrp.get()[u] ) {
00332         LOG(MODELB,"join relevant");
00333         return Base::getNextIModel(u);
00334     }
00335     else {
00336         LOG(MODELB,"not join relevant");
00337         assert(offmbp[u].builtIModels);
00338         // TODO how about iproj?
00339         const ModelList& mlist = Base::mg.modelsAt(u, MT_IN);
00340         if( !!offmbp[u].currentIModel ) {
00341             //assert(offmbp[u].currentIModel.get() != mlist.end());
00342             LOG(MODELB,"advancing iterator");
00343             //if( Base::mg.propsOf(*offmbp[u].currentIModel.get()).dummy == 1 )
00344             //  logEvalGraphModelGraph();
00345             offmbp[u].currentIModel.get()++;
00346         }
00347         else {
00348             LOG(MODELB,"initializing iterator");
00349             offmbp[u].currentIModel = mlist.begin();
00350         }
00351         if( offmbp[u].currentIModel.get() == mlist.end() ) {
00352             LOG(MODELB,"no more models");
00353             Base::mbp[u].setIModel(boost::none);
00354             offmbp[u].currentIModel = boost::none;
00355             return boost::none;
00356         }
00357         else {
00358             Model m = *offmbp[u].currentIModel.get();
00359             Base::mbp[u].setIModel(m);
00360             LOG(MODELB,"got model " << m);
00361             return m;
00362         }
00363     }
00364 }
00365 
00366 
00367 DLVHEX_NAMESPACE_END
00368 #endif                           // OFFLINE_MODEL_BUILDER_HPP_INCLUDED__28092010
00369 
00370 // vim:expandtab:ts=4:sw=4:
00371 // mode: C++
00372 // End: