From 112a3efba0f06deba0a24455bf1b0ce8fe31d6c2 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Tue, 21 Jul 2026 13:37:11 +0200 Subject: [PATCH 01/20] Add translator documentation to website --- .github/workflows/update-website.yml | 1 + docs/SUMMARY.md | 1 + misc/autodoc/generate-translate-docs.py | 72 +++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100755 misc/autodoc/generate-translate-docs.py diff --git a/.github/workflows/update-website.yml b/.github/workflows/update-website.yml index 9d6ccf0ea5..f19724a607 100644 --- a/.github/workflows/update-website.yml +++ b/.github/workflows/update-website.yml @@ -39,6 +39,7 @@ jobs: cd misc/autodoc python3 -m pip install -r requirements.txt python3 generate-docs.py + python3 generate-translate-docs.py cd ../../.. - name: Move website material to website repo diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 160452a715..7ba3485d21 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -2,6 +2,7 @@ This file controls the navigation below "documentation" on the website. - [](README.md) - [Planner usage](planner-usage.md) + - [Translator usage](translator-usage.md) - [Search plugins](search/) - [Syntax for search plugins](search-plugin-syntax.md) - [Exit codes](exit-codes.md) diff --git a/misc/autodoc/generate-translate-docs.py b/misc/autodoc/generate-translate-docs.py new file mode 100755 index 0000000000..40906ca307 --- /dev/null +++ b/misc/autodoc/generate-translate-docs.py @@ -0,0 +1,72 @@ +#! /usr/bin/env python3 + +import argparse +import logging +from pathlib import Path +import subprocess +import sys + +SCRIPT_DIR = Path(__file__).resolve().parent +REPO_ROOT_DIR = SCRIPT_DIR.parents[1] +BUILD = "release" +FILENAME = "translator-usage.md" + +INTRO_TEXT = """ +# Translator + +Fast Downward's PDDL to SAS^+ translator can be called through Fast Downward's driver script + +``` +./fast-downward.py --translate [domain] problem [--translate-options OPTIONS] +``` + +""" + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("--outdir", default=f"{REPO_ROOT_DIR}/docs") + return parser.parse_args() + + +def build_translator(): + subprocess.check_call([sys.executable, "build.py", BUILD, "translate"], cwd=REPO_ROOT_DIR) + + +def import_argparser_from_translator(): + sys.path.insert(0, str(REPO_ROOT_DIR / "builds" / BUILD / "bin")) + from translate import options + return options.get_arg_parser() + + +def parser_to_markdown(parser: argparse.ArgumentParser): + lines = [INTRO_TEXT] + lines.append("## Options") + lines.append("") + + for action in parser._actions: + if action.option_strings: + name = ", ".join(f"`{s}`" for s in action.option_strings) + else: + name = f"`{action.dest}`" + lines.append(f"### {name}") + lines.append(action.help) + lines.append("") + return "\n".join(lines) + + +def build_docs(path: Path): + parser = import_argparser_from_translator() + path.write_text(parser_to_markdown(parser)) + + +if __name__ == '__main__': + args = parse_args() + logging.info("building translator...") + build_translator() + logging.info("building documentation...") + outdir = SCRIPT_DIR / args.outdir + outdir.mkdir(parents=True, exist_ok=True) + outpath = outdir / FILENAME + if outpath.exists(): + sys.exit(f"{outpath} already exists.") + build_docs(outpath) From 0ce335b98d091c6ecde8b3860dcc62245101b911 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Tue, 21 Jul 2026 13:59:15 +0200 Subject: [PATCH 02/20] fix default values and choices --- misc/autodoc/generate-translate-docs.py | 50 ++++++++++++++++++++----- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/misc/autodoc/generate-translate-docs.py b/misc/autodoc/generate-translate-docs.py index 40906ca307..26a57ce6eb 100755 --- a/misc/autodoc/generate-translate-docs.py +++ b/misc/autodoc/generate-translate-docs.py @@ -20,6 +20,8 @@ ./fast-downward.py --translate [domain] problem [--translate-options OPTIONS] ``` +## Options + """ def parse_args(): @@ -38,19 +40,47 @@ def import_argparser_from_translator(): return options.get_arg_parser() +def action_to_markdown(parser: argparse.ArgumentParser, action: argparse.Action): + if action.option_strings: + names = [] + for opt in action.option_strings: + if action.choices is not None: + choice_str = ",".join(map(str, action.choices)) + names.append(f"`{opt} {{{choice_str}}}`") + elif action.metavar is not None: + names.append(f"`{opt} {action.metavar}`") + elif action.nargs != 0: + metavar = action.dest.upper() + names.append(f"`{opt} {metavar}`") + else: + names.append(f"`{opt}`") + name = ", ".join(names) + else: + name = f"`{action.dest}`" + # Expand %(default)s, %(choices)s, etc. + + help_text = action.help or "" + if help_text is not argparse.SUPPRESS: + params = { + "default": action.default, + "prog": parser.prog, + "type": action.type, + "choices": action.choices, + "metavar": action.metavar, + "dest": action.dest, + } + try: + help_text = help_text % params + except Exception: + pass + + return f"### {name}\n{help_text}\n" + + def parser_to_markdown(parser: argparse.ArgumentParser): lines = [INTRO_TEXT] - lines.append("## Options") - lines.append("") - for action in parser._actions: - if action.option_strings: - name = ", ".join(f"`{s}`" for s in action.option_strings) - else: - name = f"`{action.dest}`" - lines.append(f"### {name}") - lines.append(action.help) - lines.append("") + lines.append(action_to_markdown(parser, action)) return "\n".join(lines) From f6b9e9f4292aa10181bb7d355507a623cfd5afe9 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Tue, 21 Jul 2026 14:36:25 +0200 Subject: [PATCH 03/20] add translate to buildwebsite script --- misc/website/build_website.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/misc/website/build_website.py b/misc/website/build_website.py index 8f7c6981af..0508db9512 100755 --- a/misc/website/build_website.py +++ b/misc/website/build_website.py @@ -34,9 +34,12 @@ rmtree(GENERATED_DOC_DIR, ignore_errors=True) print("Start creating documentation of search plugins") - out = subprocess.run( + subprocess.run( [REPO_ROOT_DIR/"misc"/"autodoc"/"generate-docs.py", "--outdir", GENERATED_DOC_DIR]) + subprocess.run( + [REPO_ROOT_DIR/"misc"/"autodoc"/"generate-translate-docs.py", "--outdir", + GENERATED_DOC_DIR]) print("Done creating documentation of search plugins") print("\n\n", "Done. Run 'mkdocs serve' from the build directory " From ed7e58767797cd45c9b2465fbdba95f299a8587d Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Tue, 21 Jul 2026 14:48:53 +0200 Subject: [PATCH 04/20] fix paths in build_website script --- misc/website/build_website.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/misc/website/build_website.py b/misc/website/build_website.py index 0508db9512..4a66c05f17 100755 --- a/misc/website/build_website.py +++ b/misc/website/build_website.py @@ -11,6 +11,7 @@ REPO_ROOT_DIR = SCRIPT_DIR.parents[1] BUILD_DIR = SCRIPT_DIR/"build" GENERATED_DOC_DIR = BUILD_DIR/"docs"/"documentation"/"search" +GENERATED_TRANSLATE_DOC_DIR = BUILD_DIR/"docs"/"documentation" if __name__ == '__main__': try: @@ -37,10 +38,13 @@ subprocess.run( [REPO_ROOT_DIR/"misc"/"autodoc"/"generate-docs.py", "--outdir", GENERATED_DOC_DIR]) + print("Done creating documentation of search plugins") + + print("Start creating documentation of translator") subprocess.run( [REPO_ROOT_DIR/"misc"/"autodoc"/"generate-translate-docs.py", "--outdir", - GENERATED_DOC_DIR]) - print("Done creating documentation of search plugins") + GENERATED_TRANSLATE_DOC_DIR]) + print("Done creating documentation of translator") print("\n\n", "Done. Run 'mkdocs serve' from the build directory " "to see the website in the browser at http://localhost:8001/:\n", From 6e943cb579daeb6cf26ab0b030e0a756d8c7ec03 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Tue, 21 Jul 2026 14:57:09 +0200 Subject: [PATCH 05/20] rename page title and link pages --- docs/planner-usage.md | 4 ++-- misc/autodoc/generate-translate-docs.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/planner-usage.md b/docs/planner-usage.md index 8403ac4ab1..a1f35873d6 100644 --- a/docs/planner-usage.md +++ b/docs/planner-usage.md @@ -1,4 +1,4 @@ -# Usage +# Planner Usage Fast Downward is a domain-independent classical planning system that consists of two main components: @@ -26,7 +26,7 @@ Note: - Giving the domain file as input is optional. In case no domain file is specified, the component will search for a file called `domain.pddl` located in the same directory as the task file. -- Translator component options can be specified after the input files following the `--translator-options` flag. +- Translator component options can be specified after the input files following the `--translator-options` flag. See [translator usage](translator-usage.md) for details. ## Search component To run a search on a PDDL input task run the following: diff --git a/misc/autodoc/generate-translate-docs.py b/misc/autodoc/generate-translate-docs.py index 26a57ce6eb..272464f9c8 100755 --- a/misc/autodoc/generate-translate-docs.py +++ b/misc/autodoc/generate-translate-docs.py @@ -12,7 +12,7 @@ FILENAME = "translator-usage.md" INTRO_TEXT = """ -# Translator +# Translator Usage Fast Downward's PDDL to SAS^+ translator can be called through Fast Downward's driver script From 6fdfeea051ddbe7212683ae266523b38f37aba18 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Tue, 21 Jul 2026 17:59:16 +0200 Subject: [PATCH 06/20] code review --- misc/autodoc/generate-translate-docs.py | 2 +- misc/website/build_website.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/misc/autodoc/generate-translate-docs.py b/misc/autodoc/generate-translate-docs.py index 272464f9c8..0c0b309219 100755 --- a/misc/autodoc/generate-translate-docs.py +++ b/misc/autodoc/generate-translate-docs.py @@ -57,8 +57,8 @@ def action_to_markdown(parser: argparse.ArgumentParser, action: argparse.Action) name = ", ".join(names) else: name = f"`{action.dest}`" - # Expand %(default)s, %(choices)s, etc. + # Expand %(default)s, %(choices)s, etc. help_text = action.help or "" if help_text is not argparse.SUPPRESS: params = { diff --git a/misc/website/build_website.py b/misc/website/build_website.py index 4a66c05f17..d827892278 100755 --- a/misc/website/build_website.py +++ b/misc/website/build_website.py @@ -10,8 +10,8 @@ SCRIPT_DIR = Path(__file__).resolve().parent REPO_ROOT_DIR = SCRIPT_DIR.parents[1] BUILD_DIR = SCRIPT_DIR/"build" -GENERATED_DOC_DIR = BUILD_DIR/"docs"/"documentation"/"search" -GENERATED_TRANSLATE_DOC_DIR = BUILD_DIR/"docs"/"documentation" +GENERATED_DOC_DIR = BUILD_DIR/"docs"/"documentation" +GENERATED_SEARCH_DOC_DIR = GENERATED_DOC_DIR/"search" if __name__ == '__main__': try: @@ -32,18 +32,18 @@ # we remove the search directory from the documentation (in case it is # there) because we will re-generate its content in the next step from the # actual code (binary). - rmtree(GENERATED_DOC_DIR, ignore_errors=True) + rmtree(GENERATED_SEARCH_DOC_DIR, ignore_errors=True) print("Start creating documentation of search plugins") subprocess.run( [REPO_ROOT_DIR/"misc"/"autodoc"/"generate-docs.py", "--outdir", - GENERATED_DOC_DIR]) + GENERATED_SEARCH_DOC_DIR]) print("Done creating documentation of search plugins") print("Start creating documentation of translator") subprocess.run( [REPO_ROOT_DIR/"misc"/"autodoc"/"generate-translate-docs.py", "--outdir", - GENERATED_TRANSLATE_DOC_DIR]) + GENERATED_DOC_DIR]) print("Done creating documentation of translator") print("\n\n", "Done. Run 'mkdocs serve' from the build directory " From b14679517aea75e3fcdfaea53447795ce297e3d7 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Thu, 23 Jul 2026 11:16:12 +0200 Subject: [PATCH 07/20] code review --- docs/SUMMARY.md | 2 +- misc/autodoc/generate-translate-docs.py | 52 ++++++++++++------------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 7ba3485d21..241b7cb002 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -2,7 +2,7 @@ This file controls the navigation below "documentation" on the website. - [](README.md) - [Planner usage](planner-usage.md) - - [Translator usage](translator-usage.md) + - [Translator options](translator-options.md) - [Search plugins](search/) - [Syntax for search plugins](search-plugin-syntax.md) - [Exit codes](exit-codes.md) diff --git a/misc/autodoc/generate-translate-docs.py b/misc/autodoc/generate-translate-docs.py index 0c0b309219..8f80981ad6 100755 --- a/misc/autodoc/generate-translate-docs.py +++ b/misc/autodoc/generate-translate-docs.py @@ -9,21 +9,20 @@ SCRIPT_DIR = Path(__file__).resolve().parent REPO_ROOT_DIR = SCRIPT_DIR.parents[1] BUILD = "release" -FILENAME = "translator-usage.md" +FILENAME = "translator-options.md" -INTRO_TEXT = """ -# Translator Usage +HEADER_TEXT = """ +# Translator Options -Fast Downward's PDDL to SAS^+ translator can be called through Fast Downward's driver script - -``` -./fast-downward.py --translate [domain] problem [--translate-options OPTIONS] -``` +""" -## Options +FOOTER_TEXT = """ +# Examples """ + + def parse_args(): parser = argparse.ArgumentParser() parser.add_argument("--outdir", default=f"{REPO_ROOT_DIR}/docs") @@ -41,22 +40,19 @@ def import_argparser_from_translator(): def action_to_markdown(parser: argparse.ArgumentParser, action: argparse.Action): - if action.option_strings: - names = [] - for opt in action.option_strings: - if action.choices is not None: - choice_str = ",".join(map(str, action.choices)) - names.append(f"`{opt} {{{choice_str}}}`") - elif action.metavar is not None: - names.append(f"`{opt} {action.metavar}`") - elif action.nargs != 0: - metavar = action.dest.upper() - names.append(f"`{opt} {metavar}`") - else: - names.append(f"`{opt}`") - name = ", ".join(names) - else: - name = f"`{action.dest}`" + names = [] + for opt in action.option_strings: + if action.choices is not None: + choice_str = ",".join(map(str, action.choices)) + names.append(f"`{opt} {{{choice_str}}}`") + elif action.metavar is not None: + names.append(f"`{opt} {action.metavar}`") + elif action.nargs != 0: + metavar = action.dest.upper() + names.append(f"`{opt} {metavar}`") + else: + names.append(f"`{opt}`") + name = ", ".join(names) # Expand %(default)s, %(choices)s, etc. help_text = action.help or "" @@ -78,9 +74,11 @@ def action_to_markdown(parser: argparse.ArgumentParser, action: argparse.Action) def parser_to_markdown(parser: argparse.ArgumentParser): - lines = [INTRO_TEXT] + lines = [HEADER_TEXT] for action in parser._actions: - lines.append(action_to_markdown(parser, action)) + if action.option_strings: + lines.append(action_to_markdown(parser, action)) + lines += [FOOTER_TEXT] return "\n".join(lines) From f06d6a49839d29f2841cae0895436fa913a7a220 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Thu, 23 Jul 2026 11:18:07 +0200 Subject: [PATCH 08/20] fix link --- docs/planner-usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/planner-usage.md b/docs/planner-usage.md index a1f35873d6..3e6b5faad5 100644 --- a/docs/planner-usage.md +++ b/docs/planner-usage.md @@ -26,7 +26,7 @@ Note: - Giving the domain file as input is optional. In case no domain file is specified, the component will search for a file called `domain.pddl` located in the same directory as the task file. -- Translator component options can be specified after the input files following the `--translator-options` flag. See [translator usage](translator-usage.md) for details. +- Translator component options can be specified after the input files following the `--translator-options` flag. See [translator options](translator-options.md) for details. ## Search component To run a search on a PDDL input task run the following: From f479b91f878603ccf970d2ada2ae731cf883b36b Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Thu, 23 Jul 2026 11:27:15 +0200 Subject: [PATCH 09/20] uppercase meta variables for positional arguments in translator --- src/translate/options.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/translate/options.py b/src/translate/options.py index 1943b60a1f..f5ab86a9d2 100644 --- a/src/translate/options.py +++ b/src/translate/options.py @@ -31,9 +31,9 @@ def get_arg_parser(): # process (issue1217). argparser = argparse.ArgumentParser(prog=infer_prog()) argparser.add_argument( - "domain", help="path to domain pddl file") + "domain", metavar="DOMAIN", help="path to domain pddl file") argparser.add_argument( - "task", help="path to task pddl file") + "task", metavar="TASK", help="path to task pddl file") argparser.add_argument( "--relaxed", dest="generate_relaxed_task", action="store_true", help="output relaxed task (no delete effects)") From baa1af81b080df6f1bbba23e03e65360dd845e71 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Thu, 23 Jul 2026 11:53:34 +0200 Subject: [PATCH 10/20] rename task to problem when talking about PDDL files --- src/translate/main.py | 2 +- src/translate/options.py | 2 +- src/translate/pddl_parser/parsing_functions.py | 14 +++++++------- src/translate/pddl_parser/pddl_file.py | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/translate/main.py b/src/translate/main.py index d047353677..1ee0da6aae 100755 --- a/src/translate/main.py +++ b/src/translate/main.py @@ -693,7 +693,7 @@ def main(): timer = timers.Timer() with timers.timing("Parsing", True): task = pddl_parser.open( - domain_filename=get_options().domain, task_filename=get_options().task) + domain_filename=get_options().domain, problem_filename=get_options().problem) with timers.timing("Normalizing task"): normalize.normalize(task) diff --git a/src/translate/options.py b/src/translate/options.py index f5ab86a9d2..825e6588bc 100644 --- a/src/translate/options.py +++ b/src/translate/options.py @@ -33,7 +33,7 @@ def get_arg_parser(): argparser.add_argument( "domain", metavar="DOMAIN", help="path to domain pddl file") argparser.add_argument( - "task", metavar="TASK", help="path to task pddl file") + "problem", metavar="PROBLEM", help="path to problem pddl file") argparser.add_argument( "--relaxed", dest="generate_relaxed_task", action="store_true", help="output relaxed task (no delete effects)") diff --git a/src/translate/pddl_parser/parsing_functions.py b/src/translate/pddl_parser/parsing_functions.py index 025e4ce497..d280c7166b 100644 --- a/src/translate/pddl_parser/parsing_functions.py +++ b/src/translate/pddl_parser/parsing_functions.py @@ -619,16 +619,16 @@ def parse_init(context, alist, predicate_dict, term_names): return initial -def parse_task(domain_pddl, task_pddl): +def parse_task(domain_pddl, problem_pddl): context = Context() if not isinstance(domain_pddl, list): context.error("Invalid definition of a PDDL domain.") domain_name, domain_requirements, types, type_dict, constants, predicates, \ predicate_dict, functions, actions, axioms = parse_domain_pddl(context, domain_pddl) - if not isinstance(task_pddl, list): - context.error("Invalid definition of a PDDL task.") + if not isinstance(problem_pddl, list): + context.error("Invalid definition of a PDDL problem.") task_name, task_domain_name, task_requirements, objects, init, goal, \ - use_metric = parse_task_pddl(context, task_pddl, type_dict, + use_metric = parse_problem_pddl(context, problem_pddl, type_dict, predicate_dict, {c.name for c in constants}) if domain_name != task_domain_name: @@ -738,9 +738,9 @@ def parse_domain_pddl(context, domain_pddl): yield the_axioms -def parse_task_pddl(context, task_pddl, type_dict, predicate_dict, constant_names): - iterator = iter(task_pddl) - with context.layer("Parsing task"): +def parse_problem_pddl(context, problem_pddl, type_dict, predicate_dict, constant_names): + iterator = iter(problem_pddl) + with context.layer("Parsing problem"): try: define_tag = next(iterator) if define_tag != "define": diff --git a/src/translate/pddl_parser/pddl_file.py b/src/translate/pddl_parser/pddl_file.py index 98d2bc7b17..b202e7e6d8 100644 --- a/src/translate/pddl_parser/pddl_file.py +++ b/src/translate/pddl_parser/pddl_file.py @@ -22,8 +22,8 @@ def parse_pddl_file(type, filename): (type, filename, e)) -def open(domain_filename=None, task_filename=None): - if domain_filename is None or task_filename is None: +def open(domain_filename=None, problem_filename=None): + if domain_filename is None or problem_filename is None: # Importing options triggers parsing the problem and domain file names # as arguments from the command line. We don't import unconditionally # at the head of this file because open is exposed in __init__.py @@ -31,9 +31,9 @@ def open(domain_filename=None, task_filename=None): # external code would then trigger this arg parse. from translate.options import get_options domain_filename = domain_filename or get_options().domain - task_filename = task_filename or get_options().task + problem_filename = problem_filename or get_options().problem domain_pddl = parse_pddl_file("domain", domain_filename) - task_pddl = parse_pddl_file("task", task_filename) + problem_pddl = parse_pddl_file("problem", problem_filename) - return parsing_functions.parse_task(domain_pddl, task_pddl) + return parsing_functions.parse_task(domain_pddl, problem_pddl) From 19ef73e1ccc1b125aced978226e33bb5b7077dcd Mon Sep 17 00:00:00 2001 From: Claudia Grundke Date: Thu, 23 Jul 2026 12:02:09 +0200 Subject: [PATCH 11/20] Add examples. --- misc/autodoc/generate-translate-docs.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/misc/autodoc/generate-translate-docs.py b/misc/autodoc/generate-translate-docs.py index 8f80981ad6..380e790d8d 100755 --- a/misc/autodoc/generate-translate-docs.py +++ b/misc/autodoc/generate-translate-docs.py @@ -19,6 +19,18 @@ FOOTER_TEXT = """ # Examples +### Translate with disabled invariant synthesis and find a plan with A* + LM-Cut: +``` +fast-downward.py domain.pddl problem.pddl --search "astar(lmcut())" --translate-options --invariant-generation-max-candidates 0 +``` +Note that the order of the arguments matters. + + +### Print the help message of the translator +``` +fast-downward.py -- --translate-options --help +``` +The singular `--` is used to skip passing a domain and problem file to the driver. """ From 135b1f41803bf792def42ae8ff5dfc3cf3722e61 Mon Sep 17 00:00:00 2001 From: Florian Pommerening Date: Thu, 23 Jul 2026 12:10:50 +0200 Subject: [PATCH 12/20] style --- misc/autodoc/generate-translate-docs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/misc/autodoc/generate-translate-docs.py b/misc/autodoc/generate-translate-docs.py index 380e790d8d..b1d1b2680c 100755 --- a/misc/autodoc/generate-translate-docs.py +++ b/misc/autodoc/generate-translate-docs.py @@ -34,7 +34,6 @@ """ - def parse_args(): parser = argparse.ArgumentParser() parser.add_argument("--outdir", default=f"{REPO_ROOT_DIR}/docs") From bf3c60f6e086d49647ff822c9ddca389e238be23 Mon Sep 17 00:00:00 2001 From: Claudia Grundke Date: Fri, 24 Jul 2026 09:54:17 +0200 Subject: [PATCH 13/20] Rename task to problem in pddl/tasks.py. --- src/translate/pddl/tasks.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/translate/pddl/tasks.py b/src/translate/pddl/tasks.py index d473388240..b9d79259e7 100644 --- a/src/translate/pddl/tasks.py +++ b/src/translate/pddl/tasks.py @@ -11,7 +11,7 @@ from translate.pddl.predicates import Predicate class Task: - def __init__(self, domain_name: str, task_name: str, + def __init__(self, domain_name: str, problem_name: str, requirements: "Requirements", types: List[Type], objects: List[TypedObject], predicates: List[Predicate], functions: List[Function], @@ -19,7 +19,7 @@ def __init__(self, domain_name: str, task_name: str, actions: List[Action], axioms: List[Axiom], use_metric: bool) -> None: self.domain_name = domain_name - self.task_name = task_name + self.problem_name = problem_name self.requirements = requirements self.types = types self.objects = objects @@ -41,8 +41,9 @@ def add_axiom(self, parameters, condition): return axiom def dump(self): - print("Problem %s: %s [%s]" % ( - self.domain_name, self.task_name, self.requirements)) + print("Domain:", self.domain_name) + print("Problem:", self.problem_name) + print("Requirements:", self.requirements) print("Types:") for type in self.types: print(" %s" % type) From cd8e2d5c1f56ac3a768b6b231ea72116c97294c2 Mon Sep 17 00:00:00 2001 From: Claudia Grundke Date: Fri, 24 Jul 2026 13:23:13 +0200 Subject: [PATCH 14/20] Use 'task' and 'problem' consistently in docs. A task consists of a domain file and a problem file. --- docs/planner-usage.md | 20 ++++++++++---------- docs/quick-start.md | 14 +++++++------- docs/translator-output-format.md | 6 +++--- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/planner-usage.md b/docs/planner-usage.md index 3e6b5faad5..a123525eb6 100644 --- a/docs/planner-usage.md +++ b/docs/planner-usage.md @@ -20,18 +20,18 @@ participated in IPC 2011, please also check the page on ## Translation component To translate a PDDL input task into a SAS+ task without performing a search run the following: - ./fast-downward.py --translate [] + ./fast-downward.py --translate [] Note: - Giving the domain file as input is optional. - In case no domain file is specified, the component will search for a file called `domain.pddl` located in the same directory as the task file. + In case no domain file is specified for the task, the component will search for a file called `domain.pddl` located in the same directory as the problem file. - Translator component options can be specified after the input files following the `--translator-options` flag. See [translator options](translator-options.md) for details. ## Search component To run a search on a PDDL input task run the following: - ./fast-downward.py [] \ + ./fast-downward.py [] \ --search "()" Note: @@ -39,7 +39,7 @@ Note: - The PDDL task is translated into a SAS+ task internally without the need to explicitly call the `translate` component. Instead of a PDDL task a SAS+ translator output file could be given as input. In this case the translation step is omitted. - Giving the domain file as input is optional. - In case no domain file is specified, the component will search for a file called `domain.pddl` located in the same directory as the task file. + In case no domain file is specified for the task, the component will search for a file called `domain.pddl` located in the same directory as the problem file. - `` can be any of the [search algorithms](search/SearchAlgorithm.md) with corresponding `` as input. - Search component options can be specified anywhere after the input files. Search component options following translator component options need to first be escaped with the `--search-options` flag. @@ -49,11 +49,11 @@ Note: The following example is a recommended search algorithm configuration: [A* algorithm](search/SearchAlgorithm/#a_search_eager) with the [LM-cut heuristic](search/Evaluator/#landmark-cut_heuristic), which can be run as follows: - ./fast-downward.py [] --search "astar(lmcut())" + ./fast-downward.py [] --search "astar(lmcut())" As this is a common search configuration an alias (`seq-opt-lmcut`) exists that results in the same execution and can be used as follows: - ./fast-downward.py --alias seq-opt-lmcut [] + ./fast-downward.py --alias seq-opt-lmcut [] ### Aliases @@ -65,7 +65,7 @@ To find out which actual search options the aliases corresponds to, check the so For example to run the "LAMA 2011 configuration" of the planner, call: - ./fast-downward.py --alias seq-sat-lama-2011 [] + ./fast-downward.py --alias seq-sat-lama-2011 [] Note: @@ -79,19 +79,19 @@ The search options are built with flexibility in mind, not ease of use. It is very easy to use option settings that look plausible, yet introduce significant inefficiencies. For example, an invocation like - ./fast-downward.py [] \ + ./fast-downward.py [] \ --search "lazy_greedy([ff()], preferred=[ff()])" looks plausible, yet is hugely inefficient since it will compute the FF heuristic twice per state. To circumvent this a [`let`-expression](search-plugin-syntax.md#variables_as_parameters) could be used: - ./fast-downward.py [] \ + ./fast-downward.py [] \ --search "let(hff, ff(), lazy_greedy([hff], preferred=[hff]))" ## Validating plans To validate a plan found by some search algorithm using [VAL](https://github.com/KCL-Planning/VAL) run the following: - ./fast-downward.py --validate [] \ + ./fast-downward.py --validate [] \ --search "()" Note: diff --git a/docs/quick-start.md b/docs/quick-start.md index e7dcb56fa5..a77e497f82 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -35,7 +35,7 @@ You can run the planner as follows: Assume you want to solve a planning task (e.g. from the [Fast Downward benchmarks](https://github.com/aibasel/downward-benchmarks)) using A* search with the LM-cut heuristic. To do so you can run the following: - ./fast-downward.sif --search "astar(lmcut())" + ./fast-downward.sif --search "astar(lmcut())" See more planner options at [planner usage](planner-usage.md). @@ -58,16 +58,16 @@ Note: Assume you want to solve a planning task (e.g. from the [Fast Downward benchmarks](https://github.com/aibasel/downward-benchmarks)) using A* search with the LM-cut heuristic. To do so you can run the following: sudo docker run --rm -v :/benchmarks aibasel/downward \ - /benchmarks/ /benchmarks/ \ + /benchmarks/ /benchmarks/ \ --search "astar(lmcut())" -Here `` refers to your local directory containing your domain and task file. +Here `` refers to your local directory containing your domain and problem file. Note: - The Docker flag `-v` mounts the local directory `` of your host machine under the container directory `/benchmarks`, which is the - place where the containerised planner looks for the problem. + place where the containerised planner looks for the domain and problem file. - `` must be an absolute path; relative paths are only supported as of Docker Engine version 23. See more planner options at [planner usage](planner-usage.md). @@ -128,7 +128,7 @@ vagrant ssh # Run the planner. downward/fast-downward.py \ -/vagrant/benchmarks/ /vagrant/benchmarks/ \ +/vagrant/benchmarks/ /vagrant/benchmarks/ \ --search "astar(lmcut())" # Log out from the VM. @@ -138,7 +138,7 @@ logout vagrant halt ``` -Here `` refers to your local directory containing your domain and task file. +Here `` refers to your local directory containing your domain and problem file. See more planner options at [planner usage](planner-usage.md). @@ -168,7 +168,7 @@ You can run the planner as follows: Assume you want to solve a planning task (e.g. from the [Fast Downward benchmarks](https://github.com/aibasel/downward-benchmarks)) using A* search with the LM-cut heuristic. To do so you can run the following: - ./fast-downward.py --search "astar(lmcut())" + ./fast-downward.py --search "astar(lmcut())" See more planner options at [planner usage](planner-usage.md). diff --git a/docs/translator-output-format.md b/docs/translator-output-format.md index 8a944804c4..7759af942b 100644 --- a/docs/translator-output-format.md +++ b/docs/translator-output-format.md @@ -444,8 +444,8 @@ conditions (0) and affects var6 (6). It requires that the old value of the variable is 1, so it is only applicable if the robot is in rooma. It establishes the value 0, so that the robot will be in roomb afterwards. This domain does not use explicit action_costs (as encoded in the `metric` -section), so the final line is `0`. (The search code will treat problems with -no explicit action costs as unit-cost problems though, so the action will be +section), so the final line is `0`. (The search code will treat tasks with +no explicit action costs as unit-cost tasks though, so the action will be handled as if its cost were 1.) The two pick-up operators are similar, so we only explain the last one. @@ -554,7 +554,7 @@ generated for domains that contain derived predicates, but they can also be generated for PDDL tasks without derived predicates if they use non-STRIPS features such as universally quantified conditions, as some of these are compiled away with the help of axioms. As an example, here -is an axiom rules from a Miconic-FullADL task: +is an axiom rule from a Miconic-FullADL task: *Sample axiom section (Miconic-FullADL domain):* From 6900aa1a20348434bac6964803c81b06979dada7 Mon Sep 17 00:00:00 2001 From: Claudia Grundke Date: Fri, 24 Jul 2026 16:59:52 +0200 Subject: [PATCH 15/20] Rename task_name and task_domain_name. --- src/translate/pddl_parser/parsing_functions.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/translate/pddl_parser/parsing_functions.py b/src/translate/pddl_parser/parsing_functions.py index d280c7166b..26f6a57f8d 100644 --- a/src/translate/pddl_parser/parsing_functions.py +++ b/src/translate/pddl_parser/parsing_functions.py @@ -627,17 +627,17 @@ def parse_task(domain_pddl, problem_pddl): predicate_dict, functions, actions, axioms = parse_domain_pddl(context, domain_pddl) if not isinstance(problem_pddl, list): context.error("Invalid definition of a PDDL problem.") - task_name, task_domain_name, task_requirements, objects, init, goal, \ + problem_name, problem_domain_name, problem_requirements, objects, init, goal, \ use_metric = parse_problem_pddl(context, problem_pddl, type_dict, predicate_dict, {c.name for c in constants}) - if domain_name != task_domain_name: + if domain_name != problem_domain_name: context.error(f"The domain name specified by the task " - f"({task_domain_name}) does not match the name specified " + f"({problem_domain_name}) does not match the name specified " f"by the domain file ({domain_name}).") requirements = pddl.Requirements(sorted(set( domain_requirements.requirements + - task_requirements.requirements))) + problem_requirements.requirements))) objects = constants + objects check_for_duplicates(context, [o.name for o in objects], "object") @@ -646,7 +646,7 @@ def parse_task(domain_pddl, problem_pddl): init += [pddl.Atom("=", (obj.name, obj.name)) for obj in objects] return pddl.Task( - domain_name, task_name, requirements, types, objects, + domain_name, problem_name, requirements, types, objects, predicates, functions, init, goal, actions, axioms, use_metric) From 5e25f410a7fe82942898c43ffeecb720df9eb552 Mon Sep 17 00:00:00 2001 From: Gabriele Roeger Date: Mon, 27 Jul 2026 12:00:43 +0200 Subject: [PATCH 16/20] Revert "Rename task_name and task_domain_name." This reverts commit 6900aa1a20348434bac6964803c81b06979dada7. --- src/translate/pddl_parser/parsing_functions.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/translate/pddl_parser/parsing_functions.py b/src/translate/pddl_parser/parsing_functions.py index 26f6a57f8d..d280c7166b 100644 --- a/src/translate/pddl_parser/parsing_functions.py +++ b/src/translate/pddl_parser/parsing_functions.py @@ -627,17 +627,17 @@ def parse_task(domain_pddl, problem_pddl): predicate_dict, functions, actions, axioms = parse_domain_pddl(context, domain_pddl) if not isinstance(problem_pddl, list): context.error("Invalid definition of a PDDL problem.") - problem_name, problem_domain_name, problem_requirements, objects, init, goal, \ + task_name, task_domain_name, task_requirements, objects, init, goal, \ use_metric = parse_problem_pddl(context, problem_pddl, type_dict, predicate_dict, {c.name for c in constants}) - if domain_name != problem_domain_name: + if domain_name != task_domain_name: context.error(f"The domain name specified by the task " - f"({problem_domain_name}) does not match the name specified " + f"({task_domain_name}) does not match the name specified " f"by the domain file ({domain_name}).") requirements = pddl.Requirements(sorted(set( domain_requirements.requirements + - problem_requirements.requirements))) + task_requirements.requirements))) objects = constants + objects check_for_duplicates(context, [o.name for o in objects], "object") @@ -646,7 +646,7 @@ def parse_task(domain_pddl, problem_pddl): init += [pddl.Atom("=", (obj.name, obj.name)) for obj in objects] return pddl.Task( - domain_name, problem_name, requirements, types, objects, + domain_name, task_name, requirements, types, objects, predicates, functions, init, goal, actions, axioms, use_metric) From d4c4fec51648f831ad11689cf8f836e9a60a34ff Mon Sep 17 00:00:00 2001 From: Gabriele Roeger Date: Mon, 27 Jul 2026 12:01:03 +0200 Subject: [PATCH 17/20] Revert "Rename task to problem in pddl/tasks.py." This reverts commit bf3c60f6e086d49647ff822c9ddca389e238be23. --- src/translate/pddl/tasks.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/translate/pddl/tasks.py b/src/translate/pddl/tasks.py index b9d79259e7..d473388240 100644 --- a/src/translate/pddl/tasks.py +++ b/src/translate/pddl/tasks.py @@ -11,7 +11,7 @@ from translate.pddl.predicates import Predicate class Task: - def __init__(self, domain_name: str, problem_name: str, + def __init__(self, domain_name: str, task_name: str, requirements: "Requirements", types: List[Type], objects: List[TypedObject], predicates: List[Predicate], functions: List[Function], @@ -19,7 +19,7 @@ def __init__(self, domain_name: str, problem_name: str, actions: List[Action], axioms: List[Axiom], use_metric: bool) -> None: self.domain_name = domain_name - self.problem_name = problem_name + self.task_name = task_name self.requirements = requirements self.types = types self.objects = objects @@ -41,9 +41,8 @@ def add_axiom(self, parameters, condition): return axiom def dump(self): - print("Domain:", self.domain_name) - print("Problem:", self.problem_name) - print("Requirements:", self.requirements) + print("Problem %s: %s [%s]" % ( + self.domain_name, self.task_name, self.requirements)) print("Types:") for type in self.types: print(" %s" % type) From c247f1b6d36e2b0338179ff99cd4213ebf10461f Mon Sep 17 00:00:00 2001 From: Gabriele Roeger Date: Mon, 27 Jul 2026 12:01:21 +0200 Subject: [PATCH 18/20] Revert "rename task to problem when talking about PDDL files" This reverts commit baa1af81b080df6f1bbba23e03e65360dd845e71. --- src/translate/main.py | 2 +- src/translate/options.py | 2 +- src/translate/pddl_parser/parsing_functions.py | 14 +++++++------- src/translate/pddl_parser/pddl_file.py | 10 +++++----- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/translate/main.py b/src/translate/main.py index 1ee0da6aae..d047353677 100755 --- a/src/translate/main.py +++ b/src/translate/main.py @@ -693,7 +693,7 @@ def main(): timer = timers.Timer() with timers.timing("Parsing", True): task = pddl_parser.open( - domain_filename=get_options().domain, problem_filename=get_options().problem) + domain_filename=get_options().domain, task_filename=get_options().task) with timers.timing("Normalizing task"): normalize.normalize(task) diff --git a/src/translate/options.py b/src/translate/options.py index 825e6588bc..f5ab86a9d2 100644 --- a/src/translate/options.py +++ b/src/translate/options.py @@ -33,7 +33,7 @@ def get_arg_parser(): argparser.add_argument( "domain", metavar="DOMAIN", help="path to domain pddl file") argparser.add_argument( - "problem", metavar="PROBLEM", help="path to problem pddl file") + "task", metavar="TASK", help="path to task pddl file") argparser.add_argument( "--relaxed", dest="generate_relaxed_task", action="store_true", help="output relaxed task (no delete effects)") diff --git a/src/translate/pddl_parser/parsing_functions.py b/src/translate/pddl_parser/parsing_functions.py index d280c7166b..025e4ce497 100644 --- a/src/translate/pddl_parser/parsing_functions.py +++ b/src/translate/pddl_parser/parsing_functions.py @@ -619,16 +619,16 @@ def parse_init(context, alist, predicate_dict, term_names): return initial -def parse_task(domain_pddl, problem_pddl): +def parse_task(domain_pddl, task_pddl): context = Context() if not isinstance(domain_pddl, list): context.error("Invalid definition of a PDDL domain.") domain_name, domain_requirements, types, type_dict, constants, predicates, \ predicate_dict, functions, actions, axioms = parse_domain_pddl(context, domain_pddl) - if not isinstance(problem_pddl, list): - context.error("Invalid definition of a PDDL problem.") + if not isinstance(task_pddl, list): + context.error("Invalid definition of a PDDL task.") task_name, task_domain_name, task_requirements, objects, init, goal, \ - use_metric = parse_problem_pddl(context, problem_pddl, type_dict, + use_metric = parse_task_pddl(context, task_pddl, type_dict, predicate_dict, {c.name for c in constants}) if domain_name != task_domain_name: @@ -738,9 +738,9 @@ def parse_domain_pddl(context, domain_pddl): yield the_axioms -def parse_problem_pddl(context, problem_pddl, type_dict, predicate_dict, constant_names): - iterator = iter(problem_pddl) - with context.layer("Parsing problem"): +def parse_task_pddl(context, task_pddl, type_dict, predicate_dict, constant_names): + iterator = iter(task_pddl) + with context.layer("Parsing task"): try: define_tag = next(iterator) if define_tag != "define": diff --git a/src/translate/pddl_parser/pddl_file.py b/src/translate/pddl_parser/pddl_file.py index b202e7e6d8..98d2bc7b17 100644 --- a/src/translate/pddl_parser/pddl_file.py +++ b/src/translate/pddl_parser/pddl_file.py @@ -22,8 +22,8 @@ def parse_pddl_file(type, filename): (type, filename, e)) -def open(domain_filename=None, problem_filename=None): - if domain_filename is None or problem_filename is None: +def open(domain_filename=None, task_filename=None): + if domain_filename is None or task_filename is None: # Importing options triggers parsing the problem and domain file names # as arguments from the command line. We don't import unconditionally # at the head of this file because open is exposed in __init__.py @@ -31,9 +31,9 @@ def open(domain_filename=None, problem_filename=None): # external code would then trigger this arg parse. from translate.options import get_options domain_filename = domain_filename or get_options().domain - problem_filename = problem_filename or get_options().problem + task_filename = task_filename or get_options().task domain_pddl = parse_pddl_file("domain", domain_filename) - problem_pddl = parse_pddl_file("problem", problem_filename) + task_pddl = parse_pddl_file("task", task_filename) - return parsing_functions.parse_task(domain_pddl, problem_pddl) + return parsing_functions.parse_task(domain_pddl, task_pddl) From 47cbe2adbcfd63240ce506380a8e62a945d53a47 Mon Sep 17 00:00:00 2001 From: Gabriele Roeger Date: Mon, 27 Jul 2026 12:01:35 +0200 Subject: [PATCH 19/20] Revert "uppercase meta variables for positional arguments in translator" This reverts commit f479b91f878603ccf970d2ada2ae731cf883b36b. --- src/translate/options.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/translate/options.py b/src/translate/options.py index f5ab86a9d2..1943b60a1f 100644 --- a/src/translate/options.py +++ b/src/translate/options.py @@ -31,9 +31,9 @@ def get_arg_parser(): # process (issue1217). argparser = argparse.ArgumentParser(prog=infer_prog()) argparser.add_argument( - "domain", metavar="DOMAIN", help="path to domain pddl file") + "domain", help="path to domain pddl file") argparser.add_argument( - "task", metavar="TASK", help="path to task pddl file") + "task", help="path to task pddl file") argparser.add_argument( "--relaxed", dest="generate_relaxed_task", action="store_true", help="output relaxed task (no delete effects)") From b77f5ffacca48523d206a74682e2b883797c37d0 Mon Sep 17 00:00:00 2001 From: Gabriele Roeger Date: Mon, 27 Jul 2026 12:34:10 +0200 Subject: [PATCH 20/20] nicer toc entries --- misc/autodoc/generate-translate-docs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/misc/autodoc/generate-translate-docs.py b/misc/autodoc/generate-translate-docs.py index b1d1b2680c..d0906eb6a0 100755 --- a/misc/autodoc/generate-translate-docs.py +++ b/misc/autodoc/generate-translate-docs.py @@ -53,6 +53,7 @@ def import_argparser_from_translator(): def action_to_markdown(parser: argparse.ArgumentParser, action: argparse.Action): names = [] for opt in action.option_strings: + toc_entry = opt if action.choices is not None: choice_str = ",".join(map(str, action.choices)) names.append(f"`{opt} {{{choice_str}}}`") @@ -81,7 +82,7 @@ def action_to_markdown(parser: argparse.ArgumentParser, action: argparse.Action) except Exception: pass - return f"### {name}\n{help_text}\n" + return f"### {name} {{: data-toc-label=\"{toc_entry}\"}}\n{help_text}\n" def parser_to_markdown(parser: argparse.ArgumentParser):