dlvhex
2.5.0
|
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 EVAL_GRAPH_HPP_INCLUDED__29082010 00035 #define EVAL_GRAPH_HPP_INCLUDED__29082010 00036 00037 #include "dlvhex2/PlatformDefinitions.h" 00038 #include "dlvhex2/Printhelpers.h" 00039 #include "dlvhex2/GraphvizHelpers.h" 00040 00041 #include <cassert> 00042 00043 #include <boost/graph/graph_traits.hpp> 00044 #include <boost/graph/adjacency_list.hpp> 00045 #include <boost/concept/assert.hpp> 00046 #include <boost/concept_check.hpp> 00047 #include <boost/shared_ptr.hpp> 00048 #include <boost/foreach.hpp> 00049 00050 DLVHEX_NAMESPACE_BEGIN 00051 00052 struct none_t 00053 { 00054 inline std::ostream& print(std::ostream& o) const { return o; } 00055 }; 00056 00059 template< 00060 typename EvalUnitPropertyBaseT = none_t, 00061 typename EvalUnitDepPropertyBaseT = none_t> 00062 class EvalGraph 00063 { 00065 // types 00067 public: 00068 typedef EvalUnitPropertyBaseT EvalUnitPropertyBase; 00069 typedef EvalUnitDepPropertyBaseT EvalUnitDepPropertyBase; 00070 00072 struct EvalUnitPropertyBundle: 00073 public EvalUnitPropertyBase, 00074 public ostream_printable<EvalUnitPropertyBundle> 00075 { 00078 EvalUnitPropertyBundle( 00079 const EvalUnitPropertyBase& base = EvalUnitPropertyBase()): 00080 EvalUnitPropertyBase(base) {} 00081 00082 std::ostream& print(std::ostream& o) const 00083 { return o << static_cast<const EvalUnitPropertyBase>(*this); } 00084 }; 00086 struct EvalUnitDepPropertyBundle: 00087 public EvalUnitDepPropertyBaseT, 00088 public ostream_printable<EvalUnitDepPropertyBundle> 00089 { 00090 // storage 00092 unsigned joinOrder; 00093 00094 // init 00097 EvalUnitDepPropertyBundle( 00098 unsigned joinOrder = 0): 00099 joinOrder(joinOrder) {} 00103 EvalUnitDepPropertyBundle( 00104 const EvalUnitDepPropertyBase& base, 00105 unsigned joinOrder = 0): 00106 EvalUnitDepPropertyBase(base), 00107 joinOrder(joinOrder) {} 00108 00109 std::ostream& print(std::ostream& o) const 00110 { 00111 return o << "joinOrder=" << joinOrder << " " << 00112 static_cast<const EvalUnitDepPropertyBase>(*this); 00113 } 00114 }; 00115 00116 // rationales for choice of vecS here: 00117 // * we will add eval units once and don't remove units later on, 00118 // therefore the high cost of removing units is not problematic 00119 // (if we need to modify the eval graph, this should be done before 00120 // creating it in this form, and it should be done on a listS representation 00121 // - for that we could add a template parameter StorageT to this class 00122 // and convertibility from listS to vecS storage) 00123 // * vecS creates an implicit vertex index, as descriptors of vecS are integers 00124 // * therefore we can create vector_property_maps over EvalUnit and EvalUnitDep, 00125 // and these property maps have efficient lookup. 00126 // * therefore we can distribute the properties among several such maps and 00127 // need not put all into one property bundle 00128 typedef boost::adjacency_list< 00129 boost::vecS, boost::vecS, boost::bidirectionalS, 00130 EvalUnitPropertyBundle, EvalUnitDepPropertyBundle> 00131 EvalGraphInt; 00132 typedef typename boost::graph_traits<EvalGraphInt> Traits; 00133 00134 typedef typename EvalGraphInt::vertex_descriptor EvalUnit; 00135 typedef typename EvalGraphInt::edge_descriptor EvalUnitDep; 00136 typedef typename Traits::vertex_iterator EvalUnitIterator; 00137 typedef typename Traits::edge_iterator DependencyIterator; 00138 typedef typename Traits::out_edge_iterator PredecessorIterator; 00139 typedef typename Traits::in_edge_iterator SuccessorIterator; 00140 00142 class Observer 00143 { 00144 public: 00146 virtual ~Observer() {} 00149 virtual void addUnit(EvalUnit u) = 0; 00152 virtual void addDependency(EvalUnitDep d) = 0; 00153 }; 00154 typedef boost::shared_ptr<Observer> ObserverPtr; 00155 00157 // members 00159 private: 00160 EvalGraphInt eg; 00161 std::set<ObserverPtr> observers; 00162 00164 // methods 00166 public: 00168 EvalGraph() 00169 {} 00175 EvalGraph(const EvalGraph& other); 00176 inline const EvalGraphInt& getInt() const 00177 { return eg; } 00178 00181 inline EvalUnit addUnit(const EvalUnitPropertyBundle& prop) { 00182 EvalUnit u = boost::add_vertex(prop, eg); 00183 BOOST_FOREACH(ObserverPtr o, observers) 00184 { o->addUnit(u); } 00185 return u; 00186 } 00187 00192 inline EvalUnitDep addDependency(EvalUnit u1, EvalUnit u2, 00193 const EvalUnitDepPropertyBundle& prop) { 00194 #ifndef NDEBUG 00195 // check if the joinOrder is correct 00196 // (require that dependencies are added in join order) 00197 PredecessorIterator pit, pend; 00198 boost::tie(pit,pend) = getPredecessors(u1); 00199 unsigned count; 00200 for(count = 0; pit != pend; ++pit, ++count) { 00201 const EvalUnitDepPropertyBundle& predprop = propsOf(*pit); 00202 if( prop.joinOrder == predprop.joinOrder ) 00203 throw std::runtime_error("EvalGraph::addDependency " 00204 "reusing join order not allowed"); 00205 } 00206 if( count != prop.joinOrder ) 00207 throw std::runtime_error("EvalGraph::addDependency " 00208 "using wrong (probably too high) join order"); 00209 #endif 00210 00211 bool success; 00212 EvalUnitDep dep; 00213 boost::tie(dep, success) = boost::add_edge(u1, u2, prop, eg); 00214 // if this fails, we tried to add a foreign eval unit or something strange like this 00215 assert(success); 00216 BOOST_FOREACH(ObserverPtr o, observers) 00217 { o->addDependency(dep); } 00218 return dep; 00219 } 00220 00223 void addObserver(ObserverPtr o) { 00224 observers.insert(o); 00225 } 00226 00229 void eraseObserver(ObserverPtr o) { 00230 observers.erase(o); 00231 } 00232 00235 inline std::pair<EvalUnitIterator, EvalUnitIterator> 00236 getEvalUnits() const 00237 { 00238 return boost::vertices(eg); 00239 } 00240 00241 // predecessors are eval units providing input to us, 00242 // edges are dependencies, so predecessors are at outgoing edges 00243 inline std::pair<PredecessorIterator, PredecessorIterator> 00244 getPredecessors(EvalUnit u) const 00245 { 00246 return boost::out_edges(u, eg); 00247 } 00248 00253 inline std::pair<SuccessorIterator, SuccessorIterator> 00254 getSuccessors(EvalUnit u) const 00255 { 00256 return boost::in_edges(u, eg); 00257 } 00258 00262 inline const EvalUnitDepPropertyBundle& propsOf(EvalUnitDep d) const 00263 { 00264 return eg[d]; 00265 } 00266 00270 inline EvalUnitDepPropertyBundle& propsOf(EvalUnitDep d) { 00271 return eg[d]; 00272 } 00273 00277 inline const EvalUnitPropertyBundle& propsOf(EvalUnit u) const 00278 { 00279 return eg[u]; 00280 } 00281 00285 inline EvalUnitPropertyBundle& propsOf(EvalUnit u) { 00286 return eg[u]; 00287 } 00288 00292 inline EvalUnit sourceOf(EvalUnitDep d) const 00293 { 00294 return boost::source(d, eg); 00295 } 00296 00300 inline EvalUnit targetOf(EvalUnitDep d) const 00301 { 00302 return boost::target(d, eg); 00303 } 00304 00307 inline unsigned countEvalUnits() const 00308 { 00309 return boost::num_vertices(eg); 00310 } 00311 00314 inline unsigned countEvalUnitDeps() const 00315 { 00316 return boost::num_edges(eg); 00317 } 00318 00322 void writeGraphViz(std::ostream& o, bool verbose) const; 00323 00324 struct Impl; 00325 }; // class EvalGraph<...> 00326 00329 struct EvalUnitProjectionProperties 00330 { 00331 // storage 00333 bool iproject; 00335 bool oproject; 00336 00337 // init 00341 EvalUnitProjectionProperties( 00342 bool iproject = false, 00343 bool oproject = false): 00344 iproject(iproject), oproject(oproject) {} 00345 }; 00346 00348 template<typename EvalUnitPropertyBaseT, typename EvalUnitDepPropertyBaseT> 00349 struct EvalGraph<EvalUnitPropertyBaseT, EvalUnitDepPropertyBaseT>::Impl 00350 { 00354 static std::string graphviz_node_id(EvalUnit u) { 00355 std::ostringstream os; 00356 os << "u" << u; 00357 return os.str(); 00358 } 00359 }; 00360 00364 template<typename EvalUnitPropertyBaseT, typename EvalUnitDepPropertyBaseT> 00365 void EvalGraph<EvalUnitPropertyBaseT, EvalUnitDepPropertyBaseT>:: 00366 writeGraphViz(std::ostream& o, bool verbose) const 00367 { 00368 // boost::graph::graphviz is horribly broken! 00369 // therefore we print it ourselves 00370 00371 o << "digraph G {" << std::endl << 00372 "rankdir=BT;" << std::endl;// print root nodes at bottom, leaves at top! 00373 00374 // print vertices 00375 EvalUnitIterator it, it_end; 00376 unsigned index = 0; 00377 for(boost::tie(it, it_end) = boost::vertices(eg); 00378 it != it_end; ++it, ++index) { 00379 o << Impl::graphviz_node_id(*it) << "[shape=record,label=\"{" << *it << "|"; 00380 { 00381 std::ostringstream ss; 00382 // write eval unit property 00383 ss << propsOf(*it); 00384 graphviz::escape(o, ss.str()); 00385 } 00386 o << "}\"];" << std::endl; 00387 } 00388 00389 // print edges 00390 DependencyIterator dit, dit_end; 00391 for(boost::tie(dit, dit_end) = boost::edges(eg); 00392 dit != dit_end; ++dit) { 00393 EvalUnit src = sourceOf(*dit); 00394 EvalUnit target = targetOf(*dit); 00395 o << Impl::graphviz_node_id(src) << " -> " << Impl::graphviz_node_id(target) << 00396 "[label=\""; 00397 { 00398 std::ostringstream ss; 00399 ss << *dit; 00400 graphviz::escape(o, ss.str()); 00401 } 00402 o << "\"];" << std::endl; 00403 } 00404 00405 o << "}" << std::endl; 00406 } 00407 00408 00409 DLVHEX_NAMESPACE_END 00410 #endif // EVAL_GRAPH_HPP_INCLUDED__29082010 00411 00412 // vim:expandtab:ts=4:sw=4: 00413 // mode: C++ 00414 // End: