From be4bf166ac441468f845b19a06c014ba4f4b9be9 Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Tue, 30 Jan 2024 10:15:05 +0100 Subject: [PATCH 01/30] [issue1134] Rename existing delete-relaxation constraints and add copy for new Rankooh and Rintanen implementation. --- src/search/CMakeLists.txt | 2 +- ...cc => delete_relaxation_constraints_if.cc} | 30 +- ...s.h => delete_relaxation_constraints_if.h} | 8 +- .../delete_relaxation_constraints_rr.cc | 286 ++++++++++++++++++ .../delete_relaxation_constraints_rr.h | 76 +++++ 5 files changed, 382 insertions(+), 20 deletions(-) rename src/search/operator_counting/{delete_relaxation_constraints.cc => delete_relaxation_constraints_if.cc} (89%) rename src/search/operator_counting/{delete_relaxation_constraints.h => delete_relaxation_constraints_if.h} (89%) create mode 100644 src/search/operator_counting/delete_relaxation_constraints_rr.cc create mode 100644 src/search/operator_counting/delete_relaxation_constraints_rr.h diff --git a/src/search/CMakeLists.txt b/src/search/CMakeLists.txt index e9a8209a25..49b7569e55 100644 --- a/src/search/CMakeLists.txt +++ b/src/search/CMakeLists.txt @@ -856,7 +856,7 @@ create_fast_downward_library( HELP "Plugin containing the code for operator-counting heuristics" SOURCES operator_counting/constraint_generator - operator_counting/delete_relaxation_constraints + operator_counting/delete_relaxation_constraints_if operator_counting/lm_cut_constraints operator_counting/operator_counting_heuristic operator_counting/pho_constraints diff --git a/src/search/operator_counting/delete_relaxation_constraints.cc b/src/search/operator_counting/delete_relaxation_constraints_if.cc similarity index 89% rename from src/search/operator_counting/delete_relaxation_constraints.cc rename to src/search/operator_counting/delete_relaxation_constraints_if.cc index 959de4bad9..5a2161797d 100644 --- a/src/search/operator_counting/delete_relaxation_constraints.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_if.cc @@ -1,4 +1,4 @@ -#include "delete_relaxation_constraints.h" +#include "delete_relaxation_constraints_if.h" #include "../task_proxy.h" @@ -21,37 +21,37 @@ static void add_lp_variables(int count, LPVariables &variables, vector &ind } -DeleteRelaxationConstraints::DeleteRelaxationConstraints(const plugins::Options &opts) +DeleteRelaxationConstraintsIF::DeleteRelaxationConstraintsIF(const plugins::Options &opts) : use_time_vars(opts.get("use_time_vars")), use_integer_vars(opts.get("use_integer_vars")) { } -int DeleteRelaxationConstraints::get_var_op_used(const OperatorProxy &op) { +int DeleteRelaxationConstraintsIF::get_var_op_used(const OperatorProxy &op) { return lp_var_id_op_used[op.get_id()]; } -int DeleteRelaxationConstraints::get_var_fact_reached(FactPair f) { +int DeleteRelaxationConstraintsIF::get_var_fact_reached(FactPair f) { return lp_var_id_fact_reached[f.var][f.value]; } -int DeleteRelaxationConstraints::get_var_first_achiever( +int DeleteRelaxationConstraintsIF::get_var_first_achiever( const OperatorProxy &op, FactPair f) { return lp_var_id_first_achiever[op.get_id()][f.var][f.value]; } -int DeleteRelaxationConstraints::get_var_op_time(const OperatorProxy &op) { +int DeleteRelaxationConstraintsIF::get_var_op_time(const OperatorProxy &op) { return lp_var_id_op_time[op.get_id()]; } -int DeleteRelaxationConstraints::get_var_fact_time(FactPair f) { +int DeleteRelaxationConstraintsIF::get_var_fact_time(FactPair f) { return lp_var_id_fact_time[f.var][f.value]; } -int DeleteRelaxationConstraints::get_constraint_id(FactPair f) { +int DeleteRelaxationConstraintsIF::get_constraint_id(FactPair f) { return constraint_ids[f.var][f.value]; } -void DeleteRelaxationConstraints::create_auxiliary_variables( +void DeleteRelaxationConstraintsIF::create_auxiliary_variables( const TaskProxy &task_proxy, LPVariables &variables) { OperatorsProxy ops = task_proxy.get_operators(); int num_ops = ops.size(); @@ -94,7 +94,7 @@ void DeleteRelaxationConstraints::create_auxiliary_variables( } } -void DeleteRelaxationConstraints::create_constraints(const TaskProxy &task_proxy, +void DeleteRelaxationConstraintsIF::create_constraints(const TaskProxy &task_proxy, lp::LinearProgram &lp) { LPVariables &variables = lp.get_variables(); LPConstraints &constraints = lp.get_constraints(); @@ -213,7 +213,7 @@ void DeleteRelaxationConstraints::create_constraints(const TaskProxy &task_proxy } -void DeleteRelaxationConstraints::initialize_constraints( +void DeleteRelaxationConstraintsIF::initialize_constraints( const shared_ptr &task, lp::LinearProgram &lp) { TaskProxy task_proxy(*task); create_auxiliary_variables(task_proxy, lp.get_variables()); @@ -221,7 +221,7 @@ void DeleteRelaxationConstraints::initialize_constraints( } -bool DeleteRelaxationConstraints::update_constraints( +bool DeleteRelaxationConstraintsIF::update_constraints( const State &state, lp::LPSolver &lp_solver) { // Unset old bounds. for (FactPair f : last_state) { @@ -236,9 +236,9 @@ bool DeleteRelaxationConstraints::update_constraints( return false; } -class DeleteRelaxationConstraintsFeature : public plugins::TypedFeature { +class DeleteRelaxationConstraintsIFFeature : public plugins::TypedFeature { public: - DeleteRelaxationConstraintsFeature() : TypedFeature("delete_relaxation_constraints") { + DeleteRelaxationConstraintsIFFeature() : TypedFeature("delete_relaxation_constraints") { document_title("Delete relaxation constraints"); document_synopsis( "Operator-counting constraints based on the delete relaxation. By " @@ -282,5 +282,5 @@ class DeleteRelaxationConstraintsFeature : public plugins::TypedFeature _plugin; +static plugins::FeaturePlugin _plugin; } diff --git a/src/search/operator_counting/delete_relaxation_constraints.h b/src/search/operator_counting/delete_relaxation_constraints_if.h similarity index 89% rename from src/search/operator_counting/delete_relaxation_constraints.h rename to src/search/operator_counting/delete_relaxation_constraints_if.h index a28fed269e..b508bd0026 100644 --- a/src/search/operator_counting/delete_relaxation_constraints.h +++ b/src/search/operator_counting/delete_relaxation_constraints_if.h @@ -1,5 +1,5 @@ -#ifndef OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_H -#define OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_H +#ifndef OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_IF_H +#define OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_IF_H #include "constraint_generator.h" @@ -20,7 +20,7 @@ namespace operator_counting { using LPConstraints = named_vector::NamedVector; using LPVariables = named_vector::NamedVector; -class DeleteRelaxationConstraints : public ConstraintGenerator { +class DeleteRelaxationConstraintsIF : public ConstraintGenerator { bool use_time_vars; bool use_integer_vars; @@ -63,7 +63,7 @@ class DeleteRelaxationConstraints : public ConstraintGenerator { const TaskProxy &task_proxy, LPVariables &variables); void create_constraints(const TaskProxy &task_proxy, lp::LinearProgram &lp); public: - explicit DeleteRelaxationConstraints(const plugins::Options &opts); + explicit DeleteRelaxationConstraintsIF(const plugins::Options &opts); virtual void initialize_constraints( const std::shared_ptr &task, diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc new file mode 100644 index 0000000000..14922400df --- /dev/null +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -0,0 +1,286 @@ +#include "delete_relaxation_constraints_rr.h" + +#include "../task_proxy.h" + +#include "../lp/lp_solver.h" +#include "../plugins/plugin.h" +#include "../utils/markup.h" + +#include + +using namespace std; + +namespace operator_counting { +static void add_lp_variables(int count, LPVariables &variables, vector &indices, + double lower, double upper, double objective, + bool is_integer) { + for (int i = 0; i < count; ++i) { + indices.push_back(variables.size()); + variables.emplace_back(lower, upper, objective, is_integer); + } +} + + +DeleteRelaxationConstraintsRR::DeleteRelaxationConstraintsRR(const plugins::Options &opts) + : use_time_vars(opts.get("use_time_vars")), + use_integer_vars(opts.get("use_integer_vars")) { +} + +int DeleteRelaxationConstraintsRR::get_var_op_used(const OperatorProxy &op) { + return lp_var_id_op_used[op.get_id()]; +} + +int DeleteRelaxationConstraintsRR::get_var_fact_reached(FactPair f) { + return lp_var_id_fact_reached[f.var][f.value]; +} + +int DeleteRelaxationConstraintsRR::get_var_first_achiever( + const OperatorProxy &op, FactPair f) { + return lp_var_id_first_achiever[op.get_id()][f.var][f.value]; +} + +int DeleteRelaxationConstraintsRR::get_var_op_time(const OperatorProxy &op) { + return lp_var_id_op_time[op.get_id()]; +} + +int DeleteRelaxationConstraintsRR::get_var_fact_time(FactPair f) { + return lp_var_id_fact_time[f.var][f.value]; +} + +int DeleteRelaxationConstraintsRR::get_constraint_id(FactPair f) { + return constraint_ids[f.var][f.value]; +} + +void DeleteRelaxationConstraintsRR::create_auxiliary_variables( + const TaskProxy &task_proxy, LPVariables &variables) { + OperatorsProxy ops = task_proxy.get_operators(); + int num_ops = ops.size(); + VariablesProxy vars = task_proxy.get_variables(); + int num_vars = vars.size(); + + // op_used + add_lp_variables(num_ops, variables, lp_var_id_op_used, 0, 1, 0, use_integer_vars); + + // fact_reached + lp_var_id_fact_reached.resize(num_vars); + for (VariableProxy var : vars) { + add_lp_variables(var.get_domain_size(), variables, + lp_var_id_fact_reached[var.get_id()], + 0, 1, 0, use_integer_vars); + } + + // first_achiever + lp_var_id_first_achiever.resize(num_ops); + for (OperatorProxy op : ops) { + lp_var_id_first_achiever[op.get_id()].resize(num_vars); + for (VariableProxy var : vars) { + add_lp_variables(var.get_domain_size(), variables, + lp_var_id_first_achiever[op.get_id()][var.get_id()], + 0, 1, 0, use_integer_vars); + } + } + + if (use_time_vars) { + // op_time + add_lp_variables(num_ops, variables, lp_var_id_op_time, 0, num_ops, 0, use_integer_vars); + + // fact_time + lp_var_id_fact_time.resize(num_vars); + for (VariableProxy var : vars) { + add_lp_variables(var.get_domain_size(), variables, + lp_var_id_fact_time[var.get_id()], + 0, num_ops, 0, use_integer_vars); + } + } +} + +void DeleteRelaxationConstraintsRR::create_constraints(const TaskProxy &task_proxy, + lp::LinearProgram &lp) { + LPVariables &variables = lp.get_variables(); + LPConstraints &constraints = lp.get_constraints(); + double infinity = lp.get_infinity(); + OperatorsProxy ops = task_proxy.get_operators(); + VariablesProxy vars = task_proxy.get_variables(); + + /* + All goal facts must be reached (handled in variable bound instead of + constraint). + R_f = 1 for all goal facts f. + */ + for (FactProxy goal : task_proxy.get_goals()) { + variables[get_var_fact_reached(goal.get_pair())].lower_bound = 1; + } + + /* + A fact is reached if it has a first achiever or is true in the + current state. + sum_{o \in achievers(f)} F_{o,f} - R_f >= [s |= f] for each fact f. + */ + constraint_ids.resize(vars.size()); + for (VariableProxy var : vars) { + int var_id = var.get_id(); + constraint_ids[var_id].resize(var.get_domain_size()); + for (int value = 0; value < var.get_domain_size(); ++value) { + constraint_ids[var_id][value] = constraints.size(); + constraints.emplace_back(0, infinity); + /* We add "- R_f" here, collect the achiever below and adapt + the lower bound in each iteration, i.e., in + update_constraints. */ + constraints.back().insert( + get_var_fact_reached(FactPair(var_id, value)), -1); + } + } + for (OperatorProxy op : ops) { + for (EffectProxy eff : op.get_effects()) { + FactPair f = eff.get_fact().get_pair(); + lp::LPConstraint &constraint = constraints[get_constraint_id(f)]; + constraint.insert(get_var_first_achiever(op, f), 1); + } + } + + /* + If an operator is a first achiever, it must be used. + U_o >= F_{o,f} for each operator o and each of its effects f. + */ + for (OperatorProxy op : ops) { + for (EffectProxy eff : op.get_effects()) { + FactPair f = eff.get_fact().get_pair(); + lp::LPConstraint constraint(0, infinity); + constraint.insert(get_var_op_used(op), 1); + constraint.insert(get_var_first_achiever(op, f), -1); + constraints.push_back(constraint); + } + } + + /* + If an operator is used, its preconditions must be reached. + R_f >= U_o for each operator o and each of its preconditions f. + */ + for (OperatorProxy op : ops) { + for (FactProxy f : op.get_preconditions()) { + lp::LPConstraint constraint(0, infinity); + constraint.insert(get_var_fact_reached(f.get_pair()), 1); + constraint.insert(get_var_op_used(op), -1); + constraints.push_back(constraint); + } + } + + if (use_time_vars) { + /* + Preconditions must be reached before the operator is used. + T_f <= T_o for each operator o and each of its preconditions f. + */ + for (OperatorProxy op : ops) { + for (FactProxy f : op.get_preconditions()) { + lp::LPConstraint constraint(0, infinity); + constraint.insert(get_var_op_time(op), 1); + constraint.insert(get_var_fact_time(f.get_pair()), -1); + constraints.push_back(constraint); + } + } + + /* + If an operator is a first achiever, its effects are reached in + the time step following its use. + T_o + 1 <= T_f + M(1 - F_{o,f}) + for each operator o and each of its effects f. + We rewrite this as + 1 - M <= T_f - T_o - M*F_{o,f} <= infty + */ + int M = ops.size() + 1; + for (OperatorProxy op : ops) { + for (EffectProxy eff : op.get_effects()) { + FactPair f = eff.get_fact().get_pair(); + lp::LPConstraint constraint(1 - M, infinity); + constraint.insert(get_var_fact_time(f), 1); + constraint.insert(get_var_op_time(op), -1); + constraint.insert(get_var_first_achiever(op, f), -M); + constraints.push_back(constraint); + } + } + } + + /* + If an operator is used, it must occur at least once. + U_o <= C_o for each operator o. + */ + for (OperatorProxy op : ops) { + lp::LPConstraint constraint(0, infinity); + constraint.insert(op.get_id(), 1); + constraint.insert(get_var_op_used(op), -1); + constraints.push_back(constraint); + } +} + + +void DeleteRelaxationConstraintsRR::initialize_constraints( + const shared_ptr &task, lp::LinearProgram &lp) { + TaskProxy task_proxy(*task); + create_auxiliary_variables(task_proxy, lp.get_variables()); + create_constraints(task_proxy, lp); +} + + +bool DeleteRelaxationConstraintsRR::update_constraints( + const State &state, lp::LPSolver &lp_solver) { + // Unset old bounds. + for (FactPair f : last_state) { + lp_solver.set_constraint_lower_bound(get_constraint_id(f), 0); + } + last_state.clear(); + // Set new bounds. + for (FactProxy f : state) { + lp_solver.set_constraint_lower_bound(get_constraint_id(f.get_pair()), -1); + last_state.push_back(f.get_pair()); + } + return false; +} + +class DeleteRelaxationConstraintsRRFeature : public plugins::TypedFeature { +public: + DeleteRelaxationConstraintsRRFeature() : TypedFeature("delete_relaxation_constraints") { + document_title("Delete relaxation constraints"); + document_synopsis( + "Operator-counting constraints based on the delete relaxation. By " + "default the constraints encode an easy-to-compute relaxation of h^+^. " + "With the right settings, these constraints can be used to compute the " + "optimal delete-relaxation heuristic h^+^ (see example below). " + "For details, see" + utils::format_journal_reference( + {"Tatsuya Imai", "Alex Fukunaga"}, + "On a practical, integer-linear programming model for delete-free" + "tasks and its use as a heuristic for cost-optimal planning", + "https://www.jair.org/index.php/jair/article/download/10972/26119/", + "Journal of Artificial Intelligence Research", + "54", + "631-677", + "2015")); + + add_option( + "use_time_vars", + "use variables for time steps. With these additional variables the " + "constraints enforce an order between the selected operators. Leaving " + "this off (default) corresponds to the time relaxation by Imai and " + "Fukunaga. Switching it on, can increase the heuristic value but will " + "increase the size of the constraints which has a strong impact on " + "runtime. Constraints involving time variables use a big-M encoding, " + "so they are more useful if used with integer variables.", + "false"); + add_option( + "use_integer_vars", + "restrict auxiliary variables to integer values. These variables " + "encode whether operators are used, facts are reached, which operator " + "first achieves which fact, and in which order the operators are used. " + "Restricting them to integers generally improves the heuristic value " + "at the cost of increased runtime.", + "false"); + + document_note( + "Example", + "To compute the optimal delete-relaxation heuristic h^+^, use\n" + "{{{\noperatorcounting([delete_relaxation_constraints(use_time_vars=true, " + "use_integer_vars=true)], use_integer_operator_counts=true))\n}}}\n"); + } +}; + +static plugins::FeaturePlugin _plugin; +} diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.h b/src/search/operator_counting/delete_relaxation_constraints_rr.h new file mode 100644 index 0000000000..4619cc8b50 --- /dev/null +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.h @@ -0,0 +1,76 @@ +#ifndef OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_RR_H +#define OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_RR_H + +#include "constraint_generator.h" + +#include "../task_proxy.h" + +#include + +namespace lp { +class LPConstraint; +struct LPVariable; +} + +namespace plugins { +class Options; +} + +namespace operator_counting { +using LPConstraints = named_vector::NamedVector; +using LPVariables = named_vector::NamedVector; + +class DeleteRelaxationConstraintsRR : public ConstraintGenerator { + bool use_time_vars; + bool use_integer_vars; + + /* [U_o] Is op part of the relaxed plan? + Binary, indexed with op.id */ + std::vector lp_var_id_op_used; + + /* [R_f] Is fact reached by the relaxed plan? + Binary, indexed with var.id, value */ + std::vector> lp_var_id_fact_reached; + + /* [F_{o,f}] Is o the first achiever of fact in the relaxed plan? + Binary, indexed with op.id, var.id, value */ + std::vector>> lp_var_id_first_achiever; + + /* [T_o] At what time is o used first? + {0, ..., |O|}, indexed with op.id */ + std::vector lp_var_id_op_time; + + /* [T_f] At what time is first achieved? + {0, ..., |O|}, indexed with var.id, value */ + std::vector> lp_var_id_fact_time; + + /* Indices of constraints that change in every state + Indexed with var.id, value */ + std::vector> constraint_ids; + + /* The state that is currently used for setting the bounds. Remembering + this makes it faster to unset the bounds when the state changes. */ + std::vector last_state; + + int get_var_op_used(const OperatorProxy &op); + int get_var_fact_reached(FactPair f); + int get_var_first_achiever(const OperatorProxy &op, FactPair f); + int get_var_op_time(const OperatorProxy &op); + int get_var_fact_time(FactPair f); + int get_constraint_id(FactPair f); + + void create_auxiliary_variables( + const TaskProxy &task_proxy, LPVariables &variables); + void create_constraints(const TaskProxy &task_proxy, lp::LinearProgram &lp); +public: + explicit DeleteRelaxationConstraintsRR(const plugins::Options &opts); + + virtual void initialize_constraints( + const std::shared_ptr &task, + lp::LinearProgram &lp) override; + virtual bool update_constraints( + const State &state, lp::LPSolver &lp_solver) override; +}; +} + +#endif From 7bc1dac1715be235aaf2cfc2a4bad65d8066d652 Mon Sep 17 00:00:00 2001 From: Simon Dold Date: Tue, 30 Jan 2024 15:52:14 +0100 Subject: [PATCH 02/30] [issue1134] adjust synopsis, add alias for issue --- driver/aliases.py | 4 +++ .../delete_relaxation_constraints_rr.cc | 30 ++++++++----------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/driver/aliases.py b/driver/aliases.py index 88dfb09ce0..d7b474d4ab 100644 --- a/driver/aliases.py +++ b/driver/aliases.py @@ -141,6 +141,10 @@ def _get_lama(pref): ALIASES["seq-opt-lmcut"] = [ "--search", "astar(lmcut())"] +ALIASES["issue1134-1"] = [ + "--search", + "astar(operatorcounting([delete_relaxation_constraints(use_time_vars=true, use_integer_vars=true)], use_integer_operator_counts=false, lpsolver=cplex, verbosity=normal, transform=no_transform(), cache_estimates=true))" +] # TODO issue1134 remove PORTFOLIOS = {} for portfolio in os.listdir(PORTFOLIO_DIR): diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 14922400df..b843762aad 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -238,32 +238,28 @@ bool DeleteRelaxationConstraintsRR::update_constraints( class DeleteRelaxationConstraintsRRFeature : public plugins::TypedFeature { public: - DeleteRelaxationConstraintsRRFeature() : TypedFeature("delete_relaxation_constraints") { - document_title("Delete relaxation constraints"); + DeleteRelaxationConstraintsRRFeature() : TypedFeature("delete_relaxation_constraints_rr") { + document_title("Delete relaxation constraints from Rankooh and Rintanen"); document_synopsis( "Operator-counting constraints based on the delete relaxation. By " "default the constraints encode an easy-to-compute relaxation of h^+^. " "With the right settings, these constraints can be used to compute the " "optimal delete-relaxation heuristic h^+^ (see example below). " "For details, see" + utils::format_journal_reference( - {"Tatsuya Imai", "Alex Fukunaga"}, - "On a practical, integer-linear programming model for delete-free" - "tasks and its use as a heuristic for cost-optimal planning", - "https://www.jair.org/index.php/jair/article/download/10972/26119/", - "Journal of Artificial Intelligence Research", - "54", - "631-677", - "2015")); + {"Masood Feyzbakhsh Rankooh", "Jussi Rintanen"}, + "Efficient Computation and Informative Estimation of" + "h+ by Integer and Linear Programming" + "", + "https://ojs.aaai.org/index.php/ICAPS/article/view/19787/19546", + "Proceedings of the Thirty-Second International Conference on Automated Planning and Scheduling (ICAPS2022)", + "32", + "71-79", + "2022")); add_option( "use_time_vars", "use variables for time steps. With these additional variables the " - "constraints enforce an order between the selected operators. Leaving " - "this off (default) corresponds to the time relaxation by Imai and " - "Fukunaga. Switching it on, can increase the heuristic value but will " - "increase the size of the constraints which has a strong impact on " - "runtime. Constraints involving time variables use a big-M encoding, " - "so they are more useful if used with integer variables.", + "constraints enforce an order between the selected operators.", "false"); add_option( "use_integer_vars", @@ -277,7 +273,7 @@ class DeleteRelaxationConstraintsRRFeature : public plugins::TypedFeature Date: Wed, 31 Jan 2024 16:01:09 +0100 Subject: [PATCH 03/30] [issue1134] Add causal partial function constraints and remove copy-pasted code. --- .../delete_relaxation_constraints_if.cc | 2 +- .../delete_relaxation_constraints_rr.cc | 279 +++++++----------- .../delete_relaxation_constraints_rr.h | 51 ++-- 3 files changed, 132 insertions(+), 200 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_if.cc b/src/search/operator_counting/delete_relaxation_constraints_if.cc index 5a2161797d..a44945aba7 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_if.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_if.cc @@ -95,7 +95,7 @@ void DeleteRelaxationConstraintsIF::create_auxiliary_variables( } void DeleteRelaxationConstraintsIF::create_constraints(const TaskProxy &task_proxy, - lp::LinearProgram &lp) { + lp::LinearProgram &lp) { LPVariables &variables = lp.get_variables(); LPConstraints &constraints = lp.get_constraints(); double infinity = lp.get_infinity(); diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index b843762aad..212f4b05ff 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -1,9 +1,8 @@ #include "delete_relaxation_constraints_rr.h" -#include "../task_proxy.h" - #include "../lp/lp_solver.h" #include "../plugins/plugin.h" +#include "../task_proxy.h" #include "../utils/markup.h" #include @@ -11,44 +10,47 @@ using namespace std; namespace operator_counting { -static void add_lp_variables(int count, LPVariables &variables, vector &indices, - double lower, double upper, double objective, - bool is_integer) { +static void add_lp_variables(int count, LPVariables &variables, + vector &indices, double lower, double upper, + double objective, bool is_integer) { for (int i = 0; i < count; ++i) { indices.push_back(variables.size()); variables.emplace_back(lower, upper, objective, is_integer); } } - -DeleteRelaxationConstraintsRR::DeleteRelaxationConstraintsRR(const plugins::Options &opts) +DeleteRelaxationConstraintsRR::DeleteRelaxationConstraintsRR( + const plugins::Options &opts) : use_time_vars(opts.get("use_time_vars")), - use_integer_vars(opts.get("use_integer_vars")) { -} - -int DeleteRelaxationConstraintsRR::get_var_op_used(const OperatorProxy &op) { - return lp_var_id_op_used[op.get_id()]; -} + use_integer_vars(opts.get("use_integer_vars")) {} -int DeleteRelaxationConstraintsRR::get_var_fact_reached(FactPair f) { - return lp_var_id_fact_reached[f.var][f.value]; +int DeleteRelaxationConstraintsRR::get_var_f_defined(FactPair f) { + return lp_var_id_f_defined[f.var][f.value]; } -int DeleteRelaxationConstraintsRR::get_var_first_achiever( - const OperatorProxy &op, FactPair f) { - return lp_var_id_first_achiever[op.get_id()][f.var][f.value]; +int DeleteRelaxationConstraintsRR::get_var_f_maps_to(FactPair f, + const OperatorProxy &op) { + return lp_var_id_f_maps_to.at(make_tuple(f.var, f.value, op.get_id())); } -int DeleteRelaxationConstraintsRR::get_var_op_time(const OperatorProxy &op) { - return lp_var_id_op_time[op.get_id()]; -} - -int DeleteRelaxationConstraintsRR::get_var_fact_time(FactPair f) { - return lp_var_id_fact_time[f.var][f.value]; +bool DeleteRelaxationConstraintsRR::is_in_effect(FactPair f, + const OperatorProxy &op) { + for (EffectProxy eff : op.get_effects()) { + if (eff.get_fact().get_pair() == f) { + return true; + } + } + return false; } -int DeleteRelaxationConstraintsRR::get_constraint_id(FactPair f) { - return constraint_ids[f.var][f.value]; +bool DeleteRelaxationConstraintsRR::is_in_precondition( + FactPair f, const OperatorProxy &op) { + for (FactProxy pre : op.get_preconditions()) { + if (pre.get_pair() == f) { + return true; + } + } + return false; } void DeleteRelaxationConstraintsRR::create_auxiliary_variables( @@ -58,44 +60,29 @@ void DeleteRelaxationConstraintsRR::create_auxiliary_variables( VariablesProxy vars = task_proxy.get_variables(); int num_vars = vars.size(); - // op_used - add_lp_variables(num_ops, variables, lp_var_id_op_used, 0, 1, 0, use_integer_vars); - - // fact_reached - lp_var_id_fact_reached.resize(num_vars); + lp_var_id_f_defined.resize(num_vars); for (VariableProxy var : vars) { + int var_id = var.get_id(); + // Add f_p variable. add_lp_variables(var.get_domain_size(), variables, - lp_var_id_fact_reached[var.get_id()], - 0, 1, 0, use_integer_vars); - } - - // first_achiever - lp_var_id_first_achiever.resize(num_ops); - for (OperatorProxy op : ops) { - lp_var_id_first_achiever[op.get_id()].resize(num_vars); - for (VariableProxy var : vars) { - add_lp_variables(var.get_domain_size(), variables, - lp_var_id_first_achiever[op.get_id()][var.get_id()], - 0, 1, 0, use_integer_vars); - } - } - - if (use_time_vars) { - // op_time - add_lp_variables(num_ops, variables, lp_var_id_op_time, 0, num_ops, 0, use_integer_vars); - - // fact_time - lp_var_id_fact_time.resize(num_vars); - for (VariableProxy var : vars) { - add_lp_variables(var.get_domain_size(), variables, - lp_var_id_fact_time[var.get_id()], - 0, num_ops, 0, use_integer_vars); + lp_var_id_f_defined[var_id], 0, 1, 0, + use_integer_vars); + // Add f_{p,a} variables. + for (int value = 0; value < var.get_domain_size(); ++value) { + for (OperatorProxy op : ops) { + if (is_in_effect(FactPair(var_id, value), op)) { + lp_var_id_f_maps_to.emplace( + make_pair(make_tuple(var_id, value, op.get_id()), + variables.size())); + variables.emplace_back(0, 1, 0, use_integer_vars); + } + } } } } -void DeleteRelaxationConstraintsRR::create_constraints(const TaskProxy &task_proxy, - lp::LinearProgram &lp) { +void DeleteRelaxationConstraintsRR::create_constraints( + const TaskProxy &task_proxy, lp::LinearProgram &lp) { LPVariables &variables = lp.get_variables(); LPConstraints &constraints = lp.get_constraints(); double infinity = lp.get_infinity(); @@ -103,116 +90,65 @@ void DeleteRelaxationConstraintsRR::create_constraints(const TaskProxy &task_pro VariablesProxy vars = task_proxy.get_variables(); /* - All goal facts must be reached (handled in variable bound instead of - constraint). - R_f = 1 for all goal facts f. - */ - for (FactProxy goal : task_proxy.get_goals()) { - variables[get_var_fact_reached(goal.get_pair())].lower_bound = 1; - } - - /* - A fact is reached if it has a first achiever or is true in the - current state. - sum_{o \in achievers(f)} F_{o,f} - R_f >= [s |= f] for each fact f. + f must map a proposition to at most one operator. + Constraint (2) in paper. */ - constraint_ids.resize(vars.size()); - for (VariableProxy var : vars) { - int var_id = var.get_id(); - constraint_ids[var_id].resize(var.get_domain_size()); - for (int value = 0; value < var.get_domain_size(); ++value) { - constraint_ids[var_id][value] = constraints.size(); - constraints.emplace_back(0, infinity); - /* We add "- R_f" here, collect the achiever below and adapt - the lower bound in each iteration, i.e., in - update_constraints. */ - constraints.back().insert( - get_var_fact_reached(FactPair(var_id, value)), -1); - } - } - for (OperatorProxy op : ops) { - for (EffectProxy eff : op.get_effects()) { - FactPair f = eff.get_fact().get_pair(); - lp::LPConstraint &constraint = constraints[get_constraint_id(f)]; - constraint.insert(get_var_first_achiever(op, f), 1); + for (VariableProxy var_p : vars) { + for (int value_p = 0; value_p < var_p.get_domain_size(); ++value_p) { + constraints.emplace_back(0, 0); + FactPair fact_p(var_p.get_id(), value_p); + constraints.back().insert(get_var_f_defined(fact_p), -1); + for (OperatorProxy op : ops) { + if (is_in_effect(fact_p, op)) + constraints.back().insert(get_var_f_maps_to(fact_p, op), 1); + } } } /* - If an operator is a first achiever, it must be used. - U_o >= F_{o,f} for each operator o and each of its effects f. + Constraint (3) in paper. */ - for (OperatorProxy op : ops) { - for (EffectProxy eff : op.get_effects()) { - FactPair f = eff.get_fact().get_pair(); - lp::LPConstraint constraint(0, infinity); - constraint.insert(get_var_op_used(op), 1); - constraint.insert(get_var_first_achiever(op, f), -1); - constraints.push_back(constraint); + for (VariableProxy var_p : vars) { + for (int value_p = 0; value_p < var_p.get_domain_size(); ++value_p) { + FactPair fact_p(var_p.get_id(), value_p); + for (VariableProxy var_q : vars) { + for (int value_q = 0; value_q < var_q.get_domain_size(); + ++value_q) { + FactPair fact_q(var_q.get_id(), value_q); + constraints.emplace_back(0, 1); + constraints.back().insert(get_var_f_defined(fact_q), 1); + for (OperatorProxy op : ops) { + if (is_in_precondition(fact_q, op) && + is_in_effect(fact_p, op)) { + constraints.back().insert( + get_var_f_maps_to(fact_p, op), -1); + } + } + } + } } } /* - If an operator is used, its preconditions must be reached. - R_f >= U_o for each operator o and each of its preconditions f. + Constraint (4) in paper. */ - for (OperatorProxy op : ops) { - for (FactProxy f : op.get_preconditions()) { - lp::LPConstraint constraint(0, infinity); - constraint.insert(get_var_fact_reached(f.get_pair()), 1); - constraint.insert(get_var_op_used(op), -1); - constraints.push_back(constraint); - } - } - - if (use_time_vars) { - /* - Preconditions must be reached before the operator is used. - T_f <= T_o for each operator o and each of its preconditions f. - */ - for (OperatorProxy op : ops) { - for (FactProxy f : op.get_preconditions()) { - lp::LPConstraint constraint(0, infinity); - constraint.insert(get_var_op_time(op), 1); - constraint.insert(get_var_fact_time(f.get_pair()), -1); - constraints.push_back(constraint); - } - } - - /* - If an operator is a first achiever, its effects are reached in - the time step following its use. - T_o + 1 <= T_f + M(1 - F_{o,f}) - for each operator o and each of its effects f. - We rewrite this as - 1 - M <= T_f - T_o - M*F_{o,f} <= infty - */ - int M = ops.size() + 1; - for (OperatorProxy op : ops) { - for (EffectProxy eff : op.get_effects()) { - FactPair f = eff.get_fact().get_pair(); - lp::LPConstraint constraint(1 - M, infinity); - constraint.insert(get_var_fact_time(f), 1); - constraint.insert(get_var_op_time(op), -1); - constraint.insert(get_var_first_achiever(op, f), -M); - constraints.push_back(constraint); - } - } + for (FactProxy goal : task_proxy.get_goals()) { + variables[get_var_f_defined(goal.get_pair())].lower_bound = 1; } /* - If an operator is used, it must occur at least once. - U_o <= C_o for each operator o. + Constraint (5) in paper. */ for (OperatorProxy op : ops) { - lp::LPConstraint constraint(0, infinity); - constraint.insert(op.get_id(), 1); - constraint.insert(get_var_op_used(op), -1); - constraints.push_back(constraint); + for (EffectProxy eff : op.get_effects()) { + FactPair fact_p = eff.get_fact().get_pair(); + constraints.emplace_back(0, infinity); + constraints.back().insert(get_var_f_maps_to(fact_p, op), -1); + constraints.back().insert(op.get_id(), 1); + } } } - void DeleteRelaxationConstraintsRR::initialize_constraints( const shared_ptr &task, lp::LinearProgram &lp) { TaskProxy task_proxy(*task); @@ -220,7 +156,6 @@ void DeleteRelaxationConstraintsRR::initialize_constraints( create_constraints(task_proxy, lp); } - bool DeleteRelaxationConstraintsRR::update_constraints( const State &state, lp::LPSolver &lp_solver) { // Unset old bounds. @@ -230,31 +165,38 @@ bool DeleteRelaxationConstraintsRR::update_constraints( last_state.clear(); // Set new bounds. for (FactProxy f : state) { - lp_solver.set_constraint_lower_bound(get_constraint_id(f.get_pair()), -1); + lp_solver.set_constraint_lower_bound(get_constraint_id(f.get_pair()), + -1); last_state.push_back(f.get_pair()); } return false; } -class DeleteRelaxationConstraintsRRFeature : public plugins::TypedFeature { +class DeleteRelaxationConstraintsRRFeature + : public plugins::TypedFeature { public: - DeleteRelaxationConstraintsRRFeature() : TypedFeature("delete_relaxation_constraints_rr") { - document_title("Delete relaxation constraints from Rankooh and Rintanen"); + DeleteRelaxationConstraintsRRFeature() + : TypedFeature("delete_relaxation_constraints_rr") { + document_title( + "Delete relaxation constraints from Rankooh and Rintanen"); document_synopsis( "Operator-counting constraints based on the delete relaxation. By " - "default the constraints encode an easy-to-compute relaxation of h^+^. " - "With the right settings, these constraints can be used to compute the " + "default the constraints encode an easy-to-compute relaxation of " + "h^+^. " + "With the right settings, these constraints can be used to compute " + "the " "optimal delete-relaxation heuristic h^+^ (see example below). " - "For details, see" + utils::format_journal_reference( + "For details, see" + + utils::format_journal_reference( {"Masood Feyzbakhsh Rankooh", "Jussi Rintanen"}, "Efficient Computation and Informative Estimation of" "h+ by Integer and Linear Programming" "", "https://ojs.aaai.org/index.php/ICAPS/article/view/19787/19546", - "Proceedings of the Thirty-Second International Conference on Automated Planning and Scheduling (ICAPS2022)", - "32", - "71-79", - "2022")); + "Proceedings of the Thirty-Second International Conference on " + "Automated Planning and Scheduling (ICAPS2022)", + "32", "71-79", "2022")); add_option( "use_time_vars", @@ -264,17 +206,22 @@ class DeleteRelaxationConstraintsRRFeature : public plugins::TypedFeature( "use_integer_vars", "restrict auxiliary variables to integer values. These variables " - "encode whether operators are used, facts are reached, which operator " - "first achieves which fact, and in which order the operators are used. " - "Restricting them to integers generally improves the heuristic value " + "encode whether operators are used, facts are reached, which " + "operator " + "first achieves which fact, and in which order the operators are " + "used. " + "Restricting them to integers generally improves the heuristic " + "value " "at the cost of increased runtime.", "false"); document_note( "Example", "To compute the optimal delete-relaxation heuristic h^+^, use\n" - "{{{\noperatorcounting([delete_relaxation_constraints_rr(use_time_vars=true, " - "use_integer_vars=true)], use_integer_operator_counts=true))\n}}}\n"); + "{{{\noperatorcounting([delete_relaxation_constraints_rr(use_time_" + "vars=true, " + "use_integer_vars=true)], " + "use_integer_operator_counts=true))\n}}}\n"); } }; diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.h b/src/search/operator_counting/delete_relaxation_constraints_rr.h index 4619cc8b50..c40362e82b 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.h +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.h @@ -21,43 +21,28 @@ using LPConstraints = named_vector::NamedVector; using LPVariables = named_vector::NamedVector; class DeleteRelaxationConstraintsRR : public ConstraintGenerator { - bool use_time_vars; - bool use_integer_vars; - - /* [U_o] Is op part of the relaxed plan? - Binary, indexed with op.id */ - std::vector lp_var_id_op_used; - - /* [R_f] Is fact reached by the relaxed plan? - Binary, indexed with var.id, value */ - std::vector> lp_var_id_fact_reached; + /* + A causal partial function f maps a fact to one of its achieving operators. + */ - /* [F_{o,f}] Is o the first achiever of fact in the relaxed plan? - Binary, indexed with op.id, var.id, value */ - std::vector>> lp_var_id_first_achiever; + /* + [f_p] Is f defined for fact p? + Binary, indexed with var.id, value */ + std::vector> lp_var_id_f_defined; - /* [T_o] At what time is o used first? - {0, ..., |O|}, indexed with op.id */ - std::vector lp_var_id_op_time; + /* + [f_{p,a}] Does f map fact p to operator a? + Binary, maps to LP variable index */ + std::unordered_map, int> lp_var_id_f_maps_to; - /* [T_f] At what time is first achieved? - {0, ..., |O|}, indexed with var.id, value */ - std::vector> lp_var_id_fact_time; - - /* Indices of constraints that change in every state - Indexed with var.id, value */ - std::vector> constraint_ids; - - /* The state that is currently used for setting the bounds. Remembering - this makes it faster to unset the bounds when the state changes. */ - std::vector last_state; + // TODO: Rework these. + bool use_time_vars; + bool use_integer_vars; - int get_var_op_used(const OperatorProxy &op); - int get_var_fact_reached(FactPair f); - int get_var_first_achiever(const OperatorProxy &op, FactPair f); - int get_var_op_time(const OperatorProxy &op); - int get_var_fact_time(FactPair f); - int get_constraint_id(FactPair f); + bool is_in_effect(FactPair f, const OperatorProxy &op); + bool is_in_precondition(FactPair f, const OperatorProxy &op); + int get_var_f_defined(FactPair f); + int get_var_f_maps_to(FactPair f, const OperatorProxy &op); void create_auxiliary_variables( const TaskProxy &task_proxy, LPVariables &variables); From e0295047cd8174e808360a75dfc52fee31d855b3 Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Thu, 1 Feb 2024 18:52:58 +0100 Subject: [PATCH 04/30] [issue1134] Improve constraints 2-5 and add first implementation of update function. --- driver/aliases.py | 9 +++- src/search/CMakeLists.txt | 1 + .../delete_relaxation_constraints_rr.cc | 43 +++++++++++-------- .../delete_relaxation_constraints_rr.h | 27 +++++++++--- src/search/utils/hash.h | 7 ++- 5 files changed, 59 insertions(+), 28 deletions(-) diff --git a/driver/aliases.py b/driver/aliases.py index d7b474d4ab..53f3b7eac5 100644 --- a/driver/aliases.py +++ b/driver/aliases.py @@ -141,9 +141,14 @@ def _get_lama(pref): ALIASES["seq-opt-lmcut"] = [ "--search", "astar(lmcut())"] -ALIASES["issue1134-1"] = [ +ALIASES["issue1134-if"] = [ "--search", - "astar(operatorcounting([delete_relaxation_constraints(use_time_vars=true, use_integer_vars=true)], use_integer_operator_counts=false, lpsolver=cplex, verbosity=normal, transform=no_transform(), cache_estimates=true))" + "astar(operatorcounting([delete_relaxation_constraints(use_time_vars=true, use_integer_vars=true)], use_integer_operator_counts=true, lpsolver=cplex, verbosity=normal, transform=no_transform(), cache_estimates=true))" +] # TODO issue1134 remove + +ALIASES["issue1134-rr"] = [ + "--search", + "astar(operatorcounting([delete_relaxation_constraints_rr(use_time_vars=true, use_integer_vars=true)], use_integer_operator_counts=true, lpsolver=cplex, verbosity=normal, transform=no_transform(), cache_estimates=true))" ] # TODO issue1134 remove PORTFOLIOS = {} diff --git a/src/search/CMakeLists.txt b/src/search/CMakeLists.txt index 49b7569e55..8347c08b7b 100644 --- a/src/search/CMakeLists.txt +++ b/src/search/CMakeLists.txt @@ -857,6 +857,7 @@ create_fast_downward_library( SOURCES operator_counting/constraint_generator operator_counting/delete_relaxation_constraints_if + operator_counting/delete_relaxation_constraints_rr operator_counting/lm_cut_constraints operator_counting/operator_counting_heuristic operator_counting/pho_constraints diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 212f4b05ff..78fcad8f94 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -33,6 +33,10 @@ int DeleteRelaxationConstraintsRR::get_var_f_maps_to(FactPair f, return lp_var_id_f_maps_to.at(make_tuple(f.var, f.value, op.get_id())); } +int DeleteRelaxationConstraintsRR::get_constraint_id(FactPair f) { + return lp_con_id_f_defined[f.var][f.value]; +} + bool DeleteRelaxationConstraintsRR::is_in_effect(FactPair f, const OperatorProxy &op) { for (EffectProxy eff : op.get_effects()) { @@ -56,7 +60,6 @@ bool DeleteRelaxationConstraintsRR::is_in_precondition( void DeleteRelaxationConstraintsRR::create_auxiliary_variables( const TaskProxy &task_proxy, LPVariables &variables) { OperatorsProxy ops = task_proxy.get_operators(); - int num_ops = ops.size(); VariablesProxy vars = task_proxy.get_variables(); int num_vars = vars.size(); @@ -89,25 +92,23 @@ void DeleteRelaxationConstraintsRR::create_constraints( OperatorsProxy ops = task_proxy.get_operators(); VariablesProxy vars = task_proxy.get_variables(); - /* - f must map a proposition to at most one operator. - Constraint (2) in paper. - */ + // Constraint (2) in paper. + lp_con_id_f_defined.resize(vars.size()); for (VariableProxy var_p : vars) { + lp_con_id_f_defined[var_p.get_id()].resize(var_p.get_domain_size()); for (int value_p = 0; value_p < var_p.get_domain_size(); ++value_p) { + lp_con_id_f_defined[var_p.get_id()][value_p] = constraints.size(); constraints.emplace_back(0, 0); FactPair fact_p(var_p.get_id(), value_p); - constraints.back().insert(get_var_f_defined(fact_p), -1); + constraints.back().insert(get_var_f_defined(fact_p), 1); for (OperatorProxy op : ops) { if (is_in_effect(fact_p, op)) - constraints.back().insert(get_var_f_maps_to(fact_p, op), 1); + constraints.back().insert(get_var_f_maps_to(fact_p, op), -1); } } } - /* - Constraint (3) in paper. - */ + // Constraint (3) in paper. for (VariableProxy var_p : vars) { for (int value_p = 0; value_p < var_p.get_domain_size(); ++value_p) { FactPair fact_p(var_p.get_id(), value_p); @@ -115,6 +116,8 @@ void DeleteRelaxationConstraintsRR::create_constraints( for (int value_q = 0; value_q < var_q.get_domain_size(); ++value_q) { FactPair fact_q(var_q.get_id(), value_q); + if (fact_q != fact_p) + break; constraints.emplace_back(0, 1); constraints.back().insert(get_var_f_defined(fact_q), 1); for (OperatorProxy op : ops) { @@ -129,16 +132,12 @@ void DeleteRelaxationConstraintsRR::create_constraints( } } - /* - Constraint (4) in paper. - */ + // Constraint (4) in paper. for (FactProxy goal : task_proxy.get_goals()) { variables[get_var_f_defined(goal.get_pair())].lower_bound = 1; } - /* - Constraint (5) in paper. - */ + // Constraint (5) in paper. for (OperatorProxy op : ops) { for (EffectProxy eff : op.get_effects()) { FactPair fact_p = eff.get_fact().get_pair(); @@ -147,6 +146,8 @@ void DeleteRelaxationConstraintsRR::create_constraints( constraints.back().insert(op.get_id(), 1); } } + + // TODO: Implement Constraints (6)-(8). } void DeleteRelaxationConstraintsRR::initialize_constraints( @@ -159,14 +160,18 @@ void DeleteRelaxationConstraintsRR::initialize_constraints( bool DeleteRelaxationConstraintsRR::update_constraints( const State &state, lp::LPSolver &lp_solver) { // Unset old bounds. + int con_id; for (FactPair f : last_state) { - lp_solver.set_constraint_lower_bound(get_constraint_id(f), 0); + con_id = get_constraint_id(f); + lp_solver.set_constraint_lower_bound(con_id, 0); + lp_solver.set_constraint_upper_bound(con_id, 0); } last_state.clear(); // Set new bounds. for (FactProxy f : state) { - lp_solver.set_constraint_lower_bound(get_constraint_id(f.get_pair()), - -1); + con_id = get_constraint_id(f.get_pair()); + lp_solver.set_constraint_lower_bound(con_id, 1); + lp_solver.set_constraint_upper_bound(con_id, 1); last_state.push_back(f.get_pair()); } return false; diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.h b/src/search/operator_counting/delete_relaxation_constraints_rr.h index c40362e82b..3028115fa6 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.h +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.h @@ -4,6 +4,7 @@ #include "constraint_generator.h" #include "../task_proxy.h" +#include "../utils/hash.h" #include @@ -21,6 +22,10 @@ using LPConstraints = named_vector::NamedVector; using LPVariables = named_vector::NamedVector; class DeleteRelaxationConstraintsRR : public ConstraintGenerator { + // TODO: Rework these. + bool use_time_vars; + bool use_integer_vars; + /* A causal partial function f maps a fact to one of its achieving operators. */ @@ -33,16 +38,26 @@ class DeleteRelaxationConstraintsRR : public ConstraintGenerator { /* [f_{p,a}] Does f map fact p to operator a? Binary, maps to LP variable index */ - std::unordered_map, int> lp_var_id_f_maps_to; + //std::unordered_map, int> lp_var_id_f_maps_to; + utils::HashMap, int> lp_var_id_f_maps_to; + + /* + Store constraint IDs of Constraints (2) in the paper. We need to + reference them when updating constraints for a given state. They are + indexed by the fact p. + */ + std::vector> lp_con_id_f_defined; + + /* The state that is currently used for setting the bounds. Remembering + this makes it faster to unset the bounds when the state changes. */ + std::vector last_state; - // TODO: Rework these. - bool use_time_vars; - bool use_integer_vars; - bool is_in_effect(FactPair f, const OperatorProxy &op); - bool is_in_precondition(FactPair f, const OperatorProxy &op); int get_var_f_defined(FactPair f); int get_var_f_maps_to(FactPair f, const OperatorProxy &op); + int get_constraint_id(FactPair f); + bool is_in_effect(FactPair f, const OperatorProxy &op); + bool is_in_precondition(FactPair f, const OperatorProxy &op); void create_auxiliary_variables( const TaskProxy &task_proxy, LPVariables &variables); diff --git a/src/search/utils/hash.h b/src/search/utils/hash.h index db13437ad3..bc755d7558 100644 --- a/src/search/utils/hash.h +++ b/src/search/utils/hash.h @@ -26,7 +26,7 @@ namespace utils { that are "fed" to the main hashing function (implemented in class HashState) one by one. This allows a compositional approach to hashing. For example, the code for a pair p is the concatenation of - code(x.first) and code(x.second). + code(p.first) and code(p.second). A simpler compositional approach to hashing would first hash the components of an object and then combine the hash values, and this @@ -258,6 +258,11 @@ void feed(HashState &hash_state, const std::vector &vec) { } } +template +void feed(HashState &hash_state, const std::tuple &t) { + std::apply([&](auto &&... element) {((feed(hash_state, element)), ...);}, t); +} + /* Public hash functions. From b2cfc258c9cc765295d28cb4d8180b043417a772 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Thu, 1 Feb 2024 23:42:07 +0100 Subject: [PATCH 05/30] untested version of vertex elimination graph --- .../delete_relaxation_constraints_rr.cc | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 78fcad8f94..606dc3a614 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -2,14 +2,165 @@ #include "../lp/lp_solver.h" #include "../plugins/plugin.h" +#include "../algorithms/priority_queues.h" #include "../task_proxy.h" #include "../utils/markup.h" #include +#include +#include using namespace std; namespace operator_counting { + +class VEGraph { + struct Node { + vector predecessors; + vector successors; + bool is_eliminated = false; + int in_degree; + }; + + /* + Vertex Elimination Graphs have one node per fact. We index them by + variable and value. + */ + vector> nodes; + vector> delta; + priority_queues::AdaptiveQueue elimination_queue; + + Node &get_node(FactPair fact) { + return nodes[fact.var][fact.value]; + } + + const Node &get_node(FactPair fact) const { + return nodes[fact.var][fact.value]; + } + + void add_edge(FactPair from_fact, FactPair to_fact) { + get_node(from_fact).successors.push_back(to_fact); + get_node(to_fact).predecessors.push_back(from_fact); + } + + void push_fact(FactPair fact) { + Node &node = get_node(fact); + if (node.is_eliminated) { + return; + } + int in_degree = 0; + for (FactPair predecessor : node.predecessors) { + if (!get_node(predecessor).is_eliminated) { + ++in_degree; + } + } + node.in_degree = in_degree; + elimination_queue.push(in_degree, fact); + } + + optional pop_fact() { + while (!elimination_queue.empty()) { + const auto[key, fact] = elimination_queue.pop(); + Node &node = get_node(fact); + if (node.in_degree == key) { + return fact; + } + } + return nullopt; + } + + void eliminate(FactPair fact) { + Node &node = get_node(fact); + /* + When eliminating the given fact from the graph, we add shorcut edges + from all its (non-eliminated) predecessors, to all its + (non-eliminated) successors. + */ + for (FactPair predecessor : node.predecessors) { + if (get_node(predecessor).is_eliminated) { + continue; + } + for (FactPair successor : node.successors) { + if (get_node(successor).is_eliminated) { + continue; + } + if (successor != predecessor) { + add_edge(predecessor, successor); + delta.push_back(make_tuple(predecessor, fact, successor)); + } + } + } + node.is_eliminated = true; + + /* + The elimination can affect the priority queue which uses the number of + incoming edges from non-eliminated nodes as a key. However, this can + only change for successors of 'fact'. We add them back into the queue + with updated keys and lazily filter out the outdated values. + */ + for (FactPair successor : node.successors) { + if (!get_node(successor).is_eliminated) { + push_fact(successor); + } + } + + } + + void initialize_queue() { + int num_vars = nodes.size(); + for (int var = 0; var < num_vars; ++var) { + int num_values = nodes[var].size(); + for (int val = 0; val < num_values; ++val) { + push_fact(FactPair(var, val)); + } + } + } +public: + VEGraph(const TaskProxy &task_proxy) { + nodes.resize(task_proxy.get_variables().size()); + for (VariableProxy var: task_proxy.get_variables()) { + nodes[var.get_id()].resize(var.get_domain_size()); + } + for (OperatorProxy op : task_proxy.get_operators()) { + for (FactProxy pre_proxy : op.get_preconditions()) { + FactPair pre = pre_proxy.get_pair(); + for (EffectProxy eff_proxy : op.get_effects()) { + FactPair eff = eff_proxy.get_fact().get_pair(); + if (pre != eff) { + add_edge(pre, eff); + } + } + } + } + } + + void run() { + initialize_queue(); + while (optional fact = pop_fact()) { + eliminate(*fact); + } + } + + const vector> &get_delta() const { + return delta; + } + + vector> copy_edges() const { + vector> edges; + int num_vars = nodes.size(); + for (int var = 0; var < num_vars; ++var) { + int num_values = nodes[var].size(); + for (int val = 0; val < num_values; ++val) { + FactPair fact(var, val); + for (FactPair succ : get_node(fact).successors) { + edges.emplace_back(fact, succ); + } + } + } + return edges; + } +}; + static void add_lp_variables(int count, LPVariables &variables, vector &indices, double lower, double upper, double objective, bool is_integer) { From bdd4cbc7d54c0981307398f722f4731d2b151304 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Thu, 1 Feb 2024 23:47:51 +0100 Subject: [PATCH 06/30] missing explicit --- .../operator_counting/delete_relaxation_constraints_rr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 606dc3a614..7d5afc2236 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -116,7 +116,7 @@ class VEGraph { } } public: - VEGraph(const TaskProxy &task_proxy) { + explicit VEGraph(const TaskProxy &task_proxy) { nodes.resize(task_proxy.get_variables().size()); for (VariableProxy var: task_proxy.get_variables()) { nodes[var.get_id()].resize(var.get_domain_size()); From 451b4bc0aa94d1f4223708ff73c85424520763e1 Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Fri, 2 Feb 2024 14:19:13 +0100 Subject: [PATCH 07/30] [issue1134] Untested version of constraints 6-8. --- .../delete_relaxation_constraints_rr.cc | 86 +++++++++++++++++-- .../delete_relaxation_constraints_rr.h | 7 +- 2 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 7d5afc2236..d453e604db 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -1,5 +1,6 @@ #include "delete_relaxation_constraints_rr.h" +#include "../algorithms/priority_queues.h" #include "../lp/lp_solver.h" #include "../plugins/plugin.h" #include "../algorithms/priority_queues.h" @@ -60,7 +61,7 @@ class VEGraph { optional pop_fact() { while (!elimination_queue.empty()) { - const auto[key, fact] = elimination_queue.pop(); + const auto [key, fact] = elimination_queue.pop(); Node &node = get_node(fact); if (node.in_degree == key) { return fact; @@ -103,7 +104,6 @@ class VEGraph { push_fact(successor); } } - } void initialize_queue() { @@ -115,10 +115,11 @@ class VEGraph { } } } + public: explicit VEGraph(const TaskProxy &task_proxy) { nodes.resize(task_proxy.get_variables().size()); - for (VariableProxy var: task_proxy.get_variables()) { + for (VariableProxy var : task_proxy.get_variables()) { nodes[var.get_id()].resize(var.get_domain_size()); } for (OperatorProxy op : task_proxy.get_operators()) { @@ -209,7 +210,7 @@ bool DeleteRelaxationConstraintsRR::is_in_precondition( } void DeleteRelaxationConstraintsRR::create_auxiliary_variables( - const TaskProxy &task_proxy, LPVariables &variables) { + const TaskProxy &task_proxy, LPVariables &variables, VEGraph &ve_graph) { OperatorsProxy ops = task_proxy.get_operators(); VariablesProxy vars = task_proxy.get_variables(); int num_vars = vars.size(); @@ -233,10 +234,15 @@ void DeleteRelaxationConstraintsRR::create_auxiliary_variables( } } } + + for (pair edge : ve_graph.copy_edges()) { + lp_var_id_edge.emplace(make_pair(edge, variables.size())); + variables.emplace_back(0, 1, 0, use_integer_vars); + } } void DeleteRelaxationConstraintsRR::create_constraints( - const TaskProxy &task_proxy, lp::LinearProgram &lp) { + const TaskProxy &task_proxy, lp::LinearProgram &lp, VEGraph &ve_graph) { LPVariables &variables = lp.get_variables(); LPConstraints &constraints = lp.get_constraints(); double infinity = lp.get_infinity(); @@ -254,7 +260,8 @@ void DeleteRelaxationConstraintsRR::create_constraints( constraints.back().insert(get_var_f_defined(fact_p), 1); for (OperatorProxy op : ops) { if (is_in_effect(fact_p, op)) - constraints.back().insert(get_var_f_maps_to(fact_p, op), -1); + constraints.back().insert(get_var_f_maps_to(fact_p, op), + -1); } } } @@ -298,14 +305,75 @@ void DeleteRelaxationConstraintsRR::create_constraints( } } - // TODO: Implement Constraints (6)-(8). + // Constraint (6) in paper. + for (OperatorProxy op : ops) { + for (FactProxy pre_proxy : op.get_preconditions()) { + FactPair pre = pre_proxy.get_pair(); + for (EffectProxy eff_proxy : op.get_effects()) { + FactPair eff = eff_proxy.get_fact().get_pair(); + constraints.emplace_back(0, infinity); + constraints.back().insert( + lp_var_id_edge.at(make_pair(pre, eff)), 1); + constraints.back().insert(get_var_f_maps_to(eff, op), -1); + } + } + } + + // Constraint (7) in paper. + /* + TODO: Consider storing the result of cop_edges in VEGraph instead of + computing it twice (here and in create_auxiliary_variables) + */ + for (pair &edge : ve_graph.copy_edges()) { + auto reverse_edge_it = + lp_var_id_edge.find(make_pair(edge.second, edge.first)); + if (reverse_edge_it == lp_var_id_edge.end()) + continue; + int edge_id = lp_var_id_edge.at(edge); + int reverse_edge_id = reverse_edge_it->second; + constraints.emplace_back(-1, infinity); + constraints.back().insert(edge_id, -1); + constraints.back().insert(reverse_edge_id, -1); + } + + // Constraint (8) in paper. + for (const tuple &edge_triple : + ve_graph.get_delta()) { + constraints.emplace_back(-1, infinity); + constraints.back().insert( + lp_var_id_edge.at( + make_pair(get<0>(edge_triple), get<1>(edge_triple))), + -1); + constraints.back().insert( + lp_var_id_edge.at( + make_pair(get<1>(edge_triple), get<2>(edge_triple))), + -1); + constraints.back().insert( + lp_var_id_edge.at( + make_pair(get<0>(edge_triple), get<2>(edge_triple))), + 1); + } + + /* + TODO: Implement constraint (9). + - define ternary option to replace use_time_vars and use_integer_vars + - create timing variables + - create constraint + */ + /* + TODO: Make sure that objects that are only needed for constraint + generation only exist in that context and not beyond. In particular there + are lp_var_id_maps that are currently member variables, but should not be. + */ } void DeleteRelaxationConstraintsRR::initialize_constraints( const shared_ptr &task, lp::LinearProgram &lp) { TaskProxy task_proxy(*task); - create_auxiliary_variables(task_proxy, lp.get_variables()); - create_constraints(task_proxy, lp); + VEGraph ve_graph(task_proxy); + ve_graph.run(); + create_auxiliary_variables(task_proxy, lp.get_variables(), ve_graph); + create_constraints(task_proxy, lp, ve_graph); } bool DeleteRelaxationConstraintsRR::update_constraints( diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.h b/src/search/operator_counting/delete_relaxation_constraints_rr.h index 3028115fa6..78a5be1d01 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.h +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.h @@ -18,6 +18,7 @@ class Options; } namespace operator_counting { +class VEGraph; using LPConstraints = named_vector::NamedVector; using LPVariables = named_vector::NamedVector; @@ -41,6 +42,8 @@ class DeleteRelaxationConstraintsRR : public ConstraintGenerator { //std::unordered_map, int> lp_var_id_f_maps_to; utils::HashMap, int> lp_var_id_f_maps_to; + utils::HashMap, int> lp_var_id_edge; + /* Store constraint IDs of Constraints (2) in the paper. We need to reference them when updating constraints for a given state. They are @@ -60,8 +63,8 @@ class DeleteRelaxationConstraintsRR : public ConstraintGenerator { bool is_in_precondition(FactPair f, const OperatorProxy &op); void create_auxiliary_variables( - const TaskProxy &task_proxy, LPVariables &variables); - void create_constraints(const TaskProxy &task_proxy, lp::LinearProgram &lp); + const TaskProxy &task_proxy, LPVariables &variables, VEGraph &ve_graph); + void create_constraints(const TaskProxy &task_proxy, lp::LinearProgram &lp, VEGraph &ve_graph); public: explicit DeleteRelaxationConstraintsRR(const plugins::Options &opts); From f56b8e6102a4b93c7a13558cfa964923fa3ccaf7 Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Fri, 2 Feb 2024 14:22:43 +0100 Subject: [PATCH 08/30] [issue1134] Fix style. --- src/search/operator_counting/delete_relaxation_constraints_rr.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index d453e604db..9ac93b1e67 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -14,7 +14,6 @@ using namespace std; namespace operator_counting { - class VEGraph { struct Node { vector predecessors; From d3d3f6701d94c498d623e9bf90c00485b2d014d5 Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Fri, 2 Feb 2024 15:56:16 +0100 Subject: [PATCH 09/30] [issue1134] Make VEGraph parameter const. --- .../operator_counting/delete_relaxation_constraints_rr.cc | 4 ++-- .../operator_counting/delete_relaxation_constraints_rr.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 9ac93b1e67..44b1725c58 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -209,7 +209,7 @@ bool DeleteRelaxationConstraintsRR::is_in_precondition( } void DeleteRelaxationConstraintsRR::create_auxiliary_variables( - const TaskProxy &task_proxy, LPVariables &variables, VEGraph &ve_graph) { + const TaskProxy &task_proxy, LPVariables &variables, const VEGraph &ve_graph) { OperatorsProxy ops = task_proxy.get_operators(); VariablesProxy vars = task_proxy.get_variables(); int num_vars = vars.size(); @@ -241,7 +241,7 @@ void DeleteRelaxationConstraintsRR::create_auxiliary_variables( } void DeleteRelaxationConstraintsRR::create_constraints( - const TaskProxy &task_proxy, lp::LinearProgram &lp, VEGraph &ve_graph) { + const TaskProxy &task_proxy, lp::LinearProgram &lp, const VEGraph &ve_graph) { LPVariables &variables = lp.get_variables(); LPConstraints &constraints = lp.get_constraints(); double infinity = lp.get_infinity(); diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.h b/src/search/operator_counting/delete_relaxation_constraints_rr.h index 78a5be1d01..d0e95acd63 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.h +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.h @@ -63,8 +63,8 @@ class DeleteRelaxationConstraintsRR : public ConstraintGenerator { bool is_in_precondition(FactPair f, const OperatorProxy &op); void create_auxiliary_variables( - const TaskProxy &task_proxy, LPVariables &variables, VEGraph &ve_graph); - void create_constraints(const TaskProxy &task_proxy, lp::LinearProgram &lp, VEGraph &ve_graph); + const TaskProxy &task_proxy, LPVariables &variables, const VEGraph &ve_graph); + void create_constraints(const TaskProxy &task_proxy, lp::LinearProgram &lp, const VEGraph &ve_graph); public: explicit DeleteRelaxationConstraintsRR(const plugins::Options &opts); From 6c5d1e2e5906a0acea54100ae09f60446ba21347 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Fri, 2 Feb 2024 23:59:33 +0100 Subject: [PATCH 10/30] fix bug in VEGraph --- .../delete_relaxation_constraints_rr.cc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 44b1725c58..3bbf3c23ec 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -76,6 +76,7 @@ class VEGraph { from all its (non-eliminated) predecessors, to all its (non-eliminated) successors. */ + vector> new_shortcuts; for (FactPair predecessor : node.predecessors) { if (get_node(predecessor).is_eliminated) { continue; @@ -84,14 +85,21 @@ class VEGraph { if (get_node(successor).is_eliminated) { continue; } - if (successor != predecessor) { - add_edge(predecessor, successor); - delta.push_back(make_tuple(predecessor, fact, successor)); + // TODO avoid linear scan + const vector pre_succs = get_node(predecessor).successors; + if (successor != predecessor && find(pre_succs.begin(), pre_succs.end(), successor) == pre_succs.end()) { + new_shortcuts.push_back(make_tuple(predecessor, fact, successor)); } } } node.is_eliminated = true; + for (tuple shortcut : new_shortcuts) { + auto [from, _, to] = shortcut; + add_edge(from, to); + delta.push_back(shortcut); + } + /* The elimination can affect the priority queue which uses the number of incoming edges from non-eliminated nodes as a key. However, this can @@ -320,7 +328,7 @@ void DeleteRelaxationConstraintsRR::create_constraints( // Constraint (7) in paper. /* - TODO: Consider storing the result of cop_edges in VEGraph instead of + TODO: Consider storing the result of copy_edges in VEGraph instead of computing it twice (here and in create_auxiliary_variables) */ for (pair &edge : ve_graph.copy_edges()) { From a730fb5830ea656fabc193504ff493d35c19c6b7 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Sat, 3 Feb 2024 21:47:40 +0100 Subject: [PATCH 11/30] fix bug in named vector --- src/search/algorithms/named_vector.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/search/algorithms/named_vector.h b/src/search/algorithms/named_vector.h index 619053acf6..f75db7f69d 100644 --- a/src/search/algorithms/named_vector.h +++ b/src/search/algorithms/named_vector.h @@ -46,7 +46,8 @@ class NamedVector { void set_name(int index, const std::string &name) { assert(index >= 0 && index < size()); - if (index >= names.size()) { + int num_names = names.size(); + if (index >= num_names) { if (name.empty()) { // All unspecified names are empty by default. return; From 34fd6da9b604906867f97d64368c2557cd30c580 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Sat, 3 Feb 2024 21:48:07 +0100 Subject: [PATCH 12/30] fix bug in cplex interface --- src/search/lp/cplex_solver_interface.h | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/search/lp/cplex_solver_interface.h b/src/search/lp/cplex_solver_interface.h index db8d7ad64e..d6c6651068 100644 --- a/src/search/lp/cplex_solver_interface.h +++ b/src/search/lp/cplex_solver_interface.h @@ -7,6 +7,7 @@ #include "../algorithms/named_vector.h" #include "../utils/memory.h" +#include #include namespace lp { @@ -144,15 +145,26 @@ class CplexSolverInterface : public SolverInterface { template explicit CplexNameData(const named_vector::NamedVector &values) { if (values.has_names()) { - names.resize(values.size()); - indices.resize(values.size()); + names.reserve(values.size()); + indices.reserve(values.size()); int num_values = values.size(); for (int i = 0; i < num_values; ++i) { - names[i] = values.get_name(i).data(); - indices[i] = i; + const std::string &name = values.get_name(i); + if (!name.empty()) { + names.push_back(new char[name.size() + 1]); + std::strcpy(names.back(), name.data()); + indices.push_back(i); + } } } } + + ~CplexNameData() { + for (char *name : names) { + delete[] name; + } + } + int size() {return names.size();} int *get_indices() { if (indices.empty()) { From 1330d0671f76459790b83b012985a9fa2ca51f98 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Sat, 3 Feb 2024 21:48:46 +0100 Subject: [PATCH 13/30] add names for operator-counting variables --- src/search/operator_counting/operator_counting_heuristic.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/search/operator_counting/operator_counting_heuristic.cc b/src/search/operator_counting/operator_counting_heuristic.cc index 05fa85d698..a844b377bb 100644 --- a/src/search/operator_counting/operator_counting_heuristic.cc +++ b/src/search/operator_counting/operator_counting_heuristic.cc @@ -4,6 +4,7 @@ #include "../plugins/plugin.h" #include "../utils/markup.h" +#include "../utils/strings.h" #include @@ -22,6 +23,9 @@ OperatorCountingHeuristic::OperatorCountingHeuristic(const plugins::Options &opt for (OperatorProxy op : task_proxy.get_operators()) { int op_cost = op.get_cost(); variables.push_back(lp::LPVariable(0, infinity, op_cost, use_integer_operator_counts)); +#ifndef NDEBUG + variables.set_name(op.get_id(), op.get_name()); +#endif } lp::LinearProgram lp(lp::LPObjectiveSense::MINIMIZE, move(variables), {}, infinity); for (const auto &generator : constraint_generators) { From 62633d545a480af07254cf91568ab2601f264120 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Sat, 3 Feb 2024 21:50:01 +0100 Subject: [PATCH 14/30] fixes and rewrites in RR h^+ --- .../delete_relaxation_constraints_rr.cc | 228 +++++++++++++----- 1 file changed, 164 insertions(+), 64 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 3bbf3c23ec..91833e0a9b 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -39,8 +39,12 @@ class VEGraph { } void add_edge(FactPair from_fact, FactPair to_fact) { - get_node(from_fact).successors.push_back(to_fact); - get_node(to_fact).predecessors.push_back(from_fact); + // HACK avoid linear scan + const vector pre_succs = get_node(from_fact).successors; + if (find(pre_succs.begin(), pre_succs.end(), to_fact) == pre_succs.end()) { + get_node(from_fact).successors.push_back(to_fact); + get_node(to_fact).predecessors.push_back(from_fact); + } } void push_fact(FactPair fact) { @@ -229,6 +233,13 @@ void DeleteRelaxationConstraintsRR::create_auxiliary_variables( add_lp_variables(var.get_domain_size(), variables, lp_var_id_f_defined[var_id], 0, 1, 0, use_integer_vars); +#ifndef NDEBUG + for (int value = 0; value < var.get_domain_size(); ++value) { + variables.set_name(lp_var_id_f_defined[var_id][value], + "f_" + var.get_name() + "_" + + var.get_fact(value).get_name()); + } +#endif // Add f_{p,a} variables. for (int value = 0; value < var.get_domain_size(); ++value) { for (OperatorProxy op : ops) { @@ -237,6 +248,13 @@ void DeleteRelaxationConstraintsRR::create_auxiliary_variables( make_pair(make_tuple(var_id, value, op.get_id()), variables.size())); variables.emplace_back(0, 1, 0, use_integer_vars); +#ifndef NDEBUG + variables.set_name(variables.size() - 1, + "f_" + var.get_name() + "_" + + var.get_fact(value).get_name() + + "_achieved_by_" + + op.get_name()); +#endif } } } @@ -245,6 +263,20 @@ void DeleteRelaxationConstraintsRR::create_auxiliary_variables( for (pair edge : ve_graph.copy_edges()) { lp_var_id_edge.emplace(make_pair(edge, variables.size())); variables.emplace_back(0, 1, 0, use_integer_vars); +#ifndef NDEBUG + auto [f1, f2] = edge; + VariableProxy var1 = task_proxy.get_variables()[f1.var]; + int value1 = f1.value; + VariableProxy var2 = task_proxy.get_variables()[f2.var]; + int value2 = f2.value; + variables.set_name(variables.size() - 1, + "e_" + + var1.get_name() + "_" + + var1.get_fact(value1).get_name() + + "_before_" + + var2.get_name() + "_" + + var2.get_fact(value2).get_name()); +#endif } } @@ -256,77 +288,144 @@ void DeleteRelaxationConstraintsRR::create_constraints( OperatorsProxy ops = task_proxy.get_operators(); VariablesProxy vars = task_proxy.get_variables(); - // Constraint (2) in paper. + /* + Constraint (2) in paper: + + f_p = [p in s] + sum_{a in A where p in add(a)} f_{p,a} + for all facts p. + + Intuition: p is reached iff we selected exactly one achiever for it, or + if it is true in state s. + Implementation notes: we will set the state-dependent part ([p in s]) in + the update function and leave the right-hand side at 0 for now. The first + loop creates all constraints and adds the term "f_p", the second loop adds + the terms f_{p,a} to the appropriate constraints. + */ lp_con_id_f_defined.resize(vars.size()); for (VariableProxy var_p : vars) { - lp_con_id_f_defined[var_p.get_id()].resize(var_p.get_domain_size()); + int var_id_p = var_p.get_id(); + lp_con_id_f_defined[var_id_p].resize(var_p.get_domain_size()); for (int value_p = 0; value_p < var_p.get_domain_size(); ++value_p) { - lp_con_id_f_defined[var_p.get_id()][value_p] = constraints.size(); - constraints.emplace_back(0, 0); - FactPair fact_p(var_p.get_id(), value_p); - constraints.back().insert(get_var_f_defined(fact_p), 1); - for (OperatorProxy op : ops) { - if (is_in_effect(fact_p, op)) - constraints.back().insert(get_var_f_maps_to(fact_p, op), - -1); - } + lp_con_id_f_defined[var_id_p][value_p] = constraints.size(); + FactPair fact_p(var_id_p, value_p); + lp::LPConstraint constraint(0, 0); + constraint.insert(get_var_f_defined(fact_p), 1); + constraints.push_back(move(constraint)); + } + } + for (OperatorProxy op : ops) { + for (EffectProxy eff_proxy : op.get_effects()) { + FactPair eff = eff_proxy.get_fact().get_pair(); + int constraint_id = lp_con_id_f_defined[eff.var][eff.value]; + lp::LPConstraint &constraint = constraints[constraint_id]; + constraint.insert(get_var_f_maps_to(eff, op), -1); } } - // Constraint (3) in paper. - for (VariableProxy var_p : vars) { - for (int value_p = 0; value_p < var_p.get_domain_size(); ++value_p) { - FactPair fact_p(var_p.get_id(), value_p); - for (VariableProxy var_q : vars) { - for (int value_q = 0; value_q < var_q.get_domain_size(); - ++value_q) { - FactPair fact_q(var_q.get_id(), value_q); - if (fact_q != fact_p) - break; - constraints.emplace_back(0, 1); - constraints.back().insert(get_var_f_defined(fact_q), 1); - for (OperatorProxy op : ops) { - if (is_in_precondition(fact_q, op) && - is_in_effect(fact_p, op)) { - constraints.back().insert( - get_var_f_maps_to(fact_p, op), -1); - } - } + /* + Constraint (3) in paper: + + sum_{a in A where q in pre(a) and p in add(a)} f_{p,a} <= f_q + for all facts p, q. + + Intuition: If q is the precondition of an action that is selected as an + achiever for p, then q must be reached. (Also, at most one action may be + selected as the achiever of p.) + Implementation notes: if there is no action in the sum for a pair (p, q), + the constraint trivializes to 0 <= f_q which is guaranteed by the variable + bounds. We thus only loop over pairs (p, q) that occur as effect and + precondition in some action. + */ + utils::HashMap, int> constraint3_ids; + for (OperatorProxy op : ops) { + for (EffectProxy eff_proxy : op.get_effects()) { + FactPair eff = eff_proxy.get_fact().get_pair(); + for (FactProxy pre_proxy : op.get_preconditions()) { + FactPair pre = pre_proxy.get_pair(); + if (pre == eff) { + continue; } + pair key = make_pair(pre, eff); + if (!constraint3_ids.contains(key)) { + constraint3_ids[key] = constraints.size(); + lp::LPConstraint constraint(0, 1); + constraint.insert(get_var_f_defined(pre), 1); + constraints.push_back(move(constraint)); + } + int constraint_id = constraint3_ids[key]; + lp::LPConstraint &constraint = constraints[constraint_id]; + constraint.insert(get_var_f_maps_to(eff, op), -1); } } } - // Constraint (4) in paper. + /* + Constraint (4) in paper: + + f_p = 1 for all goal facts p. + + Intuition: We have to reach all goal facts. + Implementation notes: we don't add a constraint but instead raise the + lower bound of the (binary) variable to 1. A further optimization step + would be to replace all occurrences of f_p with 1 in all other constraints + but this would be more complicated. + */ for (FactProxy goal : task_proxy.get_goals()) { variables[get_var_f_defined(goal.get_pair())].lower_bound = 1; } - // Constraint (5) in paper. + /* + Constraint (5) in paper: + + f_{p,a} <= count_a for all a in A and p in add(a). + + Intuition: if we use an action as an achiever for some fact, we have to + use it at least once. + Implementation notes: the paper uses a binary variable f_a instead of the + operator-counting variable count_a. We can make this change without + problems as f_a does not occur in any other constraint. + */ for (OperatorProxy op : ops) { - for (EffectProxy eff : op.get_effects()) { - FactPair fact_p = eff.get_fact().get_pair(); - constraints.emplace_back(0, infinity); - constraints.back().insert(get_var_f_maps_to(fact_p, op), -1); - constraints.back().insert(op.get_id(), 1); + for (EffectProxy eff_proxy : op.get_effects()) { + FactPair eff = eff_proxy.get_fact().get_pair(); + lp::LPConstraint constraint(0, infinity); + constraint.insert(get_var_f_maps_to(eff, op), -1); + constraint.insert(op.get_id(), 1); + constraints.push_back(move(constraint)); } } - // Constraint (6) in paper. + /* + Constraint (6) in paper: + + f_{p_j,a} <= e_{i,j} for all a in A, p_i in pre(a), and p_j in add(a). + + Intuition: if we use a as the achiever of p_j, then its preconditions (in + particular p_i) must be achieved earlier than p_j. + */ for (OperatorProxy op : ops) { for (FactProxy pre_proxy : op.get_preconditions()) { FactPair pre = pre_proxy.get_pair(); for (EffectProxy eff_proxy : op.get_effects()) { FactPair eff = eff_proxy.get_fact().get_pair(); - constraints.emplace_back(0, infinity); - constraints.back().insert( - lp_var_id_edge.at(make_pair(pre, eff)), 1); - constraints.back().insert(get_var_f_maps_to(eff, op), -1); + lp::LPConstraint constraint(0, infinity); + constraint.insert(lp_var_id_edge.at(make_pair(pre, eff)), 1); + constraint.insert(get_var_f_maps_to(eff, op), -1); + constraints.push_back(move(constraint)); } } } - // Constraint (7) in paper. + /* + Constraint (7) in paper: + + e_{i,j} + e_{j,i} <= 1 for all (p_i, p_j) in E_Pi^*. + + Intuition: if there is a 2-cycle in the elimination graph, we have to + avoid it by either ordering i before j or vice versa. + Implementation note: the paper is not explicit about this but the + constraint only makes sense if the reverse edge is in the graph. + */ /* TODO: Consider storing the result of copy_edges in VEGraph instead of computing it twice (here and in create_auxiliary_variables) @@ -338,27 +437,28 @@ void DeleteRelaxationConstraintsRR::create_constraints( continue; int edge_id = lp_var_id_edge.at(edge); int reverse_edge_id = reverse_edge_it->second; - constraints.emplace_back(-1, infinity); - constraints.back().insert(edge_id, -1); - constraints.back().insert(reverse_edge_id, -1); + lp::LPConstraint constraint(-infinity, 1); + constraint.insert(edge_id, 1); + constraint.insert(reverse_edge_id, 1); + constraints.push_back(move(constraint)); } - // Constraint (8) in paper. - for (const tuple &edge_triple : - ve_graph.get_delta()) { - constraints.emplace_back(-1, infinity); - constraints.back().insert( - lp_var_id_edge.at( - make_pair(get<0>(edge_triple), get<1>(edge_triple))), - -1); - constraints.back().insert( - lp_var_id_edge.at( - make_pair(get<1>(edge_triple), get<2>(edge_triple))), - -1); - constraints.back().insert( - lp_var_id_edge.at( - make_pair(get<0>(edge_triple), get<2>(edge_triple))), - 1); + /* + Constraint (8) in paper: + + e_{i,j} + e_{j,k} - 1 <= e_{i,k} for all (p_i, p_j, p_k) in Delta. + + Intuition: if we introduced shortcut edge (p_i, p_k) while eliminating p_j + cycles involving the new edge represents cycles containing the edges + (p_i, p_j) and (p_j, p_k). If we don't order p_i before p_k, we also may + not have both p_i ordered before p_j, and p_j ordered before p_k. + */ + for (auto [pi, pj, pk] : ve_graph.get_delta()) { + lp::LPConstraint constraint(-infinity, 1); + constraint.insert(lp_var_id_edge.at(make_pair(pi, pj)), 1); + constraint.insert(lp_var_id_edge.at(make_pair(pj, pk)), 1); + constraint.insert(lp_var_id_edge.at(make_pair(pi, pk)), -1); + constraints.push_back(move(constraint)); } /* From 51c6d544b086a64626adbeda3b1074e16f1f147b Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Sun, 4 Feb 2024 18:58:02 +0100 Subject: [PATCH 15/30] use const_cast instead of copying the string --- src/search/algorithms/named_vector.h | 10 +++++++--- src/search/lp/cplex_solver_interface.h | 10 ++-------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/search/algorithms/named_vector.h b/src/search/algorithms/named_vector.h index f75db7f69d..82f6abe748 100644 --- a/src/search/algorithms/named_vector.h +++ b/src/search/algorithms/named_vector.h @@ -57,14 +57,18 @@ class NamedVector { names[index] = name; } - std::string get_name(int index) const { + const std::string &get_name(int index) const { assert(index >= 0 && index < size()); int num_names = names.size(); if (index < num_names) { return names[index]; } else { - // All unspecified names are empty by default. - return ""; + /* + All unspecified names are empty by default. We use a static + string here to avoid returning a reference to a local object. + */ + static std::string empty = ""; + return empty; } } diff --git a/src/search/lp/cplex_solver_interface.h b/src/search/lp/cplex_solver_interface.h index d6c6651068..5ba35cd532 100644 --- a/src/search/lp/cplex_solver_interface.h +++ b/src/search/lp/cplex_solver_interface.h @@ -151,20 +151,14 @@ class CplexSolverInterface : public SolverInterface { for (int i = 0; i < num_values; ++i) { const std::string &name = values.get_name(i); if (!name.empty()) { - names.push_back(new char[name.size() + 1]); - std::strcpy(names.back(), name.data()); + // CPLEX copies the names, so the const_cast should be fine. + names.push_back(const_cast(name.data())); indices.push_back(i); } } } } - ~CplexNameData() { - for (char *name : names) { - delete[] name; - } - } - int size() {return names.size();} int *get_indices() { if (indices.empty()) { From db189f95bd654d5418441f7f7813b88d5f87e087 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Mon, 5 Feb 2024 18:45:56 +0100 Subject: [PATCH 16/30] efficiency improvements --- .../delete_relaxation_constraints_rr.cc | 126 ++++++------------ .../delete_relaxation_constraints_rr.h | 2 - 2 files changed, 41 insertions(+), 87 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 91833e0a9b..eb0bbc51a3 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -28,6 +28,7 @@ class VEGraph { */ vector> nodes; vector> delta; + utils::HashSet> edges; priority_queues::AdaptiveQueue elimination_queue; Node &get_node(FactPair fact) { @@ -39,11 +40,11 @@ class VEGraph { } void add_edge(FactPair from_fact, FactPair to_fact) { - // HACK avoid linear scan - const vector pre_succs = get_node(from_fact).successors; - if (find(pre_succs.begin(), pre_succs.end(), to_fact) == pre_succs.end()) { + pair edge = make_pair(from_fact, to_fact); + if (!edges.count(edge)) { get_node(from_fact).successors.push_back(to_fact); get_node(to_fact).predecessors.push_back(from_fact); + edges.insert(edge); } } @@ -89,9 +90,7 @@ class VEGraph { if (get_node(successor).is_eliminated) { continue; } - // TODO avoid linear scan - const vector pre_succs = get_node(predecessor).successors; - if (successor != predecessor && find(pre_succs.begin(), pre_succs.end(), successor) == pre_succs.end()) { + if (!edges.count(make_pair(predecessor, successor))) { new_shortcuts.push_back(make_tuple(predecessor, fact, successor)); } } @@ -117,18 +116,7 @@ class VEGraph { } } - void initialize_queue() { - int num_vars = nodes.size(); - for (int var = 0; var < num_vars; ++var) { - int num_values = nodes[var].size(); - for (int val = 0; val < num_values; ++val) { - push_fact(FactPair(var, val)); - } - } - } - -public: - explicit VEGraph(const TaskProxy &task_proxy) { + void construct_task_graph(const TaskProxy &task_proxy) { nodes.resize(task_proxy.get_variables().size()); for (VariableProxy var : task_proxy.get_variables()) { nodes[var.get_id()].resize(var.get_domain_size()); @@ -146,8 +134,19 @@ class VEGraph { } } - void run() { - initialize_queue(); + void initialize_queue(const TaskProxy &task_proxy) { + for (VariableProxy var : task_proxy.get_variables()) { + int num_values = var.get_domain_size(); + for (int val = 0; val < num_values; ++val) { + push_fact(var.get_fact(val).get_pair()); + } + } + } + +public: + VEGraph(const TaskProxy &task_proxy) { + construct_task_graph(task_proxy); + initialize_queue(task_proxy); while (optional fact = pop_fact()) { eliminate(*fact); } @@ -157,18 +156,7 @@ class VEGraph { return delta; } - vector> copy_edges() const { - vector> edges; - int num_vars = nodes.size(); - for (int var = 0; var < num_vars; ++var) { - int num_values = nodes[var].size(); - for (int val = 0; val < num_values; ++val) { - FactPair fact(var, val); - for (FactPair succ : get_node(fact).successors) { - edges.emplace_back(fact, succ); - } - } - } + const utils::HashSet> &get_edges() const { return edges; } }; @@ -185,7 +173,8 @@ static void add_lp_variables(int count, LPVariables &variables, DeleteRelaxationConstraintsRR::DeleteRelaxationConstraintsRR( const plugins::Options &opts) : use_time_vars(opts.get("use_time_vars")), - use_integer_vars(opts.get("use_integer_vars")) {} + use_integer_vars(opts.get("use_integer_vars")) { +} int DeleteRelaxationConstraintsRR::get_var_f_defined(FactPair f) { return lp_var_id_f_defined[f.var][f.value]; @@ -200,26 +189,6 @@ int DeleteRelaxationConstraintsRR::get_constraint_id(FactPair f) { return lp_con_id_f_defined[f.var][f.value]; } -bool DeleteRelaxationConstraintsRR::is_in_effect(FactPair f, - const OperatorProxy &op) { - for (EffectProxy eff : op.get_effects()) { - if (eff.get_fact().get_pair() == f) { - return true; - } - } - return false; -} - -bool DeleteRelaxationConstraintsRR::is_in_precondition( - FactPair f, const OperatorProxy &op) { - for (FactProxy pre : op.get_preconditions()) { - if (pre.get_pair() == f) { - return true; - } - } - return false; -} - void DeleteRelaxationConstraintsRR::create_auxiliary_variables( const TaskProxy &task_proxy, LPVariables &variables, const VEGraph &ve_graph) { OperatorsProxy ops = task_proxy.get_operators(); @@ -240,42 +209,34 @@ void DeleteRelaxationConstraintsRR::create_auxiliary_variables( + var.get_fact(value).get_name()); } #endif - // Add f_{p,a} variables. - for (int value = 0; value < var.get_domain_size(); ++value) { - for (OperatorProxy op : ops) { - if (is_in_effect(FactPair(var_id, value), op)) { - lp_var_id_f_maps_to.emplace( - make_pair(make_tuple(var_id, value, op.get_id()), - variables.size())); - variables.emplace_back(0, 1, 0, use_integer_vars); + } + + // Add f_{p,a} variables. + for (OperatorProxy op : ops) { + for (EffectProxy eff_proxy : op.get_effects()) { + FactPair eff = eff_proxy.get_fact().get_pair(); + lp_var_id_f_maps_to.emplace( + make_pair(make_tuple(eff.var, eff.value, op.get_id()), + variables.size())); + variables.emplace_back(0, 1, 0, use_integer_vars); #ifndef NDEBUG - variables.set_name(variables.size() - 1, - "f_" + var.get_name() + "_" - + var.get_fact(value).get_name() - + "_achieved_by_" - + op.get_name()); + variables.set_name(variables.size() - 1, + "f_" + eff_proxy.get_fact().get_name() + + "_achieved_by_" + op.get_name()); #endif - } - } } } - for (pair edge : ve_graph.copy_edges()) { + for (pair edge : ve_graph.get_edges()) { lp_var_id_edge.emplace(make_pair(edge, variables.size())); variables.emplace_back(0, 1, 0, use_integer_vars); #ifndef NDEBUG auto [f1, f2] = edge; - VariableProxy var1 = task_proxy.get_variables()[f1.var]; - int value1 = f1.value; - VariableProxy var2 = task_proxy.get_variables()[f2.var]; - int value2 = f2.value; + FactProxy f1_proxy = vars[f1.var].get_fact(f1.value); + FactProxy f2_proxy = vars[f1.var].get_fact(f1.value); variables.set_name(variables.size() - 1, - "e_" - + var1.get_name() + "_" - + var1.get_fact(value1).get_name() - + "_before_" - + var2.get_name() + "_" - + var2.get_fact(value2).get_name()); + "e_" + f1_proxy.get_name() + + "_before_" + f2_proxy.get_name()); #endif } } @@ -426,11 +387,7 @@ void DeleteRelaxationConstraintsRR::create_constraints( Implementation note: the paper is not explicit about this but the constraint only makes sense if the reverse edge is in the graph. */ - /* - TODO: Consider storing the result of copy_edges in VEGraph instead of - computing it twice (here and in create_auxiliary_variables) - */ - for (pair &edge : ve_graph.copy_edges()) { + for (const pair &edge : ve_graph.get_edges()) { auto reverse_edge_it = lp_var_id_edge.find(make_pair(edge.second, edge.first)); if (reverse_edge_it == lp_var_id_edge.end()) @@ -478,7 +435,6 @@ void DeleteRelaxationConstraintsRR::initialize_constraints( const shared_ptr &task, lp::LinearProgram &lp) { TaskProxy task_proxy(*task); VEGraph ve_graph(task_proxy); - ve_graph.run(); create_auxiliary_variables(task_proxy, lp.get_variables(), ve_graph); create_constraints(task_proxy, lp, ve_graph); } diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.h b/src/search/operator_counting/delete_relaxation_constraints_rr.h index d0e95acd63..5308f6a6ce 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.h +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.h @@ -59,8 +59,6 @@ class DeleteRelaxationConstraintsRR : public ConstraintGenerator { int get_var_f_defined(FactPair f); int get_var_f_maps_to(FactPair f, const OperatorProxy &op); int get_constraint_id(FactPair f); - bool is_in_effect(FactPair f, const OperatorProxy &op); - bool is_in_precondition(FactPair f, const OperatorProxy &op); void create_auxiliary_variables( const TaskProxy &task_proxy, LPVariables &variables, const VEGraph &ve_graph); From 34e282c8dc6f04266b515f905dcfb9398380c33a Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Mon, 5 Feb 2024 22:26:52 +0100 Subject: [PATCH 17/30] only store IDs of constraints permanently. --- .../delete_relaxation_constraints_rr.cc | 143 +++++++++--------- .../delete_relaxation_constraints_rr.h | 65 +++++--- 2 files changed, 112 insertions(+), 96 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index eb0bbc51a3..e9058eb7ca 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -161,63 +161,64 @@ class VEGraph { } }; -static void add_lp_variables(int count, LPVariables &variables, - vector &indices, double lower, double upper, - double objective, bool is_integer) { - for (int i = 0; i < count; ++i) { - indices.push_back(variables.size()); - variables.emplace_back(lower, upper, objective, is_integer); - } +int DeleteRelaxationConstraintsRR::LPVariableIDs::id_of_fp(FactPair f) const { + return fp_offsets[f.var] + f.value; } -DeleteRelaxationConstraintsRR::DeleteRelaxationConstraintsRR( - const plugins::Options &opts) - : use_time_vars(opts.get("use_time_vars")), - use_integer_vars(opts.get("use_integer_vars")) { +int DeleteRelaxationConstraintsRR::LPVariableIDs::id_of_fpa( + FactPair f, const OperatorProxy &op) const { + return fpa_ids[op.get_id()].at(f); } -int DeleteRelaxationConstraintsRR::get_var_f_defined(FactPair f) { - return lp_var_id_f_defined[f.var][f.value]; +int DeleteRelaxationConstraintsRR::LPVariableIDs::id_of_e( + pair edge) const { + return e_ids.at(edge); } -int DeleteRelaxationConstraintsRR::get_var_f_maps_to(FactPair f, - const OperatorProxy &op) { - return lp_var_id_f_maps_to.at(make_tuple(f.var, f.value, op.get_id())); +int DeleteRelaxationConstraintsRR::LPVariableIDs::has_e( + pair edge) const { + return e_ids.find(edge) != e_ids.end(); +} + +DeleteRelaxationConstraintsRR::DeleteRelaxationConstraintsRR( + const plugins::Options &opts) + : use_time_vars(opts.get("use_time_vars")), + use_integer_vars(opts.get("use_integer_vars")) { } -int DeleteRelaxationConstraintsRR::get_constraint_id(FactPair f) { - return lp_con_id_f_defined[f.var][f.value]; +int DeleteRelaxationConstraintsRR::get_constraint_id(FactPair f) const { + return constraint_ids[f.var][f.value]; } -void DeleteRelaxationConstraintsRR::create_auxiliary_variables( - const TaskProxy &task_proxy, LPVariables &variables, const VEGraph &ve_graph) { +DeleteRelaxationConstraintsRR::LPVariableIDs +DeleteRelaxationConstraintsRR::create_auxiliary_variables( + const TaskProxy &task_proxy, const VEGraph &ve_graph, LPVariables &variables) const { OperatorsProxy ops = task_proxy.get_operators(); - VariablesProxy vars = task_proxy.get_variables(); - int num_vars = vars.size(); - - lp_var_id_f_defined.resize(num_vars); - for (VariableProxy var : vars) { - int var_id = var.get_id(); - // Add f_p variable. - add_lp_variables(var.get_domain_size(), variables, - lp_var_id_f_defined[var_id], 0, 1, 0, - use_integer_vars); + VariablesProxy task_variables = task_proxy.get_variables(); + int num_vars = task_variables.size(); + LPVariableIDs lp_var_ids; + + // Add f_p variables. + lp_var_ids.fp_offsets.reserve(num_vars); + for (VariableProxy var : task_variables) { + lp_var_ids.fp_offsets.push_back(variables.size()); + int num_values = var.get_domain_size(); + for (int value = 0; value < num_values; ++value) { + variables.emplace_back(0, 1, 0, use_integer_vars); #ifndef NDEBUG - for (int value = 0; value < var.get_domain_size(); ++value) { - variables.set_name(lp_var_id_f_defined[var_id][value], + variables.set_name(variables.size() -1, "f_" + var.get_name() + "_" + var.get_fact(value).get_name()); - } #endif + } } // Add f_{p,a} variables. + lp_var_ids.fpa_ids.resize(ops.size()); for (OperatorProxy op : ops) { for (EffectProxy eff_proxy : op.get_effects()) { FactPair eff = eff_proxy.get_fact().get_pair(); - lp_var_id_f_maps_to.emplace( - make_pair(make_tuple(eff.var, eff.value, op.get_id()), - variables.size())); + lp_var_ids.fpa_ids[op.get_id()][eff] = variables.size(); variables.emplace_back(0, 1, 0, use_integer_vars); #ifndef NDEBUG variables.set_name(variables.size() - 1, @@ -227,22 +228,27 @@ void DeleteRelaxationConstraintsRR::create_auxiliary_variables( } } + // Add e_{i,j} variables. for (pair edge : ve_graph.get_edges()) { - lp_var_id_edge.emplace(make_pair(edge, variables.size())); + lp_var_ids.e_ids[edge] = variables.size(); variables.emplace_back(0, 1, 0, use_integer_vars); #ifndef NDEBUG auto [f1, f2] = edge; - FactProxy f1_proxy = vars[f1.var].get_fact(f1.value); - FactProxy f2_proxy = vars[f1.var].get_fact(f1.value); + FactProxy f1_proxy = task_variables[f1.var].get_fact(f1.value); + FactProxy f2_proxy = task_variables[f1.var].get_fact(f1.value); variables.set_name(variables.size() - 1, "e_" + f1_proxy.get_name() + "_before_" + f2_proxy.get_name()); #endif } + + return lp_var_ids; } void DeleteRelaxationConstraintsRR::create_constraints( - const TaskProxy &task_proxy, lp::LinearProgram &lp, const VEGraph &ve_graph) { + const TaskProxy &task_proxy, const VEGraph &ve_graph, + const DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids, + lp::LinearProgram &lp) { LPVariables &variables = lp.get_variables(); LPConstraints &constraints = lp.get_constraints(); double infinity = lp.get_infinity(); @@ -262,24 +268,24 @@ void DeleteRelaxationConstraintsRR::create_constraints( loop creates all constraints and adds the term "f_p", the second loop adds the terms f_{p,a} to the appropriate constraints. */ - lp_con_id_f_defined.resize(vars.size()); + constraint_ids.resize(vars.size()); for (VariableProxy var_p : vars) { int var_id_p = var_p.get_id(); - lp_con_id_f_defined[var_id_p].resize(var_p.get_domain_size()); + constraint_ids[var_id_p].resize(var_p.get_domain_size()); for (int value_p = 0; value_p < var_p.get_domain_size(); ++value_p) { - lp_con_id_f_defined[var_id_p][value_p] = constraints.size(); + constraint_ids[var_id_p][value_p] = constraints.size(); FactPair fact_p(var_id_p, value_p); lp::LPConstraint constraint(0, 0); - constraint.insert(get_var_f_defined(fact_p), 1); + constraint.insert(lp_var_ids.id_of_fp(fact_p), 1); constraints.push_back(move(constraint)); } } for (OperatorProxy op : ops) { for (EffectProxy eff_proxy : op.get_effects()) { FactPair eff = eff_proxy.get_fact().get_pair(); - int constraint_id = lp_con_id_f_defined[eff.var][eff.value]; + int constraint_id = constraint_ids[eff.var][eff.value]; lp::LPConstraint &constraint = constraints[constraint_id]; - constraint.insert(get_var_f_maps_to(eff, op), -1); + constraint.insert(lp_var_ids.id_of_fpa(eff, op), -1); } } @@ -310,12 +316,12 @@ void DeleteRelaxationConstraintsRR::create_constraints( if (!constraint3_ids.contains(key)) { constraint3_ids[key] = constraints.size(); lp::LPConstraint constraint(0, 1); - constraint.insert(get_var_f_defined(pre), 1); + constraint.insert(lp_var_ids.id_of_fp(pre), 1); constraints.push_back(move(constraint)); } int constraint_id = constraint3_ids[key]; lp::LPConstraint &constraint = constraints[constraint_id]; - constraint.insert(get_var_f_maps_to(eff, op), -1); + constraint.insert(lp_var_ids.id_of_fpa(eff, op), -1); } } } @@ -332,7 +338,7 @@ void DeleteRelaxationConstraintsRR::create_constraints( but this would be more complicated. */ for (FactProxy goal : task_proxy.get_goals()) { - variables[get_var_f_defined(goal.get_pair())].lower_bound = 1; + variables[lp_var_ids.id_of_fp(goal.get_pair())].lower_bound = 1; } /* @@ -350,7 +356,7 @@ void DeleteRelaxationConstraintsRR::create_constraints( for (EffectProxy eff_proxy : op.get_effects()) { FactPair eff = eff_proxy.get_fact().get_pair(); lp::LPConstraint constraint(0, infinity); - constraint.insert(get_var_f_maps_to(eff, op), -1); + constraint.insert(lp_var_ids.id_of_fpa(eff, op), -1); constraint.insert(op.get_id(), 1); constraints.push_back(move(constraint)); } @@ -370,8 +376,8 @@ void DeleteRelaxationConstraintsRR::create_constraints( for (EffectProxy eff_proxy : op.get_effects()) { FactPair eff = eff_proxy.get_fact().get_pair(); lp::LPConstraint constraint(0, infinity); - constraint.insert(lp_var_id_edge.at(make_pair(pre, eff)), 1); - constraint.insert(get_var_f_maps_to(eff, op), -1); + constraint.insert(lp_var_ids.id_of_e(make_pair(pre, eff)), 1); + constraint.insert(lp_var_ids.id_of_fpa(eff, op), -1); constraints.push_back(move(constraint)); } } @@ -388,16 +394,13 @@ void DeleteRelaxationConstraintsRR::create_constraints( constraint only makes sense if the reverse edge is in the graph. */ for (const pair &edge : ve_graph.get_edges()) { - auto reverse_edge_it = - lp_var_id_edge.find(make_pair(edge.second, edge.first)); - if (reverse_edge_it == lp_var_id_edge.end()) - continue; - int edge_id = lp_var_id_edge.at(edge); - int reverse_edge_id = reverse_edge_it->second; - lp::LPConstraint constraint(-infinity, 1); - constraint.insert(edge_id, 1); - constraint.insert(reverse_edge_id, 1); - constraints.push_back(move(constraint)); + pair reverse_edge = make_pair(edge.second, edge.first); + if (lp_var_ids.has_e(reverse_edge)) { + lp::LPConstraint constraint(-infinity, 1); + constraint.insert(lp_var_ids.id_of_e(edge), 1); + constraint.insert(lp_var_ids.id_of_e(reverse_edge), 1); + constraints.push_back(move(constraint)); + } } /* @@ -412,9 +415,9 @@ void DeleteRelaxationConstraintsRR::create_constraints( */ for (auto [pi, pj, pk] : ve_graph.get_delta()) { lp::LPConstraint constraint(-infinity, 1); - constraint.insert(lp_var_id_edge.at(make_pair(pi, pj)), 1); - constraint.insert(lp_var_id_edge.at(make_pair(pj, pk)), 1); - constraint.insert(lp_var_id_edge.at(make_pair(pi, pk)), -1); + constraint.insert(lp_var_ids.id_of_e(make_pair(pi, pj)), 1); + constraint.insert(lp_var_ids.id_of_e(make_pair(pj, pk)), 1); + constraint.insert(lp_var_ids.id_of_e(make_pair(pi, pk)), -1); constraints.push_back(move(constraint)); } @@ -424,19 +427,15 @@ void DeleteRelaxationConstraintsRR::create_constraints( - create timing variables - create constraint */ - /* - TODO: Make sure that objects that are only needed for constraint - generation only exist in that context and not beyond. In particular there - are lp_var_id_maps that are currently member variables, but should not be. - */ } void DeleteRelaxationConstraintsRR::initialize_constraints( const shared_ptr &task, lp::LinearProgram &lp) { TaskProxy task_proxy(*task); VEGraph ve_graph(task_proxy); - create_auxiliary_variables(task_proxy, lp.get_variables(), ve_graph); - create_constraints(task_proxy, lp, ve_graph); + LPVariableIDs lp_var_ids = create_auxiliary_variables( + task_proxy, ve_graph, lp.get_variables()); + create_constraints(task_proxy, ve_graph, lp_var_ids, lp); } bool DeleteRelaxationConstraintsRR::update_constraints( diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.h b/src/search/operator_counting/delete_relaxation_constraints_rr.h index 5308f6a6ce..071fd24068 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.h +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.h @@ -7,6 +7,7 @@ #include "../utils/hash.h" #include +#include namespace lp { class LPConstraint; @@ -23,46 +24,62 @@ using LPConstraints = named_vector::NamedVector; using LPVariables = named_vector::NamedVector; class DeleteRelaxationConstraintsRR : public ConstraintGenerator { + struct LPVariableIDs { + /* + The variables f_p in the paper represent if a fact p is reached by the + relaxed plan encoded in the LP solution. We only store the offset for + each variable (LP variables for different facts of the same variable + are consecutive). + */ + std::vector fp_offsets; + + /* + The variables f_{p,a} in the paper represent if an action a is used to + achieve a fact p in the relaxed plan encoded in the LP solution. The + variable is only needed for combinations of p and a where p is an + effect of a. We store one hash map for each operator a that maps facts + p to LP variable IDs. + */ + std::vector> fpa_ids; + + /* + The variable e_{i,j} in the paper is used as part of the vertex + elimination method. It represents that fact p_i is used before fact + p_j. Not all pairs of facts have to be ordered, the vertex elimination + graph ensures that enough variables are created to exclude all cycles. + */ + utils::HashMap, int> e_ids; + + int id_of_fp(FactPair f) const; + int id_of_fpa(FactPair f, const OperatorProxy &op) const; + int id_of_e(std::pair edge) const; + int has_e(std::pair edge) const; + }; + // TODO: Rework these. bool use_time_vars; bool use_integer_vars; - /* - A causal partial function f maps a fact to one of its achieving operators. - */ - - /* - [f_p] Is f defined for fact p? - Binary, indexed with var.id, value */ - std::vector> lp_var_id_f_defined; - - /* - [f_{p,a}] Does f map fact p to operator a? - Binary, maps to LP variable index */ - //std::unordered_map, int> lp_var_id_f_maps_to; - utils::HashMap, int> lp_var_id_f_maps_to; - - utils::HashMap, int> lp_var_id_edge; - /* Store constraint IDs of Constraints (2) in the paper. We need to reference them when updating constraints for a given state. They are indexed by the fact p. */ - std::vector> lp_con_id_f_defined; + std::vector> constraint_ids; /* The state that is currently used for setting the bounds. Remembering this makes it faster to unset the bounds when the state changes. */ std::vector last_state; - int get_var_f_defined(FactPair f); - int get_var_f_maps_to(FactPair f, const OperatorProxy &op); - int get_constraint_id(FactPair f); + int get_constraint_id(FactPair f) const; - void create_auxiliary_variables( - const TaskProxy &task_proxy, LPVariables &variables, const VEGraph &ve_graph); - void create_constraints(const TaskProxy &task_proxy, lp::LinearProgram &lp, const VEGraph &ve_graph); + LPVariableIDs create_auxiliary_variables( + const TaskProxy &task_proxy, const VEGraph &ve_graph, + LPVariables &variables) const; + void create_constraints( + const TaskProxy &task_proxy, const VEGraph &ve_graph, + const LPVariableIDs &lp_var_ids, lp::LinearProgram &lp); public: explicit DeleteRelaxationConstraintsRR(const plugins::Options &opts); From 9829569058bbd4b0d3dd8f674b2cae2e10e6f3e3 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Mon, 5 Feb 2024 22:34:31 +0100 Subject: [PATCH 18/30] only store offsets to constraint IDs --- .../delete_relaxation_constraints_rr.cc | 10 ++++------ .../delete_relaxation_constraints_rr.h | 8 ++++---- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index e9058eb7ca..d4c6af2f00 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -187,7 +187,7 @@ DeleteRelaxationConstraintsRR::DeleteRelaxationConstraintsRR( } int DeleteRelaxationConstraintsRR::get_constraint_id(FactPair f) const { - return constraint_ids[f.var][f.value]; + return constraint_offsets[f.var] + f.value; } DeleteRelaxationConstraintsRR::LPVariableIDs @@ -268,12 +268,11 @@ void DeleteRelaxationConstraintsRR::create_constraints( loop creates all constraints and adds the term "f_p", the second loop adds the terms f_{p,a} to the appropriate constraints. */ - constraint_ids.resize(vars.size()); + constraint_offsets.reserve(vars.size()); for (VariableProxy var_p : vars) { int var_id_p = var_p.get_id(); - constraint_ids[var_id_p].resize(var_p.get_domain_size()); + constraint_offsets.push_back(constraints.size()); for (int value_p = 0; value_p < var_p.get_domain_size(); ++value_p) { - constraint_ids[var_id_p][value_p] = constraints.size(); FactPair fact_p(var_id_p, value_p); lp::LPConstraint constraint(0, 0); constraint.insert(lp_var_ids.id_of_fp(fact_p), 1); @@ -283,8 +282,7 @@ void DeleteRelaxationConstraintsRR::create_constraints( for (OperatorProxy op : ops) { for (EffectProxy eff_proxy : op.get_effects()) { FactPair eff = eff_proxy.get_fact().get_pair(); - int constraint_id = constraint_ids[eff.var][eff.value]; - lp::LPConstraint &constraint = constraints[constraint_id]; + lp::LPConstraint &constraint = constraints[get_constraint_id(eff)]; constraint.insert(lp_var_ids.id_of_fpa(eff, op), -1); } } diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.h b/src/search/operator_counting/delete_relaxation_constraints_rr.h index 071fd24068..52773691b5 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.h +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.h @@ -61,11 +61,11 @@ class DeleteRelaxationConstraintsRR : public ConstraintGenerator { bool use_integer_vars; /* - Store constraint IDs of Constraints (2) in the paper. We need to - reference them when updating constraints for a given state. They are - indexed by the fact p. + Store offsets to identify Constraints (2) in the paper. We need to + reference them when updating constraints for a given state. The constraint + for a fact with variable v and value d has ID (constraint_offsets[v] + d). */ - std::vector> constraint_ids; + std::vector constraint_offsets; /* The state that is currently used for setting the bounds. Remembering this makes it faster to unset the bounds when the state changes. */ From 376b0419d20dd96288aba4b4b3f3033df55f00bd Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Tue, 6 Feb 2024 00:34:00 +0100 Subject: [PATCH 19/30] first try for time label constraints --- driver/aliases.py | 2 +- .../delete_relaxation_constraints_rr.cc | 168 +++++++++++++++--- .../delete_relaxation_constraints_rr.h | 28 ++- 3 files changed, 165 insertions(+), 33 deletions(-) diff --git a/driver/aliases.py b/driver/aliases.py index 53f3b7eac5..2670a74f24 100644 --- a/driver/aliases.py +++ b/driver/aliases.py @@ -148,7 +148,7 @@ def _get_lama(pref): ALIASES["issue1134-rr"] = [ "--search", - "astar(operatorcounting([delete_relaxation_constraints_rr(use_time_vars=true, use_integer_vars=true)], use_integer_operator_counts=true, lpsolver=cplex, verbosity=normal, transform=no_transform(), cache_estimates=true))" + "astar(operatorcounting([delete_relaxation_constraints_rr(acyclicity_type=vertex_elimination, use_integer_vars=true)], use_integer_operator_counts=true, lpsolver=cplex, verbosity=normal, transform=no_transform(), cache_estimates=true))" ] # TODO issue1134 remove PORTFOLIOS = {} diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index d4c6af2f00..6e0f3b149e 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -180,9 +180,13 @@ int DeleteRelaxationConstraintsRR::LPVariableIDs::has_e( return e_ids.find(edge) != e_ids.end(); } +int DeleteRelaxationConstraintsRR::LPVariableIDs::id_of_t(FactPair f) const { + return t_offsets[f.var] + f.value; +} + DeleteRelaxationConstraintsRR::DeleteRelaxationConstraintsRR( const plugins::Options &opts) - : use_time_vars(opts.get("use_time_vars")), + : acyclicity_type(opts.get("acyclicity_type")), use_integer_vars(opts.get("use_integer_vars")) { } @@ -192,7 +196,7 @@ int DeleteRelaxationConstraintsRR::get_constraint_id(FactPair f) const { DeleteRelaxationConstraintsRR::LPVariableIDs DeleteRelaxationConstraintsRR::create_auxiliary_variables( - const TaskProxy &task_proxy, const VEGraph &ve_graph, LPVariables &variables) const { + const TaskProxy &task_proxy, LPVariables &variables) const { OperatorsProxy ops = task_proxy.get_operators(); VariablesProxy task_variables = task_proxy.get_variables(); int num_vars = task_variables.size(); @@ -227,26 +231,51 @@ DeleteRelaxationConstraintsRR::create_auxiliary_variables( #endif } } + return lp_var_ids; +} +void DeleteRelaxationConstraintsRR::create_auxiliary_variables_ve( + const TaskProxy &task_proxy, const VEGraph &ve_graph, LPVariables &variables, + DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids) const { // Add e_{i,j} variables. for (pair edge : ve_graph.get_edges()) { lp_var_ids.e_ids[edge] = variables.size(); variables.emplace_back(0, 1, 0, use_integer_vars); #ifndef NDEBUG auto [f1, f2] = edge; - FactProxy f1_proxy = task_variables[f1.var].get_fact(f1.value); - FactProxy f2_proxy = task_variables[f1.var].get_fact(f1.value); + FactProxy f1_proxy = task_proxy.get_variables()[f1.var].get_fact(f1.value); + FactProxy f2_proxy = task_proxy.get_variables()[f2.var].get_fact(f2.value); variables.set_name(variables.size() - 1, "e_" + f1_proxy.get_name() + "_before_" + f2_proxy.get_name()); #endif } +} - return lp_var_ids; +void DeleteRelaxationConstraintsRR::create_auxiliary_variables_tl( + const TaskProxy &task_proxy, LPVariables &variables, + DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids) const { + int num_facts = 0; + for (VariableProxy var : task_proxy.get_variables()) { + num_facts += var.get_domain_size(); + } + + lp_var_ids.t_offsets.resize(task_proxy.get_variables().size()); + for (VariableProxy var : task_proxy.get_variables()) { + lp_var_ids.t_offsets.push_back(variables.size()); + int num_values = var.get_domain_size(); + for (int value = 0; value < num_values; ++value) { + variables.emplace_back(1, num_facts, 0, use_integer_vars); +#ifndef NDEBUG + variables.set_name(variables.size() - 1, + "t_" + var.get_fact(value).get_name()); +#endif + } + } } void DeleteRelaxationConstraintsRR::create_constraints( - const TaskProxy &task_proxy, const VEGraph &ve_graph, + const TaskProxy &task_proxy, const DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids, lp::LinearProgram &lp) { LPVariables &variables = lp.get_variables(); @@ -359,6 +388,15 @@ void DeleteRelaxationConstraintsRR::create_constraints( constraints.push_back(move(constraint)); } } +} + +void DeleteRelaxationConstraintsRR::create_constraints_ve( + const TaskProxy &task_proxy, const VEGraph &ve_graph, + const DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids, + lp::LinearProgram &lp) { + LPConstraints &constraints = lp.get_constraints(); + double infinity = lp.get_infinity(); + OperatorsProxy ops = task_proxy.get_operators(); /* Constraint (6) in paper: @@ -418,22 +456,74 @@ void DeleteRelaxationConstraintsRR::create_constraints( constraint.insert(lp_var_ids.id_of_e(make_pair(pi, pk)), -1); constraints.push_back(move(constraint)); } +} +void DeleteRelaxationConstraintsRR::create_constraints_tl( + const TaskProxy &task_proxy, + const DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids, + lp::LinearProgram &lp) { /* - TODO: Implement constraint (9). - - define ternary option to replace use_time_vars and use_integer_vars - - create timing variables - - create constraint + Constraint (9) in paper: + + t_i - t_j + 1 <= |P|(1 - f_{p_j, a}) + for all a in A, p_i in pre(a) and p_j in add(a) + Equivalent form: + t_i - t_j + |P|f_{p_j, a} <= |P| - 1 + + Intuition: if a is used to achieve p_j and p_i is one of a's + preconditions, we have to achieve p_i before p_j. */ + LPConstraints &constraints = lp.get_constraints(); + double infinity = lp.get_infinity(); + int num_facts = 0; + for (VariableProxy var : task_proxy.get_variables()) { + num_facts += var.get_domain_size(); + } + + for (OperatorProxy op : task_proxy.get_operators()) { + for (FactProxy pre_proxy : op.get_preconditions()) { + FactPair pre = pre_proxy.get_pair(); + for (EffectProxy eff_proxy : op.get_effects()) { + FactPair eff = eff_proxy.get_fact().get_pair(); + if (pre == eff) { + // Prevail conditions are compiled away in the paper. + continue; + } + lp::LPConstraint constraint(-infinity, num_facts - 1); + constraint.insert(lp_var_ids.id_of_t(pre), 1); + constraint.insert(lp_var_ids.id_of_t(eff), -1); + constraint.insert(lp_var_ids.id_of_fpa(eff, op), num_facts); + constraints.push_back(move(constraint)); + } + } + } } void DeleteRelaxationConstraintsRR::initialize_constraints( const shared_ptr &task, lp::LinearProgram &lp) { TaskProxy task_proxy(*task); - VEGraph ve_graph(task_proxy); LPVariableIDs lp_var_ids = create_auxiliary_variables( - task_proxy, ve_graph, lp.get_variables()); - create_constraints(task_proxy, ve_graph, lp_var_ids, lp); + task_proxy, lp.get_variables()); + create_constraints(task_proxy, lp_var_ids, lp); + + switch (acyclicity_type) { + case AcyclicityType::VERTEX_ELIMINATION: { + VEGraph ve_graph(task_proxy); + create_auxiliary_variables_ve( + task_proxy, ve_graph, lp.get_variables(), lp_var_ids); + create_constraints_ve(task_proxy, ve_graph, lp_var_ids, lp); + break; + } + case AcyclicityType::TIME_LABELS: + create_auxiliary_variables_tl( + task_proxy, lp.get_variables(), lp_var_ids); + create_constraints_tl(task_proxy, lp_var_ids, lp); + break; + case AcyclicityType::NONE: + break; + default: + ABORT("Unknown AcyclicityType"); + } } bool DeleteRelaxationConstraintsRR::update_constraints( @@ -482,32 +572,52 @@ class DeleteRelaxationConstraintsRRFeature "Automated Planning and Scheduling (ICAPS2022)", "32", "71-79", "2022")); - add_option( - "use_time_vars", - "use variables for time steps. With these additional variables the " - "constraints enforce an order between the selected operators.", - "false"); + add_option( + "acyclicity_type", + "The most relaxed version of this constraint only enforces that " + "achievers of facts are picked in such a way that all goal facts " + "have an achiever, and the preconditions all achievers are either " + "true in the current state or have achievers themselves. In this " + "version, cycles in the achiever relation can occur. Such cycles " + "can be excluded with additional auxilliary varibles and " + "constraints.", + "vertex_elimination"); add_option( "use_integer_vars", "restrict auxiliary variables to integer values. These variables " - "encode whether operators are used, facts are reached, which " - "operator " - "first achieves which fact, and in which order the operators are " - "used. " - "Restricting them to integers generally improves the heuristic " - "value " - "at the cost of increased runtime.", + "encode whether facts are reached, which operator first achieves " + "which fact, and (depending on the acyclicity_type) in which order " + "the operators are used. Restricting them to integers generally " + "improves the heuristic value at the cost of increased runtime.", "false"); document_note( "Example", - "To compute the optimal delete-relaxation heuristic h^+^, use\n" - "{{{\noperatorcounting([delete_relaxation_constraints_rr(use_time_" - "vars=true, " - "use_integer_vars=true)], " + "To compute the optimal delete-relaxation heuristic h^+^, use" + "integer variables and some way of enforcing acyclicity (other " + "than \"none\"). For example\n" + "{{{\noperatorcounting([delete_relaxation_constraints_rr(" + "acyclicity_type=vertex_elimination, use_integer_vars=true)], " "use_integer_operator_counts=true))\n}}}\n"); } }; static plugins::FeaturePlugin _plugin; + +static plugins::TypedEnumPlugin _enum_plugin({ + {"time_labels", + "introduces MIP variables that encode the time at which each fact is " + "reached. Acyclicity is enforced with constraints that ensure that " + "preconditions of actions are reached before their effects."}, + {"vertex_elimination", + "introduces binary variables based on vertex elimination. These " + "variables encode that one fact has to be reached before another " + "fact. Instead of adding such variables for every pair of states, " + "they are only added for a subset sufficient to ensure acyclicity. " + "Constraints enforce that preconditions of actions are reached before " + "their effects and that the assignment encodes a valid order."}, + {"none", + "No acyclicity is enforced. The resulting heuristic is a relaxation " + "of the delete-relaxation heuristic."} + }); } diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.h b/src/search/operator_counting/delete_relaxation_constraints_rr.h index 52773691b5..bbb816cdba 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.h +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.h @@ -23,6 +23,10 @@ class VEGraph; using LPConstraints = named_vector::NamedVector; using LPVariables = named_vector::NamedVector; +enum class AcyclicityType { + TIME_LABELS, VERTEX_ELIMINATION, NONE +}; + class DeleteRelaxationConstraintsRR : public ConstraintGenerator { struct LPVariableIDs { /* @@ -50,14 +54,21 @@ class DeleteRelaxationConstraintsRR : public ConstraintGenerator { */ utils::HashMap, int> e_ids; + /* + The variable t_p in the paper is used as part of the time labels + method. It represents the time at which fact p is first made true. + We store the offsets here, analogous to fp. + */ + std::vector t_offsets; + int id_of_fp(FactPair f) const; int id_of_fpa(FactPair f, const OperatorProxy &op) const; int id_of_e(std::pair edge) const; int has_e(std::pair edge) const; + int id_of_t(FactPair f) const; }; - // TODO: Rework these. - bool use_time_vars; + AcyclicityType acyclicity_type; bool use_integer_vars; /* @@ -75,11 +86,22 @@ class DeleteRelaxationConstraintsRR : public ConstraintGenerator { int get_constraint_id(FactPair f) const; LPVariableIDs create_auxiliary_variables( + const TaskProxy &task_proxy, LPVariables &variables) const; + void create_auxiliary_variables_ve( const TaskProxy &task_proxy, const VEGraph &ve_graph, - LPVariables &variables) const; + LPVariables &variables, LPVariableIDs &lp_var_ids) const; + void create_auxiliary_variables_tl( + const TaskProxy &task_proxy, LPVariables &variables, + LPVariableIDs &lp_var_ids) const; void create_constraints( + const TaskProxy &task_proxy, const LPVariableIDs &lp_var_ids, + lp::LinearProgram &lp); + void create_constraints_ve( const TaskProxy &task_proxy, const VEGraph &ve_graph, const LPVariableIDs &lp_var_ids, lp::LinearProgram &lp); + void create_constraints_tl( + const TaskProxy &task_proxy, const LPVariableIDs &lp_var_ids, + lp::LinearProgram &lp); public: explicit DeleteRelaxationConstraintsRR(const plugins::Options &opts); From b5c457e066e3422a6e52c50d8992395856217dc7 Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Tue, 6 Feb 2024 11:43:34 +0100 Subject: [PATCH 20/30] [issue1134] Fix time label ID bug. --- .../operator_counting/delete_relaxation_constraints_rr.cc | 4 ++-- src/search/operator_counting/operator_counting_heuristic.cc | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 6e0f3b149e..7b527dcbb8 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -210,7 +210,7 @@ DeleteRelaxationConstraintsRR::create_auxiliary_variables( for (int value = 0; value < num_values; ++value) { variables.emplace_back(0, 1, 0, use_integer_vars); #ifndef NDEBUG - variables.set_name(variables.size() -1, + variables.set_name(variables.size() - 1, "f_" + var.get_name() + "_" + var.get_fact(value).get_name()); #endif @@ -262,7 +262,7 @@ void DeleteRelaxationConstraintsRR::create_auxiliary_variables_tl( lp_var_ids.t_offsets.resize(task_proxy.get_variables().size()); for (VariableProxy var : task_proxy.get_variables()) { - lp_var_ids.t_offsets.push_back(variables.size()); + lp_var_ids.t_offsets[var.get_id()] = variables.size(); int num_values = var.get_domain_size(); for (int value = 0; value < num_values; ++value) { variables.emplace_back(1, num_facts, 0, use_integer_vars); diff --git a/src/search/operator_counting/operator_counting_heuristic.cc b/src/search/operator_counting/operator_counting_heuristic.cc index a844b377bb..c76c3a1431 100644 --- a/src/search/operator_counting/operator_counting_heuristic.cc +++ b/src/search/operator_counting/operator_counting_heuristic.cc @@ -48,6 +48,7 @@ int OperatorCountingHeuristic::compute_heuristic(const State &ancestor_state) { } } int result; + lp_solver.write_lp("model.lp"); lp_solver.solve(); if (lp_solver.has_optimal_solution()) { double epsilon = 0.01; From 8cf704342416841db89a23e7bd2fa8bdfb889411 Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Tue, 6 Feb 2024 14:34:08 +0100 Subject: [PATCH 21/30] [issue1134] Remove debug output. --- src/search/operator_counting/operator_counting_heuristic.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/search/operator_counting/operator_counting_heuristic.cc b/src/search/operator_counting/operator_counting_heuristic.cc index c76c3a1431..a844b377bb 100644 --- a/src/search/operator_counting/operator_counting_heuristic.cc +++ b/src/search/operator_counting/operator_counting_heuristic.cc @@ -48,7 +48,6 @@ int OperatorCountingHeuristic::compute_heuristic(const State &ancestor_state) { } } int result; - lp_solver.write_lp("model.lp"); lp_solver.solve(); if (lp_solver.has_optimal_solution()) { double epsilon = 0.01; From 5596fbe33afba94818395cfc25ace093b076eac0 Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Tue, 6 Feb 2024 14:44:15 +0100 Subject: [PATCH 22/30] [issue1134] Fix style. --- .../delete_relaxation_constraints_rr.cc | 11 ++++++++--- .../delete_relaxation_constraints_rr.h | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 7b527dcbb8..b6df81c48b 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -41,7 +41,7 @@ class VEGraph { void add_edge(FactPair from_fact, FactPair to_fact) { pair edge = make_pair(from_fact, to_fact); - if (!edges.count(edge)) { + if (!edges.count(edge)) { get_node(from_fact).successors.push_back(to_fact); get_node(to_fact).predecessors.push_back(from_fact); edges.insert(edge); @@ -236,7 +236,7 @@ DeleteRelaxationConstraintsRR::create_auxiliary_variables( void DeleteRelaxationConstraintsRR::create_auxiliary_variables_ve( const TaskProxy &task_proxy, const VEGraph &ve_graph, LPVariables &variables, - DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids) const { + DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids) const { // Add e_{i,j} variables. for (pair edge : ve_graph.get_edges()) { lp_var_ids.e_ids[edge] = variables.size(); @@ -507,7 +507,8 @@ void DeleteRelaxationConstraintsRR::initialize_constraints( create_constraints(task_proxy, lp_var_ids, lp); switch (acyclicity_type) { - case AcyclicityType::VERTEX_ELIMINATION: { + case AcyclicityType::VERTEX_ELIMINATION: + { VEGraph ve_graph(task_proxy); create_auxiliary_variables_ve( task_proxy, ve_graph, lp.get_variables(), lp_var_ids); @@ -515,12 +516,16 @@ void DeleteRelaxationConstraintsRR::initialize_constraints( break; } case AcyclicityType::TIME_LABELS: + { create_auxiliary_variables_tl( task_proxy, lp.get_variables(), lp_var_ids); create_constraints_tl(task_proxy, lp_var_ids, lp); break; + } case AcyclicityType::NONE: + { break; + } default: ABORT("Unknown AcyclicityType"); } diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.h b/src/search/operator_counting/delete_relaxation_constraints_rr.h index bbb816cdba..4af9bce7d4 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.h +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.h @@ -94,7 +94,7 @@ class DeleteRelaxationConstraintsRR : public ConstraintGenerator { const TaskProxy &task_proxy, LPVariables &variables, LPVariableIDs &lp_var_ids) const; void create_constraints( - const TaskProxy &task_proxy, const LPVariableIDs &lp_var_ids, + const TaskProxy &task_proxy, const LPVariableIDs &lp_var_ids, lp::LinearProgram &lp); void create_constraints_ve( const TaskProxy &task_proxy, const VEGraph &ve_graph, From ff9e91c86051519b64696c210c45a960e9e22ecb Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Tue, 6 Feb 2024 15:23:22 +0100 Subject: [PATCH 23/30] [issue1134] Remove redundant string initialization and make variable explicitily unused. --- src/search/algorithms/named_vector.h | 2 +- .../operator_counting/delete_relaxation_constraints_rr.cc | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/search/algorithms/named_vector.h b/src/search/algorithms/named_vector.h index 82f6abe748..66814dde21 100644 --- a/src/search/algorithms/named_vector.h +++ b/src/search/algorithms/named_vector.h @@ -67,7 +67,7 @@ class NamedVector { All unspecified names are empty by default. We use a static string here to avoid returning a reference to a local object. */ - static std::string empty = ""; + static std::string empty; return empty; } } diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index b6df81c48b..3225a0a80d 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -237,6 +237,7 @@ DeleteRelaxationConstraintsRR::create_auxiliary_variables( void DeleteRelaxationConstraintsRR::create_auxiliary_variables_ve( const TaskProxy &task_proxy, const VEGraph &ve_graph, LPVariables &variables, DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids) const { + utils::unused_variable(task_proxy); // Add e_{i,j} variables. for (pair edge : ve_graph.get_edges()) { lp_var_ids.e_ids[edge] = variables.size(); From a1a343790f9da47e895655c5783673a4624ea02c Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Tue, 6 Feb 2024 15:54:58 +0100 Subject: [PATCH 24/30] [issue1134] Fix style. --- .../operator_counting/delete_relaxation_constraints_rr.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index 3225a0a80d..a5e256b9d5 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -331,7 +331,7 @@ void DeleteRelaxationConstraintsRR::create_constraints( bounds. We thus only loop over pairs (p, q) that occur as effect and precondition in some action. */ - utils::HashMap, int> constraint3_ids; + utils::HashMap, int> constraint3_ids; for (OperatorProxy op : ops) { for (EffectProxy eff_proxy : op.get_effects()) { FactPair eff = eff_proxy.get_fact().get_pair(); From 94c445745a1c9e606cf19ea2f2d883ca9af87e71 Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Tue, 6 Feb 2024 15:56:04 +0100 Subject: [PATCH 25/30] [issue1134] Remove testing aliases. --- driver/aliases.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/driver/aliases.py b/driver/aliases.py index 2670a74f24..abff50529d 100644 --- a/driver/aliases.py +++ b/driver/aliases.py @@ -141,16 +141,6 @@ def _get_lama(pref): ALIASES["seq-opt-lmcut"] = [ "--search", "astar(lmcut())"] -ALIASES["issue1134-if"] = [ - "--search", - "astar(operatorcounting([delete_relaxation_constraints(use_time_vars=true, use_integer_vars=true)], use_integer_operator_counts=true, lpsolver=cplex, verbosity=normal, transform=no_transform(), cache_estimates=true))" -] # TODO issue1134 remove - -ALIASES["issue1134-rr"] = [ - "--search", - "astar(operatorcounting([delete_relaxation_constraints_rr(acyclicity_type=vertex_elimination, use_integer_vars=true)], use_integer_operator_counts=true, lpsolver=cplex, verbosity=normal, transform=no_transform(), cache_estimates=true))" -] # TODO issue1134 remove - PORTFOLIOS = {} for portfolio in os.listdir(PORTFOLIO_DIR): if portfolio == "__pycache__": From 070269720da5f60fd7cf652fb3bd464973ccdea5 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Wed, 7 Feb 2024 19:01:49 +0100 Subject: [PATCH 26/30] bugfixes --- .../delete_relaxation_constraints_rr.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_constraints_rr.cc index a5e256b9d5..517a8c3fb5 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_rr.cc @@ -27,7 +27,7 @@ class VEGraph { variable and value. */ vector> nodes; - vector> delta; + utils::HashSet> delta; utils::HashSet> edges; priority_queues::AdaptiveQueue elimination_queue; @@ -67,7 +67,7 @@ class VEGraph { while (!elimination_queue.empty()) { const auto [key, fact] = elimination_queue.pop(); Node &node = get_node(fact); - if (node.in_degree == key) { + if (node.in_degree == key && !node.is_eliminated) { return fact; } } @@ -90,7 +90,7 @@ class VEGraph { if (get_node(successor).is_eliminated) { continue; } - if (!edges.count(make_pair(predecessor, successor))) { + if (predecessor != successor) { new_shortcuts.push_back(make_tuple(predecessor, fact, successor)); } } @@ -100,7 +100,7 @@ class VEGraph { for (tuple shortcut : new_shortcuts) { auto [from, _, to] = shortcut; add_edge(from, to); - delta.push_back(shortcut); + delta.insert(shortcut); } /* @@ -152,7 +152,7 @@ class VEGraph { } } - const vector> &get_delta() const { + const utils::HashSet> &get_delta() const { return delta; } From 535155719a2372be6969cd99e217eacc939752e9 Mon Sep 17 00:00:00 2001 From: Remo Christen Date: Fri, 9 Feb 2024 17:53:17 +0100 Subject: [PATCH 27/30] [issue1134] Adapt option names and add recommendation notes to wiki. --- .../delete_relaxation_constraints_if.cc | 9 +++++++-- .../delete_relaxation_constraints_rr.cc | 12 ++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_constraints_if.cc b/src/search/operator_counting/delete_relaxation_constraints_if.cc index a44945aba7..f931f5b757 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_if.cc +++ b/src/search/operator_counting/delete_relaxation_constraints_if.cc @@ -238,7 +238,7 @@ bool DeleteRelaxationConstraintsIF::update_constraints( class DeleteRelaxationConstraintsIFFeature : public plugins::TypedFeature { public: - DeleteRelaxationConstraintsIFFeature() : TypedFeature("delete_relaxation_constraints") { + DeleteRelaxationConstraintsIFFeature() : TypedFeature("delete_relaxation_if_constraints") { document_title("Delete relaxation constraints"); document_synopsis( "Operator-counting constraints based on the delete relaxation. By " @@ -277,8 +277,13 @@ class DeleteRelaxationConstraintsIFFeature : public plugins::TypedFeature { public: DeleteRelaxationConstraintsRRFeature() - : TypedFeature("delete_relaxation_constraints_rr") { + : TypedFeature("delete_relaxation_rr_constraints") { document_title( "Delete relaxation constraints from Rankooh and Rintanen"); document_synopsis( @@ -602,9 +602,17 @@ class DeleteRelaxationConstraintsRRFeature "To compute the optimal delete-relaxation heuristic h^+^, use" "integer variables and some way of enforcing acyclicity (other " "than \"none\"). For example\n" - "{{{\noperatorcounting([delete_relaxation_constraints_rr(" + "{{{\noperatorcounting([delete_relaxation_rr_constraints(" "acyclicity_type=vertex_elimination, use_integer_vars=true)], " "use_integer_operator_counts=true))\n}}}\n"); + document_note( + "Note", + "While the delete-relaxation constraints by Imai and Fukunaga " + "(accessible via option {{{delete_relaxation_if_constraints}}}) " + "serve a similar purpose to the constraints implemented here, we " + "recommend using this formulation as it can generally be solved " + "more efficiently, in particular in case of the h^+^ " + "configuration, and some relaxations offer tighter bounds.\n"); } }; From 36d3f00c5a4add4bb82361d1f89b1c9b7be69d3f Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Tue, 2 Jul 2024 16:20:26 +0200 Subject: [PATCH 28/30] Reduce diff to main --- driver/aliases.py | 1 + 1 file changed, 1 insertion(+) diff --git a/driver/aliases.py b/driver/aliases.py index abff50529d..88dfb09ce0 100644 --- a/driver/aliases.py +++ b/driver/aliases.py @@ -141,6 +141,7 @@ def _get_lama(pref): ALIASES["seq-opt-lmcut"] = [ "--search", "astar(lmcut())"] + PORTFOLIOS = {} for portfolio in os.listdir(PORTFOLIO_DIR): if portfolio == "__pycache__": From e9911f4c997bd8898c00672844093de7b1c0a9e5 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Tue, 2 Jul 2024 17:15:25 +0200 Subject: [PATCH 29/30] Rename files to match names of commandline options --- src/search/CMakeLists.txt | 4 ++-- ..._constraints_if.cc => delete_relaxation_if_constraints.cc} | 2 +- ...on_constraints_if.h => delete_relaxation_if_constraints.h} | 0 ..._constraints_rr.cc => delete_relaxation_rr_constraints.cc} | 2 +- ...on_constraints_rr.h => delete_relaxation_rr_constraints.h} | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename src/search/operator_counting/{delete_relaxation_constraints_if.cc => delete_relaxation_if_constraints.cc} (99%) rename src/search/operator_counting/{delete_relaxation_constraints_if.h => delete_relaxation_if_constraints.h} (100%) rename src/search/operator_counting/{delete_relaxation_constraints_rr.cc => delete_relaxation_rr_constraints.cc} (99%) rename src/search/operator_counting/{delete_relaxation_constraints_rr.h => delete_relaxation_rr_constraints.h} (100%) diff --git a/src/search/CMakeLists.txt b/src/search/CMakeLists.txt index 8347c08b7b..7d8177ba14 100644 --- a/src/search/CMakeLists.txt +++ b/src/search/CMakeLists.txt @@ -856,8 +856,8 @@ create_fast_downward_library( HELP "Plugin containing the code for operator-counting heuristics" SOURCES operator_counting/constraint_generator - operator_counting/delete_relaxation_constraints_if - operator_counting/delete_relaxation_constraints_rr + operator_counting/delete_relaxation_if_constraints + operator_counting/delete_relaxation_rr_constraints operator_counting/lm_cut_constraints operator_counting/operator_counting_heuristic operator_counting/pho_constraints diff --git a/src/search/operator_counting/delete_relaxation_constraints_if.cc b/src/search/operator_counting/delete_relaxation_if_constraints.cc similarity index 99% rename from src/search/operator_counting/delete_relaxation_constraints_if.cc rename to src/search/operator_counting/delete_relaxation_if_constraints.cc index f931f5b757..b5564936d2 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_if.cc +++ b/src/search/operator_counting/delete_relaxation_if_constraints.cc @@ -1,4 +1,4 @@ -#include "delete_relaxation_constraints_if.h" +#include "delete_relaxation_if_constraints.h" #include "../task_proxy.h" diff --git a/src/search/operator_counting/delete_relaxation_constraints_if.h b/src/search/operator_counting/delete_relaxation_if_constraints.h similarity index 100% rename from src/search/operator_counting/delete_relaxation_constraints_if.h rename to src/search/operator_counting/delete_relaxation_if_constraints.h diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.cc b/src/search/operator_counting/delete_relaxation_rr_constraints.cc similarity index 99% rename from src/search/operator_counting/delete_relaxation_constraints_rr.cc rename to src/search/operator_counting/delete_relaxation_rr_constraints.cc index 8de8429f4d..887b6fcd13 100644 --- a/src/search/operator_counting/delete_relaxation_constraints_rr.cc +++ b/src/search/operator_counting/delete_relaxation_rr_constraints.cc @@ -1,4 +1,4 @@ -#include "delete_relaxation_constraints_rr.h" +#include "delete_relaxation_rr_constraints.h" #include "../algorithms/priority_queues.h" #include "../lp/lp_solver.h" diff --git a/src/search/operator_counting/delete_relaxation_constraints_rr.h b/src/search/operator_counting/delete_relaxation_rr_constraints.h similarity index 100% rename from src/search/operator_counting/delete_relaxation_constraints_rr.h rename to src/search/operator_counting/delete_relaxation_rr_constraints.h From 92060afaf750e208e50aa504d7c868bc65f01862 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Tue, 2 Jul 2024 17:21:18 +0200 Subject: [PATCH 30/30] Rename classes and include guards to match names of commandline options --- .../delete_relaxation_if_constraints.cc | 28 +++++------ .../delete_relaxation_if_constraints.h | 8 +-- .../delete_relaxation_rr_constraints.cc | 50 +++++++++---------- .../delete_relaxation_rr_constraints.h | 8 +-- 4 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/search/operator_counting/delete_relaxation_if_constraints.cc b/src/search/operator_counting/delete_relaxation_if_constraints.cc index b5564936d2..6890d0c2ae 100644 --- a/src/search/operator_counting/delete_relaxation_if_constraints.cc +++ b/src/search/operator_counting/delete_relaxation_if_constraints.cc @@ -21,37 +21,37 @@ static void add_lp_variables(int count, LPVariables &variables, vector &ind } -DeleteRelaxationConstraintsIF::DeleteRelaxationConstraintsIF(const plugins::Options &opts) +DeleteRelaxationIFConstraints::DeleteRelaxationIFConstraints(const plugins::Options &opts) : use_time_vars(opts.get("use_time_vars")), use_integer_vars(opts.get("use_integer_vars")) { } -int DeleteRelaxationConstraintsIF::get_var_op_used(const OperatorProxy &op) { +int DeleteRelaxationIFConstraints::get_var_op_used(const OperatorProxy &op) { return lp_var_id_op_used[op.get_id()]; } -int DeleteRelaxationConstraintsIF::get_var_fact_reached(FactPair f) { +int DeleteRelaxationIFConstraints::get_var_fact_reached(FactPair f) { return lp_var_id_fact_reached[f.var][f.value]; } -int DeleteRelaxationConstraintsIF::get_var_first_achiever( +int DeleteRelaxationIFConstraints::get_var_first_achiever( const OperatorProxy &op, FactPair f) { return lp_var_id_first_achiever[op.get_id()][f.var][f.value]; } -int DeleteRelaxationConstraintsIF::get_var_op_time(const OperatorProxy &op) { +int DeleteRelaxationIFConstraints::get_var_op_time(const OperatorProxy &op) { return lp_var_id_op_time[op.get_id()]; } -int DeleteRelaxationConstraintsIF::get_var_fact_time(FactPair f) { +int DeleteRelaxationIFConstraints::get_var_fact_time(FactPair f) { return lp_var_id_fact_time[f.var][f.value]; } -int DeleteRelaxationConstraintsIF::get_constraint_id(FactPair f) { +int DeleteRelaxationIFConstraints::get_constraint_id(FactPair f) { return constraint_ids[f.var][f.value]; } -void DeleteRelaxationConstraintsIF::create_auxiliary_variables( +void DeleteRelaxationIFConstraints::create_auxiliary_variables( const TaskProxy &task_proxy, LPVariables &variables) { OperatorsProxy ops = task_proxy.get_operators(); int num_ops = ops.size(); @@ -94,7 +94,7 @@ void DeleteRelaxationConstraintsIF::create_auxiliary_variables( } } -void DeleteRelaxationConstraintsIF::create_constraints(const TaskProxy &task_proxy, +void DeleteRelaxationIFConstraints::create_constraints(const TaskProxy &task_proxy, lp::LinearProgram &lp) { LPVariables &variables = lp.get_variables(); LPConstraints &constraints = lp.get_constraints(); @@ -213,7 +213,7 @@ void DeleteRelaxationConstraintsIF::create_constraints(const TaskProxy &task_pro } -void DeleteRelaxationConstraintsIF::initialize_constraints( +void DeleteRelaxationIFConstraints::initialize_constraints( const shared_ptr &task, lp::LinearProgram &lp) { TaskProxy task_proxy(*task); create_auxiliary_variables(task_proxy, lp.get_variables()); @@ -221,7 +221,7 @@ void DeleteRelaxationConstraintsIF::initialize_constraints( } -bool DeleteRelaxationConstraintsIF::update_constraints( +bool DeleteRelaxationIFConstraints::update_constraints( const State &state, lp::LPSolver &lp_solver) { // Unset old bounds. for (FactPair f : last_state) { @@ -236,9 +236,9 @@ bool DeleteRelaxationConstraintsIF::update_constraints( return false; } -class DeleteRelaxationConstraintsIFFeature : public plugins::TypedFeature { +class DeleteRelaxationIFConstraintsFeature : public plugins::TypedFeature { public: - DeleteRelaxationConstraintsIFFeature() : TypedFeature("delete_relaxation_if_constraints") { + DeleteRelaxationIFConstraintsFeature() : TypedFeature("delete_relaxation_if_constraints") { document_title("Delete relaxation constraints"); document_synopsis( "Operator-counting constraints based on the delete relaxation. By " @@ -287,5 +287,5 @@ class DeleteRelaxationConstraintsIFFeature : public plugins::TypedFeature _plugin; +static plugins::FeaturePlugin _plugin; } diff --git a/src/search/operator_counting/delete_relaxation_if_constraints.h b/src/search/operator_counting/delete_relaxation_if_constraints.h index b508bd0026..7adfb543e9 100644 --- a/src/search/operator_counting/delete_relaxation_if_constraints.h +++ b/src/search/operator_counting/delete_relaxation_if_constraints.h @@ -1,5 +1,5 @@ -#ifndef OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_IF_H -#define OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_IF_H +#ifndef OPERATOR_COUNTING_DELETE_RELAXATION_IF_CONSTRAINTS_H +#define OPERATOR_COUNTING_DELETE_RELAXATION_IF_CONSTRAINTS_H #include "constraint_generator.h" @@ -20,7 +20,7 @@ namespace operator_counting { using LPConstraints = named_vector::NamedVector; using LPVariables = named_vector::NamedVector; -class DeleteRelaxationConstraintsIF : public ConstraintGenerator { +class DeleteRelaxationIFConstraints : public ConstraintGenerator { bool use_time_vars; bool use_integer_vars; @@ -63,7 +63,7 @@ class DeleteRelaxationConstraintsIF : public ConstraintGenerator { const TaskProxy &task_proxy, LPVariables &variables); void create_constraints(const TaskProxy &task_proxy, lp::LinearProgram &lp); public: - explicit DeleteRelaxationConstraintsIF(const plugins::Options &opts); + explicit DeleteRelaxationIFConstraints(const plugins::Options &opts); virtual void initialize_constraints( const std::shared_ptr &task, diff --git a/src/search/operator_counting/delete_relaxation_rr_constraints.cc b/src/search/operator_counting/delete_relaxation_rr_constraints.cc index 887b6fcd13..0e305279ec 100644 --- a/src/search/operator_counting/delete_relaxation_rr_constraints.cc +++ b/src/search/operator_counting/delete_relaxation_rr_constraints.cc @@ -161,41 +161,41 @@ class VEGraph { } }; -int DeleteRelaxationConstraintsRR::LPVariableIDs::id_of_fp(FactPair f) const { +int DeleteRelaxationRRConstraints::LPVariableIDs::id_of_fp(FactPair f) const { return fp_offsets[f.var] + f.value; } -int DeleteRelaxationConstraintsRR::LPVariableIDs::id_of_fpa( +int DeleteRelaxationRRConstraints::LPVariableIDs::id_of_fpa( FactPair f, const OperatorProxy &op) const { return fpa_ids[op.get_id()].at(f); } -int DeleteRelaxationConstraintsRR::LPVariableIDs::id_of_e( +int DeleteRelaxationRRConstraints::LPVariableIDs::id_of_e( pair edge) const { return e_ids.at(edge); } -int DeleteRelaxationConstraintsRR::LPVariableIDs::has_e( +int DeleteRelaxationRRConstraints::LPVariableIDs::has_e( pair edge) const { return e_ids.find(edge) != e_ids.end(); } -int DeleteRelaxationConstraintsRR::LPVariableIDs::id_of_t(FactPair f) const { +int DeleteRelaxationRRConstraints::LPVariableIDs::id_of_t(FactPair f) const { return t_offsets[f.var] + f.value; } -DeleteRelaxationConstraintsRR::DeleteRelaxationConstraintsRR( +DeleteRelaxationRRConstraints::DeleteRelaxationRRConstraints( const plugins::Options &opts) : acyclicity_type(opts.get("acyclicity_type")), use_integer_vars(opts.get("use_integer_vars")) { } -int DeleteRelaxationConstraintsRR::get_constraint_id(FactPair f) const { +int DeleteRelaxationRRConstraints::get_constraint_id(FactPair f) const { return constraint_offsets[f.var] + f.value; } -DeleteRelaxationConstraintsRR::LPVariableIDs -DeleteRelaxationConstraintsRR::create_auxiliary_variables( +DeleteRelaxationRRConstraints::LPVariableIDs +DeleteRelaxationRRConstraints::create_auxiliary_variables( const TaskProxy &task_proxy, LPVariables &variables) const { OperatorsProxy ops = task_proxy.get_operators(); VariablesProxy task_variables = task_proxy.get_variables(); @@ -234,9 +234,9 @@ DeleteRelaxationConstraintsRR::create_auxiliary_variables( return lp_var_ids; } -void DeleteRelaxationConstraintsRR::create_auxiliary_variables_ve( +void DeleteRelaxationRRConstraints::create_auxiliary_variables_ve( const TaskProxy &task_proxy, const VEGraph &ve_graph, LPVariables &variables, - DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids) const { + DeleteRelaxationRRConstraints::LPVariableIDs &lp_var_ids) const { utils::unused_variable(task_proxy); // Add e_{i,j} variables. for (pair edge : ve_graph.get_edges()) { @@ -253,9 +253,9 @@ void DeleteRelaxationConstraintsRR::create_auxiliary_variables_ve( } } -void DeleteRelaxationConstraintsRR::create_auxiliary_variables_tl( +void DeleteRelaxationRRConstraints::create_auxiliary_variables_tl( const TaskProxy &task_proxy, LPVariables &variables, - DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids) const { + DeleteRelaxationRRConstraints::LPVariableIDs &lp_var_ids) const { int num_facts = 0; for (VariableProxy var : task_proxy.get_variables()) { num_facts += var.get_domain_size(); @@ -275,9 +275,9 @@ void DeleteRelaxationConstraintsRR::create_auxiliary_variables_tl( } } -void DeleteRelaxationConstraintsRR::create_constraints( +void DeleteRelaxationRRConstraints::create_constraints( const TaskProxy &task_proxy, - const DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids, + const DeleteRelaxationRRConstraints::LPVariableIDs &lp_var_ids, lp::LinearProgram &lp) { LPVariables &variables = lp.get_variables(); LPConstraints &constraints = lp.get_constraints(); @@ -391,9 +391,9 @@ void DeleteRelaxationConstraintsRR::create_constraints( } } -void DeleteRelaxationConstraintsRR::create_constraints_ve( +void DeleteRelaxationRRConstraints::create_constraints_ve( const TaskProxy &task_proxy, const VEGraph &ve_graph, - const DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids, + const DeleteRelaxationRRConstraints::LPVariableIDs &lp_var_ids, lp::LinearProgram &lp) { LPConstraints &constraints = lp.get_constraints(); double infinity = lp.get_infinity(); @@ -459,9 +459,9 @@ void DeleteRelaxationConstraintsRR::create_constraints_ve( } } -void DeleteRelaxationConstraintsRR::create_constraints_tl( +void DeleteRelaxationRRConstraints::create_constraints_tl( const TaskProxy &task_proxy, - const DeleteRelaxationConstraintsRR::LPVariableIDs &lp_var_ids, + const DeleteRelaxationRRConstraints::LPVariableIDs &lp_var_ids, lp::LinearProgram &lp) { /* Constraint (9) in paper: @@ -500,7 +500,7 @@ void DeleteRelaxationConstraintsRR::create_constraints_tl( } } -void DeleteRelaxationConstraintsRR::initialize_constraints( +void DeleteRelaxationRRConstraints::initialize_constraints( const shared_ptr &task, lp::LinearProgram &lp) { TaskProxy task_proxy(*task); LPVariableIDs lp_var_ids = create_auxiliary_variables( @@ -532,7 +532,7 @@ void DeleteRelaxationConstraintsRR::initialize_constraints( } } -bool DeleteRelaxationConstraintsRR::update_constraints( +bool DeleteRelaxationRRConstraints::update_constraints( const State &state, lp::LPSolver &lp_solver) { // Unset old bounds. int con_id; @@ -552,11 +552,11 @@ bool DeleteRelaxationConstraintsRR::update_constraints( return false; } -class DeleteRelaxationConstraintsRRFeature +class DeleteRelaxationRRConstraintsFeature : public plugins::TypedFeature { + DeleteRelaxationRRConstraints> { public: - DeleteRelaxationConstraintsRRFeature() + DeleteRelaxationRRConstraintsFeature() : TypedFeature("delete_relaxation_rr_constraints") { document_title( "Delete relaxation constraints from Rankooh and Rintanen"); @@ -616,7 +616,7 @@ class DeleteRelaxationConstraintsRRFeature } }; -static plugins::FeaturePlugin _plugin; +static plugins::FeaturePlugin _plugin; static plugins::TypedEnumPlugin _enum_plugin({ {"time_labels", diff --git a/src/search/operator_counting/delete_relaxation_rr_constraints.h b/src/search/operator_counting/delete_relaxation_rr_constraints.h index 4af9bce7d4..cb43921cd9 100644 --- a/src/search/operator_counting/delete_relaxation_rr_constraints.h +++ b/src/search/operator_counting/delete_relaxation_rr_constraints.h @@ -1,5 +1,5 @@ -#ifndef OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_RR_H -#define OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_RR_H +#ifndef OPERATOR_COUNTING_DELETE_RELAXATION_RR_CONSTRAINTS_H +#define OPERATOR_COUNTING_DELETE_RELAXATION_RR_CONSTRAINTS_H #include "constraint_generator.h" @@ -27,7 +27,7 @@ enum class AcyclicityType { TIME_LABELS, VERTEX_ELIMINATION, NONE }; -class DeleteRelaxationConstraintsRR : public ConstraintGenerator { +class DeleteRelaxationRRConstraints : public ConstraintGenerator { struct LPVariableIDs { /* The variables f_p in the paper represent if a fact p is reached by the @@ -103,7 +103,7 @@ class DeleteRelaxationConstraintsRR : public ConstraintGenerator { const TaskProxy &task_proxy, const LPVariableIDs &lp_var_ids, lp::LinearProgram &lp); public: - explicit DeleteRelaxationConstraintsRR(const plugins::Options &opts); + explicit DeleteRelaxationRRConstraints(const plugins::Options &opts); virtual void initialize_constraints( const std::shared_ptr &task,