dlvhex  2.1.0
src/EvalHeuristicEasy.cpp
Go to the documentation of this file.
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: