Exemple #1
0
 def get_children(self, action_rule_set, ndr_settings=None):
     for i in range(len(action_rule_set.ndrs)):
         for new_lit in self._all_possible_additions:
             # if new_lit.predicate.name == "start":
                 # import ipdb; ipdb.set_trace()
             # No use adding a lit that's already there
             if new_lit in action_rule_set.ndrs[i].preconditions or \
                Not(new_lit) in action_rule_set.ndrs[i].preconditions:
                 continue
             new_rule_set = action_rule_set.copy()
             pos_ndr = new_rule_set.ndrs[i]
             pos_ndr.preconditions.append(new_lit)
             neg_ndr = action_rule_set.ndrs[i].copy()
             neg_ndr.preconditions.append(Not(new_lit))
             new_rule_set.ndrs.insert(i+1, neg_ndr)
             partitions = new_rule_set.partition_transitions(self.transitions_for_action)
             # Induce new outcomes for modified ndrs
             induce_outcomes(pos_ndr, partitions[i], ndr_settings=ndr_settings)
             induce_outcomes(neg_ndr, partitions[i+1], ndr_settings=ndr_settings)
             # Update default rule parameters
             learn_parameters(new_rule_set.default_ndr, partitions[-1], 
                 ndr_settings=ndr_settings)
             score = score_action_rule_set(new_rule_set, self.transitions_for_action,
                 ndr_settings=ndr_settings)
             yield score, new_rule_set
Exemple #2
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.")
Exemple #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.")
Exemple #4
0
 def _prolog_goal_line(self, lit):
     """
     """
     if isinstance(lit, LiteralConjunction):
         inner_str = ",".join(
             self._prolog_goal_line(l) for l in lit.literals)
         return "({})".format(inner_str)
     if isinstance(lit, LiteralDisjunction):
         inner_str = ";".join(
             self._prolog_goal_line(l) for l in lit.literals)
         return "({})".format(inner_str)
     if lit.is_negative:
         pos_pred_str = self._prolog_goal_line(lit.positive)
         pred_str = "\\+({})".format(pos_pred_str)
         return pred_str
     if isinstance(lit, Literal):
         pred_name = self._clean_predicate_name(lit.predicate.name)
         variables = ",".join(
             [self._clean_variable_name(a.name) for a in lit.variables])
         pred_str = "{}({})".format(pred_name, variables)
         return pred_str
     if isinstance(lit, ForAll):
         variables = ",".join(
             [self._clean_variable_name(a.name) for a in lit.variables])
         assert len(variables
                    ) == 1, "TODO: support ForAlls over multiple variables"
         variable = variables[0]
         var_type = lit.variables[0].var_type
         objects_of_type = self._type_to_atomnames[var_type]
         objects_str = "[" + ",".join(objects_of_type) + "]"
         pred_str_body = self._prolog_goal_line(lit.body)
         pred_str = "forall(member({}, {}), {})".format(
             variable, objects_str, pred_str_body)
         return pred_str
     if isinstance(lit, Exists):
         return self._prolog_goal_line(
             Not(ForAll(Not(lit.body), lit.variables)))
     raise NotImplementedError()
