예제 #1
0
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.")
예제 #2
0
파일: parser.py 프로젝트: camall3n/pddlgym
 def _parse_domain_predicates(self):
     start_ind = re.search(r"\(:predicates", self.domain).start()
     predicates = self._find_balanced_expression(self.domain, start_ind)
     predicates = predicates[12:-1].strip()
     predicates = self._find_all_balanced_expressions(predicates)
     self.predicates = {}
     for pred in predicates:
         pred = pred.strip()[1:-1].split("?")
         pred_name = pred[0].strip()
         # arg_types = [self.types[arg.strip().split("-")[1].strip()]
         #              for arg in pred[1:]]
         arg_types = []
         for arg in pred[1:]:
             if ' - ' in arg:
                 assert arg_types is not None, "Mixing of typed and untyped args not allowed"
                 assert self.uses_typing
                 arg_type = self.types[arg.strip().split("-", 1)[1].strip()]
                 arg_types.append(arg_type)
             else:
                 assert not self.uses_typing
                 arg_types.append(self.types["default"])
         self.predicates[pred_name] = Predicate(pred_name, len(pred[1:]),
                                                arg_types)
     # Handle equality
     if "=" in self.domain:
         self.predicates["="] = Predicate("=", 2)
예제 #3
0
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.")
예제 #4
0
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 effect_to_literal(literal):
    assert isinstance(literal, Literal)
    assert literal.predicate.name.startswith("Effect")
    non_effect_pred = Predicate(literal.predicate.name[len("Effect"):],
                                literal.predicate.arity,
                                literal.predicate.var_types,
                                is_negative=literal.predicate.is_negative,
                                is_anti=literal.predicate.is_anti)
    return non_effect_pred(*literal.variables)
예제 #6
0
 def _create_actions_from_operators(self):
     actions = set()
     for name, operator in self.operators.items():
         types = [p.var_type for p in operator.params]
         action = Predicate(name, len(types), types)
         assert name not in self.predicates, "Cannot have predicate with same name as operator"
         self.predicates[name] = action
         actions.add(action)
     return actions
예제 #7
0
 def _preprocess_negative_literals(cls, kb, conds):
     # Check for negated quantifiers, which we do not handle
     if any((isinstance(c, Exists) or isinstance(c, ForAll)) and c.is_negative \
             for c in conds):
         raise NotImplementedError("We do not yet handle negated quantifiers")
     # Find all predicates with a negated literal in the conds
     negated_predicates = set()
     for cond in cls._get_lits_from_conds(conds):
         if cond.is_negative:
             negated_predicates.add(cond.predicate)
     if len(negated_predicates) == 0:
         return kb, conds
     # Start the new kb and conds
     kb = [lit for lit in kb]
     conds = [c for c in conds]
     # Sanity check
     assert all(str(p).startswith("Not") for p in negated_predicates)
     # Create positive predicates for the negated predicates
     negated_pred_to_pos_pred = {}
     for p in negated_predicates:
         # Prolog hands = specially
         if p.name == "=":
             pos_pred = Predicate(f"neg-eq", p.arity, p.var_types)
         else:
             pos_pred = Predicate(f"neg-{p.name}", p.arity, p.var_types)
         negated_pred_to_pos_pred[p] = pos_pred
     # TODO pass in objects separately
     objects = { o for lit in kb for o in lit.variables }
     # Get all instantiations of the new positive predicates
     for negated_pred, pos_pred in negated_pred_to_pos_pred.items():
         original_positive_pred = negated_pred.positive
         # Get all combinations of objects
         for objs in get_object_combinations(objects,
             arity=pos_pred.arity,
             var_types=pos_pred.var_types,
             allow_duplicates=True):
             # Check whether the positive version is in the kb
             if original_positive_pred(*objs) in kb:
                 continue
             # Add the new positive literal to the kb
             kb.append(pos_pred(*objs))
         # Update the conds to include the positive pred instead of the negative pred
         conds = cls._replace_predicate(conds, negated_pred, pos_pred)
     return kb, conds
예제 #8
0
 def wrap_goal_literal(cls, x):
     """Helper for converting a state to required input representation
     """
     if isinstance(x, Predicate):
         return Predicate("WANT" + x.name,
                          x.arity,
                          var_types=x.var_types,
                          is_negative=x.is_negative,
                          is_anti=x.is_anti)
     new_predicate = cls.wrap_goal_literal(x.predicate)
     return new_predicate(*x.variables)
예제 #9
0
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 Effect(x):  # pylint:disable=invalid-name
    """An effect predicate or literal.
    """
    if isinstance(x, Predicate):
        return Predicate("Effect" + x.name,
                         x.arity,
                         var_types=x.var_types,
                         is_negative=x.is_negative,
                         is_anti=x.is_anti)
    assert isinstance(x, Literal)
    new_predicate = Effect(x.predicate)
    return new_predicate(*x.variables)
예제 #11
0
 def reverse_binary_literal(cls, x):
     """Helper for converting a state to required input representation
     """
     if isinstance(x, Predicate):
         assert x.arity == 2
         return Predicate("REV" + x.name,
                          x.arity,
                          var_types=x.var_types,
                          is_negative=x.is_negative,
                          is_anti=x.is_anti)
     new_predicate = cls.reverse_binary_literal(x.predicate)
     variables = [v for v in x.variables]
     assert len(variables) == 2
     return new_predicate(*variables[::-1])
예제 #12
0
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.")
예제 #13
0
    def _create_problem_file(self, raw_problem_fname, use_cache=True):
        if (not use_cache) or (raw_problem_fname not in self._problem_files):
            problem_fname = os.path.split(raw_problem_fname)[-1]
            problem_fname = problem_fname.split('.pddl')[0]
            problem_fname += '_{}_with_diffs_{}.pddl'.format(
                self.domain_name, random.randint(0, 9999999))
            problem_fname = os.path.join('/tmp', problem_fname)

            # Parse raw problem
            problem_parser = PDDLProblemParser(raw_problem_fname,
                                               self.domain_name.lower(),
                                               self._types, self._predicates,
                                               self._actions)
            new_initial_state = set(problem_parser.initial_state)

            # Add actions
            action_lits = set(
                self._action_space.all_ground_literals(State(
                    new_initial_state, problem_parser.objects,
                    problem_parser.goal),
                                                       valid_only=False))
            new_initial_state |= action_lits

            # Add 'Different' pairs for each pair of objects
            Different = Predicate('Different', 2)

            for obj1 in problem_parser.objects:
                for obj2 in problem_parser.objects:
                    if obj1 == obj2:
                        continue
                    # if obj1.var_type != obj2.var_type:
                    #     continue
                    diff_lit = Different(obj1, obj2)
                    new_initial_state.add(diff_lit)

            # Write out new temporary problem file
            problem_parser.initial_state = frozenset(new_initial_state)
            problem_parser.write(problem_fname)

            # Add to cache
            self._problem_files[raw_problem_fname] = problem_fname

        return self._problem_files[raw_problem_fname]
