Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
95078e9
Add completeness check to eager search, all pruning methods, and some…
grucla Feb 10, 2026
fa784a2
Add comments and shorten EagerSearch::is_complete.
grucla Feb 11, 2026
25939f4
Add completeness check to lazy search.
grucla Feb 11, 2026
5ea8eb2
Make for loop in tiebreaking_open_list.cc consistent.
grucla Feb 12, 2026
efc35c9
Fix error and make comments style conform.
grucla Feb 12, 2026
3d26d49
Add completeness check to pareto open list.
grucla Feb 12, 2026
94d835d
Add completeness check to type based open list.
grucla Feb 12, 2026
549ac5e
Remove default from check in open_list.h.
grucla Feb 12, 2026
014e993
Add completeness check to ehc.
grucla Feb 12, 2026
a257b08
Add timeout check.
grucla Feb 12, 2026
bc57cac
Add completeness check to iterated search.
grucla Feb 12, 2026
a3a1ab7
Remove default of SearchAlgorithm::is_complete.
grucla Feb 12, 2026
48c1bfa
Adjust documentation of exit code 11.
grucla Feb 12, 2026
7a208d1
Rename pruning_is_safe to is_complete.
grucla Feb 12, 2026
fb57384
Rename dead_ends_are_reliable to is_safe.
grucla Feb 12, 2026
0708d6b
Add some comments.
grucla Feb 12, 2026
a9e3c82
Use lambdas and adjust code comments.
grucla Feb 13, 2026
b3e1d66
Add exit code and search status UNSOLVABLE_WITHIN_BOUND.
grucla Feb 13, 2026
54e4939
Rename search algorithm's is_complete to is_complete_within_bound.
grucla Feb 13, 2026
68314af
Fix draft of IteratedSearch::is_complete().
grucla Feb 13, 2026
0a50aca
add exit code in docs.
SimonDold Feb 15, 2026
95936bd
minor renaming.
SimonDold Feb 15, 2026
927dc0b
add missing is_safe check to const evaluator.
SimonDold Feb 15, 2026
f35111d
remove std.
SimonDold Feb 15, 2026
9d9c5a7
add infty check for const eval and weighted eval.
SimonDold Feb 16, 2026
305ab66
Change if-else to switch.
grucla Feb 20, 2026
4bf5f9c
Add exitcode tests.
grucla Feb 20, 2026
65f1b22
Add more exit code tests and a missing driver return code.
grucla Feb 20, 2026
04e80a7
update report message.
SimonDold Feb 25, 2026
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
5 changes: 3 additions & 2 deletions docs/exit-codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ termination which prevents the execution of further components.

| **Code** | **Name** | **Meaning** |
| -------- | -------- | ----------- |
| 10 | TRANSLATE_UNSOLVABLE | Translator proved task to be unsolvable. Currently not used |
| 11 | SEARCH_UNSOLVABLE | Task is provably unsolvable with current bound. Currently only used by hillclimbing search. See also [issue377](http://issues.fast-downward.org/issue377). |
| 10 | TRANSLATE_UNSOLVABLE | Translator proved task to be unsolvable. Currently not used. |
| 11 | SEARCH_UNSOLVABLE | Task is provably unsolvable. |
| 12 | SEARCH_UNSOLVED_INCOMPLETE | Search ended without finding a solution. |
| 13 | SEARCH_UNSOLVABLE_WITHIN_BOUND | Task is provably unsolvable with current bound. |

The third block (20-29) represents expected failures which prevent the
execution of further components.
Expand Down
1 change: 1 addition & 0 deletions driver/returncodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
TRANSLATE_UNSOLVABLE = 10
SEARCH_UNSOLVABLE = 11
SEARCH_UNSOLVED_INCOMPLETE = 12
SEARCH_UNSOLVABLE_WITHIN_BOUND = 13

TRANSLATE_OUT_OF_MEMORY = 20
TRANSLATE_OUT_OF_TIME = 21
Expand Down
48 changes: 48 additions & 0 deletions misc/tests/benchmarks/blocks-unsolvable/domain.pddl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 4 Op-blocks world
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (domain BLOCKS)
(:requirements :strips)
(:predicates (on ?x ?y)
(ontable ?x)
(clear ?x)
(handempty)
(holding ?x)
)

(:action pick-up
:parameters (?x)
:precondition (and (clear ?x) (ontable ?x) (handempty))
:effect
(and (not (ontable ?x))
(not (clear ?x))
(not (handempty))
(holding ?x)))

(:action put-down
:parameters (?x)
:precondition (holding ?x)
:effect
(and (not (holding ?x))
(clear ?x)
(handempty)
(ontable ?x)))
(:action stack
:parameters (?x ?y)
:precondition (and (holding ?x) (clear ?y))
:effect
(and (not (holding ?x))
(not (clear ?y))
(clear ?x)
(handempty)
(on ?x ?y)))
(:action unstack
:parameters (?x ?y)
:precondition (and (on ?x ?y) (clear ?x) (handempty))
:effect
(and (holding ?x)
(clear ?y)
(not (clear ?x))
(not (handempty))
(not (on ?x ?y)))))
7 changes: 7 additions & 0 deletions misc/tests/benchmarks/blocks-unsolvable/probBLOCKS-4-0.pddl
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
(define (problem BLOCKS-4-0)
(:domain BLOCKS)
(:objects D B A C )
(:INIT (CLEAR C) (CLEAR A) (CLEAR B) (CLEAR D) (ONTABLE C) (ONTABLE A)
(ONTABLE B) (ONTABLE D) (HANDEMPTY))
(:goal (AND (ON D C) (ON C B) (ON B A) (ON A D)))
)
31 changes: 31 additions & 0 deletions misc/tests/test-exitcodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"strips": "miconic/s1-0.pddl",
"axioms": "philosophers/p01-phil2.pddl",
"cond-eff": "miconic-simpleadl/s1-0.pddl",
"unsolvable": "blocks-unsolvable/probBLOCKS-4-0.pddl",
"large": "satellite/p25-HC-pfile5.pddl",
}

