Package teamwork :: Package dynamics :: Module pwlDynamics
[hide private]
[frames] | no frames]

Source Code for Module teamwork.dynamics.pwlDynamics

  1  """Dynamics objects for the PWL implementation 
  2  @var constantDynamics: a reusable instance of dynamics for the constant value in the state vector 
  3  @type constantDynamics: L{PWLDynamics} 
  4  """ 
  5  from teamwork.math.Keys import * 
  6  from teamwork.math.matrices import * 
  7  from teamwork.math.KeyedVector import * 
  8  from teamwork.math.KeyedMatrix import * 
  9  from teamwork.math.ProbabilityTree import * 
 10  import arbitraryDynamics 
 11   
 12  import time 
 13  from types import * 
 14  from xml.dom.minidom import * 
 15   
16 -class PWLDynamics(arbitraryDynamics.BaseDynamics):
17 """Class of objects that represent the dynamics of a specific 18 state/belief feature in the simulation 19 @ivar effects: table of roles affected, containing keys 'actor','object','other'. If the value is C{True}, then the dynamics object affects that role 20 @type effects: strS{->}bool 21 """ 22
23 - def __init__(self,args=None):
24 arbitraryDynamics.BaseDynamics.__init__(self,args) 25 self.effects = {}
26
27 - def extractTable(self,entity,action):
28 """Helper function that extracts the context used in instantiating dynamics 29 @rtype: dict 30 """ 31 table = dict(action) 32 table['self'] = entity 33 for relationship,entities in entity.relationships.items(): 34 if len(entities) == 1: 35 table[relationship] = entities[0] 36 return table
37
38 - def instantiate(self,entity,action):
39 """Returns a new L{PWLDynamics} instance that has been specialized to apply to only the specified entity in response to the specified instantiated action. This produces a more compact decision tree where branches irrelevant to the given entity and action have been pruned away. 40 @type action: dict 41 @rtype: L{PWLDynamics} 42 """ 43 table = self.extractTable(entity,action) 44 args = copy.copy(self.args) 45 args['tree'] = self.getTree().instantiate(table) 46 args['tree'].prune() 47 return self.__class__(args)
48
49 - def instantiateAndApply(self,state,entity=None,action=None, 50 table={},tree=None):
51 """Performs both L{instantiate} and L{apply} in a single call, but does a minimal instantiation, by ignoring branches that are irrelevant in the given state 52 @param entity: the entity performing the update 53 @type entity: L{Agent<teamwork.agent.Agent.Agent>} 54 @param action: the action being applied 55 @type action: L{Action<teamwork.action.PsychActions.Action>} 56 @param state: the current state of the world 57 @type state: L{Distribution}(L{KeyedVector}) 58 @rtype: L{Distribution}(L{KeyedMatrix}) 59 """ 60 if not table: 61 table = self.extractTable(entity,action) 62 if tree is None: 63 tree = self.getTree() 64 if tree.isLeaf(): 65 return tree.getValue().instantiate(table) 66 else: 67 falseTree,trueTree = tree.getValue() 68 value = True 69 for plane in tree.split: 70 result = plane.instantiate(table) 71 if isinstance(result,plane.__class__): 72 value = result.test(state) 73 elif result < 0: 74 value = False 75 if not value: 76 break 77 if value: 78 return self.instantiateAndApply(state,table=table, 79 tree=trueTree) 80 else: 81 return self.instantiateAndApply(state,table=table, 82 tree=falseTree)
83
84 - def getTree(self):
85 """ 86 @return: the decision tree for this dynamics object 87 @rtype: L{ProbabilityTree}""" 88 return self.args['tree']
89
90 - def apply(self,state,debug=0):
91 """Applies this dynamics function to the given state 92 @rtype: L{Distribution}(L{KeyedMatrix}) 93 """ 94 tree = self.getTree() 95 dynamics = tree[state] 96 return dynamics
97
98 - def merge(self,other):
99 """Merges the new dynamics into this one by calling L{KeyedMatrix.merge} on the leaves of the decision trees 100 @type other: L{PWLDynamics} 101 """ 102 myTree = self.getTree() 103 yrTree = other.getTree() 104 newTree = myTree.merge(yrTree,KeyedMatrix.merge) 105 return self.__class__({'tree':newTree})
106
107 - def renameEntity(self,old,new,tree=None):
108 """ 109 @param old: the current name of the entity 110 @param new: the new name of the entity 111 @type old,new: str 112 """ 113 if tree is None: 114 tree = self.getTree() 115 if not tree.isLeaf(): 116 for index in range(len(tree.split)): 117 # Update any refs to the old name in branches 118 plane = tree.split[index] 119 newKeys = [] 120 for key in plane.weights.specialKeys: 121 newKey = {} 122 newKey.update(key) 123 if isinstance(key,StateKey) and key['entity'] == old: 124 newKey['entity'] = new 125 elif isinstance(key,ClassKey) and key['value'] == old: 126 newKey['value'] = new 127 newKeys.append(newKey) 128 newPlane = plane.weights.__class__(keys=newKeys) 129 tree.split[index] = KeyedPlane(newPlane,plane.threshold) 130 # Recurse 131 for child in tree.children(): 132 self.renameEntity(old,new,child)
133
134 - def __add__(self,other):
135 myTree = self.getTree() 136 yrTree = other.getTree() 137 newTree = myTree + yrTree 138 return self.__class__({'tree':newTree})
139
140 - def __sub__(self,other):
141 myTree = self.getTree() 142 yrTree = other.getTree() 143 newTree = myTree - yrTree 144 return self.__class__({'tree':newTree})
145
146 - def __xml__(self):
147 doc = Document() 148 root = doc.createElement('dynamic') 149 doc.appendChild(root) 150 tree = self.getTree() 151 root.appendChild(tree.__xml__().documentElement) 152 return doc
153
154 - def parse(self,element):
155 self.args['tree'] = ProbabilityTree() 156 child = element.firstChild 157 while child and child.nodeType != child.ELEMENT_NODE: 158 child = child.nextSibling 159 if child: 160 self.args['tree'].parse(child) 161 else: 162 print element.toxml() 163 raise UserWarning,'Dynamics element missing tree!'
164
165 - def __str__(self):
166 return self.getTree().simpleText()
167
168 -def NullDynamics():
169 """ 170 @return: a dynamics object with a zero matrix 171 @rtype: L{PWLDynamics} 172 """ 173 dynamics = ProbabilityTree() 174 dynamics.makeLeaf(KeyedMatrix()) 175 return PWLDynamics({'tree':dynamics})
176
177 -def IdentityDynamics(feature):
178 """ 179 @param feature: the feature to be held constant 180 @type feature: str 181 @return: a dynamics object with an identity matrix over the given feature 182 @rtype: L{PWLDynamics} 183 """ 184 dynamics = ProbabilityTree() 185 dynamics.makeLeaf(IdentityMatrix(feature)) 186 return PWLDynamics({'tree':dynamics})
187
188 -def ConstantDynamics():
189 """ 190 @return: a dynamics object with an identity matrix over the constant value 191 @rtype: L{KeyedMatrix} 192 """ 193 row = KeyedVector({keyConstant:1.}) 194 matrix = KeyedMatrix() 195 matrix[keyConstant] = row 196 return matrix
197 198 constantDynamics = ConstantDynamics() 199 200 if __name__ == '__main__': 201 dynamics = PWLDynamics() 202 doc = parse('dynamics.xml') 203 dynamics.parse(doc.documentElement) 204 205 blah 206 from teamwork.math.KeyedTree import * 207 208 # Default keys 209 keys = {'myPower':keyMyValue, 210 'constant': keyConstant} 211 # Total power of actor 212 keys['actorPower'] = `{'entity':'actor', 213 'feature':'militarypower', 214 'total':1}` 215 # Total power of object 216 keys['objectPower'] = `{'entity':'object', 217 'feature':'militarypower', 218 'total':1}` 219 # Am I actor? 220 keys['amActor'] = `{'entity':'actor', 221 'relationship':'identity'}` 222 # Am I object? 223 keys['amObject'] = `{'entity':'object', 224 'relationship':'identity'}` 225 226 # Power unchanged 227 weights = {keys['myPower']:1.} 228 unchangedTree = createNodeTree(KeyedVector(weights)) 229 230 # Branch on whether actor is stronger than object 231 weights = {keys['actorPower']: -1., 232 keys['objectPower']: 1.} 233 plane = KeyedPlane(KeyedVector(weights),0.) 234 235 # Object dynamics if object is stronger 236 weights = {keys['myPower']: 1., 237 keys['actorPower']: -.1, 238 keys['objectPower']: .1, 239 keys['constant']: -.05} 240 objWeaker = createNodeTree(KeyedVector(weights)) 241 242 # Object dynamics if object is weaker 243 weights= {keys['myPower']: 1., 244 keys['constant']: -.01} 245 objStronger = createNodeTree(KeyedVector(weights)) 246 247 # Object dynamics 248 objectTree = createBranchTree(plane,objWeaker,objStronger) 249 250 # Branch on whether I'm object 251 weights = {keys['amObject']: 1.} 252 notActorTree = createBranchTree(KeyedPlane(KeyedVector(weights),0.5), 253 unchangedTree,objectTree) 254 255 # Actor much weaker 256 weights = {keys['myPower']: 1., 257 keys['actorPower']: .1, 258 keys['objectPower']: -.1, 259 keys['constant']: .02} 260 actorMuchWeakerTree = createNodeTree(KeyedVector(weights)) 261 262 # Actor weaker 263 weights = {keys['myPower']: 1., 264 keys['constant']: -.01} 265 actorWeakerTree = createNodeTree(KeyedVector(weights)) 266 267 # Branch on whether actor is *much* weaker than object 268 weights = {keys['actorPower']: -1., 269 keys['objectPower']: 1.} 270 actorTree = createBranchTree(KeyedPlane(KeyedVector(weights),0.2), 271 actorWeakerTree,actorMuchWeakerTree) 272 273 # Branch on whether I'm actor 274 weights = {keys['amActor']: 1.} 275 tree = createBranchTree(KeyedPlane(KeyedVector(weights),0.5), 276 notActorTree,actorTree) 277 278 dynamics = PWLDynamics({'tree':tree}) 279 280 from teamwork.utils.PsychUtils import load 281 from teamwork.action.PsychActions import PsychAction 282 283 print 'Loading...' 284 entities = load('/home/pynadath/python/teamwork/examples/MRE/mre.scn') 285 print 'done.' 286 feature = 'firepower' 287 followers = entities['Followers'] 288 aides = entities['Aides'] 289 print aides.getState(feature) 290 action = followers.actionClass({'actor':followers, 291 'type':'demonstrate', 292 'object':aides}) 293 entities.performAct([action]) 294 print aides.getState(feature) 295