dlvhex  2.5.0
src/BoostComponentFinder.cpp
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 
00038 #ifdef HAVE_CONFIG_H
00039 #include "config.h"
00040 #endif                           // HAVE_CONFIG_H
00041 
00042 #include "dlvhex2/BoostComponentFinder.h"
00043 #include "dlvhex2/globals.h"
00044 #include "dlvhex2/PrintVisitor.h"
00045 #include "dlvhex2/Component.h"
00046 
00047 #include <sstream>
00048 
00049 #include <boost/graph/adjacency_list.hpp>
00050 #include <boost/graph/connected_components.hpp>
00051 #include <boost/graph/strong_components.hpp>
00052 #include <boost/graph/graphviz.hpp>
00053 #include <boost/algorithm/string/replace.hpp>
00054 
00055 DLVHEX_NAMESPACE_BEGIN
00056 
00057 void
00058 BoostComponentFinder::makeEdges(const std::vector<AtomNodePtr>& nodes,
00059 Edges& edges) const
00060 {
00061     for (std::vector<AtomNodePtr>::const_iterator node = nodes.begin();
00062         node != nodes.end();
00063     ++node) {
00064         ComponentFinder::Vertex v1 = (*node)->getId();
00065 
00066         //
00067         // considering all types of dependencies
00068         //
00069         for (std::set<Dependency>::const_iterator d = (*node)->getSucceeding().begin();
00070             d != (*node)->getSucceeding().end();
00071         ++d) {
00072             ComponentFinder::Vertex v2 = (*d).getAtomNode()->getId();
00073 
00074             //
00075             // making edge from v2 to v1, because the direction is not relevant
00076             // for finding WCCs and SCCs and this is the "traditional" direction
00077             // for lp-dependency (head->body), and we want these arrows in the
00078             // graphviz output (see below)!
00079             //
00080             edges.push_back(ComponentFinder::Edge(v2, v1));
00081         }
00082 
00083     }
00084 }
00085 
00086 
00087 void
00088 BoostComponentFinder::selectNodes(const Vertices& vertices,
00089 const std::vector<AtomNodePtr>& nodes,
00090 std::vector<AtomNodePtr>& newnodes) const
00091 {
00092     newnodes.clear();
00093 
00094     for (ComponentFinder::Vertices::const_iterator vi = vertices.begin();
00095         vi != vertices.end();
00096     ++vi) {
00101         std::vector<AtomNodePtr>::const_iterator an;
00102 
00103         for (an = nodes.begin(); an != nodes.end(); ++an) {
00104             if ((*an)->getId() == *vi)
00105                 break;
00106         }
00107 
00108         if (an != nodes.end()) {
00109             newnodes.push_back(*an);
00110         }
00111     }
00112 }
00113 
00114 
00115 void
00116 BoostComponentFinder::findWeakComponents(const std::vector<AtomNodePtr>& nodes,
00117 std::vector<std::vector<AtomNodePtr> >& wccs)
00118 {
00119     /*
00120     std::map<int, Vertex> vmap;
00121 
00122     Edges contedges;
00123 
00124     for (Edges::const_iterator ei = edges.begin();
00125          ei != edges.end();
00126          ++ei)
00127     {
00128 
00129     }
00130     */
00131 
00132     ComponentFinder::Edges edges;
00133 
00134     makeEdges(nodes, edges);
00135 
00136     using namespace boost;
00137     {
00138         typedef adjacency_list <listS, vecS, undirectedS> Graph;
00139 
00140         Graph G;
00141 
00142         for (Edges::const_iterator ei = edges.begin();
00143             ei != edges.end();
00144         ++ei) {
00145             add_edge(ei->first, ei->second, G);
00146         }
00147 
00148         std::vector<int> component(num_vertices(G));
00149 
00150         int num = connected_components(G, &component[0]);
00151 
00152         //        std::cout << "Total number of components: " << num << std::endl;
00153 
00154         std::vector<AtomNodePtr> wcc;
00155 
00156         for (int cn = 0; cn < num; ++cn) {
00157             Vertices thiscomponent;
00158 
00159             for (std::vector<int>::size_type i = 0; i != component.size(); ++i) {
00160                 if (component[i] == cn) {
00161                     thiscomponent.push_back(Vertex(i));
00162                 }
00163             }
00164 
00165             //
00166             // hack - remove all single noded-components, as long as we don't know
00167             // how to use boost with non-contiguous vertices!
00168             //
00169             if (thiscomponent.size() > 1) {
00170                 //.push_back(thiscomponent);
00171 
00172                 wcc.clear();
00173 
00174                 selectNodes(thiscomponent, nodes, wcc);
00175 
00176                 wccs.push_back(wcc);
00177             }
00178         }
00179 
00180         //        for (std::vector<int>::size_type i = 0; i != component.size(); ++i)
00181         //            std::cout << "Vertex " << i <<" is in component " << component[i] << std::endl;
00182         //        std::cout << std::endl;
00183 
00184     }
00185 }
00186 
00187 
00188 void
00189 BoostComponentFinder::findStrongComponents(const std::vector<AtomNodePtr>& nodes,
00190 std::vector<std::vector<AtomNodePtr> >& sccs)
00191 {
00192     ComponentFinder::Edges edges;
00193 
00194     makeEdges(nodes, edges);
00195 
00196     using namespace boost;
00197     {
00198         typedef adjacency_list<vecS, vecS, directedS> Graph;
00199 
00200         Graph G(0);
00201 
00202         for (Edges::const_iterator ei = edges.begin();
00203             ei != edges.end();
00204         ++ei) {
00205             add_edge(ei->first, ei->second, G);
00206         }
00207 
00208         std::vector<int> component(num_vertices(G));
00209 
00210         int num = strong_components(G, &component[0]);
00211         //std::cout << "Total number of components: " << num << std::endl;
00212 
00213         std::vector<AtomNodePtr> scc;
00214 
00215         for (int cn = 0; cn < num; ++cn) {
00216             Vertices thiscomponent;
00217 
00218             for (std::vector<int>::size_type i = 0; i != component.size(); ++i) {
00219                 if (component[i] == cn)
00220                     thiscomponent.push_back(Vertex(i));
00221             }
00222 
00229 
00232 
00233             //
00234             // only add components with more than one vertex:
00235             //
00236             if (thiscomponent.size() > 1) {
00237                 //components.push_back(thiscomponent);
00238 
00239                 scc.clear();
00240 
00241                 selectNodes(thiscomponent, nodes, scc);
00242 
00243                 sccs.push_back(scc);
00244             }
00245         }
00246 
00247         if (Globals::Instance()->doVerbose(Globals::DUMP_DEPENDENCY_GRAPH)) {
00248             //
00249             // create a label table for the graphviz output
00250             //
00251             const int nnames = 3*nodes.size();
00252             std::vector<std::string> nms(nnames);
00253             const char* nmsc[nnames];
00254 
00255             std::ostringstream oss;
00256             RawPrintVisitor rpv(oss);
00257 
00258             for (unsigned y = 0; y < nodes.size(); ++y) {
00259                 oss.str("");
00260 
00261                 nodes[y]->getAtom()->accept(rpv);
00262 
00263                 std::string at(oss.str());
00264 
00265                 boost::algorithm::replace_all(at, "\"", "\\\"");
00266 
00267                 nms[y] = at;
00268                 nmsc[y] = nms[y].c_str();
00269             }
00270 
00271             std::ofstream out;
00272 
00273             out.open(Globals::Instance()->lpfilename.c_str());
00274             write_graphviz(out, G, make_label_writer(nmsc));
00275             out.close();
00276 
00277             Globals::Instance()->getVerboseStream() << "Graph written to "
00278                 << Globals::Instance()->lpfilename << std::endl;
00279         }
00280     }
00281 }
00282 
00283 
00284 DLVHEX_NAMESPACE_END
00285 
00286 
00287 // vim:expandtab:ts=4:sw=4:
00288 // mode: C++
00289 // End: