Skip to content

Commit c5d0692

Browse files
committed
[conditional_effects] Fix backward deviation flaws in rare cases
1 parent 39ebf3a commit c5d0692

2 files changed

Lines changed: 111 additions & 12 deletions

File tree

src/search/cartesian_abstractions/abstraction.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ tuple<int, int> Abstraction::refine(
223223
CartesianSet &v2_cartesian_set = cartesian_sets.second;
224224

225225
vector<int> v2_values = wanted;
226+
#ifndef NDEBUG
227+
sort(v2_values.begin(), v2_values.end());
228+
#endif
226229
assert(v2_values == v2_cartesian_set.get_values(var));
227230
// We partition the abstract domain into two subsets. Since the refinement
228231
// hierarchy stores helper nodes for all values of one of the children, we

src/search/cartesian_abstractions/flaw_search.cc

Lines changed: 108 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,25 @@ static void update_affected_variables(
260260
}
261261
}
262262

263+
// For backward deviations, preconditions are always affected and conditional
264+
// effects are always unaffected, since values are split in the target state
265+
// instead of the source state.
266+
static void update_affected_variables_backward(
267+
const OperatorProxy &op,
268+
int num_variables,
269+
vector<bool> &affected_vars,
270+
const Abstraction &abstraction) {
271+
affected_vars.assign(num_variables, false);
272+
const vector<FactPair> &uncond_effects = abstraction.get_unconditional_effects(op.get_id());
273+
for (const FactPair &eff : uncond_effects) {
274+
affected_vars[eff.var] = true;
275+
}
276+
const vector<FactPair> &pre = abstraction.get_preconditions(op.get_id());
277+
for (const FactPair &precondition : pre) {
278+
affected_vars[precondition.var] = true;
279+
}
280+
}
281+
263282
struct FactPairHash {
264283
size_t operator()(FactPair fact) const {
265284
utils::HashState hash_state;
@@ -528,6 +547,7 @@ static void get_deviation_splits(
528547
static void get_backward_deviation_splits(
529548
const AbstractState &abs_state,
530549
const AbstractState &flaw_search_state,
550+
const vector<CondEffect> &cond_effects,
531551
const vector<bool> &affected_variables,
532552
const AbstractState &source_abs_state,
533553
const vector<int> &domain_sizes,
@@ -557,19 +577,94 @@ static void get_backward_deviation_splits(
557577
for (size_t var = 0; var < domain_sizes.size(); ++var) {
558578
for (int value = 0; value < domain_sizes[var]; ++value) {
559579
// Direct deviations in unaffected variables.
560-
if (fact_count[var][value] && !source_abs_state.contains(var, value)) {
561-
// Note: we could precompute the "wanted" vector, but not the split.
562-
vector<int> wanted;
563-
for (int value = 0; value < domain_sizes[var]; ++value) {
564-
if (abs_state.contains(var, value) &&
565-
source_abs_state.contains(var, value)) {
566-
wanted.push_back(value);
580+
if (fact_count[var][value] && !source_abs_state.contains(var, value) &&
581+
!flaw_search_state.intersects(source_abs_state, var)) {
582+
// If there is some conditional effect in var, the wanted values
583+
// are all possibly triggered effects.
584+
// If it is always triggered in the source abstract state because
585+
// all conditions are always satisfied, then the triggered
586+
// effects are the only wanted values, otherwise the values of
587+
// the source abstract state are also wanted.
588+
// If there is not satisfied conditional effects, then only
589+
// the values of the source abstract state are wanted.
590+
bool always_triggered = false;
591+
unordered_set<int> wanted;
592+
for (const CondEffect &eff : cond_effects) {
593+
if (eff.effect.var == static_cast<int>(var) && eff.effect.value != value &&
594+
abs_state.contains(eff.effect.var, eff.effect.value)) {
595+
bool satisfied = true;
596+
bool effect_always_triggered = true;
597+
for (const FactPair &cond : eff.conds) {
598+
if (source_abs_state.contains(cond.var, cond.value)) {
599+
if (effect_always_triggered && source_abs_state.count(cond.var) > 1) {
600+
effect_always_triggered = false;
601+
}
602+
} else {
603+
satisfied = false;
604+
break;
605+
}
606+
}
607+
if (satisfied) {
608+
wanted.insert(eff.effect.value);
609+
if (effect_always_triggered) {
610+
always_triggered = true;
611+
break;
612+
}
613+
}
614+
}
615+
}
616+
if (!always_triggered) {
617+
for (int value = 0; value < domain_sizes[var]; ++value) {
618+
if (abs_state.contains(var, value) &&
619+
source_abs_state.contains(var, value)) {
620+
wanted.insert(value);
621+
}
622+
}
623+
}
624+
if (!wanted.empty()) {
625+
add_backward_split(splits, Split(
626+
abs_state.get_id(), var, value, vector<int>(wanted.begin(), wanted.end()),
627+
1));
628+
}
629+
} else if (fact_count[var][value]) {
630+
// Deviation produced because the condition must be satisfied
631+
// in the source abstract state to trigger the effect and so
632+
// change the value of a variable modified by a conditional
633+
// effect. For each conditional effect:
634+
// 1. Check that the effect value is in the target in the
635+
// variable of such effect and it is not in the source
636+
// abstract state.
637+
// 2. Check that all conditions may be satisfied in the source
638+
// state.
639+
// 3. The wanted value is the value of the condition.
640+
for (const CondEffect &eff : cond_effects) {
641+
if (flaw_search_state.contains(eff.effect.var, eff.effect.value) &&
642+
!source_abs_state.contains(eff.effect.var, eff.effect.value) &&
643+
!flaw_search_state.intersects(source_abs_state, eff.effect.var)) {
644+
int cond_value = -1;
645+
bool conds_satisfied = true;
646+
for (const FactPair &cond : eff.conds) {
647+
if (!source_abs_state.contains(cond.var, cond.value)) {
648+
conds_satisfied = false;
649+
break;
650+
}
651+
if (cond.var == static_cast<int>(var)) {
652+
if (flaw_search_state.contains(cond.var, cond.value)) {
653+
// The condition is satisfied in the flaw-search state,
654+
// and so this condition is not the source of deviation.
655+
break;
656+
} else {
657+
cond_value = cond.value;
658+
}
659+
}
660+
}
661+
if (conds_satisfied && cond_value >= 0) {
662+
add_backward_split(splits, Split(
663+
abs_state.get_id(), var, value, {cond_value},
664+
1));
665+
}
567666
}
568667
}
569-
assert(!wanted.empty());
570-
add_backward_split(splits, Split(
571-
abs_state.get_id(), var, value, move(wanted),
572-
1));
573668
}
574669
}
575670
}
@@ -880,10 +975,11 @@ unique_ptr<Split> FlawSearch::create_backward_split(AbstractState &&state, int a
880975
<< ", source: " << source << endl;
881976
}
882977
const AbstractState &source_state = abstraction.get_state(source);
883-
update_affected_variables(op, n_vars, source_state, affected_vars, conditionally_affected_vars, abstraction);
978+
update_affected_variables_backward(op, n_vars, affected_vars, abstraction);
884979
get_backward_deviation_splits(
885980
abstract_state,
886981
state,
982+
abstraction.get_conditional_effects(op.get_id()),
887983
affected_vars,
888984
source_state, domain_sizes,
889985
backward_deviation_fact_count, splits);

0 commit comments

Comments
 (0)