dlvhex  2.5.0
include/dlvhex2/DependencyGraph.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 DEPENDENCY_GRAPH_HPP_INCLUDED__18102010
00035 #define DEPENDENCY_GRAPH_HPP_INCLUDED__18102010
00036 
00037 #include "dlvhex2/PlatformDefinitions.h"
00038 #include "dlvhex2/fwd.h"
00039 #include "dlvhex2/Logger.h"
00040 #include "dlvhex2/ID.h"
00041 
00042 #include <boost/graph/graph_traits.hpp>
00043 #include <boost/graph/adjacency_list.hpp>
00044 #include <boost/shared_ptr.hpp>
00045 
00046 #include <boost/multi_index/member.hpp>
00047 #include <boost/multi_index/hashed_index.hpp>
00048 
00049 //#include <cassert>
00050 
00051 /*
00052  * TODO update paper/formal stuff:
00053  * definition of unifying dependency as in roman's thesis, not as in eswc paper
00054  * rule nodes added to graph
00055  * constraints have extra types of dependencies
00056  * negative dependencies unclear in roman's thesis: def 4.6.2 after second point 2:
00057  * "or b is a non-monotonic external atom" should imho be "or b \in B(r) and b a non-monotonic external atom"
00058  * (doesn't this give us fixed-point vs guess-and-check model generator choice for free?)
00059  * we will add those negative dependencies from rule to body atoms only
00060  * add external dependency if constant input has a variable created by output of other extatom (not covered by roman's thesis)
00061  * auxiliary rules do not take all body literals with the external atom's input variable, they only take positive literals!
00062  *   (this is stated differently in the thesis. perhaps it would be more efficient to take the
00063  *   transitive closure of dependencies over variables to make the body larger (and therefore reduce the grounding)
00064  *   example: &foo[X](), bar(X,Y), not baz(X,Z), boo(Z) -> is it more efficient to take all body atoms instead of only bar(X,Y)?)
00065  *
00066  * for eval only:
00067  * create auxiliary input collecting predicates/rule before creating depedency graph
00068  * pos dependency from ext. atom to its auxiliary input collecting predicate
00069  */
00070 
00071 DLVHEX_NAMESPACE_BEGIN
00072 
00074 class DependencyGraph
00075 {
00077     // types
00079     public:
00081         struct NodeInfo:
00082     public ostream_printable<NodeInfo>
00083     {
00084         // ID storage:
00085         // store rule as rule
00086         // store external atom body literal as atom (in non-naf-negated form)
00087         // store nothing else as node
00089         ID id;
00090 
00093         NodeInfo(ID id=ID_FAIL): id(id) {}
00094         std::ostream& print(std::ostream& o) const;
00095     };
00096 
00128     struct DependencyInfo:
00129     public ostream_printable<DependencyInfo>
00130     {
00131         bool positiveRegularRule;
00132         bool positiveConstraint;
00133         bool negativeRule;
00134         bool unifyingHead;
00135         bool disjunctive;
00136         bool positiveExternal;
00137         bool negativeExternal;
00138         bool externalConstantInput;
00139         bool externalPredicateInput;
00140         bool externalNonmonotonicPredicateInput;
00141 
00143         DependencyInfo():
00144         positiveRegularRule(false),
00145             positiveConstraint(false),
00146             negativeRule(false),
00147             unifyingHead(false),
00148             disjunctive(false),
00149             positiveExternal(false),
00150             negativeExternal(false),
00151             externalConstantInput(false),
00152             externalPredicateInput(false),
00153             externalNonmonotonicPredicateInput(false)
00154             {}
00155 
00161         const DependencyInfo& operator|=(const DependencyInfo& other);
00162         std::ostream& print(std::ostream& o) const;
00163     };
00164 
00165     // for out-edge list we use vecS so we may have duplicate edges which is not a
00166     // problem (at least not for the SCC algorithm, for drawing the graph we must take
00167     // care a bit, but drawing a graph need not be efficient)
00168     //
00169     // for vertices it is necesssary to use vecS because so many nice algorithms need
00170     // implicit vertex_index
00171     //
00172     // TODO: do we need bidirectional? (at the moment yes, to find roots and leaves)
00173     typedef boost::adjacency_list<
00174         boost::vecS, boost::vecS, boost::bidirectionalS,
00175         NodeInfo, DependencyInfo> Graph;
00176     typedef boost::graph_traits<Graph> Traits;
00177 
00178     typedef Graph::vertex_descriptor Node;
00179     typedef Graph::edge_descriptor Dependency;
00180     typedef Traits::vertex_iterator NodeIterator;
00181     typedef Traits::edge_iterator DependencyIterator;
00182     typedef Traits::out_edge_iterator PredecessorIterator;
00183     typedef Traits::in_edge_iterator SuccessorIterator;
00184 
00185     protected:
00186         // the node mapping maps IDs of external atoms and rules
00187         // to nodes of the dependency graph
00189         struct IDTag {};
00191         struct NodeMappingInfo
00192         {
00193             ID id;
00194             Node node;
00195             NodeMappingInfo(): id(ID_FAIL) {}
00196             NodeMappingInfo(ID id, Node node): id(id), node(node) {}
00197         };
00198         typedef boost::multi_index_container<
00199             NodeMappingInfo,
00200             boost::multi_index::indexed_by<
00201             boost::multi_index::hashed_unique<
00202             boost::multi_index::tag<IDTag>,
00203             BOOST_MULTI_INDEX_MEMBER(NodeMappingInfo,ID,id)
00204             >
00205             >
00206             > NodeMapping;
00207         typedef NodeMapping::index<IDTag>::type NodeIDIndex;
00208 
00209     protected:
00210         typedef std::vector<Node> NodeList;
00212         struct HeadBodyInfo
00213         {
00215             ID id;
00217             bool inHead;
00219             bool inBody;
00221             NodeList inHeadOfNondisjunctiveRules;
00223             NodeList inHeadOfDisjunctiveRules;
00225             NodeList inPosBodyOfRegularRules;
00227             NodeList inPosBodyOfConstraints;
00229             NodeList inNegBodyOfRules;
00231             ID headPredicate;
00233             const OrdinaryAtom* oatom;
00234 
00237             HeadBodyInfo(const OrdinaryAtom* oatom = NULL):
00238             id(ID_FAIL), inHead(false), inBody(false),
00239                 headPredicate(ID_FAIL), oatom(oatom) {}
00240         };
00241 
00243         struct InHeadTag {};
00245         struct InBodyTag {};
00247         struct HeadPredicateTag {};
00249         struct HeadBodyHelper
00250         {
00251             typedef boost::multi_index_container<
00252                 HeadBodyInfo,
00253                 boost::multi_index::indexed_by<
00254                 boost::multi_index::hashed_unique<
00255                 boost::multi_index::tag<IDTag>,
00256                 BOOST_MULTI_INDEX_MEMBER(HeadBodyInfo,ID,id)
00257                 >,
00258                 boost::multi_index::hashed_non_unique<
00259                 boost::multi_index::tag<InHeadTag>,
00260                 BOOST_MULTI_INDEX_MEMBER(HeadBodyInfo,bool,inHead)
00261                 >,
00262                 boost::multi_index::hashed_non_unique<
00263                 boost::multi_index::tag<InBodyTag>,
00264                 BOOST_MULTI_INDEX_MEMBER(HeadBodyInfo,bool,inBody)
00265                 >,
00266                 boost::multi_index::hashed_non_unique<
00267                 boost::multi_index::tag<HeadPredicateTag>,
00268                 BOOST_MULTI_INDEX_MEMBER(HeadBodyInfo,ID,headPredicate)
00269                 >
00270                 >
00271                 > HBInfos;
00272             typedef HBInfos::index<IDTag>::type IDIndex;
00273             typedef HBInfos::index<InHeadTag>::type InHeadIndex;
00274             typedef HBInfos::index<InBodyTag>::type InBodyIndex;
00275             typedef HBInfos::index<HeadPredicateTag>::type HeadPredicateIndex;
00276 
00278             HBInfos infos;
00279         };
00280 
00282         // members
00284     protected:
00286         ProgramCtx& ctx;
00288         RegistryPtr registry;
00290         Graph dg;
00292         NodeMapping nm;
00293 
00295         // methods
00297     private:
00302         DependencyGraph(const Dependency& other);
00303     public:
00307         DependencyGraph(ProgramCtx& ctx, RegistryPtr registry);
00309         virtual ~DependencyGraph();
00310 
00314         void createDependencies(const std::vector<ID>& idb, std::vector<ID>& createdAuxRules);
00315 
00319         virtual void writeGraphViz(std::ostream& o, bool verbose) const;
00320 
00323         const Graph& getInternalGraph() const
00324             { return dg; }
00325 
00326         // get node given some object id
00327         inline Node getNode(ID id) const
00328         {
00329             const NodeIDIndex& idx = nm.get<IDTag>();
00330             NodeIDIndex::const_iterator it = idx.find(id);
00331             assert(it != idx.end());
00332             return it->node;
00333         }
00334 
00338         inline std::pair<NodeIterator, NodeIterator> getNodes() const
00339             { return boost::vertices(dg); }
00340 
00344         inline const NodeInfo& getNodeInfo(Node node) const
00345             { return dg[node]; }
00346 
00350         inline const DependencyInfo& getDependencyInfo(Dependency dep) const
00351             { return dg[dep]; }
00352 
00356         inline std::pair<PredecessorIterator, PredecessorIterator>
00357             getDependencies(Node node) const
00358             { return boost::out_edges(node, dg); }
00359 
00363         inline std::pair<SuccessorIterator, SuccessorIterator>
00364             getProvides(Node node) const
00365             { return boost::in_edges(node, dg); }
00366 
00370         inline Node sourceOf(Dependency d) const
00371             { return boost::source(d, dg); }
00372 
00376         inline Node targetOf(Dependency d) const
00377             { return boost::target(d, dg); }
00378 
00382         inline const NodeInfo& propsOf(Node n) const
00383             { return dg[n]; }
00387         inline NodeInfo& propsOf(Node n)
00388             { return dg[n]; }
00392         inline const DependencyInfo& propsOf(Dependency d) const
00393             { return dg[d]; }
00397         inline DependencyInfo& propsOf(Dependency d)
00398             { return dg[d]; }
00399 
00400         // counting -> mainly for allocating and testing
00401         inline unsigned countNodes() const
00402             { return boost::num_vertices(dg); }
00403         inline unsigned countDependencies() const
00404             { return boost::num_edges(dg); }
00405 
00406     protected:
00410         inline Node createNode(ID id);
00411 
00412     protected:
00421         void createNodesAndIntraRuleDependencies(
00422             const std::vector<ID>& idb,
00423             std::vector<ID>& createdAuxRules,
00424             HeadBodyHelper& hbh);
00425         // helpers
00430         void createNodesAndIntraRuleDependenciesForRule(
00431             ID idrule,
00432             std::vector<ID>& createdAuxRules,
00433             HeadBodyHelper& hbh);
00439         void createNodesAndIntraRuleDependenciesForRuleAddHead(
00440             ID idat, const Rule& rule, Node nrule, HeadBodyHelper& hbh);
00449         void createNodesAndIntraRuleDependenciesForBody(
00450             ID idlit, ID idrule, const Tuple& body, Node nrule,
00451             HeadBodyHelper& hbh, std::vector<ID>& createdAuxRules,
00452             bool inAggregateBody = false);
00468         void createAuxiliaryRuleIfRequired(
00469             const Tuple& body,
00470             ID idlit, ID idat, Node neatom, const ExternalAtom& eatom,
00471             const PluginAtom* pluginAtom,
00472             std::vector<ID>& createdAuxRules,
00473             HeadBodyHelper& hbh);
00477         ID createAuxiliaryRuleHeadPredicate(ID forEAtom);
00482         ID createAuxiliaryRuleHead(ID idauxpred, const std::list<ID>& variables);
00487         ID createAuxiliaryRule(ID head, const std::list<ID>& body);
00488 
00491         void createExternalPredicateInputDependencies(const HeadBodyHelper& hbh);
00492         // helpers
00498         void createExternalPredicateInputDependenciesForInput(
00499             bool nonmonotonic, const NodeMappingInfo& ni_eatom, ID predicate, const HeadBodyHelper& hbh);
00500 
00503         void createUnifyingDependencies(const HeadBodyHelper& hbh);
00504         // helpers
00507         void createHeadHeadUnifyingDependencies(const HeadBodyHelper& hbh);
00510         void createHeadBodyUnifyingDependencies(const HeadBodyHelper& hbh);
00511 
00512     protected:
00513         // helpers for writeGraphViz: extend for more output
00518         virtual void writeGraphVizNodeLabel(std::ostream& o, Node n, bool verbose) const;
00523         virtual void writeGraphVizDependencyLabel(std::ostream& o, Dependency dep, bool verbose) const;
00524 };
00525 
00526 DependencyGraph::Node DependencyGraph::createNode(ID id)
00527 {
00528     DBGLOG(DBG,"creating node for ID " << id);
00529     Node n = boost::add_vertex(NodeInfo(id), dg);
00530     {
00531         NodeIDIndex::const_iterator it;
00532         bool success;
00533         boost::tie(it, success) = nm.insert(NodeMappingInfo(id, n));
00534         assert(success);
00535     }
00536     return n;
00537 }
00538 
00539 
00540 DLVHEX_NAMESPACE_END
00541 #endif                           // DEPENDENCY_GRAPH_HPP_INCLUDED__18102010
00542 
00543 // vim:expandtab:ts=4:sw=4:
00544 // mode: C++
00545 // End: