dlvhex  2.5.0
src/GraphProcessor.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 
00037 #ifdef HAVE_CONFIG_H
00038 #include "config.h"
00039 #endif                           // HAVE_CONFIG_H
00040 
00041 #include <iostream>
00042 #include "dlvhex2/globals.h"
00043 #include "dlvhex2/GraphProcessor.h"
00044 #include "dlvhex2/ModelGenerator.h"
00045 #include "dlvhex2/AtomSet.h"
00046 #include "dlvhex2/Error.h"
00047 #include "dlvhex2/PrintVisitor.h"
00048 #include "dlvhex2/DependencyGraph.h"
00049 #include "dlvhex2/ProgramCtx.h"
00050 
00051 DLVHEX_NAMESPACE_BEGIN
00052 
00053 GraphProcessor::GraphProcessor(const ProgramCtx& c)
00054 : ctx(c), resultModels()
00055 {
00056     resultSetIndex = resultModels.begin();
00057 }
00058 
00059 
00060 void
00061 GraphProcessor::run(const AtomSet& in)
00062 {
00063     DependencyGraph* const depGraph = ctx.getDependencyGraph();
00064     assert(depGraph != 0);
00065 
00066     Subgraph* graph = depGraph->getNextSubgraph();
00067 
00068     if (Globals::Instance()->doVerbose(Globals::GRAPH_PROCESSOR)) {
00069         Globals::Instance()->getVerboseStream() << "Graph Processor starts." << std::endl;
00070         graph->dump(Globals::Instance()->getVerboseStream());
00071     }
00072 
00073     //
00074     // start with program's EDB
00075     //
00076     resultModels.clear();
00077     resultModels.push_back(in);
00078 
00080     //
00081     // The Big Loop:
00082     // do this as long as there is something left to be solved.
00083     //
00084     // more precisely:
00085     // 1) solve all components (scc with extatoms) at the bottom of the graph
00086     // 2) remove them from the graph
00087     // 3) solve ordinary ASP-subprogram now at the bottom of the graph
00088     //
00089     // if any further components left 'above' this, then continue with 1)
00090     //
00091     // In case of an ordinary ASP program (without any external atoms), 1) and
00092     // 2) do nothing and 3) solves the program.
00093     //
00094     do {
00095         //
00096         // accumulated result of all leaf-components with all current models as
00097         // input
00098         //
00099         std::set<AtomSet> allLeavesResult;
00100 
00101         //
00102         // all leaf components
00103         //
00104         std::vector<Component*> leaves;
00105         graph->getUnsolvedLeaves(leaves);
00106 
00107         if (Globals::Instance()->doVerbose(Globals::GRAPH_PROCESSOR)) {
00108             Globals::Instance()->getVerboseStream() << "=======================" << std::endl
00109                 << "current iteration has "
00110                 << leaves.size()
00111                 << " leaf components $\\bar{T}$" << std::endl
00112                 << "=======================" << std::endl;
00113         }
00114 
00115         if (leaves.empty()) {
00116             // this is the first iteration: resultModels = EDB.
00117             // no leaves: just insert current resultModels to allLeavesResult.
00118             allLeavesResult.insert(resultModels.begin(), resultModels.end());
00119         }
00120         else {
00121             //
00122             // go through current result, i.e., answer sets previously computed from
00123             // lower parts of the graph.
00124             //
00125             // with each of these models (*mi), we loop through all leaf components.
00126             // result sets of one component are input to the next.
00127             //
00128             for (std::vector<AtomSet>::iterator mi = resultModels.begin(); mi != resultModels.end(); ++mi) {
00129                 if (Globals::Instance()->doVerbose(Globals::GRAPH_PROCESSOR)) {
00130                     Globals::Instance()->getVerboseStream() << "==============================" << std::endl
00131                         << "current input interpretation $M$ for leaf layer with "
00132                         << leaves.size()
00133                         << " leaves: " << std::endl;
00134                     RawPrintVisitor rpv(Globals::Instance()->getVerboseStream());
00135                     mi->accept(rpv);
00136                     Globals::Instance()->getVerboseStream() << std::endl << "==============================" << std::endl;
00137                 }
00138 
00139                 // componentInput is input to a component
00141                 std::vector<AtomSet> componentInput;
00142                 componentInput.push_back(*mi);
00143 
00144                 //
00145                 // now loop through these leaf components with componentInput as input
00146                 //
00147                 unsigned u = 0;
00148                 for (std::vector<Component*>::iterator ci = leaves.begin(); ci != leaves.end(); ++ci, ++u) {
00149                     if (Globals::Instance()->doVerbose(Globals::GRAPH_PROCESSOR)) {
00150                         Globals::Instance()->getVerboseStream() << "==============================" << std::endl
00151                             << "computing leaf component with idx " << u << ": " << std::endl;
00152                         (*ci)->dump(Globals::Instance()->getVerboseStream());
00153                         Globals::Instance()->getVerboseStream() << std::endl << "==============================" << std::endl;
00154                     }
00155 
00156                     //
00157                     // evaluate leaf component with previous result as input
00158                     // (in case of multiple models, this will multiply the sets of
00159                     // sets correctly)
00160                     //
00161                     (*ci)->evaluate(componentInput);
00162                 }
00163 
00164                 //
00165                 // componentLayerResult is the accumulated result of all current
00166                 // leaf components. input to start with is the current model *mi.
00167                 //
00168                 std::vector<AtomSet> componentLayerResult;
00169 
00170                 std::vector<AtomSet> f1;
00171                 std::vector<AtomSet> f2;
00172                 bool firstround = true;
00173 
00174                 //
00175                 // collect the results of each component and multiply them
00176                 //
00177                 u = 0;
00178                 for (std::vector<Component*>::iterator ci = leaves.begin();
00179                 ci != leaves.end(); ++ci, ++u) {
00180                     // get the result of this component
00181                     (*ci)->getResult(f1);
00182 
00183                     if (Globals::Instance()->doVerbose(Globals::GRAPH_PROCESSOR)) {
00184                         Globals::Instance()->getVerboseStream() << "==============================" << std::endl
00185                             << "result of leaf with idx " << u
00186                             << "(" << f1.size() << " answer sets):" << std::endl;
00187 
00188                         RawPrintVisitor rpv(Globals::Instance()->getVerboseStream());
00189                         for (std::vector<AtomSet>::iterator tmpi = f1.begin();
00190                             tmpi != f1.end();
00191                         ++tmpi) {
00192                             tmpi->accept(rpv);
00193                             Globals::Instance()->getVerboseStream() << std::endl;
00194                         }
00195 
00196                         Globals::Instance()->getVerboseStream() << "==============================" << std::endl;
00197                     }
00198 
00199                     if (firstround) {
00200                         componentLayerResult = f1;
00201                         firstround = false;
00202                     }
00203                     else {
00204                                  // this component is inconsistent, clear result and get out
00205                         if (f1.empty()) {
00206                             componentLayerResult.clear();
00207                             break;
00208                         }
00209                         else {   // multiply models of this component with the results of previous round
00210                             // save the old results
00211                             f2 = componentLayerResult;
00212 
00213                             // clear the results
00214                             componentLayerResult.clear();
00215 
00216                             for (std::vector<AtomSet>::const_iterator i1 = f1.begin();
00217                                 i1 != f1.end();
00218                             ++i1) {
00219                                 for (std::vector<AtomSet>::const_iterator i2 = f2.begin();
00220                                     i2 != f2.end();
00221                                 ++i2) {
00222                                     AtomSet un;
00223 
00224                                     un.insert(*i1);
00225                                     un.insert(*i2);
00226 
00227                                     // add back the multiplied results
00228                                     componentLayerResult.push_back(un);
00229                                 }
00230                             }
00231                         }
00232                     }
00233                 }                // multiply every component
00234 
00235                 if (Globals::Instance()->doVerbose(Globals::GRAPH_PROCESSOR)) {
00236                     Globals::Instance()->getVerboseStream() << "current allLeavesResult ("
00237                         << allLeavesResult.size() << " answer sets ):" << std::endl;
00238 
00239                     for (std::set<AtomSet>::iterator it = allLeavesResult.begin();
00240                         it != allLeavesResult.end();
00241                     ++it) {
00242                         RawPrintVisitor rpv(Globals::Instance()->getVerboseStream());
00243                         const_cast<AtomSet&>(*it).accept(rpv);
00244                         Globals::Instance()->getVerboseStream() << std::endl;
00245                     }
00246 
00247                     Globals::Instance()->getVerboseStream() << "Now start copying from above componentLayerResult to allLeavesResult." << std::endl;
00248                 }
00249 
00250                 //
00251                 // we are done now with evaluating all leaf components w.r.t. the
00252                 // intermediate result *mi. add the resulting model to
00253                 // allLeavesResult.
00254                 //
00255                 allLeavesResult.insert(componentLayerResult.begin(), componentLayerResult.end());
00256 
00257                 if (Globals::Instance()->doVerbose(Globals::GRAPH_PROCESSOR)) {
00258                     Globals::Instance()->getVerboseStream() << "current allLeavesResult ("
00259                         << allLeavesResult.size() << " answer sets ):" << std::endl;
00260 
00261                     for (std::set<AtomSet>::iterator it = allLeavesResult.begin();
00262                         it != allLeavesResult.end();
00263                     ++it) {
00264                         RawPrintVisitor rpv(Globals::Instance()->getVerboseStream());
00265                         const_cast<AtomSet&>(*it).accept(rpv);
00266                         Globals::Instance()->getVerboseStream() << std::endl;
00267                     }
00268 
00269                     Globals::Instance()->getVerboseStream() << "current allLeavesResult end" << std::endl;
00270                 }
00271 
00272             }                    // foreach resultModels
00273 
00274         }                        
00275 
00276         //
00277         // in case we have programs with head cycles, we need to
00278         // check allLeavesResult for minimality here
00279         //
00280 
00281         if (Globals::Instance()->doVerbose(Globals::MODEL_GENERATOR)) {
00282             Globals::Instance()->getVerboseStream() << std::endl
00283                 << "Checking allLeavesResult for minimality:"
00284                 << std::endl;
00285         }
00286 
00288         std::vector<AtomSet> models;
00289 
00290         for (std::set<AtomSet>::const_iterator ans = allLeavesResult.begin();
00291             ans != allLeavesResult.end();
00292         ++ans) {
00293             //
00294             // now ensure minimality:
00295             //
00296             bool isMinimal = true;
00297 
00298             std::vector<std::vector<AtomSet>::iterator> todelete;
00299 
00300             for (std::vector<AtomSet>::iterator curras = models.begin();
00301                 curras != models.end();
00302             ++curras) {
00303                 //
00304                 // is the new one a superset (or equal) than an existing one
00305                 //
00306                 if (std::includes(ans->begin(), ans->end(), curras->begin(), curras->end())) {
00307                     isMinimal = false;
00308                     break;
00309                 }
00310 
00311                 //
00312                 // is the new one a subset of an existing one? Must be a *real* subset,
00313                 // if we passed the previous "if"!
00314                 //
00315                 if (std::includes(curras->begin(), curras->end(), ans->begin(), ans->end())) {
00316                     //
00317                     // remove existing one
00318                     //
00319                     todelete.push_back(curras);
00320                 }
00321             }
00322 
00323             for (std::vector<std::vector<AtomSet>::iterator>::const_iterator it = todelete.begin();
00324                 it != todelete.end();
00325             ++it) {
00326                 if (Globals::Instance()->doVerbose(Globals::MODEL_GENERATOR)) {
00327                     Globals::Instance()->getVerboseStream() << " Killing model: ";
00328                     RawPrintVisitor rpv(Globals::Instance()->getVerboseStream());
00329                     (*it)->accept(rpv);
00330                     Globals::Instance()->getVerboseStream() << std::endl;
00331                 }
00332 
00333                 models.erase(*it);
00334             }
00335 
00336             if (isMinimal) {
00338                 models.push_back(*ans);
00339 
00340                 if (Globals::Instance()->doVerbose(Globals::MODEL_GENERATOR)) {
00341                     Globals::Instance()->getVerboseStream() << " Model passed minimality test for now: ";
00342                     RawPrintVisitor rpv(Globals::Instance()->getVerboseStream());
00343                     ans->accept(rpv);
00344                     Globals::Instance()->getVerboseStream() << std::endl;
00345                 }
00346             }
00347             else {
00348                 if (Globals::Instance()->doVerbose(Globals::MODEL_GENERATOR)) {
00349                     Globals::Instance()->getVerboseStream() << " Model did not pass minimality test:";
00350                     RawPrintVisitor rpv(Globals::Instance()->getVerboseStream());
00351                     ans->accept(rpv);
00352                     Globals::Instance()->getVerboseStream() << std::endl;
00353                 }
00354             }
00355         }
00356 
00357         // minimality check is done, now models contains the minimal models
00358 
00359         //
00360         // done with feeding all current result models into the leaf components.
00361         // now take care of what's above these components.
00362         //
00363 
00364         //
00365         // first of all, we can update the "set of current result models" now
00366         //
00367         //       resultModels = allLeavesResult;
00368 
00370         resultModels.clear();
00371         resultModels.insert(resultModels.end(), models.begin(), models.end());
00372 
00373         //
00374         // make copy of subgraph
00375         //
00376         Subgraph tmpGraph(*graph);
00377 
00378         //
00379         // remove components from temp subgraph
00380         // the result is a subgraph without any SCCs
00381         //
00382         tmpGraph.pruneComponents();
00383 
00384         //
00385         // anything left in the pruned subgraph?
00386         //
00387 
00388         const std::vector<AtomNodePtr>& tmpNodes = tmpGraph.getNodes();
00389 
00390         if (!tmpNodes.empty()) {
00391             if (Globals::Instance()->doVerbose(Globals::GRAPH_PROCESSOR)) {
00392                 Globals::Instance()->getVerboseStream() << "evaluating wcc on "
00393                     << resultModels.size()
00394                     << " models" << std::endl;
00395             }
00396 
00398 
00399             //
00400             // make a component from the node-set
00401             //
00402             ModelGenerator* mg = new OrdinaryModelGenerator(ctx);
00403 
00404             Component* weakComponent = new ProgramComponent(tmpNodes, mg);
00405 
00406             //
00407             // add the weak component to the subgraph
00408             //
00410             graph->addComponent(weakComponent);
00411 
00412             try
00413             {
00414                 weakComponent->evaluate(resultModels);
00415             }
00416             catch (GeneralError&) {
00417                 throw;
00418             }
00419 
00420             weakComponent->getResult(resultModels);
00421 
00422             if (Globals::Instance()->doVerbose(Globals::GRAPH_PROCESSOR)) {
00423                 Globals::Instance()->getVerboseStream() << "wcc result: " << resultModels.size() << " models" << std::endl;
00424 
00425                 for (std::vector<AtomSet>::iterator it = resultModels.begin();
00426                     it != resultModels.end();
00427                 ++it) {
00428                     RawPrintVisitor rpv(Globals::Instance()->getVerboseStream());
00429                     it->accept(rpv);
00430                     Globals::Instance()->getVerboseStream() << std::endl;
00431                 }
00432             }
00433 
00435             if (resultModels.empty()) {
00436                 //
00437                 // inconsistent!
00438                 //
00439                 break;
00440             }
00441         }
00442     }  while (graph->unsolvedComponentsLeft() && !resultModels.empty());
00443 
00444     if (resultModels.empty()) {
00445         //
00446         // inconsistent!
00448         resultModels.clear();
00449     }
00450 
00451     // set begin of the results to the newly computed result models
00452     resultSetIndex = resultModels.begin();
00453 }
00454 
00455 
00456 AtomSet*
00457 GraphProcessor::getNextModel()
00458 {
00459     if (resultSetIndex != resultModels.end()) {
00460         return &(*(resultSetIndex++));
00461     }
00462 
00463     return 0;
00464 }
00465 
00466 
00467 DLVHEX_NAMESPACE_END
00468 
00469 // vim: set noet sw=4 ts=8 tw=80:
00470 
00471 
00472 // vim:expandtab:ts=4:sw=4:
00473 // mode: C++
00474 // End: