def adds_dels(self): for f in self.fluent_lits: self.adds_fluent[f] = [] self.dels_fluent[f] = [] for a in self.effects: effect = self.effects[a] if effect is None: pass elif effect.name != 'and': raise MyError('effect isnt and') else: for arg in effect.args: if arg.name == 'Primitive': raise MyError('this should not be here') elif arg.name == 'Literal': self.adds_fluent[arg].append(And([a])) elif arg.name == 'not': if arg.args[0].name != 'Literal': raise MyError('nope') else: self.dels_fluent[arg.args[0]].append(And([a])) elif arg.name == 'when': result = arg.result if result.name != 'and': raise MyError('when result ?') for r in result.args: if r.name == 'Literal': self.adds_fluent[r].append(And([a, arg.condition])) elif r.name == 'not': self.dels_fluent[r.args[0]].append(And([a, arg.condition])) else: raise MyError('whenresult {}'.format(r.name)) else: raise MyError('whhaaaaa')
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 __init__(self, p, h): self.problem = p self.initial = p.init # self.actions = p.actions self.goal = p.goal # self.type_to_obj = p.type_to_obj # self.objects = p.obj_to_type self.fluents = p.fluents self.operators = p.operators self.precs = {} self.effects = {} self.observes = {} self.adds_fluent = {}#use self.dels_fluent = {}#use self.horizon = h self.j = 1 self.logic = Logic() self.jk = [] self.fluent_lits = [] self.op_lits = [] self.djk_lits = [] self.all_literals = [] self.initial_lits = None self.subproblems = [] self.init_known = None self.lit_dict = {} self.lit_lookup = {} self.dg_atom = Predicate('DG', None, []) self.fluents.add(self.dg_atom) self.end_atom = Operator('End', [], self.goal, None, And([Primitive(self.dg_atom)])) self.operators.add(self.end_atom)
def add_observes(self): self.check.write('OBSERVES \n') for djk in self.jk: self.printtofile(Not([Literal('D', djk, 0)])) for (j,k) in self.jk: for t in range(self.horizon-1): djkt = self.lit_lookup['D', (j,k), t+1] djkt0 = self.lit_lookup['D', (j,k), t] self.printtofile(When(djkt0, djkt)) for o in self.possible_ops: if o.observe is None: ajt = self.lit_lookup[o,j,t] akt = self.lit_lookup[o,k,t] (When(And([Not([djkt0]), ajt]), Not([djkt]))) (When(And([Not([djkt0]), akt]), Not([djkt]))) else: obs = o.observe ajt = self.lit_lookup[o, j, t] akt = self.lit_lookup[o, k, t] obsjt = self.lit_lookup[obs, j, t] obskt = self.lit_lookup[obs, k, t] iff = And([Not([djkt0]), ajt, obsjt, Not([obskt]) ]) thenf = djkt self.printtofile(When(iff,thenf)) iff = And([Not([djkt0]), ajt, obskt, Not([obsjt]) ]) self.printtofile(When(iff,thenf)) iff = And([Not([djkt0]), akt, obsjt, Not([obskt])]) thenf = djkt self.printtofile(When(iff, thenf)) iff = And([Not([djkt0]), akt, obskt, Not([obsjt])]) self.printtofile(When(iff, thenf)) iff = And([Not([djkt0]), ajt, obsjt, obskt]) thenf = Not([djkt]) self.printtofile(When(iff, thenf)) iff = And([Not([djkt0]), ajt, Not([obskt]), Not([obsjt])]) self.printtofile(When(iff, thenf)) iff = And([Not([djkt0]), akt, obsjt, obskt]) thenf = Not([djkt]) self.printtofile(When(iff, thenf)) iff = And([Not([djkt0]), akt, Not([obskt]), Not([obsjt])]) self.printtofile(When(iff, thenf))
def add_restrictions(self): self.check.write('RESTRICTIONS \n') pos = list(self.possible_ops) for i in range(len(pos)-1): for l in range(i+1, len(pos)): a1 = pos[i] a2 = pos[l] for t in range(self.horizon-1): for j in range(self.j): a1jt = self.lit_lookup[a1, j, t] a2jt = self.lit_lookup[a2, j, t] self.printtofile(When(a1jt, Not([a2jt]))) for (j,k) in self.jk: a1jt = self.lit_lookup[a1, j, t] a2kt = self.lit_lookup[a2, k, t] a1kt = self.lit_lookup[a1, k, t] a2jt = self.lit_lookup[a2, j, t] djkt = self.lit_lookup['D', (j,k), t] self.printtofile(When(And([a1jt, a2kt]), djkt)) self.printtofile(When(And([a1kt, a2jt]), djkt)) for o in pos: for t in range(self.horizon-1): for (j, k) in self.jk: ajt = self.lit_lookup[o,j,t] akt = self.lit_lookup[o,k,t] djkt = self.lit_lookup['D', (j,k), t] self.printtofile(When(And([ajt, Not([djkt])]),akt )) self.printtofile(When(And([akt, Not([djkt])]), ajt)) for j in range(self.j): for t in range(self.horizon-1): # alist = [self.lit_lookup[o,j,t] for o in pos] # dgjt = self.lit_lookup[self.dg_atom, j,t] # self.printtofile(Or([dgjt]+alist)) goallist = [self.lit_lookup[g.predicate,j,t] for g in self.goal.args ] enda = self.lit_lookup[self.end_atom, j, t] self.printtofile(When(And(goallist), enda)) dgjt = self.lit_lookup[self.dg_atom, j,t] alist = [self.lit_lookup[o, j, t] for o in pos] self.printtofile(When(dgjt, Not([Or(alist)])))
def add_persistence(self): self.check.write('PERSISTENCE \n') for j in range(self.j): for t in range(self.horizon-1): for p in self.fluents: pjt = self.lit_lookup[p,j,t+1] pjt0 = self.lit_lookup[p,j,t] adds = self.adds_fluent[pjt] if len(adds) > 0: iff = And([Not([pjt0])] + [Not([a]) for a in adds]) thenf = Not([pjt]) self.printtofile(When(iff, thenf)) else: self.printtofile(When(Not([pjt0]), Not([pjt]))) dels = self.dels_fluent[pjt] if len(dels) > 0: iff = And([pjt0] + [Not([a]) for a in dels]) thenf = pjt self.printtofile(When(iff, thenf)) else: self.printtofile(When(pjt0, pjt))
def create_literals(self): self.all_atoms = list(self.fluents) + list(self.possible_ops) + self.jk for t in range(self.horizon): for j in range(self.j): for f in self.fluents: lit = Literal('fluent', f, (j,t)) self.fluent_lits.append(lit) self.lit_lookup[f, j, t] = lit for t in range(self.horizon-1): for j in range(self.j): for o in self.possible_ops: lit = Literal('action', o, (j,t)) self.op_lits.append(lit) self.lit_lookup[o, j, t] = lit self.precs[lit] = self.lit_formula(o.precondition, j,t) self.effects[lit] = self.lit_formula(o.effect, j, t+1) self.observes[lit] = self.lit_formula(o.observe,j,t+1) if o.name == 'End': self.effects[lit] = And([ self.effects[lit], self.lit_formula(Primitive(self.dg_atom), j, self.horizon-1)]) for t in range(self.horizon): for djk in self.jk: lit = Literal('D', djk, t) self.djk_lits.append(Literal('D', djk, t)) self.lit_lookup['D',djk, t] = lit self.all_literals = self.fluent_lits + self.op_lits + self.djk_lits self.goal_lits = [self.lit_lookup[self.dg_atom, j, self.horizon-1] for j in range(self.j)] self.initial_lits = [self.lit_formula(self.init_known, j, 0) for j in range(self.j)] self.subinit_lits = [self.lit_formula(And(self.subproblems[j]),j, 0) for j in range(self.j)] self.initnot_lits = [self.lit_formula(And([Not([Primitive(i)]) for i in self.initnot]),j,0) for j in range(self.j)] d = 1 for l in self.all_literals: self.lit_dict[l] = d d += 1
def norm_init(self, formula): oneofs = [] ooset = set([]) new_args = formula.args[:] for f in formula.args: if f.name == 'oneof': oneofs.append(f) new_args.remove(f) oneargs = [[]] for o in oneofs: newnew = [] for oo in o.args: nots = o.args[:] nots.remove(oo) newnew.extend([[oo] + [Not([n]) for n in nots] + a for a in oneargs]) oneargs = newnew return oneargs, self.norm(And(new_args))
def _partial_ground_formula(self, formula, assignment, fluent_dict): """ Inputs: formula The formula to be converted assignment a dictionary mapping each possible variable name to an object Returns: A formula that has the particular valuation for the variables as given in input. The old formula is *untouched* """ if formula is None: return None if isinstance(formula, Primitive): return Primitive( self._predicate_to_fluent(formula.predicate, assignment, fluent_dict)) elif isinstance(formula, Forall): new_conjuncts = [] var_names, val_generator = self._create_valuations(formula.params) for valuation in val_generator: new_assignment = { var_name: val for var_name, val in zip(var_names, valuation) } for k in assignment: new_assignment[k] = assignment[k] new_conjuncts.append( self._partial_ground_formula(formula.args[0], new_assignment, fluent_dict)) return And(new_conjuncts) elif isinstance(formula, When): return When( self._partial_ground_formula(formula.condition, assignment, fluent_dict), self._partial_ground_formula(formula.result, assignment, fluent_dict)) else: return type(formula)([ self._partial_ground_formula(arg, assignment, fluent_dict) for arg in formula.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 norm(self, formula): name = formula.name if (name == 'Literal') | (name == 'Primitive'): return formula elif name == 'not': if len(formula.args) != 1: raise MyError('not with more args') if (formula.args[0].name == 'Literal') | (formula.args[0].name == 'Primitive'): return formula elif formula.args[0].name == 'and': new_formula = Or([Not([a]) for a in formula.args[0].args]) return self.norm(new_formula) elif formula.args[0].name == 'or': new_formula = And([Not([a]) for a in formula.args[0].args]) return self.norm(new_formula) elif formula.args[0].name == 'not': new_formula = formula.args[0].args[0] return self.norm(new_formula) else: raise MyError('Formula in NOT:{}'.format(formula.args[0].name)) elif name == 'and': for f in formula.args: if (f.name == 'Literal') or (f.name == 'Primitive'): pass elif f.name == 'and': rest = formula.args[:] rest.remove(f) rest.extend(f.args) new_formula = And(rest) return self.norm(new_formula) elif f.name == 'when': f1 = self.norm(f) rest = formula.args[:] rest.remove(f) rest.append(f1) new_formula = And(rest) return self.norm(new_formula) elif f.name == 'or' or f.name == 'not': f1 = self.norm(f) if f1 != f: rest = formula.args[:] rest.remove(f) rest.append(f1) new_formula = And(rest) return self.norm(new_formula) else: raise MyError('j') return formula elif name == 'or': if len(formula.args) == 1: return self.norm(formula.args[0]) for arg in formula.args: if arg.name == 'and': rest = formula.args[:] rest.remove(arg) new_list = [] for f in arg.args: new_new_list = rest[:] new_new_list.append(f) new_list.append(Or(new_new_list)) new_formula = And(new_list) return self.norm(new_formula) elif arg.name == 'or': rest = formula.args[:] rest.remove(arg) new_list = arg.args[:] new_list.extend(rest) new_formula = Or(new_list) return self.norm(new_formula) elif arg.name == 'not': arg2 = self.norm(arg) if arg2 != arg: rest = formula.args[:] rest.remove(arg) rest.append(arg2) new_formula = Or(rest) return self.norm(new_formula) elif arg.name == 'when': rest = formula.args[:] rest.remove(arg) arg2 = self.norm(arg) return self.norm(Or(rest + [arg2])) return formula elif name == 'when': # when(a,b) <=> or(not-a, b) a = formula.condition b = formula.result new_a = Not([a]) new_formula = Or([new_a, b]) return self.norm(new_formula) else: raise MyError('not enough')
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)