Skip to content

Commit

Permalink
Added source files
Browse files Browse the repository at this point in the history
  • Loading branch information
TheAeryan authored Nov 3, 2022
1 parent a4429e7 commit 3eed76b
Show file tree
Hide file tree
Showing 7 changed files with 958 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/lifted_pddl/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# __init__.py

__version__ = "1.0.1"

from lifted_pddl.parser import Parser
170 changes: 170 additions & 0 deletions src/lifted_pddl/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
# __main__.py

import argparse
import sys
import os

from lifted_pddl.parser import Parser

# Execute the following code if the script is called from the command-line, i.e.,
# python -m lifted_parser
def main():
# Parse command-line arguments with module argparse
# Different options of use:
# > help: we show how to use this script from the command-line
# > example: we show an example of use, for the logistics domain
# > print_planning_task domain_file problem_file:
# we print the information encoded in the PDDL domain and problem, according to the format used in Parser.__str__()
# problem_file is an optional parameter. If not used, we assume there is no PDDL problem.
# > get_applicable_actions domain_file problem_file:
# we print the list of applicable actions at the init state of the planning task given by (domain_file, problem_file)
# > is_action_applicable domain_file problem_file action:
# we print 'True' if action @action is applicable at the init state of the planning task given by (domain_file, problem_file).
# @action must correspond to a string in standard PDDL form (e.g., '(drive t1 l1 l2 c1)')
# > get_next_state domain_file problem_file action:
# we print the next state resulting from applying the action @action at the current state (i.e., the init state of the
# planning task given by (domain_file, problem_file)). The state is printed as a list of its atoms in PDDL format
# (e.g., (at p1 l2) (in-city l1 c5) ...)

cli_parser = argparse.ArgumentParser(prog='Lifted Parser',
description='This program makes possible to parse PDDL domains and problems to obtain their information, \
obtain the applicable actions in an efficient manner (without grounding), and obtain the state \
resulting from applying an action at the current state (successor function).')

cli_parser.add_argument('execution_mode', choices=('example', 'print_planning_task', 'get_applicable_actions', 'is_action_applicable', 'get_next_state'),
help="Execution mode, i.e., what this program will do. There are several options: example -> shows an example of use for the logistics domain, \
print_planning_task -> prints the information encoded in the PDDL domain (and also the PDDL problem if it's passed as an argument), \
get_applicable_actions -> prints the ground actions applicable at the init state of the problem passed as an argument, \
is_action_applicable -> prints whether the action passed as an argument is applicable at the init state of the problem, \
get_next_state -> prints the next state (as a list of atoms) obtained by applying the action to the init state of the problem.")
cli_parser.add_argument('-d', '--domain', required=False, help='Path to the domain file')
cli_parser.add_argument('-p', '--problem', required=False, help='Path to the problem file')
cli_parser.add_argument('-a', '--action', required=False, help='Action in PDDL format (e.g., "(unload t1 p11 l1)" )')

args = cli_parser.parse_args()
execution_mode = args.execution_mode
domain_path = args.domain
problem_path = args.problem
action = args.action

# --- Example of use ---
if execution_mode == 'example':
# Change working directory to this file's location
os.chdir(os.path.realpath(os.path.dirname(__file__)))

# Parse logistics domain
parser = Parser()
parser.parse_domain('data/logistics-domain.pddl')
print("Parser information after parsing the domain\n", parser)

# Parse logistics problem
parser.parse_problem('data/logistics-problem.pddl')
print("\nParser information after parsing the domain AND problem\n", parser)

# Obtain actions applicable at the current state (given by logistics-problem.pddl)
print("\nApplicable actions:\n", parser.get_applicable_actions()) # Average execution time: 0.0007s
print("\nApplicable actions in PDDL format:\n", parser.encode_ground_actions_as_pddl(parser.get_applicable_actions(), 'str'))

# Check if individual actions are applicable
print("\nIs ('drive', (44, 15, 12, 1)) applicable?:", parser.is_action_applicable('drive', (44, 15, 12, 1)))
print("Is ('drive', (44, 15, 18, 1)) applicable?:", parser.is_action_applicable('drive', (44, 15, 18, 1)))
print("Is ('unload', (37, 64, 8)) applicable?:", parser.is_action_applicable('unload', (37, 64, 8)))

# Apply an action at the current state (given by logistics-problem.pddl) and obtain the next state
print("\nApply action ('drive', (44, 15, 12, 1)) and get next state:\n", parser.get_next_state('drive', (44, 15, 12, 1)))
print("\nApply action ('drive', (44, 15, 12, 1)) and get next state in PDDL format:\n", parser.encode_atoms_as_pddl(parser.get_next_state('drive', (44, 15, 12, 1)), 'str'))

# --- Print the information of the PDDL domain (and problem if given as argument) ---
elif execution_mode == 'print_planning_task':
if domain_path is None:
raise Exception('No domain provided')

parser = Parser()
parser.parse_domain(domain_path)
if problem_path is not None:
parser.parse_problem(problem_path)

print(parser)

# --- Print the ground actions which are applicable at the init state of the planning task ---
elif execution_mode == 'get_applicable_actions':
if domain_path is None:
raise Exception('No domain provided')
if problem_path is None:
raise Exception('No problem provided')

parser = Parser()
parser.parse_domain(domain_path)
parser.parse_problem(problem_path)

applicable_actions = parser.encode_ground_actions_as_pddl(parser.get_applicable_actions(), 'str')

# Print the applicable ground actions (in PDDL format)
for a in applicable_actions:
print(a)

# --- Print whether the action given as a parameter is applicable at the init state of the planning task ---
elif execution_mode == 'is_action_applicable':
if domain_path is None:
raise Exception('No domain provided')
if problem_path is None:
raise Exception('No problem provided')
if action is None:
raise Exception('No action provided')

parser = Parser()
parser.parse_domain(domain_path)
parser.parse_problem(problem_path)

action = action.strip('(').strip(')').split()

if len(action) == 0: # Action with no parameters
action_name = action[0]
action_params = tuple()
else:
action_name = action[0]
action_params = action[1:]

# Encode each object as an index (e.g., loc1 -> 2)
object_names = parser.object_names
action_params = tuple([object_names.index(param) for param in action_params])

# Print whether the actions is applicable ('True' or 'False')
print(parser.is_action_applicable(action_name, action_params))

# --- execution_mode == get_next_state ---
# --- Print the next state (as a list of atoms) resulting from applying the action given as a parameter to the init state of the planning task ---
else:
if domain_path is None:
raise Exception('No domain provided')
if problem_path is None:
raise Exception('No problem provided')
if action is None:
raise Exception('No action provided')

parser = Parser()
parser.parse_domain(domain_path)
parser.parse_problem(problem_path)

action = action.strip('(').strip(')').split()

if len(action) == 0: # Action with no parameters
raise Exception('Actions with no parameters (variables) are not supported')

action_name = action[0]
action_params = action[1:]

# Encode each object as an index (e.g., loc1 -> 2)
object_names = parser.object_names
action_params = tuple([object_names.index(param) for param in action_params])

next_state_atoms = parser.encode_atoms_as_pddl(parser.get_next_state(action_name, action_params), 'str')

# Print the atoms of the next state
for atom in next_state_atoms:
print(atom)


if __name__ == '__main__':
main()

53 changes: 53 additions & 0 deletions src/lifted_pddl/data/blocksworld-domain.pddl
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 4 Op-blocks world
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(define (domain blocksworld)
(:requirements :strips :typing)
(:types block)
(:predicates (on ?x - block ?y - block)
(ontable ?x - block)
(clear ?x - block)
(handempty)
(holding ?x - block)
)

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

(:action put-down
:parameters (?x - block)
:precondition (holding ?x)
:effect
(and (not (holding ?x))
(clear ?x)
(handempty)
(ontable ?x)))

(:action stack
:parameters (?x - block ?y - block)
:precondition (and (holding ?x) (clear ?y))
:effect
(and (not (holding ?x))
(not (clear ?y))
(clear ?x)
(handempty)
(on ?x ?y)))

(:action unstack
:parameters (?x - block ?y - block)
:precondition (and (on ?x ?y) (clear ?x)
(handempty))
:effect
(and (holding ?x)
(clear ?y)
(not (clear ?x))
(not (handempty))
(not (on ?x ?y)))))
43 changes: 43 additions & 0 deletions src/lifted_pddl/data/blocksworld-problem.pddl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
(define (problem bw_both_generative_policies_8)

(:domain blocksworld)

(:objects
obj0 obj1 obj2 obj3 obj4 obj5 obj6 obj7 obj8 obj9 obj10 - block
)

(:init
(ontable obj0)
(ontable obj1)
(ontable obj2)
(on obj3 obj1)
(on obj4 obj0)
(on obj5 obj4)
(on obj6 obj2)
(on obj7 obj5)
(on obj8 obj7)
(on obj9 obj3)
(clear obj8)
(clear obj6)
(clear obj9)
(holding obj10)
)

(:goal (and
(holding obj7)
(ontable obj8)
(ontable obj10)
(on obj9 obj10)
(ontable obj2)
(on obj3 obj2)
(on obj5 obj8)
(clear obj9)
(ontable obj0)
(on obj1 obj4)
(clear obj5)
(clear obj3)
(on obj4 obj0)
(clear obj6)
(on obj6 obj1)
))
)
44 changes: 44 additions & 0 deletions src/lifted_pddl/data/logistics-domain.pddl
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
;; Source: https://github.com/josej30/Planner-Sat-Constraints

(define (domain logistics)

(:requirements :strips :typing)

(:types city location thing - object
package vehicle - thing
truck airplane - vehicle
airport - location)

(:predicates (in-city ?l - location ?c - city)
(at ?obj - thing ?l - location)
(in ?p - package ?veh - vehicle))

(:action drive
:parameters (?t - truck ?from ?to - location ?c - city)
:precondition (and (at ?t ?from)
(in-city ?from ?c)
(in-city ?to ?c))
:effect (and (not (at ?t ?from))
(at ?t ?to)))

(:action fly
:parameters (?a - airplane ?from ?to - airport)
:precondition (at ?a ?from)
:effect (and (not (at ?a ?from))
(at ?a ?to)))

(:action load
:parameters (?v - vehicle ?p - package ?l - location)
:precondition (and (at ?v ?l)
(at ?p ?l))
:effect (and (not (at ?p ?l))
(in ?p ?v)))

(:action unload
:parameters (?v - vehicle ?p - package ?l - location)
:precondition (and (at ?v ?l)
(in ?p ?v))
:effect (and (not (in ?p ?v))
(at ?p ?l)))

)
Loading

0 comments on commit 3eed76b

Please sign in to comment.