Issue1208

Title Remove old task transfomation code
Priority feature Status chatting
Superseder Nosy List florian, jendrik, malte
Assigned To Keywords
Optional summary
Pull Request: https://github.com/aibasel/downward/pull/296
Experiments: https://ai.dmi.unibas.ch/_experiments/ai/downward/issue1208/data/

Some ancillary things to keep in mind:
- Reuse per-task information (which includes Evaluators now) (issue564)
- Can we enable reuse of heuristics across different searches? See issue121.

TODOs for final implementation:
1. Check that goalcount heuristic benefits from the changes in this issue.
Converting GlobalStates to States made it slower (see issue554) and the change 
in issue348 should imply that the performance goes up again if we avoid copying 
the state due to a task transformation.

Follow-up work:
* issue1227 (Improve interplay between SearchAlgorithms, Heuristics, EvaluationContext, and StateRegistry)
* issue1236 (Unpack states only for heuristics that benefit from it)

Created on 2026-03-02.09:25:20 by florian, last changed by florian.

Summary
Pull Request: https://github.com/aibasel/downward/pull/296
Experiments: https://ai.dmi.unibas.ch/_experiments/ai/downward/issue1208/data/

Some ancillary things to keep in mind:
- Reuse per-task information (which includes Evaluators now) (issue564)
- Can we enable reuse of heuristics across different searches? See issue121.

TODOs for final implementation:
1. Check that goalcount heuristic benefits from the changes in this issue.
Converting GlobalStates to States made it slower (see issue554) and the change 
in issue348 should imply that the performance goes up again if we avoid copying 
the state due to a task transformation.

Follow-up work:
* issue1227 (Improve interplay between SearchAlgorithms, Heuristics, EvaluationContext, and StateRegistry)
* issue1236 (Unpack states only for heuristics that benefit from it)
Messages
msg12152 (view) Author: florian Date: 2026-08-04.16:42:58
Experiments ran for some optimal/satisficing portfolio/non-portfolio configurations.
The results are under "v3" here: https://ai.dmi.unibas.ch/_experiments/ai/downward/issue1208/data/

In general, the results looks ok in the sense that no configuration gets a lot worse or behaves differently than before (same expansions, roughly same time and memory requirements). However, we do see a consistent slow-down of a couple of percent across almost all configurations that costs 1-2 coverage in each configuration. For example, here is the scatter plot for A*/LM-cut:
https://ai.dmi.unibas.ch/_visualizer/?c=eJxVT8sKAjEM_BXJ2W19IIi_IiLRBi3stjVJ11XZf7ddD-pthknm8YKeWHwMsJvByixgPgOmVOmmQIeKBb4gc1svrqpJdtaiN67zJgd_QjHnqz3SkIh9R0GlqNbFe7gjO-tFMi1Xi62tXl_a9OsmJm2ox9YmjuVbPYlRZDM8Yfz0mLIHVOWC1rXR45dgkgL3e-jQh0boNlm23TlrHfIN-5cOh8m9LlLOVMiFaxS4WI1gHN8q5VoW

I tried reproducing this locally but on the tasks I tried, the performance was only lower by 1% in the profiler and that 1% was inside the heuristic evaluation (`LMcutLandmarks::second_exploration`). This is somewhat counterintuitive as we did not expect our changes to have any impact there.

We decided to not rush this story towards merging before the end of the current sprint but instead have a closer look and try to figure out why the performance looks as it does.
msg12151 (view) Author: florian Date: 2026-08-04.16:29:15
The pull request linked in the summary handles the changes discussed below. We did not remove the state/operator conversion methods in TaskProxy because task transformations are used internally in CEGAR. This is fine and unrelated to this issue, as this transformation only happens while the abstraction is built. The CEGAR classes that take a transformed task cannot deal with arbitrary transformations but since there is no way of calling the code with transformations other than those explicitly used this is not a problem.

The old code also used to wrap some tasks in transformations that add axioms in a way that deals with negative values. This transformation is now done in an explicit wrapping evaluator similar to the cost-modifying evaluator. The main difference is that the axiom evaluator cannot be used from the commandline and is wrapped around the relevant heuristics on demand (i.e., they cannot be used on the command-line without getting wrapped). The point of this is that the delete-relaxation heuristics would be incorrect when used with an unwrapped task with axioms and that the task transformation does not end up with a valid task (axioms are no longer stratifiable), so it cannot be used in arbitrary circumstances.

