Skip to content

Commit b936047

Browse files
authored
Merge pull request #156 from plaans/fix/useless
Fix Useless Supports
2 parents a511781 + 9412b4d commit b936047

File tree

2 files changed

+74
-65
lines changed

2 files changed

+74
-65
lines changed

planning/planners/src/encode/symmetry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::Model;
1616
/// The value of this parameter is loaded from the environment variable `ARIES_LCP_SYMMETRY_BREAKING`.
1717
/// Possible values are `none` and `simple` (default).
1818
pub static SYMMETRY_BREAKING: EnvParam<SymmetryBreakingType> = EnvParam::new("ARIES_LCP_SYMMETRY_BREAKING", "psp");
19-
pub static USELESS_SUPPORTS: EnvParam<bool> = EnvParam::new("ARIES_USELESS_SUPPORTS", "false");
19+
pub static USELESS_SUPPORTS: EnvParam<bool> = EnvParam::new("ARIES_USELESS_SUPPORTS", "true");
2020
pub static PSP_ABSTRACTION_HIERARCHY: EnvParam<bool> = EnvParam::new("ARIES_PSP_ABSTRACTION_HIERARCHY", "true");
2121

2222
/// The type of symmetry breaking to apply to problems.

planning/planning/src/chronicles/analysis/detrimental_supports.rs

Lines changed: 73 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,15 @@ pub fn find_useless_supports(pb: &Problem) -> HashSet<CausalSupport> {
100100
}
101101
}
102102

103-
let mut useful_values = HashSet::new(); // TODO: extend with goals
104-
105-
for ch in &pb.templates {
106-
for cond in &ch.chronicle.conditions {
107-
let gval = value_of(&cond.state_var.fluent, &cond.state_var.args, cond.value);
108-
useful_values.insert(gval);
109-
}
110-
}
103+
// Extract all values that are useful.
104+
// A value is useful if it is a goal or a condition of a Chronicle template.
105+
let useful_values = pb
106+
.chronicles
107+
.iter()
108+
.flat_map(|ch| ch.chronicle.conditions.iter())
109+
.chain(pb.templates.iter().flat_map(|t| t.chronicle.conditions.iter()))
110+
.map(|c| value_of(&c.state_var.fluent, &c.state_var.args, c.value))
111+
.collect::<HashSet<_>>();
111112

112113
println!("Useful values:");
113114
for v in &useful_values {
@@ -294,7 +295,14 @@ fn gather_detrimental_supports(
294295
useful_values: &HashSet<GAtom>,
295296
detrimentals: &mut HashSet<CausalSupport>,
296297
) {
297-
let mut external_contributors = HashSet::new();
298+
let mut external_contributors = pb
299+
.chronicles
300+
.iter()
301+
.flat_map(|ch| ch.chronicle.conditions.iter())
302+
.filter(|c| c.state_var.fluent.as_ref() == fluent) // Goals on the fluent
303+
.map(|c| value_of(&c.state_var.fluent, &c.state_var.args, c.value))
304+
.collect::<HashSet<_>>();
305+
298306
for ch in &pb.templates {
299307
let mut conds = HashMap::new();
300308
for c in &ch.chronicle.conditions {
@@ -310,8 +318,6 @@ fn gather_detrimental_supports(
310318
let key = (&e.state_var, e.transition_start);
311319
if !conds.contains_key(&key) {
312320
return; // the fluent is not continuous
313-
} else {
314-
// conds.remove(&key).unwrap();
315321
}
316322
} else {
317323
let EffectOp::Assign(value) = e.operation else { panic!() };
@@ -337,18 +343,6 @@ fn gather_detrimental_supports(
337343
println!(" - {}", c.format(pb));
338344
}
339345

340-
// gather all values that are affected by non-optional chronicles (ie, non-templates)
341-
let mut initial_values = HashSet::new();
342-
for ch in &pb.chronicles {
343-
for e in &ch.chronicle.effects {
344-
if e.state_var.fluent.as_ref() == fluent {
345-
let EffectOp::Assign(value) = e.operation else { panic!() };
346-
let atom = value_of(&e.state_var.fluent, &e.state_var.args, value);
347-
initial_values.insert(atom.value);
348-
}
349-
}
350-
}
351-
352346
let conditions = find_conditions(fluent, pb);
353347
let transitions = find_transitions(fluent, pb);
354348
let supporters = |val: &GAtom| transitions.iter().filter(move |t| &t.post == val).collect_vec();
@@ -383,45 +377,60 @@ fn gather_detrimental_supports(
383377
}
384378
}
385379
}
386-
} /* Deactivated as it may be incorrect in some lifted cases where unless checking that the return (supported)
387-
transition ends up at the same value
388-
else {
389-
// detect pattern where the is a single transition value:
390-
// - always is the initial value
391-
// - is not useful in itself
392-
// - is the source/target of all transition to/from useful values
393-
let from_useful = transitions
394-
.iter()
395-
.filter(|t| external_contributors.contains(&t.pre))
396-
.collect_vec();
397-
let post_useful: HashSet<_> = from_useful.iter().map(|t| &t.post).collect();
398-
let to_useful = transitions
399-
.iter()
400-
.filter(|t| external_contributors.contains(&t.post))
401-
.collect_vec();
402-
let pre_useful: HashSet<_> = to_useful.iter().map(|t| &t.pre).collect();
403-
if post_useful.len() == 1 && post_useful == pre_useful {
404-
let transition_value = post_useful.iter().next().copied().unwrap();
405-
// true if there is a unique tranisition value (ie, it does not correspond to a type that could have ultiple values)
406-
let transition_value_is_unique = transition_value.value.is_constant();
407-
// true if the state variables always start from the initial value
408-
let transition_is_initial = initial_values.iter().all(|a| a == &transition_value.value);
409-
410-
if !external_contributors.contains(&transition_value) && transition_value_is_unique && transition_is_initial
411-
{
412-
// we have our single transition value,
413-
// mark as detrimental all transitions to it.
414-
// proof: any transition to it must be preceded by transition from it (with no other side effects)
415-
for t1 in supporters(transition_value) {
416-
for t2 in supported(transition_value) {
417-
if t1.post == t2.pre {
418-
// this is a transition from `transition_value -> useful_value -> transition_value`
419-
detrimentals.insert(CausalSupport::transitive(t1, t2));
420-
}
421-
}
422-
}
423-
}
424-
425-
}
426-
} */
380+
} else {
381+
// detect pattern where there is a single transition value:
382+
// - always is the initial value
383+
// - is not useful in itself
384+
// - is the source/target of all transition to/from useful values
385+
386+
// gather all values that are affected by non-optional chronicles (ie, non-templates)
387+
let mut initial_values = HashSet::new();
388+
for ch in &pb.chronicles {
389+
for e in &ch.chronicle.effects {
390+
if e.state_var.fluent.as_ref() == fluent {
391+
let EffectOp::Assign(value) = e.operation else { panic!() };
392+
let atom = value_of(&e.state_var.fluent, &e.state_var.args, value);
393+
initial_values.insert(atom.value);
394+
}
395+
}
396+
}
397+
let from_useful = transitions
398+
.iter()
399+
.filter(|t| external_contributors.contains(&t.pre))
400+
.collect_vec();
401+
let post_useful: HashSet<_> = from_useful.iter().map(|t| &t.post).collect();
402+
let to_useful = transitions
403+
.iter()
404+
.filter(|t| external_contributors.contains(&t.post))
405+
.collect_vec();
406+
let pre_useful: HashSet<_> = to_useful.iter().map(|t| &t.pre).collect();
407+
if post_useful.len() == 1 && post_useful == pre_useful {
408+
let transition_value = post_useful.iter().next().copied().unwrap();
409+
// true if there is a unique transition value (ie, it does not correspond to a type that could have multiple values)
410+
let transition_value_is_unique = transition_value.value.is_constant();
411+
// true if the state variables always start from the initial value
412+
let transition_is_initial = initial_values.iter().all(|a| a == &transition_value.value);
413+
414+
if !external_contributors.contains(transition_value) && transition_value_is_unique && transition_is_initial
415+
{
416+
// We have our single transition value.
417+
// Mark all transition cycles `useful -> transition_value -> useful` as detrimental.
418+
// Proof: There is not need to go through the transition value to reach
419+
// the useful value again with no other intermediate value.
420+
for t1 in supporters(transition_value) {
421+
for t2 in supported(transition_value) {
422+
if t1.post == t2.pre {
423+
println!(
424+
" => Detrimental: {} -> {} -> {}",
425+
t1.pre.format(pb),
426+
t1.post.format(pb),
427+
t2.post.format(pb)
428+
);
429+
detrimentals.insert(CausalSupport::transitive(t1, t2));
430+
}
431+
}
432+
}
433+
}
434+
}
435+
}
427436
}

0 commit comments

Comments
 (0)