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

Source Code for Module teamwork.agent.support

  1  """ 
  2  Defines dynamics binary relationships between agents 
  3  """ 
  4  import copy 
  5   
  6  from GoalBased import * 
  7  from teamwork.math.KeyedVector import KeyedVector 
  8  from teamwork.math.Keys import LinkKey 
  9   
10 -class Supporter(GoalBasedAgent):
11 """Mix-in class that enables and updates support relationships 12 @cvar supportLimit: the maximum distance allowed between the goals as stated in another entity's messages and one's own beliefs, when determining whether that entity's messages are in support of one's current beliefs 13 @type supportLimit: float 14 @ivar links: the current dynamic relationship values 15 @type links: L{KeyedVector} 16 @ivar linkTypes: list of current dynamic relationship types 17 @type linkTypes: str[] 18 @ivar linkDynamics: the decision tree defining the effects on the dynamic relationship values, indexed by link type, then by action type 19 @type: strS{->}strS{->}PWLDynamics 20 """ 21 22 _supportFeature = 'likes' 23 _trustFeature = 'trusts' 24 supportWeights = {'support':0.1, 25 'legitimacy':0.1, 26 'past':0.5, 27 'future':0.3 28 } 29 supportLimit = 0.5 30
31 - def __init__(self,name=''):
32 # Kind of hacky way to make sure we don't do this superclass 33 # constructor more than once 34 try: 35 self.goals 36 except AttributeError: 37 GoalBasedAgent.__init__(self,name) 38 self.links = KeyedVector() 39 self.linkDynamics = {} 40 self.linkTypes = [self._supportFeature,self._trustFeature]
41 42 # Methods for accessing/manipulating entity state 43
44 - def getLinkKey(self,relation,entity):
45 """ 46 @return: the vector index for this entity's relation to the given 47 entity 48 @rtype: L{LinkKey} 49 """ 50 return LinkKey({'subject':self.name, 51 'verb':relation, 52 'object':entity})
53 69 82 94
95 - def getLinkees(self,relationship):
96 """ 97 @param relationship: the dynamic relationship (e.g., 'likes', 98 'trusts') to evaluate 99 @type relationship: str 100 @return: the others to which this entity has explicit 101 relationships of the specified type 102 @rtype: str[] 103 """ 104 result = [] 105 for key in self.links.keys(): 106 if key['subject'] == self.name and key['verb'] == relationship: 107 result.append(key['object']) 108 return result
109
110 - def getLinkTypes(self):
111 """ 112 @return: all of the available dynamics relationship types that 113 his entity has 114 @rtype: str[] 115 """ 116 return self.linkTypes[:]
117
118 - def getTrust(self,entity):
119 """ 120 @return: the trust that I have in the given entity 121 @rtype: float 122 """ 123 return self.getLink(self._trustFeature,entity)
124
125 - def setTrust(self,entity,value):
126 """Sets the trust that I have in the given entity 127 @param entity: the entity I (dis)trust 128 @type entity: str 129 @param value: the new value for my trust level 130 """ 131 self.setLink(self._trustFeature,entity,value)
132
133 - def getSupport(self,entity):
134 """ 135 @return: the support/liking that I have in the given entity 136 @rtype: L{teamwork.math.probability.Distribution} 137 """ 138 return self.getLink(self._supportFeature,entity)
139
140 - def setSupport(self,entity,value):
141 """Sets the support/liking that I have in the given entity 142 @param entity: the entity I (dis)like 143 @type entity: str 144 @param value: the new value for my support/liking level 145 """ 146 self.setLink(self._supportFeature,entity,value)
147
148 - def initEntities(self,entityList):
149 """Sets the entities linked to 150 """ 151 # Update my link types 152 for myClass in self.classes: 153 myType = self.hierarchy[myClass] 154 for linkType in myType.getLinkTypes(): 155 if linkType == self._supportFeature or \ 156 linkType == self._trustFeature: 157 pass 158 elif linkType in self.linkTypes: 159 # Already found more specific model for this link 160 for action in myType.linkDynamics[linkType].keys(): 161 if not self.linkDynamics[linkType].has_key(action): 162 dyn = myType.linkDynamics[linkType][action] 163 self.linkDynamics[linkType][action] = dyn 164 else: 165 self.linkTypes.append(linkType) 166 self.linkDynamics[linkType] = {} 167 for action,dyn in myType.linkDynamics[linkType].items(): 168 self.linkDynamics[linkType][action] = dyn 169 # Update links to other entities 170 for other in entityList: 171 if other.name != self.name: 172 # Assumes you can't have links to yourself. Questionable. 173 for myClass in self.classes: 174 myType = self.hierarchy[myClass] 175 for linkType in myType.getLinkTypes(): 176 if not other.name in self.getLinkees(linkType): 177 for yrClass in other.classes: 178 if yrClass in myType.getLinkees(linkType): 179 value = myType.getLink(linkType,yrClass) 180 self.setLink(linkType,other.name,value) 181 break
182
183 - def getAllBeliefs(self):
184 """Packages up all of this agent's beliefs into a handy dictionary 185 @return: the dictionary has the following indices: 186 - state: what this agent believes about the state of the world 187 - I{name}: what this agent think agent, I{name}, believes (i.e., a recursive call to L{getAllBeliefs}) 188 @rtype: dict 189 """ 190 result = GoalBasedAgent.getAllBeliefs(self) 191 result['relationships'] = self.links 192 return result
193
194 - def preComStateEstimator(self,beliefs,actions,epoch=-1,debug=None):
195 """ 196 Computes the hypothetical changes to the given beliefs in response to the given actions 197 @param beliefs: the beliefs to be updated (traditionally, the result from L{getAllBeliefs}) 198 @type beliefs: dict 199 @param actions: the actions observed by this agent 200 @type actions: C{dict:strS{->}L{Action}} 201 @param epoch: the current epoch in which these observations occurred (currently ignored, but potentially important) 202 @type epoch: C{int} 203 @type debug: L{Debugger} 204 @return: the belief changes that would result from the specified observed actions, in dictionary form: 205 - beliefs: results as returned by L{hypotheticalAct<SequentialAgents.hypotheticalAct>} 206 - observations: the given actions 207 @rtype: C{dict} 208 """ 209 delta = GoalBasedAgent.preComStateEstimator(self,beliefs,actions, 210 epoch,debug) 211 delta['relationships'] = {} 212 diff = None 213 change = None 214 goals = None 215 for link in self.links.keys(): 216 if actions.has_key(link['object']): 217 # Update only relationships with actors? 218 if link['verb'] == self._supportFeature: 219 # Liking of an actor 220 if change is None: 221 # First compute the change in our expected utility 222 change = copy.deepcopy(delta['state'].expectation()) 223 for key in change.rowKeys(): 224 change.set(key,key,change[key][key]-1.) 225 if goals is None: 226 # Compute our goals 227 goals = self.getGoalVector()['state'] 228 goals.fill(change.rowKeys()) 229 goals = goals.expectation() 230 if diff is None: 231 # We're not distinguishing among the individual effects 232 # of the different actions (if multiple actors act in 233 # parallel), so everyone's liking changes the same 234 diff = goals*change 235 diff[link] = 1. 236 delta['relationships'][link] = diff 237 elif link['verb'] == self._trustFeature: 238 pass 239 else: 240 # User-defined link 241 table = self.linkDynamics[link['verb']] 242 for action in actions[link['object']]: 243 try: 244 dynamics = table[action['type']] 245 except KeyError: 246 dynamics = None 247 if dynamics: 248 if beliefs is None: 249 beliefs = self.getAllBeliefs() 250 vector = dynamics.instantiateAndApply(beliefs['state'],self,action)[link] 251 try: 252 delta['relationships'][link] += vector 253 except KeyError: 254 delta['relationships'][link] = vector 255 return delta
256
257 - def updateTrust(self,sender,delta,accept):
258 """Updates the given delta based on any changes due to the 259 acceptance/reject of a message 260 @param sender: the agent sending the message 261 @type sender: str 262 @param delta: the current effect dictionary 263 @type delta: dict 264 @param accept: flat indicating whether the message has been accepted 265 (C{True} means accepted) 266 @type accept: bool 267 @return: the updated effect dictionary (original dictionary is changed 268 as a side effect) 269 @rtype: dict 270 """ 271 if sender in self.getLinkees(self._trustFeature): 272 key = self.getLinkKey(self._trustFeature,sender) 273 vector = KeyedVector() 274 if accept: 275 vector[keyConstant] = 0.1 276 else: 277 vector[keyConstant] = -0.1 278 vector.fill(self.entities.state.domain()[0].keys()) 279 try: 280 delta['relationships'][key] = vector 281 except KeyError: 282 delta['relationships'] = {key: vector} 283 if not delta.has_key(self.name): 284 delta[self.name] = {} 285 return delta
286 298
299 - def __xml__(self,doc=None):
300 if doc is None: 301 doc = GoalBasedAgent.__xml__(self) 302 node = doc.createElement('links') 303 element = self.links.__xml__().documentElement 304 node.appendChild(element) 305 doc.documentElement.appendChild(node) 306 # Write available link types 307 for linkType in self.getLinkTypes(): 308 node = doc.createElement('linktype') 309 node.setAttribute('name',linkType) 310 doc.documentElement.appendChild(node) 311 # Write link dynamics 312 for linkType,table in self.linkDynamics.items(): 313 for action,dynamics in table.items(): 314 if isinstance(action,str): 315 node = doc.createElement('linkdynamics') 316 node.setAttribute('feature',linkType) 317 node.setAttribute('action',action) 318 node.appendChild(dynamics.__xml__().documentElement) 319 doc.documentElement.appendChild(node) 320 return doc
321
322 - def parse(self,element):
323 if self.name is None: 324 GoalBasedAgent.parse(self,element) 325 child = element.firstChild 326 while child: 327 if child.nodeType == child.ELEMENT_NODE: 328 if child.tagName == 'links': 329 subChild = child.firstChild 330 while subChild: 331 if subChild.nodeType == child.ELEMENT_NODE: 332 self.links = self.links.parse(subChild) 333 subChild = subChild.nextSibling 334 elif child.tagName == 'linktype': 335 linkType = str(child.getAttribute('name')) 336 if not self.linkDynamics.has_key(linkType): 337 self.linkTypes.append(linkType) 338 self.linkDynamics[linkType] = {} 339 elif child.tagName == 'linkdynamics': 340 linkType = str(child.getAttribute('feature')) 341 action = str(child.getAttribute('action')) 342 dyn = PWLDynamics() 343 subChild = child.firstChild 344 while subChild: 345 if subChild.nodeType == child.ELEMENT_NODE: 346 dyn.parse(subChild) 347 break 348 subChild = subChild.nextSibling 349 try: 350 self.linkDynamics[linkType][action] = dyn 351 except KeyError: 352 self.linkDynamics[linkType] = {action: dyn} 353 child = child.nextSibling
354