1 import copy
2 import operator
3 import os
4 import string
5 from threading import *
6 import time
7 from Tkinter import *
8 import tkMessageBox
9 import Pmw
10
13
14 from teamwork.widgets.images import getImage
15 from teamwork.widgets.WizardShell import WizardShell
16 from teamwork.widgets.cookbook import MultiListbox
17 from teamwork.utils.PsychUtils import load
18 from teamwork.messages.PsychMessage import *
19 from teamwork.math.probability import *
20 from teamwork.widgets.images import getImage
21
23 wizname = 'Message Analysis'
24 wizimage = 'analyzing_computer_tv_head_md_wht.gif'
25
26
27 frameWidth = 600
28 frameHeight = 500
29 phases = ['sender','receivers','overhearers','models','messages',
30 'progress','results']
31
32 - def __init__(self, entities, sender=None, receivers=[],
33 messages=[], parent=None, **kw):
69
80
81
83 senders = filter(lambda n:len(self.entities[n].entities) > 0 ,
84 self.entities.keys())
85 widget = self.createcomponent('senders', (), None,
86 Pmw.RadioSelect,
87 (self.pInterior(pane),),
88 labelpos='n',
89 label_text='Select sender:',
90 buttontype='radiobutton',
91 orient='vertical',
92 command=self.selectSender,
93 )
94 for name in senders:
95 widget.add(name)
96 if self.sender:
97 widget.invoke(self.sender)
98 widget.pack(fill='both',expand='yes')
99
101 """Precludes the selected sender from being a potential receiver"""
102 try:
103 widget = self.component('receivers')
104 if self.sender and self.sender != name:
105 widget.component(self.sender).configure(state='normal')
106 widget.component(name).configure(state='disabled')
107 widget = self.component('hearers')
108 if self.sender and self.sender != name:
109 widget.component(self.sender).configure(state='normal')
110 widget.component(name).configure(state='disabled')
111 self.sender = name
112 except KeyError:
113 pass
114
117
118
120 receivers = filter(lambda n:len(self.entities[n].entities) > 0,
121 self.entities.keys())
122 widget = self.createcomponent('receivers', (), None,
123 Pmw.RadioSelect,
124 (self.pInterior(pane),),
125 labelpos='n',
126 label_text='Select receiver(s):',
127 buttontype='checkbutton',
128 orient='vertical',
129 command=self.selectReceiver,
130 )
131 for name in receivers:
132 widget.add(name)
133 if name == self.getSender():
134 widget.component(name).configure(state='disabled')
135 widget.pack(fill='both',expand='yes')
136
138 """Updates the availability of the selected receiver as a possible sender/overhearer"""
139 if 'sender' in self.components():
140 widget = self.component('sender')
141 if value:
142 self.nextB['state'] = 'normal'
143 widget.component(name).configure(state='disabled')
144 else:
145 if len(self.getReceivers()) == 0:
146 self.nextB['state'] = 'disabled'
147 widget.component(name).configure(state='normal')
148 if 'hearers' in self.components():
149 widget = self.component('hearers')
150 if value:
151 widget.component(name).configure(state='disabled')
152 else:
153 widget.component(name).configure(state='normal')
154
156 if self.receivers:
157 return self.receivers
158 else:
159 return list(self.component('receivers').getvalue())
160
161
163 receivers = filter(lambda n:len(self.entities[n].entities) > 0,
164 self.entities.keys())
165 widget = self.createcomponent('hearers', (), None,
166 Pmw.RadioSelect,
167 (self.pInterior(pane),),
168 labelpos='n',
169 label_text='Select overhearer(s):',
170 buttontype='checkbutton',
171 orient='vertical',
172 command=self.selectHearer,
173 )
174 for name in receivers:
175 widget.add(name)
176 if name == self.getSender() or name in self.getReceivers():
177 widget.component(name).configure(state='disabled')
178 widget.pack(fill='both',expand='yes')
179
181 """Updates the availability of the selected overhearer as a possible sender/receiver"""
182 if 'sender' in self.components():
183
184 widget = self.component('sender')
185 if value:
186 self.nextB['state'] = 'normal'
187 widget.component(name).configure(state='disabled')
188 else:
189 if len(self.getHearers()) == 0:
190 self.nextB['state'] = 'disabled'
191 widget.component(name).configure(state='normal')
192 if 'receivers' in self.components():
193
194 widget = self.component('receivers')
195 if value:
196 widget.component(name).configure(state='disabled')
197 else:
198 widget.component(name).configure(state='normal')
199
201 return list(self.component('hearers').getvalue())
202
203
205 if len(self.messages) > 0:
206 widget = self.createcomponent('messages',(),None,Pmw.RadioSelect,
207 (self.pInterior(pane),),
208 labelpos='n',
209 label_text='Select message(s):',
210 buttontype='checkbutton',
211 orient='vertical',
212 )
213 for msg in self.messages.keys():
214 widget.add(msg)
215 widget.component(msg).invoke()
216 widget.pack(fill='both',expand='yes')
217 else:
218 self.createSelectModels(pane)
219
223
224
229
231 """Configures model selection pane based on current selections"""
232 book = self.component('modelbook')
233
234 for entity in self.entities.members():
235 if len(entity.models) == 0:
236 continue
237 try:
238 page = book.add(entity)
239 except ValueError:
240
241 continue
242 widget = Pmw.Group(page,tag_text='Select the model variations for this agent:')
243 try:
244 entry = self.models[entity]
245 except KeyError:
246 entry = self.models[entity] = {}
247
248 for label,model in self.entities[entity].models.items():
249 if not entry.has_key(label):
250
251 var = BooleanVar()
252 entry[label] = {'variable':var,
253 'model':model}
254
255 button = Checkbutton(widget.interior(),variable=var,
256 text=label,anchor=W,justify='left')
257 button.pack(fill=X,expand=YES)
258
259 var.set(1)
260 widget.pack(fill=BOTH)
261
263 """Returns a dictionary of available models for each entity"""
264 models = {}
265 for entity in self.entities.members():
266 if self.models.has_key(entity.name):
267 models[entity.name] = []
268 for label,entry in self.models[entity.name].items():
269 if entry['variable'].get():
270 models[entity.name].append(label)
271 elif len(entity.models) > 0:
272 models[entity.name] = []
273 return models
274
275
276
279
281 """Set up the table of variations and the progress through them"""
282 try:
283 self.destroycomponent('progress')
284 except KeyError:
285
286 pass
287
288 columns = map(lambda n:(n,8),self.models.keys())
289 columns.sort()
290 self.columns = map(lambda c:{'type':'model',
291 'name':c,
292 'values':self.models[c]},columns)
293 for msg in self.getMessages():
294 columns.append((msg,16))
295 self.columns.append({'type':'message',
296 'name':msg,
297 'values':[True,False]})
298 for hearer in self.getHearers():
299 label = '%s Hears' % (hearer)
300 columns.append((label,12))
301 self.columns.append({'type':'hearer',
302 'name':'%s hears' % (hearer),
303 'values':[True,False]})
304 columns.append(('Status',6))
305
306 widget = self.createcomponent('progress',(),None,MultiListbox,
307 (self.pInterior(pane),columns))
308 widget.pack(fill='both',expand='yes')
309 count = reduce(operator.mul,map(lambda c:len(c['values']) ,
310 self.columns))
311 for index in xrange(count):
312 variation = self.getVariation(index)
313 item = ['Pending']
314 for column in self.columns:
315 entry = variation[column['name']]
316 if isinstance(entry,bool):
317 if entry:
318 entry = 'Yes'
319 else:
320 entry = 'No'
321 item.insert(0,entry)
322 self.root.after(10,lambda w=widget,i=item:w.insert(END,i))
323
325 variation = {}
326 for column in self.columns:
327 subIndex = index % len(column['values'])
328 variation[column['name']] = column['values'][subIndex]
329 index /= len(column['values'])
330 return variation
331
332
333
335 self.createcomponent('Overall',(),None,Label,
336 (self.pInterior(pane),),
337 text='Overall Analysis').pack(fill=X,expand=YES)
338 self.result = self.createcomponent('Results',(),None,
339 Pmw.ScrolledText,
340 (self.pInterior(pane),),
341 usehullsize=1,
342 hull_height=280)
343 self.result.pack(fill=BOTH,expand=YES)
344
346 """Handle context-sensitive transitions from pane to pane"""
347 WizardShell.next(self)
348 last = self.sequence[self.pCurrent-1]
349 phase = self.sequence[self.pCurrent]
350 if phase == 'actions':
351 self.setupActions()
352 elif phase == 'models':
353 self.setupModels()
354 elif phase == 'progress':
355 self.setupProgress(self.pCurrent)
356 self.results = []
357 thread = Thread(target=self.analyze)
358 thread.start()
359 elif phase == 'receiver':
360 pass
361 elif phase == 'messages':
362 pass
363
364
365
366
367
368
369
370
371
372
373
374
375 elif phase == 'results':
376 self.results.sort(lambda x,y:
377 cmp(x['count'],y['count']))
378 content = ''
379 for result in self.results:
380 variation = self.getVariation(result['variation'])
381 hearers = []
382 for name in self.entities.keys():
383 try:
384 model = variation[name]
385 content += '%s: %s\n' % (name,model)
386 except KeyError:
387 pass
388 try:
389 if variation['%s hears' % (name)]:
390 hearers.append(name)
391 except KeyError:
392 pass
393 msgList = []
394 for msg in self.getMessages():
395 if variation[msg]:
396 msgList.append(msg)
397 if len(msgList) > 0:
398 content += 'Messages: \n\t%s\n' % ('\n\t'.join(msgList))
399 if len(hearers) > 0:
400 content += 'Overheard by: '
401 content += ', '.join(hearers)
402 content += '\n'
403 else:
404 content += 'No message\n'
405 content += '\tViolations: %d\n\n' % (result['count'])
406 self.result.settext(content)
407
409 if value < 0.0:
410 return 'Fail'
411 elif value < 0.2:
412 return 'Neutral'
413 else:
414 return 'Succeed'
415
427
429 """Changes status entry of the indexed row to be the given string"""
430 self.root.after(100,lambda s=self,i=index,st=status:
431 s._changeStatus(i,st))
432
434 item = self.component('progress').get(index)
435 item[-1] = status
436 self.component('progress').delete(index)
437 self.component('progress').insert(index,item)
438
440 """Simulates the result of the current configuration"""
441 self.changeStatus(index,'Projecting')
442 if len(self.models) > 0:
443 sim = copy.deepcopy(self.entities)
444 else:
445 sim = self.entities
446 messages = []
447 hearers = []
448 for column in self.columns:
449 key = column['name']
450 if column['type'] == 'model':
451 sim[key].setModel(variation[key])
452 elif column['type'] == 'message':
453 if variation[key]:
454 messages.append(self.messages[key])
455 elif column['type'] == 'hearer':
456 if variation[key]:
457 hearers.append(key[:-6])
458 self.processMsg(messages,hearers,index,sim)
459 self.changeStatus(index,'Done')
460
461 - def processMsg(self,messages,hearers,index,sim=None):
462 if sim == None:
463 self.changeStatus(index,'Projecting')
464 sim = copy.deepcopy(self.entities)
465 self.changeStatus(index,'Sending')
466 factors = []
467 for msg in messages:
468 factors.append({'topic':'state',
469 'lhs':['entities',msg['subject'],'state',
470 msg['type']],
471 'value':msg['value'],
472 'relation':'='})
473 message = Message({'factors':factors})
474 receivers = self.getReceivers() + hearers
475 violations = {'variation':index,'count':0,'total':0}
476 for name in receivers:
477
478 receiver = self.entities[name]
479 beliefs = receiver.getAllBeliefs()
480 if len(factors) > 0:
481 delta,explanation = receiver.incorporateMessage(message)
482 receiver.entities.applyChanges(delta,beliefs=beliefs)
483
484 self.changeStatus(index,'Evaluating')
485 actions = receiver.actions.getOptions()
486 decision,explanation = receiver.applyPolicy(beliefs,actions)
487 violations[name] = decision
488
489 for action in decision:
490 violations['total'] += len(self.entities.objectives)
491 result = self.entities.detectViolations(action)
492 for objective in result:
493 violations['count'] += 1
494 try:
495 violations[str(objective)] += 1
496 except KeyError:
497 violations[str(objective)] = 1
498 self.results.append(violations)
499
501 self.quit()
502 self.root.destroy()
503
504 if __name__ == '__main__':
505 test = AnalysisWizard()
506 test.run()
507