def test_scan_tokens_problem(self): parser = PDDL_Parser() self.assertEqual(parser.scan_tokens('examples/dinner/pb1.pddl'), [ 'define', ['problem', 'pb1'], [':domain', 'dinner'], [':init', ['garbage'], ['clean'], ['quiet']], [':goal', ['and', ['dinner'], ['present'], ['not', ['garbage']]]] ])
def test_scan_tokens_domain(self): parser = PDDL_Parser() self.assertEqual(parser.scan_tokens('examples/dinner/dinner.pddl'), [ 'define', ['domain', 'dinner'], [':requirements', ':strips'], [ ':predicates', ['clean'], ['dinner'], ['quiet'], ['present'], ['garbage'] ], [ ':action', 'cook', ':precondition', ['clean'], ':effect', ['dinner'] ], [ ':action', 'wrap', ':precondition', ['quiet'], ':effect', ['present'] ], [ ':action', 'carry', ':precondition', ['garbage'], ':effect', ['and', ['not', ['garbage']], ['not', ['clean']]] ], [ ':action', 'dolly', ':precondition', ['garbage'], ':effect', ['and', ['not', ['garbage']], ['not', ['quiet']]] ] ])
def test_scan_tokens_problem(self): parser = PDDL_Parser() self.assertEqual(parser.scan_tokens('dinner/pb1.pddl'), ['define', ['problem', 'pb1'], [':domain', 'dinner'], [':init', ['garbage'], ['clean'], ['quiet']], [':goal', ['and', ['dinner'], ['present'], ['not', ['garbage']]]]] )
def test_scan_tokens_domain(self): parser = PDDL_Parser() self.assertEqual(parser.scan_tokens('dinner/dinner.pddl'), ['define', ['domain', 'dinner'], [':requirements', ':strips'], [':predicates', ['clean'], ['dinner'], ['quiet'], ['present'], ['garbage']], [':action', 'cook', ':parameters', [], ':precondition', ['and', ['clean']], ':effect', ['and', ['dinner']]], [':action', 'wrap', ':parameters', [], ':precondition', ['and', ['quiet']], ':effect', ['and', ['present']]], [':action', 'carry', ':parameters', [], ':precondition', ['and', ['garbage']], ':effect', ['and', ['not', ['garbage']], ['not', ['clean']]]], [':action', 'dolly', ':parameters', [], ':precondition', ['and', ['garbage']], ':effect', ['and', ['not', ['garbage']], ['not', ['quiet']]]]] )
class trajectory: def parseObjects(self, objTokens): self.types2objs = { } # Map of types -> objects; useful when you need to know what objects have a specified type self.objs2types = { } # Map of objects -> types; useful when you want to know what the type of a specific object is objs = [] isType = False for token in objTokens[ 1:]: # Throw out objTokens[0], which will be the string ':objects' if isType: if token not in self.types2objs: self.types2objs[token] = [] self.types2objs[token].extend(objs) for obj in objs: self.objs2types[obj] = token objs = [] isType = False elif token == '-': isType = True else: objs.append(token) # Parses the :init and :state blocks in the trajectory file, and also makes a dictionary of all the predicates that appear in the states, along with the types of their peremeters def parseStates(self, tokens): self.states = [] self.predicates = {} for block in tokens: if block[0] == ':state' or block[0] == ':init': self.states.append(block[1:]) for pred in block[1:]: pName = pred[0] pTypes = [] for arg in pred[1:]: pTypes.append( [self.objs2types[arg]] ) # Predicate type lists are now lists of lists of strings- each inner list representing the types observed for one parameter if pName in self.predicates: for oldParamTypes, newType in zip( self.predicates[pName], pTypes): if newType[0] not in oldParamTypes: oldParamTypes.append(newType[0]) # if self.predicates[pName] != pTypes: # raise TypeError('Predicate {} believed to have parameter types {}; inconsistent with observed parameters {}'.format(pName, self.predicates[pName], pTypes)) else: self.predicates[pName] = pTypes def parseActions(self, tokens): self.actions = {} for block in tokens: if block[0] == ':action': act_in = block[1] # print('Parsing action {}'.format(act_in)) parTypes = [] for param in act_in[1:]: parTypes.append( self.objs2types[param] ) # Not doing list-of-lists here- that'll be handled in actionCandidate constructor if act_in[0] in self.actions: # print ('Found action with same name: {}'.format(act_in[0])) for oldTypes, newType in zip( self.actions[act_in[0]].parameterTypes, parTypes): if newType not in oldTypes: oldTypes.append(newType) self.actions[act_in[0]].updateParameterTypes(parTypes) # if act.parameterTypes != parTypes: # raise TypeError('Action {} found using parameters {}; inconsistent with earlier {}. Are you using type inheritance?'.format(act_in[0], parTypes, act.parameterTypes)) else: newAct = actionCandidate(act_in[0], parTypes, self) self.actions[newAct.name] = newAct def refineActions(self, tokens): assignments = [((n - 1) // 2 - 1, block[1]) for (n, block) in enumerate(tokens) if block[0] == ':action'] # pprint.pprint(assignments) for i, agmt in assignments: assignedTypes = [self.objs2types[par] for par in agmt[1:]] self.actions[agmt[0]].updateParameterTypes(assignedTypes) for act in self.actions.values(): act.createPrecons(self) needsDoubleChecking = False for i, agmt in assignments: # print('State {}: {}'.format(i, self.states[i])) # print('Action {}: {}'.format(i, agmt)) # print('State {}: {}'.format(i+1, self.states[i+1])) # print() act = self.actions[agmt[0]] assignment = agmt[1:] # assignedTypes = [self.objs2types[par] for par in assignment] act.prunePrecons(self.states[i], assignment) needsDoubleChecking |= act.updateEffects(self.states[i], assignment, self.states[i + 1]) if needsDoubleChecking: # print('Double-checking action effects\n') needsDoubleChecking = False for i, agmt in assignments: act = self.actions[agmt[0]] assignment = agmt[1:] # assignedTypes = [self.objs2types[par] for par in assignment] needsDoubleChecking |= act.updateEffects( self.states[i], assignment, self.states[i + 1]) if needsDoubleChecking: raise ValueError( "Some actions still had unexpected effects during the second pass. This shouldn't be possible. If you see this message, please let me know. --SE" ) def genTypeclasses(self): #TODO Add code to deal with deeper hierarchies classList = [] for typesOuter in self.predicates.values(): for types in typesOuter: # print(types) sorTypes = list(sorted(types)) if sorTypes not in classList: classList.append(sorTypes) for act in self.actions: for types in self.actions[act].parameterTypes: sorTypes = list(sorted(types)) if sorTypes not in classList: classList.append(sorTypes) # print(classList) self.typeclasses = {} for tclass in classList: self.typeclasses['_'.join(tclass)] = 'object' for typ in self.types2objs.keys(): container = 'object' for tclass in classList: if typ in tclass and typ != '_'.join(tclass): container = '_'.join(tclass) self.typeclasses[typ] = container def __init__(self, filename, domainName='reconstructed'): self.domainName = domainName self.parser = PDDL_Parser() self.tokens = self.parser.scan_tokens(filename) pprint.pprint(self.tokens) print('=== Objects ===') self.parseObjects(self.tokens[1]) pprint.pprint(self.types2objs) print('=== States ===') self.parseStates(self.tokens) pprint.pprint(self.states) print('=== Predicates ===') pprint.pprint(self.predicates) print('=== Actions ===') self.parseActions(self.tokens) # print(self.tokens[3]) # p, n = self.actions[0].assignPrecons(self.tokens[3][1][1:]) # print('Grounded Positive preconditions') # print(p) # print('Grounded Negative preconditions') # print(n) # print('Before State') # print(self.states[0]) # self.actions[0].prunePrecons(self.states[0], self.tokens[3][1][1:]) # print(self.actions[0]) self.refineActions(self.tokens) pprint.pprint(self.actions) self.genTypeclasses() def __repr__(self): fmtTypeclasses = [ '{} - {}'.format(k, v) for k, v in self.typeclasses.items() ] fmtPredicates = [] for name, types in self.predicates.items(): fmtParams = [name] for i, typ in enumerate(types): fmtParams.append('?{} - {}'.format(i, '_'.join(typ))) fmtPredicates.append('({})'.format(' '.join(fmtParams))) fmtActions = [str(act) for act in self.actions.values()] return '''(define (domain {}) (:requirements :typing :negative-preconditions) (:types {}) (:predicates {}) {}) '''.format(self.domainName, ' '.join(fmtTypeclasses), ' '.join(fmtPredicates), ''.join(fmtActions))