dlvhex
2.5.0
|
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: