dlvhex  2.5.0
include/dlvhex2/ModelGraph.h
Go to the documentation of this file.
00001 /* dlvhex -- Answer-Set Programming with external interfaces.
00002  * Copyright (C) 2009-2016 Peter Schüller
00003  * Copyright (C) 2011-2016 Christoph Redl
00004  * Copyright (C) 2015-2016 Tobias Kaminski
00005  * Copyright (C) 2015-2016 Antonius Weinzierl
00006  *
00007  * This file is part of dlvhex.
00008  *
00009  * dlvhex is free software; you can redistribute it and/or modify it
00010  * under the terms of the GNU Lesser General Public License as
00011  * published by the Free Software Foundation; either version 2.1 of
00012  * the License, or (at your option) any later version.
00013  *
00014  * dlvhex is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with dlvhex; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00022  * 02110-1301 USA.
00023  */
00024 
00025 #ifndef MODEL_GRAPH_HPP_INCLUDED__29082010
00026 #define MODEL_GRAPH_HPP_INCLUDED__29082010
00027 
00028 #include "dlvhex2/PlatformDefinitions.h"
00029 #include "dlvhex2/EvalGraph.h"
00030 #include "dlvhex2/Logger.h"
00031 #include "dlvhex2/Printhelpers.h"
00032 
00033 #include <boost/graph/graph_traits.hpp>
00034 #include <boost/graph/adjacency_list.hpp>
00035 #include <boost/concept/assert.hpp>
00036 #include <boost/concept_check.hpp>
00037 #include <boost/optional.hpp>
00038 #include <boost/shared_ptr.hpp>
00039 
00040 #include <cassert>
00041 #include <iomanip>
00042 
00043 DLVHEX_NAMESPACE_BEGIN
00044 
00046 enum ModelType
00047 {
00049     MT_IN = 0,
00051     MT_INPROJ = 1,
00053     MT_OUT = 2,
00055     MT_OUTPROJ = 3,
00056 };
00057 
00061 inline const char* toString(ModelType mt)
00062 {
00063     switch(mt) {
00064         case MT_IN:      return "IN";
00065         case MT_INPROJ:  return "INPROJ";
00066         case MT_OUT:     return "OUT";
00067         case MT_OUTPROJ: return "OUTPROJ";
00068                                  // keep compiler happy with NDEBUG
00069         default: assert(false); return "";
00070     }
00071 }
00072 
00073 
00081 template<
00082 typename EvalGraphT,
00083 typename ModelPropertyBaseT = none_t,
00084 typename ModelDepPropertyBaseT = none_t>
00085 class ModelGraph
00086 {
00088     // types
00090     public:
00091         typedef ModelGraph<EvalGraphT, ModelPropertyBaseT, ModelDepPropertyBaseT> Self;
00092         typedef EvalGraphT MyEvalGraph;
00093         typedef ModelPropertyBaseT ModelPropertyBase;
00094         typedef ModelDepPropertyBaseT ModelDepPropertyBase;
00095 
00096         // concept check: must be an eval graph
00097         // TODO: solve not via convertible but via other helper
00098         BOOST_CONCEPT_ASSERT((boost::Convertible<
00099             EvalGraphT,
00100             EvalGraph<
00101             typename EvalGraphT::EvalUnitPropertyBase,
00102             typename EvalGraphT::EvalUnitDepPropertyBase> >));
00103         typedef typename EvalGraphT::EvalUnit EvalUnit;
00104         typedef typename EvalGraphT::EvalUnitDep EvalUnitDep;
00105 
00106         // concept check: eval graph must store projection properties for units
00107         BOOST_CONCEPT_ASSERT((boost::Convertible<
00108             typename EvalGraphT::EvalUnitPropertyBundle,
00109             EvalUnitProjectionProperties>));
00110 
00111         struct ModelPropertyBundle;
00112         struct ModelDepPropertyBundle;
00113 
00114     private:
00115         typedef boost::adjacency_list<
00116             boost::listS, boost::listS, boost::bidirectionalS,
00117             ModelPropertyBundle, ModelDepPropertyBundle>
00118             ModelGraphInt;
00119         typedef typename boost::graph_traits<ModelGraphInt> Traits;
00120 
00121     public:
00122         typedef typename ModelGraphInt::vertex_descriptor Model;
00123         typedef typename ModelGraphInt::edge_descriptor ModelDep;
00124         typedef typename Traits::vertex_iterator ModelIterator;
00125         typedef typename Traits::out_edge_iterator PredecessorIterator;
00126         typedef typename Traits::in_edge_iterator SuccessorIterator;
00127 
00129         struct ModelPropertyBundle:
00130     public ModelPropertyBaseT,
00131         public ostream_printable<ModelPropertyBundle>
00132     {
00133         // storage
00134 
00136         EvalUnit location;
00138         ModelType type;
00139 
00140         protected:
00141             // successor models per successor eval unit, suitable for fast set intersection
00142             // (we also need the chronological ordering of adjacency_list,
00143             //  so we cannot replace that one by an ordered container)
00144 
00145             // (we must not use "Model" here because "Model" is defined using
00146             // "ModelPropertyBundle" (i.e., this class))
00147             //typedef std::map<EvalUnit, std::set<Model> > SuccessorModelMap;
00148             typedef std::map<EvalUnit, std::set<void*> > SuccessorModelMap;
00149             SuccessorModelMap successors;
00150 
00151         public:
00152             // init
00156             ModelPropertyBundle(
00157                 EvalUnit location = EvalUnit(),
00158                 ModelType type = MT_IN):
00159             location(location),
00160                 type(type) {}
00165             ModelPropertyBundle(
00166                 const ModelPropertyBaseT& base,
00167                 EvalUnit location = EvalUnit(),
00168                 ModelType type = MT_IN):
00169             ModelPropertyBaseT(base),
00170                 location(location),
00171                 type(type) {}
00172             std::ostream& print(std::ostream& o) const
00173             {
00174                 return o << print_method(static_cast<ModelPropertyBaseT>(*this));
00175             }
00176             // the model graph will manage the set of successors
00177             friend class ModelGraph<EvalGraphT, ModelPropertyBaseT, ModelDepPropertyBaseT>;
00178     };
00179 
00181     struct ModelDepPropertyBundle:
00182     public ModelDepPropertyBaseT,
00183         public ostream_printable<ModelDepPropertyBundle>
00184     {
00185         // storage
00186 
00188         unsigned joinOrder;
00189 
00190         // init
00193         ModelDepPropertyBundle(
00194             unsigned joinOrder = 0):
00195         joinOrder(joinOrder) {}
00199         ModelDepPropertyBundle(
00200             const ModelDepPropertyBaseT& base,
00201             unsigned joinOrder = 0):
00202         ModelDepPropertyBaseT(base),
00203             joinOrder(joinOrder) {}
00204     };
00205 
00206     // "exterior property map" for the eval graph: which models are present at which unit
00207     typedef std::list<Model> ModelList;
00209     struct EvalUnitModels
00210     {
00211         protected:
00217             boost::shared_ptr< std::vector<ModelList> > models;
00218         public:
00220             EvalUnitModels(): models(new std::vector<ModelList>(4, ModelList()))
00221                 { DBGLOG(DBG, "EvalUnitModels()@" << this); }
00224             EvalUnitModels(const EvalUnitModels& eum): models(eum.models)
00225                 { DBGLOG(DBG, "EvalUnitModels(const EvalUnitModels&)@" << this << " from " << &eum); }
00226             ~EvalUnitModels()
00227                 { DBGLOG(DBG, "~EvalUnitModels()@" << this); }
00231             inline ModelList& getModels(ModelType t)
00232                 { assert(0 <= t && t <= 4); assert(models.use_count() == 1); return (*models)[t]; }
00236             inline const ModelList& getModels(ModelType t) const
00237                 { assert(0 <= t && t <= 4); assert(models.use_count() == 1); return (*models)[t]; }
00239             void reallocate()
00240                 { models.reset(new std::vector<ModelList>(models->begin(), models->end())); }
00241     };
00242     typedef boost::vector_property_map<EvalUnitModels>
00243         EvalUnitModelsPropertyMap;
00244 
00246     // members
00248     private:
00250         EvalGraphT& eg;
00252         ModelGraphInt mg;
00256         EvalUnitModelsPropertyMap mau;
00257 
00259         // methods
00261     public:
00266         ModelGraph(EvalGraphT& eg):
00267         eg(eg), mg(), mau() {
00268             // get last unit
00269             // as eg uses vecS this is the maximum index we need in mau
00270             EvalUnit lastUnit = *(eg.getEvalUnits().second - 1);
00271             // this is an integer -> reserve for one more unit
00272             lastUnit++;
00273             // do it this way as we are not allowed to do
00274             // mau.store->reserve(lastUnit)
00275             mau[lastUnit] = EvalUnitModels();
00276             // now reallocate all (we do not want duplicate pointers to model lists)
00277             // @todo: this is a real hack, we should create our own vector property map with custom resizing
00278             for(unsigned u = 0; u <= lastUnit; ++u)
00279                 mau[u].reallocate();
00280         }
00281 
00305         Model addModel(
00306             EvalUnit location,
00307             ModelType type,
00308             const std::vector<Model>& deps=std::vector<Model>());
00309 
00313         boost::optional<Model> getSuccessorIntersection(EvalUnit location, const std::vector<Model>& mm) const;
00314 
00317         inline std::pair<ModelIterator, ModelIterator> getModels() const
00318             { return boost::vertices(mg); }
00319 
00322         inline const ModelGraphInt& getInternalGraph() const
00323             { return mg; }
00324 
00329         inline const ModelList& modelsAt(EvalUnit unit, ModelType type) const
00330         {
00331             return mau[unit].getModels(type);
00332         }
00333 
00337         inline const ModelList& relevantIModelsAt(EvalUnit unit) const
00338         {
00339             if( eg.propsOf(unit).iproject )
00340                 return modelsAt(unit, MT_INPROJ);
00341             else
00342                 return modelsAt(unit, MT_IN);
00343         }
00344 
00348         inline const ModelList& relevantOModelsAt(EvalUnit unit) const
00349         {
00350             if( eg.propsOf(unit).oproject )
00351                 return modelsAt(unit, MT_OUTPROJ);
00352             else
00353                 return modelsAt(unit, MT_OUT);
00354         }
00355 
00359         inline const ModelPropertyBundle& propsOf(Model m) const
00360         {
00361             return mg[m];
00362         }
00363 
00367         inline ModelPropertyBundle& propsOf(Model m) {
00368             return mg[m];
00369         }
00370 
00374         inline const ModelDepPropertyBundle& propsOf(ModelDep d) const
00375         {
00376             return mg[d];
00377         }
00378 
00382         inline ModelDepPropertyBundle& propsOf(ModelDep d) {
00383             return mg[d];
00384         }
00385 
00391         inline std::pair<PredecessorIterator, PredecessorIterator>
00392             getPredecessors(Model m) const
00393         {
00394             return boost::out_edges(m, mg);
00395         }
00396 
00402         inline std::pair<SuccessorIterator, SuccessorIterator>
00403             getSuccessors(Model m) const
00404         {
00405             return boost::in_edges(m, mg);
00406         }
00407 
00411         inline Model sourceOf(ModelDep d) const
00412         {
00413             return boost::source(d, mg);
00414         }
00415 
00419         inline Model targetOf(ModelDep d) const
00420         {
00421             return boost::target(d, mg);
00422         }
00423 
00426         inline unsigned countModels() const
00427         {
00428             return boost::num_vertices(mg);
00429         }
00430 
00433         inline unsigned countModelDeps() const
00434         {
00435             return boost::num_edges(mg);
00436         }
00437 };                               // class ModelGraph
00438 
00439 // ModelGraph<...>::addModel(...) implementation
00440 template<typename EvalGraphT, typename ModelPropertiesT, typename ModelDepPropertiesT>
00441 typename ModelGraph<EvalGraphT, ModelPropertiesT, ModelDepPropertiesT>::Model
00442 ModelGraph<EvalGraphT, ModelPropertiesT, ModelDepPropertiesT>::addModel(
00443 EvalUnit location,
00444 ModelType type,
00445 const std::vector<Model>& deps)
00446 {
00447     typedef typename EvalGraphT::PredecessorIterator PredecessorIterator;
00448     typedef typename EvalGraphT::EvalUnitDepPropertyBundle EvalUnitDepPropertyBundle;
00449     typedef typename EvalGraphT::EvalUnitPropertyBundle EvalUnitPropertyBundle;
00450     LOG_VSCOPE(MODELB,"MG::addModel",this,true);
00451 
00452     #ifndef NDEBUG
00453     DBGLOG(DBG, "running debug checks");
00454     switch(type) {
00455         case MT_IN:
00456         {
00457             // input models:
00458             // * checks if join order is equal to join order of eval graph
00459             // * checks if input models depend on all units this unit depends on
00460             // (this is an implicit check if we exactly use all predecessor units)
00461             PredecessorIterator it, end;
00462             for(boost::tie(it, end) = eg.getPredecessors(location);
00463             it != end; ++it) {
00464                 // check whether each predecessor is stored at the right position in the vector
00465                 // the join order starts at 0, so we use it for indexing into the deps vector
00466 
00467                 // check if joinOrder == index is within range of deps vector
00468                 const EvalUnitDepPropertyBundle& predprop = eg.propsOf(*it);
00469                 if( predprop.joinOrder >= deps.size() )
00470                     throw std::runtime_error("ModelGraph::addModel MT_IN "
00471                         "not enough join dependencies");
00472 
00473                 // check if correct unit is referenced by model
00474                 EvalUnit predunit = eg.targetOf(*it);
00475                 const ModelPropertyBundle& depprop = propsOf(deps[predprop.joinOrder]);
00476                 if( depprop.location != predunit )
00477                     throw std::runtime_error("ModelGraph::addModel MT_IN "
00478                         "with wrong join order");
00479             }
00480             // if we are here we found for each predecessor one unit in deps,
00481             // assuming joinOrder of predecessors are correct,
00482             // the models in the deps vector exactly use all predecessor units
00483         }
00484         break;
00485 
00486         case MT_INPROJ:
00487         {
00488             // projected input models
00489             // * checks if model depends on MT_IN model at same unit
00490             // * checks if projection is configured for unit
00491             if( deps.size() != 1 )
00492                 throw std::runtime_error("ModelGraph::addModel MT_INPROJ "
00493                     "must depend on exactly one MT_IN model");
00494             const ModelPropertyBundle& depprop = propsOf(deps[0]);
00495             if( depprop.location != location )
00496                 throw std::runtime_error("ModelGraph::addModel MT_INPROJ "
00497                     "must depend on model at same eval unit");
00498             if( depprop.type != MT_IN )
00499                 throw std::runtime_error("ModelGraph::addModel MT_INPROJ "
00500                     "must depend on exactly one MT_IN model");
00501             const EvalUnitPropertyBundle& unitprop = eg.propsOf(location);
00502             if( !unitprop.iproject )
00503                 throw std::runtime_error("ModelGraph::addModel MT_INPROJ "
00504                     "only possible for units with iproject==true");
00505         }
00506         break;
00507 
00508         case MT_OUT:
00509         {
00510             // output models:
00511             // * checks if model depends on MT_IN or MT_INPROJ at same unit
00512             PredecessorIterator it, end;
00513             boost::tie(it, end) = eg.getPredecessors(location);
00514             if( it != end ) {
00515                 const ModelPropertyBundle& depprop = propsOf(deps[0]);
00516                 if( depprop.location != location )
00517                     throw std::runtime_error("ModelGraph::addModel MT_OUT "
00518                         "must depend on model at same eval unit");
00519                 const EvalUnitPropertyBundle& unitprop = eg.propsOf(location);
00520                 if( (unitprop.iproject && depprop.type != MT_INPROJ) ||
00521                     (!unitprop.iproject && depprop.type != MT_IN) )
00522                     throw std::runtime_error("ModelGraph::addModel MT_OUT "
00523                         "must depend on MT_INPROJ model for iproject==true "
00524                         "and on MT_IN model for iproject==false");
00525             }
00526         }
00527         break;
00528 
00529         case MT_OUTPROJ:
00530         {
00531             // projected output models:
00532             // * checks if model depends on MT_OUT at same unit
00533             // * checks if projection is configured for unit
00534             if( deps.size() != 1 )
00535                 throw std::runtime_error("ModelGraph::addModel MT_OUTPROJ "
00536                     "must depend on exactly one MT_OUT model");
00537             const ModelPropertyBundle& depprop = propsOf(deps[0]);
00538             if( depprop.location != location )
00539                 throw std::runtime_error("ModelGraph::addModel MT_OUTPROJ "
00540                     "must depend on model at same eval unit");
00541             if( depprop.type != MT_OUT )
00542                 throw std::runtime_error("ModelGraph::addModel MT_OUTPROJ "
00543                     "must depend on exactly one MT_OUT model");
00544             const EvalUnitPropertyBundle& unitprop = eg.propsOf(location);
00545             if( !unitprop.oproject )
00546                 throw std::runtime_error("ModelGraph::addModel MT_OUTPROJ "
00547                     "only possible for units with oproject==true");
00548         }
00549         break;
00550     }
00551     #endif
00552 
00553     // add model
00554     ModelPropertyBundle prop;
00555     prop.location = location;
00556     prop.type = type;
00557     Model m = boost::add_vertex(prop, mg);
00558     LOG(MODELB, "add_vertex returned " << m);
00559 
00560     // add model dependencies
00561     for(unsigned i = 0; i < deps.size(); ++i) {
00562         ModelDepPropertyBundle dprop(i);
00563         ModelDep dep;
00564         bool success;
00565         boost::tie(dep, success) = boost::add_edge(m, deps[i], dprop, mg);
00566         assert(success);
00567 
00568         // update ordered set of successors
00569         // (required for efficiently finding out whether for a given set of models
00570         //  there already exists a joined successor model at some eval unit)
00571 
00572         // if index does not exist, empty set will be created
00573         // TODO see getSuccessorIntersection
00574         std::set<void*>& successorsForThisEvalUnit =
00575             propsOf(deps[i]).successors[location];
00576         successorsForThisEvalUnit.insert(m);
00577     }
00578 
00579     // update modelsAt property map (models at each eval unit are registered there)
00580     LOG(MODELB, "updating mau");
00581     mau[location].getModels(type).push_back(m);
00582 
00583     return m;
00584 }                                // ModelGraph<...>::addModel(...) implementation
00585 
00586 
00587 // ModelGraph<...>::getSuccessorIntersection(...) implementation
00588 //
00589 // given an eval unit and for each predecessor of this unit a model,
00590 // this method intersects the successor models of all these models
00591 // return first intersected element, boost::none if none exists
00592 template<typename EvalGraphT, typename ModelPropertiesT, typename ModelDepPropertiesT>
00593 boost::optional<typename ModelGraph<EvalGraphT, ModelPropertiesT, ModelDepPropertiesT>::Model>
00594 ModelGraph<EvalGraphT, ModelPropertiesT, ModelDepPropertiesT>::getSuccessorIntersection(
00595 //EvalUnit location,
00596 //const std::vector<Model>& mm) const
00597 typename ModelGraph<EvalGraphT, ModelPropertiesT, ModelDepPropertiesT>::EvalUnit location,
00598 const std::vector<typename ModelGraph<EvalGraphT, ModelPropertiesT, ModelDepPropertiesT>::Model>& mm) const
00599 {
00600     const unsigned predecessors = mm.size();
00601 
00602     DBGLOG_SCOPE(DBG, "gSI", false);
00603     DBGLOG(DBG, "=getSuccessorIntersection(" << location << "," << predecessors << ")");
00604 
00605     #ifndef NDEBUG
00606     BOOST_FOREACH(Model m, mm) {
00607         // assert that we only to this for output models
00608         assert(propsOf(m).type == MT_OUT || propsOf(m).type == MT_OUTPROJ);
00609         // assert that we only do this for models between eval units (i.e., for joins)
00610         assert(propsOf(m).location != location);
00611         // (rationale: for other models we do not need this functionality,
00612         //  and therefore for other models "successors" will not be managed by addModel
00613         //  in order to conserve space)
00614         // TODO: really do not do this for other models
00615     }
00616     #endif
00617 
00618     // shortcut if only one dependency
00619     if( predecessors == 1 ) {
00620         DBGLOG(DBG, "one-dependency shortcut: simply finding corresponding model");
00621         typename ModelPropertyBundle::SuccessorModelMap::const_iterator itsucc =
00622             propsOf(mm.front()).successors.find(location);
00623         if( itsucc != propsOf(mm.front()).successors.end() ) {
00624             // found successor set -> good (take first, which should be the only one)
00625             const std::set<void*>& succs = itsucc->second;
00626             DBGLOG(DBG, "found successor (" << succs.size() << ")");
00627             assert(succs.size() == 1);
00628             return *succs.begin();
00629         }
00630         else {
00631             // did not find successor set
00632             DBGLOG(DBG, "no successors");
00633             return boost::none;
00634         }
00635     }
00636 
00637     // regular processing
00638     typedef typename std::set<void*>::const_iterator SuccIter;
00639     // for each predecessor model we have a begin and an end iterator of all of their successors
00640     typename std::vector<SuccIter> iters;
00641     typename std::vector<SuccIter> ends;
00642 
00643     // store begin() and end() of each model's successor iterators into succs and ends
00644     BOOST_FOREACH(Model m, mm) {
00645         typename ModelPropertyBundle::SuccessorModelMap::const_iterator itsucc =
00646             propsOf(m).successors.find(location);
00647         if( itsucc != propsOf(m).successors.end() ) {
00648             const std::set<void*>& succs = itsucc->second;
00649             iters.push_back(succs.begin());
00650             ends.push_back(succs.end());
00651             #ifndef NDEBUG
00652             DBGLOG(DBG, "model " << m << " at cursor index " <<
00653                 static_cast<unsigned>(iters.size()-1) << " has successors:");
00654             DBGLOG_INDENT(DBG);
00655             for(SuccIter sit = succs.begin(); sit != succs.end(); ++sit) {
00656                 DBGLOG(DBG, *sit);
00657             }
00658             #endif
00659         }
00660         else {
00661             // if one dependency has no successors, we can find no join
00662             DBGLOG(DBG, "model " << m << " at cursor index " <<
00663                 static_cast<unsigned>(iters.size()) << " has no successors -> failing");
00664             return boost::none;
00665         }
00666     }
00667 
00668     // here we have the guarantee, that every pair of iterators has at least one element in the range
00669 
00670     // join loop
00671 
00672     // this is the position where we currently "are"
00673     unsigned at = 0;
00674 
00675     // invariant: *iters[at] == *iters[at-1] == ... == *iters[0] (they point to the same successor model)
00676     // -> if "at == predecessors-1" cursor is at the end, we found a common successor (stored in all iterators)
00677 
00678     // strategy:
00679     // try to find equal successor at [at+1] as it already is at [at]
00680     //   increment iters[at+1] while < iters[at]
00681     //     if equal -> at++
00682     //     else -> increment all iters[X<=at] until >= iters[at+1] and set at = 0
00683     do {
00684         #ifndef NDEBUG
00685         DBGLOG(DBG, "at loop begin with cursor at " << at << ", models:");
00686         for(unsigned u = 0; u < predecessors; ++u) {
00687             DBGLOG(DBG, "  iterator " << u << " pointing to model " << *iters[u]);
00688         }
00689         #endif
00690         // success condition
00691         if( at == (predecessors-1) ) {
00692             Model m = *iters[0];
00693             DBGLOG(DBG, "found common successor model " << m << " -> returning");
00694             return m;
00695         }
00696 
00697         assert((at+1) < predecessors);
00698 
00699         // try to advance iters[at+1]
00700         while( *iters[at+1] < *iters[at] ) {
00701             iters[at+1]++;
00702             if( iters[at+1] == ends[at+1] ) {
00703                 DBGLOG(DBG, "no suitable model at " << at << " -> returning none");
00704                 return boost::none;
00705             }
00706             DBGLOG(DBG, "advancing " << (at+1) << " to model " << *iters[at+1]);
00707         }
00708 
00709         // check if same or greater
00710         if( *iters[at+1] == *iters[at] ) {
00711             DBGLOG(DBG, "model at " << (at+1) << " equal to model at " << at << " -> next position");
00712             at++;
00713         }
00714         else {
00715             DBGLOG(DBG, "model at " << (at+1) << " bigger than model at " << at << " -> backtracking");
00716             for(unsigned u = 0; u <= at; ++u) {
00717                 while( *iters[u] < *iters[at+1] ) {
00718                     iters[u]++;
00719                     if( iters[u] == ends[u] ) {
00720                         DBGLOG(DBG, "no suitable model at " << u << " -> returning none");
00721                         return boost::none;
00722                     }
00723                     DBGLOG(DBG, "advancing " << (u) << " to model " << *iters[u]);
00724                 }
00725             }
00726             // restart loop
00727             at = 0;
00728         }
00729     }
00730     while(true);
00731 }                                // ModelGraph<...>::getSuccessorIntersection(...) implementation
00732 
00733 
00734 DLVHEX_NAMESPACE_END
00735 #endif                           // MODEL_GRAPH_HPP_INCLUDED__29082010
00736 
00737 // vim:expandtab:ts=4:sw=4:
00738 // mode: C++
00739 // End: