1 import string
2 from Tkinter import *
3 import Pmw
4 from teamwork.agent.stereotypes import Stereotyper
5 from teamwork.messages.PsychMessage import Message as PsychMessage
6 from teamwork.math.Keys import StateKey,keyConstant
7 from teamwork.math.KeyedVector import SetToConstantRow,UnchangedRow
8 from teamwork.math.KeyedMatrix import KeyedMatrix
9 from teamwork.math.probability import *
10 from teamwork.widgets.pmfScale import PMFScale
11
13 resolution = 0.01
14
16 optiondefs = (
17 ('send', lambda a,b,c,d,e,f:None, None),
18 ('generic',False,Pmw.INITOPT),
19 ('society',{},None),
20 ('expert', 0, self.setExpert),
21 ('balloon',None,Pmw.INITOPT),
22 )
23 self.defineoptions(kw, optiondefs)
24 self.entity = entity
25 self.message = {}
26 Pmw.ScrolledFrame.__init__(self,parent)
27
28 widget = self.createcomponent('sender',(),None,Pmw.OptionMenu,
29 (self.interior(),),
30 items=entity.getEntities(),
31 labelpos='nw',
32 label_text='Sender:')
33 widget.pack(side=TOP,fill=X)
34
35 widget = self.createcomponent('subject',(),None,Pmw.OptionMenu,
36 (self.interior(),),
37 items=entity.getEntities(),
38 labelpos='nw',
39 command=self.selectSubject,
40 label_text='Subject:')
41 widget.pack(side=TOP,fill=X)
42
43 widget = self.createcomponent('type',(),None,Pmw.OptionMenu,
44 (self.interior(),),
45 labelpos='nw',
46 command=self.selectType,
47 label_text='Message Type:')
48 widget.pack(side=TOP,fill=X)
49
50 widget = self.createcomponent('value',(),None,PMFScale,
51 (self.interior(),),
52 hull_bd=2,hull_relief='groove',
53 hull_padx=5,hull_pady=5,
54 distribution=Distribution({0.:1.}),
55 )
56
57 widget.pack(side=TOP,fill=X)
58
59 frame = Frame(self.interior())
60 for other in entity.getEntityBeliefs():
61 subframe = Frame(frame,relief='sunken',borderwidth=2)
62 name = other.ancestry().replace('_','')
63
64 widget = Label(subframe,text=other.name)
65 widget.pack(side=LEFT,fill=X,expand=1)
66 name = other.name.replace('_','')
67
68 widget = self.createcomponent('%s Receiver' % (name),
69 (),'receiver',Pmw.OptionMenu,
70 (subframe,),
71 menubutton_width=12,
72 items=('Hears nothing',
73 'Receives',
74 'Overhears'))
75 widget.configure(command=lambda val,s=self,n=name:\
76 s.receiver(n,val))
77 widget.pack(side=LEFT)
78 rcvFlag = widget.getvalue()
79
80 widget = self.createcomponent('%s Force' % (name),
81 (),'force',Pmw.OptionMenu,
82 (subframe,),
83 menubutton_width=12,
84 items=('Unforced',
85 'Must accept',
86 'Must reject'),
87 menubutton_state=DISABLED)
88 widget.pack(side=LEFT)
89 self.message[other.name] = {'receives':rcvFlag,
90 'force':widget.getvalue()
91 }
92 subframe.pack(side=TOP,fill=X)
93 frame.pack(side=TOP,fill=BOTH)
94
95 box = self.createcomponent('actions',(),None,Pmw.ButtonBox,
96 (self.interior(),),orient='horizontal')
97
98 widget = box.add('Send',command=self.send)
99 widget = box.add('Add',command=self.add)
100 widget = box.add('Query',command=self.query)
101 widget = box.add('Evaluate',command=self.evaluate)
102 if self['balloon']:
103 self['balloon'].bind(box.component('Send'),'Simulate the communication of the current message from the specified sender to all of the hearers and overhearers')
104 self['balloon'].bind(box.component('Add'),'Add the current message to the options for the agent to consider along with its current set of possible actions.')
105 self['balloon'].bind(box.component('Query'),'Ask the sending agent to determine whether it perceives the message as being beneficial to send.')
106 self['balloon'].bind(box.component('Evaluate'),'Simulate whether the message is really beneficial to the sender, using the ground truth model.')
107 box.pack()
108 if len(entity.getEntities()) > 0:
109 widget = self.component('sender')
110 if entity.name in widget.cget('items'):
111 widget.invoke(entity.name)
112 widget = self.component('subject')
113 widget.invoke(entity.getEntities()[0])
114 self.initialiseoptions()
115
117 """Sets the expert mode on the value scale"""
118 nameList = ['Add','Query','Evaluate']
119 for index in range(len(nameList)):
120 widget = self.component('actions_%s' % (nameList[index]))
121 if self['expert']:
122 widget.grid(column=index+2,row=0)
123 widget.configure(state='disabled')
124 else:
125 widget.grid_forget()
126
128 """Callback for subject OptionMenu"""
129 entity = self.entity.getEntity(name)
130 self.subjects = {}
131 self.contents = []
132
133 itemList = entity.getStateFeatures()
134 itemList.sort()
135 for feature in itemList:
136 label = 'has a %s value of ' % (feature)
137 self.subjects[label] = len(self.contents)
138 self.contents.append({'lhs':['entities','_subject',
139 'state',feature],
140 'topic':'state'})
141
142
143
144
145
146
147
148
149
150 if isinstance(entity,Stereotyper):
151 itemList = entity.models.keys()
152 itemList.sort()
153 for model in itemList:
154 label = 'is %s' % (model)
155 self.subjects[label] = len(self.contents)
156 self.contents.append({'topic':'model',
157 'entity':[name],
158 'value':model})
159 widget = self.component('type')
160 itemList = self.subjects.keys()
161 itemList.sort()
162 widget.setitems(itemList)
163 if len(self.subjects) > 0:
164 widget.invoke()
165 self.message['_subject'] = name
166
168 """Callback for statement type OptionMenu"""
169
170 widget = self.component('subject')
171 entity = self.entity.getEntity(widget.getvalue())
172 widget = self.component('value')
173 content = self.contents[self.subjects[name]]
174 if content['topic'] == 'state':
175 widget.configure(state='normal')
176 feature = name[6:-10]
177 widget.configure(distribution=entity.getState(feature))
178
179
180 elif content['topic'] in ['observation','model']:
181 widget.configure(state='disabled')
182
183
184 else:
185 raise NotImplementedError,'No callback for message of type %s' % \
186 content['topic']
187 widget.setDistribution()
188 self.message['_type'] = name
189
191 """Callback for selecting a receiver/overhearer"""
192 widget = self.component('%s Force' % (name))
193 if value == 'Hears nothing':
194 widget.configure(menubutton_state=DISABLED)
195 else:
196 widget.configure(menubutton_state=NORMAL)
197
199 """Constructs the Message object from the current widget state"""
200 widget = self.component('sender')
201 self.message['_sender'] = widget.getvalue()
202 widget = self.component('value')
203 self.message['_value'] = widget['distribution']
204 receivers = []
205 overhears = []
206 for other in self.entity.getEntityBeliefs():
207 widget = self.component('%s Receiver' % (other.name))
208 value = widget.getvalue()
209 self.message[other.name]['receives'] = value
210 if value == 'Receives':
211 receivers.append(other.name)
212 elif value == 'Overhears':
213 overhears.append(other.name)
214 widget = self.component('%s Force' % (other.name))
215 value = widget.getvalue()
216 self.message[other.name]['force'] = value
217
218 factor = self.contents[self.subjects[self.message['_type']]]
219 if factor['topic'] == 'state':
220 factor['lhs'] = map(lambda s:s.replace('_subject',
221 self.message['_subject']),
222 factor['lhs'])
223 factor['value'] = self.message['_value']
224 factor['relation'] = '='
225
226 keyList = self.entity.entities.state.expectation().keys()
227 distribution = self.component('value')['distribution']
228 factor['matrix'] = Distribution()
229 for element,prob in distribution.items():
230 matrix = KeyedMatrix()
231 for key in keyList:
232 matrix[key] = UnchangedRow(sourceKey=key)
233 key = StateKey({'entity': self.message['_subject'],
234 'feature': factor['lhs'][-1]})
235 matrix[key] = SetToConstantRow(sourceKey=key,
236 value=element)
237 matrix.fill(keyList)
238 factor['matrix'][matrix] = prob
239 elif factor['topic'] == ['observation']:
240
241 pass
242 msg = PsychMessage({'factors':[factor]})
243 for name in receivers+overhears:
244 if self.message[name]['force'] == 'Must accept':
245 msg.forceAccept(name)
246 elif self.message[name]['force'] == 'Must reject':
247 msg.forceReject(name)
248 self.message['content'] = msg
249 self.message['receivers'] = receivers
250 self.message['overhearers'] = overhears
251 return self.message
252
258
264
266 """Adds the specified message to the decision space of the entity"""
267 msg = self.extractMsg()
268 self.entity.actions.directAdd([msg])
269
275
277 """Sets up the menus to send the specified message"""
278 self.component('sender').invoke(msg['sender'])
279 self.component('subject').invoke(msg['subject'])
280
281 for index in range(len(self.contents)):
282 content = self.contents[index]
283 if content['topic'] == 'state' and len(content['lhs']) == 4 \
284 and content['lhs'][1] == '_subject' \
285 and content['lhs'][3] == msg['type']:
286 self.component('type').invoke(index)
287 break
288 else:
289
290 print 'Unable to find message type:',msg['type']
291 self.component('value').updateNew(msg['value'])
292 self.component('value').update()
293
294 for name in self.components():
295 if self.componentgroup(name) == 'receiver':
296 if name[:-9] == msg['receiver']:
297 self.component(name).invoke('Receives')
298 else:
299 self.component(name).invoke('Hears nothing')
300