Skip to content

Commit

Permalink
[issue1134] Implement delete-relaxation operator-counting constraints…
Browse files Browse the repository at this point in the history
… by Rankooh and Rintanen.

We implement the delete-relaxation operator-counting constraints described in "Efficient Computation and Informative Estimation of h^+ by Integer and Linear Programming" ICAPS 2022 by Masood Feyzbakhsh Rankooh and Jussi Rintanen. The command line option for the existing delete-relaxation constraint formulation by Tatsuya Imai and Alex Fukunaga changed from `delete_relaxation_constraints(...)` to `delete_relaxation_if_constraints(...)`. The Rankooh and Rintanen formulation generally shows better performance. We also fix a small bug in named vector.
  • Loading branch information
remochristen authored Jul 5, 2024
1 parent ea0f93a commit 00625e7
Show file tree
Hide file tree
Showing 9 changed files with 810 additions and 31 deletions.
3 changes: 2 additions & 1 deletion src/search/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +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
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
Expand Down
13 changes: 9 additions & 4 deletions src/search/algorithms/named_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -56,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;
}
}

Expand Down
14 changes: 10 additions & 4 deletions src/search/lp/cplex_solver_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "../algorithms/named_vector.h"
#include "../utils/memory.h"

#include <cstring>
#include <cplex.h>

namespace lp {
Expand Down Expand Up @@ -144,15 +145,20 @@ class CplexSolverInterface : public SolverInterface {
template<typename T>
explicit CplexNameData(const named_vector::NamedVector<T> &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()) {
// CPLEX copies the names, so the const_cast should be fine.
names.push_back(const_cast<char *>(name.data()));
indices.push_back(i);
}
}
}
}

int size() {return names.size();}
int *get_indices() {
if (indices.empty()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "delete_relaxation_constraints.h"
#include "delete_relaxation_if_constraints.h"

#include "../task_proxy.h"

Expand All @@ -21,37 +21,37 @@ static void add_lp_variables(int count, LPVariables &variables, vector<int> &ind
}


DeleteRelaxationConstraints::DeleteRelaxationConstraints(const plugins::Options &opts)
DeleteRelaxationIFConstraints::DeleteRelaxationIFConstraints(const plugins::Options &opts)
: use_time_vars(opts.get<bool>("use_time_vars")),
use_integer_vars(opts.get<bool>("use_integer_vars")) {
}

int DeleteRelaxationConstraints::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 DeleteRelaxationConstraints::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 DeleteRelaxationConstraints::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 DeleteRelaxationConstraints::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 DeleteRelaxationConstraints::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 DeleteRelaxationConstraints::get_constraint_id(FactPair f) {
int DeleteRelaxationIFConstraints::get_constraint_id(FactPair f) {
return constraint_ids[f.var][f.value];
}

void DeleteRelaxationConstraints::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();
Expand Down Expand Up @@ -94,8 +94,8 @@ void DeleteRelaxationConstraints::create_auxiliary_variables(
}
}

void DeleteRelaxationConstraints::create_constraints(const TaskProxy &task_proxy,
lp::LinearProgram &lp) {
void DeleteRelaxationIFConstraints::create_constraints(const TaskProxy &task_proxy,
lp::LinearProgram &lp) {
LPVariables &variables = lp.get_variables();
LPConstraints &constraints = lp.get_constraints();
double infinity = lp.get_infinity();
Expand Down Expand Up @@ -213,15 +213,15 @@ void DeleteRelaxationConstraints::create_constraints(const TaskProxy &task_proxy
}


void DeleteRelaxationConstraints::initialize_constraints(
void DeleteRelaxationIFConstraints::initialize_constraints(
const shared_ptr<AbstractTask> &task, lp::LinearProgram &lp) {
TaskProxy task_proxy(*task);
create_auxiliary_variables(task_proxy, lp.get_variables());
create_constraints(task_proxy, lp);
}


bool DeleteRelaxationConstraints::update_constraints(
bool DeleteRelaxationIFConstraints::update_constraints(
const State &state, lp::LPSolver &lp_solver) {
// Unset old bounds.
for (FactPair f : last_state) {
Expand All @@ -236,9 +236,9 @@ bool DeleteRelaxationConstraints::update_constraints(
return false;
}

class DeleteRelaxationConstraintsFeature : public plugins::TypedFeature<ConstraintGenerator, DeleteRelaxationConstraints> {
class DeleteRelaxationIFConstraintsFeature : public plugins::TypedFeature<ConstraintGenerator, DeleteRelaxationIFConstraints> {
public:
DeleteRelaxationConstraintsFeature() : TypedFeature("delete_relaxation_constraints") {
DeleteRelaxationIFConstraintsFeature() : TypedFeature("delete_relaxation_if_constraints") {
document_title("Delete relaxation constraints");
document_synopsis(
"Operator-counting constraints based on the delete relaxation. By "
Expand Down Expand Up @@ -277,10 +277,15 @@ class DeleteRelaxationConstraintsFeature : public plugins::TypedFeature<Constrai
document_note(
"Example",
"To compute the optimal delete-relaxation heuristic h^+^, use\n"
"{{{\noperatorcounting([delete_relaxation_constraints(use_time_vars=true, "
"{{{\noperatorcounting([delete_relaxation_if_constraints(use_time_vars=true, "
"use_integer_vars=true)], use_integer_operator_counts=true))\n}}}\n");
document_note(
"Note",
"For best performance we recommend using the alternative "
"formulation by Rankooh and Rintanen, accessible through the "
"option {{{delete_relaxation_rr_constraints}}}.\n");
}
};

static plugins::FeaturePlugin<DeleteRelaxationConstraintsFeature> _plugin;
static plugins::FeaturePlugin<DeleteRelaxationIFConstraintsFeature> _plugin;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_H
#define OPERATOR_COUNTING_DELETE_RELAXATION_CONSTRAINTS_H
#ifndef OPERATOR_COUNTING_DELETE_RELAXATION_IF_CONSTRAINTS_H
#define OPERATOR_COUNTING_DELETE_RELAXATION_IF_CONSTRAINTS_H

#include "constraint_generator.h"

Expand All @@ -20,7 +20,7 @@ namespace operator_counting {
using LPConstraints = named_vector::NamedVector<lp::LPConstraint>;
using LPVariables = named_vector::NamedVector<lp::LPVariable>;

class DeleteRelaxationConstraints : public ConstraintGenerator {
class DeleteRelaxationIFConstraints : public ConstraintGenerator {
bool use_time_vars;
bool use_integer_vars;

Expand Down Expand Up @@ -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 DeleteRelaxationIFConstraints(const plugins::Options &opts);

virtual void initialize_constraints(
const std::shared_ptr<AbstractTask> &task,
Expand Down
Loading

0 comments on commit 00625e7

Please sign in to comment.