diff --git a/README.md b/README.md index a286bc03..fede197d 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,14 @@ If you plan to use PDDLGym for non-trivial domains, you will almost certainly ne See `pddlgym/pddl/blocks.pddl` and `pddlgym/pddl/blocks/problem1.pddl` for an example to follow, where there are four action predicates: pickup, putdown, stack, and unstack. +## Running unit tests + +From the root of the repo, run + +```sh +python -m unittest discover pddlgym/tests/ +``` + ## Citation Please use this bibtex if you want to cite this repository in your publications: diff --git a/pddlgym/tests/test_inference.py b/pddlgym/tests/test_inference.py index 96a49ccb..ee821805 100644 --- a/pddlgym/tests/test_inference.py +++ b/pddlgym/tests/test_inference.py @@ -1,112 +1,109 @@ from pddlgym.inference import find_satisfying_assignments from pddlgym.structs import Predicate, Type, Not +import unittest -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') +class TestProver(unittest.TestCase): + def test_prover(self): + 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]) + # 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 + 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 + assignments = find_satisfying_assignments(kb0, [predicate0(var0), predicate0(var1)]) + assert len(assignments) == 1 - kb1 = [predicate0(atom0), predicate0(atom1)] + kb1 = [predicate0(atom0), predicate0(atom1)] - assignments = find_satisfying_assignments(kb1, [predicate0(var0)]) - assert len(assignments) == 2 + 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)]) + assert len(assignments) == 2 - assignments = find_satisfying_assignments(kb1, [predicate0(var0), predicate0(var1), predicate0(var2)]) - 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)] + 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)]) + 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)]) + assert len(assignments) == 2 - assignments = find_satisfying_assignments(kb2, [predicate0(var0), predicate0(var1), predicate0(var2)]) - 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)] + # 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)]) + 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, 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(var1, var0)]) + assert len(assignments) == 0 - assignments = find_satisfying_assignments(kb3, [predicate1(var0, var1), predicate1(var2, var3)]) - assert len(assignments) == 2 + 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)] + ## 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 + 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)] + ## 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 + assignments = find_satisfying_assignments(kb6, [predicate0(var0), predicate2(var1), predicate1(var0, var1)]) + assert len(assignments) == 0 - print("Pass.") +class TestNegativePreconditions(unittest.TestCase): + def test_negative_preconditions(self): + 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]) -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 - # ?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 - # 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 +class TestZeroArityNegativePreconditions(unittest.TestCase): - print("Pass.") + def test_zero_arity_negative_preconditions(self): + MoveableType = Type('moveable') + Holding = Predicate('Holding', 1, var_types=[MoveableType]) + HandEmpty = Predicate('HandEmpty', 0, var_types=[]) -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 - 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.") if __name__ == "__main__": - test_prover() - test_negative_preconditions() - test_zero_arity_negative_preconditions() - + unittest.main() diff --git a/pddlgym/tests/test_parser.py b/pddlgym/tests/test_parser.py index c1de9159..6d4adb10 100644 --- a/pddlgym/tests/test_parser.py +++ b/pddlgym/tests/test_parser.py @@ -2,103 +2,104 @@ from pddlgym.structs import Predicate, Literal, Type, Not, Anti, LiteralConjunction import os - -def test_parser(): - 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, domain.actions) - - ## 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', 3, [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'), pred2('?c') } - - # Operator effects (set of Literals) - assert len(operator.effects.literals) == 2 - assert set(operator.effects.literals) == { Anti(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 == frozenset({ pred1('b2'), pred2('c1'), - pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2') }) - - 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, domain.actions) - - 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.") +import unittest + +class TestParser(unittest.TestCase): + def test_parser(self): + 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, domain.actions) + + ## 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', 3, [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'), pred2('?c') } + + # Operator effects (set of Literals) + assert len(operator.effects.literals) == 2 + assert set(operator.effects.literals) == { Anti(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 == frozenset({ pred1('b2'), pred2('c1'), + pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2') }) + + +class TestHierarchicalTypes(unittest.TestCase): + def test_hierarchical_types(self): + 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, domain.actions) + + 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.") if __name__ == "__main__": - test_parser() - test_hierarchical_types() + unittest.main() diff --git a/pddlgym/tests/test_pddlenv.py b/pddlgym/tests/test_pddlenv.py index aeb5b4f2..1b74ac10 100644 --- a/pddlgym/tests/test_pddlenv.py +++ b/pddlgym/tests/test_pddlenv.py @@ -2,360 +2,350 @@ from pddlgym.structs import Predicate, Type, LiteralConjunction import os - - -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', 3, [type1, type2, type2]) - action_pred = Predicate('actionpred', 1, [type1]) - - obs, _ = env.reset() - - assert obs.literals == frozenset({ pred1('b2'), pred2('c1'), pred3('a1', 'c1', 'd1'), - pred3('a2', 'c2', 'd2') }) - - # 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(obs), "Dynamic action space not working" - env2.reset() - assert action in env2.action_space.all_ground_literals(obs), "Dynamic action space not working" - - # Valid args - action = action_pred('b2') - - obs, _, _, _ = env.step(action) - - assert obs.literals == frozenset({ pred1('b2'), pred3('b2', 'd1', 'c1'), - pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2') }) - - assert isinstance(obs.goal, LiteralConjunction) - assert set(obs.goal.literals) == {pred2('c2'), pred3('b1', 'c1', 'd1')} - - print("Test passed.") - - -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_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_independent_effects(): - dir_path = os.path.dirname(os.path.realpath(__file__)) - domain_file = os.path.join( - dir_path, 'pddl', 'test_probabilistic_domain_alt.pddl') - problem_dir = os.path.join(dir_path, 'pddl', 'test_probabilistic_domain_alt') - - 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) == 4 - - states = set({ - transition_list[0][0].literals, transition_list[1][0].literals, - transition_list[2][0].literals, transition_list[3][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({pred1('b2'), pred3( - 'a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1')}), - frozenset({pred1('b2'), pred2('c1'), pred3( - 'a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2')}), - frozenset({pred1('b2'), pred2('c1'), pred3( +import unittest + +class TestPDDLEnv(unittest.TestCase): + def test_pddlenv(self): + 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', 3, [type1, type2, type2]) + action_pred = Predicate('actionpred', 1, [type1]) + + obs, _ = env.reset() + + assert obs.literals == frozenset({ pred1('b2'), pred2('c1'), pred3('a1', 'c1', 'd1'), + pred3('a2', 'c2', 'd2') }) + + # 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(obs), "Dynamic action space not working" + env2.reset() + assert action in env2.action_space.all_ground_literals(obs), "Dynamic action space not working" + + # Valid args + action = action_pred('b2') + + obs, _, _, _ = env.step(action) + + assert obs.literals == frozenset({ pred1('b2'), pred3('b2', 'd1', 'c1'), + pred3('a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2') }) + + assert isinstance(obs.goal, LiteralConjunction) + assert set(obs.goal.literals) == {pred2('c2'), pred3('b1', 'c1', 'd1')} + + + def test_pddlenv_hierarchical_types(self): + 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) + }) + + + + + def test_get_all_possible_transitions(self): + 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 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) == 4 - 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], - transition_list[3][0][0].literals: transition_list[3][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.225, - frozenset({pred1('b2'), pred3( - 'a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1')}): 0.075, - frozenset({pred1('b2'), pred2('c1'), pred3( - 'a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2')}): 0.525, - frozenset({pred1('b2'), pred2('c1'), pred3( - 'a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1')}): 0.175 - } - - for s, prob in states_and_probs.items(): - assert s in expected_states - assert prob - expected_states[s] < 1e-5 - - 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( + assert state2.literals == 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 - } + # Now test again with return_probs=True. + transitions = env.get_all_possible_transitions(action, return_probs=True) - for s, prob in states_and_probs.items(): - assert s in expected_states - assert prob - expected_states[s] < 1e-5 + 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] - print("Test passed.") + type1 = Type('type1') + type2 = Type('type2') + pred1 = Predicate('pred1', 1, [type1]) + pred2 = Predicate('pred2', 1, [type2]) + pred3 = Predicate('pred3', 3, [type1, type2, type2]) -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') + state1, state2 = (state1, state2) if pred2( + 'c1') in state2.literals else (state2, state1) - 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] + 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')}) - 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')}) + def test_get_all_possible_transitions_multiple_independent_effects(self): + dir_path = os.path.dirname(os.path.realpath(__file__)) + domain_file = os.path.join( + dir_path, 'pddl', 'test_probabilistic_domain_alt.pddl') + problem_dir = os.path.join(dir_path, 'pddl', 'test_probabilistic_domain_alt') + + 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) == 4 + + states = set({ + transition_list[0][0].literals, transition_list[1][0].literals, + transition_list[2][0].literals, transition_list[3][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({pred1('b2'), pred3( + 'a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1')}), + frozenset({pred1('b2'), 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) == 4 + 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], + transition_list[3][0][0].literals: transition_list[3][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.225, + frozenset({pred1('b2'), pred3( + 'a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1')}): 0.075, + frozenset({pred1('b2'), pred2('c1'), pred3( + 'a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2')}): 0.525, + frozenset({pred1('b2'), pred2('c1'), pred3( + 'a1', 'c1', 'd1'), pred3('a2', 'c2', 'd2'), pred3('b2', 'd1', 'c1')}): 0.175 + } + + for s, prob in states_and_probs.items(): + assert s in expected_states + assert prob - expected_states[s] < 1e-5 + + + def test_get_all_possible_transitions_multiple_effects(self): + 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 + + + def test_determinize(self): + 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.") if __name__ == "__main__": - test_pddlenv() - test_pddlenv_hierarchical_types() - test_get_all_possible_transitions() - test_get_all_possible_transitions_multiple_effects() - test_get_all_possible_transitions_multiple_independent_effects() - test_determinize() + unittest.main() diff --git a/pddlgym/tests/test_searchandrescue.py b/pddlgym/tests/test_searchandrescue.py index 435ecedf..38cb995a 100644 --- a/pddlgym/tests/test_searchandrescue.py +++ b/pddlgym/tests/test_searchandrescue.py @@ -1,91 +1,93 @@ import pddlgym import numpy as np -def test_searchandrescue(num_actions_to_test=10, verbose=False): - """Test state encoding and decoding - """ - for level in range(1, 7): - env = pddlgym.make(f"SearchAndRescueLevel{level}-v0") - if level == 1: - assert len(env.problems) == 20 - else: - assert len(env.problems) == 50 - env.fix_problem_index(0) - state, debug_info = env.reset() - rng = np.random.RandomState(0) - - all_actions = env.get_possible_actions() - actions = rng.choice(all_actions, size=num_actions_to_test) - done = False - for t, act in enumerate(actions): - if verbose: - print(f"Taking action {t}/{num_actions_to_test}", end='\r', flush=True) - - assert state == env._internal_to_state(env._state) - assert env._state.literals == env._state_to_internal(state).literals - assert env._state.objects == env._state_to_internal(state).objects - assert set(env._state.goal.literals) == set(env._state_to_internal(state).goal.literals) - assert env.check_goal(state) == done - for a in all_actions: - ns = env.get_successor_state(state, a) - assert ns == env._internal_to_state(env._state_to_internal(ns)) - - if done: - break - state, _, done, _ = env.step(act) - if verbose: - print() - - print("Test passed.") - -def test_searchandrescue_walls(num_actions_to_test=10): - """Test that when we try to move into walls, we stay put. - """ - rng = np.random.RandomState(0) - for level in [1, 2]: - env = pddlgym.make(f"SearchAndRescueLevel{level}-v0") - for idx in range(len(env.problems)): - env.fix_problem_index(idx) +import unittest + + +class TestSearchAndRescue(unittest.TestCase): + def skip_test_searchandrescue(self, num_actions_to_test=10, verbose=False): + """Test state encoding and decoding + """ + for level in range(1, 7): + env = pddlgym.make(f"SearchAndRescueLevel{level}-v0") + if level == 1: + assert len(env.problems) == 20 + else: + assert len(env.problems) == 50 + env.fix_problem_index(0) state, debug_info = env.reset() + rng = np.random.RandomState(0) - all_actions = dropoff, down, left, right, up, pickup = env.get_possible_actions() - - act_to_delta = { - dropoff : (0, 0), - down : (1, 0), - left : (0, -1), - right : (0, 1), - up : (-1, 0), - pickup : (0, 0), - } - + all_actions = env.get_possible_actions() actions = rng.choice(all_actions, size=num_actions_to_test) done = False - robot_r, robot_c = dict(state)["robot0"] - walls = { dict(state)[k] for k in dict(state) if k.startswith("wall") } for t, act in enumerate(actions): - - dr, dc = act_to_delta[act] - can_r, can_c = robot_r + dr, robot_c + dc + if verbose: + print(f"Taking action {t}/{num_actions_to_test}", end='\r', flush=True) + + assert state == env._internal_to_state(env._state) + assert env._state.literals == env._state_to_internal(state).literals + assert env._state.objects == env._state_to_internal(state).objects + assert set(env._state.goal.literals) == set(env._state_to_internal(state).goal.literals) + assert env.check_goal(state) == done + for a in all_actions: + ns = env.get_successor_state(state, a) + assert ns == env._internal_to_state(env._state_to_internal(ns)) if done: break - state1, _, done, _ = env.step(act) - state2 = env.get_successor_state(state, act) - assert state2 == state1 - state = state1 + state, _, done, _ = env.step(act) + if verbose: + print() + + + def test_searchandrescue_walls(self, num_actions_to_test=10): + """Test that when we try to move into walls, we stay put. + """ + rng = np.random.RandomState(0) + for level in [1, 2]: + env = pddlgym.make(f"SearchAndRescueLevel{level}-v0") + for idx in range(len(env.problems)): + env.fix_problem_index(idx) + state, debug_info = env.reset() + + all_actions = dropoff, down, left, right, up, pickup = env.get_possible_actions() + + act_to_delta = { + dropoff : (0, 0), + down : (1, 0), + left : (0, -1), + right : (0, 1), + up : (-1, 0), + pickup : (0, 0), + } + + actions = rng.choice(all_actions, size=num_actions_to_test) + done = False + robot_r, robot_c = dict(state)["robot0"] + walls = { dict(state)[k] for k in dict(state) if k.startswith("wall") } + for t, act in enumerate(actions): + + dr, dc = act_to_delta[act] + can_r, can_c = robot_r + dr, robot_c + dc - new_r, new_c = dict(state)["robot0"] + if done: + break + state1, _, done, _ = env.step(act) + state2 = env.get_successor_state(state, act) + assert state2 == state1 + state = state1 - if (can_r, can_c) in walls: - # Can't move into walls! - assert (new_r, new_c) == (robot_r, robot_c) + new_r, new_c = dict(state)["robot0"] - robot_r, robot_c = new_r, new_c + if (can_r, can_c) in walls: + # Can't move into walls! + assert (new_r, new_c) == (robot_r, robot_c) - print("Test passed.") + robot_r, robot_c = new_r, new_c if __name__ == "__main__": # test_searchandrescue(verbose=True) - test_searchandrescue_walls() + # test_searchandrescue_walls() + unittest.main() diff --git a/pddlgym/tests/test_spaces.py b/pddlgym/tests/test_spaces.py index 0e976132..1952ab9a 100644 --- a/pddlgym/tests/test_spaces.py +++ b/pddlgym/tests/test_spaces.py @@ -5,161 +5,157 @@ import os import time +import unittest + + +class TestSpaces(unittest.TestCase): + def test_hierarchical_spaces(self): + 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, domain.actions) + 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) + all_ground_literals = space.all_ground_literals(State(problem.initial_state, + problem.objects, problem.goal)) + + 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), + } + + + + def test_dynamic_action_space(self, verbose=False): + """ + """ + dir_path = os.path.join( + os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pddl") + + for name in [ + # "Manymiconic", + # "Manygripper", + "Blocks_operator_actions", + "Hanoi_operator_actions", + ]: + domain_file = os.path.join(dir_path, "{}.pddl".format(name.lower())) + problem_dir = os.path.join(dir_path, name.lower()) + # problem_dir = os.path.join(dir_path, name.lower()+"_test") + + env1 = PDDLEnv(domain_file, problem_dir, + operators_as_actions=True, + dynamic_action_space=False, + ) + + env2 = PDDLEnv(domain_file, problem_dir, + operators_as_actions=True, + dynamic_action_space=True, + ) + + env1.action_space.seed(0) + env2.action_space.seed(0) + state1, _ = env1.reset() + state2, _ = env2.reset() + assert state1 == state2 + + for _ in range(25): + start_time = time.time() + valid_actions1 = env1.action_space.all_ground_literals(state1) + if verbose: + print("Computing valid action spaces without instantiator took {} seconds".format( + time.time() - start_time)) + start_time = time.time() + valid_actions2 = env2.action_space.all_ground_literals(state2) + if verbose: + print("Computing valid action spaces *with* instantiator took {} seconds".format( + time.time() - start_time)) + assert valid_actions2.issubset(valid_actions1) + action = env2.action_space.sample(state2) + state1, _, _, _ = env1.step(action) + state2, _, _, _ = env2.step(action) + + if verbose: + print("Test passed for environment {}.".format(name)) + -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, domain.actions) - 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) - all_ground_literals = space.all_ground_literals(State(problem.initial_state, - problem.objects, problem.goal)) - - 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_dynamic_action_space(verbose=False): - """ - """ - dir_path = os.path.join( - os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pddl") - - for name in [ - # "Manymiconic", - # "Manygripper", - "Blocks_operator_actions", - "Hanoi_operator_actions", - ]: + def test_dynamic_action_space_same_obj(self): + """ + """ + dir_path = os.path.join( + os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pddl") + + name = "dynamic_action_space_same_obj" domain_file = os.path.join(dir_path, "{}.pddl".format(name.lower())) problem_dir = os.path.join(dir_path, name.lower()) - # problem_dir = os.path.join(dir_path, name.lower()+"_test") - - env1 = PDDLEnv(domain_file, problem_dir, - operators_as_actions=True, - dynamic_action_space=False, - ) - env2 = PDDLEnv(domain_file, problem_dir, + env = PDDLEnv(domain_file, problem_dir, operators_as_actions=True, dynamic_action_space=True, ) + assert len(env.problems) == 2 # both problems have the same object set - env1.action_space.seed(0) - env2.action_space.seed(0) - state1, _ = env1.reset() - state2, _ = env2.reset() - assert state1 == state2 - + env.fix_problem_index(0) + state1, _ = env.reset() + # Only one action is possible: unstack(a, b) for _ in range(25): - start_time = time.time() - valid_actions1 = env1.action_space.all_ground_literals(state1) - if verbose: - print("Computing valid action spaces without instantiator took {} seconds".format( - time.time() - start_time)) - start_time = time.time() - valid_actions2 = env2.action_space.all_ground_literals(state2) - if verbose: - print("Computing valid action spaces *with* instantiator took {} seconds".format( - time.time() - start_time)) - assert valid_actions2.issubset(valid_actions1) - action = env2.action_space.sample(state2) - state1, _, _, _ = env1.step(action) - state2, _, _, _ = env2.step(action) - - if verbose: - print("Test passed for environment {}.".format(name)) - - print("Test passed.") - - -def test_dynamic_action_space_same_obj(): - """ - """ - dir_path = os.path.join( - os.path.dirname(os.path.dirname(os.path.realpath(__file__))), "pddl") - - name = "dynamic_action_space_same_obj" - domain_file = os.path.join(dir_path, "{}.pddl".format(name.lower())) - problem_dir = os.path.join(dir_path, name.lower()) - - env = PDDLEnv(domain_file, problem_dir, - operators_as_actions=True, - dynamic_action_space=True, - ) - assert len(env.problems) == 2 # both problems have the same object set - - env.fix_problem_index(0) - state1, _ = env.reset() - # Only one action is possible: unstack(a, b) - for _ in range(25): - act1 = env.action_space.sample(state1) - assert act1.predicate.name == "unstack" - assert act1.variables[0].name == "a" - assert act1.variables[1].name == "b" - - env.fix_problem_index(1) - state2, _ = env.reset() - assert state1.objects == state2.objects - # Only one action is possible: unstack(d, c) - for _ in range(25): - act2 = env.action_space.sample(state2) - assert act2.predicate.name == "unstack" - assert act2.variables[0].name == "d" - assert act2.variables[1].name == "c" - - print("Test passed.") + act1 = env.action_space.sample(state1) + assert act1.predicate.name == "unstack" + assert act1.variables[0].name == "a" + assert act1.variables[1].name == "b" + + env.fix_problem_index(1) + state2, _ = env.reset() + assert state1.objects == state2.objects + # Only one action is possible: unstack(d, c) + for _ in range(25): + act2 = env.action_space.sample(state2) + assert act2.predicate.name == "unstack" + assert act2.variables[0].name == "d" + assert act2.variables[1].name == "c" + if __name__ == "__main__": - test_hierarchical_spaces() - # test_dynamic_literal_action_space(verbose=False) - test_dynamic_action_space(verbose=False) - test_dynamic_action_space_same_obj() + unittest.main() diff --git a/pddlgym/tests/test_system.py b/pddlgym/tests/test_system.py index 63411f96..84ac0254 100644 --- a/pddlgym/tests/test_system.py +++ b/pddlgym/tests/test_system.py @@ -3,11 +3,15 @@ import gym import pddlgym -def test_system(): - print("WARNING: this test may take around a minute...") - run_all(render=False, verbose=False) - print("Test passed.") +import unittest + + +class TestSystem(unittest.TestCase): + def test_system(self): + print("WARNING: this test may take around a minute...") + run_all(render=False, verbose=False) + print("Test passed.") if __name__ == '__main__': - test_system() + unittest.main()