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
00072
00073 list<AspFluentRef>::const_iterator beforeSuspect = firstSuspect;
00074 advance(beforeSuspect, -1);
00075 list<AspFluentRef> withoutBeforeSuspect(planCleaned.begin(),beforeSuspect);
00076 withoutBeforeSuspect.insert(withoutBeforeSuspect.end(),firstSuspect,planCleaned.end());
00077 bool lastCheck = checkPlanValidity(withoutBeforeSuspect);
00078 if(lastCheck) {
00079 bad->insert(planCleaned);
00080
00081 }
00082
00083
00084
00085 return lastCheck;
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105 }
00106
00107 bool IsNotLocallyOptimal::hasLoops(const AnswerSet& plan) const {
00108 set<AspFluentRef> state;
00109
00110 set< set<AspFluentRef>, StateComparator<AspFluentRef> > allStates;
00111
00112 IsAnAction isAnAction(allActions);
00113 int timeStep = 0;
00114
00115 AnswerSet::FluentSet::const_iterator p = plan.getFluents().begin();
00116 for(; p!= plan.getFluents().end(); ++p) {
00117
00118 if(p->getTimeStep() != timeStep) {
00119
00120 bool present = !(allStates.insert(state).second);
00121
00122 if(present)
00123 return true;
00124
00125 state.clear();
00126 ++timeStep;
00127 }
00128
00129 if(!isAnAction(*p))
00130 state.insert(*p);
00131
00132 }
00133
00134
00135 bool present = !(allStates.insert(state).second);
00136
00137 if(present)
00138 return true;
00139
00140 return false;
00141 }
00142
00143
00144 bool IsNotLocallyOptimal::checkSectionWithLength(const std::list<AspFluentRef>& planCleaned,
00145 const std::list<AspFluentRef>::const_iterator firstSuspect,
00146 int length) const {
00147
00148
00149 int pos = distance(planCleaned.begin(), firstSuspect);
00150 int diffPos = std::max(-(length -1), -pos);
00151 unsigned int initialPos = pos + diffPos;
00152
00153
00154
00155
00156 std::list<AspFluentRef>::const_iterator initial = firstSuspect;
00157 advance(initial, diffPos);
00158
00159 for(int size = planCleaned.size(); initialPos <= pos && initialPos + length <= size; ++ initialPos, ++initial) {
00160
00161
00162
00163 list<AspFluentRef> testPlan(planCleaned.begin(), initial);
00164
00165 std::list<AspFluentRef>::const_iterator final = initial;
00166 advance(final,length);
00167
00168 testPlan.insert(testPlan.end(),final,planCleaned.end());
00169
00170
00171
00172
00173
00174 if(checkPlanValidity(testPlan)) {
00175
00176 return true;
00177 }
00178 }
00179
00180
00181
00182 return false;
00183 }
00184
00185
00186 bool IsNotLocallyOptimal::validFrom(const list<AspFluentRef>& planCleaned, list<AspFluentRef>::const_iterator firstSuspect) const{
00187
00188
00189 list<AspFluentRef> testPlan(planCleaned.begin(), firstSuspect);
00190 list<AspFluentRef>::iterator suspectInTest = testPlan.end();
00191
00192 testPlan.insert(testPlan.end(),(++firstSuspect),planCleaned.end());
00193 advance(suspectInTest, -distance(firstSuspect,planCleaned.end()));
00194
00195 bool done = false;
00196 while(!done) {
00197
00198
00199
00200
00201
00202 bool isValid = checkPlanValidity(testPlan);
00203 if(isValid) {
00204 bad->insert(planCleaned);
00205
00206
00207
00208 return true;
00209
00210 }
00211
00212 if(suspectInTest == testPlan.end())
00213 done = true;
00214 else
00215 suspectInTest = testPlan.erase(suspectInTest);
00216
00217 }
00218
00219
00220 return false;
00221 }
00222
00223 list<AspFluentRef> IsNotLocallyOptimal::cleanPlan(const AnswerSet& plan) const{
00224
00225
00226 list<AspFluentRef> actionsOnly;
00227
00228 if(planFiltered) {
00229 actionsOnly.insert(actionsOnly.end(),plan.getFluents().begin(),plan.getFluents().end());
00230 }
00231 else {
00232 remove_copy_if(plan.getFluents().begin(), plan.getFluents().end(),
00233 back_inserter(actionsOnly),not1(IsAnAction(allActions)));
00234 }
00235
00236 return actionsOnly;
00237
00238 }
00239
00240 list<AspFluentRef>::const_iterator IsNotLocallyOptimal::findFirstSuspiciousAction(const list<AspFluentRef>& plan) const {
00241
00242 if(good->empty())
00243 return plan.end();
00244
00245
00246
00247 PlanSet::iterator lb = good->lower_bound(plan);
00248
00249
00250
00251
00252
00253
00254
00255
00256 int dist1 = -1, dist2 = -1;
00257 list<AspFluentRef>::const_iterator sus1=plan.end(), sus2= plan.end();
00258
00259 if(lb != good->end()) {
00260 pair< list<AspFluentRef>::const_iterator, list<AspFluentRef>::const_iterator > different =
00261 mismatch(lb->begin(), lb->end(), plan.begin(), ActionEquality());
00262 dist1 = distance(plan.begin(), different.second);
00263 sus1 = different.second;
00264 }
00265
00266
00267 if (lb != good->begin()) {
00268 --lb;
00269
00270
00271
00272
00273
00274 pair< list<AspFluentRef>::const_iterator, list<AspFluentRef>::const_iterator > different =
00275 mismatch(lb->begin(), lb->end(), plan.begin(), ActionEquality());
00276 dist2 = distance(plan.begin(), different.second);
00277 sus2 = different.second;
00278 }
00279
00280
00281 if(dist1 > dist2){
00282
00283 return sus1;
00284 }
00285
00286
00287
00288 return sus2;
00289
00290 }
00291
00292 bool IsNotLocallyOptimal::checkPlanValidity(const list<AspFluentRef>& plan) const {
00293 PlanSet::const_iterator found = good->find(plan);
00294 if(found != good->end())
00295 return true;
00296
00297 found = bad->find(plan);
00298
00299 return found != bad->end();
00300 }
00301
00302
00303 }
00304