def _parse_domain_types(self): match = re.search(r"\(:types", self.domain) if not match: self.types = {"default": Type("default")} self.uses_typing = False return self.uses_typing = True start_ind = match.start() types = self._find_balanced_expression(self.domain, start_ind) types = types[7:-1].split() self.types = {type_name: Type(type_name) for type_name in types}
def _parse_domain_types(self): match = re.search(r"\(:types", self.domain) if not match: self.types = {"default": Type("default")} self.type_hierarchy = {} self.uses_typing = False return self.uses_typing = True start_ind = match.start() types = self._find_balanced_expression(self.domain, start_ind) # Non-hierarchical types if " - " not in types: types = types[7:-1].split() self.types = {type_name: Type(type_name) for type_name in types} self.type_hierarchy = {} # Hierarchical types else: self.types = {} self.type_hierarchy = {} remaining_type_str = types[7:-1] while " - " in remaining_type_str: dash_index = remaining_type_str.index(" - ") s = remaining_type_str[dash_index:] super_start_index = dash_index + len(s) - len(s.lstrip()) + 2 s = remaining_type_str[super_start_index:] try: end_index_offset = min(s.index(" "), s.index("\n")) except ValueError: end_index_offset = len(s) super_end_index = super_start_index + end_index_offset super_type_name = remaining_type_str[ super_start_index:super_end_index] sub_type_names = remaining_type_str[:dash_index].split() # Add new types for new_type in sub_type_names + [super_type_name]: if new_type not in self.types: self.types[new_type] = Type(new_type) # Add to hierarchy super_type = self.types[super_type_name] if super_type in self.type_hierarchy: self.type_hierarchy[super_type].update( {self.types[t] for t in sub_type_names}) else: self.type_hierarchy[super_type] = { self.types[t] for t in sub_type_names } remaining_type_str = remaining_type_str[super_end_index:] assert len(remaining_type_str.strip( )) == 0, "Cannot mix hierarchical and non-hierarchical types"
def _parse_objects(self, objects): if objects.find("\n") != -1: objects = objects.split("\n") elif self.uses_typing: # Must be one object then; assumes that typed objects are new-line separated assert objects.count(" - ") == 1 objects = [objects] else: # Space-separated objects = objects.split() to_return = set() for obj in objects: if self.uses_typing: obj_name, obj_type_name = obj.strip().split(" - ") obj_name = obj_name.strip() obj_type_name = obj_type_name.strip() else: obj_name = obj.strip() if " - " in obj_name: obj_name, temp = obj_name.split(" - ") obj_name = obj_name.strip() assert temp == "default" obj_type_name = "default" if obj_type_name not in self.types: print( "Warning: type not declared for object {}, type {}".format( obj_name, obj_type_name)) obj_type = Type(obj_type_name) else: obj_type = self.types[obj_type_name] to_return.add(TypedEntity(obj_name, obj_type)) return sorted(to_return)
def parse_objects(objects, types, uses_typing=False): if uses_typing: split_objects = [] remaining_str = objects while True: try: obj, remaining_str = re.split(r"\s-\s|\n-\s", remaining_str, 1) except ValueError: break if " " in remaining_str: object_type, remaining_str = re.split( r"[\s]+|[\n]+", remaining_str, 1) else: object_type = remaining_str remaining_str = "" split_objects.append(obj + " - " + object_type) objects = split_objects else: objects = objects.split() obj_names = [] obj_type_names = [] for obj in objects: if uses_typing: obj_name, obj_type_name = obj.strip().split(" - ") obj_name = obj_name.strip() obj_type_name = obj_type_name.strip() if len(obj_name.split()) > 1: for single_obj_name in obj_name.split(): obj_names.append(single_obj_name.strip()) obj_type_names.append(obj_type_name) else: obj_names.append(obj_name) obj_type_names.append(obj_type_name) else: obj_name = obj.strip() if " - " in obj_name: obj_name, temp = obj_name.split(" - ") obj_name = obj_name.strip() assert temp == "default" obj_type_name = "default" obj_names.append(obj_name) obj_type_names.append(obj_type_name) to_return = set() for obj_name, obj_type_name in zip(obj_names, obj_type_names): if obj_type_name not in types: print( "Warning: type not declared for object {}, type {}".format( obj_name, obj_type_name)) obj_type = Type(obj_type_name) else: obj_type = types[obj_type_name] to_return.add(TypedEntity(obj_name, obj_type)) return sorted(to_return)
def test_zero_arity_negative_preconditions(): MoveableType = Type('moveable') Holding = Predicate('Holding', 1, var_types=[MoveableType]) HandEmpty = Predicate('HandEmpty', 0, var_types=[]) conds = [Holding("?x1"), Not(HandEmpty())] kb = {Holding("a"), HandEmpty()} assignments = find_satisfying_assignments(kb, conds, allow_redundant_variables=False) assert len(assignments) == 0 print("Pass.")
def test_determinize(): dir_path = os.path.dirname(os.path.realpath(__file__)) domain_file = os.path.join(dir_path, 'pddl', 'test_probabilistic_domain.pddl') problem_dir = os.path.join(dir_path, 'pddl', 'test_probabilistic_domain') env = PDDLEnv(domain_file, problem_dir, raise_error_on_invalid_action=True, dynamic_action_space=True) env.domain.determinize() obs, _ = env.reset() action = env.action_space.all_ground_literals(obs).pop() transitions = env.get_all_possible_transitions(action, return_probs=True) transition_list = list(transitions) assert len(transition_list) == 1 assert transition_list[0][1] == 1.0 newstate = transition_list[0][0][0] type1 = Type('type1') type2 = Type('type2') pred1 = Predicate('pred1', 1, [type1]) pred2 = Predicate('pred2', 1, [type2]) pred3 = Predicate('pred3', 3, [type1, type2, type2]) assert newstate.literals == frozenset({ pred1('b2'), pred2('c1'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1') }) print("Test passed.")
def test_heuristic(): dir_path = os.path.dirname(os.path.realpath(__file__)) domain_file = os.path.join(dir_path, 'pddl', 'easyblocks.pddl') problem_dir = os.path.join(dir_path, 'pddl', 'easyblocks') block = Type("block") pickup = Predicate("pickup", 1, [block]) stack = Predicate("stack", 2, [block, block]) shaped_env = PDDLEnv( domain_file, problem_dir, shape_reward_mode="lmcut", raise_error_on_invalid_action=True, ) env = PDDLEnv( domain_file, problem_dir, shape_reward_mode=None, raise_error_on_invalid_action=True, ) shaped_env.reset() env.reset() _, rew, _, _ = env.step(pickup("b")) _, shaped_rew, _, _ = shaped_env.step(pickup("b")) assert rew == 0. assert shaped_rew == 1. intermediate_state = env.get_state() def assert_last_step(): _, rew, done, _ = env.step(stack("b", "a")) _, shaped_rew, shaped_done, _ = shaped_env.step(stack("b", "a")) assert done assert shaped_done assert rew == 1. assert shaped_rew == 2. # check if the step to the goal is terminal and with correct rewards assert_last_step() # check if shaped reward is consistent after setting the state shaped_env.set_state(intermediate_state) env.set_state(intermediate_state) assert_last_step() print("Test passed.")
def test_negative_preconditions(): MoveableType = Type('moveable') Holding = Predicate('Holding', 1, var_types=[MoveableType]) IsPawn = Predicate('IsPawn', 1, var_types=[MoveableType]) PutOn = Predicate('PutOn', 1, var_types=[MoveableType]) On = Predicate('On', 2, var_types=[MoveableType, MoveableType]) # ?x0 must bind to o0 and ?x1 must bind to o1, so ?x2 must bind to o2 conds = [ PutOn("?x0"), Holding("?x1"), IsPawn("?x2"), Not(On("?x2", "?x0")) ] kb = { PutOn('o0'), IsPawn('o0'), IsPawn('o1'), IsPawn('o2'), Holding('o1'), } assignments = find_satisfying_assignments(kb, conds, allow_redundant_variables=False) assert len(assignments) == 1 # should be the same, even though IsPawn("?x2") is removed conds = [PutOn("?x0"), Holding("?x1"), Not(On("?x2", "?x0"))] kb = { PutOn('o0'), IsPawn('o0'), IsPawn('o1'), IsPawn('o2'), Holding('o1'), } assignments = find_satisfying_assignments(kb, conds, allow_redundant_variables=False) assert len(assignments) == 1 print("Pass.")
def _parse_objects(self, objects): if self.uses_typing: # Assume typed objects are new-line separated. objects = objects.split("\n") else: # Untyped objects can be separated by any form of whitespace. objects = objects.split() obj_names = [] obj_type_names = [] for obj in objects: if self.uses_typing: obj_name, obj_type_name = obj.strip().split(" - ") obj_name = obj_name.strip() obj_type_name = obj_type_name.strip() if len(obj_name.split()) > 1: for single_obj_name in obj_name.split(): obj_names.append(single_obj_name.strip()) obj_type_names.append(obj_type_name) else: obj_names.append(obj_name) obj_type_names.append(obj_type_name) else: obj_name = obj.strip() if " - " in obj_name: obj_name, temp = obj_name.split(" - ") obj_name = obj_name.strip() assert temp == "default" obj_type_name = "default" obj_names.append(obj_name) obj_type_names.append(obj_type_name) to_return = set() for obj_name, obj_type_name in zip(obj_names, obj_type_names): if obj_type_name not in self.types: print( "Warning: type not declared for object {}, type {}".format( obj_name, obj_type_name)) obj_type = Type(obj_type_name) else: obj_type = self.types[obj_type_name] to_return.add(TypedEntity(obj_name, obj_type)) return sorted(to_return)
def test_pddlenv_hierarchical_types(): dir_path = os.path.dirname(os.path.realpath(__file__)) domain_file = os.path.join(dir_path, 'pddl', 'hierarchical_type_test_domain.pddl') problem_dir = os.path.join(dir_path, 'pddl', 'hierarchical_type_test_domain') env = PDDLEnv(domain_file, problem_dir) obs, _ = env.reset() ispresent = Predicate("ispresent", 1, [Type("entity")]) islight = Predicate("islight", 1, [Type("object")]) isfurry = Predicate("isfurry", 1, [Type("animal")]) ishappy = Predicate("ishappy", 1, [Type("animal")]) pet = Predicate("pet", 1, [Type("animal")]) nomsy = Type("jindo")("nomsy") rover = Type("corgi")("rover") rene = Type("cat")("rene") block1 = Type("block")("block1") block2 = Type("block")("block2") cylinder1 = Type("cylinder")("cylinder1") assert obs.literals == frozenset({ ispresent(nomsy), ispresent(rover), ispresent(rene), ispresent(block1), ispresent(block2), ispresent(cylinder1), islight(block1), islight(cylinder1), isfurry(nomsy), }) obs, _, _, _ = env.step(pet('block1')) assert obs.literals == frozenset({ ispresent(nomsy), ispresent(rover), ispresent(rene), ispresent(block1), ispresent(block2), ispresent(cylinder1), islight(block1), islight(cylinder1), isfurry(nomsy), }) obs, _, _, _ = env.step(pet(nomsy)) assert obs.literals == frozenset({ ispresent(nomsy), ispresent(rover), ispresent(rene), ispresent(block1), ispresent(block2), ispresent(cylinder1), islight(block1), islight(cylinder1), isfurry(nomsy), ishappy(nomsy) }) print("Test passed.")
def test_prover(): TType = Type('t') atom0, atom1, atom2 = TType('atom0'), TType('atom1'), TType('atom2') var0, var1, var2, var3 = TType('Var0'), TType('Var1'), TType( 'Var2'), TType('Var3') # Single predicate single arity test predicate0 = Predicate('Predicate0', 1, [TType]) predicate1 = Predicate('Predicate1', 2, [TType, TType]) predicate2 = Predicate('Predicate2', 1, [TType]) kb0 = [predicate0(atom0)] assignments = find_satisfying_assignments(kb0, [predicate0(var0)]) assert len(assignments) == 1 assert len(assignments[0]) == 1 assert assignments[0][var0] == atom0 assignments = find_satisfying_assignments( kb0, [predicate0(var0), predicate0(var1)]) assert len(assignments) == 1 kb1 = [predicate0(atom0), predicate0(atom1)] assignments = find_satisfying_assignments(kb1, [predicate0(var0)]) assert len(assignments) == 2 assignments = find_satisfying_assignments( kb1, [predicate0(var0), predicate0(var1)]) assert len(assignments) == 2 assignments = find_satisfying_assignments( kb1, [predicate0(var0), predicate0(var1), predicate0(var2)]) assert len(assignments) == 2 kb2 = [predicate0(atom0), predicate0(atom1), predicate0(atom2)] assignments = find_satisfying_assignments(kb2, [predicate0(var0)]) assert len(assignments) == 2 assignments = find_satisfying_assignments( kb2, [predicate0(var0), predicate0(var1)]) assert len(assignments) == 2 assignments = find_satisfying_assignments( kb2, [predicate0(var0), predicate0(var1), predicate0(var2)]) assert len(assignments) == 2 # Single predicate multiple arity test kb3 = [predicate1(atom0, atom1), predicate1(atom1, atom2)] assignments = find_satisfying_assignments(kb3, [predicate1(var0, var1)]) assert len(assignments) == 2 assignments = find_satisfying_assignments( kb3, [predicate1(var0, var1), predicate1(var1, var2)]) assert len(assignments) == 1 assignments = find_satisfying_assignments( kb3, [predicate1(var0, var1), predicate1(var1, var0)]) assert len(assignments) == 0 assignments = find_satisfying_assignments( kb3, [predicate1(var0, var1), predicate1(var2, var3)]) assert len(assignments) == 2 ## Multiple predicate multiple arity test kb4 = [ predicate0(atom2), predicate1(atom0, atom1), predicate1(atom1, atom2) ] assignments = find_satisfying_assignments( kb4, [predicate1(var0, var1), predicate0(var1), predicate0(var0)]) assert len(assignments) == 0 ## Tricky case! kb6 = [ predicate0(atom0), predicate2(atom1), predicate1(atom0, atom2), predicate1(atom2, atom1) ] assignments = find_satisfying_assignments( kb6, [predicate0(var0), predicate2(var1), predicate1(var0, var1)]) assert len(assignments) == 0 print("Pass.")
def get_sar_successor_state(state, action): """Search and rescue specific successor generation Assumptions: - One robot called robot0 """ # Remake predicates to keep this function self-contained person_type = Type('person') robot_type = Type('robot') location_type = Type('location') direction_type = Type('direction') clear = Predicate('clear', 1, [location_type]) conn = Predicate("conn", 3, [location_type, location_type, direction_type]) robot_at = Predicate('robot-at', 2, [robot_type, location_type]) carrying = Predicate('carrying', 2, [robot_type, person_type]) person_at = Predicate('person-at', 2, [person_type, location_type]) handsfree = Predicate('handsfree', 1, [robot_type]) # Parse the state robot_location = None # location robot_carrying = None # person adjacency_map = {} # (location, direction) -> location people_locs = {} # person -> location clear_locs = set() for lit in state.literals: if lit.predicate.name == "robot-at": assert lit.variables[0] == "robot0" robot_location = lit.variables[1] elif lit.predicate.name == "conn": adjacency_map[(lit.variables[0], lit.variables[2])] = lit.variables[1] elif lit.predicate.name == "carrying": assert lit.variables[0] == "robot0" robot_carrying = lit.variables[1] elif lit.predicate.name == "person-at": people_locs[lit.variables[0]] = lit.variables[1] elif lit.predicate.name == "clear": clear_locs.add(lit.variables[0]) assert robot_location is not None is_valid = False pos_preconds = set() neg_preconds = set() pos_effects = set() neg_effects = set() if action.predicate.name == "move": """ (:action move-robot :parameters (?robot - robot ?from - location ?to - location ?dir - direction) :precondition (and (move ?dir) (conn ?from ?to ?dir) (robot-at ?robot ?from) (clear ?to)) :effect (and (not (robot-at ?robot ?from)) (robot-at ?robot ?to) (not (clear ?to)) (clear ?from)) ) """ direction = action.variables[0] if (robot_location, direction) in adjacency_map: next_robot_location = adjacency_map[(robot_location, direction)] if next_robot_location in clear_locs: is_valid = True pos_preconds = { conn(robot_location, next_robot_location, direction), robot_at("robot0", robot_location), clear(next_robot_location), } pos_effects = { robot_at("robot0", next_robot_location), clear(robot_location) } neg_effects = { robot_at("robot0", robot_location), clear(next_robot_location) } elif action.predicate.name == "pickup": """ (:action pickup-person :parameters (?robot - robot ?person - person ?loc - location) :precondition (and (pickup ?person) (robot-at ?robot ?loc) (person-at ?person ?loc) (handsfree ?robot)) :effect (and (not (person-at ?person ?loc)) (not (handsfree ?robot)) (carrying ?robot ?person)) ) """ if robot_carrying is None: person = action.variables[0] person_loc = people_locs[person] if person_loc == robot_location: is_valid = True pos_preconds = { robot_at("robot0", robot_location), person_at(person, person_loc), handsfree("robot0"), } pos_effects = { carrying("robot0", person), } neg_effects = { person_at(person, person_loc), handsfree("robot0"), } elif action.predicate.name == "dropoff": """ (:action dropoff-person :parameters (?robot - robot ?person - person ?loc - location) :precondition (and (dropoff ) (carrying ?robot ?person) (robot-at ?robot ?loc)) :effect (and (person-at ?person ?loc) (handsfree ?robot) (not (carrying ?robot ?person))) ) """ if robot_carrying is not None: is_valid = True pos_preconds = { robot_at("robot0", robot_location), carrying("robot0", robot_carrying), } pos_effects = { person_at(robot_carrying, robot_location), handsfree("robot0"), } neg_effects = { carrying("robot0", robot_carrying), } else: raise Exception(f"Unrecognized action {action}.") if not is_valid: return state assert state.literals.issuperset(pos_preconds) assert len(state.literals & {Not(p) for p in neg_preconds}) == 0 new_state_literals = set(state.literals) new_state_literals -= neg_effects new_state_literals |= pos_effects return state.with_literals(frozenset(new_state_literals))
class SearchAndRescueEnv(PDDLSearchAndRescueEnv): """Changes the state space to just be positions of objects and the identity of the person being carried. """ person_type = Type('person') robot_type = Type('robot') location_type = Type('location') direction_type = Type('direction') wall_type = Type('wall') hospital_type = Type('hospital') clear = Predicate('clear', 1, [location_type]) conn = Predicate("conn", 3, [location_type, location_type, direction_type]) robot_at = Predicate('robot-at', 2, [robot_type, location_type]) person_at = Predicate('person-at', 2, [person_type, location_type]) wall_at = Predicate('wall-at', 2, [wall_type, location_type]) hospital_at = Predicate('hospital-at', 2, [hospital_type, location_type]) carrying = Predicate('carrying', 2, [robot_type, person_type]) handsfree = Predicate('handsfree', 1, [robot_type]) @property def observation_space(self): raise NotImplementedError() def _state_to_internal(self, state): state = dict(state) new_state_literals = set() directions_to_deltas = { self.direction_type('up') : (-1, 0), self.direction_type('down') : (1, 0), self.direction_type('left') : (0, -1), self.direction_type('right') : (0, 1), } # conn height, width = 6, 6 for r in range(height): for c in range(width): loc = self.location_type(f"f{r}-{c}f") for direction, (dr, dc) in directions_to_deltas.items(): next_r, next_c = r + dr, c + dc if not (0 <= next_r < height and 0 <= next_c < width): continue next_loc = self.location_type(f"f{next_r}-{next_c}f") conn_lit = self.conn(loc, next_loc, direction) new_state_literals.add(conn_lit) # at occupied_locs = set() hospital_loc = None for obj_name, loc_tup in state.items(): if obj_name in ["carrying", "rescue"]: continue r, c = loc_tup loc = self.location_type(f"f{r}-{c}f") if obj_name.startswith("person"): at_pred = self.person_at elif obj_name.startswith("robot"): at_pred = self.robot_at occupied_locs.add((r, c)) elif obj_name.startswith("wall"): at_pred = self.wall_at occupied_locs.add((r, c)) elif obj_name.startswith("hospital"): at_pred = self.hospital_at assert hospital_loc is None hospital_loc = loc else: raise Exception(f"Unrecognized object {obj_name}") new_state_literals.add(at_pred(obj_name, loc)) assert hospital_loc is not None # carrying/handsfree if state["carrying"] is None: new_state_literals.add(self.handsfree("robot0")) else: new_state_literals.add(self.carrying("robot0", state["carrying"])) # clear for r in range(height): for c in range(width): if (r, c) not in occupied_locs: loc = self.location_type(f"f{r}-{c}f") clear_lit = self.clear(loc) new_state_literals.add(clear_lit) # objects new_objects = frozenset({o for lit in new_state_literals for o in lit.variables }) # goal new_goal = LiteralConjunction([self.person_at(person, hospital_loc) \ for person in sorted(state["rescue"])]) new_state = State(frozenset(new_state_literals), new_objects, new_goal) return new_state def _internal_to_state(self, internal_state): state = { "carrying" : None } state["rescue"] = set() for lit in internal_state.goal.literals: assert lit.predicate == self.person_at state["rescue"].add(lit.variables[0].name) state["rescue"] = frozenset(state["rescue"]) # make hashable for lit in internal_state.literals: if lit.predicate.name.endswith("at"): obj_name = lit.variables[0].name r, c = self._loc_to_rc(lit.variables[1]) state[obj_name] = (r, c) if lit.predicate.name == "carrying": person_name = lit.variables[1].name state["carrying"] = person_name state = tuple(sorted(state.items())) # make hashable return state def _loc_to_rc(self, loc_str): assert loc_str.startswith("f") and loc_str.endswith("f") r, c = loc_str[1:-1].split('-') return (int(r), int(c)) def set_state(self, state): assert isinstance(state, State), "Do not call set_state" self._state = state def get_state(self): assert isinstance(self._state, State), "Do not call get_state" return self._state def reset(self): internal_state, debug_info = super().reset() return self._internal_to_state(internal_state), debug_info def step(self, action): internal_state, reward, done, debug_info = super().step(action) state = self._internal_to_state(internal_state) return state, reward, done, debug_info def get_successor_state(self, state, action): internal_state = self._state_to_internal(state) next_internal_state = super().get_successor_state(internal_state, action) next_state = self._internal_to_state(next_internal_state) # Sanity checks assert state == self._internal_to_state(internal_state) assert next_internal_state == self._state_to_internal(next_state) return next_state def render_from_state(self, state): internal_state = self._state_to_internal(state) return super().render_from_state(internal_state) def check_goal(self, state): internal_state = self._state_to_internal(state) return super().check_goal(internal_state)
from ndr.ndrs import * from ndr.learn import * from pddlgym.structs import Type, Anti from ndr.main import * from ndr.utils import nostdout import gym import pddlgym import pybullet_abstraction_envs import numpy as np VERBOSE = True # Some shared stuff block_type = Type("block") Act0 = Predicate("act0", 0, []) Act01 = Predicate("act01", 0, []) Act1 = Predicate("act1", 0, [block_type]) Red = Predicate("red", 1, [block_type]) Blue = Predicate("blue", 1, [block_type]) HandsFree0 = Predicate("HandsFree0", 0, []) MoveableType = Type('moveable') StaticType = Type('static') IsRobot = Predicate('IsRobot', 1, var_types=[MoveableType]) IsBear = Predicate('IsBear', 1, var_types=[MoveableType]) IsHoney = Predicate('IsHoney', 1, var_types=[MoveableType]) IsPawn = Predicate('IsPawn', 1, var_types=[MoveableType]) IsMonkey = Predicate('IsMonkey', 1, var_types=[MoveableType]) IsGoal = Predicate('IsGoal', 1, var_types=[StaticType]) At = Predicate('At', 2, var_types=[MoveableType, StaticType]) Holding = Predicate('Holding', 1, var_types=[MoveableType])
def test_hierarchical_spaces(): dir_path = os.path.dirname(os.path.realpath(__file__)) domain_file = os.path.join(dir_path, 'pddl', 'hierarchical_type_test_domain.pddl') problem_file = os.path.join(dir_path, 'pddl', 'hierarchical_type_test_domain', 'hierarchical_type_test_problem.pddl') domain = PDDLDomainParser(domain_file) problem = PDDLProblemParser(problem_file, domain.domain_name, domain.types, domain.predicates) actions = list(domain.actions) action_predicates = [domain.predicates[a] for a in actions] space = LiteralSpace(set(domain.predicates.values()) - set(action_predicates), type_to_parent_types=domain.type_to_parent_types) space.update(problem.objects) all_ground_literals = space.all_ground_literals() ispresent = Predicate("ispresent", 1, [Type("entity")]) islight = Predicate("islight", 1, [Type("object")]) isfurry = Predicate("isfurry", 1, [Type("animal")]) ishappy = Predicate("ishappy", 1, [Type("animal")]) attending = Predicate("attending", 2, [Type("animal"), Type("object")]) nomsy = Type("jindo")("nomsy") rover = Type("corgi")("rover") rene = Type("cat")("rene") block1 = Type("block")("block1") block2 = Type("block")("block2") cylinder1 = Type("cylinder")("cylinder1") assert all_ground_literals == { ispresent(nomsy), ispresent(rover), ispresent(rene), ispresent(block1), ispresent(block2), ispresent(cylinder1), islight(block1), islight(block2), islight(cylinder1), isfurry(nomsy), isfurry(rover), isfurry(rene), ishappy(nomsy), ishappy(rover), ishappy(rene), attending(nomsy, block1), attending(nomsy, block2), attending(nomsy, cylinder1), attending(rover, block1), attending(rover, block2), attending(rover, cylinder1), attending(rene, block1), attending(rene, block2), attending(rene, cylinder1), } print("Test passed.")
def test_hierarchical_types(): dir_path = os.path.dirname(os.path.realpath(__file__)) domain_file = os.path.join(dir_path, 'pddl', 'hierarchical_type_test_domain.pddl') problem_file = os.path.join(dir_path, 'pddl', 'hierarchical_type_test_domain', 'hierarchical_type_test_problem.pddl') domain = PDDLDomainParser(domain_file) problem = PDDLProblemParser(problem_file, domain.domain_name, domain.types, domain.predicates) assert set(domain.types.keys()) == { Type("dog"), Type("cat"), Type("animal"), Type("block"), Type("cylinder"), Type("jindo"), Type("corgi"), Type("object"), Type("entity") } assert domain.type_hierarchy == { Type("animal"): {Type("dog"), Type("cat")}, Type("dog"): {Type("jindo"), Type("corgi")}, Type("object"): {Type("block"), Type("cylinder")}, Type("entity"): {Type("object"), Type("animal")}, } assert domain.type_to_parent_types == { Type("entity"): {Type("entity")}, Type("object"): {Type("object"), Type("entity")}, Type("animal"): {Type("animal"), Type("entity")}, Type("dog"): {Type("dog"), Type("animal"), Type("entity")}, Type("cat"): {Type("cat"), Type("animal"), Type("entity")}, Type("corgi"): {Type("corgi"), Type("dog"), Type("animal"), Type("entity")}, Type("jindo"): {Type("jindo"), Type("dog"), Type("animal"), Type("entity")}, Type("block"): {Type("block"), Type("object"), Type("entity")}, Type("cylinder"): {Type("cylinder"), Type("object"), Type("entity")}, } print("Test passed.")
def test_get_all_possible_transitions(): dir_path = os.path.dirname(os.path.realpath(__file__)) domain_file = os.path.join(dir_path, 'pddl', 'test_probabilistic_domain.pddl') problem_dir = os.path.join(dir_path, 'pddl', 'test_probabilistic_domain') env = PDDLEnv(domain_file, problem_dir, raise_error_on_invalid_action=True, dynamic_action_space=True) obs, _ = env.reset() action = env.action_space.all_ground_literals(obs).pop() transitions = env.get_all_possible_transitions(action) transition_list = list(transitions) assert len(transition_list) == 2 state1, state2 = transition_list[0][0], transition_list[1][0] type1 = Type('type1') type2 = Type('type2') pred1 = Predicate('pred1', 1, [type1]) pred2 = Predicate('pred2', 1, [type2]) pred3 = Predicate('pred3', 3, [type1, type2, type2]) state1, state2 = (state1, state2) if pred2('c1') in state2.literals else (state2, state1) assert state1.literals == frozenset({ pred1('b2'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1') }) assert state2.literals == frozenset({ pred1('b2'), pred2('c1'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1') }) # Now test again with return_probs=True. transitions = env.get_all_possible_transitions(action, return_probs=True) transition_list = list(transitions) assert len(transition_list) == 2 assert abs(transition_list[0][1] - 0.3) < 1e-5 or abs(transition_list[0][1] - 0.7) < 1e-5 assert abs(transition_list[1][1] - 0.3) < 1e-5 or abs(transition_list[1][1] - 0.7) < 1e-5 assert abs(transition_list[0][1] - transition_list[1][1]) > 0.3 state1, state2 = transition_list[0][0][0], transition_list[1][0][0] type1 = Type('type1') type2 = Type('type2') pred1 = Predicate('pred1', 1, [type1]) pred2 = Predicate('pred2', 1, [type2]) pred3 = Predicate('pred3', 3, [type1, type2, type2]) state1, state2 = (state1, state2) if pred2('c1') in state2.literals else (state2, state1) assert state1.literals == frozenset({ pred1('b2'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1') }) assert state2.literals == frozenset({ pred1('b2'), pred2('c1'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1') }) print("Test passed.")
def test_get_all_possible_transitions_multiple_effects(): dir_path = os.path.dirname(os.path.realpath(__file__)) domain_file = os.path.join(dir_path, 'pddl', 'test_probabilistic_domain_alt_2.pddl') problem_dir = os.path.join(dir_path, 'pddl', 'test_probabilistic_domain_alt_2') env = PDDLEnv(domain_file, problem_dir, raise_error_on_invalid_action=True, dynamic_action_space=True) obs, _ = env.reset() action = env.action_space.all_ground_literals(obs).pop() transitions = env.get_all_possible_transitions(action) transition_list = list(transitions) assert len(transition_list) == 3 states = set({ transition_list[0][0].literals, transition_list[1][0].literals, transition_list[2][0].literals }) type1 = Type('type1') type2 = Type('type2') pred1 = Predicate('pred1', 1, [type1]) pred2 = Predicate('pred2', 1, [type2]) pred3 = Predicate('pred3', 3, [type1, type2, type2]) expected_states = set({ frozenset( {pred1('b2'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2')}), frozenset( {pred2('c1'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2')}), frozenset({ pred1('b2'), pred2('c1'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1') }) }) assert states == expected_states # Now test again with return_probs=True. transitions = env.get_all_possible_transitions(action, return_probs=True) transition_list = list(transitions) assert len(transition_list) == 3 states_and_probs = { transition_list[0][0][0].literals: transition_list[0][1], transition_list[1][0][0].literals: transition_list[1][1], transition_list[2][0][0].literals: transition_list[2][1] } type1 = Type('type1') type2 = Type('type2') pred1 = Predicate('pred1', 1, [type1]) pred2 = Predicate('pred2', 1, [type2]) pred3 = Predicate('pred3', 3, [type1, type2, type2]) expected_states = { frozenset({ pred1('b2'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2') }): 0.5, frozenset({ pred2('c1'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2') }): 0.4, frozenset({ pred1('b2'), pred2('c1'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1') }): 0.1 } for s, prob in states_and_probs.items(): assert s in expected_states assert prob - expected_states[s] < 1e-5 print("Test passed.")
def integration_test(): dir_path = os.path.dirname(os.path.realpath(__file__)) domain_file = os.path.join(dir_path, 'pddl', 'test_domain.pddl') problem_file = os.path.join(dir_path, 'pddl', 'test_domain', 'test_problem.pddl') domain = PDDLDomainParser(domain_file) problem = PDDLProblemParser(problem_file, domain.domain_name, domain.types, domain.predicates) ## Check domain type1 = Type('type1') type2 = Type('type2') # Action predicates action_pred = Predicate('actionpred', 1, [type1]) # Predicates pred1 = Predicate('pred1', 1, [type1]) pred2 = Predicate('pred2', 1, [type2]) pred3 = Predicate('pred3', 1, [type1, type2, type2]) assert set(domain.predicates.values()) == { pred1, pred2, pred3, action_pred } assert domain.actions == { action_pred.name } # Operators assert len(domain.operators) == 1 operator1 = Predicate('action1', 4, [type1, type1, type2, type2]) assert operator1 in domain.operators operator = domain.operators[operator1] # Operator parameters assert len(operator.params) == 4 assert operator.params[0] == type1('?a') assert operator.params[1] == type1('?b') assert operator.params[2] == type2('?c') assert operator.params[3] == type2('?d') # Operator preconditions (set of Literals) assert len(operator.preconds.literals) == 4 assert set(operator.preconds.literals) == { action_pred('?b'), pred1('?b'), pred3('?a', '?c', '?d'), Not(pred2('?c')) } # Operator effects (set of Literals) assert len(operator.effects.literals) == 3 assert set(operator.effects.literals) == { Anti(pred2('?d')), pred2('?c'), pred3('?b', '?d', '?c')} ## Check problem # Objects assert set(problem.objects) == {type1('a1'), type1('a2'), type1('b1'), type1('b2'), type1('b3'), type2('c1'), type2('c2'), type2('d1'), type2('d2'), type2('d3')} # Goal assert isinstance(problem.goal, LiteralConjunction) assert set(problem.goal.literals) == {pred2('c2'), pred3('b1', 'c1', 'd1')} # Init assert problem.initial_state == { pred1('b2'), pred2('c1'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), action_pred('a1'), action_pred('a2'), action_pred('b1'), action_pred('b2')} print("Test passed.")
def test_pddlenv(): dir_path = os.path.dirname(os.path.realpath(__file__)) domain_file = os.path.join(dir_path, 'pddl', 'test_domain.pddl') problem_dir = os.path.join(dir_path, 'pddl', 'test_domain') env = PDDLEnv(domain_file, problem_dir, raise_error_on_invalid_action=True, dynamic_action_space=True) env2 = PDDLEnv(domain_file, problem_dir, raise_error_on_invalid_action=True, dynamic_action_space=False) type1 = Type('type1') type2 = Type('type2') pred1 = Predicate('pred1', 1, [type1]) pred2 = Predicate('pred2', 1, [type2]) pred3 = Predicate('pred3', 1, [type1, type2, type2]) operator_name = 'action1' action_pred = Predicate('actionpred', 1, [type1]) obs, _ = env.reset() assert obs == { pred1('b2'), pred2('c1'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2') } operator = env.domain.operators[operator_name] # Invalid action action = action_pred('b1') try: env.step(action) assert False, "Action was supposed to be invalid" except InvalidAction: pass assert action not in env.action_space.all_ground_literals( ), "Dynamic action space not working" env2.reset() assert action in env2.action_space.all_ground_literals( ), "Dynamic action space not working" # Valid args action = action_pred('b2') obs, _, _, _ = env.step(action) assert obs == { pred1('b2'), pred2('c1'), pred2('c2'), pred3('b2', 'd2', 'c2'), pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2') } print("Test passed.")