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
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
80 self.susceptibilities = []
81
82 try:
83 self.themes = self.getDefault('themes')
84 except KeyError:
85 self.themes = {}
86 self.description = ''
87
96
97
99 """Calls the superclass state estimator, but also handles messages"""
100 if beliefs is None:
101 beliefs = self.getAllBeliefs()
102
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
113 if len(msgs) == 0:
114
115 beliefs,new = GenericEntity.stateEstimator(self,beliefs,
116 actions,epoch,debug)
117 delta.update(new)
118 return beliefs,delta
119
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
147
148 try:
149 self.updateLinks(effect['relationships'])
150 except KeyError:
151 pass
152 self.entities.applyChanges(effect)
153 return beliefs,delta
154
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
163 acceptance = None
164 label = msg.pretty()
165
166 subExp = {}
167
168 explanation[label] = subExp
169
170 try:
171 entity = self.getEntity(sender)
172 except KeyError:
173
174 continue
175 acceptance,accExp = self.acceptMessage(entity,msg,debug)
176 subExp['decision'] = acceptance
177 subExp['breakdown'] = accExp
178 if acceptance:
179
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
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
209 try:
210 entity = entity.getEntity(self.name)
211 except KeyError:
212 entity = None
213 if entity:
214
215
216 entity.postComStateEstimator(entity,{sender:[msg]},
217 epoch,debug)
218 return explanation
219
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
229 value = {'forced':None,
230 'accept':{},
231 'reject':{},
232 }
233 valueAccept = 0.
234 valueReject = 0.
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
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
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
272 value['differential'] = valueAccept - valueReject
273
274
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
284
285
286
287
288
289
290
291
292
293
294
295 debug.message(1,'Overall evaluation of message = '+\
296 `valueAccept`)
297
298
299
300
301 return (float(valueAccept) > \
302 self.beliefWeights['threshold']),value
303
350
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
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
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
370 self.policy.extend(LookaheadPolicy(self,self.entities,depth))
371 elif self.policy.type == 'lookupahead':
372 self.policy.depth = depth
373
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
383 return 0
384 elif self.policy.type == 'lookupahead':
385 return self.policy.depth
386
387
388
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
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
405 """Remove any image info before pickling"""
406 new = copy.copy(self.__dict__)
407 new['image'] = None
408 return new
409
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
422
423 - def parse(self,element):
426