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 00034 #ifdef HAVE_CONFIG_H 00035 #include "config.h" 00036 #endif // HAVE_CONFIG_H 00037 00038 #include "dlvhex2/EvalHeuristicEasy.h" 00039 #include "dlvhex2/EvalHeuristicShared.h" 00040 #include "dlvhex2/Logger.h" 00041 00042 #include <boost/unordered_map.hpp> 00043 #include <boost/property_map/property_map.hpp> 00044 #include <boost/graph/depth_first_search.hpp> 00045 #include <boost/graph/properties.hpp> 00046 #include <boost/scoped_ptr.hpp> 00047 00048 DLVHEX_NAMESPACE_BEGIN 00049 00050 EvalHeuristicEasy::EvalHeuristicEasy(): 00051 Base() 00052 { 00053 } 00054 00055 00056 EvalHeuristicEasy::~EvalHeuristicEasy() 00057 { 00058 } 00059 00060 00061 typedef ComponentGraph::Component Component; 00062 typedef ComponentGraph::ComponentIterator ComponentIterator; 00063 typedef std::vector<Component> ComponentContainer; 00064 typedef ComponentGraph::ComponentSet ComponentSet; 00065 00066 namespace internal 00067 { 00068 00069 // collect all components on the way 00070 struct DFSVisitor: 00071 public boost::default_dfs_visitor 00072 { 00073 const ComponentGraph& cg; 00074 ComponentSet& comps; 00075 DFSVisitor(const ComponentGraph& cg, ComponentSet& comps): boost::default_dfs_visitor(), cg(cg), comps(comps) {} 00076 DFSVisitor(const DFSVisitor& other): boost::default_dfs_visitor(), cg(other.cg), comps(other.comps) {} 00077 template<typename GraphT> 00078 void discover_vertex(Component comp, const GraphT&) { 00079 comps.insert(comp); 00080 } 00081 }; 00082 00083 template<typename ComponentGraph, typename Set> 00084 void transitivePredecessorComponents(const ComponentGraph& compgraph, Component from, Set& preds) { 00085 // we need a hash map, as component graph is no graph with vecS-storage 00086 // 00087 typedef boost::unordered_map<Component, boost::default_color_type> CompColorHashMap; 00088 typedef boost::associative_property_map<CompColorHashMap> CompColorMap; 00089 CompColorHashMap ccWhiteHashMap; 00090 // fill white hash map 00091 ComponentIterator cit, cit_end; 00092 for(boost::tie(cit, cit_end) = compgraph.getComponents(); 00093 cit != cit_end; ++cit) { 00094 //boost::put(ccWhiteHashMap, *cit, boost::white_color); 00095 ccWhiteHashMap[*cit] = boost::white_color; 00096 } 00097 CompColorHashMap ccHashMap(ccWhiteHashMap); 00098 00099 // 00100 // do DFS 00101 // 00102 DFSVisitor dfs_vis(compgraph, preds); 00103 //LOG("doing dfs visit for root " << *itr); 00104 boost::depth_first_visit( 00105 compgraph.getInternalGraph(), 00106 from, 00107 dfs_vis, 00108 CompColorMap(ccHashMap)); 00109 DBGLOG(DBG,"predecessors of " << from << " are " << printrange(preds)); 00110 } 00111 00112 } 00113 00114 00115 // required for some GCCs for DFSVisitor CopyConstructible Concept Check 00116 using namespace internal; 00117 00118 void EvalHeuristicEasy::build(EvalGraphBuilder& builder) 00119 { 00120 ComponentGraph& compgraph = builder.getComponentGraph(); 00121 00122 bool didSomething; 00123 do { 00124 didSomething = false; 00125 00126 // 00127 // forall external components e: 00128 // merge with all rules that 00129 // * depend on e 00130 // * do not contain external atoms 00131 // * do not depend on something e does not (transitively) depend on 00132 // 00133 { 00134 ComponentIterator cit; 00135 // do not use boost::tie here! the container is modified in the loop! 00136 for(cit = compgraph.getComponents().first; 00137 cit != compgraph.getComponents().second; ++cit) { 00138 Component comp = *cit; 00139 if( compgraph.propsOf(comp).outerEatoms.empty() ) 00140 continue; 00141 00142 LOG(ANALYZE,"checking whether to collapse external component " << comp << " with successors"); 00143 00144 // get predecessors 00145 ComponentSet preds; 00146 transitivePredecessorComponents(compgraph, comp, preds); 00147 00148 // get successors 00149 ComponentSet collapse; 00150 bool addedToCollapse; 00151 // do this as long as we find new ones 00152 // if we do not do this loop, we might miss something 00153 // as PredecessorIterator not necessarily honours topological order 00154 // (TODO this could be made more efficient) 00155 do { 00156 addedToCollapse = false; 00157 00158 ComponentGraph::SuccessorIterator sit, sit_end; 00159 for(boost::tie(sit, sit_end) = compgraph.getProvides(comp); 00160 sit != sit_end; ++sit) { 00161 Component succ = compgraph.sourceOf(*sit); 00162 00163 // skip successors with eatoms 00164 if( !compgraph.propsOf(succ).outerEatoms.empty() ) 00165 continue; 00166 // do not check found stuff twice 00167 if( collapse.find(succ) != collapse.end() ) 00168 continue; 00169 00170 DBGLOG(DBG,"found successor " << succ); 00171 00172 ComponentGraph::PredecessorIterator pit, pit_end; 00173 bool good = true; 00174 for(boost::tie(pit, pit_end) = compgraph.getDependencies(succ); 00175 pit != pit_end; ++pit) { 00176 Component dependson = compgraph.targetOf(*pit); 00177 if( preds.find(dependson) == preds.end() ) { 00178 LOG(DBG,"successor bad as it depends on other node " << dependson); 00179 good = false; 00180 break; 00181 } 00182 } 00183 if( good ) { 00184 // collapse with this 00185 collapse.insert(succ); 00186 preds.insert(succ); 00187 addedToCollapse = true; 00188 } 00189 } 00190 } 00191 while(addedToCollapse); 00192 00193 // collapse if not nonempty 00194 if( !collapse.empty() ) { 00195 collapse.insert(comp); 00196 Component c = compgraph.collapseComponents(collapse); 00197 LOG(ANALYZE,"collapse of " << printrange(collapse) << " yielded new component " << c); 00198 00199 // restart loop after collapse 00200 cit = compgraph.getComponents().first; 00201 didSomething = true; 00202 } 00203 } 00204 } 00205 00206 // 00207 // forall components with only inner rules or constraints: 00208 // merge with children that are no eatoms and do not depend on anything else 00209 // 00210 { 00211 ComponentIterator cit = compgraph.getComponents().first; 00212 while(cit != compgraph.getComponents().second) { 00213 Component comp = *cit; 00214 if( !compgraph.propsOf(comp).outerEatoms.empty() ) { 00215 cit++; 00216 continue; 00217 } 00218 00219 LOG(ANALYZE,"checking whether to collapse internal-only component " << comp << " with children"); 00220 00221 // get successors 00222 ComponentSet collapse; 00223 ComponentGraph::SuccessorIterator sit, sit_end; 00224 for(boost::tie(sit, sit_end) = compgraph.getProvides(comp); 00225 sit != sit_end; 00226 ++sit) { 00227 Component succ = compgraph.sourceOf(*sit); 00228 00229 // skip successors with eatoms 00230 if( !compgraph.propsOf(succ).outerEatoms.empty() ) 00231 continue; 00232 00233 DBGLOG(DBG,"found successor " << succ); 00234 00235 ComponentGraph::PredecessorIterator pit, pit_end; 00236 boost::tie(pit, pit_end) = compgraph.getDependencies(succ); 00237 bool good = true; 00238 assert(pit != pit_end); 00239 if( compgraph.targetOf(*pit) != comp ) { 00240 LOG(DBG,"successor bad as it depends on other node " << compgraph.targetOf(*pit)); 00241 good = false; 00242 } 00243 pit++; 00244 if( pit != pit_end ) { 00245 good = false; 00246 LOG(DBG,"successor bad as it depends on more nodes"); 00247 } 00248 if( good ) 00249 collapse.insert(succ); 00250 } 00251 00252 if( !collapse.empty() ) { 00253 // collapse! (decreases graph size) 00254 collapse.insert(comp); 00255 assert(collapse.size() > 1); 00256 Component c = compgraph.collapseComponents(collapse); 00257 LOG(ANALYZE,"collapse of " << printrange(collapse) << " yielded new component " << c); 00258 00259 // restart loop after collapse 00260 cit = compgraph.getComponents().first; 00261 didSomething = true; 00262 } 00263 else { 00264 // advance 00265 ++cit; 00266 } 00267 } 00268 } 00269 00270 // 00271 // forall components with only inner rules or constraints: 00272 // merge with components that depend on exactly the same predecessors 00273 // 00274 { 00275 ComponentIterator cit = compgraph.getComponents().first; 00276 while(cit != compgraph.getComponents().second) { 00277 Component comp = *cit; 00278 if( !compgraph.propsOf(comp).outerEatoms.empty() ) { 00279 cit++; 00280 continue; 00281 } 00282 00283 LOG(ANALYZE,"checking whether to collapse internal-only component " << comp << " with others"); 00284 ComponentSet collapse; 00285 00286 // get direct predecessors 00287 ComponentSet preds; 00288 { 00289 ComponentGraph::PredecessorIterator pit, pit_end; 00290 for(boost::tie(pit, pit_end) = compgraph.getDependencies(comp); 00291 pit != pit_end; ++pit) { 00292 preds.insert(compgraph.targetOf(*pit)); 00293 } 00294 } 00295 if( preds.empty() ) { 00296 // do not combine stuff that depends only on edb 00297 cit++; 00298 continue; 00299 } 00300 00301 // compare all further ones (further because of symmetry breaking) 00302 ComponentIterator cit2 = cit; 00303 cit2++; 00304 while( cit2 != compgraph.getComponents().second ) { 00305 Component comp2 = *cit2; 00306 DBGLOG(DBG,"checking other component " << comp2); 00307 ComponentSet preds2; 00308 { 00309 ComponentGraph::PredecessorIterator pit, pit_end; 00310 for(boost::tie(pit, pit_end) = compgraph.getDependencies(comp2); 00311 pit != pit_end; ++pit) { 00312 preds2.insert(compgraph.targetOf(*pit)); 00313 } 00314 } 00315 00316 if( preds2 == preds ) 00317 collapse.insert(comp2); 00318 00319 cit2++; 00320 } 00321 00322 if( !collapse.empty() ) { 00323 // collapse! (decreases graph size) 00324 collapse.insert(comp); 00325 assert(collapse.size() > 1); 00326 Component c = compgraph.collapseComponents(collapse); 00327 LOG(ANALYZE,"collapse of " << printrange(collapse) << " yielded new component " << c); 00328 00329 // restart loop after collapse 00330 cit = compgraph.getComponents().first; 00331 didSomething = true; 00332 } 00333 else { 00334 // advance 00335 ++cit; 00336 } 00337 } 00338 } 00339 00340 // 00341 // forall components with only inner constraints: 00342 // merge with all other constraint-only components 00343 // 00344 if(false) { 00345 ComponentSet collapse; 00346 00347 ComponentIterator cit; 00348 // do not use boost::tie here! the container is modified in the loop! 00349 for(cit = compgraph.getComponents().first; 00350 cit != compgraph.getComponents().second; ++cit) { 00351 Component comp = *cit; 00352 if( compgraph.propsOf(comp).outerEatoms.empty() && 00353 compgraph.propsOf(comp).innerRules.empty() ) 00354 collapse.insert(comp); 00355 } 00356 00357 if( !collapse.empty() ) { 00358 // collapse! (decreases graph size) 00359 LOG(ANALYZE,"collapsing constraint-only nodes " << printrange(collapse)); 00360 Component c = compgraph.collapseComponents(collapse); 00361 didSomething = true; 00362 } 00363 } 00364 00365 } 00366 while(didSomething); 00367 00368 // 00369 // create eval units using topological sort 00370 // 00371 ComponentContainer sortedcomps; 00372 evalheur::topologicalSortComponents(compgraph.getInternalGraph(), sortedcomps); 00373 LOG(ANALYZE,"now creating evaluation units from components " << printrange(sortedcomps)); 00374 for(ComponentContainer::const_iterator it = sortedcomps.begin(); 00375 it != sortedcomps.end(); ++it) { 00376 // just create a unit from each component (we collapsed above) 00377 std::list<Component> comps; 00378 comps.push_back(*it); 00379 std::list<Component> ccomps; 00380 EvalGraphBuilder::EvalUnit u = builder.createEvalUnit(comps, ccomps); 00381 LOG(ANALYZE,"component " << *it << " became eval unit " << u); 00382 } 00383 } 00384 00385 00386 DLVHEX_NAMESPACE_END 00387 00388 00389 // vim:expandtab:ts=4:sw=4: 00390 // mode: C++ 00391 // End: