dlvhex  2.1.0
include/dlvhex2/OfflineModelBuilder.h
Go to the documentation of this file.
00001 /* dlvhex -- Answer-Set Programming with external interfaces.
00002  * Copyright (C) 2005, 2006, 2007 Roman Schindlauer
00003  * Copyright (C) 2006, 2007, 2008, 2009, 2010 Thomas Krennwallner
00004  * Copyright (C) 2009, 2010 Peter Schüller
00005  * 
00006  * This file is part of dlvhex.
00007  *
00008  * dlvhex is free software; you can redistribute it and/or modify it
00009  * under the terms of the GNU Lesser General Public License as
00010  * published by the Free Software Foundation; either version 2.1 of
00011  * the License, or (at your option) any later version.
00012  *
00013  * dlvhex is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with dlvhex; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00021  * 02110-1301 USA.
00022  */
00023 
00031 #ifndef OFFLINE_MODEL_BUILDER_HPP_INCLUDED__28092010
00032 #define OFFLINE_MODEL_BUILDER_HPP_INCLUDED__28092010
00033 
00034 #include "dlvhex2/PlatformDefinitions.h"
00035 #include "dlvhex2/OnlineModelBuilder.h"
00036 #include "dlvhex2/CAUAlgorithms.h"
00037 
00038 DLVHEX_NAMESPACE_BEGIN
00039 
00040 template<typename EvalGraphT>
00041 class OfflineModelBuilder:
00042   public OnlineModelBuilder<EvalGraphT>
00043 {
00044   // types
00045 protected:
00046   typedef OnlineModelBuilder<EvalGraphT> Base;
00047 
00048 public:
00049   typedef OfflineModelBuilder<EvalGraphT> Self;
00050 
00051   typedef typename Base::EvalUnit EvalUnit;
00052   typedef typename Base::EvalUnitDep EvalUnitDep;
00053   typedef typename Base::EvalUnitPropertyBundle EvalUnitPropertyBundle;
00054   typedef typename Base::MyModelGraph MyModelGraph;
00055   typedef typename Base::Model Model;
00056   typedef typename Base::ModelPropertyBundle ModelPropertyBundle;
00057   typedef typename Base::OptionalModel OptionalModel;
00058   typedef typename MyModelGraph::ModelList ModelList;
00059   typedef typename ModelList::const_iterator ModelListIterator;
00060   typedef boost::optional<ModelListIterator> OptionalModelListIterator;
00061 
00062 protected:
00063   struct OfflineModelBuildingProperties
00064   {
00065     bool builtIModels;
00066     bool builtOModels;
00067 
00068     // for non-joining iteration, we need this
00069     OptionalModelListIterator currentIModel;
00070     OptionalModelListIterator currentOModel;
00071 
00072     OfflineModelBuildingProperties():
00073       builtIModels(false), builtOModels(false),
00074       currentIModel(), currentOModel() {}
00075   };
00076   typedef boost::vector_property_map<OfflineModelBuildingProperties>
00077     OfflineModelBuildingPropertyMap;
00078 
00079   // storage
00080 protected:
00081   OfflineModelBuildingPropertyMap offmbp;
00082   // TODO: for each call we need this storage, this is not threadsafe! (but the rest of model building is unlikely to be threadsafe as well)
00083   boost::optional<CAUAlgorithms::JoinRelevancePropertyMap> currentjrp;
00084 
00085   // methods
00086 public:
00087   OfflineModelBuilder(EvalGraphT& eg):
00088     Base(eg), offmbp()
00089   {
00090     // allocate full mbp (plus one unit, as we will likely get an additional vertex)
00091     OfflineModelBuildingProperties& offmbproptemp = offmbp[eg.countEvalUnits()];
00092     (void)offmbproptemp;
00093 
00094     // (defaults for properties are ok)
00095   }
00096 
00097   virtual ~OfflineModelBuilder() { }
00098 
00099   inline EvalGraphT& getEvalGraph() { return Base::getEvalGraph(); }
00100   inline MyModelGraph& getModelGraph() { return Base::getModelGraph(); }
00101   void printEvalGraphModelGraph(std::ostream& o) { Base::printEvalGraphModelGraph(o); }
00102   void printModelBuildingPropertyMap(std::ostream& o) { Base::printModelBuildingPropertyMap(o); }
00103 
00104   virtual unsigned buildIModels(EvalUnit u);
00105   virtual unsigned buildOModels(EvalUnit u);
00106 
00107   // automatically calls buildOModelsRecursively on any non-calculated predecessor
00108   virtual unsigned buildIModelsRecursively(EvalUnit u);
00109   // automatically calls buildIModelsRecursively if imodels are not calculated yet
00110   virtual unsigned buildOModelsRecursively(EvalUnit u);
00111 
00112 protected:
00113   // get next input model (projected if projection is configured) at unit u
00114   virtual OptionalModel getNextIModel(EvalUnit u);
00115 };
00116 
00117 template<typename EvalGraphT>
00118 unsigned OfflineModelBuilder<EvalGraphT>::buildIModels(
00119     typename OfflineModelBuilder<EvalGraphT>::EvalUnit u)
00120 {
00121   LOG_VSCOPE(MODELB,"bIM",u,true);
00122   DBGLOG(DBG,"=OfflineModelBuilder<...>::buildIModels(" << u << ")");
00123   //const EvalUnitPropertyBundle& uprops = Base::eg.propsOf(u);
00124   //LOG("rules: " << uprops.ctx.rules);
00125 
00126   typename EvalGraphT::PredecessorIterator pbegin, pend;
00127   boost::tie(pbegin, pend) = Base::eg.getPredecessors(u);
00128 
00129   #ifndef NDEBUG
00130   typename EvalGraphT::PredecessorIterator pit;
00131   for(pit = pbegin; pit != pend; ++pit)
00132   {
00133     EvalUnit upred = Base::eg.targetOf(*pit);
00134     assert(offmbp[upred].builtOModels == true);
00135   }
00136   #endif
00137 
00138   assert(offmbp[u].builtIModels == false);
00139 
00140   // if no predecessors
00141   //   call Base::getNextIModel while it returns (dummy) models
00142   // if 1 predecessor
00143   //   call Self::getNextIModel with limit where nothing is relevant
00144   //   (this returns (simply linked) models without backtracking in the model graph)
00145   // otherwise
00146   //   calculate CAUs from u
00147   //   calculate join-relevant units
00148   //   call Self::getNextIModel while it returns models
00149   // mark u as calculated
00150   // return number of generated models
00151 
00152   unsigned modelcounter = 0;
00153   if( pbegin == pend )
00154   {
00155     // no predecessors -> create dummy models using base class functionality
00156     LOG(MODELB,"asking for (dummy) models");
00157     while(Base::getNextIModel(u) != boost::none)
00158       modelcounter++;
00159   }
00160   else if( (pbegin+1) == pend )
00161   {
00162     // one predecessor -> create jrp directly (no CAUAlgorithms required, although they would do the job)
00163     LOG(MODELB,"one predecessor, manually creating join relevance");
00164     assert(!currentjrp);
00165 
00166     CAUAlgorithms::JoinRelevancePropertyMap jr;
00167     CAUAlgorithms::initJoinRelevance(jr, Base::eg);
00168     currentjrp = jr;
00169 
00170     DBGLOG(DBG,"asking for imodels");
00171     while(Base::getNextIModel(u) != boost::none)
00172       modelcounter++;
00173     LOG(MODELB,"created " << modelcounter << " imodels");
00174 
00175     currentjrp = boost::none;
00176   }
00177   else
00178   {
00179     LOG(MODELB,"more than one predecessor -> using CAUAlgorithms");
00180     assert(!currentjrp);
00181 
00182     CAUAlgorithms::AncestryPropertyMap apm;
00183     std::set<EvalUnit> caus;
00184     CAUAlgorithms::findCAUs(caus, Base::eg, u, apm);
00185     CAUAlgorithms::logAPM(apm);
00186     CAUAlgorithms::JoinRelevancePropertyMap jr;
00187     CAUAlgorithms::markJoinRelevance(jr, Base::eg, u, caus, apm);
00188     CAUAlgorithms::logJRPM(jr);
00189     currentjrp = jr;
00190 
00191     DBGLOG(DBG,"asking for imodels");
00192     while(Base::getNextIModel(u) != boost::none)
00193       modelcounter++;
00194     LOG(MODELB,"created " << modelcounter << " imodels");
00195 
00196     currentjrp = boost::none;
00197   }
00198 
00199   offmbp[u].builtIModels = true;
00200   return modelcounter;
00201 }
00202 
00203 template<typename EvalGraphT>
00204 unsigned OfflineModelBuilder<EvalGraphT>::buildOModels(
00205     EvalUnit u)
00206 {
00207   LOG_VSCOPE(MODELB,"bOM",u,true);
00208   DBGLOG(DBG,"=OfflineModelBuilder<...>::buildOModels(" << u << ")");
00209   //const EvalUnitPropertyBundle& uprops = Base::eg.propsOf(u);
00210   //LOG("rules: " << uprops.ctx.rules);
00211 
00212   assert(offmbp[u].builtIModels == true);
00213   assert(offmbp[u].builtOModels == false);
00214 
00215   // for all imodels present
00216   //   call Base::getNextOModel while it returns models
00217   // mark u as calculated
00218   // return number of generated models
00219 
00220   unsigned modelcounter = 0;
00221 
00222   assert(!currentjrp);
00223   CAUAlgorithms::JoinRelevancePropertyMap jr;
00224   CAUAlgorithms::initJoinRelevance(jr, Base::eg);
00225   currentjrp = jr;
00226 
00227   DBGLOG(DBG,"asking for omodels");
00228   while(Base::getNextOModel(u) != boost::none)
00229     modelcounter++;
00230   LOG(MODELB,"created " << modelcounter << " omodels");
00231 
00232   currentjrp = boost::none;
00233   offmbp[u].builtOModels = true;
00234   return modelcounter;
00235 }
00236 
00237 // automatically calls buildOModelsRecursively on any non-calculated predecessor
00238 template<typename EvalGraphT>
00239 unsigned OfflineModelBuilder<EvalGraphT>::buildIModelsRecursively(
00240     EvalUnit u)
00241 {
00242   LOG_VSCOPE(MODELB,"bIMR",u,true);
00243   DBGLOG(DBG,"=OfflineModelBuilder<...>::buildIModelsRecursively(" << u << ")@" << printptr(this));
00244 
00245   // no assertions here, we succeed if we already built the models
00246   if( offmbp[u].builtIModels == true )
00247   {
00248     unsigned count = Base::mg.modelsAt(u,MT_IN).size(); // TODO: how about iproject?
00249     LOG(MODELB,"already built -> counting " << count << " imodels");
00250     return count;
00251   }
00252 
00253   typename EvalGraphT::PredecessorIterator pbegin, pend;
00254   boost::tie(pbegin, pend) = Base::eg.getPredecessors(u);
00255 
00256   typename EvalGraphT::PredecessorIterator pit;
00257   for(pit = pbegin; pit != pend; ++pit)
00258   {
00259     EvalUnit upred = Base::eg.targetOf(*pit);
00260     if( offmbp[upred].builtOModels == false )
00261     {
00262       LOG(MODELB,"predecessor " << upred << " has no built omodels");
00263       unsigned count = buildOModelsRecursively(upred);
00264       LOG(MODELB,"built " << count << " models in predecessor");
00265     }
00266     else
00267     {
00268       LOG(MODELB,"predecessor " << upred << " has omodels");
00269     }
00270   }
00271 
00272   unsigned count = buildIModels(u);
00273   LOG(MODELB,"built " << count << " imodels here");
00274   return count;
00275 }
00276 
00277 template<typename EvalGraphT>
00278 // automatically calls buildIModelsRecursively if imodels are not calculated yet
00279 unsigned OfflineModelBuilder<EvalGraphT>::buildOModelsRecursively(
00280     EvalUnit u)
00281 {
00282   LOG_VSCOPE(MODELB,"bOMR",u,true);
00283   DBGLOG(DBG,"=OfflineModelBuilder<...>::buildOModelsRecursively(" << u << ")@" << printptr(this));
00284 
00285   // no assertions here, we succeed if we already built the models
00286   if( offmbp[u].builtOModels == true )
00287   {
00288     unsigned count = Base::mg.modelsAt(u,MT_OUT).size(); // TODO: how about oproject?
00289     LOG(MODELB,"already built -> counting " << count << " omodels");
00290     return count;
00291   }
00292 
00293   if( offmbp[u].builtIModels == false )
00294   {
00295     LOG(MODELB,"have no imodels");
00296     unsigned count = buildIModelsRecursively(u);
00297     LOG(MODELB,"built " << count << " imodels here");
00298   }
00299   else
00300   {
00301     LOG(MODELB,"already have imodels");
00302   }
00303   
00304   unsigned count = buildOModels(u);
00305   LOG(MODELB,"built " << count << " omodels here");
00306   return count;
00307 }
00308 
00309 template<typename EvalGraphT>
00310 typename OfflineModelBuilder<EvalGraphT>::OptionalModel
00311 OfflineModelBuilder<EvalGraphT>::getNextIModel(
00312     EvalUnit u)
00313 {
00314   LOG_VSCOPE(MODELB,"offgnIM",u,true);
00315   DBGLOG(DBG,"=OfflineModelBuilder<...>::getNextIModel(" << u << ")");
00316   //logEvalGraphModelGraph();
00317 
00318   assert(!!currentjrp);
00319   if( currentjrp.get()[u] )
00320   {
00321     LOG(MODELB,"join relevant");
00322     return Base::getNextIModel(u);
00323   }
00324   else
00325   {
00326     LOG(MODELB,"not join relevant");
00327     assert(offmbp[u].builtIModels);
00328     // TODO how about iproj?
00329     const ModelList& mlist = Base::mg.modelsAt(u, MT_IN);
00330     if( !!offmbp[u].currentIModel )
00331     {
00332       //assert(offmbp[u].currentIModel.get() != mlist.end());
00333       LOG(MODELB,"advancing iterator");
00334       //if( Base::mg.propsOf(*offmbp[u].currentIModel.get()).dummy == 1 )
00335       //  logEvalGraphModelGraph();
00336       offmbp[u].currentIModel.get()++;
00337     }
00338     else
00339     {
00340       LOG(MODELB,"initializing iterator");
00341       offmbp[u].currentIModel = mlist.begin();
00342     }
00343     if( offmbp[u].currentIModel.get() == mlist.end() )
00344     {
00345       LOG(MODELB,"no more models");
00346       Base::mbp[u].setIModel(boost::none);
00347       offmbp[u].currentIModel = boost::none;
00348       return boost::none;
00349     }
00350     else
00351     {
00352       Model m = *offmbp[u].currentIModel.get();
00353       Base::mbp[u].setIModel(m);
00354       LOG(MODELB,"got model " << m);
00355       return m;
00356     }
00357   }
00358 }
00359 
00360 DLVHEX_NAMESPACE_END
00361 
00362 #endif // OFFLINE_MODEL_BUILDER_HPP_INCLUDED__28092010