def _parse_domain(self, f_domain): """ Extract information from the domain file. The following will be extracted: * types * predicates * actions """ parse_tree = PDDL_Tree.create(f_domain) assert "domain" in parse_tree, "Domain must have a name" self.domain_name = parse_tree ["domain"].named_children ()[0] # must read types before constants if ":types" in parse_tree: if "-" in parse_tree[":types"].named_children(): type_hierarchy = PDDL_Utils.read_type(parse_tree[":types"]) self.parent_types = {subtype: parent for subtype, parent in type_hierarchy} self.types = set(parse_tree[":types"].named_children()) self.types.discard("-") else: self.types = set(parse_tree[":types"].named_children()) self.parent_types = {t: None for t in self.types} else: self.types = set([Predicate.OBJECT]) self.parent_types = {Predicate.OBJECT: None} # must read in constants before actions or predicates if ":constants" in parse_tree: object_list = PDDL_Utils.read_type(parse_tree[":constants"]) self._add_objects(object_list) #TODO this may not be correct, depending on the type hierchy const_map = {const: list(self.obj_to_type[const])[0] for const in self.objects} self.predicates = [self.to_predicate(c, map=const_map) for c in parse_tree[":predicates"].children] # some predicates have this property: they are untyped. for predicate in self.predicates: if Predicate.OBJECT not in self.types and any([arg[1] == Predicate.OBJECT for arg in predicate.args]): for t in self.types: if self.parent_types[t] is None: self.parent_types[t] = Predicate.OBJECT self.parent_types[Predicate.OBJECT] = None self.types.add(Predicate.OBJECT) self.type_to_obj[Predicate.OBJECT] = set([]) for obj, type_list in self.obj_to_type.iteritems(): type_list.add(Predicate.OBJECT) self.type_to_obj[Predicate.OBJECT].add(obj) # only need to do this once, obviously break self.actions = [self.to_action(c) for c in parse_tree.find_all(":action")]
def _parse_problem(self, f_problem): """ Extract information from the problem file. The following will be extracted: * problem name * objects * initial state * goal state * type_to_obj * obj_to_type """ parse_tree = PDDL_Tree.create(f_problem) assert "problem" in parse_tree, "Problem must have a name" self.problem_name = parse_tree["problem"].named_children()[0] # objects must be parsed first if ":objects" in parse_tree: object_list = PDDL_Utils.read_type(parse_tree[":objects"]) self._add_objects(object_list) #TODO this may not be valid with a non-flat type hierchy obj_map = {obj: list(self.obj_to_type[obj])[0] for obj in self.objects} # the goal can be expressed in either a formula form, or a direct form if len(parse_tree[":goal"].children ) == 1 and parse_tree[":goal"].children[0].name == "and": self.goal = And([ Primitive(self.to_fluents(c)) for c in parse_tree[":goal"].children[0].children ]) else: self.goal = And([ Primitive(self.to_fluents(c)) for c in parse_tree[":goal"].children ]) # it is critical that the formula here be checked against the objects if len(parse_tree[":init"].children) == 1 and \ parse_tree[":init"].children[0].name == "and": self.init = self.to_formula(parse_tree[":init"].children[0], obj_map) else: # initial condition is one big AND # print "```", self.init self.init = And([ self.to_formula(c, obj_map) for c in parse_tree[":init"].children ])
def to_action(self, node): """ Create an action out of this PDDL_Tree node. For now, will assume this makes sense. """ name = node.children[0].name parameter_map = {} if ":parameters" in node: params = PDDL_Utils.read_type(node[":parameters"]) parameter_map = {p[0]: p[1] for p in params} # map of variable-names to types else: params = [] assert ":derive-condition" in node, "Error: You must include the :derive-condition value for every action." dcond_ind = [n.name for n in node.children].index(':derive-condition') dcond = self.to_formula(node.children[dcond_ind + 1], parameter_map) if ":precondition" in node: assert len(node[":precondition"].children) == 1,\ "precondition should have one top-level child" precond = self.to_formula(node[":precondition"].children[0], parameter_map) else: precond = None if ":observe" in node: assert len(node[":observe"].children) == 1,\ "observe should have one top-level child" observe = self.to_predicate(node[":observe"].children[0], map=parameter_map) else: observe = None if ":effect" in node: assert len(node[":effect"].children) == 1,\ "effect should have one top-level child" effect = self.to_formula(node[":effect"].children[0], parameter_map) else: effect = None return Action(name, params, precond, observe, effect, dcond)
def to_predicate(self, node, f='predicate', map=None): """ Create a predicate out of this PDDL_Tree node. For now, will assume this makes sense. """ if 'AK{}' == node.name: assert 1 == len( node.children), "Error: AK{} had more than one child" pred = self.to_predicate(node.children[0], f, map) pred.always_known = True return pred args = PDDL_Utils.read_type(node) # change the type if there is only 1 type if len(self.types) == 1: t_args = args t = list(self.types)[0] args = [] for arg in t_args: if arg[1] != t: args.append((arg[0], t)) else: args.append(arg) # here is where the map comes in... if map is None: if 'predicate' == f: return Predicate(node.name, args) elif 'fluent' == f: return Predicate(node.name, args=None, ground_args=args) else: new_args = [] for v, t in args: if v in map: new_args.append((v, map[v])) else: new_args.append((v, t)) if 'predicate' == f: return Predicate(node.name, new_args) elif 'fluent' == f: return Predicate(node.name, args=None, ground_args=new_args)
def to_action(self, node): """ Create an action out of this PDDL_Tree node. For now, will assume this makes sense. """ name = node.children[0].name parameter_map = {} if ":parameters" in node: params = PDDL_Utils.read_type(node[":parameters"]) parameter_map = {p[0]: p[1] for p in params} # map of variable-names to types else: params = [] if ":precondition" in node: assert len(node[":precondition"].children) == 1,\ "precondition should have one top-level child" precond = self.to_formula(node[":precondition"].children[0], parameter_map) else: precond = None if ":observe" in node: assert len(node[":observe"].children) == 1,\ "observe should have one top-level child" observe = self.to_predicate(node[":observe"].children[0], map=parameter_map) else: observe = None if ":effect" in node: assert len(node[":effect"].children) == 1,\ "effect should have one top-level child" effect = self.to_formula(node[":effect"].children[0], parameter_map) else: effect = None return Action(name, params, precond, observe, effect)
def _parse_problem(self, f_problem): """ Extract information from the problem file. The following will be extracted: * problem name * objects * initial state * goal state * type_to_obj * obj_to_type """ parse_tree = PDDL_Tree.create(f_problem) assert "problem" in parse_tree, "Problem must have a name" self.problem_name = parse_tree ["problem"].named_children ()[0] # objects must be parsed first if ":objects" in parse_tree: object_list = PDDL_Utils.read_type(parse_tree[":objects"]) self._add_objects(object_list) #TODO this may not be valid with a non-flat type hierchy obj_map = {obj: list(self.obj_to_type[obj])[0] for obj in self.objects} # the goal can be expressed in either a formula form, or a direct form if len(parse_tree[":goal"].children) == 1 and parse_tree[":goal"].children[0].name == "and": self.goal = And([Primitive(self.to_fluents(c)) for c in parse_tree[":goal"].children[0].children]) else: self.goal = And([Primitive(self.to_fluents(c)) for c in parse_tree[":goal"].children]) # it is critical that the formula here be checked against the objects if len(parse_tree[":init"].children) == 1 and \ parse_tree[":init"].children[0].name == "and": self.init = self.to_formula(parse_tree[":init"].children[0], obj_map) else: # initial condition is one big AND self.init = And([self.to_formula(c, obj_map) for c in parse_tree[":init"].children])
def to_predicate(self, node, f='predicate', map=None): """ Create a predicate out of this PDDL_Tree node. For now, will assume this makes sense. """ args = PDDL_Utils.read_type(node) # change the type if there is only 1 type if len(self.types) == 1: t_args = args t = list(self.types)[0] args = [] for arg in t_args: if arg[1] != t: args.append((arg[0], t)) else: args.append(arg) # here is where the map comes in... if map is None: if 'predicate' == f: return Predicate(node.name, args) elif 'fluent' == f: return Predicate(node.name, args=None, ground_args=args) else: new_args = [] for v, t in args: if v in map: new_args.append((v, map[v])) else: new_args.append((v, t)) if 'predicate' == f: return Predicate(node.name, new_args) elif 'fluent' == f: return Predicate(node.name, args=None, ground_args=new_args)
def to_predicate(self, node, f='predicate', map=None): """ Create a predicate out of this PDDL_Tree node. For now, will assume this makes sense. """ args = PDDL_Utils.read_type(node) # change the type if there is only 1 type if len (self.types) == 1: t_args = args t = list (self.types) [0] args = [] for arg in t_args: if arg[1] != t: args.append ( (arg[0], t) ) else: args.append (arg) # here is where the map comes in... if map is None: if 'predicate' == f: return Predicate(node.name, args) elif 'fluent' == f: return Predicate(node.name, args=None, ground_args=args) else: new_args = [] for v, t in args: if v in map: new_args.append((v, map[v])) else: new_args.append((v, t)) if 'predicate' == f: return Predicate(node.name, new_args) elif 'fluent' == f: return Predicate(node.name, args=None, ground_args=new_args)
def to_formula(self, node, parameter_map=None): """ Return a formula out of this PDDL_Tree node. For now, will assume this makes sense. """ # forall is so weird that we can treat it as an entirely seperate entity if "forall" == node.name: # treat args differently in this case assert len(node.children) in[2, 4],\ "Forall must have a variable(typed or untyped) and formula that it quantifies" i = len(node.children) - 1 if len(node.children) == 2 and len(node.children[0].children) > 0: # adjust this node by changing the structure of the first child new_child = PDDL_Tree(PDDL_Tree.EMPTY) new_child.add_child(PDDL_Tree(node.children[0].name)) for c in node.children[0].children: new_child.add_child(c) node.children[0] = new_child l = PDDL_Utils.read_type(new_child) for v, t in l: parameter_map[v] = t args = [ self.to_formula(c, parameter_map) for c in node.children[i:] ] for v, t in l: del (parameter_map[v]) return Forall(l, args) i = 0 args = [self.to_formula(c, parameter_map) for c in node.children[i:]] if "and" == node.name: return And(args) elif "or" == node.name: return Or(args) elif "oneof" == node.name: return Oneof(args) elif "not" == node.name: return Not(args) elif "xor" == node.name: return Xor(args) elif "nondet" == node.name: assert len(node.children) == 1,\ "nondet must only have a single child as a predicate" # make p != p2, otherwise might run into issues with mutation in some later step return Oneof([args[0], Not(args)]) elif "unknown" == node.name: assert len(node.children) == 1,\ "unknown must only have a single child as a predicate" # make p != p2, otherwise might run into issues with mutation in some later step p = Primitive( self.to_predicate(node.children[0], map=parameter_map)) p2 = Primitive( self.to_predicate(node.children[0], map=parameter_map)) return Xor([p, Not([p2])]) elif "when" == node.name: assert len(args) == 2,\ "When clause must have exactly 2 children" return When(args[0], args[1]) else: # it's a predicate return Primitive(self.to_predicate(node, map=parameter_map))
def _parse_domain(self, f_domain): """ Extract information from the domain file. The following will be extracted: * types * predicates * actions """ parse_tree = PDDL_Tree.create(f_domain) assert "domain" in parse_tree, "Domain must have a name" self.domain_name = parse_tree["domain"].named_children()[0] # must read types before constants if ":types" in parse_tree: if "-" in parse_tree[":types"].named_children(): type_hierarchy = PDDL_Utils.read_type(parse_tree[":types"]) self.parent_types = { subtype: parent for subtype, parent in type_hierarchy } self.types = set(parse_tree[":types"].named_children()) self.types.discard("-") else: self.types = set(parse_tree[":types"].named_children()) self.parent_types = {t: None for t in self.types} else: self.types = set([Predicate.OBJECT]) self.parent_types = {Predicate.OBJECT: None} # must read in constants before actions or predicates if ":constants" in parse_tree: object_list = PDDL_Utils.read_type(parse_tree[":constants"]) self._add_objects(object_list) #TODO this may not be correct, depending on the type hierchy const_map = { const: list(self.obj_to_type[const])[0] for const in self.objects } self.predicates = [ self.to_predicate(c, map=const_map) for c in parse_tree[":predicates"].children ] # some predicates have this property: they are untyped. for predicate in self.predicates: if Predicate.OBJECT not in self.types and any( [arg[1] == Predicate.OBJECT for arg in predicate.args]): for t in self.types: if self.parent_types[t] is None: self.parent_types[t] = Predicate.OBJECT self.parent_types[Predicate.OBJECT] = None self.types.add(Predicate.OBJECT) self.type_to_obj[Predicate.OBJECT] = set([]) for obj, type_list in self.obj_to_type.iteritems(): type_list.add(Predicate.OBJECT) self.type_to_obj[Predicate.OBJECT].add(obj) # only need to do this once, obviously break self.actions = [ self.to_action(c) for c in parse_tree.find_all(":action") ]
def to_formula(self, node, parameter_map=None): """ Return a formula out of this PDDL_Tree node. For now, will assume this makes sense. """ # forall is so weird that we can treat it as an entirely seperate entity if "forall" == node.name: # treat args differently in this case assert len(node.children) in[2, 4],\ "Forall must have a variable(typed or untyped) and formula that it quantifies" i = len(node.children) - 1 if len(node.children) == 2 and len(node.children[0].children) > 0: # adjust this node by changing the structure of the first child new_child = PDDL_Tree(PDDL_Tree.EMPTY) new_child.add_child(PDDL_Tree(node.children[0].name)) for c in node.children[0].children: new_child.add_child(c) node.children[0] = new_child l = PDDL_Utils.read_type(new_child) for v, t in l: parameter_map[v] = t args = [self.to_formula(c, parameter_map) for c in node.children[i:]] for v, t in l: del(parameter_map[v]) return Forall(l, args) i = 0 args = [self.to_formula(c, parameter_map) for c in node.children[i:]] if "and" == node.name: return And(args) elif "or" == node.name: return Or(args) elif "oneof" == node.name: return Oneof(args) elif "not" == node.name: return Not(args) elif "xor" == node.name: return Xor(args) elif "nondet" == node.name: assert len(node.children) == 1,\ "nondet must only have a single child as a predicate" # make p != p2, otherwise might run into issues with mutation in some later step return Oneof([args[0], Not(args)]) elif "unknown" == node.name: assert len(node.children) == 1,\ "unknown must only have a single child as a predicate" # make p != p2, otherwise might run into issues with mutation in some later step p = Primitive(self.to_predicate(node.children[0], map=parameter_map)) p2 = Primitive(self.to_predicate(node.children[0], map=parameter_map)) return Xor([p, Not([p2])]) elif "when" == node.name: assert len(args) == 2,\ "When clause must have exactly 2 children" return When(args[0], args[1]) else: # it's a predicate return Primitive(self.to_predicate(node, map=parameter_map))
def to_formula(self, node, parameter_map=None): """ Return a formula out of this PDDL_Tree node. For now, will assume this makes sense. """ # forall is so weird that we can treat it as an entirely seperate entity if "forall" == node.name: # treat args differently in this case assert len(node.children) in[2, 4],\ "Forall must have a variable(typed or untyped) and formula that it quantifies" i = len(node.children) - 1 if len(node.children) == 2 and len(node.children[0].children) > 0: # adjust this node by changing the structure of the first child new_child = PDDL_Tree(PDDL_Tree.EMPTY) new_child.add_child(PDDL_Tree(node.children[0].name)) for c in node.children[0].children: new_child.add_child(c) node.children[0] = new_child l = PDDL_Utils.read_type(new_child) else: l = [(node.children[0].name, node.children[2].name)] for v, t in l: parameter_map[v] = t args = [ self.to_formula(c, parameter_map) for c in node.children[i:] ] for v, t in l: del (parameter_map[v]) return Forall(l, args) i = 0 args = [self.to_formula(c, parameter_map) for c in node.children[i:]] def handle_modality(node, pref_len, modality): assert 1 <= len( node.children) <= 2, "Error: Found %d children." % len( node.children) #print "%s / %s / %s" % (str(node), str(pref_len), str(modality)) ag = node.name[pref_len:-1] if len(node.children) == 1: pred = self.to_formula(node.children[0], parameter_map) else: pred = self.to_formula(node.children[1], parameter_map) pred.negated_rml = True assert not isinstance( pred, Not ), "Error: Cannot nest lack of belief with (not ...): %s" % pred.dump( ) assert isinstance( pred, Primitive ), "Error: Type should have been Primitive, but was %s" % str( type(pred)) pred.agent_list = "%s%s %s" % (modality, ag, pred.agent_list) return pred if "and" == node.name: return And(args) elif "or" == node.name: return Or(args) elif "oneof" == node.name: return Oneof(args) elif "not" == node.name: return Not(args) elif "xor" == node.name: return Xor(args) elif "nondet" == node.name: assert len(node.children) == 1,\ "nondet must only have a single child as a predicate" # make p != p2, otherwise might run into issues with mutation in some later step return Oneof([args[0], Not(args)]) elif "unknown" == node.name: assert len(node.children) == 1,\ "unknown must only have a single child as a predicate" # make p != p2, otherwise might run into issues with mutation in some later step p = Primitive( self.to_predicate(node.children[0], map=parameter_map)) p2 = Primitive( self.to_predicate(node.children[0], map=parameter_map)) return Xor([p, Not([p2])]) elif "when" == node.name: assert len(args) == 2,\ "When clause must have exactly 2 children" return When(args[0], args[1]) elif "P{" == node.name[:2]: return handle_modality(node, 2, 'P') elif "!P{" == node.name[:3]: return handle_modality(node, 3, '!P') elif "B{" == node.name[:2]: return handle_modality(node, 2, 'B') elif "!B{" == node.name[:3]: return handle_modality(node, 3, '!B') elif "!" == node.name[0]: node.name = node.name[1:] pred = Primitive(self.to_predicate(node, map=parameter_map)) pred.negated_rml = True return pred else: # it's a predicate return Primitive(self.to_predicate(node, map=parameter_map))
def _parse_problem(self, f_problem): """ Extract information from the problem file. The following will be extracted: * problem name * objects * initial state * goal state * type_to_obj * obj_to_type """ parse_tree = PDDL_Tree.create(f_problem) assert "problem" in parse_tree, "Problem must have a name" self.problem_name = parse_tree["problem"].named_children()[0] # objects must be parsed first if ":objects" in parse_tree: object_list = PDDL_Utils.read_type(parse_tree[":objects"]) self._add_objects(object_list) #TODO this may not be valid with a non-flat type hierchy obj_map = {obj: list(self.obj_to_type[obj])[0] for obj in self.objects} # the goal can be expressed in either a formula form, or a direct form if len(parse_tree[":goal"].children ) == 1 and parse_tree[":goal"].children[0].name == "and": self.goal = And([ self.to_formula(c, obj_map) for c in parse_tree[":goal"].children[0].children ]) else: self.goal = And([ self.to_formula(c, obj_map) for c in parse_tree[":goal"].children ]) # it is critical that the formula here be checked against the objects if len(parse_tree[":init"].children) == 1 and \ parse_tree[":init"].children[0].name == "and": self.init = self.to_formula(parse_tree[":init"].children[0], obj_map) else: # initial condition is one big AND self.init = And([ self.to_formula(c, obj_map) for c in parse_tree[":init"].children ]) # Parse the multiagent stuff self.task = parse_tree[":task"].children[0].name self.depth = int(parse_tree[":depth"].children[0].name) self.projection = [a.name for a in parse_tree[":projection"].children] self.init_type = parse_tree[":init-type"].children[0].name self.plan = [] if ':plan' in parse_tree: self.plan = map( lambda x: '_'.join( map(str, [x.name] + [y.name for y in x.children])), parse_tree[":plan"].children)