|
dlvhex
2.1.0
|
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 EVAL_GRAPH_HPP_INCLUDED__29082010 00032 #define EVAL_GRAPH_HPP_INCLUDED__29082010 00033 00034 #include "dlvhex2/PlatformDefinitions.h" 00035 #include "dlvhex2/Printhelpers.h" 00036 #include "dlvhex2/GraphvizHelpers.h" 00037 00038 #include <cassert> 00039 00040 #include <boost/graph/graph_traits.hpp> 00041 #include <boost/graph/adjacency_list.hpp> 00042 #include <boost/concept/assert.hpp> 00043 #include <boost/concept_check.hpp> 00044 #include <boost/shared_ptr.hpp> 00045 #include <boost/foreach.hpp> 00046 00047 DLVHEX_NAMESPACE_BEGIN 00048 00049 struct none_t 00050 { 00051 inline std::ostream& print(std::ostream& o) const { return o; } 00052 }; 00053 00054 // 00055 // the EvalGraph template manages a generic evaluation graph: 00056 // it takes care of a correct join order among in-edges of units 00057 // 00058 template< 00059 typename EvalUnitPropertyBaseT = none_t, 00060 typename EvalUnitDepPropertyBaseT = none_t> 00061 class EvalGraph 00062 { 00064 // types 00066 public: 00067 typedef EvalUnitPropertyBaseT EvalUnitPropertyBase; 00068 typedef EvalUnitDepPropertyBaseT EvalUnitDepPropertyBase; 00069 00070 struct EvalUnitPropertyBundle: 00071 public EvalUnitPropertyBase, 00072 public ostream_printable<EvalUnitPropertyBundle> 00073 { 00074 EvalUnitPropertyBundle( 00075 const EvalUnitPropertyBase& base = EvalUnitPropertyBase()): 00076 EvalUnitPropertyBase(base) {} 00077 00078 std::ostream& print(std::ostream& o) const 00079 { return o << static_cast<const EvalUnitPropertyBase>(*this); } 00080 }; 00081 struct EvalUnitDepPropertyBundle: 00082 public EvalUnitDepPropertyBaseT, 00083 public ostream_printable<EvalUnitDepPropertyBundle> 00084 { 00085 // storage 00086 unsigned joinOrder; 00087 00088 // init 00089 EvalUnitDepPropertyBundle( 00090 unsigned joinOrder = 0): 00091 joinOrder(joinOrder) {} 00092 EvalUnitDepPropertyBundle( 00093 const EvalUnitDepPropertyBase& base, 00094 unsigned joinOrder = 0): 00095 EvalUnitDepPropertyBase(base), 00096 joinOrder(joinOrder) {} 00097 00098 std::ostream& print(std::ostream& o) const 00099 { return o << "joinOrder=" << joinOrder << " " << 00100 static_cast<const EvalUnitDepPropertyBase>(*this); } 00101 }; 00102 00103 // rationales for choice of vecS here: 00104 // * we will add eval units once and don't remove units later on, 00105 // therefore the high cost of removing units is not problematic 00106 // (if we need to modify the eval graph, this should be done before 00107 // creating it in this form, and it should be done on a listS representation 00108 // - for that we could add a template parameter StorageT to this class 00109 // and convertibility from listS to vecS storage) 00110 // * vecS creates an implicit vertex index, as descriptors of vecS are integers 00111 // * therefore we can create vector_property_maps over EvalUnit and EvalUnitDep, 00112 // and these property maps have efficient lookup. 00113 // * therefore we can distribute the properties among several such maps and 00114 // need not put all into one property bundle 00115 typedef boost::adjacency_list< 00116 boost::vecS, boost::vecS, boost::bidirectionalS, 00117 EvalUnitPropertyBundle, EvalUnitDepPropertyBundle> 00118 EvalGraphInt; 00119 typedef typename boost::graph_traits<EvalGraphInt> Traits; 00120 00121 typedef typename EvalGraphInt::vertex_descriptor EvalUnit; 00122 typedef typename EvalGraphInt::edge_descriptor EvalUnitDep; 00123 typedef typename Traits::vertex_iterator EvalUnitIterator; 00124 typedef typename Traits::edge_iterator DependencyIterator; 00125 typedef typename Traits::out_edge_iterator PredecessorIterator; 00126 typedef typename Traits::in_edge_iterator SuccessorIterator; 00127 00128 class Observer 00129 { 00130 public: 00131 virtual ~Observer() {} 00132 virtual void addUnit(EvalUnit u) = 0; 00133 virtual void addDependency(EvalUnitDep d) = 0; 00134 }; 00135 typedef boost::shared_ptr<Observer> ObserverPtr; 00136 00138 // members 00140 private: 00141 EvalGraphInt eg; 00142 std::set<ObserverPtr> observers; 00143 00145 // methods 00147 public: 00148 EvalGraph() 00149 {} 00150 // this is not implemented on purpose (=linker error) because it is forbidden to use 00151 // (it cannot be private as this would cause concept checks to fail (TODO: check why clang produces such bad error messages in this case) 00152 EvalGraph(const EvalGraph& other); 00153 inline const EvalGraphInt& getInt() const 00154 { return eg; } 00155 00156 inline EvalUnit addUnit(const EvalUnitPropertyBundle& prop) 00157 { 00158 EvalUnit u = boost::add_vertex(prop, eg); 00159 BOOST_FOREACH(ObserverPtr o, observers) 00160 { o->addUnit(u); } 00161 return u; 00162 } 00163 00164 inline EvalUnitDep addDependency(EvalUnit u1, EvalUnit u2, 00165 const EvalUnitDepPropertyBundle& prop) 00166 { 00167 #ifndef NDEBUG 00168 // check if the joinOrder is correct 00169 // (require that dependencies are added in join order) 00170 PredecessorIterator pit, pend; 00171 boost::tie(pit,pend) = getPredecessors(u1); 00172 unsigned count; 00173 for(count = 0; pit != pend; ++pit, ++count) 00174 { 00175 const EvalUnitDepPropertyBundle& predprop = propsOf(*pit); 00176 if( prop.joinOrder == predprop.joinOrder ) 00177 throw std::runtime_error("EvalGraph::addDependency " 00178 "reusing join order not allowed"); 00179 } 00180 if( count != prop.joinOrder ) 00181 throw std::runtime_error("EvalGraph::addDependency " 00182 "using wrong (probably too high) join order"); 00183 #endif 00184 00185 bool success; 00186 EvalUnitDep dep; 00187 boost::tie(dep, success) = boost::add_edge(u1, u2, prop, eg); 00188 // if this fails, we tried to add a foreign eval unit or something strange like this 00189 assert(success); 00190 BOOST_FOREACH(ObserverPtr o, observers) 00191 { o->addDependency(dep); } 00192 return dep; 00193 } 00194 00195 void addObserver(ObserverPtr o) 00196 { 00197 observers.insert(o); 00198 } 00199 00200 void eraseObserver(ObserverPtr o) 00201 { 00202 observers.erase(o); 00203 } 00204 00205 inline std::pair<EvalUnitIterator, EvalUnitIterator> 00206 getEvalUnits() const 00207 { 00208 return boost::vertices(eg); 00209 } 00210 00211 // predecessors are eval units providing input to us, 00212 // edges are dependencies, so predecessors are at outgoing edges 00213 inline std::pair<PredecessorIterator, PredecessorIterator> 00214 getPredecessors(EvalUnit u) const 00215 { 00216 return boost::out_edges(u, eg); 00217 } 00218 00219 // successors are eval units we provide input to, 00220 // edges are dependencies, so successors are at incoming edges 00221 inline std::pair<SuccessorIterator, SuccessorIterator> 00222 getSuccessors(EvalUnit u) const 00223 { 00224 return boost::in_edges(u, eg); 00225 } 00226 00227 inline const EvalUnitDepPropertyBundle& propsOf(EvalUnitDep d) const 00228 { 00229 return eg[d]; 00230 } 00231 00232 inline EvalUnitDepPropertyBundle& propsOf(EvalUnitDep d) 00233 { 00234 return eg[d]; 00235 } 00236 00237 inline const EvalUnitPropertyBundle& propsOf(EvalUnit u) const 00238 { 00239 return eg[u]; 00240 } 00241 00242 inline EvalUnitPropertyBundle& propsOf(EvalUnit u) 00243 { 00244 return eg[u]; 00245 } 00246 00247 inline EvalUnit sourceOf(EvalUnitDep d) const 00248 { 00249 return boost::source(d, eg); 00250 } 00251 inline EvalUnit targetOf(EvalUnitDep d) const 00252 { 00253 return boost::target(d, eg); 00254 } 00255 00256 inline unsigned countEvalUnits() const 00257 { 00258 return boost::num_vertices(eg); 00259 } 00260 inline unsigned countEvalUnitDeps() const 00261 { 00262 return boost::num_edges(eg); 00263 } 00264 00265 // output graph as graphviz source 00266 void writeGraphViz(std::ostream& o, bool verbose) const; 00267 00268 struct Impl; 00269 }; // class EvalGraph<...> 00270 00271 // projection properties for eval units 00272 // such properties are required by the model graph 00273 struct EvalUnitProjectionProperties 00274 { 00275 // storage 00276 bool iproject; 00277 bool oproject; 00278 00279 // init 00280 EvalUnitProjectionProperties( 00281 bool iproject = false, 00282 bool oproject = false): 00283 iproject(iproject), oproject(oproject) {} 00284 }; 00285 00286 template<typename EvalUnitPropertyBaseT, typename EvalUnitDepPropertyBaseT> 00287 struct EvalGraph<EvalUnitPropertyBaseT, EvalUnitDepPropertyBaseT>::Impl 00288 { 00289 static std::string graphviz_node_id(EvalUnit u) 00290 { 00291 std::ostringstream os; 00292 os << "u" << u; 00293 return os.str(); 00294 } 00295 }; 00296 00297 template<typename EvalUnitPropertyBaseT, typename EvalUnitDepPropertyBaseT> 00298 void EvalGraph<EvalUnitPropertyBaseT, EvalUnitDepPropertyBaseT>:: 00299 writeGraphViz(std::ostream& o, bool verbose) const 00300 { 00301 // boost::graph::graphviz is horribly broken! 00302 // therefore we print it ourselves 00303 00304 o << "digraph G {" << std::endl << 00305 "rankdir=BT;" << std::endl; // print root nodes at bottom, leaves at top! 00306 00307 // print vertices 00308 EvalUnitIterator it, it_end; 00309 unsigned index = 0; 00310 for(boost::tie(it, it_end) = boost::vertices(eg); 00311 it != it_end; ++it, ++index) 00312 { 00313 o << Impl::graphviz_node_id(*it) << "[shape=record,label=\"{" << *it << "|"; 00314 { 00315 std::ostringstream ss; 00316 // write eval unit property 00317 ss << propsOf(*it); 00318 graphviz::escape(o, ss.str()); 00319 } 00320 o << "}\"];" << std::endl; 00321 } 00322 00323 // print edges 00324 DependencyIterator dit, dit_end; 00325 for(boost::tie(dit, dit_end) = boost::edges(eg); 00326 dit != dit_end; ++dit) 00327 { 00328 EvalUnit src = sourceOf(*dit); 00329 EvalUnit target = targetOf(*dit); 00330 o << Impl::graphviz_node_id(src) << " -> " << Impl::graphviz_node_id(target) << 00331 "[label=\""; 00332 { 00333 std::ostringstream ss; 00334 ss << *dit; 00335 graphviz::escape(o, ss.str()); 00336 } 00337 o << "\"];" << std::endl; 00338 } 00339 00340 o << "}" << std::endl; 00341 } 00342 00343 DLVHEX_NAMESPACE_END 00344 00345 #endif // EVAL_GRAPH_HPP_INCLUDED__29082010