dlvhex  2.5.0
src/EvalHeuristicEasy.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 
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: