1 """Defines the agent layer that handles beliefs about other agents"""
2 from copy import copy
3 from xml.dom.minidom import *
4
5 from Agent import *
6
7 from teamwork.action.PsychActions import *
8 from teamwork.action.DecisionSpace import parseSpace
9 from teamwork.math.Keys import *
10 from teamwork.math.probability import *
11 from teamwork.utils.PsychUtils import *
12 from teamwork.multiagent.sequential import SequentialAgents
13 from teamwork.policy.policyTable import PolicyTable
14 from teamwork.dynamics.pwlDynamics import *
15
17 """Base class for an agent that keeps recursive models of the other agents in its world.
18 @ivar state: the probability distribution over the state of this agent's world
19 @type state: L{Distribution}
20 @ivar parent: the agent whose subjective view this agent represents (C{None}, if this is an objective view)
21 @type parent: L{RecursiveAgent}
22 @ivar dynamics: the dynamics by which this agent's state evolves
23 @type dynamics: dict
24 @ivar relationships: inter-agent relationships from this agent. In dictionary form:
25 - I{relationship name}: list of agent names
26 """
27
47
67
68
69
71 """Returns the current L{Distribution} over the specified feature
72 @type feature: string
73 @rtype: L{Distribution}"""
74 key = StateKey({'entity':self.name,'feature':feature})
75 return self.state.getMarginal(key)
76
78 """Sets this entity's state value for the specified feature
79 @type feature: string
80 @type value: either a float or a L{Distribution}. If the value is a float, it is first converted into a point distribution."""
81 key = StateKey({'entity':self.name,'feature':feature})
82 frozen = self.state.unfreeze()
83 self.state.join(key,value)
84 if frozen:
85 self.state.freeze()
86
88 """Returns the current L{Distribution} over the specified observation flag
89 @type name: string
90 @rtype: L{Distribution}"""
91 key = ObservationKey({'type':name})
92 return self.state.getMarginal(key)
93
95 """Sets this entity's observation flag for the observation type
96 @type name: string
97 @type value: either a float or a L{Distribution}. If the value is a float, it is first converted into a point distribution."""
98 key = ObservationKey({'type':name})
99 self.state.unfreeze()
100 self.state.join(key,value)
101 self.state.freeze()
102
104 """
105 @return: names of the valid state features
106 @rtype: C{str[]}
107 """
108 keyList = []
109 for key in self.state.domainKeys():
110 if isinstance(key,StateKey) and key['entity'] == self.name:
111 keyList.append(key['feature'])
112 return keyList
113
114
115
117 """
118 @return: the agent representing the beliefs about the given entity
119 @type name: string
120 @rtype: L{RecursiveAgent}
121 """
122 if not isinstance(name,str):
123 raise DeprecationWarning,'getEntity requires string argument'
124 try:
125 return self.entities[name]
126 except KeyError:
127 raise KeyError,'Entity %s has no belief about %s' \
128 % (self.ancestry(),name)
129
131 """Allows indexing into entity beliefs (i.e., C{entity['Bill']})"""
132 return self.getEntity(index)
133
135 """
136 @param entity: the name of the entity being queried about
137 @type entity: C{str}
138 @return: C{True} iff I have a belief about the named entity
139 @rtype: C{boolean}
140 """
141 return self.entities.has_key(entity)
142
144 """
145 @return: the names of entities that I have beliefs about
146 @rtype: C{str[]}
147 """
148 return self.entities.keys()
149
151 """
152 @return: the subjective entity views that I have
153 @rtype: L{Agent}[]
154 """
155 return self.entities.values()
156
158 """
159 @return: the state features across all beliefs that this agent has
160 @rtype: L{StateKey}[]
161 """
162 return self.entities.getStateKeys().keys()
163
165 """Shortcut for C{self.L{getEntity}(entity).L{getState}(feature)}"""
166 subjectiveEntity = self.getEntity(entity)
167 return subjectiveEntity.getState(feature)
168
170 """Accesses a nested belief by following the branches specified by keys (a list of strings).
171 @warning: may not actually work anymore!
172 """
173 currentBelief = self
174 for key in keys:
175 if type(currentBelief) is InstanceType:
176 if key == 'state':
177 currentBelief = currentBelief.state
178 continue
179 elif key == 'entities':
180 continue
181
182 if key == 'self':
183 key = self.name
184 try:
185 currentBelief = currentBelief[key]
186 except KeyError:
187 try:
188 currentBelief = currentBelief.getEntity(key)
189 except AttributeError,e:
190 raise AttributeError,'Illegal belief spec: %s' % (`keys`)
191 except AttributeError,e:
192 raise AttributeError,'Illegal belief spec: %s' % (`keys`)
193 return currentBelief
194
196 """Shortcut for C{self.L{getEntity}(self.name).L{getState}(feature)}"""
197 selfImage = self.getEntity(self.name)
198 return selfImage.getState(feature)
199
200
201
203 """Shortcut for C{self.L{getEntity}(entity).{setState}(feature,value)}"""
204 subjectiveEntity = self.getEntity(name)
205 subjectiveEntity.setState(feature,value)
206
208 """Shortcut for C{self.setBelief(self,feature,value)}"""
209 self.setBelief(self.name,feature,value)
210
212 """Sets my belief about the given entity to be the provided entity object. Basically equivalent to C{self.entities[entity.name] = entity}.
213 @type entity: L{RecursiveAgent}
214 """
215 self.entities.addMember(entity)
216 entity.parent = self
217
219 """Helper method for setting the beliefs of a feature
220 @param name: the name of the other entity about whom our belief is is subject to change.
221 @type name: C{str}
222 @param feature: the state feature to change
223 @type feature: C{str}
224 @param value: the new value for the named state feature
225
226 @note: this will change all of the subjective beliefs that this entityd holds. Thus, not only will my beliefs about C{name}, but also my beliefs about I{X}'s beliefs about C{name}."""
227 if self.hasBelief(name):
228 self.setBelief(name,feature,value)
229 for entity in self.getEntityBeliefs():
230 entity.setRecursiveBelief(name,feature,value)
231
233 """Packages up all of this agent's beliefs into a handy dictionary
234 @return: the dictionary has the following indices:
235 - state: what this agent believes about the state of the world
236 - I{name}: what this agent think agent, I{name}, believes (i.e., a recursive call to L{getAllBeliefs})
237 @rtype: dict
238 """
239 result = {'state':self.entities.getState(),
240 'turn':self.entities.order,
241 'observations':self.entities.getActions()
242 }
243 for agent in self.getEntityBeliefs():
244 result[agent.name] = agent.getAllBeliefs()
245
246
247
248 if len(agent.entities.members()) == 0:
249 result[agent.name]['_cheating'] = result
250 return result
251
252
253
254 - def applyPolicy(self,state=None,actions=[],history=None,debug=None,
255 explain=False):
256 """Generates a decision chosen according to the agent's current policy
257 @param state: the current state vector
258 @type state: L{Distribution}(L{KeyedVector})
259 @param actions: the possible actions the agent can consider (defaults to all available actions)
260 @type actions: L{Action}[]
261 @param history: a dictionary of actions that have already been performed (and which should not be performed again if they are labeled as not repeatable)
262 @type history: L{Action}[]:bool
263 @param explain: flag indicating whether an explanation should be generated
264 @type explain: bool
265 @return: a list of actions and an explanation, the latter provided by L{execute<PolicyTable.execute>}
266 @rtype: C{(L{Action}[],Element)}
267 """
268 if state is None:
269 state = self.getAllBeliefs()
270 return self.policy.execute(state=state,choices=actions,
271 history=history,debug=debug,explain=explain)
272
279
280
281
283 """Initializes beliefs"""
284 beliefs = {}
285 beliefs['entities'] = self.entities = SequentialAgents()
286 self.resetHistory(beliefs)
287 return beliefs
288
290 """Trying to unify L{preComStateEstimator} and L{postComStateEstimator}"""
291 return self.preComStateEstimator(beliefs,actions,epoch,debug)
292
294 """
295 Computes the hypothetical changes to the given beliefs in response to the given actions
296 @param beliefs: the beliefs to be updated (traditionally, the result from L{getAllBeliefs})
297 @type beliefs: dict
298 @param actions: the actions observed by this agent
299 @type actions: C{dict:strS{->}L{Action}}
300 @param epoch: the current epoch in which these observations occurred (currently ignored, but potentially important)
301 @type epoch: C{int}
302 @type debug: L{Debugger}
303 @return: the belief changes that would result from the specified observed actions, in dictionary form:
304 - beliefs: results as returned by L{SequentialAgents.hypotheticalAct}
305 - observations: the given actions
306 @rtype: C{dict}
307 """
308
309 delta = self.entities.hypotheticalAct(actions,beliefs)
310 if beliefs is not None:
311
312 self.applyChanges(beliefs,delta,descend=False)
313 return delta
314
316 """Update an entity's beliefs in response to set of messages
317 @param msg: the message whose dynamics we wish to compute
318 @type msg: L{Message<teamwork.messages.PsychMessage.Message>}
319 @param log: not sure what this is for, probably auditing at some point, but nothing happens to it right now, so it's not very useful
320 @return: the dynamics matrix corresponding to the desired change of beliefs implied by the given message
321 @rtype: L{KeyedMatrix}
322 """
323 delta = None
324 explanation = []
325 for factor in msg['factors']:
326 try:
327 result = factor['matrix']
328 except KeyError:
329 result = self.__incorporateMessage(factor)
330 if delta is None:
331 delta = result
332 else:
333 delta *= result
334 explanation.append(factor)
335 return {'state':delta},explanation
336
338 """Update an entity's beliefs in response to a received message
339 @param factor: the individual message factor
340 @type factor: dict
341 @return: the dynamics corresponding to an individual factor
342 @rtype: L{KeyedMatrix}
343 """
344
345 matrix = KeyedMatrix()
346 keyList = self.entities.state.expectation().keys()
347 matrix.fill(keyList)
348 for key in keyList:
349 matrix.set(key,key,1.)
350 delta = Distribution({matrix:1.})
351
352 if factor['topic'] == 'state':
353 state = None
354 currentBelief = self
355 path = []
356 for key in factor['lhs'][:len(factor['lhs'])-1]:
357 if key == 'entities':
358 currentBelief = currentBelief.entities
359 elif type(currentBelief) is InstanceType:
360 if key == 'state':
361 state = 1
362
363 continue
364 elif key == 'policy':
365 currentBelief = currentBelief.policy
366 else:
367 currentBelief = currentBelief.beliefs
368 currentBelief = currentBelief[key]
369 else:
370 try:
371 currentBelief = currentBelief[key]
372 path.append(key)
373 except KeyError,ex:
374
375 break
376 else:
377 if len(path) != 1:
378 raise NotImplementedError,'My apologies, I am unable to handle such rich messages right now'
379 else:
380 feature = factor['lhs'][len(factor['lhs'])-1]
381 key = StateKey({'entity':path[0],
382 'feature':feature})
383 if factor['relation'] == '=':
384
385 if isinstance(factor['value'],float):
386 for element,prob in delta.items():
387 del delta[element]
388 element.set(key,key,0.)
389 element.set(key,keyConstant,factor['value'])
390 delta[element] = prob
391 elif isinstance(factor['value'],Distribution):
392 if len(factor['value']) == 1:
393 for element,prob in delta.items():
394 del delta[element]
395 element.set(key,key,0.)
396 element.set(key,keyConstant,
397 factor['value'].expectation())
398 delta[element] = prob
399 else:
400 for matrix,oldProb in delta.items():
401 del delta[matrix]
402 for value,newProb in factor['value'].items():
403 newMatrix = copy.deepcopy(matrix)
404 newMatrix.set(key,key,0.)
405 newMatrix.set(key,keyConstant,value)
406 delta[newMatrix] = oldProb*newProb
407 else:
408
409 raise NotImplementedError,'Unable to handle messages with relationship, "%s"' % (factor['relation'])
410 elif factor['topic'] == 'observation':
411 raise NotImplementedError,'Currently unable to handle messages about actions'
412
413
414
415
416 elif factor['topic'] == 'model':
417 raise NotImplementedError,'Currently unable to handle messages about mental models'
418
419
420
421
422
423
424
425
426
427
428
429
430 delta.freeze()
431 return delta
432
433
434
436 """
437 @return: the sequence of events that this entity has witnessed
438 @rtype: C{list}
439 """
440 return self.beliefs['observations']
441
443 """Adds the given observation to the history
444 """
445 self.beliefs['observations'].insert(0,obs)
446
448 """Returns true iff the agent has observed the given action
449 @param action: the observation to look for
450 @type action: L{Action}
451 @param depth: the maximum number of steps to look into the past (by default, look arbitrarily far)
452 @type depth: int
453 @rtype: a tuple (boolean,int)
454 @return: the first return value is true iff the agent has observed the given action within the past depth time steps. The second return value is the number of steps in the past that the observation occurs. This value is negative if no such observation is found within the specified depth."""
455 obsList = self.getObservations()
456 if depth and depth < len(obsList):
457 limit = depth
458 else:
459 limit = len(obsList)
460 for index in range(limit):
461 for actor,actions in obsList[index].items():
462 for obs in actions:
463 if obs.matchTemplate(action):
464 return obs,index
465 return None,-1
466
467 - def resetHistory(self,beliefs=None):
468 """Resets the observation history of the specified beliefs (defaults to this entity's beliefs if none provided)"""
469 if not beliefs:
470 beliefs = self.beliefs
471 beliefs['observations'] = []
472
474 """
475 @param actionDict: the performed actions, indexed by actor name
476 @type actionDict: C{dict:strS{->}L{Action}[]}
477 @return: observations this entity would make of the given actions, in the same format as the provided action dictionary
478 @rtype: C{dict}
479 """
480 observations = {}
481 for actor,action in actionDict.items():
482 if actor == self.name:
483
484 observations[actor] = action
485 else:
486 observation = []
487
488 for subAct in action:
489
490 observation.append(subAct)
491 if len(observation) > 0:
492
493 observations[actor] = observation
494 return observations
495
497 """
498 @return: the minimal set of observations relevant to this agent
499 @rtype: C{L{teamwork.math.Keys.ActionKey}[]}"""
500 actionKeys = []
501
502 for key in self.getGoalVector()['action'].keys():
503 actionKeys.append(key)
504
505 for key in self.policy.tree.getKeys():
506 if key['class'] == 'observation':
507 if not key in actionKeys:
508 actionKeys.append(key)
509 return actionKeys
510
511
512
513 - def multistep(self,horizon=1,start={},state=None,debug=None):
514 """Steps this entity the specified number of steps into the future (where a step is one entity performing its policy-specified action)
515 @param state: the world state to evaluate the actions in (defaults to current world state)
516 @type state: L{Distribution}(L{KeyedVector})
517 @warning: This method still needs to be handed an updated turn vector
518 """
519 if state is None:
520 state = self.getAllBeliefs()
521 sequence = []
522
523 for t in range(horizon):
524 if debug:
525 debug.message(9,'Time %d' % (t))
526 if t == 0:
527 entityDict = start
528 else:
529 entityDict = {}
530 nextGroup = self.entities.next(state['turn'])
531 for entity in nextGroup:
532 if isinstance(entity,dict):
533 try:
534 choices = entity['choices']
535 except KeyError:
536 choices = []
537 entity = entity['name']
538 else:
539 raise DeprecationWarning,'Turns should be expressed in dictionary form'
540 if len(entityDict) < len(nextGroup) and \
541 not entityDict.has_key(entity):
542 entityDict[entity] = choices
543
544 delta = self.step(entityDict,state,debug)
545 self.updateStateDict(state,delta['effect'])
546
547 sequence.append(delta)
548 return sequence
549
558
559 - def step(self,actDict,state=None,debug=None):
560 """Modifies the current entity in response to the
561 policy-driven actions selected by the provided dictionary of
562 entities.
563 @param state: the world state to evaluate the actions in (defaults to current world state)
564 @type state: L{Distribution}(L{KeyedVector})
565 """
566 explanation = {}
567
568 if state is None:
569 state = self.getAllBeliefs()
570
571 for name,action in actDict.items():
572 if debug:
573 debug.message(4,'%s predicting %s...' % (self.name,name))
574 try:
575 entity = self.getEntity(name)
576 except KeyError:
577
578 entity = None
579
580 if entity and entity.model:
581 if debug:
582 debug.message(7,'%s is modeled as %s' %
583 (name,entity.model['name']))
584 if isinstance(action,list) and len(action) > 0:
585
586 if isinstance(action[0],list):
587
588 action,exp = entity.applyPolicy(state=state[entity.name],
589 actions=action,
590 debug=debug)
591 else:
592
593 exp = {'forced':True,
594 'decision':action}
595 elif entity:
596
597 action,exp = entity.applyPolicy(state=state[entity.name],
598 debug=debug)
599 else:
600 action = None
601 exp = {}
602 if action and entity:
603 if debug:
604 debug.message(9,'\t%s expects %s to %s' %
605 (self.name,entity.name,action))
606 actDict[name] = action
607 explanation[name] = exp
608 if len(actDict) > 0:
609 result = {'effect':self.preComStateEstimator(state,actDict,
610 debug=debug),
611 'action':actDict
612 }
613 result['state'] = state['state']
614 result['turn'] = state['turn']
615 else:
616 result = {'effect':None,
617 'action':actDict
618 }
619 result['breakdown'] = explanation
620 return result
621
623 """
624 @return: this entity's dynamics model for the given action
625 @param act: the action whose effect we are interested in
626 @type act: L{Action}
627 @param feature: if the optional feature argument is provided, then this method returns the dynamics for only the given feature; otherwise, returns the effect over all state features (but this latter capability is now deprecated)
628 @type feature: C{str}
629 @rtype: L{PWLDynamics}
630 """
631 try:
632
633 dynFun = self.dynamics[feature][act]
634 except KeyError:
635
636 try:
637 dynFun = self.dynamics[feature][act['type']]
638 except KeyError:
639
640
641 try:
642 self.dynamics[feature][act] = None
643 except KeyError:
644 self.dynamics[feature] = {act: None}
645 return None
646 if isinstance(dynFun,str):
647 dynFun = self.hierarchy[dynFun].dynamics[feature][act['type']]
648 dynFun = dynFun.instantiate(self,act)
649
650 vector = self.state.domain()[0]
651 for leaf in dynFun.getTree().leaves():
652 for key in leaf.rowKeys():
653 if not vector.has_key(key):
654 print 'Dynamics of %s\'s %s in response to %s has extraneous key, %s' % (self.ancestry(),feature,str(act),str(key))
655 for key in leaf.colKeys():
656 if not vector.has_key(key):
657 print 'Dynamics of %s\'s %s in response to %s has extraneous key, %s' % (self.ancestry(),feature,str(act),str(key))
658 for branch in dynFun.getTree().branches().values():
659 if not isinstance(branch,Distribution):
660 for key in branch.weights.keys():
661 if not vector.has_key(key):
662 print 'Dynamics of %s\'s %s in response to %s has extraneous key, %s' % (self.ancestry(),feature,str(act),str(key))
663 self.dynamics[feature][act] = dynFun
664 return dynFun
665
667 """Takes changes and modifies the given beliefs accordingly
668 @param descend: If the descend flag is set, then the recursive changes in the delta will also be applied.
669 @type descend: C{boolean}
670 @param rewind: If the rewind flag is set, then the changes will be undone, instead of applied.
671 @type rewind: C{boolean}"""
672 for feature,diff in delta.items():
673 if feature == 'state':
674 beliefs['state'] = diff*beliefs['state']
675 elif feature == 'turn':
676 pass
677 elif feature == 'observations':
678 beliefs['observations'] = diff*beliefs['observations']
679 elif feature == 'relationships':
680 pass
681 else:
682 if descend:
683 self.applyChanges(beliefs[feature],diff,descend,rewind)
684
686 """Takes the current state of beliefs and marks it as the initial, beginning-of-the-world state of beliefs.
687 @note: as a side effect, it resets the observation history"""
688 self.initial = None
689
690
691
692
693
694
695 self.resetHistory()
696
697
698
700 """
701 @return: a string representation of this entity's position in the recursive belief tree.
702 - If C{self.parent == None}, then returns C{self.name}
703 - Otherwise, returns C{self.parent.ancestry()+'->'+self.name}
704 @rtype: C{str}"""
705 name = self.name
706 parent = self.parent
707 while parent:
708 name = parent.name + '->' + name
709 parent = parent.parent
710 return name
711
713 """
714 @return: the recursive depth of the current entity (0 is the depth of a root entity)
715 @rtype: C{int}"""
716 if self.parent:
717 return 1 + self.parent.beliefDepth()
718 else:
719 return 0
720
733
735 new = copy.copy(self)
736 new.dynamics = copy.deepcopy(self.dynamics,memo)
737 memo[id(self)] = new
738 new.beliefs['observations'] = self.beliefs['observations'][:]
739 new.entities = copy.deepcopy(self.entities,memo)
740 return new
741
763
843
845 return not (self == entity)
846
848 """Equality test between agents
849 @warning: only partially implemented
850 @param entity: the entity to be compared against
851 @type entity: L{RecursiveAgent}
852 @rtype: C{boolean}"""
853 if type(entity)== StringType:
854 return self.name == entity
855 if self.name != entity.name:
856 return False
857 if self.parent != entity.parent:
858 return False
859 if self.state != entity.state:
860 return False
861 return True
862
864 doc = Agent.__xml__(self)
865 root = doc.documentElement
866
867 node = doc.createElement('beliefs')
868 root.appendChild(node)
869 node.appendChild(self.entities.__xml__().documentElement)
870
871 node = doc.createElement('actions')
872 root.appendChild(node)
873 node.appendChild(self.actions.__xml__().documentElement)
874
875 node = doc.createElement('relationships')
876 root.appendChild(node)
877 for label,agents in self.relationships.items():
878 relationshipNode = doc.createElement('relationship')
879 node.appendChild(relationshipNode)
880 relationshipNode.setAttribute('label',label)
881 for name in agents:
882 subNode = doc.createElement('relatee')
883 subNode.appendChild(doc.createTextNode(name))
884 relationshipNode.appendChild(subNode)
885 if not self.parent:
886
887 node = doc.createElement('dynamics')
888 root.appendChild(node)
889 for feature,subDict in self.dynamics.items():
890 featureNode = doc.createElement('feature')
891 node.appendChild(featureNode)
892 featureNode.setAttribute('label',feature)
893 for actType,dynamic in subDict.items():
894 if isinstance(actType,str):
895
896 actNode = doc.createElement('action')
897 featureNode.appendChild(actNode)
898 actNode.setAttribute('type',actType)
899 if isinstance(dynamic,str):
900 dynamic = self.hierarchy[dynamic].dynamics[feature][actType]
901 actNode.appendChild(dynamic.__xml__().documentElement)
902 elif actType is None:
903
904 actNode = doc.createElement('action')
905 featureNode.appendChild(actNode)
906 if isinstance(dynamic,str):
907 dynamic = self.hierarchy[dynamic].dynamics[feature][actType]
908 actNode.appendChild(dynamic.__xml__().documentElement)
909
910 if self.policy:
911 if isinstance(self.policy,list):
912 node = doc.createElement('policy')
913 root.appendChild(node)
914 node.setAttribute('type','list')
915 node.setAttribute('value',str(self.policy))
916 else:
917 root.appendChild(self.policy.__xml__().documentElement)
918 return doc
919
920 - def parse(self,element):
921 """Extracts this agent's recursive belief structure from the given XML Element
922 @type element: Element
923 """
924 Agent.parse(self,element)
925 child = element.firstChild
926 while child:
927 if child.nodeType == Node.ELEMENT_NODE:
928 if child.tagName == 'beliefs':
929 node = child.firstChild
930 while node:
931 if node.nodeType == node.ELEMENT_NODE:
932 self.entities.parse(node,self.__class__)
933 node = node.nextSibling
934 for entity in self.entities.members():
935 entity.parent = self
936 elif child.tagName == 'state':
937 self.state = Distribution()
938 subNodes = child.getElementsByTagName('distribution')
939 if len(subNodes) == 1:
940 self.state.parse(subNodes[0],KeyedVector)
941 elif len(subNodes) > 1:
942 raise UserWarning,'Multiple distributions in state of %s' % (self.ancestry())
943 elif child.tagName == 'actions':
944 subNode = child.firstChild
945 while subNode and subNode.nodeType != Node.ELEMENT_NODE:
946 subNode = subNode.nextSibling
947 if subNode:
948 self.actions = parseSpace(subNode)
949 elif child.tagName == 'relationships':
950 node = child.firstChild
951 while node:
952 if node.nodeType == node.ELEMENT_NODE:
953 label = str(node.getAttribute('label'))
954 self.relationships[label] = []
955 subNode = node.firstChild
956 while subNode:
957 if subNode.nodeType == subNode.ELEMENT_NODE:
958 assert(subNode.tagName == 'relatee')
959 name = subNode.firstChild.data
960 name = str(name).strip()
961 self.relationships[label].append(name)
962 subNode = subNode.nextSibling
963 node = node.nextSibling
964 elif child.tagName == 'dynamics':
965 node = child.firstChild
966 while node:
967 if node.nodeType == node.ELEMENT_NODE:
968 assert(node.tagName=='feature')
969 feature = str(node.getAttribute('label'))
970 self.dynamics[feature] = {}
971 subNode = node.firstChild
972 while subNode:
973 if subNode.nodeType == subNode.ELEMENT_NODE:
974 assert(subNode.tagName=='action')
975 actionType = str(subNode.getAttribute('type'))
976 if not actionType:
977 actionType = None
978 assert(actionType not in self.dynamics[feature].keys())
979 dyn = str(subNode.getAttribute('link'))
980 if not dyn:
981 dyn = PWLDynamics()
982 subchild = subNode.firstChild
983 while subchild and subchild.nodeType != child.ELEMENT_NODE:
984 subchild = subchild.nextSibling
985 dyn.parse(subchild)
986 self.dynamics[feature][actionType] = dyn
987 subNode = subNode.nextSibling
988 node = node.nextSibling
989 elif child.tagName == 'policy':
990 self.policy = PolicyTable(self,self.actions)
991 self.policy.parse(child)
992 child = child.nextSibling
993
994 for action in self.actions.getOptions():
995 for subAct in action:
996 subAct['actor'] = self.name
997 if not self.policy:
998 self.policy = PolicyTable(self,self.actions,self.horizon)
999
1001 str = '<TABLE WIDTH="100%%" HEIGHT="100%%"><TR>'
1002 if positive:
1003 str += '<TD WIDTH="%d%%" BGCOLOR="#000000"></TD><TD></TD>' % (value*100.)
1004 else:
1005 if value > 0.:
1006 str += '<TD WIDTH="50%%"></TD>\n'
1007 str += '<TD WIDTH="%d%%" BGCOLOR="#000000"></TD><TD></TD>' % (value*50.)
1008 else:
1009 str += '<TD WIDTH="%d%%"></TD>\n' % ((value+1.)*50.)
1010 str += '<TD WIDTH="%d%%" BGCOLOR="#ff0000"></TD>' % (-value*50.)
1011 str += '<TD WIDTH="50%%"></TD>\n'
1012 str += '</TR></TABLE>'
1013 return str
1014
1015 if __name__ == '__main__':
1016 from unittest import TestResult
1017 import sys
1018 from teamwork.test.agent.testRecursiveAgent import TestRecursiveAgentIraq
1019 if len(sys.argv) > 1:
1020 method = sys.argv[1]
1021 else:
1022 method = 'testLocalState'
1023 case = TestRecursiveAgentIraq(method)
1024 result = TestResult()
1025 case(result)
1026 for failure in result.errors+result.failures:
1027 print failure[1]
1028