Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue1140 #225

Merged
merged 8 commits into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 32 additions & 29 deletions src/search/search_algorithms/eager_search.cc
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,16 @@ SearchStatus EagerSearch::step() {
With lazy evaluators (and only with these) we can have dead nodes
in the open list.

For example, consider a state s that is reached twice before it is expanded.
The first time we insert it into the open list, we compute a finite
heuristic value. The second time we insert it, the cached value is reused.

During first expansion, the heuristic value is recomputed and might become
infinite, for example because the reevaluation uses a stronger heuristic or
because the heuristic is path-dependent and we have accumulated more
information in the meantime. Then upon second expansion we have a dead-end
node which we must ignore.
For example, consider a state s that is reached twice before it is
expanded. The first time we insert it into the open list, we
compute a finite heuristic value. The second time we insert it,
the cached value is reused.

During first expansion, the heuristic value is recomputed and
might become infinite, for example because the reevaluation uses a
stronger heuristic or because the heuristic is path-dependent and
we have accumulated more information in the meantime. Then upon
second expansion we have a dead-end node which we must ignore.
*/
if (node->is_dead_end())
continue;
Expand Down Expand Up @@ -233,7 +234,7 @@ SearchStatus EagerSearch::step() {
statistics.inc_dead_ends();
continue;
}
succ_node.open(*node, op, get_adjusted_cost(op));
succ_node.open_new_node(*node, op, get_adjusted_cost(op));

open_list->insert(succ_eval_context, succ_state.get_id());
if (search_progress.check_progress(succ_eval_context)) {
Expand All @@ -242,22 +243,24 @@ SearchStatus EagerSearch::step() {
}
} else if (succ_node.get_g() > node->get_g() + get_adjusted_cost(op)) {
// We found a new cheapest path to an open or closed state.
if (reopen_closed_nodes) {
if (succ_node.is_closed()) {
/*
TODO: It would be nice if we had a way to test
that reopening is expected behaviour, i.e., exit
with an error when this is something where
reopening should not occur (e.g. A* with a
consistent heuristic).
*/
statistics.inc_reopened();
}
succ_node.reopen(*node, op, get_adjusted_cost(op));

if (succ_node.is_open()) {
succ_node.update_open_node_parent(
*node, op, get_adjusted_cost(op));
EvaluationContext succ_eval_context(
succ_state, succ_node.get_g(), is_preferred, &statistics);
open_list->insert(succ_eval_context, succ_state.get_id());
} else if (succ_node.is_closed() && reopen_closed_nodes) {
/*
TODO: It would be nice if we had a way to test
that reopening is expected behaviour, i.e., exit
with an error when this is something where
reopening should not occur (e.g. A* with a
consistent heuristic).
*/
statistics.inc_reopened();
succ_node.reopen_closed_node(*node, op, get_adjusted_cost(op));
EvaluationContext succ_eval_context(
succ_state, succ_node.get_g(), is_preferred, &statistics);

/*
Note: our old code used to retrieve the h value from
remochristen marked this conversation as resolved.
Show resolved Hide resolved
the search node here. Our new code recomputes it as
Expand All @@ -277,14 +280,14 @@ SearchStatus EagerSearch::step() {
*/
open_list->insert(succ_eval_context, succ_state.get_id());
} else {
// If we do not reopen closed nodes, we just update the parent pointers.
// Note that this could cause an incompatibility between
// the g-value and the actual path that is traced back.
remochristen marked this conversation as resolved.
Show resolved Hide resolved
succ_node.update_parent(*node, op, get_adjusted_cost(op));
assert(succ_node.is_closed() && !reopen_closed_nodes);
succ_node.update_closed_node_parent(
*node, op, get_adjusted_cost(op));
}
} else {
// We found a more expensive path to an open or closed state.
remochristen marked this conversation as resolved.
Show resolved Hide resolved
}
}

return IN_PROGRESS;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,8 @@ SearchStatus EnforcedHillClimbingSearch::ehc() {
}

int h = eval_context.get_evaluator_value(evaluator.get());
node.open(parent_node, last_op, get_adjusted_cost(last_op));
node.open_new_node(parent_node, last_op,
get_adjusted_cost(last_op));

if (h < current_eval_context.get_evaluator_value(evaluator.get())) {
++num_ehc_phases;
Expand Down
7 changes: 5 additions & 2 deletions src/search/search_algorithms/lazy_search.cc
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,13 @@ SearchStatus LazySearch::step() {
SearchNode parent_node = search_space.get_node(parent_state);
OperatorProxy current_operator = task_proxy.get_operators()[current_operator_id];
if (reopen) {
node.reopen(parent_node, current_operator, get_adjusted_cost(current_operator));
node.reopen_closed_node(parent_node, current_operator,
get_adjusted_cost(
current_operator));
statistics.inc_reopened();
} else {
node.open(parent_node, current_operator, get_adjusted_cost(current_operator));
node.open_new_node(parent_node, current_operator,
get_adjusted_cost(current_operator));
}
}
node.close();
Expand Down
55 changes: 27 additions & 28 deletions src/search/search_space.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,44 +53,43 @@ void SearchNode::open_initial() {
info.creating_operator = OperatorID::no_operator;
}

void SearchNode::open(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost) {
assert(info.status == SearchNodeInfo::NEW);
info.status = SearchNodeInfo::OPEN;
void SearchNode::update_parent(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost) {
info.g = parent_node.info.g + adjusted_cost;
info.real_g = parent_node.info.real_g + parent_op.get_cost();
info.parent_state_id = parent_node.get_state().get_id();
info.creating_operator = OperatorID(parent_op.get_id());
}

void SearchNode::reopen(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost) {
assert(info.status == SearchNodeInfo::OPEN ||
info.status == SearchNodeInfo::CLOSED);
void SearchNode::open_new_node(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost) {
assert(info.status == SearchNodeInfo::NEW);
info.status = SearchNodeInfo::OPEN;
update_parent(parent_node, parent_op, adjusted_cost);
}

// The latter possibility is for inconsistent heuristics, which
// may require reopening closed nodes.
void SearchNode::reopen_closed_node(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost) {
assert(info.status == SearchNodeInfo::CLOSED);
info.status = SearchNodeInfo::OPEN;
info.g = parent_node.info.g + adjusted_cost;
info.real_g = parent_node.info.real_g + parent_op.get_cost();
info.parent_state_id = parent_node.get_state().get_id();
info.creating_operator = OperatorID(parent_op.get_id());
update_parent(parent_node, parent_op, adjusted_cost);
}

// like reopen, except doesn't change status
void SearchNode::update_parent(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost) {
assert(info.status == SearchNodeInfo::OPEN ||
info.status == SearchNodeInfo::CLOSED);
// The latter possibility is for inconsistent heuristics, which
// may require reopening closed nodes.
info.g = parent_node.info.g + adjusted_cost;
info.real_g = parent_node.info.real_g + parent_op.get_cost();
info.parent_state_id = parent_node.get_state().get_id();
info.creating_operator = OperatorID(parent_op.get_id());
void SearchNode::update_open_node_parent(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost) {
assert(info.status == SearchNodeInfo::OPEN);
update_parent(parent_node, parent_op, adjusted_cost);
}

void SearchNode::update_closed_node_parent(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost) {
assert(info.status == SearchNodeInfo::CLOSED);
update_parent(parent_node, parent_op, adjusted_cost);
}

void SearchNode::close() {
Expand Down
21 changes: 14 additions & 7 deletions src/search/search_space.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class LogProxy;
class SearchNode {
State state;
SearchNodeInfo &info;

void update_parent(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost);
public:
SearchNode(const State &state, SearchNodeInfo &info);

Expand All @@ -32,15 +36,18 @@ class SearchNode {
int get_real_g() const;

void open_initial();
void open(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost);
void reopen(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost);
void update_parent(const SearchNode &parent_node,
void open_new_node(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost);
void reopen_closed_node(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost);
void update_open_node_parent(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost);
void update_closed_node_parent(const SearchNode &parent_node,
const OperatorProxy &parent_op,
int adjusted_cost);
void close();
void mark_as_dead_end();

Expand Down
Loading