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

Source Code for Module teamwork.agent.Entities

  1  import copy 
  2  import string 
  3  import sys 
  4  import time 
  5  from types import * 
  6   
  7  from support import * 
  8  from stereotypes import * 
  9  from consistency import * 
 10  from GoalBased import * 
 11  from DefaultBased import * 
 12  from MemoryAgent import * 
 13   
 14  from teamwork.math.probability import * 
 15  from teamwork.utils.PsychUtils import dict2str 
 16  from teamwork.action.PsychActions import * 
 17  from teamwork.messages.PsychMessage import * 
 18  from teamwork.widgets.images import getAgentImage 
 19  from teamwork.utils.Debugger import * 
 20   
21 -class PsychEntity(GenericEntity,Supporter,ConsistentAgent):
22 """ 23 Entity class 24 25 0. Creating a new agent mode: 26 - C{agent = L{PsychEntity}(name)} 27 28 1. Picking a specific stereotypical mental model: 29 - C{agent.L{setModel}(name)} 30 31 2. Manipulating the goals: 32 - C{agent.L{getGoals}()} 33 - C{agent.L{setGoals}(goalList)} 34 - C{agent.L{getGoalWeight}(goal)} 35 - C{agent.L{setGoalWeight}(goal,num)} 36 37 3. Manipulating the recursive belief structure: 38 - C{agent.L{ancestry}()} 39 - C{agent.L{getBelief}(entityName,feature)} 40 - C{agent.L{setBelief}(entityName,feature,num)} 41 - C{agent.L{getEntities}()} 42 - C{agent.L{getEntity}(entityName)} 43 - C{agent.L{setEntity}(entityName,entityObj)} 44 - C{agent.L{getEntityBeliefs}()} 45 46 4. Manipulating the state: 47 - C{agent.L{getState}(feature)} 48 - C{agent.L{setState}(feature,num)} 49 50 5. Manipulating the actions (see L{teamwork.action.PsychActions.Action}): 51 - C{agent.actions}: a list of action objects 52 53 6. Manipulating the dynamics (see L{teamwork.dynamics.pwlDynamics.PWLDynamics}): 54 - C{agent.dynamics} --- coming soon 55 """ 56 57 beliefWeights = {'trust':0.15, 58 'liking':0.075, 59 'self-interest':0.1, 60 'sender-interest':-0.0, 61 'consistency':1.0, 62 'threshold':-0.0001 63 } 64 consistencyWeights = {'self-interest':0.1, 65 'sender-interest':-0.1, 66 'consistency':0.9, 67 'threshold':0.0 68 } 69
70 - def __init__(self,name):
71 """Constructor 72 73 Takes a string name, a list of action type strings, and a list 74 of message factors. The final parameters is a flag indicating 75 whether Tk variables should be used (default is yes).""" 76 GenericEntity.__init__(self,name) 77 Supporter.__init__(self,name) 78 ConsistentAgent.__init__(self,name) 79 # Known susceptibilities (themes or messages) of this entity 80 self.susceptibilities = [] 81 # Initialize themes 82 try: 83 self.themes = self.getDefault('themes') 84 except KeyError: 85 self.themes = {} 86 self.description = ''
87
88 - def initEntities(self,entityList,maxDepth=-1):
89 """Sets the entities known to be the list provided, and makes 90 the appropriate updates to goals, policy depth, etc. 91 @param maxDepth: the maximum depth of this agent's recursive models 92 @type maxDepth: int 93 """ 94 GenericEntity.initEntities(self,entityList,maxDepth) 95 Supporter.initEntities(self,entityList)
96 97 # Belief dynamics
98 - def stateEstimator(self,beliefs,actions,epoch=-1,debug=Debugger()):
99 """Calls the superclass state estimator, but also handles messages""" 100 if beliefs is None: 101 beliefs = self.getAllBeliefs() 102 # First, immediate message effects 103 msgs = {} 104 for actor,actionList in actions.items(): 105 msgList = [] 106 for action in actionList: 107 if action['type'] == '_message': 108 msgList.append(action) 109 if len(msgList) > 0: 110 msgs[actor] = msgList 111 beliefs,delta = self.postComStateEstimator(beliefs,msgs,epoch,debug) 112 # The following test is temporary 113 if len(msgs) == 0: 114 # Then, dynamics 115 beliefs,new = GenericEntity.stateEstimator(self,beliefs, 116 actions,epoch,debug) 117 delta.update(new) 118 return beliefs,delta
119
120 - def preComStateEstimator(self,beliefs,actions,epoch=-1,debug=Debugger()):
121 """ 122 Computes the hypothetical changes to the given beliefs in response to the given actions 123 @param beliefs: the beliefs to be updated (traditionally, the result from L{getAllBeliefs}) 124 @type beliefs: dict 125 @param actions: the actions observed by this agent 126 @type actions: C{dict:strS{->}L{Action}} 127 @param epoch: the current epoch in which these observations occurred (currently ignored, but potentially important) 128 @type epoch: C{int} 129 @type debug: L{Debugger} 130 @return: the belief changes that would result from the specified observed actions, in dictionary form: 131 - beliefs: results as returned by L{hypotheticalAct<SequentialAgents.hypotheticalAct>} 132 - observations: the given actions 133 @rtype: C{dict} 134 """ 135 return Supporter.preComStateEstimator(self,beliefs,actions, 136 epoch,debug)
137
138 - def postComStateEstimator(self,beliefs,msgs,epoch=-1,debug=Debugger()):
139 """Updates the agent's beliefs based on 140 received messages""" 141 delta = self.hypotheticalPostCom(beliefs,msgs,epoch,debug) 142 for sender,messages in msgs.items(): 143 effect = delta[sender]['effect'] 144 if effect is not None: 145 if not self.parent: 146 # Kind of annoying necessity; perhaps it will be 147 # smoother in the future 148 try: 149 self.updateLinks(effect['relationships']) 150 except KeyError: 151 pass 152 self.entities.applyChanges(effect) 153 return beliefs,delta
154
155 - def hypotheticalPostCom(self,beliefs,msgs,epoch=-1,debug=Debugger()):
156 """ 157 @return: the potential change in the agent's beliefs based on received messages""" 158 explanation = {} 159 for sender in msgs.keys(): 160 explanation[sender] = {'effect':None} 161 for msg in msgs[sender]: 162 # Iterate through all messages sent by this sender 163 acceptance = None 164 label = msg.pretty() 165 # Create a sub-explanation for this individual message 166 subExp = {} 167 # Do we want to return the explanation in the delta? 168 explanation[label] = subExp 169 # Determine whether receiver believes message 170 try: 171 entity = self.getEntity(sender) 172 except KeyError: 173 # What to do here? 174 continue 175 acceptance,accExp = self.acceptMessage(entity,msg,debug) 176 subExp['decision'] = acceptance 177 subExp['breakdown'] = accExp 178 if acceptance: 179 # Update beliefs if accepting message 180 debug.message(4,'%s accepts %s' % (self.ancestry(), 181 label)) 182 delta,subExp = self.incorporateMessage(msg) 183 if explanation[sender]['effect'] is None: 184 explanation[sender]['effect'] = delta 185 else: 186 raise NotImplementedError,'Currently unable to incorporate multiple messages from the same sender' 187 self.updateTrust(sender,explanation[sender]['effect'], 188 True) 189 # Update any beliefs about myself 190 try: 191 entity = self.getEntity(self.name) 192 except KeyError: 193 entity = None 194 if entity: 195 previous = copy.deepcopy(msg['force']) 196 msg.forceAccept(self.name) 197 subExp = entity.hypotheticalPostCom(beliefs[sender], 198 {sender:[msg]}, 199 epoch,debug) 200 explanation[sender]['effect'][sender] = {self.name:subExp[sender]['effect']} 201 msg['force'] = previous 202 elif entity: 203 debug.message(4,'%s rejects %s' % \ 204 (self.ancestry(),label)) 205 explanation[sender]['effect'] = {} 206 self.updateTrust(sender,explanation[sender]['effect'], 207 False) 208 # Update sender's beliefs about entities' beliefs 209 try: 210 entity = entity.getEntity(self.name) 211 except KeyError: 212 entity = None 213 if entity: 214 # This entity has a belief about me, so I need to 215 # update it 216 entity.postComStateEstimator(entity,{sender:[msg]}, 217 epoch,debug) 218 return explanation
219
220 - def acceptMessage(self,sender,msg,debug=Debugger()):
221 """Boolean test that returns true iff this entity will accept 222 (i.e., believe) the message sent by the specified sender entity""" 223 if msg.mustAccept(self.name): 224 return True,{'forced':1,'accept':'forced','reject':None} 225 elif msg.mustReject(self.name): 226 return False,{'forced':1,'accept':'forced','reject':None} 227 debug.message(1,'Deciding: does '+self.ancestry()+' accept '+`msg`) 228 # Try message in conjunction with current model 229 value = {'forced':None, 230 'accept':{}, 231 'reject':{}, 232 } 233 valueAccept = 0. 234 valueReject = 0. 235 ## projection = copy.deepcopy(self) 236 #### delta,exp = projection.incorporateMessage(msg) 237 ## msg = copy.copy(msg) 238 ## msg.forceAccept() 239 ## delta,exp = projection.postComStateEstimator(projection, 240 ## {sender.name:[msg]}, 241 ## None,debug-1) 242 #### delta,exp = projection.initial.incorporateMessage(msg) 243 ## if not delta: 244 ## # There is no way for me to modify my beliefs to accept this 245 ## # message 246 ## debug.message(5,'Cannot accept message: '+`exp`) 247 ## return None,exp 248 ## # Add a filter to determine which entities to check 249 ## filter = None 250 ## valueAccept,value['accept'] = projection.acceptability(sender,0.0,filter,debug) 251 # Compute relevant trust totals 252 ## entityList = self.trustees(debug) 253 entityList = [sender] 254 key = 'trust' 255 try: 256 belief = self.getTrust(sender.name) 257 except KeyError: 258 belief = 0. 259 debug.message(1,'Trust in %s = %s' % (sender.name,`belief`)) 260 value['accept'][key] = belief 261 valueAccept += float(value['accept'][key])*self.beliefWeights[key] 262 # Compute relevant support totals 263 key = 'liking' 264 try: 265 belief = self.getSupport(sender.name) 266 except KeyError: 267 belief = 0. 268 debug.message(1,'Liking of %s = %s '% (sender.name,`belief`)) 269 value['accept'][key] = belief 270 valueAccept += float(value['accept'][key])*self.beliefWeights[key] 271 ## valueReject,value['reject'] = self.acceptability(sender,0.0,filter,debug) 272 value['differential'] = valueAccept - valueReject 273 274 #evaluate consistency 275 if consistencyCalculationAvailable: 276 key = 'consistency' 277 consistencyCalc = self.calculateMessageConsistency(msg) 278 value['accept'][key] = consistencyCalc['proposedConsistency'] - consistencyCalc['currentConsistency'] 279 debug.message(1,'Consistency of msg = %f'% value['accept'][key]) 280 valueAccept += float(value['accept'][key])*self.beliefWeights[key] 281 282 283 ## # Evaluate susceptibility 284 ## if msg.theme: 285 ## try: 286 ## item = self.susceptibilities 287 ## except AttributeError: 288 ## self.susceptibilities = [] 289 ## for item in self.susceptibilities: 290 ## if item[0] == msg.theme: 291 ## debug.message(1,'Susceptibility: '+item[2]) 292 ## value['susceptibility'] = float(item[2]) 293 ## value['differential'] += value['susceptibility'] 294 ## break 295 debug.message(1,'Overall evaluation of message = '+\ 296 `valueAccept`) 297 # Try message with sender's models 298 299 # Try message with other models 300 301 return (float(valueAccept) > \ 302 self.beliefWeights['threshold']),value
303
304 - def acceptability(self,sender=None,distance=0.0,filter=None, 305 debug=Debugger()):
306 """Quantitative assessment of the acceptability of my current beliefs""" 307 value = {} 308 # Compute the value to myself 309 debug.message(1,'Computing my expected reward...') 310 projection = copy.deepcopy(self) 311 entityList = [self] 312 if sender: 313 entityList.append(sender) 314 horizon = projection.policy.depth 315 eValues,exp = projection.expectedValue(horizon=horizon, 316 goals=entityList, 317 debug=debug-1) 318 key = 'self-interest' 319 value[key] = eValues[self.name] 320 debug.message(4,'Value of beliefs to myself = '+`value[key]`) 321 if sender: 322 # Compute the value to sender 323 debug.message(1,'Computing sender''s expected reward...') 324 key = 'sender-interest' 325 value[key] = eValues[sender.name] 326 debug.message(4,'Value of beliefs to sender = '+`value[key]`) 327 # Compute consistency of message with my observations 328 observations = self.getObservations()[:] 329 observations.reverse() 330 ## projection = copy.deepcopy(self.initial) 331 ## projection.freezeModels() 332 ## debug.message(1,'Computing consistency...') 333 ## key = 'consistency' 334 ## value[key] = projection._consistency(observations,filter,debug-1) 335 ## debug.message(4,'Belief consistency = '+`value[key]`) 336 # Compute weighted sum of values 337 total = Distribution({0.:1.}) 338 for key in value.keys(): 339 try: 340 weight = self.beliefWeights[key] 341 try: 342 total = total + value[key].total()*weight 343 except AttributeError: 344 total = total + value[key]*weight 345 except KeyError: 346 # We don't have a weight for this subtotal 347 pass 348 debug.message(4,'Overall evaluation of beliefs = '+`total`) 349 return total,value
350
351 - def extendPolicy(self,subpolicy):
352 """Extends the lookup policy I{within} the overall composite policy""" 353 for policy in self.policy.subpolicies: 354 if policy.type == 'lookup': 355 policy.extend(subpolicy,entity=self) 356 break
357
358 - def setPolicyDepth(self,depth):
359 """Sets the lookahead policy depth I{within} the overall composite policy (creates a lookahead subpolicy if none pre-existing) 360 @param depth: the desired horizon 361 @type depth: int""" 362 ## self.invalidateCache() 363 if self.policy.type == 'composite': 364 for policy in self.policy.subpolicies: 365 if policy.type == 'lookahead': 366 policy.depth = depth 367 break 368 else: 369 # No pre-existing lookahead policy 370 self.policy.extend(LookaheadPolicy(self,self.entities,depth)) 371 elif self.policy.type == 'lookupahead': 372 self.policy.depth = depth
373
374 - def getPolicyDepth(self):
375 """@return: the lookahead policy depth I{within} the overall composite policy (returns 0 if no such subpolicy) 376 @rtype: int""" 377 if self.policy.type == 'composite': 378 for policy in self.policy.subpolicies: 379 if policy.type == 'lookahead': 380 return policy.depth 381 else: 382 # No pre-existing lookahead policy 383 return 0 384 elif self.policy.type == 'lookupahead': 385 return self.policy.depth
386 387 # Utility methods 388
389 - def __cmp__(self,agent):
390 """@note: This is just a string compare on names. Feel free to override with a more domain-specific comparison""" 391 return cmp(self.name.lower(),agent.name.lower())
392
393 - def __copy__(self):
394 new = GenericEntity.__copy__(self) 395 new = Stereotyper.__copy__(self,new) 396 new.themes = self.themes 397 new.factors = self.factors 398 if self.attributes.has_key('imageName'): 399 new.attributes['image'] = self.attributes['image'] 400 new.attributes['imageName'] = self.attributes['imageName'] 401 new.description = copy.copy(self.description) 402 return new
403
404 - def __getstate__(self):
405 """Remove any image info before pickling""" 406 new = copy.copy(self.__dict__) 407 new['image'] = None 408 return new
409
410 - def __setstate__(self,newDict):
411 """Restore image info after unpickling""" 412 for key,value in newDict.items(): 413 self.__dict__[key] = value 414 if self.attributes.has_key('window'): 415 name = self.attributes['imageName'] 416 self.attributes['image'] = getAgentImage(name) 417 return self
418
419 - def __xml__(self):
420 doc = GenericEntity.__xml__(self) 421 return Supporter.__xml__(self,doc)
422
423 - def parse(self,element):
424 GenericEntity.parse(self,element) 425 Supporter.parse(self,element)
426