예제 #14
0
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.")
예제 #15
0
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.")
예제 #16
0
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.")
class FOLDTOperatorLearningModule:

    _NoChange = Predicate("NoChange", 0)

    def __init__(self, learned_operators):
        self._learned_operators = learned_operators
        self._learned_operators_for_action = defaultdict(set)
        self._Xs = defaultdict(list)
        self._Ys = defaultdict(list)
        self._seed = ac.seed
        self._rand_state = np.random.RandomState(seed=ac.seed)
        self.learned_dts = {}
        self._fits_all_data = defaultdict(bool)
        self._learning_on = True

    def observe(self, state, action, effects):
        if not self._learning_on:
            return
        x = (state.literals | {action})
        y = sorted([Effect(e) for e in effects])

        if not y:
            y.append(Effect(self._NoChange()))

        self._Xs[action.predicate].append(x)
        self._Ys[action.predicate].append(y)
        # print("observed data:")
        # print(x)
        # print(y)
        # input("!!")

        # Check whether we'll need to relearn
        if self._fits_all_data[action.predicate]:
            dt = self.learned_dts[action.predicate]
            if not self._dt_fits_data(dt, x, y):
                self._fits_all_data[action.predicate] = False

    def learn(self):
        if not self._learning_on:
            return False
        is_updated = False
        for action_predicate in self._fits_all_data:
            if not self._fits_all_data[action_predicate]:
                # Learn one main tree.
                try:
                    dt = self._learn_single_dt(action_predicate, self._seed,
                                               self._Xs[action_predicate],
                                               self._Ys[action_predicate])
                except LearningFailure:
                    # Aggressive!!!!!!!!!
                    self._Xs[action_predicate] = []
                    self._Ys[action_predicate] = []
                    continue
                self.learned_dts[action_predicate] = dt
                operators = self._foldt_to_operators(dt, action_predicate.name)
                for op in operators:
                    if not sum(lit.predicate.name == action_predicate
                               for lit in op.preconds.literals) == 1:
                        # Something is wrong...why are multiple action
                        # predicates appearing in the preconditions?
                        import ipdb
                        ipdb.set_trace()
                # Remove old operators
                self._learned_operators_for_action[action_predicate].clear()
                # Add new operators
                self._learned_operators_for_action[action_predicate].update(
                    operators)
                self._fits_all_data[action_predicate] = True
                is_updated = True

        # Update all learned operators
        if is_updated:
            self._learned_operators.clear()
            for operators in self._learned_operators_for_action.values():
                self._learned_operators.update(operators)

        return is_updated

    @staticmethod
    def _learn_single_dt(action_predicate,
                         seed,
                         X,
                         Y,
                         bag_predicates=False,
                         bag_features=False):
        root_literal = action_predicate(
            *
            ['Placeholder{}'.format(i) for i in range(action_predicate.arity)])
        dt = FOLDTClassifier(
            seed=seed,
            root_feature=root_literal,
            max_feature_length=ac.max_foldt_feature_length,
            max_learning_time=ac.max_foldt_learning_time,
            max_exceeded_strategy=ac.max_foldt_exceeded_strategy,
            bag_predicates=bag_predicates,
            bag_features=bag_features)
        dt.fit(X, Y)
        return dt

    def turn_off(self):
        self._learning_on = False

    def _dt_fits_data(self, dt, x, y):
        prediction = self.get_prediction(x, dt)
        if prediction is None:
            match = y is None
        else:
            match = set(y) == set(prediction)
        # if not match:
        #     print("Mismatch:")
        #     print("x =", x)
        #     print("y =", y)
        #     print("prediction =", prediction)
        return match

    @classmethod
    def get_prediction(cls, x, dt):
        prediction = dt.predict(x)
        if prediction is None:
            return prediction
        # Cancel out effects if possible (e.g. At(x) and AntiAt(x))
        final_prediction = set()
        for lit in prediction:
            if lit.inverted_anti in final_prediction:
                final_prediction.remove(lit.inverted_anti)
            else:
                final_prediction.add(lit)
        if not final_prediction:
            final_prediction = [Effect(cls._NoChange())]
        return sorted(list(final_prediction))

    def _foldt_to_operators(self, dt, action_name, suffix=''):
        op_counter = 0
        operators = set()
        for (path, leaf) in dt.get_conditional_literals(dt.root):
            if leaf is None:
                continue
            if any(lit.predicate == Effect(self._NoChange) for lit in leaf):
                continue
            name = "LearnedOperator{}{}{}".format(action_name, op_counter,
                                                  suffix)
            op_counter += 1
            # NoChange appears only in effects in the training data, so it
            # should never be in the preconditions of the learned operators.
            assert not any(lit.predicate.positive == self._NoChange
                           for lit in path)
            preconds = LiteralConjunction(path)
            effects = LiteralConjunction([effect_to_literal(l) for l in leaf])
            params = self._get_params_from_preconds(preconds)
            operator = Operator(name, params, preconds, effects)
            operators.add(operator)
        return operators

    def _get_params_from_preconds(self, preconds):
        param_set = set()
        for lit in preconds.literals:
            if lit.negated_as_failure:
                continue
            for v in lit.variables:
                param_set.add(v)
        return sorted(list(param_set))