Expand Down Expand Up @@ -121,6 +122,36 @@
defaultdict(lambda: returncodes.SEARCH_UNSUPPORTED)),
("cond-eff", [], MERGE_AND_SHRINK,
defaultdict(lambda: returncodes.SUCCESS)),
("unsolvable", [], "astar(blind())",
defaultdict(lambda: returncodes.SEARCH_UNSOLVABLE)),
("unsolvable", [], "astar(lmcut())",
defaultdict(lambda: returncodes.SEARCH_UNSOLVABLE)),
("unsolvable", [], "lazy(single(lmcut()))",
defaultdict(lambda: returncodes.SEARCH_UNSOLVABLE)),
("unsolvable", [], "eager(alt([single(const(infinity)),single(const(1))]))",
defaultdict(lambda: returncodes.SEARCH_UNSOLVABLE)),
("unsolvable", [], "eager(type_based([const(infinity),const(1)]))",
defaultdict(lambda: returncodes.SEARCH_UNSOLVABLE)),
("unsolvable", [], "eager(pareto([const(infinity),const(1)]))",
defaultdict(lambda: returncodes.SEARCH_UNSOLVABLE)),
("unsolvable", [], "eager(tiebreaking([const(infinity),const(1)],unsafe_pruning=false))",
defaultdict(lambda: returncodes.SEARCH_UNSOLVABLE)),
("unsolvable", [], "astar(blind(),bound=2)",
defaultdict(lambda: returncodes.SEARCH_UNSOLVABLE_WITHIN_BOUND)),
("unsolvable", [], "ehc(blind())",
defaultdict(lambda: returncodes.SEARCH_UNSOLVED_INCOMPLETE)),
("unsolvable", [], "eager(single(blind(),pref_only=true))",
defaultdict(lambda: returncodes.SEARCH_UNSOLVED_INCOMPLETE)),
("unsolvable", [], "eager(pareto([blind()],pref_only=true))",
defaultdict(lambda: returncodes.SEARCH_UNSOLVED_INCOMPLETE)),
("unsolvable", [], "eager(pareto([cg(),cea()]))",
defaultdict(lambda: returncodes.SEARCH_UNSOLVED_INCOMPLETE)),
("unsolvable", [], "eager(tiebreaking([const(infinity),blind()]))",
defaultdict(lambda: returncodes.SEARCH_UNSOLVED_INCOMPLETE)),
("unsolvable", [], "eager(alt([single(cg()),single(const(infinity))]))",
defaultdict(lambda: returncodes.SEARCH_UNSOLVED_INCOMPLETE)),
("unsolvable", [], "lazy(type_based([cg(),const(infinity)]))",
defaultdict(lambda: returncodes.SEARCH_UNSOLVED_INCOMPLETE)),
# We cannot set/enforce memory limits on Windows/macOS and thus expect
# DRIVER_UNSUPPORTED as exit code in those cases.
("large", ["--search-memory-limit", "100M"], MERGE_AND_SHRINK,
Expand Down
2 changes: 1 addition & 1 deletion src/search/evaluator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Evaluator::Evaluator(
log(utils::get_log_for_verbosity(verbosity)) {
}

bool Evaluator::dead_ends_are_reliable() const {
bool Evaluator::is_safe() const {
return true;
}

Expand Down
6 changes: 3 additions & 3 deletions src/search/evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ class Evaluator {
virtual ~Evaluator() = default;

/*
dead_ends_are_reliable should return true if the evaluator is
"safe", i.e., infinite estimates can be trusted.
is_safe returns true if the evaluator reports dead ends reliably,
i.e., if its infinite estimates can be trusted.

The default implementation returns true.
*/
virtual bool dead_ends_are_reliable() const;
virtual bool is_safe() const;

/*
get_path_dependent_evaluators should insert all path-dependent
Expand Down
10 changes: 5 additions & 5 deletions src/search/evaluators/combining_evaluator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ CombiningEvaluator::CombiningEvaluator(
: Evaluator(false, false, false, description, verbosity),
subevaluators(evals) {
utils::verify_list_not_empty(evals, "evals");
all_dead_ends_are_reliable = true;
all_subevaluators_are_safe = true;
for (const shared_ptr<Evaluator> &subevaluator : subevaluators)
if (!subevaluator->dead_ends_are_reliable())
all_dead_ends_are_reliable = false;
if (!subevaluator->is_safe())
all_subevaluators_are_safe = false;
}

bool CombiningEvaluator::dead_ends_are_reliable() const {
return all_dead_ends_are_reliable;
bool CombiningEvaluator::is_safe() const {
return all_subevaluators_are_safe;
}

EvaluationResult CombiningEvaluator::compute_result(
Expand Down
13 changes: 6 additions & 7 deletions src/search/evaluators/combining_evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace combining_evaluator {
*/
class CombiningEvaluator : public Evaluator {
std::vector<std::shared_ptr<Evaluator>> subevaluators;
bool all_dead_ends_are_reliable;
bool all_subevaluators_are_safe;
protected:
virtual int combine_values(const std::vector<int> &values) = 0;
public:
Expand All @@ -24,19 +24,18 @@ class CombiningEvaluator : public Evaluator {
const std::string &description, utils::Verbosity verbosity);

/*
Note: dead_ends_are_reliable() is a state-independent method, so
it only returns true if all subevaluators report dead ends reliably.
Note: is_safe() is a state-independent method, so
it only returns true if all subevaluators are safe.

Note that we could get more fine-grained information when
considering of reliability for a given evaluated state. For
example, if we use h1 (unreliable) and h2 (reliable) and have a
example, if we use h1 (unsafe) and h2 (safe) and have a
state where h1 is finite and h2 is infinite, then we can
*reliably* mark the state as a dead end. There is currently no
*safely* mark the state as a dead end. There is currently no
way to exploit such state-based information, and hence we do not
compute it.
*/

virtual bool dead_ends_are_reliable() const override;
virtual bool is_safe() const override;
virtual EvaluationResult compute_result(
EvaluationContext &eval_context) override;

Expand Down
5 changes: 5 additions & 0 deletions src/search/evaluators/const_evaluator.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "const_evaluator.h"

#include "../evaluation_result.h"

#include "../plugins/plugin.h"

using namespace std;
Expand All @@ -15,6 +17,9 @@ EvaluationResult ConstEvaluator::compute_result(EvaluationContext &) {
result.set_evaluator_value(value);
return result;
}
bool ConstEvaluator::is_safe() const {
return value < EvaluationResult::INFTY;
}

class ConstEvaluatorFeature
: public plugins::TypedFeature<Evaluator, ConstEvaluator> {
Expand Down
1 change: 1 addition & 0 deletions src/search/evaluators/const_evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class ConstEvaluator : public Evaluator {
virtual void get_path_dependent_evaluators(
std::set<Evaluator *> &) override {
}
virtual bool is_safe() const override;
};
}

Expand Down
10 changes: 8 additions & 2 deletions src/search/evaluators/weighted_evaluator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@ WeightedEvaluator::WeightedEvaluator(
weight(weight) {
}

bool WeightedEvaluator::dead_ends_are_reliable() const {
return evaluator->dead_ends_are_reliable();
bool WeightedEvaluator::is_safe() const {
if (weight == 0) {
return true;
}
if (weight == EvaluationResult::INFTY) {
return false;
}
return evaluator->is_safe();
}

EvaluationResult WeightedEvaluator::compute_result(
Expand Down
2 changes: 1 addition & 1 deletion src/search/evaluators/weighted_evaluator.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class WeightedEvaluator : public Evaluator {
const std::shared_ptr<Evaluator> &eval, int weight,
const std::string &description, utils::Verbosity verbosity);

virtual bool dead_ends_are_reliable() const override;
virtual bool is_safe() const override;
virtual EvaluationResult compute_result(
EvaluationContext &eval_context) override;
virtual void get_path_dependent_evaluators(
Expand Down
2 changes: 1 addition & 1 deletion src/search/heuristics/cea_heuristic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ ContextEnhancedAdditiveHeuristic::~ContextEnhancedAdditiveHeuristic() {
delete problem;
}

bool ContextEnhancedAdditiveHeuristic::dead_ends_are_reliable() const {
bool ContextEnhancedAdditiveHeuristic::is_safe() const {
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion src/search/heuristics/cea_heuristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class ContextEnhancedAdditiveHeuristic : public Heuristic {
const std::shared_ptr<AbstractTask> &transform, bool cache_estimates,
const std::string &description, utils::Verbosity verbosity);
~ContextEnhancedAdditiveHeuristic();
virtual bool dead_ends_are_reliable() const override;
virtual bool is_safe() const override;
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/search/heuristics/cg_heuristic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ CGHeuristic::CGHeuristic(
transition_graphs = factory.build_dtgs();
}

bool CGHeuristic::dead_ends_are_reliable() const {
bool CGHeuristic::is_safe() const {
return false;
}

Expand Down
2 changes: 1 addition & 1 deletion src/search/heuristics/cg_heuristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class CGHeuristic : public Heuristic {
int max_cache_size, tasks::AxiomHandlingType axiom_hanlding,
const std::shared_ptr<AbstractTask> &transform, bool cache_estimates,
const std::string &description, utils::Verbosity verbosity);
virtual bool dead_ends_are_reliable() const override;
virtual bool is_safe() const override;
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/search/heuristics/hm_heuristic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ HMHeuristic::HMHeuristic(
generate_all_tuples();
}

bool HMHeuristic::dead_ends_are_reliable() const {
bool HMHeuristic::is_safe() const {
return !task_properties::has_axioms(task_proxy) && !has_cond_effects;
}

Expand Down
2 changes: 1 addition & 1 deletion src/search/heuristics/hm_heuristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class HMHeuristic : public Heuristic {
bool cache_estimates, const std::string &description,
utils::Verbosity verbosity);

virtual bool dead_ends_are_reliable() const override;
virtual bool is_safe() const override;
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/search/heuristics/relaxation_heuristic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ RelaxationHeuristic::RelaxationHeuristic(
}
}

bool RelaxationHeuristic::dead_ends_are_reliable() const {
bool RelaxationHeuristic::is_safe() const {
return !task_properties::has_axioms(task_proxy);
}

Expand Down
2 changes: 1 addition & 1 deletion src/search/heuristics/relaxation_heuristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class RelaxationHeuristic : public Heuristic {
const std::shared_ptr<AbstractTask> &transform, bool cache_estimates,
const std::string &description, utils::Verbosity verbosity);

virtual bool dead_ends_are_reliable() const override;
virtual bool is_safe() const override;
};

extern void add_relaxation_heuristic_options_to_feature(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ int LandmarkCostPartitioningHeuristic::get_heuristic_value(
}
}

bool LandmarkCostPartitioningHeuristic::dead_ends_are_reliable() const {
bool LandmarkCostPartitioningHeuristic::is_safe() const {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class LandmarkCostPartitioningHeuristic : public LandmarkHeuristic {
CostPartitioningMethod cost_partitioning, bool alm,
lp::LPSolverType lpsolver);

virtual bool dead_ends_are_reliable() const override;
virtual bool is_safe() const override;
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/search/landmarks/landmark_sum_heuristic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ int LandmarkSumHeuristic::get_heuristic_value(const State &ancestor_state) {
return h;
}

bool LandmarkSumHeuristic::dead_ends_are_reliable() const {
bool LandmarkSumHeuristic::is_safe() const {
return dead_ends_reliable;
}

Expand Down
2 changes: 1 addition & 1 deletion src/search/landmarks/landmark_sum_heuristic.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class LandmarkSumHeuristic : public LandmarkHeuristic {
const std::string &description, utils::Verbosity verbosity,
tasks::AxiomHandlingType axioms);

virtual bool dead_ends_are_reliable() const override;
virtual bool is_safe() const override;
};
}

Expand Down
5 changes: 5 additions & 0 deletions src/search/open_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ class OpenList {
virtual bool is_dead_end(EvaluationContext &eval_context) const = 0;
virtual bool is_reliable_dead_end(
EvaluationContext &eval_context) const = 0;
/*
If for some solvable task no reachable goal state is ever inserted
into the open list then it is not complete, i.e. is_complete is false.
*/
virtual bool is_complete() const = 0;
};

using StateOpenListEntry = StateID;
Expand Down
Loading
Loading