Package teamwork :: Package widgets :: Package PsychGUI :: Package AgentWindow :: Module MessagePane
[hide private]
[frames] | no frames]

Source Code for Module teamwork.widgets.PsychGUI.AgentWindow.MessagePane

  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   
12 -class MessageFrame(Pmw.ScrolledFrame):
13 resolution = 0.01 14
15 - def __init__(self,parent,entity,**kw):
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 # Select the apparent sender of the message 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 # Select the subject of the message 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 # Select the statement type about that subject 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 # Select the value to state 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 ## widget.scale.configure(command=widget._doCommand) 57 widget.pack(side=TOP,fill=X) 58 # Select the receiver of the message 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 # Create label for this agent 64 widget = Label(subframe,text=other.name) 65 widget.pack(side=LEFT,fill=X,expand=1) 66 name = other.name.replace('_','') 67 # Create receive/overhear/none flag for this agent 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 # Create force flag for this agent 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 # Button box 95 box = self.createcomponent('actions',(),None,Pmw.ButtonBox, 96 (self.interior(),),orient='horizontal') 97 # Send button 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
116 - def setExpert(self):
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
127 - def selectSubject(self,name):
128 """Callback for subject OptionMenu""" 129 entity = self.entity.getEntity(name) 130 self.subjects = {} 131 self.contents = [] 132 # Messages about states 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 # Messages about observations 142 ## for action in entity.actions.getOptions(): 143 ## cmd = lambda act:'%s %s' % (act['type'],act['object']) 144 ## label = 'did %s' % (string.join(map(cmd,action),' and ')) 145 ## self.subjects[label] = len(self.contents) 146 ## self.contents.append({'action':action, 147 ## 'actor':name, 148 ## 'topic':'observation'}) 149 # Messages about mental models 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
167 - def selectType(self,name):
168 """Callback for statement type OptionMenu""" 169 # Identify the subject of the message 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 ## widget.configure(scale_from=-1) 179 ## widget.configure(color=1) 180 elif content['topic'] in ['observation','model']: 181 widget.configure(state='disabled') 182 ## widget.configure(scale_from=0) 183 ## widget.configure(color=0) 184 else: 185 raise NotImplementedError,'No callback for message of type %s' % \ 186 content['topic'] 187 widget.setDistribution() 188 self.message['_type'] = name
189
190 - def receiver(self,name,value):
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
198 - def extractMsg(self):
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 # Specialize the content to the selected field values 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 # Create a linear representation of this belief change 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 # Nothing to do here? 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
253 - def send(self):
254 self.extractMsg() 255 self['send'](self.message['_sender'],self.message['receivers'], 256 self.message['_subject'],self.message['content'], 257 'none',self.message['overhearers'])
258
259 - def evaluate(self):
260 msg = self.extractMsg() 261 self['send'](self.message['_sender'],self.message['receivers'], 262 self.message['_subject'],self.message['content'], 263 'none',self.message['overhearers'],'objective')
264
265 - def add(self):
266 """Adds the specified message to the decision space of the entity""" 267 msg = self.extractMsg() 268 self.entity.actions.directAdd([msg])
269
270 - def query(self):
271 msg = self.extractMsg() 272 self['send'](self.message['_sender'],self.message['receivers'], 273 self.message['_subject'],self.message['content'], 274 'none',self.message['overhearers'],'subjective')
275
276 - def seedMessage(self,msg):
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 # Set the state features selector 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 # Shouldn't happen 290 print 'Unable to find message type:',msg['type'] 291 self.component('value').updateNew(msg['value']) 292 self.component('value').update() 293 # Update receivers/overhearers 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