예제 #18
0
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))
예제 #19
0
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.")
예제 #20
0
from pddlgym.structs import Predicate, ground_literal, LiteralConjunction
from pddlgym.parser import Operator
from pddlgym.inference import find_satisfying_assignments
import numpy as np

### Noisy deictic rules
NOISE_OUTCOME = Predicate("noiseoutcome", 0, [])()


class MultipleOutcomesPossible(Exception):
    pass


class NDR:
    """A Noisy Deictic Rule has a lifted action, lifted preconditions, and a
       distribution over effects.

    Parameters
    ----------
    action : Literal
    preconditions : [ Literal ]
    effect_probs : np.ndarray
    effects : [Literal]
    """
    def __init__(self,
                 action,
                 preconditions,
                 effect_probs,
                 effects,
                 allow_redundant_variables=False):
        self._action = action
예제 #21
0
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)
예제 #22
0
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.")
예제 #23
0
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.")
예제 #24
0
    def _create_problem_file(self, raw_problem_fname, use_cache=True):
        if (not use_cache) or (raw_problem_fname not in self._problem_files):
            problem_fname = os.path.split(raw_problem_fname)[-1]
            problem_fname = problem_fname.split('.pddl')[0]
            problem_fname += '_{}_with_diffs_{}.pddl'.format(
                self.domain_name, random.randint(0, 9999999))
            problem_fname = os.path.join('/tmp', problem_fname)

            # Parse raw problem
            action_names = [
            ]  # purposely empty b/c we WANT action literals in there
            problem_parser = PDDLProblemParser(raw_problem_fname,
                                               self.domain_name.lower(),
                                               self._types, self._predicates,
                                               action_names)

            # Add action literals (in case they're not already present in the initial state)
            # which will be true when the original domain uses operators_as_actions
            init_state = State(problem_parser.initial_state,
                               problem_parser.objects, None)
            act_lits = self._action_space.all_ground_literals(init_state,
                                                              valid_only=False)
            problem_parser.initial_state = frozenset(
                act_lits | problem_parser.initial_state)

            # Add 'Different' pairs for each pair of objects
            Different = Predicate('Different', 2)
            init_state = set(problem_parser.initial_state)
            for obj1 in problem_parser.objects:
                for obj2 in problem_parser.objects:
                    if obj1 == obj2:
                        continue
                    # if obj1.var_type != obj2.var_type:
                    #     continue
                    diff_lit = Different(obj1, obj2)
                    init_state.add(diff_lit)
            problem_parser.initial_state = frozenset(init_state)
            # Also add 'different' pairs for goal if it's existential
            if isinstance(problem_parser.goal, Exists):
                diffs = []
                for var1 in problem_parser.goal.variables:
                    for var2 in problem_parser.goal.variables:
                        if var1 == var2:
                            continue
                        diffs.append(Different(var1, var2))
                problem_parser.goal = Exists(
                    problem_parser.goal.variables,
                    type(problem_parser.goal.body)(
                        problem_parser.goal.body.literals + diffs))

            # If no objects, write a dummy one to make FF not crash.
            if not problem_parser.objects:
                problem_parser.objects.append("DUMMY")

            # Write out new temporary problem file
            problem_parser.write(problem_fname)

            # Add to cache
            self._problem_files[raw_problem_fname] = (problem_fname,
                                                      problem_parser.objects)

        return self._problem_files[raw_problem_fname]