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 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: