@@ -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