Both the cost-modifying evaluator and the axiom-handling evaluator now use a common class of a task-transforming evaluator that just "forwards" its state. Evaluators receive states from their own task, so if they use nested evaluators for a different task, they would have to give them a registered state from the transformed task. However, we don't want to register and store states twice when using task transformations that do not affect the states. The new forwarding evaluator uses a registry that registers a state from a different registry by giving it the same ID it has in the other registry, without actually storing it. Lookup etc. is delegated to the other registry. Using this, the new state-forwarding evaluator can give its nested evaluator a state from its own task without duplicating the state. There are rough edges regarding const-correctness which we intent to fix in issue1227.

One final change we had to do was to support the heuristic caching, boosting, etc. through transformations. To that end, we introduced a new class EvaluatorCall that represents a single call to an evaluator, where EvaluatorContext represents this call and all its sub-calls. In particular, the state stored in an EvaluatorContext represents the state for which the root node of the call "tree" is evaluated, while an EvaluatorCall can contain a different state (a transformation of the state in the context). The EvaluatorCall has a reference to the EvaluatorContext, and accesses it for statistics, caching, and properties about the call.

Previously, each heuristic converted the incoming state before evaluating it. This had the side effect of unpacking the state. As this conversion is now no longer done, we unpack the state in the heuristic base class to get the same behaviour as before. Figuring out better settings for each heuristic is issue1236.
msg12087 (view) Author: florian Date: 2026-06-18.17:02:17
moved TODO about checking for the performance of goalcount from issue559 to the summary here.
msg12084 (view) Author: florian Date: 2026-06-16.17:56:04
More things to cover in this issue:
* convert_ancestor_state and get_ancestor_operator_id
* update the comment in task_proxy.h (marked with "TODO(issue1208)")
* possibly the cost transformation in search algorithms
msg12041 (view) Author: florian Date: 2026-03-02.12:43:04
I moved some notes from issue559 about related issues here.
msg12036 (view) Author: florian Date: 2026-03-02.09:25:20
Once issue559 is merged, we should remove the traces of the old task transformation code. In particular this includes:
* Heursitic::convert_ancestor_state
* The transformation in Heuristic::set_preferred
* The check that the given task is a transformation of the root task in
  LandmarkHeuristic::initialize

Possibly this requires other changes such as
* making PerStateInformation no longer dispatch on the task
* transforming states in the virtual methods of ModifyCostsEvaluator
* updating the place the tasks are wrapped into the special axioms tasks (tasks::get_default_value_axioms_task_if_needed)
History
Date User Action Args
2026-08-04 16:42:58floriansetmessages: + msg12152
2026-08-04 16:29:15floriansetmessages: + msg12151
summary: Some ancillary things to keep in mind: - Reuse per-task information (which includes Evaluators now) (issue564) - Can we enable reuse of heuristics across different searches? See issue121. TODOs for final implementation: 1. Check that goalcount heuristic benefits from the changes in this issue. Converting GlobalStates to States made it slower (see issue554) and the change in issue348 should imply that the performance goes up again if we avoid copying the state due to a task transformation. -> Pull Request: https://github.com/aibasel/downward/pull/296 Experiments: https://ai.dmi.unibas.ch/_experiments/ai/downward/issue1208/data/ Some ancillary things to keep in mind: - Reuse per-task information (which includes Evaluators now) (issue564) - Can we enable reuse of heuristics across different searches? See issue121. TODOs for final implementation: 1. Check that goalcount heuristic benefits from the changes in this issue. Converting GlobalStates to States made it slower (see issue554) and the change in issue348 should imply that the performance goes up again if we avoid copying the state due to a task transformation. Follow-up work: * issue1227 (Improve interplay between SearchAlgorithms, Heuristics, EvaluationContext, and StateRegistry) * issue1236 (Unpack states only for heuristics that benefit from it)
2026-06-18 17:02:17floriansetmessages: + msg12087
summary: Some ancillary things to keep in mind: - Reuse per-task information (which includes Evaluators now) (issue564) - Can we enable reuse of heuristics across different searches? See issue121. -> Some ancillary things to keep in mind: - Reuse per-task information (which includes Evaluators now) (issue564) - Can we enable reuse of heuristics across different searches? See issue121. TODOs for final implementation: 1. Check that goalcount heuristic benefits from the changes in this issue. Converting GlobalStates to States made it slower (see issue554) and the change in issue348 should imply that the performance goes up again if we avoid copying the state due to a task transformation.
2026-06-16 17:56:04floriansetmessages: + msg12084
2026-03-02 12:43:04floriansetmessages: + msg12041
status: unread -> chatting
summary: Some ancillary things to keep in mind: - Reuse per-task information (which includes Evaluators now) (issue564) - Can we enable reuse of heuristics across different searches? See issue121.
2026-03-02 09:25:20floriancreate