Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
10068a0
evaluator to handle default value axioms
FlorianPommerening Jul 21, 2026
42b2c1c
remove std
FlorianPommerening Jul 22, 2026
cd07a8e
remove dead code
FlorianPommerening Jul 22, 2026
031299e
add warnings for unsupported axioms in heuristics previously using De…
FlorianPommerening Jul 22, 2026
e21fb0d
delegating implementation for the state registry
FlorianPommerening Jul 22, 2026
3f42d5e
hacked partial implementation for discussion
FlorianPommerening Jul 23, 2026
3c933ea
code review
FlorianPommerening Jul 24, 2026
fbc7b3b
rename files default_value_axioms_evaluator.* to axiom_handling_evalu…
FlorianPommerening Jul 24, 2026
27363af
replace checks that are now outdated with a check that states belong …
FlorianPommerening Jul 24, 2026
a1b6b4c
move flags for evaluator inside AxiomHandlingEvaluator and change the…
FlorianPommerening Jul 24, 2026
232d539
unify AxiomHandlingEvaluator and ModifyCostsEvaluator
FlorianPommerening Jul 24, 2026
75d7c6f
extract simple task transforming evaluator
FlorianPommerening Jul 24, 2026
0e2abeb
use correct task
FlorianPommerening Jul 24, 2026
f24bb02
notify transitions with correct states
FlorianPommerening Jul 24, 2026
5e30a05
rename simple_task_transforming_evaluator to state_forwarding_evaluat…
FlorianPommerening Jul 24, 2026
0d949fd
allow different registries inside transforming evaluators
FlorianPommerening Jul 24, 2026
2ad1ac5
style
FlorianPommerening Jul 24, 2026
1e784b5
remove convert_ancestor_state from heuristics
FlorianPommerening Jul 24, 2026
52250d3
remove get_ancestor_operator_id
FlorianPommerening Jul 24, 2026
47479bd
change concept of global root task to local explicit task read from file
FlorianPommerening Jul 25, 2026
7053aa8
rename root_task to explicit_task
FlorianPommerening Jul 25, 2026
9ae7b85
remove unused includes
FlorianPommerening Jul 25, 2026
0357ed4
remove unused includes
FlorianPommerening Jul 25, 2026
f53354e
unpack state before accessing unpacked data
FlorianPommerening Jul 25, 2026
3e90f7d
style
FlorianPommerening Jul 25, 2026
afa0ca4
style
FlorianPommerening Jul 25, 2026
5e6e628
Introduce EvaluatorCall class to represent the part of the evaluation…
FlorianPommerening Jul 29, 2026
b89b8c8
merge with main
FlorianPommerening Jul 29, 2026
e3c607e
style
FlorianPommerening Jul 29, 2026
e5f80c2
unpack state before heuristic evaluation
FlorianPommerening Jul 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion src/search/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ create_fast_downward_library(
evaluation_context
evaluation_result
evaluator
evaluator_call
evaluator_cache
heuristic
open_list
Expand Down Expand Up @@ -348,13 +349,32 @@ create_fast_downward_library(
DEPENDENCY_ONLY
)

create_fast_downward_library(
NAME state_forwarding_evaluator
HELP "Evaluator that uses a transformed task with the same set of states"
SOURCES
evaluators/state_forwarding_evaluator
)

create_fast_downward_library(
NAME axiom_handling_evaluator
HELP "Evaluator modifying axioms to handle negative values"
SOURCES
evaluators/axiom_handling_evaluator
DEPENDS
default_value_axioms_task
state_forwarding_evaluator
task_properties
)

create_fast_downward_library(
NAME modify_costs_evaluator
HELP "Evaluator modifying the costs"
SOURCES
evaluators/modify_costs_evaluator
DEPENDS
core_tasks
state_forwarding_evaluator
task_properties
)

Expand Down Expand Up @@ -731,7 +751,7 @@ create_fast_downward_library(
SOURCES
tasks/cost_adapted_task
tasks/delegating_task
tasks/root_task
tasks/explicit_task
CORE_LIBRARY
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@ AdditiveCartesianHeuristic::AdditiveCartesianHeuristic(
use_general_costs, random_seed, log)) {
}

int AdditiveCartesianHeuristic::compute_heuristic(const State &ancestor_state) {
State state = convert_ancestor_state(ancestor_state);
int AdditiveCartesianHeuristic::compute_heuristic(const State &state) {
int sum_h = 0;
for (const CartesianHeuristicFunction &function : heuristic_functions) {
int value = function.get_value(state);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class AdditiveCartesianHeuristic : public Heuristic {
const std::vector<CartesianHeuristicFunction> heuristic_functions;

protected:
virtual int compute_heuristic(const State &ancestor_state) override;
virtual int compute_heuristic(const State &state) override;

public:
AdditiveCartesianHeuristic(
Expand Down
4 changes: 2 additions & 2 deletions src/search/cartesian_abstractions/split_selector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ SplitSelector::SplitSelector(
: task(task), task_proxy(*task), pick(pick) {
if (pick == PickSplit::MIN_HADD || pick == PickSplit::MAX_HADD) {
additive_heuristic = make_unique<additive_heuristic::AdditiveHeuristic>(
task, tasks::AxiomHandlingType::APPROXIMATE_NEGATIVE, false,
"h^add within CEGAR abstractions", utils::Verbosity::SILENT);
task, false, "h^add within CEGAR abstractions",
utils::Verbosity::SILENT);
additive_heuristic->compute_heuristic_for_cegar(
task_proxy.get_initial_state());
}
Expand Down
4 changes: 2 additions & 2 deletions src/search/cartesian_abstractions/subtask_generators.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ class SortFactsByIncreasingHaddValues {
explicit SortFactsByIncreasingHaddValues(
const shared_ptr<AbstractTask> &task)
: hadd(make_unique<additive_heuristic::AdditiveHeuristic>(
task, tasks::AxiomHandlingType::APPROXIMATE_NEGATIVE, false,
"h^add within CEGAR abstractions", utils::Verbosity::SILENT)) {
task, false, "h^add within CEGAR abstractions",
utils::Verbosity::SILENT)) {
TaskProxy task_proxy(*task);
hadd->compute_heuristic_for_cegar(task_proxy.get_initial_state());
}
Expand Down
27 changes: 18 additions & 9 deletions src/search/evaluation_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "evaluation_result.h"
#include "evaluator.h"
#include "evaluator_call.h"
#include "search_statistics.h"

#include <cassert>
Expand All @@ -27,6 +28,13 @@ EvaluationContext::EvaluationContext(
calculate_preferred) {
}

EvaluationContext::EvaluationContext(
const EvaluationContext &other, const State &state)
: EvaluationContext(
EvaluatorCache(), state, other.g_value, other.preferred,
other.statistics, other.calculate_preferred) {
}

EvaluationContext::EvaluationContext(
const State &state, int g_value, bool is_preferred,
SearchStatistics *statistics, bool calculate_preferred)
Expand All @@ -43,21 +51,22 @@ EvaluationContext::EvaluationContext(
}

const EvaluationResult &EvaluationContext::get_result(Evaluator *evaluator) {
EvaluationResult &result = cache[evaluator];
if (result.is_uninitialized()) {
result = evaluator->compute_result(*this);
if (statistics && evaluator->is_used_for_counting_evaluations() &&
result.get_count_evaluation()) {
statistics->inc_evaluations();
}
}
return result;
EvaluatorCall call(*this, state);
return call[evaluator];
}

const EvaluatorCache &EvaluationContext::get_cache() const {
return cache;
}

EvaluatorCache &EvaluationContext::get_cache() {
return cache;
}

SearchStatistics *EvaluationContext::get_statistics() {
return statistics;
}

const State &EvaluationContext::get_state() const {
return state;
}
Expand Down
17 changes: 15 additions & 2 deletions src/search/evaluation_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
#include "operator_id.h"
#include "task_proxy.h"

#include <unordered_map>

class Evaluator;
class SearchStatistics;

Expand Down Expand Up @@ -64,6 +62,19 @@ class EvaluationContext {
EvaluationContext(
const EvaluationContext &other, int g_value, bool is_preferred,
SearchStatistics *statistics, bool calculate_preferred = false);
/*
Create new heuristic cache for caching heuristic values but copy other
information from the other evaluation context. This is only supposed to
be used by task-transforming evaluators that want to call nested
evaluators with a converted state, while still using the original
statistics. Starting from an empty cache is correct in this case:
all nested evaluators will use the transformed task or further
transformations of it while all other evaluators used outside of the
transforming evaluator do not have access to the transformed task. This
implies that cached values used in the scope of the transforming evaluator
are disjoint from any cached values used outside of this scope.
*/
EvaluationContext(const EvaluationContext &other, const State &state);
/*
Create new heuristic cache for caching heuristic values. Used for example
by eager search.
Expand All @@ -89,6 +100,8 @@ class EvaluationContext {

const EvaluationResult &get_result(Evaluator *eval);
const EvaluatorCache &get_cache() const;
EvaluatorCache &get_cache();
SearchStatistics *get_statistics();
const State &get_state() const;
int get_g_value() const;
bool is_preferred() const;
Expand Down
16 changes: 10 additions & 6 deletions src/search/evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#include <set>

class EvaluationContext;
class EvaluatorCall;
class State;

namespace plugins {
Expand Down Expand Up @@ -50,12 +50,17 @@ class Evaluator : public components::TaskSpecificComponent {
virtual void get_path_dependent_evaluators(
std::set<Evaluator *> &evals) = 0;

virtual void notify_initial_state(const State & /*initial_state*/) {
virtual void notify_initial_state(const State &initial_state) {
assert(initial_state.get_task() == TaskProxy(*task));
utils::unused_variable(initial_state);
}

virtual void notify_state_transition(
const State & /*parent_state*/, OperatorID /*op_id*/,
const State & /*state*/) {
const State &parent_state, OperatorID /*op_id*/, const State &state) {
assert(parent_state.get_task() == TaskProxy(*task));
assert(state.get_task() == TaskProxy(*task));
utils::unused_variable(parent_state);
utils::unused_variable(state);
}

/*
Expand All @@ -78,8 +83,7 @@ class Evaluator : public components::TaskSpecificComponent {
EvaluationContext. We need to think of a clean way to achieve
this.
*/
virtual EvaluationResult compute_result(
EvaluationContext &eval_context) = 0;
virtual EvaluationResult compute_result(EvaluatorCall &call) = 0;

void report_value_for_initial_state(const EvaluationResult &result) const;
void report_new_minimum_value(const EvaluationResult &result) const;
Expand Down
45 changes: 45 additions & 0 deletions src/search/evaluator_call.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#include "evaluator_call.h"

#include "evaluation_context.h"
#include "evaluation_result.h"
#include "evaluator.h"
#include "evaluator_cache.h"
#include "search_statistics.h"
#include "task_proxy.h"

EvaluatorCall::EvaluatorCall(EvaluationContext &context, const State &state)
: context(context), state(state) {
}

const EvaluationResult &EvaluatorCall::operator[](Evaluator *evaluator) {
EvaluationResult &result = context.get_cache()[evaluator];
if (result.is_uninitialized()) {
SearchStatistics *statistics = context.get_statistics();
result = evaluator->compute_result(*this);
if (statistics && evaluator->is_used_for_counting_evaluations() &&
result.get_count_evaluation()) {
statistics->inc_evaluations();
}
}
return result;
}

EvaluatorCall EvaluatorCall::get_subcall(const State &state) const {
return EvaluatorCall(context, state);
}

const State &EvaluatorCall::get_state() const {
return state;
}

int EvaluatorCall::get_g_value() const {
return context.get_g_value();
}

bool EvaluatorCall::get_calculate_preferred() const {
return context.get_calculate_preferred();
}

bool EvaluatorCall::is_preferred() const {
return context.is_preferred();
}
23 changes: 23 additions & 0 deletions src/search/evaluator_call.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef EVALUATOR_CALL_H
#define EVALUATOR_CALL_H

class EvaluationContext;
class EvaluationResult;
class Evaluator;
class State;

class EvaluatorCall {
EvaluationContext &context;
const State &state;
public:
EvaluatorCall(EvaluationContext &context, const State &state);
const EvaluationResult &operator[](Evaluator *evaluator);

EvaluatorCall get_subcall(const State &state) const;
const State &get_state() const;
int get_g_value() const;
bool get_calculate_preferred() const;
bool is_preferred() const;
};

#endif
51 changes: 51 additions & 0 deletions src/search/evaluators/axiom_handling_evaluator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "axiom_handling_evaluator.h"

#include "state_forwarding_evaluator.h"

#include "../evaluation_context.h"

#include "../task_utils/task_properties.h"

using namespace std;

namespace axiom_handling_evaluator {
shared_ptr<Evaluator>
TaskIndependentAxiomHandlingEvaluator::create_task_specific_component(
const shared_ptr<AbstractTask> &task) const {
TaskProxy proxy(*task);
if (task_properties::has_axioms(proxy)) {
shared_ptr<AbstractTask> axioms_task =
make_shared<tasks::DefaultValueAxiomsTask>(task, axioms);
shared_ptr<Evaluator> eval = nested->bind_task(axioms_task);
return make_shared<
state_forwarding_evaluator::StateForwardingEvaluator>(
task, axioms_task, eval, description, verbosity);
} else {
/*
If the task has no axioms, there is no need to wrap the evaluator
and we can bind the unmodified task to the nested evaluator directly.
*/
return nested->bind_task(task);
}
}

TaskIndependentAxiomHandlingEvaluator::TaskIndependentAxiomHandlingEvaluator(
shared_ptr<TaskIndependentEvaluator> nested,
tasks::AxiomHandlingType axioms, const string &description,
utils::Verbosity verbosity)
: nested(move(nested)),
axioms(axioms),
description(description),
verbosity(verbosity) {
}

shared_ptr<TaskIndependentEvaluator> wrap_in_axiom_handling_evaluator(
const shared_ptr<TaskIndependentEvaluator> &eval,
const plugins::Options &opts) {
return components::make_shared_from_arg_tuples<
axiom_handling_evaluator::TaskIndependentAxiomHandlingEvaluator>(
eval, tasks::get_axioms_arguments_from_options(opts),
get_evaluator_arguments_from_options(opts));
}

}
31 changes: 31 additions & 0 deletions src/search/evaluators/axiom_handling_evaluator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#ifndef EVALUATORS_AXIOM_HANDLING_EVALUATOR_H
#define EVALUATORS_AXIOM_HANDLING_EVALUATOR_H

#include "../evaluator.h"

#include "../tasks/default_value_axioms_task.h"

#include <memory.h>

namespace axiom_handling_evaluator {
class TaskIndependentAxiomHandlingEvaluator : public TaskIndependentEvaluator {
std::shared_ptr<TaskIndependentEvaluator> nested;
tasks::AxiomHandlingType axioms;
const std::string description;
utils::Verbosity verbosity;

virtual std::shared_ptr<Evaluator> create_task_specific_component(
const std::shared_ptr<AbstractTask> &task) const override;
public:
TaskIndependentAxiomHandlingEvaluator(
std::shared_ptr<TaskIndependentEvaluator> nested,
tasks::AxiomHandlingType axioms, const std::string &description,
utils::Verbosity verbosity);
};

std::shared_ptr<TaskIndependentEvaluator> wrap_in_axiom_handling_evaluator(
const std::shared_ptr<TaskIndependentEvaluator> &eval,
const plugins::Options &opts);
}

#endif
Loading
Loading