00001 #include <actasp/reasoners/Clingo3.h>
00002
00003 #include <actasp/AspRule.h>
00004 #include <actasp/AnswerSet.h>
00005 #include <actasp/AspAtom.h>
00006
00007 #include <algorithm>
00008 #include <iterator>
00009 #include <sstream>
00010 #include <fstream>
00011 #include <cstdlib>
00012 #include <iostream>
00013
00014 #define CURRENT_FILE_HOME queryDir // was std::string("/tmp/")
00015 #define CURRENT_STATE_FILE std::string("current.asp")
00016
00017 using namespace std;
00018
00019 namespace actasp {
00020
00021 Clingo3::Clingo3(const std::string& incrementalVar,
00022 const std::string& queryDir,
00023 const std::string& domainDir,
00024 const ActionSet& allActions,
00025 unsigned int max_time
00026 ) throw() :
00027 incrementalVar(incrementalVar),
00028 max_time(max_time),
00029 queryDir(queryDir),
00030 domainDir(domainDir),
00031 actionFilter() {
00032
00033 if (max_time > 0 && !system("timeout 2>/dev/null"))
00034 max_time = 0;
00035
00036
00037
00038 if (this->queryDir.find_last_of("/") != (this->queryDir.length() -1))
00039 this->queryDir += "/";
00040
00041 if ((this->domainDir.find_last_of("/")) != (this->domainDir.length() -1))
00042 this->domainDir += "/";
00043
00044
00045
00046
00047 ifstream currentFile((CURRENT_FILE_HOME + CURRENT_STATE_FILE).c_str());
00048 if(!currentFile.good())
00049 setCurrentState(set<AspFluent>());
00050
00051 currentFile.close();
00052
00053 stringstream filterStream;
00054 filterStream << "#hide." << endl;
00055
00056 std::set<AspFluent>::const_iterator actIt = allActions.begin();
00057 for (; actIt != allActions.end(); ++actIt) {
00058 filterStream << "#show " << actIt->getName() << "/" << actIt->arity() << "." << endl;
00059 }
00060
00061 actionFilter = filterStream.str();
00062 }
00063
00064 struct RuleToString3 {
00065 RuleToString3(unsigned int timeStepNum) {
00066 stringstream ss;
00067 ss << timeStepNum;
00068 timeStep = ss.str();
00069 }
00070
00071 RuleToString3(const std::string& timeStepVar) : timeStep(timeStepVar) {}
00072
00073 RuleToString3() : timeStep("") {}
00074
00075 std::string operator()(const AspRule& rule) {
00076
00077 stringstream ruleStream;
00078
00079
00080 for (int i =0, size = rule.head.size(); i <size; ++i) {
00081 if (timeStep.size() >0)
00082 ruleStream << rule.head[i].toString(timeStep);
00083 else
00084 ruleStream << rule.head[i].toString();
00085
00086 if (i < (size-1))
00087 ruleStream << ", ";
00088 }
00089
00090 if (!(rule.body.empty()))
00091 ruleStream << ":- ";
00092
00093
00094 for (int i =0, size = rule.body.size(); i <size; ++i) {
00095 if (timeStep.size() >0)
00096 ruleStream << rule.body[i].toString(timeStep);
00097 else
00098 ruleStream << rule.body[i].toString();
00099
00100 if (i < (size-1))
00101 ruleStream << ", ";
00102 }
00103
00104 if (!(rule.head.empty() && rule.body.empty()))
00105 ruleStream << "." << std::endl;
00106
00107 return ruleStream.str();
00108 }
00109
00110 string timeStep;
00111 };
00112
00113
00114 static string aspString(const std::vector<actasp::AspRule>& query, const string& timeStepVar) {
00115
00116 stringstream aspStream;
00117 transform(query.begin(),query.end(),ostream_iterator<std::string>(aspStream),RuleToString3(timeStepVar));
00118 return aspStream.str();
00119 }
00120
00121 static string aspString(const std::vector<actasp::AspRule>& query, unsigned int timeStep) {
00122
00123 stringstream vs;
00124 vs << timeStep;
00125
00126 return aspString(query,vs.str());
00127 }
00128
00129 static std::list<AspFluent> parseAnswerSet(const std::string& answerSetContent) throw() {
00130
00131 stringstream predicateLine(answerSetContent);
00132
00133 list<AspFluent> predicates;
00134
00135
00136 copy(istream_iterator<string>(predicateLine),
00137 istream_iterator<string>(),
00138 back_inserter(predicates));
00139
00140 return predicates;
00141 }
00142
00143
00144 static std::list<actasp::AnswerSet> readAnswerSets(const std::string& filePath) throw() {
00145
00146 ifstream file(filePath.c_str());
00147
00148 list<AnswerSet> allSets;
00149 bool interrupted = false;
00150
00151 string line;
00152 while (file) {
00153
00154 getline(file,line);
00155
00156 if (line == "UNSATISFIABLE")
00157 return list<AnswerSet>();
00158
00159 if (line.find("INTERRUPTED : 1") != string::npos)
00160 interrupted = true;
00161
00162 if (line.find("Answer") != string::npos) {
00163 getline(file,line);
00164 try {
00165 list<AspFluent> fluents = parseAnswerSet(line);
00166 allSets.push_back(AnswerSet(fluents.begin(), fluents.end()));
00167 } catch (std::invalid_argument& arg) {
00168
00169 }
00170 }
00171 }
00172
00173 if (interrupted)
00174 allSets.pop_back();
00175
00176 return allSets;
00177 }
00178
00179 string Clingo3::generatePlanQuery(std::vector<actasp::AspRule> goalRules,
00180 bool filterActions) const throw() {
00181 stringstream goal;
00182 goal << "#volatile " << incrementalVar << "." << endl;
00183
00184 goal << aspString(goalRules,incrementalVar+"-1") << endl;
00185
00186 if (filterActions)
00187 goal << actionFilter;
00188
00189
00190 return goal.str();
00191 }
00192
00193
00194 std::list<actasp::AnswerSet> Clingo3::minimalPlanQuery(const std::vector<actasp::AspRule>& goalRules,
00195 bool filterActions,
00196 unsigned int max_plan_length,
00197 unsigned int answerset_number) const throw() {
00198
00199 string planquery = generatePlanQuery(goalRules, filterActions);
00200
00201 return genericQuery(planquery,0,max_plan_length,"planQuery",answerset_number);
00202
00203 }
00204
00205 struct MaxTimeStepLessThan3 {
00206
00207 MaxTimeStepLessThan3(unsigned int initialTimeStep) : initialTimeStep(initialTimeStep) {}
00208
00209 bool operator()(const AnswerSet& answer) {
00210 return !answer.getFluents().empty() && answer.maxTimeStep() < initialTimeStep;
00211 }
00212
00213 unsigned int initialTimeStep;
00214 };
00215
00216 std::list<actasp::AnswerSet> Clingo3::lengthRangePlanQuery(const std::vector<actasp::AspRule>& goalRules,
00217 bool filterActions,
00218 unsigned int min_plan_length,
00219 unsigned int max_plan_length,
00220 unsigned int answerset_number) const throw() {
00221
00222 string planquery = generatePlanQuery(goalRules, filterActions);
00223
00224 std::list<actasp::AnswerSet> allplans = genericQuery(planquery,max_plan_length,max_plan_length,"planQuery",answerset_number);
00225
00226
00227
00228
00229 allplans.remove_if(MaxTimeStepLessThan3(min_plan_length));
00230
00231 return allplans;
00232
00233 }
00234
00235 AnswerSet Clingo3::currentStateQuery(const std::vector<actasp::AspRule>& query) const throw() {
00236 list<AnswerSet> sets = genericQuery(aspString(query,0),0,0,"stateQuery",1);
00237
00238 return (sets.empty())? AnswerSet() : *(sets.begin());
00239 }
00240
00241 std::list<actasp::AnswerSet> Clingo3::genericQuery(const std::vector<actasp::AspRule>& query,
00242 unsigned int timeStep,
00243 const std::string& fileName,
00244 unsigned int answerSetsNumber) const throw() {
00245 return genericQuery(aspString(query,""),timeStep,timeStep,fileName,answerSetsNumber);
00246
00247 }
00248
00249 std::list<actasp::AnswerSet> Clingo3::monitorQuery(const std::vector<actasp::AspRule>& goalRules,
00250 const AnswerSet& plan) const throw() {
00251
00252
00253
00254 string planQuery = generatePlanQuery(goalRules,true);
00255
00256 stringstream monitorQuery(planQuery, ios_base::app | ios_base::out);
00257
00258 const AnswerSet::FluentSet &allActions = plan.getFluents();
00259 AnswerSet::FluentSet::const_iterator actionIt = allActions.begin();
00260
00261 for (int i=1; actionIt != allActions.end(); ++actionIt, ++i)
00262 monitorQuery << actionIt->toString(i) << "." << endl;
00263
00264 list<actasp::AnswerSet> result = genericQuery(monitorQuery.str(),plan.getFluents().size(),plan.getFluents().size(),"monitorQuery",1);
00265
00266 result.remove_if(MaxTimeStepLessThan3(plan.getFluents().size()));
00267
00268
00269
00270
00271 return result;
00272 }
00273
00274 std::string Clingo3::makeQuery(const std::string& query,
00275 unsigned int initialTimeStep,
00276 unsigned int finalTimeStep,
00277 const std::string& fileName,
00278 unsigned int answerSetsNumber) const throw() {
00279
00280
00281 initialTimeStep++;
00282 finalTimeStep++;
00283
00284 string queryPath = queryDir + fileName + ".asp";
00285
00286 ofstream queryFile(queryPath.c_str());
00287 queryFile << query << endl;
00288 queryFile.close();
00289
00290 stringstream commandLine;
00291
00292 const string outputFilePath = queryDir + fileName + "_output.txt";
00293
00294 if (max_time > 0) {
00295 commandLine << "timeout " << max_time << " ";
00296 }
00297
00298 stringstream iterations;
00299 iterations << "--imin=" << initialTimeStep << " --imax=" << finalTimeStep;
00300
00301 commandLine << "iclingo " << iterations.str() << " " << queryPath << " " << domainDir << "*.asp " << (CURRENT_FILE_HOME + CURRENT_STATE_FILE) << " > " << outputFilePath << " " << answerSetsNumber;
00302
00303
00304 if (!system(commandLine.str().c_str())) {
00305
00306 }
00307
00308 return outputFilePath;
00309 }
00310
00311 std::list<actasp::AnswerSet> Clingo3::genericQuery(const std::string& query,
00312 unsigned int initialTimeStep,
00313 unsigned int finalTimeStep,
00314 const std::string& fileName,
00315 unsigned int answerSetsNumber) const throw() {
00316
00317 string outputFilePath = makeQuery(query,initialTimeStep,finalTimeStep,fileName,answerSetsNumber);
00318
00319 list<AnswerSet> allAnswers = readAnswerSets(outputFilePath);
00320
00321 return allAnswers;
00322 }
00323
00324 std::list< std::list<AspAtom> > Clingo3::genericQuery(const std::string& query,
00325 unsigned int timestep,
00326 const std::string& fileName,
00327 unsigned int answerSetsNumber) const throw() {
00328
00329 string outputFilePath = makeQuery(query,timestep,timestep,fileName,answerSetsNumber);
00330
00331 ifstream file(outputFilePath.c_str());
00332
00333 list<list <AspAtom> > allSets;
00334 bool answerFound = false;
00335
00336 string line;
00337 while(file) {
00338
00339 getline(file,line);
00340
00341 if(answerFound && line == "UNSATISFIABLE")
00342 return list<list <AspAtom> >();
00343
00344 if(line.find("Answer") != string::npos) {
00345 getline(file,line);
00346 try {
00347 stringstream predicateLine(line);
00348
00349 list<AspAtom> atoms;
00350
00351
00352 copy(istream_iterator<string>(predicateLine),
00353 istream_iterator<string>(),
00354 back_inserter(atoms));
00355
00356 allSets.push_back(atoms);
00357 } catch (std::invalid_argument& arg) {
00358
00359 }
00360 }
00361 }
00362
00363 return allSets;
00364
00365 }
00366
00367 void Clingo3::setCurrentState(const std::set<actasp::AspFluent>& newState) {
00368
00369
00370 ofstream currentFile((CURRENT_FILE_HOME + CURRENT_STATE_FILE).c_str());
00371
00372 set<AspFluent>::const_iterator stateIt = newState.begin();
00373 for (; stateIt != newState.end(); ++stateIt)
00374 currentFile << stateIt->toString(0) << "." << endl;
00375
00376 currentFile.close();
00377
00378 }
00379
00380
00381 }