### Install Pyperplan from source using uv Source: https://github.com/aibasel/pyperplan/blob/main/README.md Install Pyperplan in editable mode from a local repository clone using uv. ```bash uv pip install --editable . ``` -------------------------------- ### Get Pyperplan help Source: https://github.com/aibasel/pyperplan/blob/main/README.md Display available search algorithms and heuristics for the Pyperplan planner. ```bash pyperplan --help ``` -------------------------------- ### Install Pyperplan using uv Source: https://github.com/aibasel/pyperplan/blob/main/README.md Install Pyperplan from the Python Package Index (PyPI) using the uv tool. ```bash uv tool install pyperplan ``` -------------------------------- ### Install and Run Tox Tests Source: https://github.com/aibasel/pyperplan/blob/main/doc/documentation.md Install tox using pip and then run it to execute the test suite. This is preferably done within a virtual environment. ```bash pip install tox tox ``` -------------------------------- ### Install VAL for Plan Validation Source: https://github.com/aibasel/pyperplan/blob/main/doc/documentation.md Steps to install the VAL plan validation tool on Ubuntu. This involves installing dependencies, cloning the VAL repository, checking out a specific commit, and compiling. ```bash sudo apt install bison flex g++ git make git clone https://github.com/KCL-Planning/VAL.git cd VAL # Newer VAL versions need time stamps, so we use an old version # (https://github.com/KCL-Planning/VAL/issues/46). git checkout a556539 make clean # Remove old binaries. sed -i 's/-Werror //g' Makefile # Ignore warnings. make cp validate ~/bin/ # Add binary to a directory on your ``PATH``. ``` -------------------------------- ### Create Root Search Node Source: https://github.com/aibasel/pyperplan/blob/main/pyperplan/search/instructions.txt Use this function to create the root node for the initial state of a planning task. This is the starting point for building the search space. ```python searchspace.make_root_node(...) ``` -------------------------------- ### Implement Complete Planning Pipeline Source: https://context7.com/aibasel/pyperplan/llms.txt A full workflow demonstrating parsing, grounding, heuristic initialization, and searching for a solution. ```python import logging from pyperplan.pddl.parser import Parser from pyperplan.grounding import ground from pyperplan.search import greedy_best_first_search from pyperplan.heuristics.relaxation import hFFHeuristic from pyperplan.planner import write_solution # Enable logging for debugging logging.basicConfig(level=logging.INFO, format='%(message)s') def solve_planning_problem(domain_file, problem_file): """Complete pipeline to solve a PDDL planning problem.""" # Step 1: Parse PDDL files logging.info(f"Parsing domain: {domain_file}") logging.info(f"Parsing problem: {problem_file}") parser = Parser(domain_file, problem_file) domain = parser.parse_domain() problem = parser.parse_problem(domain) logging.info(f"Domain '{domain.name}' has {len(domain.actions)} actions") logging.info(f"Problem '{problem.name}' has {len(problem.objects)} objects") # Step 2: Ground the task logging.info("Grounding task...") task = ground(problem) logging.info(f"Grounded task has {len(task.operators)} operators") logging.info(f"Grounded task has {len(task.facts)} facts") # Step 3: Initialize heuristic logging.info("Initializing FF heuristic...") heuristic = hFFHeuristic(task) # Step 4: Run search logging.info("Starting greedy best-first search...") solution = greedy_best_first_search(task, heuristic) # Step 5: Process solution if solution: logging.info(f"Solution found with {len(solution)} actions:") for i, op in enumerate(solution, 1): logging.info(f" {i}. {op.name}") # Write solution to file solution_file = problem_file + ".soln" write_solution(solution, solution_file) logging.info(f"Solution written to: {solution_file}") return solution else: logging.warning("No solution found!") return None # Run the complete pipeline solution = solve_planning_problem( "benchmarks/blocks/domain.pddl", "benchmarks/blocks/task01.pddl" ) ``` -------------------------------- ### Execute Pyperplan via Command Line Source: https://context7.com/aibasel/pyperplan/llms.txt Run the planner using domain and problem files with configurable search algorithms and heuristics. ```bash # Basic usage with domain and problem files pyperplan benchmarks/blocks/domain.pddl benchmarks/blocks/task01.pddl # Let pyperplan auto-detect the domain file pyperplan benchmarks/blocks/task01.pddl # Use greedy best-first search with FF heuristic pyperplan -H hff -s gbfs benchmarks/blocks/domain.pddl benchmarks/blocks/task01.pddl # Use A* search with landmark heuristic pyperplan -H landmark -s astar benchmarks/tpp/domain.pddl benchmarks/tpp/task01.pddl # Use weighted A* search with hAdd heuristic pyperplan -H hadd -s wastar benchmarks/gripper/domain.pddl benchmarks/gripper/task01.pddl # Enable debug logging pyperplan -l debug benchmarks/blocks/domain.pddl benchmarks/blocks/task01.pddl # Available search algorithms: astar, wastar, gbfs, bfs, ehs, ids, sat # Available heuristics: blind, hadd, hmax, hff, hsa, landmark, lmcut pyperplan --help ``` -------------------------------- ### Manage Search Space with SearchNode Source: https://context7.com/aibasel/pyperplan/llms.txt Demonstrates creating a root node, expanding states, and extracting a solution path once the goal is reached. ```python from pyperplan.search.searchspace import SearchNode, make_root_node, make_child_node from pyperplan.pddl.parser import Parser from pyperplan.grounding import ground # Parse and ground the task parser = Parser("benchmarks/blocks/domain.pddl", "benchmarks/blocks/task01.pddl") problem = parser.parse_problem(parser.parse_domain()) task = ground(problem) # Create the root node root = make_root_node(task.initial_state) print(f"Root node g-value: {root.g}") # 0 print(f"Root node has parent: {root.parent is not None}") # False # Expand the root node for op, successor_state in task.get_successor_states(root.state): child = make_child_node(root, op, successor_state) print(f"Child after {op.name}: g={child.g}") # Check if we reached the goal if task.goal_reached(successor_state): # Extract the solution path solution = child.extract_solution() print(f"Solution found: {[op.name for op in solution]}") break ``` -------------------------------- ### Run Pyperplan planner Source: https://github.com/aibasel/pyperplan/blob/main/README.md Execute the Pyperplan planner with a PDDL domain and problem file. The plan will be saved with a .soln extension. ```bash pyperplan benchmarks/tpp/domain.pddl benchmarks/tpp/task01.pddl ``` -------------------------------- ### Pyperplan Search Algorithms Source: https://context7.com/aibasel/pyperplan/llms.txt Demonstrates how to use various search algorithms provided by Pyperplan to find a plan for a given task. Imports include `Parser`, `ground`, and specific search functions. Heuristics like `hFFHeuristic` can be used with informed search algorithms. ```python from pyperplan.pddl.parser import Parser from pyperplan.grounding import ground from pyperplan.search import ( breadth_first_search, astar_search, greedy_best_first_search, weighted_astar_search, enforced_hillclimbing_search, iterative_deepening_search ) from pyperplan.heuristics.relaxation import hFFHeuristic # Parse and ground the task parser = Parser("benchmarks/gripper/domain.pddl", "benchmarks/gripper/task01.pddl") problem = parser.parse_problem(parser.parse_domain()) task = ground(problem) # Breadth-first search (optimal, complete, uninformed) solution = breadth_first_search(task) # A* search (optimal with admissible heuristic) heuristic = hFFHeuristic(task) solution = astar_search(task, heuristic) # Greedy best-first search (fast but not optimal) solution = greedy_best_first_search(task, heuristic) # Weighted A* search (bounded suboptimal) solution = weighted_astar_search(task, heuristic, weight=5) # Enforced hill climbing (incomplete but very fast) solution = enforced_hillclimbing_search(task, heuristic) # Iterative deepening search (optimal, complete, uninformed) solution = iterative_deepening_search(task) if solution: print(f"Found plan with {len(solution)} actions") ``` -------------------------------- ### Run SAT Planner Source: https://github.com/aibasel/pyperplan/blob/main/doc/documentation.md To use the SAT planner, ensure the 'minisat' executable is in your system's PATH. Run the planner with the --search sat option. ```bash pyperplan --search sat ``` -------------------------------- ### Run Pyperplan with heuristic search Source: https://github.com/aibasel/pyperplan/blob/main/README.md Execute Pyperplan using greedy-best-first search with the FF heuristic. Specify the domain and problem files. ```bash pyperplan -H hff -s gbfs DOMAIN PROBLEM ``` -------------------------------- ### Use Logging in Search Algorithms Source: https://github.com/aibasel/pyperplan/blob/main/pyperplan/search/instructions.txt Integrate logging into your search algorithm implementation by importing the logging module and using its functions, such as logging.info(). ```python import logging logging.info(...) ``` -------------------------------- ### Utilize Built-in Heuristics Source: https://context7.com/aibasel/pyperplan/llms.txt Shows how to instantiate and apply various informed search heuristics to a search node. ```python from pyperplan.pddl.parser import Parser from pyperplan.grounding import ground from pyperplan.search.searchspace import make_root_node from pyperplan.heuristics.blind import BlindHeuristic from pyperplan.heuristics.relaxation import ( hAddHeuristic, hMaxHeuristic, hFFHeuristic, hSAHeuristic ) from pyperplan.heuristics.landmarks import LandmarkHeuristic # Parse and ground the task parser = Parser("benchmarks/blocks/domain.pddl", "benchmarks/blocks/task01.pddl") problem = parser.parse_problem(parser.parse_domain()) task = ground(problem) # Create the initial search node root = make_root_node(task.initial_state) # Blind heuristic (returns 0 at goal, 1 otherwise) blind = BlindHeuristic(task) print(f"Blind h-value: {blind(root)}") # hAdd heuristic (sum of costs to achieve subgoals) hadd = hAddHeuristic(task) print(f"hAdd h-value: {hadd(root)}") # hMax heuristic (maximum cost among subgoals) hmax = hMaxHeuristic(task) print(f"hMax h-value: {hmax(root)}") # hFF heuristic (based on relaxed plan length) hff = hFFHeuristic(task) print(f"hFF h-value: {hff(root)}") # hFF with relaxed plan extraction (for preferred operators) h_value, relaxed_plan = hff.calc_h_with_plan(root) print(f"hFF h-value: {h_value}, relaxed plan size: {len(relaxed_plan) if relaxed_plan else 0}") # Landmark heuristic (based on landmark counting) landmark = LandmarkHeuristic(task) print(f"Landmark h-value: {landmark(root)}") ``` -------------------------------- ### Validate and Write Solutions Source: https://context7.com/aibasel/pyperplan/llms.txt Imports necessary utilities for handling PDDL solution output and validation. ```python from pyperplan.planner import ( search_plan, write_solution, validate_solution, validator_available, SEARCHES, HEURISTICS ) ``` -------------------------------- ### Execute Planning Search Source: https://context7.com/aibasel/pyperplan/llms.txt Perform a search for a plan using specified domain and problem files, then optionally validate the output. ```python solution = search_plan( domain_file="benchmarks/blocks/domain.pddl", problem_file="benchmarks/blocks/task01.pddl", search=SEARCHES["gbfs"], heuristic_class=HEURISTICS["hff"] ) if solution: # Write solution to file solution_file = "benchmarks/blocks/task01.pddl.soln" write_solution(solution, solution_file) # The solution file contains one action per line: # (pick-up b) # (stack b a) # (pick-up c) # (stack c b) # ... # Validate solution if VAL validator is available if validator_available(): is_valid = validate_solution( domain_file="benchmarks/blocks/domain.pddl", problem_file="benchmarks/blocks/task01.pddl", solution_file=solution_file ) print(f"Solution valid: {is_valid}") else: print("VAL validator not found on PATH") ``` -------------------------------- ### Add Logging Output Source: https://github.com/aibasel/pyperplan/blob/main/doc/documentation.md To add custom logging output, import the 'logging' package and use logging.info() to record messages. ```python import logging logging.info("My log message") ``` -------------------------------- ### Find Plans Programmatically Source: https://context7.com/aibasel/pyperplan/llms.txt Use the search_plan function to solve planning tasks by specifying domain, problem, search algorithm, and heuristic. ```python from pyperplan.planner import search_plan, SEARCHES, HEURISTICS # Find a plan using breadth-first search (no heuristic needed) solution = search_plan( domain_file="benchmarks/blocks/domain.pddl", problem_file="benchmarks/blocks/task01.pddl", search=SEARCHES["bfs"], heuristic_class=None ) # Find a plan using A* with the FF heuristic solution = search_plan( domain_file="benchmarks/blocks/domain.pddl", problem_file="benchmarks/blocks/task01.pddl", search=SEARCHES["astar"], heuristic_class=HEURISTICS["hff"] ) # Find a plan using greedy best-first search with landmarks solution = search_plan( domain_file="benchmarks/tpp/domain.pddl", problem_file="benchmarks/tpp/task01.pddl", search=SEARCHES["gbfs"], heuristic_class=HEURISTICS["landmark"] ) if solution: print(f"Plan found with {len(solution)} steps:") for op in solution: print(f" {op.name}") else: print("No solution found") ``` -------------------------------- ### Ground Planning Tasks Source: https://context7.com/aibasel/pyperplan/llms.txt Transform parsed PDDL into a grounded task using the ground function. ```python from pyperplan.pddl.parser import Parser from pyperplan.grounding import ground # Parse domain and problem parser = Parser("benchmarks/blocks/domain.pddl", "benchmarks/blocks/task01.pddl") domain = parser.parse_domain() problem = parser.parse_problem(domain) ``` -------------------------------- ### Implement Search Algorithm Function Source: https://github.com/aibasel/pyperplan/blob/main/pyperplan/search/instructions.txt Search algorithms are typically implemented as single functions with a '_search' suffix. Ensure the function is imported in the package's __init__.py for convenient use. ```python def my_algorithm_search(): # Implementation of the search algorithm pass ``` -------------------------------- ### Define PDDL Problem Source: https://context7.com/aibasel/pyperplan/llms.txt Specify initial states and goals for a PDDL planning problem. ```lisp ;; Example: Logistics problem (define (problem logistics-4-0) (:domain logistics) (:objects city1 city2 - city loc1 loc2 loc3 loc4 - location truck1 truck2 - truck package1 package2 - package ) (:init ;; Locations in cities (in-city loc1 city1) (in-city loc2 city1) (in-city loc3 city2) (in-city loc4 city2) ;; Initial truck positions (at truck1 loc1) (at truck2 loc3) ;; Initial package positions (at package1 loc1) (at package2 loc2) ) (:goal (and (at package1 loc3) (at package2 loc4) )) ) ``` -------------------------------- ### Ground a PDDL problem into a planning task Source: https://context7.com/aibasel/pyperplan/llms.txt Use the `ground` function to convert a parsed PDDL problem into a grounded task object. This prepares the problem for search algorithms. Options allow for removing static facts and irrelevant operators. ```python task = ground( problem, remove_statics_from_initial_state=True, remove_irrelevant_operators=True ) print(f"Task: {task.name}") print(f"Number of facts: {len(task.facts)}") print(f"Number of operators: {len(task.operators)}") print(f"Initial state: {task.initial_state}") print(f"Goals: {task.goals}") # Examine grounded operators for op in list(task.operators)[:3]: print(f"\nOperator: {op.name}") print(f" Preconditions: {op.preconditions}") print(f" Add effects: {op.add_effects}") print(f" Delete effects: {op.del_effects}") ``` -------------------------------- ### Task Class for STRIPS Planning Source: https://context7.com/aibasel/pyperplan/llms.txt The `Task` class represents a grounded STRIPS planning task. It is essential for search algorithms and includes methods for state manipulation and successor generation. Requires `Task` and `Operator` imports. ```python from pyperplan.task import Task, Operator # Create operators manually for a simple domain op_pickup_a = Operator( name="(pick-up a)", preconditions=frozenset(["(clear a)", "(ontable a)", "(handempty)"]), add_effects=frozenset(["(holding a)"]), del_effects=frozenset(["(clear a)", "(ontable a)", "(handempty)"]) ) op_stack_a_b = Operator( name="(stack a b)", preconditions=frozenset(["(holding a)", "(clear b)"]), add_effects=frozenset(["(on a b)", "(clear a)", "(handempty)"]), del_effects=frozenset(["(holding a)", "(clear b)"]) ) # Create a planning task task = Task( name="simple-blocks", facts={"(clear a)", "(clear b)", "(ontable a)", "(ontable b)", "(handempty)", "(holding a)", "(on a b)"}, initial_state=frozenset(["(clear a)", "(clear b)", "(ontable a)", "(ontable b)", "(handempty)"]), goals=frozenset(["(on a b)"]), operators=[op_pickup_a, op_stack_a_b] ) # Check if goal is reached state = task.initial_state print(f"Goal reached: {task.goal_reached(state)}") # False # Get successor states successors = task.get_successor_states(state) for op, new_state in successors: print(f"Applying {op.name} leads to state with {len(new_state)} facts") ``` -------------------------------- ### Extract Solution from Goal Node Source: https://github.com/aibasel/pyperplan/blob/main/pyperplan/search/instructions.txt Call this method on a goal node to retrieve the plan. This function is available on SearchNode objects once a goal state is reached. ```python extract_solution() ``` -------------------------------- ### search_plan Function Source: https://context7.com/aibasel/pyperplan/llms.txt The primary programmatic interface for finding a solution to a planning problem by specifying domain, problem, search algorithm, and heuristic. ```APIDOC ## search_plan(domain_file, problem_file, search, heuristic_class) ### Description Parses domain and problem files, grounds the task, and executes the specified search algorithm using the provided heuristic to find a plan. ### Parameters - **domain_file** (string) - Required - Path to the PDDL domain file. - **problem_file** (string) - Required - Path to the PDDL problem file. - **search** (object) - Required - The search algorithm instance (e.g., from SEARCHES). - **heuristic_class** (object) - Optional - The heuristic class to use (e.g., from HEURISTICS). ### Response - **solution** (list) - A list of operators representing the plan if found, otherwise None. ``` -------------------------------- ### Parse PDDL Files Source: https://context7.com/aibasel/pyperplan/llms.txt Construct internal representations of domain and problem files using the Parser class. ```python from pyperplan.pddl.parser import Parser # Create parser with domain and problem files parser = Parser( domFile="benchmarks/blocks/domain.pddl", probFile="benchmarks/blocks/task01.pddl" ) # Parse the domain first domain = parser.parse_domain() print(f"Domain: {domain.name}") print(f"Predicates: {list(domain.predicates.keys())}") print(f"Actions: {list(domain.actions.keys())}") # Parse the problem (requires the domain) problem = parser.parse_problem(domain) print(f"Problem: {problem.name}") print(f"Objects: {list(problem.objects.keys())}") print(f"Initial state facts: {len(problem.initial_state)}") print(f"Goal facts: {len(problem.goal)}") # Example output for blocks domain: # Domain: BLOCKS # Predicates: ['on', 'ontable', 'clear', 'handempty', 'holding'] # Actions: ['pick-up', 'put-down', 'stack', 'unstack'] # Problem: BLOCKS-4-0 # Objects: ['D', 'B', 'A', 'C'] ``` -------------------------------- ### ground Function Source: https://context7.com/aibasel/pyperplan/llms.txt Converts a parsed PDDL problem into a grounded planning task. ```APIDOC ## ground(domain, problem) ### Description Instantiates action schemas with actual objects and performs relevance analysis to produce a grounded planning task. ``` -------------------------------- ### Operator Class for Planning Operators Source: https://context7.com/aibasel/pyperplan/llms.txt The `Operator` class defines a grounded planning operator, including its name, preconditions, add effects, and delete effects. It provides methods to check applicability and apply the operator to a given state. Note that add effects take precedence over delete effects for the same fact. ```python from pyperplan.task import Operator # Create an operator operator = Operator( name="(drive truck1 cityA cityB)", preconditions=frozenset(["(at truck1 cityA)", "(connected cityA cityB)"]), add_effects=frozenset(["(at truck1 cityB)"]), del_effects=frozenset(["(at truck1 cityA)"]) ) # Check applicability to a state state = frozenset(["(at truck1 cityA)", "(connected cityA cityB)", "(package1 cityA)"]) print(f"Applicable: {operator.applicable(state)}") # True # Apply the operator new_state = operator.apply(state) print(f"New state: {new_state}") # Output: frozenset({'(at truck1 cityB)', '(connected cityA cityB)', '(package1 cityA)'}) # Operator with conflicting effects (add wins over delete) op_with_conflict = Operator( name="(special-op)", preconditions=frozenset(["(fact1)"]), add_effects=frozenset(["(fact2)", "(fact3)"]), del_effects=frozenset(["(fact2)", "(fact4)"]) # fact2 is both added and deleted ) # When applied, fact2 will be in the resulting state (add effects win) ``` -------------------------------- ### Parser Class Source: https://context7.com/aibasel/pyperplan/llms.txt Handles the reading and internal representation of PDDL domain and problem files. ```APIDOC ## Parser(domFile, probFile) ### Description Constructs a parser instance to process PDDL files. ### Methods - **parse_domain()**: Parses the domain file and returns a domain object. - **parse_problem(domain)**: Parses the problem file using the provided domain object and returns a problem object. ``` -------------------------------- ### Define PDDL Domain Source: https://context7.com/aibasel/pyperplan/llms.txt Structure a PDDL domain file using STRIPS and typing requirements. ```lisp ;; Example: Logistics domain (simplified) (define (domain logistics) (:requirements :strips :typing) (:types city location - object truck package - object ) (:predicates (at ?obj - object ?loc - location) (in ?pkg - package ?truck - truck) (in-city ?loc - location ?city - city) ) (:action load-truck :parameters (?pkg - package ?truck - truck ?loc - location) :precondition (and (at ?truck ?loc) (at ?pkg ?loc)) :effect (and (in ?pkg ?truck) (not (at ?pkg ?loc))) ) (:action unload-truck :parameters (?pkg - package ?truck - truck ?loc - location) :precondition (and (at ?truck ?loc) (in ?pkg ?truck)) :effect (and (at ?pkg ?loc) (not (in ?pkg ?truck))) ) (:action drive-truck :parameters (?truck - truck ?from - location ?to - location ?city - city) :precondition (and (at ?truck ?from) (in-city ?from ?city) (in-city ?to ?city)) :effect (and (at ?truck ?to) (not (at ?truck ?from))) ) ) ``` -------------------------------- ### Create Child Search Node Source: https://github.com/aibasel/pyperplan/blob/main/pyperplan/search/instructions.txt Use this function to create a new node representing a state after applying an operator. It requires the current search node as the parent to build a tree-like structure. ```python searchspace.make_child_node(...) ``` -------------------------------- ### Implement Custom Heuristics Source: https://context7.com/aibasel/pyperplan/llms.txt Extends the Heuristic base class to define custom logic for estimating distance to the goal. ```python from pyperplan.heuristics.heuristic_base import Heuristic from pyperplan.pddl.parser import Parser from pyperplan.grounding import ground from pyperplan.search import astar_search from pyperplan.search.searchspace import make_root_node class GoalCountHeuristic(Heuristic): """Simple heuristic that counts unsatisfied goal facts.""" def __init__(self, task): self.goals = task.goals def __call__(self, node): """Return the number of unsatisfied goals.""" unsatisfied = sum(1 for goal in self.goals if goal not in node.state) return unsatisfied class WeightedGoalCountHeuristic(Heuristic): """Goal count heuristic with weights for different goal types.""" def __init__(self, task, weights=None): self.goals = task.goals self.weights = weights or {} def __call__(self, node): total = 0 for goal in self.goals: if goal not in node.state: # Use weight if specified, otherwise default to 1 weight = self.weights.get(goal, 1) total += weight return total # Use custom heuristic parser = Parser("benchmarks/blocks/domain.pddl", "benchmarks/blocks/task01.pddl") problem = parser.parse_problem(parser.parse_domain()) task = ground(problem) # Use goal count heuristic with A* heuristic = GoalCountHeuristic(task) solution = astar_search(task, heuristic) print(f"Found solution with {len(solution)} steps") ``` -------------------------------- ### Pyperplan Citation Source: https://github.com/aibasel/pyperplan/blob/main/README.md BibTeX entry for citing Pyperplan in academic work. ```bibtex @Misc{alkhazraji-et-al-zenodo2020, author = "Yusra Alkhazraji and Matthias Frorath and Markus Gr{"u}tzner and Malte Helmert and Thomas Liebetraut and Robert Mattm{"u}ller and Manuela Ortlieb and Jendrik Seipp and Tobias Springenberg and Philip Stahl and Jan W{"u}lfing", title = "Pyperplan", publisher = "Zenodo", year = "2020", doi = "10.5281/zenodo.3700819", url = "https://doi.org/10.5281/zenodo.3700819", howpublished = "\url{https://doi.org/10.5281/zenodo.3700819}" } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.