dlvhex
2.5.0
|
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: