00001 #include "IsNotLocallyOptimal.h"
00002
00003 #include <actasp/AnswerSet.h>
00004 #include <actasp/action_utils.h>
00005 #include <actasp/state_utils.h>
00006
00007 #include <algorithm>
00008
00009 #include <iostream>
00010 #include <iterator>
00011
00012 using namespace std;
00013
00014 namespace actasp {
00015
00016 IsNotLocallyOptimal::IsNotLocallyOptimal(const PlanSet* good, PlanSet* bad,
00017 const ActionSet& allActions,
00018 unsigned int shortestLength,
00019 bool planFiltered
00020 ) :
00021 good(good), bad(bad), allActions(allActions),
00022 shortestLength(shortestLength),
00023 planFiltered(planFiltered){}
00024
00025
00026 bool IsNotLocallyOptimal::operator()(const AnswerSet& plan) {
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 if(!planFiltered) {
00039 bool loops = hasLoops(plan);
00040 if(loops)
00041 return true;
00042 }
00043
00044
00045 const list<AspFluentRef> planCleaned = cleanPlan(plan);
00046
00047
00048
00049
00050
00051
00052 list<AspFluentRef>::const_iterator firstSuspect = findFirstSuspiciousAction(planCleaned);
00053
00054
00055 if(firstSuspect == planCleaned.end()) {
00056
00057 return false;
00058 }
00059
00060
00061
00062 for(int l = 1, size = planCleaned.size(); l <= size - shortestLength; ++l) {
00063
00064 if(checkSectionWithLength(planCleaned,firstSuspect,l)) {
00065 bad->insert(planCleaned);
00066 return true;
00067 }
00068
00069 }
00070
00071 return false;
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 }
00092
00093 bool IsNotLocallyOptimal::hasLoops(const AnswerSet& plan) const {
00094 set<AspFluentRef> state;
00095
00096 set< set<AspFluentRef>, StateComparator<AspFluentRef> > allStates;
00097
00098 IsAnAction isAnAction(allActions);
00099 int timeStep = 0;
00100
00101 AnswerSet::FluentSet::const_iterator p = plan.getFluents().begin();
00102 for(p; p!= plan.getFluents().end(); ++p) {
00103
00104 if(p->getTimeStep() != timeStep) {
00105
00106 bool present = !(allStates.insert(state).second);
00107
00108 if(present)
00109 return true;
00110
00111 state.clear();
00112 ++timeStep;
00113 }
00114
00115 if(!isAnAction(*p))
00116 state.insert(*p);
00117
00118 }
00119
00120
00121 bool present = !(allStates.insert(state).second);
00122
00123 if(present)
00124 return true;
00125
00126 return false;
00127 }
00128
00129
00130 bool IsNotLocallyOptimal::checkSectionWithLength(const std::list<AspFluentRef>& planCleaned,
00131 const std::list<AspFluentRef>::const_iterator firstSuspect,
00132 int length) const {
00133
00134
00135 int pos = distance(planCleaned.begin(), firstSuspect);
00136 int diffPos = std::max(-(length -1), -pos);
00137 unsigned int initialPos = pos + diffPos;
00138
00139
00140
00141
00142 std::list<AspFluentRef>::const_iterator initial = firstSuspect;
00143 advance(initial, diffPos);
00144
00145 for(int size = planCleaned.size(); initialPos <= pos && initialPos + length <= size; ++ initialPos, ++initial) {
00146
00147
00148
00149 list<AspFluentRef> testPlan(planCleaned.begin(), initial);
00150
00151 std::list<AspFluentRef>::const_iterator final = initial;
00152 advance(final,length);
00153
00154 testPlan.insert(testPlan.end(),final,planCleaned.end());
00155
00156
00157
00158
00159
00160 if(checkPlanValidity(testPlan)) {
00161
00162 return true;
00163 }
00164 }
00165
00166
00167
00168 return false;
00169 }
00170
00171
00172 bool IsNotLocallyOptimal::validFrom(const list<AspFluentRef>& planCleaned, list<AspFluentRef>::const_iterator firstSuspect) const{
00173
00174
00175 list<AspFluentRef> testPlan(planCleaned.begin(), firstSuspect);
00176 list<AspFluentRef>::iterator suspectInTest = testPlan.end();
00177
00178 testPlan.insert(testPlan.end(),(++firstSuspect),planCleaned.end());
00179 advance(suspectInTest, -distance(firstSuspect,planCleaned.end()));
00180
00181 bool done = false;
00182 while(!done) {
00183
00184
00185
00186
00187
00188 bool isValid = checkPlanValidity(testPlan);
00189 if(isValid) {
00190 bad->insert(planCleaned);
00191
00192
00193
00194 return true;
00195
00196 }
00197
00198 if(suspectInTest == testPlan.end())
00199 done = true;
00200 else
00201 suspectInTest = testPlan.erase(suspectInTest);
00202
00203 }
00204
00205
00206 return false;
00207 }
00208
00209 list<AspFluentRef> IsNotLocallyOptimal::cleanPlan(const AnswerSet& plan) const{
00210
00211
00212 list<AspFluentRef> actionsOnly;
00213
00214 if(planFiltered) {
00215 actionsOnly.insert(actionsOnly.end(),plan.getFluents().begin(),plan.getFluents().end());
00216 }
00217 else {
00218 remove_copy_if(plan.getFluents().begin(), plan.getFluents().end(),
00219 back_inserter(actionsOnly),not1(IsAnAction(allActions)));
00220 }
00221
00222 return actionsOnly;
00223
00224 }
00225
00226 list<AspFluentRef>::const_iterator IsNotLocallyOptimal::findFirstSuspiciousAction(const list<AspFluentRef>& plan) const {
00227
00228 if(good->empty())
00229 return plan.end();
00230
00231
00232
00233 PlanSet::iterator lb = good->lower_bound(plan);
00234
00235
00236
00237
00238
00239
00240
00241
00242 int dist1 = -1, dist2 = -1;
00243 list<AspFluentRef>::const_iterator sus1=plan.end(), sus2= plan.end();
00244
00245 if(lb != good->end()) {
00246 pair< list<AspFluentRef>::const_iterator, list<AspFluentRef>::const_iterator > different =
00247 mismatch(lb->begin(), lb->end(), plan.begin(), ActionEquality());
00248 dist1 = distance(plan.begin(), different.second);
00249 sus1 = different.second;
00250 }
00251
00252
00253 if (lb != good->begin()) {
00254 --lb;
00255
00256
00257
00258
00259
00260 pair< list<AspFluentRef>::const_iterator, list<AspFluentRef>::const_iterator > different =
00261 mismatch(lb->begin(), lb->end(), plan.begin(), ActionEquality());
00262 dist2 = distance(plan.begin(), different.second);
00263 sus2 = different.second;
00264 }
00265
00266
00267 if(dist1 > dist2){
00268
00269 return sus1;
00270 }
00271
00272
00273
00274 return sus2;
00275
00276 }
00277
00278 bool IsNotLocallyOptimal::checkPlanValidity(const list<AspFluentRef>& plan) const {
00279 PlanSet::const_iterator found = good->find(plan);
00280 if(found != good->end())
00281 return true;
00282
00283 found = bad->find(plan);
00284
00285 return found != bad->end();
00286 }
00287
00288
00289 }
00290