|
dlvhex
2.1.0
|
00001 /* dlvhex -- Answer-Set Programming with external interfaces. 00002 * Copyright (C) 2005, 2006, 2007 Roman Schindlauer 00003 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Thomas Krennwallner 00004 * Copyright (C) 2009, 2010 Peter Schüller 00005 * 00006 * This file is part of dlvhex. 00007 * 00008 * dlvhex is free software; you can redistribute it and/or modify it 00009 * under the terms of the GNU Lesser General Public License as 00010 * published by the Free Software Foundation; either version 2.1 of 00011 * the License, or (at your option) any later version. 00012 * 00013 * dlvhex is distributed in the hope that it will be useful, but 00014 * WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with dlvhex; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00021 * 02110-1301 USA. 00022 */ 00023 00031 #ifdef HAVE_CONFIG_H 00032 #include "config.h" 00033 #endif // HAVE_CONFIG_H 00034 00035 #include "dlvhex2/EvalHeuristicEasy.h" 00036 #include "dlvhex2/Logger.h" 00037 00038 #include <boost/unordered_map.hpp> 00039 #include <boost/property_map/property_map.hpp> 00040 #include <boost/graph/topological_sort.hpp> 00041 #include <boost/graph/depth_first_search.hpp> 00042 #include <boost/graph/properties.hpp> 00043 #include <boost/scoped_ptr.hpp> 00044 00045 DLVHEX_NAMESPACE_BEGIN 00046 00047 EvalHeuristicEasy::EvalHeuristicEasy(): 00048 Base() 00049 { 00050 } 00051 00052 EvalHeuristicEasy::~EvalHeuristicEasy() 00053 { 00054 } 00055 00056 typedef ComponentGraph::Component Component; 00057 typedef ComponentGraph::ComponentIterator ComponentIterator; 00058 typedef std::vector<Component> ComponentContainer; 00059 typedef ComponentGraph::ComponentSet ComponentSet; 00060 00061 namespace internal 00062 { 00063 00064 template<typename ComponentGraph, typename Sequence> 00065 void topologicalSortOfComponents(const ComponentGraph& compgraph, Sequence& comps) 00066 { 00067 // we need a hash map, as component graph is no graph with vecS-storage 00068 // 00069 typedef boost::unordered_map<Component, boost::default_color_type> CompColorHashMap; 00070 typedef boost::associative_property_map<CompColorHashMap> CompColorMap; 00071 CompColorHashMap ccWhiteHashMap; 00072 // fill white hash map 00073 ComponentIterator cit, cit_end; 00074 for(boost::tie(cit, cit_end) = compgraph.getComponents(); 00075 cit != cit_end; ++cit) 00076 { 00077 //boost::put(ccWhiteHashMap, *cit, boost::white_color); 00078 ccWhiteHashMap[*cit] = boost::white_color; 00079 } 00080 CompColorHashMap ccHashMap(ccWhiteHashMap); 00081 00082 // 00083 // do topological sort 00084 // 00085 std::back_insert_iterator<Sequence> compinserter(comps); 00086 boost::topological_sort( 00087 compgraph.getInternalGraph(), 00088 compinserter, 00089 boost::color_map(CompColorMap(ccHashMap))); 00090 } 00091 00092 // collect all components on the way 00093 struct DFSVisitor: 00094 public boost::default_dfs_visitor 00095 { 00096 const ComponentGraph& cg; 00097 ComponentSet& comps; 00098 DFSVisitor(const ComponentGraph& cg, ComponentSet& comps): boost::default_dfs_visitor(), cg(cg), comps(comps) {} 00099 DFSVisitor(const DFSVisitor& other): boost::default_dfs_visitor(), cg(other.cg), comps(other.comps) {} 00100 template<typename GraphT> 00101 void discover_vertex(Component comp, const GraphT&) 00102 { 00103 comps.insert(comp); 00104 } 00105 }; 00106 00107 template<typename ComponentGraph, typename Set> 00108 void transitivePredecessorComponents(const ComponentGraph& compgraph, Component from, Set& preds) 00109 { 00110 // we need a hash map, as component graph is no graph with vecS-storage 00111 // 00112 typedef boost::unordered_map<Component, boost::default_color_type> CompColorHashMap; 00113 typedef boost::associative_property_map<CompColorHashMap> CompColorMap; 00114 CompColorHashMap ccWhiteHashMap; 00115 // fill white hash map 00116 ComponentIterator cit, cit_end; 00117 for(boost::tie(cit, cit_end) = compgraph.getComponents(); 00118 cit != cit_end; ++cit) 00119 { 00120 //boost::put(ccWhiteHashMap, *cit, boost::white_color); 00121 ccWhiteHashMap[*cit] = boost::white_color; 00122 } 00123 CompColorHashMap ccHashMap(ccWhiteHashMap); 00124 00125 // 00126 // do DFS 00127 // 00128 DFSVisitor dfs_vis(compgraph, preds); 00129 //LOG("doing dfs visit for root " << *itr); 00130 boost::depth_first_visit( 00131 compgraph.getInternalGraph(), 00132 from, 00133 dfs_vis, 00134 CompColorMap(ccHashMap)); 00135 DBGLOG(DBG,"predecessors of " << from << " are " << printrange(preds)); 00136 } 00137 00138 typedef std::map<Component, std::list<Component> > Cloned2OrigMap; 00139 00140 // gets cloned cg 00141 // gets components in cloned cg to collapse 00142 // returns new component in cloned cg, 00143 // updates com accordingly 00144 Component collapseHelper(Cloned2OrigMap& com, ComponentGraph& clonedcg, const ComponentSet& clonedcollapse) 00145 { 00146 Component ret = clonedcg.collapseComponents(clonedcollapse); 00147 00148 // insert new empty mapping into com 00149 com[ret] = std::list<Component>(); 00150 00151 // collect all targets 00152 // remove sources on the way there 00153 std::list<Component>& targets = com[ret]; 00154 for(ComponentSet::const_iterator it = clonedcollapse.begin(); it != clonedcollapse.end(); ++it) 00155 { 00156 Cloned2OrigMap::iterator comit = com.find(*it); 00157 assert(comit != com.end()); 00158 targets.insert(targets.end(), comit->second.begin(), comit->second.end()); 00159 00160 // erase record in com 00161 com.erase(*it); 00162 } 00163 00164 return ret; 00165 } 00166 00167 } 00168 00169 // required for some GCCs for DFSVisitor CopyConstructible Concept Check 00170 using namespace internal; 00171 00172 void EvalHeuristicEasy::build(EvalGraphBuilder& builder) 00173 { 00174 const ComponentGraph& constcompgraph = builder.getComponentGraph(); 00175 boost::scoped_ptr<ComponentGraph> pcompgraph(constcompgraph.clone()); 00176 ComponentGraph& compgraph(*pcompgraph); 00177 // build mapping from cloned to original component graph 00178 Cloned2OrigMap cloned2orig; 00179 { 00180 ComponentGraph::ComponentIterator cit, cit_end, ccit, ccit_end; 00181 boost::tie(cit, cit_end) = constcompgraph.getComponents(); 00182 boost::tie(ccit, ccit_end) = compgraph.getComponents(); 00183 for(;cit != cit_end && ccit != ccit_end; cit++, ccit++) 00184 { 00185 std::list<Component> comps; 00186 comps.push_back(*cit); 00187 cloned2orig[*ccit] = comps; 00188 } 00189 } 00190 00191 bool didSomething; 00192 do 00193 { 00194 didSomething = false; 00195 00196 // 00197 // forall external components e: 00198 // merge with all rules that 00199 // * depend on e 00200 // * do not contain external atoms 00201 // * do not depend on something e does not (transitively) depend on 00202 // 00203 { 00204 ComponentIterator cit; 00205 for(cit = compgraph.getComponents().first; // do not use boost::tie here! the container is modified in the loop! 00206 cit != compgraph.getComponents().second; ++cit) 00207 { 00208 Component comp = *cit; 00209 if( compgraph.propsOf(comp).outerEatoms.empty() ) 00210 continue; 00211 00212 LOG(ANALYZE,"checking whether to collapse external component " << comp << " with successors"); 00213 00214 // get predecessors 00215 ComponentSet preds; 00216 transitivePredecessorComponents(compgraph, comp, preds); 00217 00218 // get successors 00219 ComponentSet collapse; 00220 bool addedToCollapse; 00221 // do this as long as we find new ones 00222 // if we do not do this loop, we might miss something 00223 // as PredecessorIterator not necessarily honours topological order 00224 // (TODO this could be made more efficient) 00225 do 00226 { 00227 addedToCollapse = false; 00228 00229 ComponentGraph::SuccessorIterator sit, sit_end; 00230 for(boost::tie(sit, sit_end) = compgraph.getProvides(comp); 00231 sit != sit_end; ++sit) 00232 { 00233 Component succ = compgraph.sourceOf(*sit); 00234 00235 // skip successors with eatoms 00236 if( !compgraph.propsOf(succ).outerEatoms.empty() ) 00237 continue; 00238 // do not check found stuff twice 00239 if( collapse.find(succ) != collapse.end() ) 00240 continue; 00241 00242 DBGLOG(DBG,"found successor " << succ); 00243 00244 ComponentGraph::PredecessorIterator pit, pit_end; 00245 bool good = true; 00246 for(boost::tie(pit, pit_end) = compgraph.getDependencies(succ); 00247 pit != pit_end; ++pit) 00248 { 00249 Component dependson = compgraph.targetOf(*pit); 00250 if( preds.find(dependson) == preds.end() ) 00251 { 00252 LOG(DBG,"successor bad as it depends on other node " << dependson); 00253 good = false; 00254 break; 00255 } 00256 } 00257 if( good ) 00258 { 00259 // collapse with this 00260 collapse.insert(succ); 00261 preds.insert(succ); 00262 addedToCollapse = true; 00263 } 00264 } 00265 } 00266 while(addedToCollapse); 00267 00268 // collapse if not nonempty 00269 if( !collapse.empty() ) 00270 { 00271 collapse.insert(comp); 00272 Component c = collapseHelper(cloned2orig, compgraph, collapse); 00273 LOG(ANALYZE,"collapse of " << printrange(collapse) << " yielded new component " << c); 00274 00275 // restart loop after collapse 00276 cit = compgraph.getComponents().first; 00277 didSomething = true; 00278 } 00279 } 00280 } 00281 00282 // 00283 // forall components with only inner rules or constraints: 00284 // merge with children that are no eatoms and do not depend on anything else 00285 // 00286 { 00287 ComponentIterator cit = compgraph.getComponents().first; 00288 while(cit != compgraph.getComponents().second) 00289 { 00290 Component comp = *cit; 00291 if( !compgraph.propsOf(comp).outerEatoms.empty() ) 00292 { 00293 cit++; 00294 continue; 00295 } 00296 00297 LOG(ANALYZE,"checking whether to collapse internal-only component " << comp << " with children"); 00298 00299 // get successors 00300 ComponentSet collapse; 00301 ComponentGraph::SuccessorIterator sit, sit_end; 00302 for(boost::tie(sit, sit_end) = compgraph.getProvides(comp); 00303 sit != sit_end; 00304 ++sit) 00305 { 00306 Component succ = compgraph.sourceOf(*sit); 00307 00308 // skip successors with eatoms 00309 if( !compgraph.propsOf(succ).outerEatoms.empty() ) 00310 continue; 00311 00312 DBGLOG(DBG,"found successor " << succ); 00313 00314 ComponentGraph::PredecessorIterator pit, pit_end; 00315 boost::tie(pit, pit_end) = compgraph.getDependencies(succ); 00316 bool good = true; 00317 assert(pit != pit_end); 00318 if( compgraph.targetOf(*pit) != comp ) 00319 { 00320 LOG(DBG,"successor bad as it depends on other node " << compgraph.targetOf(*pit)); 00321 good = false; 00322 } 00323 pit++; 00324 if( pit != pit_end ) 00325 { 00326 good = false; 00327 LOG(DBG,"successor bad as it depends on more nodes"); 00328 } 00329 if( good ) 00330 collapse.insert(succ); 00331 } 00332 00333 if( !collapse.empty() ) 00334 { 00335 // collapse! (decreases graph size) 00336 collapse.insert(comp); 00337 assert(collapse.size() > 1); 00338 Component c = collapseHelper(cloned2orig, compgraph, collapse); 00339 LOG(ANALYZE,"collapse of " << printrange(collapse) << " yielded new component " << c); 00340 00341 // restart loop after collapse 00342 cit = compgraph.getComponents().first; 00343 didSomething = true; 00344 } 00345 else 00346 { 00347 // advance 00348 ++cit; 00349 } 00350 } 00351 } 00352 00353 // 00354 // forall components with only inner rules or constraints: 00355 // merge with components that depend on exactly the same predecessors 00356 // 00357 { 00358 ComponentIterator cit = compgraph.getComponents().first; 00359 while(cit != compgraph.getComponents().second) 00360 { 00361 Component comp = *cit; 00362 if( !compgraph.propsOf(comp).outerEatoms.empty() ) 00363 { 00364 cit++; 00365 continue; 00366 } 00367 00368 LOG(ANALYZE,"checking whether to collapse internal-only component " << comp << " with others"); 00369 ComponentSet collapse; 00370 00371 // get direct predecessors 00372 ComponentSet preds; 00373 { 00374 ComponentGraph::PredecessorIterator pit, pit_end; 00375 for(boost::tie(pit, pit_end) = compgraph.getDependencies(comp); 00376 pit != pit_end; ++pit) 00377 { 00378 preds.insert(compgraph.targetOf(*pit)); 00379 } 00380 } 00381 if( preds.empty() ) 00382 { 00383 // do not combine stuff that depends only on edb 00384 cit++; 00385 continue; 00386 } 00387 00388 // compare all further ones (further because of symmetry breaking) 00389 ComponentIterator cit2 = cit; 00390 cit2++; 00391 while( cit2 != compgraph.getComponents().second ) 00392 { 00393 Component comp2 = *cit2; 00394 DBGLOG(DBG,"checking other component " << comp2); 00395 ComponentSet preds2; 00396 { 00397 ComponentGraph::PredecessorIterator pit, pit_end; 00398 for(boost::tie(pit, pit_end) = compgraph.getDependencies(comp2); 00399 pit != pit_end; ++pit) 00400 { 00401 preds2.insert(compgraph.targetOf(*pit)); 00402 } 00403 } 00404 00405 if( preds2 == preds ) 00406 collapse.insert(comp2); 00407 00408 cit2++; 00409 } 00410 00411 if( !collapse.empty() ) 00412 { 00413 // collapse! (decreases graph size) 00414 collapse.insert(comp); 00415 assert(collapse.size() > 1); 00416 Component c = collapseHelper(cloned2orig, compgraph, collapse); 00417 LOG(ANALYZE,"collapse of " << printrange(collapse) << " yielded new component " << c); 00418 00419 // restart loop after collapse 00420 cit = compgraph.getComponents().first; 00421 didSomething = true; 00422 } 00423 else 00424 { 00425 // advance 00426 ++cit; 00427 } 00428 } 00429 } 00430 00431 // 00432 // forall components with only inner constraints: 00433 // merge with all other constraint-only components 00434 // 00435 if(false){ 00436 ComponentSet collapse; 00437 00438 ComponentIterator cit; 00439 for(cit = compgraph.getComponents().first; // do not use boost::tie here! the container is modified in the loop! 00440 cit != compgraph.getComponents().second; ++cit) 00441 { 00442 Component comp = *cit; 00443 if( compgraph.propsOf(comp).outerEatoms.empty() && 00444 compgraph.propsOf(comp).innerRules.empty() ) 00445 collapse.insert(comp); 00446 } 00447 00448 if( !collapse.empty() ) 00449 { 00450 // collapse! (decreases graph size) 00451 LOG(ANALYZE,"collapsing constraint-only nodes " << printrange(collapse)); 00452 Component c = collapseHelper(cloned2orig, compgraph, collapse); 00453 didSomething = true; 00454 } 00455 } 00456 00457 } 00458 while(didSomething); 00459 00460 // 00461 // create eval units using topological sort 00462 // 00463 ComponentContainer sortedcomps; 00464 topologicalSortOfComponents(compgraph, sortedcomps); 00465 for(ComponentContainer::const_iterator it = sortedcomps.begin(); 00466 it != sortedcomps.end(); ++it) 00467 { 00468 // <foo>.find(<bar>)->second has an implicit assert() at the iterator dereferencing 00469 const std::list<Component>& comps = cloned2orig.find(*it)->second; 00470 std::list<Component> ccomps; 00471 EvalGraphBuilder::EvalUnit u = builder.createEvalUnit(comps, ccomps); 00472 LOG(ANALYZE,"component " << *it << " became eval unit " << u); 00473 } 00474 } 00475 00476 DLVHEX_NAMESPACE_END 00477 00478 // Local Variables: 00479 // mode: C++ 00480 // End: