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

Source Code for Module teamwork.agent.consistency

  1  consistencyCalculationAvailable = True 
  2  try: 
  3      from teamwork.math.KeyedVector import UnchangedRow 
  4      from MemoryAgent import MemoryAgent 
  5      from teamwork.math.probability import Distribution 
  6      from teamwork.math.Keys import StateKey,ConstantKey 
  7      from cvxopt.base import matrix,print_options 
  8      from cvxopt.solvers import qp 
  9      from cvxopt import solvers 
 10      solvers.options['show_progress'] = False 
 11      from numpy.lib.polynomial import poly1d 
 12      from copy import deepcopy 
 13  except ImportError: 
 14      consistencyCalculationAvailable = False 
 15   
16 -class ConsistentAgent(MemoryAgent):
17 - def __init__(self,name):
18 MemoryAgent.__init__(self,name)
19
20 - def calculateMessageConsistency(self,msg):
21 22 #we can short-circuit things if our agent has no memory.. thus there is nothing to be consistent with 23 if len(self.memory) == 0: 24 return {"currentConsistency" : 0, 25 "proposedConsistency" : 0, 26 "proposedMemory" : [], 27 "proposedBeliefState" : self.getAllBeliefs()['state']} 28 else: 29 currentConsistency = self.getMemoryConsistency() 30 31 proposedMemory = self.__propagateBeliefsBackInTime__(msg) 32 result = self.__propagateBeliefsForwardInTime__(memory=proposedMemory) 33 proposedConsistency = self.getMemoryConsistency(memory=result['updatedMemory']) 34 35 return {"currentConsistency" : currentConsistency, 36 "proposedConsistency" : proposedConsistency, 37 "proposedMemory" : result['updatedMemory'], 38 "proposedBeliefState" : result['updatedStateBeliefs']}
39
40 - def getMemoryConsistency(self,memory=None):
41 if not memory: 42 memory = self.memory 43 44 #iterate through the memories and figure out how 'good' each taken action was compared to the others 45 consistency = 1 46 for mem in memory: 47 actions = mem['actions'] 48 actor = actions.keys()[0] 49 availableActions = self.entities[actor].actions.getOptions() 50 avdict = {} 51 bestValue = None 52 worstValue = None 53 for action in availableActions: 54 av = self.entities[actor].actionValue(action,state=deepcopy(mem['previousBeliefs']))[0].items()[0][0] 55 avdict[action[0]] = av 56 if not bestValue: 57 bestValue = av 58 else: 59 if av > bestValue: 60 bestValue = av 61 if not worstValue: 62 worstValue = av 63 else: 64 if av < worstValue: 65 worstValue = av 66 67 performedValue = avdict[actions.values()[0][0]] 68 gap = bestValue - worstValue 69 actualGap = bestValue - performedValue 70 71 if (gap != 0): 72 consistency *= 1. - (actualGap/gap) 73 74 return consistency
75 76 77 78 79
80 - def __solveForUniqueTreePath__(self,path,leaf,memory,currentState,specifiedEqualityConstraints=None):
81 82 #inequality constraints 83 gContents = [] 84 hContents = [] 85 86 keys = self.entities.getState().domain()[0].keys()[:] 87 keys.remove(ConstantKey()) 88 89 90 for p in path: 91 multiplier = -1 92 if not p[1]: 93 multiplier = 1 94 for key in keys: 95 gContents.append(p[0][0].__getitem__(key) * multiplier) 96 hContents.append(p[0][0].threshold * multiplier) 97 98 #equality constraints 99 aContents = [] 100 bContents = [] 101 102 #if specifiedEqualityConstraints == None, then we assume we can use the current state values as the current 103 #equality targets 104 if not specifiedEqualityConstraints: 105 for key in keys: 106 row = leaf.getValue().__getitem__(key) 107 leafContents = [] 108 109 if not isinstance(row,UnchangedRow): 110 for k in keys: 111 leafContents.append(row.__getitem__(k)) 112 #the following should account for increment and settoconstant rows 113 value = currentState.items()[0][0][key] - row.__getitem__(ConstantKey()) 114 bContents.append(value) 115 aContents.extend(leafContents) 116 117 #otherwise we ONLY want to constrain certain values 118 else: 119 sec = specifiedEqualityConstraints[:] 120 for key in keys: 121 row = leaf.getValue().__getitem__(key) 122 leafContents = [] 123 124 if not isinstance(row,UnchangedRow) and sec.__contains__(key): 125 for k in keys: 126 leafContents.append(row.__getitem__(k)) 127 #the following should account for increment and settoconstant rows 128 value = currentState.items()[0][0][key] - row.__getitem__(ConstantKey()) 129 bContents.append(value) 130 aContents.extend(leafContents) 131 #remember to remove the key from specified equality constraints 132 sec.remove(key) 133 #now we add in any unadded specified constraints 134 for key in sec: 135 leafContents = [] 136 for k in keys: 137 if k == key: 138 leafContents.append(1) 139 else: 140 leafContents.append(0) 141 value = currentState.items()[0][0][key] 142 bContents.append(value) 143 aContents.extend(leafContents) 144 145 #finally, take care of the objective function 146 #this attempts to minimize the squared distance between the newly proposed beliefs and the 147 #agent's previous memory of beliefs representing the agent's desire to keep its memory 148 #as consistent as possible 149 qContents = [] 150 pContents = [] 151 for key in keys: 152 oldval = memory['previousBeliefs']['state'].items()[0][0][key] 153 # oldval = currentState.items()[0][0][key] 154 #I think the above was wrong because we want to minimize the agent's old memory, not the newly proposed one 155 eq = poly1d([1,-2*oldval,oldval**2]) 156 qContents.append(eq.deriv()[0]) 157 for k in keys: 158 if k == key: 159 #the 2nd derivitive will always reduce down to 2 in our case 160 pContents.append(2) 161 else: 162 pContents.append(0) 163 164 G = matrix(gContents, (len(keys), len(hContents))) 165 G = G.trans() 166 h = matrix(hContents, (len(hContents), 1)) 167 if len(bContents) == 0: 168 A = None 169 b = None 170 else: 171 A = matrix(aContents, (len(keys), len(bContents))) 172 A = A.trans() 173 b = matrix(bContents, (len(bContents), 1)) 174 175 q = matrix(qContents, (len(keys), 1)) 176 P = matrix(pContents, (len(keys), len(keys))) 177 178 # print "G" 179 # print G 180 # print "h" 181 # print h 182 # print "A" 183 # print A 184 # print "b" 185 # print b 186 # print "P" 187 # print P 188 # print "q" 189 # print q 190 # 191 #solve the QP 192 result = qp(P=P, q=q, G=G, h=h, A=A, b=b) 193 if result['x'] == None: 194 return None 195 196 #we need to return the value of the objective function (sum of squares) 197 objvalue = 0 198 for key,index in zip(keys,range(len(keys))): 199 objvalue += (currentState.items()[0][0][key] - result['x'][index]) ** 2 200 201 return ({'objective':objvalue,'solution':dict(zip(keys,result['x']))})
202
204 #debug: I need to reexamine this and see if there's a better way to apply the messages 205 #we need the current state 206 currentState = deepcopy(self.getAllBeliefs()['state']) 207 208 #then update the current state to reflect the message contents 209 #note that this doesn't seem to be able to handle messages referencing multiple states 210 key = self.__getMessageContentKey__(msg) 211 currentState.items()[0][0].unfreeze() 212 currentState.items()[0][0].__setitem__(key,msg['factors'][0]['value'].items()[0][0]) 213 currentState.items()[0][0].freeze() 214 215 return currentState
216
217 - def __getMessageContentKey__(self,msg):
218 key = StateKey() 219 key['entity'] = msg['factors'][0]['lhs'][1] 220 key['feature'] = msg['factors'][0]['lhs'][3] 221 return key
222
223 - def __propagateBeliefsForwardInTime__(self,memory=None):
224 225 newBeliefs = [] 226 newCurrentBeliefs = None 227 228 if not memory: 229 memory = self.memory 230 231 #we reverse the memory so that we start with the oldest memory first 232 reverseMemory = deepcopy(memory) 233 reverseMemory.reverse() 234 for mem in reverseMemory: 235 #get the dnyamics 236 dynamics = self.entities.getDynamics(mem['actions'])['state'] 237 238 #apply the dynamics 239 delta = dynamics.apply(mem['previousBeliefs']['state']) 240 241 #apply the change in state 242 newMem = delta * mem['previousBeliefs']['state'] 243 244 #append the new memory 245 newBeliefs.append(newMem) 246 247 #We're not quite done yet 248 #the last belief in our newBeliefs list is actually the current belief - not a memory so we need to adjust 249 newCurrentBeliefs = newBeliefs[-1] 250 newBeliefs = newBeliefs[:-1] 251 252 #now we reverse the new beliefs so that they align correctly with our old beliefs 253 newBeliefs.reverse() 254 255 #make a deep copy of the current memory 256 updatedMemory = deepcopy(memory) 257 258 #iterate through the beliefs and reset the state to what we just calculated 259 for mem,beliefs in zip(updatedMemory[:-1],newBeliefs): 260 mem['previousBeliefs']['state'] = beliefs 261 262 #now just return the whole thing in a nicely packed dictionary 263 return {'updatedMemory':updatedMemory,'updatedStateBeliefs':newCurrentBeliefs}
264
265 - def __propagateBeliefsBackInTime__(self,msg):
266 updatedMemory = [] 267 268 #we need the current state as if the message had been accepted 269 acceptedState = self.__getStateIntegratedWithMessage__(msg) 270 equalityConstraints = [self.__getMessageContentKey__(msg)] 271 272 #loop through the number of memories that this agent holds 273 for memory in self.memory: 274 275 #make a deep copy of our old memory 276 newMemory = deepcopy(memory) 277 278 #Get the dynamic for the most recent action that we remember 279 dynamics = self.entities.getDynamics(memory['actions'])['state'] 280 281 #Here we get all the unique paths (i.e. paths leading to differnt leaves) for the given dynamic 282 #for each unique path we'll construct a unique qp formulation 283 allPaths = map(lambda x: (x.getPath(),x), dynamics.getTree().leafNodes()) 284 285 #iterate through all the possible paths and set up and solve the QP for each one 286 bestMinResult = None 287 bestSolution = None 288 for path,leaf in allPaths: 289 result = self.__solveForUniqueTreePath__(path,leaf,memory,acceptedState,specifiedEqualityConstraints=equalityConstraints) 290 if result == None: 291 continue 292 293 if bestSolution == None or result['objective'] < bestMinResult: 294 bestMinResult = result['objective'] 295 bestSolution = result['solution'] 296 297 #reset the additional equality constraints 298 equalityConstraints = None 299 300 #here we update our current state to be the solution we just found 301 #debug - not sure if this is right 302 for key in bestSolution.keys(): 303 acceptedState.items()[0][0].__setitem__(key,bestSolution[key]) 304 305 #then update the 'state' value entry with our new accepted state 306 newMemory['previousBeliefs']['state'] = deepcopy(acceptedState) 307 308 #then append the new instance of memory to an overall updated record of memory 309 updatedMemory.append(newMemory) 310 311 return updatedMemory
312 313 if __name__ == '__main__': 314 from teamwork.messages.PsychMessage import Message 315 316 from teamwork.shell.PsychShell import PsychShell 317 318 #set up some keys 319 bPowerKey = StateKey() 320 bPowerKey['entity'] = 'Bully' 321 bPowerKey['feature'] = 'power' 322 323 vPowerKey = StateKey() 324 vPowerKey['entity'] = 'Victim' 325 vPowerKey['feature'] = 'power' 326 327 #load the test file 328 shell = PsychShell() 329 shell.load("/home/ito/Documents/isi/projects/teamwork/simpleSchool.scn") 330 agents = shell.scenario 331 332 results = agents['Teacher'].entities.microstep(turns=[{'name':'Bully'}],hypothetical=True)['decision']['Bully'] 333 print "The teacher expects the bully to do the following: %s" % results 334 print 335 336 result = agents.microstep(turns=[{'name':'Bully'}])['decision']['Bully'] 337 print "But in reality, the bully does the following: %s" % result 338 print 339 print "After %s, the teacher's beliefs are as follows:" % result 340 print "\t--> %s: %f" % (bPowerKey,agents['Teacher'].getAllBeliefs()['state'].items()[0][0][bPowerKey]) 341 print "\t--> %s: %f" % (vPowerKey,agents['Teacher'].getAllBeliefs()['state'].items()[0][0][vPowerKey]) 342 print 343 print "But the victim, who has an accurate representation of the world, has the following beliefs:" 344 print "\t--> %s: %f" % (bPowerKey,agents['Victim'].getAllBeliefs()['state'].items()[0][0][bPowerKey]) 345 print "\t--> %s: %f" % (vPowerKey,agents['Victim'].getAllBeliefs()['state'].items()[0][0][vPowerKey]) 346 347 #construct a message 348 factor = {} 349 factor['topic'] = 'state' 350 factor['lhs'] = ['entities', 'Bully', 'state', 'power'] 351 dist = Distribution() 352 dist[agents['Victim'].getAllBeliefs()['state'].items()[0][0][bPowerKey]] = 1 353 factor['value'] = dist 354 factor['relation'] = '=' 355 msg = Message({'factors':[factor]}) 356 receives = [] 357 overhears = [] 358 receives.append('Teacher') 359 360 #do the whole tamale 361 tamale = agents['Teacher'].calculateMessageConsistency(msg) 362 363 print 364 print "The victim decides to send a message to the teacher indicating that the bully's power is actually %f" % agents['Victim'].getAllBeliefs()['state'].items()[0][0][bPowerKey] 365 366 print 367 print "The teacher's full state of the world (the teacher's beliefs at t=0) before the victim was picked on is the following:" 368 print "\tMemory:" 369 print "\t\t--> %s: %f" % (bPowerKey,agents['Teacher'].memory[0]['previousBeliefs']['state'].items()[0][0][bPowerKey]) 370 print "\t\t--> %s: %f" % (vPowerKey,agents['Teacher'].memory[0]['previousBeliefs']['state'].items()[0][0][vPowerKey]) 371 print "\tCurrent Beliefs:" 372 print "\t\t--> %s: %f" % (bPowerKey,agents['Teacher'].getAllBeliefs()['state'].items()[0][0][bPowerKey]) 373 print "\t\t--> %s: %f" % (vPowerKey,agents['Teacher'].getAllBeliefs()['state'].items()[0][0][vPowerKey]) 374 print "\tCurrent Memory Consistency:" 375 print "\t\t--> %f" % tamale['currentConsistency'] 376 377 print 378 print "If the teacher were to accept the message, the teacher would adjust its memory of the state to the following:" 379 print "\tProposed Memory:" 380 print "\t\t--> %s: %f" % (bPowerKey,tamale['proposedMemory'][0]['previousBeliefs']['state'].items()[0][0][bPowerKey]) 381 print "\t\t--> %s: %f" % (vPowerKey,tamale['proposedMemory'][0]['previousBeliefs']['state'].items()[0][0][vPowerKey]) 382 print "\tProposed Beliefs:" 383 print "\t\t--> %s: %f" % (bPowerKey,tamale['proposedBeliefState'].items()[0][0][bPowerKey]) 384 print "\t\t--> %s: %f" % (vPowerKey,tamale['proposedBeliefState'].items()[0][0][vPowerKey]) 385 print "\tProposed Consistency:" 386 print "\t\t--> %f" % tamale['proposedConsistency'] 387