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

Source Code for Module teamwork.agent.Generic

  1  """Class for defining the default parameters of an individual agent""" 
  2  from xml.dom.minidom import * 
  3   
  4  from teamwork.math.Keys import StateKey 
  5  from teamwork.agent.stereotypes import * 
  6  from teamwork.agent.audit import * 
  7  from teamwork.agent.support import * 
  8  from teamwork.action.DecisionSpace import * 
  9  from teamwork.dynamics.pwlDynamics import PWLDynamics 
 10  from teamwork.math.matrices import DecisionTree 
 11   
12 -class GenericModel(Supporter,Stereotyper):
13 """ 14 A container of default values for an L{Agent} 15 16 0. Creating a new generic model: 17 C{model = L{GenericModel}(name)} 18 19 1. Society-specific methods 20 - C{model.L{getParents}()} 21 22 2. Picking a specific stereotypical mental model 23 - C{model.L{setModel}(name)} 24 25 3. Manipulating the space of stereotypical mental models: 26 - C{model[models]} --- a dictionary of the form C{modelName: modelObj, ...}, where modelObj is a L{GenericModel}. Currently we read/write only the goals and policy attributes of modelObj. 27 28 4. Manipulating the goals 29 - C{model.L{getGoals}()} 30 - C{model.L{setGoals}(goalList)} 31 - C{model.L{getGoalWeight}(goal)} 32 - C{model.L{setGoalWeight}(goal,num)} 33 34 5. Manipulating the recursive belief structure 35 - C{model.L{ancestry}()} 36 - C{model.L{getBelief}(entityName,feature)} 37 - C{model.L{setBelief}(entityName,feature,num)} 38 - C{model.L{getEntities}()} 39 - C{model.L{getEntity}(entityName)} 40 - C{model.L{setEntity}(entityName,entityObj)} 41 - C{model.L{getEntityBeliefs}()} 42 43 6. Manipulating the state 44 - C{model.L{getState}(feature)} 45 - C{model.L{setState}(feature,num)} 46 47 7. Manipulating the actions 48 - C{model.actions}: a L{DecisionSpace} object 49 50 8. Manipulating the dynamics 51 - C{model.dynamics}: a L{PWLDynamics} instance 52 @ivar depth: maximum depth of nesting of recursive beliefs 53 @type depth: int 54 """ 55
56 - def __init__(self,name=''):
57 """ 58 @param name: the unique ID for this model 59 @type name: string 60 """ 61 Stereotyper.__init__(self,name) 62 Supporter.__init__(self,name) 63 # Depth of nesting of recursive beliefs 64 self.depth = 2 65 self.parentModels = [] 66 self.setHierarchy({})
67
68 - def setHierarchy(self,classes):
69 """Sets the hierarchy of L{GenericModel} instances that this agent uses for its default values 70 @type classes: L{GenericSociety<teamwork.multiagent.GenericSociety.GenericSociety>} 71 """ 72 self.hierarchy = classes
73
74 - def merge(self,entity):
75 """Merge the contents of another L{GenericModel} into this one 76 """ 77 warnings = [] 78 # Parents 79 for parent in entity.getParents(): 80 if not self.isSubclass(parent): 81 self.parentModels.append(parent) 82 # State 83 for feature in entity.getStateFeatures(): 84 if feature in self.getStateFeatures(): 85 warnings.append('%s of %s' % (feature,self.name)) 86 else: 87 self.setState(feature,entity.getState(feature)) 88 # Actions 89 for action in entity.actions.extras: 90 if not action in self.actions.extras: 91 self.actions.directAdd(action) 92 # Coordinates 93 if len(self.getParents()) == 0: 94 try: 95 # This test takes care of Entity, but it might be unnecessary 96 self.attributes['coords'] = copy.copy(entity.attributes['coords']) 97 except KeyError: 98 pass 99 return warnings
100
101 - def renameEntity(self,old,new):
102 """ 103 @param old: the current name of the member 104 @param new: the new name of the member 105 @type old,new: str 106 """ 107 # Update name and state 108 if self.name == old: 109 self.setName(new) 110 # Update parents 111 try: 112 index = self.parentModels.index(old) 113 self.parentModels[index] = new 114 except ValueError: 115 # We don't have this agent as a parent 116 pass 117 # Update goals 118 for goal in self.getGoals(): 119 if old in goal.entity: 120 weight = self.getGoalWeight(goal) 121 del self.goals[goal] 122 eList = goal.entity[:] 123 while True: 124 try: 125 index = eList.index(old) 126 except ValueError: 127 break 128 eList[index] = new 129 goal = goal.__class__(eList,goal.direction,goal.type, 130 goal.key,goal.value) 131 self.goals[goal] = weight 132 # Update actions 133 for option in self.actions.getOptions(): 134 for action in option: 135 if action['object'] == old: 136 action['object'] = new 137 if self.name == new: 138 action['actor'] = new 139 # Update static relationships 140 for relation,fillers in self.relationships.items(): 141 for name in fillers[:]: 142 if name == old: 143 fillers.remove(old) 144 fillers.append(new) 145 # Update dynamic relationships 146 for key,value in self.links.items(): 147 remove = False 148 if key['subject'] == old: 149 remove = True 150 if key['object'] == old: 151 remove = True 152 obj = new 153 else: 154 obj = key['object'] 155 if remove: 156 del self.links[key] 157 self.setLink(key['verb'],obj,value) 158 # Update recursive beliefs 159 if self.hasBelief(old): 160 self.entities.renameMember(old,new) 161 # Update class branches in dynamics 162 for dynamics in sum(map(lambda d:d.values(), 163 self.dynamics.values()),[]): 164 dynamics.renameEntity(old,new)
165
166 - def getParents(self):
167 """Move up through the generic model hierarchy 168 @return: the immediate parent models of this generic model 169 @rtype: C{str[]}""" 170 return self.parentModels
171
172 - def isSubclass(self,cls):
173 """ 174 @return: C{True} iff this class is a subclass (inclusive) of the named class 175 @rtype: boolean 176 @param cls: The class name to test on 177 @type cls: str 178 """ 179 if self.name == cls: 180 return True 181 else: 182 for parent in self.getParents(): 183 if self.hierarchy[parent].isSubclass(cls): 184 return True 185 return False
186
187 - def getAllFillers(self,attribute):
188 """ 189 @return: all fillers of a slot (e.g, 'state', 'action', 'goal') on this model I{and} all superclasses 190 @rtype: str[] 191 """ 192 values = [] 193 # Add inherited state features 194 for name in self.ancestors(): 195 entity = self.hierarchy[name] 196 if attribute == 'state': 197 potential = entity.getStateFeatures() 198 elif attribute == 'action': 199 potential = entity.actions.getOptions() 200 else: 201 raise NotImplementedError,\ 202 'Unable to get %s slots from superclasses' % (attribute) 203 for value in potential: 204 if not value in values: 205 values.append(value) 206 return values
207
208 - def getInheritor(self,attribute,value,includeSelf=True):
209 """ 210 @param attribute: the agent model slot to look for (e.g., 'state', 'action', 'goal') 211 @type attribute,value: str 212 @param value: the slot filler to look for (e.g., state feature) 213 @return: the lowest class (either this one or some ancestory) that defines the given value in the given agent attributes 214 @rtype: str 215 @param includeSelf: if C{True}, then include self in search (default is C{True}) 216 @type includeSelf: bool 217 """ 218 if includeSelf: 219 classes = [self.name] 220 else: 221 classes = self.getParents()[:] 222 while len(classes) > 0: 223 for cls in classes[:]: 224 classes.remove(cls) 225 classes += self.hierarchy[cls].getParents() 226 if attribute == 'state': 227 if value in self.hierarchy[cls].getStateFeatures(): 228 return cls 229 else: 230 raise NotImplementedError,'Unable to get %s slots from superclasses' % (attribute) 231 # Oops, didn't find anything anywhere 232 if includeSelf: 233 raise KeyError,'No %s value %s for %s' % (attribute,value, 234 self.name) 235 else: 236 return None
237
238 - def getCumulativeState(self,feature):
239 cls = self.getInheritor('state',feature) 240 return self.hierarchy[cls].getState(feature)
241
242 - def deleteState(self,feature):
243 """Removes the given feature from the state 244 @type feature: str 245 """ 246 # Need to actually remove the feature here 247 key = StateKey({'entity':self.name,'feature':feature}) 248 self.state = self.state.marginalize(key) 249 # Remove from dynamics 250 if self.dynamics.has_key(feature): 251 del self.dynamics[feature]
252
253 - def ancestors(self,order=False):
254 """ 255 @param order: if C{True}, then order the results from general to specific (default is C{False}) 256 @type order: bool 257 @return: all ancestor classes of this class, including itself 258 @rtype: str[] 259 """ 260 result = {} 261 next = [self.name] 262 while len(next) > 0: 263 name = next.pop() 264 if not result.has_key(name): 265 result[name] = True 266 next += self.hierarchy[name].getParents() 267 if order: 268 remaining = result.keys() 269 result = [] 270 while len(remaining) > 1: 271 index = 0 272 while True: 273 entity = self.hierarchy[remaining[index]] 274 if len(filter(lambda p: not p in result, 275 entity.getParents())) == 0: 276 break 277 index += 1 278 else: 279 raise UserWarning,'Cycle in hierarchy' 280 result.append(entity.name) 281 del remaining[index] 282 result.append(remaining[0]) 283 return result 284 else: 285 return result.keys()
286
287 - def getRelationships(self):
288 """ 289 @return: all the relationships available to this generic model (including those to its superclasses 290 @rtype: str[] 291 """ 292 relationships = {} 293 for name in self.ancestors(): 294 for relationship in self.hierarchy[name].relationships.keys(): 295 relationships[relationship] = True 296 relationships = relationships.keys() 297 relationships.sort() 298 return relationships
299
300 - def __xml__(self,doc=None):
301 """Returns an XML Document representing this model""" 302 if doc is None: 303 doc = Stereotyper.__xml__(self) 304 root = doc.documentElement 305 root.setAttribute('depth',str(self.depth)) 306 node = doc.createElement('parents') 307 root.appendChild(node) 308 for name in self.parentModels: 309 child = doc.createElement('parent') 310 child.appendChild(doc.createTextNode(name)) 311 node.appendChild(child) 312 node = doc.createElement('state') 313 node.appendChild(self.state.__xml__().documentElement) 314 root.appendChild(node) 315 doc = Supporter.__xml__(self,doc) 316 return doc
317
318 - def parse(self,element):
319 """Extracts model elements from the provided XML element 320 @type element: Element""" 321 Supporter.parse(self,element) 322 try: 323 self.depth = int(element.getAttribute('depth')) 324 except ValueError: 325 # Probably means there's no depth attribute at all 326 pass 327 node = element.firstChild 328 while node: 329 if node.nodeType != node.ELEMENT_NODE: 330 pass 331 elif node.tagName == 'parents': 332 parent = node.firstChild 333 while parent: 334 if parent.nodeType == node.ELEMENT_NODE: 335 name = str(parent.firstChild.data).strip() 336 self.parentModels.append(name) 337 parent = parent.nextSibling 338 elif node.tagName == 'state': 339 parent = node.firstChild 340 while parent: 341 if parent.nodeType == node.ELEMENT_NODE: 342 self.state.parse(parent,KeyedVector) 343 parent = parent.nextSibling 344 node = node.nextSibling
345
346 - def importDict(self,generic):
347 """Updates generic model from dictionary-style spec""" 348 # Parent models 349 try: 350 self.parentModels = generic['parent'] 351 except KeyError: 352 pass 353 # State 354 if generic.has_key('state'): 355 for feature,value in generic['state'].items(): 356 self.setState(feature,value) 357 # Actions 358 if generic.has_key('actions'): 359 self.actions = extractSpace(generic['actions']) 360 # Goals 361 if generic.has_key('goals'): 362 self.setGoals(generic['goals']) 363 # Models 364 if generic.has_key('models'): 365 for name,model in generic['models'].items(): 366 agent = GenericModel(name) 367 agent.setGoals(model['goals']) 368 agent.policy = model['policy'] 369 self.models[name] = agent 370 if generic.has_key('model'): 371 self.model = generic['model'] 372 # Relationships 373 if generic.has_key('relationships'): 374 self.relationships = generic['relationships'] 375 for label,targets in self.relationships.items(): 376 if not isinstance(targets,list): 377 raise UserWarning,'For consistency, we require that the target class(es) for a relationship be provided in a list, rather than as a singleton (i.e., %s: [%s])' % (label,targets) 378 # Beliefs 379 if generic.has_key('beliefs'): 380 for other,belief in generic['beliefs'].items(): 381 if other: 382 if other == 'self': 383 entity = GenericModel(self.name) 384 else: 385 entity = GenericModel(other) 386 self.setEntity(entity) 387 for key,value in belief.items(): 388 if key == 'model': 389 entity.model = {'name':value, 390 'fixed':False} 391 else: 392 entity.setState(key,value) 393 else: 394 # What do we do with the "None" values? 395 raise DeprecationWarning,'Do not use "None" keys in generic model hierarchy' 396 # Dynamics 397 if generic.has_key('dynamics'): 398 if isinstance(generic['dynamics'],list): 399 dynamicsList = generic['dynamics'] 400 else: 401 dynamicsList = [generic['dynamics']] 402 for dynamics in dynamicsList: 403 for feature,dynDict in dynamics.items(): 404 self.dynamics[feature] = {} 405 for act,dyn in dynDict.items(): 406 if isinstance(dyn,DecisionTree): 407 dyn = {'class':PWLDynamics, 408 'args':{'tree':dyn}} 409 fun = dyn['class'] 410 args = dyn['args'] 411 self.dynamics[feature][act] = apply(fun,(args,)) 412 # Observations 413 if generic.has_key('observations'): 414 for omega,entries in generic['observations'].items(): 415 new = copy.deepcopy(entries) 416 if isinstance(omega,ObservationKey): 417 key = omega 418 else: 419 key = ObservationKey({'type': omega}) 420 try: 421 self.observations[key].update(new) 422 except KeyError: 423 self.observations[key] = new 424 # Depth of recursive beliefs 425 if generic.has_key('depth'): 426 self.depth = generic['depth'] 427 # Horizon of lookahead 428 if generic.has_key('horizon'): 429 self.horizon = generic['horizon']
430