diff --git a/src/search/search_algorithm.cc b/src/search/search_algorithm.cc index 3e32f329fa..5cec4a4e78 100644 --- a/src/search/search_algorithm.cc +++ b/src/search/search_algorithm.cc @@ -43,15 +43,16 @@ SearchAlgorithm::SearchAlgorithm( description(description), status(IN_PROGRESS), solution_found(false), + bound(bound), log(utils::get_log_for_verbosity(verbosity)), state_registry(task_proxy), successor_generator(get_successor_generator(task_proxy, log)), search_space(state_registry, log), statistics(log), - bound(bound), cost_type(cost_type), is_unit_cost(task_properties::is_unit_cost(task_proxy)), - max_time(max_time) { + max_time(max_time), + bound_was_relevant(false) { if (bound < 0) { cerr << "error: negative cost bound " << bound << endl; utils::exit_with(ExitCode::SEARCH_INPUT_ERROR); @@ -70,13 +71,13 @@ SearchStatus SearchAlgorithm::get_status() const { SearchStatus SearchAlgorithm::get_finished_search_status() const { if (found_solution()) { return SOLVED; - } else if (is_unbounded() && is_complete_within_bound()) { - log << "Search terminated -- no plan exists!" << endl; - return UNSOLVABLE; - } else if (is_complete_within_bound()) { + } else if (bound_was_relevant && is_complete_within_bound()) { log << "Search terminated -- no plan with cost " << bound - 1 << " or less exists!" << endl; return UNSOLVABLE_WITHIN_BOUND; + } else if (is_complete_within_bound()) { + log << "Search terminated -- no plan exists!" << endl; + return UNSOLVABLE; } else { log << "Search terminated without finding a plan!" << endl; return FAILED; @@ -108,6 +109,12 @@ void SearchAlgorithm::search() { log << "Actual search time: " << timer.get_elapsed_time() << endl; } +void SearchAlgorithm::shrink_bound(int b) { + if (b < bound) { + bound = b; + } +} + bool SearchAlgorithm::check_goal_and_set_plan(const State &state) { if (task_properties::is_goal_state(task_proxy, state)) { log << "Solution found!" << endl; diff --git a/src/search/search_algorithm.h b/src/search/search_algorithm.h index f00a9ad556..f0a0873d8a 100644 --- a/src/search/search_algorithm.h +++ b/src/search/search_algorithm.h @@ -45,6 +45,7 @@ class SearchAlgorithm : public components::TaskSpecificComponent { SearchStatus status; bool solution_found; Plan plan; + int bound; protected: mutable utils::LogProxy log; PlanManager plan_manager; @@ -53,10 +54,10 @@ class SearchAlgorithm : public components::TaskSpecificComponent { SearchSpace search_space; SearchProgress search_progress; SearchStatistics statistics; - int bound; OperatorCost cost_type; bool is_unit_cost; double max_time; + bool bound_was_relevant; virtual void initialize() { } @@ -65,6 +66,14 @@ class SearchAlgorithm : public components::TaskSpecificComponent { void set_plan(const Plan &plan); bool check_goal_and_set_plan(const State &state); int get_adjusted_cost(const OperatorProxy &op) const; + // Sideeffect: Set bound_was_relevant to true if this check returns true. + bool is_greater_or_equal_to_bound(int g) { + if (g >= bound) { + bound_was_relevant = true; + return true; + } + return false; + } public: SearchAlgorithm( const std::shared_ptr &task, OperatorCost cost_type, @@ -85,15 +94,15 @@ class SearchAlgorithm : public components::TaskSpecificComponent { const SearchStatistics &get_statistics() const { return statistics; } - void set_bound(int b) { - bound = b; + // Set the bound to the minimum of bound and b. + void shrink_bound(int b); + std::string get_bound_string() { + return std::to_string(bound); } - int get_bound() { + int get_final_bound() { + assert(status != SearchStatus::IN_PROGRESS); return bound; } - bool is_unbounded() const { - return bound == std::numeric_limits::max(); - } PlanManager &get_plan_manager() { return plan_manager; } diff --git a/src/search/search_algorithms/eager_search.cc b/src/search/search_algorithms/eager_search.cc index 813b245078..496729c782 100644 --- a/src/search/search_algorithms/eager_search.cc +++ b/src/search/search_algorithms/eager_search.cc @@ -44,7 +44,8 @@ EagerSearch::EagerSearch( void EagerSearch::initialize() { log << "Conducting best first search" << (reopen_closed_nodes ? " with" : " without") - << " reopening closed nodes, (real) bound = " << bound << endl; + << " reopening closed nodes, (real) bound = " << get_bound_string() + << endl; assert(open_list); set evals; @@ -223,8 +224,9 @@ void EagerSearch::generate_successors(const SearchNode &node) { for (OperatorID op_id : applicable_operators) { OperatorProxy op = task_proxy.get_operators()[op_id]; - if ((node.get_real_g() + op.get_cost()) >= bound) + if (is_greater_or_equal_to_bound(node.get_real_g() + op.get_cost())) { continue; + } State succ_state = state_registry.get_successor_state(state, op); statistics.inc_generated(); diff --git a/src/search/search_algorithms/enforced_hill_climbing_search.cc b/src/search/search_algorithms/enforced_hill_climbing_search.cc index dc072e5a0a..5b42572bb9 100644 --- a/src/search/search_algorithms/enforced_hill_climbing_search.cc +++ b/src/search/search_algorithms/enforced_hill_climbing_search.cc @@ -91,8 +91,8 @@ void EnforcedHillClimbingSearch::reach_state( void EnforcedHillClimbingSearch::initialize() { assert(evaluator); - log << "Conducting enforced hill-climbing search, (real) bound = " << bound - << endl; + log << "Conducting enforced hill-climbing search, (real) bound = " + << get_bound_string() << endl; if (use_preferred) { log << "Using preferred operators for " << (preferred_usage == PreferredUsage::RANK_PREFERRED_FIRST @@ -196,8 +196,10 @@ SearchStatus EnforcedHillClimbingSearch::ehc() { int d = parent_node.get_g() - current_phase_start_g + get_adjusted_cost(last_op); - if (parent_node.get_real_g() + last_op.get_cost() >= bound) + if (is_greater_or_equal_to_bound( + parent_node.get_real_g() + last_op.get_cost())) { continue; + } State state = state_registry.get_successor_state(parent_state, last_op); statistics.inc_generated(); diff --git a/src/search/search_algorithms/iterated_search.cc b/src/search/search_algorithms/iterated_search.cc index b7b7cbc1c1..8f4f4732e2 100644 --- a/src/search/search_algorithms/iterated_search.cc +++ b/src/search/search_algorithms/iterated_search.cc @@ -131,7 +131,8 @@ void IteratedSearch::update_best_status( case SearchStatus::UNSOLVABLE_WITHIN_BOUND: /* We ignore inner bounds if the search did not check up to the outer bound. */ - if (task_specific_search->get_bound() >= bound) { + if (is_greater_or_equal_to_bound( + task_specific_search->get_final_bound())) { best_status = current_search_status; } break; @@ -147,8 +148,8 @@ SearchStatus IteratedSearch::step() { if (!task_specific_search) { return best_status; } - if (pass_bound && best_bound < task_specific_search->get_bound()) { - task_specific_search->set_bound(best_bound); + if (pass_bound) { + task_specific_search->shrink_bound(best_bound); } ++phase; diff --git a/src/search/search_algorithms/lazy_search.cc b/src/search/search_algorithms/lazy_search.cc index 379097fe54..f1c8cab419 100644 --- a/src/search/search_algorithms/lazy_search.cc +++ b/src/search/search_algorithms/lazy_search.cc @@ -44,8 +44,8 @@ LazySearch::LazySearch( } void LazySearch::initialize() { - log << "Conducting lazy best first search, (real) bound = " << bound - << endl; + log << "Conducting lazy best first search, (real) bound = " + << get_bound_string() << endl; assert(open_list); set evals; @@ -111,12 +111,13 @@ void LazySearch::generate_successors() { int new_g = current_g + get_adjusted_cost(op); int new_real_g = current_real_g + op.get_cost(); bool is_preferred = preferred_operators.contains(op_id); - if (new_real_g < bound) { - EvaluationContext new_eval_context( - current_eval_context, new_g, is_preferred, nullptr); - open_list->insert( - new_eval_context, make_pair(current_state.get_id(), op_id)); + if (is_greater_or_equal_to_bound(new_real_g)) { + continue; } + EvaluationContext new_eval_context( + current_eval_context, new_g, is_preferred, nullptr); + open_list->insert( + new_eval_context, make_pair(current_state.get_id(), op_id)); } }