Package teamwork :: Package agent :: Module DefaultBased
[hide private]
[frames] | no frames]

Source Code for Module teamwork.agent.DefaultBased

  1  """Class for applying the defaults in a L{GenericModel<Generic.GenericModel>} instance to an instantiated L{Stereotyper<stereotypes.Stereotyper>} 
  2  @author: David V. Pynadath <pynadath@isi.edu> 
  3  """ 
  4  import copy 
  5  ##import inspect 
  6  import string 
  7  import time 
  8  from types import * 
  9   
 10  from teamwork.math.Interval import * 
 11  from teamwork.agent.stereotypes import * 
 12  from teamwork.policy.policyTable import PolicyTable 
 13  from teamwork.agent.Generic import * 
 14   
 15  classHierarchy = None 
 16   
17 -class GenericEntity(Stereotyper):
18 """Generic entity class with general-purpose methods for 19 instantiating an entity, using class-specific defaults""" 20 21 copyCount = 0.0 22 # Message factors 23 factors = [] 24
25 - def __init__(self,name):
26 Stereotyper.__init__(self,name) 27 self.classes = [] 28 self.relationships = {} 29 self.setHierarchy(None)
30
31 - def setHierarchy(self,classes):
32 """Sets the hierarchy of L{GenericModel} instances that this agent uses for its default values 33 @type classes: L{GenericSociety<teamwork.multiagent.GenericSociety.GenericSociety>} 34 """ 35 self.hierarchy = classes
36
37 - def applyDefaults(self,className=None,hierarchy=classHierarchy):
38 """Applies the generic model in the society of the given class name""" 39 self.type = className 40 self.setHierarchy(hierarchy) 41 # Initialize class branch 42 self.classes = [] 43 toExpand = [self.type] 44 while len(toExpand) > 0: 45 for className in toExpand[:]: 46 toExpand.remove(className) 47 self.classes.append(className) 48 try: 49 toExpand += self.hierarchy[className].getParents() 50 except KeyError: 51 pass 52 # Initialize model space 53 self.model = None 54 try: 55 self.models = copyModels(self.getDefault('models')) 56 except KeyError: 57 self.models = {} 58 # Initialize actions 59 self.initActions(self.getDefault('actions')) 60 # Initialize state 61 self.initState() 62 ## # Initialize goals 63 ## self.initGoals() 64 # Initialize observation function 65 self.omega.update(self.getDefault('omega')) 66 self.observations = copy.deepcopy(self.getDefault('observations')) 67 try: 68 # Initialize image 69 self.attributes['imageName'] = self.getDefault('imageName') 70 except KeyError: 71 # No image, no big deal 72 pass
73
74 - def getDefault(self,feature):
75 """Finds the most specific class defaults for the specified 76 feature; raises KeyError exception if no default exists""" 77 if self.hierarchy is None: 78 # Duh, no defaults 79 raise KeyError,'%s has no feature %s' % (self.name,feature) 80 result = None 81 last = None 82 for cls in self.classes: 83 # Check object attributes 84 try: 85 result = self.hierarchy[cls].__dict__[feature] 86 except KeyError: 87 # Check special attributes 88 try: 89 result = self.hierarchy[cls].attributes[feature] 90 except KeyError: 91 # Nothing here 92 continue 93 if feature in ['models','dynamics']: 94 # Empty values don't count 95 if len(result) > 0: 96 break 97 elif feature == 'imageName': 98 if result is not None: 99 break 100 elif feature == 'actions': 101 if result.branchType: 102 # Can't really merge AND/OR decision spaces 103 break 104 elif last is None: 105 last = result 106 else: 107 # Merge in any extras 108 last = copy.deepcopy(last) 109 for option in result.extras: 110 last.directAdd(option) 111 result = last 112 elif feature == 'depth': 113 # Belief depth is MINIMUM across all default values 114 if last is None: 115 last = result 116 else: 117 last = min(last,result) 118 result = last 119 else: 120 # For everything else, the first thing 121 break 122 if result is None: 123 if feature == 'actions': 124 pass 125 else: 126 raise KeyError,'%s has no feature %s' % (self.name,feature) 127 return result
128
129 - def initState(self):
130 """Instantiates all of the state defaults relevant to this entity""" 131 for cls in self.classes: 132 try: 133 featureList = self.hierarchy[cls].getStateFeatures() 134 except KeyError: 135 featureList = [] 136 for feature in featureList: 137 if not feature in self.getStateFeatures(): 138 value = self.hierarchy[cls].getState(feature) 139 self.setState(feature,value) 140 self.setModel(None)
141
142 - def initActions(self,decisions):
143 """Initializes the actions to follow the form of the given L{DecisionSpace<teamwork.action.DecisionSpace.DecisionSpace>}""" 144 self.actions = decisions.__class__() 145 self.actions.illegal.update(decisions.illegal) 146 self._initActions(self.actions,decisions) 147 # Add actions that have no objects 148 for option in decisions.extras: 149 if not self.actions.illegal.has_key(str(option)): 150 for action in option: 151 if action['object'] is not None: 152 break 153 else: 154 self.actions.directAdd(copy.deepcopy(option))
155
156 - def _initActions(self,mySpace,decisions):
157 while isinstance(decisions,DecisionSpace): 158 mySpace.key = decisions.key 159 for value in decisions.values: 160 if value['type'] == 'literal': 161 mySpace.append(value['value']) 162 elif value['type'] == 'decision': 163 newDecisions = value['value'].__class__() 164 self._initActions(newDecisions,value['value']) 165 mySpace.append(newDecisions) 166 if isinstance(decisions.base,DecisionSpace): 167 mySpace.base = decisions.base.__class__() 168 mySpace = mySpace.base 169 else: 170 mySpace.base = copy.deepcopy(decisions.base) 171 decisions = decisions.base
172
173 - def initRelationships(self,entityList):
174 """Instantiates the relationships of this entity regarding the 175 provided list of entities""" 176 # Fill out any relationships that this entity may have: 177 try: 178 relations = self.getDefault('relationships') 179 except KeyError: 180 relations = {} 181 for relation,targetList in relations.items(): 182 if not self.relationships.has_key(relation): 183 # Use defaults if relationships have not already been 184 # set (i.e., haven't used wizard) 185 self.relationships[relation] = [] 186 for entity in entityList: 187 # match the desired class against each and every class 188 # that this entity is a member of (string compare) 189 for target in targetList: 190 if entity.name != self.name and \ 191 target in entity.classes: 192 self.relationships[relation].append(entity.name) 193 if relation == '_commandee': 194 for name in self.relationships[relation]: 195 for entity in entityList: 196 if entity.name == name: 197 break 198 else: 199 raise NameError,'Missing commandee: %s' % (name) 200 if len(self.relationships[relation]) == 0: 201 del self.relationships[relation]
202
203 - def initModels(self,entityList):
204 """Instantiate all of the relevant models""" 205 # Prune any agents who don't have actions 206 agents = [] 207 for agent in entityList: 208 if len(agent.actions.getOptions()) > 0: 209 agents.append(agent) 210 self.horizon = self.getDefault('horizon')*len(agents) 211 for name,model in self.models.items(): 212 # If we've already instantiated the goals and policy, 213 # then the only thing left to do is set the lookahead 214 # depth 215 model.policy.depth = self.horizon 216 model.policy.entity = self
217
218 - def initEntities(self,entityList,maxDepth=-1):
219 """Sets the entities known to be the list provided, and makes 220 the appropriate updates to goals, policy depth, etc. 221 @param maxDepth: the maximum depth of this agent's recursive models 222 @type maxDepth: int 223 """ 224 # Fill out recursive beliefs 225 if maxDepth < 0: 226 maxDepth = self.getDefault('depth') 227 else: 228 maxDepth = min(self.getDefault('depth'),maxDepth) 229 if maxDepth > 0: 230 newList = [] 231 # First, generate entity objects for my beliefs 232 for entity in entityList: 233 newEntity = copy.copy(entity) 234 newEntity.dynamics = copy.deepcopy(entity.dynamics) 235 # Stick this entity object into my beliefs 236 self.setEntity(newEntity) 237 newList.append(newEntity) 238 # Assume correct beliefs about states 239 for feature in entity.getStateFeatures(): 240 try: 241 value = entity.getState(feature) 242 newEntity.setState(feature,value) 243 except KeyError: 244 pass 245 # Finally, fill in specific beliefs according to my class 246 # defaults, and go to the next recursive level 247 for entity in newList: 248 self.initBeliefs(entity) 249 entity.initEntities(newList,maxDepth-1) 250 # Add any goals related to the new entities 251 self.initGoals(entityList) 252 # Set the depth of lookahead 253 agents = [] 254 for agent in entityList: 255 if len(agent.actions.getOptions()) > 0: 256 agents.append(agent) 257 self.horizon = self.getDefault('horizon')*len(agents) 258 if not self.policy: 259 self.policy = PolicyTable(self,self.actions,self.horizon) 260 self.entities.initializeOrder() 261 self.entities.state.freeze()
262
263 - def initBeliefs(self,entity):
264 """Sets the beliefs that this entity has about the given entity, 265 following the various defaults""" 266 # Find the relationships I have with this entity 267 relations = [] 268 for relation in self.relationships.keys(): 269 if entity.name in self.relationships[relation]: 270 relations.append(relation) 271 # Consider each class that this entity belongs to 272 myClassList = self.classes[:] 273 myClassList.reverse() 274 yourClassList = entity.classes[:] 275 yourClassList.reverse() 276 for default in myClassList: 277 beliefs = {} 278 # For others, use class-based defaults 279 for cls in yourClassList: 280 # Consider all of the default beliefs I have 281 try: 282 beliefs = self.hierarchy[default].getEntity(cls) 283 except KeyError: 284 # If no generic beliefs either, then go on to 285 # next class 286 continue 287 # Copy default belief values from this class 288 entity.applyBeliefs(beliefs) 289 # Relations take precedence over class defaults 290 for relation in relations: 291 try: 292 beliefs = self.hierarchy[default].getEntity(relation) 293 except KeyError: 294 continue 295 # Copy default belief values from this class 296 entity.applyBeliefs(beliefs) 297 if entity.name == self.name: 298 try: 299 beliefs = self.hierarchy[default].getEntity('self') 300 # Copy default belief values from this class 301 entity.applyBeliefs(beliefs) 302 except KeyError: 303 pass 304 return entity
305
306 - def applyBeliefs(self,beliefs):
307 for feature in beliefs.getStateFeatures(): 308 self.setState(feature,beliefs.getState(feature)) 309 if beliefs.model: 310 self.setModel(beliefs.model['name'])
311
312 - def initDynamics(self,entities={}):
313 """Sets world dynamics of this entity in response to all of the possible actions in the given multiagent system 314 @param entities: the agents whose actions are relevant 315 @type entities: strS{->}Agent 316 """ 317 for cls in self.classes: 318 for feature,actDict in self.hierarchy[cls].dynamics.items(): 319 if not self.dynamics.has_key(feature): 320 self.dynamics[feature] = {} 321 types = filter(lambda a:not self.dynamics[feature].has_key(a), 322 actDict.keys()) 323 for actType in types: 324 dynamics = actDict[actType] 325 if actType is None: 326 ## newDynamics = copy.deepcopy(dynamics) 327 ## self.dynamics[feature][actType] = newDynamics 328 self.dynamics[feature][actType] = cls 329 else: 330 found = False 331 for agent in entities.values(): 332 for option in agent.actions.getOptions(): 333 for action in option: 334 if action['type'] == actType: 335 ## newDynamics = copy.deepcopy(dynamics) 336 ## self.dynamics[feature][actType] = newDynamics 337 self.dynamics[feature][actType] = cls 338 found = True 339 break 340 if found: 341 break 342 if found: 343 break
344
345 - def initGoals(self,entities=[]):
346 """Sets the goal weights of this entity based on class 347 defaults. The resulting goals depend on the group of entities 348 passed in as the optional argument.""" 349 goals = [] 350 # First, figure out the relevant goals and their total weight 351 # (for normalization) 352 keys = [] 353 for cls in self.classes: 354 for goal in self.hierarchy[cls].getGoals(): 355 goalList = self.instantiateGoal(goal,entities) 356 for subGoal in goalList: 357 key = str(subGoal) 358 try: 359 index = keys.index(key) 360 goals[index].weight += subGoal.weight 361 except ValueError: 362 keys.append(key) 363 goals.append(subGoal) 364 if len(goals) > 0: 365 # Then, add goal with normalized weight 366 self.setGoals(goals)
367
368 - def initObservations(self,entities=[]):
369 """Instantiates generic observation function with given entity list""" 370 for entry in self.observations: 371 # Keep running list of instances generated so far 372 print entry 373 print len(entities)
374
375 - def instantiateGoal(self,goal,entities=[]):
376 """Specializes the given goal to the given scenario context 377 378 Returns a list of goals created by instantiating the given 379 goal template (i.e., it refers to classes or relationships) 380 with respect to the provided list of entities and current 381 relationships""" 382 entityList = self.instantiateList(goal.entity,[[]],entities) 383 goals = [] 384 for refList in entityList: 385 newGoal = goal.__class__(refList,goal.direction, 386 goal.type,goal.key) 387 newGoal.weight = goal.weight 388 goals.append(newGoal) 389 return goals
390
391 - def instantiateList(self,nameList,refList,entities=[]):
392 """ 393 @param nameList: list of names to be instantiated 394 @type nameList: C{str[]} 395 @param refList: partial results of name lists instantiation so far 396 @type refList: C{str[][]} 397 @param entities: the entities from which to draw instances from 398 @type entities: C{L{Agent}[]} 399 @return: a list of entity lists appropriate for recursive beliefs with all name references replaced by the appropriate entities""" 400 try: 401 name = nameList[0] 402 except IndexError: 403 return refList 404 newNames = self.instantiateName(name,entities) 405 newList = [] 406 for ref in refList: 407 for name in newNames: 408 newList.append(ref[:]+[name]) 409 return self.instantiateList(nameList[1:],newList,entities)
410
411 - def instantiateName(self,name,entities=[]):
412 """Returns a list of instance names that match the given abstract entity reference (either 'self', relationship, or class name). 413 @param name: the reference(s) to be instantiated 414 @type name: C{str} or C{str[]} 415 @param entities: the entities to search for the given reference. If no entities are provided, defaults to the list of entities that this entity has beliefs about 416 @type entities: L{Agent}[] 417 @rtype: C{str[]} 418 """ 419 if len(entities) == 0: 420 entities = self.entities.values() 421 if isinstance(name,list): 422 return map(lambda n,s=self,e=entities:s.instantiateName(n,e)) 423 if name == 'self': 424 return [self.name] 425 elif self.relationships.has_key(name): 426 matches = [] 427 for entity in entities: 428 if entity.name in self.relationships[name]: 429 matches.append(entity.name) 430 return matches 431 else: 432 matches = [] 433 for entity in entities: 434 if entity.instanceof(name): 435 matches.append(entity.name) 436 return matches
437
438 - def addActions(self,entities):
439 """Adds any actions that I can perform with respect to the given entities 440 @type entities: L{Agent}[] 441 """ 442 default = self.getDefault('actions') 443 self._addActions(entities,default,self.actions) 444 for option in default.extras: 445 if self.actions.illegal.has_key(str(option)): 446 continue 447 newOptions = [[]] 448 for action in option: 449 if not action['object'] is None: 450 names = self.instantiateName(action['object'],entities) 451 if self.name in names: 452 try: 453 selfEligible = action['self'] 454 except KeyError: 455 # By default, assume self is ineligible 456 selfEligible = False 457 if not selfEligible: 458 names.remove(self.name) 459 for new in newOptions[:]: 460 newOptions.remove(new) 461 for name in names: 462 newAction = copy.deepcopy(action) 463 newAction['object'] = name 464 newOption = copy.deepcopy(new) 465 newOption.append(newAction) 466 newOptions.append(newOption) 467 else: 468 # No object, always applicable 469 for new in newOptions: 470 new.append(copy.deepcopy(action)) 471 if len(newOptions) == 0: 472 break 473 else: 474 for newOption in newOptions: 475 self.actions.directAdd(newOption)
476
477 - def _addActions(self,entities,baseActions,realActions):
478 while isinstance(baseActions,DecisionSpace): 479 for value in baseActions.values: 480 if value['type'] == 'generic': 481 for entity in entities: 482 if value['value'] in entity.classes: 483 if entity.name != realActions: 484 realActions.append(entity.name) 485 elif value['type'] == 'relationship': 486 for entity in entities: 487 if value['value'] in self.relationships.keys() and \ 488 entity.name in \ 489 self.relationships[value['value']]: 490 if entity.name != realActions: 491 realActions.append(entity.name) 492 elif value['type'] == 'decision': 493 space = value['value'].__class__() 494 self._initActions(space,value['value']) 495 self._addActions(entities,value['value'],space) 496 realActions.append(space) 497 baseActions = baseActions.base 498 realActions = realActions.base
499
500 - def instanceof(self,className):
501 """ 502 @return: True iff this entity is a member of the specified class 503 @param className: name of class to test against 504 @type className: C{str} 505 @rtype: C{boolean} 506 """ 507 return className in self.classes
508
509 - def __copy__(self):
510 new = Stereotyper.__copy__(self) 511 new.setHierarchy(self.hierarchy) 512 new.initial = self.initial 513 if self.policy: 514 new.policy = copy.copy(self.policy) 515 new.policy.entity = new 516 new.actions = self.actions 517 new.messages = self.messages 518 new.relationships = self.relationships 519 new.classes = self.classes 520 return new
521
522 - def __xml__(self):
523 doc = Stereotyper.__xml__(self) 524 for cls in self.classes: 525 node = doc.createElement('class') 526 node.setAttribute('name',cls) 527 doc.documentElement.appendChild(node) 528 return doc
529
530 - def parse(self,element):
531 """Extracts this agent's recursive belief structure from the given XML Element 532 @type element: Element 533 """ 534 Stereotyper.parse(self,element) 535 child = element.firstChild 536 while child: 537 if child.nodeType == child.ELEMENT_NODE and \ 538 child.tagName == 'class': 539 self.classes.append(str(child.getAttribute('name'))) 540 child = child.nextSibling
541
542 -def packageHierarchy(linkList,result):
543 """Packages up the tree branch containing L{GenericEntity} into a neat 544 little dictionary, indexed by class name, with the values being 545 lists of classes that represent the branch up to the root (we 546 don't include L{GenericEntity}, which is the root)""" 547 for entry in linkList: 548 if type(entry) is TupleType: 549 child = entry[0].__name__ 550 parent = entry[1][0].__name__ 551 if not result.has_key(child): 552 result[child] = [] 553 if parent != 'GenericEntity': 554 if not result.has_key(parent): 555 result[parent] = [] 556 result[child].append(parent) 557 result[child] = result[child] + result[parent] 558 else: 559 packageHierarchy(entry,result) 560 return result
561
562 -def copyModels(models):
563 newModels = {} 564 for key in models.keys(): 565 newModels[key] = copyModel(models[key]) 566 return newModels
567
568 -def copyModel(model):
569 newModel = GenericModel(model.name) 570 newModel.setGoals(model.getGoals()) 571 newModel.policy = copy.deepcopy(model.policy) 572 ## for key in model.keys(): 573 ## newModel[key] = copy.copy(model[key]) 574 return newModel
575 576 if __name__ == '__main__': 577 ## print extractHierarchy() 578 Beliefs.__TK__ = None 579 gov = createEntity('Government','CortinaGov') 580 clf = createEntity('TerroristCadres','CLFCadres') 581 582 print clf.instanceof('Psyops') 583 entities = [gov,clf] 584 585 ## gov.initEntities(entities) 586 ## clf.initEntities(entities) 587 588 entities = PsychAgents(entities) 589 590 ## print entities 591