Skip to content

Commit

Permalink
[issue454] Move computation of negated axioms to search component
Browse files Browse the repository at this point in the history
Negated axioms are now only computed for heuristics that need it. Specifically these are:
- additive heuristic
- context-enhanced additive heuristic
- causal graph heuristic
- FF heuristic
- max heuristic
- landmark heuristics (landmark sum and landmark cost partitioning)

Each heuristic computes the negated axioms separately. This can negatively
affect performance if a search with several such heuristics is performed, as is
for example done in LAMA (ff and landmark sum).
Heuristics that support axioms but do not need negated axioms might now be 
faster tasks with axioms, since they avoid the unnecessary computation.

A new enum option "axioms" has been added to all heuristics that need negated
axioms to determine how the negated axioms are computed.
- overapproximate_negated_cycles (default): Computes exact negation except for
  derived variables that have cyclic dependencies, which are trivially
  overapproximated (see issue453). This is the old behavior that can lead to an
  exponential explosion.
- overapproximate_negated: Trivially overapproximates all negations. This
  avoids the exponential explosion but makes the heuristic weaker.
  • Loading branch information
salome-eriksson authored Jul 19, 2024
1 parent 308812c commit f75018f
Show file tree
Hide file tree
Showing 26 changed files with 698 additions and 196 deletions.
20 changes: 18 additions & 2 deletions src/search/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -577,6 +577,8 @@ create_fast_downward_library(
SOURCES
heuristics/array_pool
heuristics/relaxation_heuristic
DEPENDS
default_value_axioms_task
DEPENDENCY_ONLY
)

Expand Down Expand Up @@ -606,6 +608,7 @@ create_fast_downward_library(
SOURCES
heuristics/cea_heuristic
DEPENDS
default_value_axioms_task
domain_transition_graph
priority_queues
task_properties
Expand All @@ -617,6 +620,7 @@ create_fast_downward_library(
SOURCES heuristics/cg_heuristic
heuristics/cg_cache
DEPENDS
default_value_axioms_task
domain_transition_graph
priority_queues
task_properties
Expand Down Expand Up @@ -700,6 +704,18 @@ create_fast_downward_library(
DEPENDENCY_ONLY
)

create_fast_downward_library(
NAME default_value_axioms_task
HELP "Task transformation adding axioms describing under which circumstances a derived variable is set to its default value."
SOURCES
tasks/default_value_axioms_task
DEPENDS
core_tasks
sccs
task_properties
DEPENDENCY_ONLY
)

create_fast_downward_library(
NAME causal_graph
HELP "Causal Graph"
Expand Down Expand Up @@ -846,6 +862,7 @@ create_fast_downward_library(
landmarks/landmark_sum_heuristic
landmarks/util
DEPENDS
default_value_axioms_task
lp_solver
priority_queues
successor_generator
Expand Down Expand Up @@ -937,8 +954,7 @@ create_fast_downward_library(

create_fast_downward_library(
NAME sccs
HELP "Algorithm to compute the strongly connected components (SCCs) of a "
"directed graph."
HELP "Algorithm to compute the strongly connected components (SCCs) of a directed graph."
SOURCES
algorithms/sccs
DEPENDENCY_ONLY
Expand Down
33 changes: 13 additions & 20 deletions src/search/axioms.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,28 @@ AxiomEvaluator::AxiomEvaluator(const TaskProxy &task_proxy) {
axiom_literals.emplace_back(var.get_domain_size());

// Initialize rules
// Since we are skipping some axioms, we cannot access them through
// their id position directly.
vector<int> axiom_id_to_position(axioms.size(), -1);
for (OperatorProxy axiom : axioms) {
assert(axiom.get_effects().size() == 1);
EffectProxy cond_effect = axiom.get_effects()[0];
FactPair effect = cond_effect.get_fact().get_pair();
int num_conditions = cond_effect.get_conditions().size();
// Ignore axioms which set the variable to its default value.
if (effect.value != variables[effect.var].get_default_axiom_value()) {
AxiomLiteral *eff_literal = &axiom_literals[effect.var][effect.value];
axiom_id_to_position[axiom.get_id()] = rules.size();
rules.emplace_back(
num_conditions, effect.var, effect.value, eff_literal);
}

// We don't allow axioms that set the variable to its default value.
assert(effect.value != variables[effect.var].get_default_axiom_value());
AxiomLiteral *eff_literal = &axiom_literals[effect.var][effect.value];
rules.emplace_back(
num_conditions, effect.var, effect.value, eff_literal);
}

// Cross-reference rules and literals
for (OperatorProxy axiom : axioms) {
// Ignore axioms which set the variable to its default value.
int position = axiom_id_to_position[axiom.get_id()];
if (position != -1) {
EffectProxy effect = axiom.get_effects()[0];
for (FactProxy condition : effect.get_conditions()) {
int var_id = condition.get_variable().get_id();
int val = condition.get_value();
AxiomRule *rule = &rules[position];
axiom_literals[var_id][val].condition_of.push_back(rule);
}
int id = axiom.get_id();
EffectProxy effect = axiom.get_effects()[0];
for (FactProxy condition : effect.get_conditions()) {
int var_id = condition.get_variable().get_id();
int val = condition.get_value();
AxiomRule *rule = &rules[id];
axiom_literals[var_id][val].condition_of.push_back(rule);
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/search/cartesian_abstractions/split_selector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ SplitSelector::SplitSelector(
if (pick == PickSplit::MIN_HADD || pick == PickSplit::MAX_HADD) {
additive_heuristic =
utils::make_unique_ptr<additive_heuristic::AdditiveHeuristic>(
task, false, "h^add within CEGAR abstractions",
tasks::AxiomHandlingType::APPROXIMATE_NEGATIVE, task,
false, "h^add within CEGAR abstractions",
utils::Verbosity::SILENT);
additive_heuristic->compute_heuristic_for_cegar(
task_proxy.get_initial_state());
Expand Down
3 changes: 2 additions & 1 deletion src/search/cartesian_abstractions/subtask_generators.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ class SortFactsByIncreasingHaddValues {
explicit SortFactsByIncreasingHaddValues(
const shared_ptr<AbstractTask> &task)
: hadd(utils::make_unique_ptr<additive_heuristic::AdditiveHeuristic>(
task, false, "h^add within CEGAR abstractions",
tasks::AxiomHandlingType::APPROXIMATE_NEGATIVE, 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
8 changes: 5 additions & 3 deletions src/search/heuristics/additive_heuristic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ namespace additive_heuristic {
const int AdditiveHeuristic::MAX_COST_VALUE;

AdditiveHeuristic::AdditiveHeuristic(
tasks::AxiomHandlingType axioms,
const shared_ptr<AbstractTask> &transform, bool cache_estimates,
const string &description, utils::Verbosity verbosity)
: RelaxationHeuristic(
transform, cache_estimates, description, verbosity),
axioms, transform, cache_estimates, description,
verbosity),
did_write_overflow_warning(false) {
if (log.is_at_least_normal()) {
log << "Initializing additive heuristic..." << endl;
Expand Down Expand Up @@ -153,7 +155,7 @@ class AdditiveHeuristicFeature
AdditiveHeuristicFeature() : TypedFeature("add") {
document_title("Additive heuristic");

add_heuristic_options_to_feature(*this, "add");
relaxation_heuristic::add_relaxation_heuristic_options_to_feature(*this, "add");

document_language_support("action costs", "supported");
document_language_support("conditional effects", "supported");
Expand All @@ -173,7 +175,7 @@ class AdditiveHeuristicFeature
const plugins::Options &opts,
const utils::Context &) const override {
return plugins::make_shared_from_arg_tuples<AdditiveHeuristic>(
get_heuristic_arguments_from_options(opts)
relaxation_heuristic::get_relaxation_heuristic_arguments_from_options(opts)
);
}
};
Expand Down
1 change: 1 addition & 0 deletions src/search/heuristics/additive_heuristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class AdditiveHeuristic : public relaxation_heuristic::RelaxationHeuristic {
int compute_add_and_ff(const State &state);
public:
AdditiveHeuristic(
tasks::AxiomHandlingType axioms,
const std::shared_ptr<AbstractTask> &transform,
bool cache_estimates, const std::string &description,
utils::Verbosity verbosity);
Expand Down
7 changes: 6 additions & 1 deletion src/search/heuristics/cea_heuristic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,12 @@ int ContextEnhancedAdditiveHeuristic::compute_heuristic(
}

ContextEnhancedAdditiveHeuristic::ContextEnhancedAdditiveHeuristic(
tasks::AxiomHandlingType axioms,
const shared_ptr<AbstractTask> &transform, bool cache_estimates,
const string &description, utils::Verbosity verbosity)
: Heuristic(transform, cache_estimates, description, verbosity),
: Heuristic(tasks::get_default_value_axioms_task_if_needed(
transform, axioms),
cache_estimates, description, verbosity),
min_action_cost(task_properties::get_min_operator_cost(task_proxy)) {
if (log.is_at_least_normal()) {
log << "Initializing context-enhanced additive heuristic..." << endl;
Expand Down Expand Up @@ -450,6 +453,7 @@ class ContextEnhancedAdditiveHeuristicFeature
ContextEnhancedAdditiveHeuristicFeature() : TypedFeature("cea") {
document_title("Context-enhanced additive heuristic");

tasks::add_axioms_option_to_feature(*this);
add_heuristic_options_to_feature(*this, "cea");

document_language_support("action costs", "supported");
Expand All @@ -470,6 +474,7 @@ class ContextEnhancedAdditiveHeuristicFeature
create_component(const plugins::Options &opts,
const utils::Context &) const override {
return plugins::make_shared_from_arg_tuples<ContextEnhancedAdditiveHeuristic>(
tasks::get_axioms_arguments_from_options(opts),
get_heuristic_arguments_from_options(opts)
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/search/heuristics/cea_heuristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "../heuristic.h"

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

#include <vector>

Expand Down Expand Up @@ -51,6 +52,7 @@ class ContextEnhancedAdditiveHeuristic : public Heuristic {
virtual int compute_heuristic(const State &ancestor_state) override;
public:
ContextEnhancedAdditiveHeuristic(
tasks::AxiomHandlingType axioms,
const std::shared_ptr<AbstractTask> &transform,
bool cache_estimates, const std::string &description,
utils::Verbosity verbosity);
Expand Down
9 changes: 7 additions & 2 deletions src/search/heuristics/cg_heuristic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ using namespace domain_transition_graph;

namespace cg_heuristic {
CGHeuristic::CGHeuristic(
int max_cache_size, const shared_ptr<AbstractTask> &transform,
int max_cache_size, tasks::AxiomHandlingType axioms,
const shared_ptr<AbstractTask> &transform,
bool cache_estimates, const string &description,
utils::Verbosity verbosity)
: Heuristic(transform, cache_estimates, description, verbosity),
: Heuristic(tasks::get_default_value_axioms_task_if_needed(
transform, axioms),
cache_estimates, description, verbosity),
cache_hits(0),
cache_misses(0),
helpful_transition_extraction_counter(0),
Expand Down Expand Up @@ -295,6 +298,7 @@ class CGHeuristicFeature
"maximum number of cached entries per variable (set to 0 to disable cache)",
"1000000",
plugins::Bounds("0", "infinity"));
tasks::add_axioms_option_to_feature(*this);
add_heuristic_options_to_feature(*this, "cg");

document_language_support("action costs", "supported");
Expand All @@ -316,6 +320,7 @@ class CGHeuristicFeature
const utils::Context &) const override {
return plugins::make_shared_from_arg_tuples<CGHeuristic>(
opts.get<int>("max_cache_size"),
tasks::get_axioms_arguments_from_options(opts),
get_heuristic_arguments_from_options(opts)
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/search/heuristics/cg_heuristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../heuristic.h"

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

#include <memory>
#include <string>
Expand Down Expand Up @@ -45,6 +46,7 @@ class CGHeuristic : public Heuristic {
public:
explicit CGHeuristic(
int max_cache_size,
tasks::AxiomHandlingType axiom_hanlding,
const std::shared_ptr<AbstractTask> &transform,
bool cache_estimates, const std::string &description,
utils::Verbosity verbosity);
Expand Down
8 changes: 5 additions & 3 deletions src/search/heuristics/ff_heuristic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ using namespace std;
namespace ff_heuristic {
// construction and destruction
FFHeuristic::FFHeuristic(
tasks::AxiomHandlingType axioms,
const shared_ptr<AbstractTask> &transform, bool cache_estimates,
const string &description, utils::Verbosity verbosity)
: AdditiveHeuristic(
transform, cache_estimates, description, verbosity),
axioms, transform, cache_estimates, description,
verbosity),
relaxed_plan(task_proxy.get_operators().size(), false) {
if (log.is_at_least_normal()) {
log << "Initializing FF heuristic..." << endl;
Expand Down Expand Up @@ -78,7 +80,7 @@ class FFHeuristicFeature
FFHeuristicFeature() : TypedFeature("ff") {
document_title("FF heuristic");

add_heuristic_options_to_feature(*this, "ff");
relaxation_heuristic::add_relaxation_heuristic_options_to_feature(*this, "ff");

document_language_support("action costs", "supported");
document_language_support("conditional effects", "supported");
Expand All @@ -98,7 +100,7 @@ class FFHeuristicFeature
const plugins::Options &opts,
const utils::Context &) const override {
return plugins::make_shared_from_arg_tuples<FFHeuristic>(
get_heuristic_arguments_from_options(opts)
relaxation_heuristic::get_relaxation_heuristic_arguments_from_options(opts)
);
}
};
Expand Down
1 change: 1 addition & 0 deletions src/search/heuristics/ff_heuristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class FFHeuristic : public additive_heuristic::AdditiveHeuristic {
virtual int compute_heuristic(const State &ancestor_state) override;
public:
FFHeuristic(
tasks::AxiomHandlingType axioms,
const std::shared_ptr<AbstractTask> &transform,
bool cache_estimates, const std::string &description,
utils::Verbosity verbosity);
Expand Down
9 changes: 6 additions & 3 deletions src/search/heuristics/max_heuristic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ namespace max_heuristic {

// construction and destruction
HSPMaxHeuristic::HSPMaxHeuristic(
tasks::AxiomHandlingType axioms,
const shared_ptr<AbstractTask> &transform, bool cache_estimates,
const string &description, utils::Verbosity verbosity)
: RelaxationHeuristic(
transform, cache_estimates, description, verbosity) {
axioms, transform, cache_estimates, description,
verbosity) {
if (log.is_at_least_normal()) {
log << "Initializing HSP max heuristic..." << endl;
}
Expand Down Expand Up @@ -107,7 +109,7 @@ class HSPMaxHeuristicFeature
HSPMaxHeuristicFeature() : TypedFeature("hmax") {
document_title("Max heuristic");

add_heuristic_options_to_feature(*this, "hmax");
relaxation_heuristic::add_relaxation_heuristic_options_to_feature(*this, "hmax");

document_language_support("action costs", "supported");
document_language_support("conditional effects", "supported");
Expand All @@ -127,7 +129,8 @@ class HSPMaxHeuristicFeature
const plugins::Options &opts,
const utils::Context &) const override {
return plugins::make_shared_from_arg_tuples<HSPMaxHeuristic>(
get_heuristic_arguments_from_options(opts));
relaxation_heuristic::get_relaxation_heuristic_arguments_from_options(opts)
);
}
};

Expand Down
1 change: 1 addition & 0 deletions src/search/heuristics/max_heuristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class HSPMaxHeuristic : public relaxation_heuristic::RelaxationHeuristic {
virtual int compute_heuristic(const State &ancestor_state) override;
public:
HSPMaxHeuristic(
tasks::AxiomHandlingType axioms,
const std::shared_ptr<AbstractTask> &transform,
bool cache_estimates, const std::string &description,
utils::Verbosity verbosity);
Expand Down
20 changes: 19 additions & 1 deletion src/search/heuristics/relaxation_heuristic.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "relaxation_heuristic.h"

#include "../plugins/plugin.h"
#include "../task_utils/task_properties.h"
#include "../utils/collections.h"
#include "../utils/logging.h"
Expand Down Expand Up @@ -33,12 +34,29 @@ UnaryOperator::UnaryOperator(
operator_no(operator_no) {
}

void add_relaxation_heuristic_options_to_feature(
plugins::Feature &feature, const string &description) {
tasks::add_axioms_option_to_feature(feature);
add_heuristic_options_to_feature(feature, description);
}

tuple<tasks::AxiomHandlingType, shared_ptr<AbstractTask>, bool, string,
utils::Verbosity>
get_relaxation_heuristic_arguments_from_options(const plugins::Options &opts) {
return tuple_cat(
tasks::get_axioms_arguments_from_options(opts),
get_heuristic_arguments_from_options(opts));
}


// construction and destruction
RelaxationHeuristic::RelaxationHeuristic(
tasks::AxiomHandlingType axioms,
const shared_ptr<AbstractTask> &transform, bool cache_estimates,
const string &description, utils::Verbosity verbosity)
: Heuristic(transform, cache_estimates, description, verbosity) {
: Heuristic(tasks::get_default_value_axioms_task_if_needed(
transform, axioms),
cache_estimates, description, verbosity) {
// Build propositions.
propositions.resize(task_properties::get_num_facts(task_proxy));

Expand Down
Loading

0 comments on commit f75018f

Please sign in to comment.