dlvhex  2.1.0
include/dlvhex2/EvalGraph.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 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