Exemple #5
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.")
Exemple #6
0
 def _parse_into_literal(self, string, params, is_effect=False):
     """Parse the given string (representing either preconditions or effects)
     into a literal. Check against params to make sure typing is correct.
     """
     assert string[0] == "("
     assert string[-1] == ")"
     if string.startswith("(and") and string[4] in (" ", "\n", "("):
         clauses = self._find_all_balanced_expressions(string[4:-1].strip())
         return LiteralConjunction([
             self._parse_into_literal(clause, params, is_effect=is_effect)
             for clause in clauses
         ])
     if string.startswith("(or") and string[3] in (" ", "\n", "("):
         clauses = self._find_all_balanced_expressions(string[3:-1].strip())
         return LiteralDisjunction([
             self._parse_into_literal(clause, params, is_effect=is_effect)
             for clause in clauses
         ])
     if string.startswith("(forall") and string[7] in (" ", "\n", "("):
         new_binding, clause = self._find_all_balanced_expressions(
             string[7:-1].strip())
         new_name, new_type_name = new_binding.strip()[1:-1].split("-")
         new_name = new_name.strip()
         new_type_name = new_type_name.strip()
         assert new_name not in params, "ForAll variable {} already exists".format(
             new_name)
         params[new_name] = self.types[new_type_name]
         result = ForAll(
             self._parse_into_literal(clause, params, is_effect=is_effect),
             TypedEntity(new_name, params[new_name]))
         del params[new_name]
         return result
     if string.startswith("(exists") and string[7] in (" ", "\n", "("):
         new_binding, clause = self._find_all_balanced_expressions(
             string[7:-1].strip())
         if new_binding[1:-1] == "":
             # Handle existential goal with no arguments.
             body = self._parse_into_literal(clause,
                                             params,
                                             is_effect=is_effect)
             return body
         variables = self._parse_objects(new_binding[1:-1])
         for v in variables:
             params[v.name] = v.var_type
         body = self._parse_into_literal(clause,
                                         params,
                                         is_effect=is_effect)
         result = Exists(variables, body)
         for v in variables:
             del params[v.name]
         return result
     if string.startswith("(probabilistic") and string[14] in (" ", "\n",
                                                               "("):
         assert is_effect, "We only support probabilistic effects"
         lits = []
         probs = []
         expr = string[14:-1].strip()
         for match in re.finditer("(\d*\.?\d+)", expr):
             prob = float(match.group())
             subexpr = self._find_balanced_expression(
                 expr[match.end():].strip(), 0)
             lit = self._parse_into_literal(subexpr,
                                            params,
                                            is_effect=is_effect)
             lits.append(lit)
             probs.append(prob)
         return ProbabilisticEffect(lits, probs)
     if string.startswith("(not") and string[4] in (" ", "\n", "("):
         clause = string[4:-1].strip()
         if is_effect:
             return Anti(
                 self._parse_into_literal(clause,
                                          params,
                                          is_effect=is_effect))
         else:
             return Not(
                 self._parse_into_literal(clause,
                                          params,
                                          is_effect=is_effect))
     string = string[1:-1].split()
     pred, args = string[0], string[1:]
     typed_args = []
     # Validate types against the given params dict.
     assert pred in self.predicates, "Predicate {} is not defined".format(
         pred)
     assert self.predicates[pred].arity == len(args), pred
     for i, arg in enumerate(args):
         if arg not in params:
             raise Exception("Argument {} not in params {}".format(
                 arg, params))
         assert arg in params, "Argument {} is not in the params".format(
             arg)
         if isinstance(params, dict):
             typed_arg = TypedEntity(arg, params[arg])
         else:
             typed_arg = params[params.index(arg)]
         typed_args.append(typed_arg)
     return self.predicates[pred](*typed_args)
Exemple #7
0
 def _parse_into_literal(self, string, params, is_effect=False):
     """Parse the given string (representing either preconditions or effects)
     into a literal. Check against params to make sure typing is correct.
     """
     assert string[0] == "("
     assert string[-1] == ")"
     if string.startswith("(and") and string[4] in (" ", "\n", "("):
         clauses = self._find_all_balanced_expressions(string[4:-1].strip())
         return LiteralConjunction([
             self._parse_into_literal(clause, params, is_effect=is_effect)
             for clause in clauses
         ])
     if string.startswith("(or") and string[3] in (" ", "\n", "("):
         clauses = self._find_all_balanced_expressions(string[3:-1].strip())
         return LiteralDisjunction([
             self._parse_into_literal(clause, params, is_effect=is_effect)
             for clause in clauses
         ])
     if string.startswith("(forall") and string[7] in (" ", "\n", "("):
         new_binding, clause = self._find_all_balanced_expressions(
             string[7:-1].strip())
         new_name, new_type_name = new_binding.strip()[1:-1].split("-")
         new_name = new_name.strip()
         new_type_name = new_type_name.strip()
         assert new_name not in params, "ForAll variable {} already exists".format(
             new_name)
         params[new_name] = self.types[new_type_name]
         result = ForAll(
             self._parse_into_literal(clause, params, is_effect=is_effect),
             TypedEntity(new_name, params[new_name]))
         del params[new_name]
         return result
     if string.startswith("(exists") and string[7] in (" ", "\n", "("):
         new_binding, clause = self._find_all_balanced_expressions(
             string[7:-1].strip())
         variables = self._parse_objects(new_binding[1:-1])
         for v in variables:
             params[v.name] = v.var_type
         body = self._parse_into_literal(clause,
                                         params,
                                         is_effect=is_effect)
         result = Exists(variables, body)
         for v in variables:
             del params[v.name]
         return result
     if string.startswith("(not") and string[4] in (" ", "\n", "("):
         clause = string[4:-1].strip()
         if is_effect:
             return Anti(
                 self._parse_into_literal(clause,
                                          params,
                                          is_effect=is_effect))
         else:
             return Not(
                 self._parse_into_literal(clause,
                                          params,
                                          is_effect=is_effect))
     string = string[1:-1].split()
     pred, args = string[0], string[1:]
     # Validate types against the given params dict.
     assert pred in self.predicates, "Predicate {} is not defined".format(
         pred)
     assert self.predicates[pred].arity == len(args), pred
     for i, arg in enumerate(args):
         if arg not in params:
             import ipdb
             ipdb.set_trace()
         assert arg in params, "Argument {} is not in the params".format(
             arg)
     return self.predicates[pred](*args)
Exemple #8
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))