dlvhex  2.5.0
include/dlvhex2/EvalGraph.h
Go to the documentation of this file.
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: