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

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

  1  from Tkinter import * 
  2  import tkMessageBox 
  3  import Pmw 
  4  from teamwork.widgets.cookbook import MultiListbox 
  5  from teamwork.widgets.images import getImage 
  6  from teamwork.widgets.attribute import AttributeDialog 
  7  from teamwork.widgets.PsychGUI.TurnDialog import TurnDialog 
  8  from teamwork.math.KeyedVector import KeyedVector 
  9  from teamwork.agent.lightweight import PWLAgent 
 10  import random 
 11  random.seed() 
 12  import string 
 13   
14 -class PolicyFrame(Pmw.ScrolledFrame):
15
16 - def __init__(self,parent,entity,**kw):
17 optiondefs = ( 18 ('balloon',None,Pmw.INITOPT), 19 ('command',None,None), 20 ('generic',False,None), 21 ('society',{},None), 22 ('expert', False,self.setExpert), 23 ('actions',None,None), 24 ) 25 self.defineoptions(kw, optiondefs) 26 self.entity = entity 27 self.selected = None 28 self.lists = {} 29 Pmw.ScrolledFrame.__init__(self,parent) 30 if self.entity.policy: 31 g = Pmw.Group(self.interior(),tag_text='Edit Rule Conditions') 32 # Button for policy iteration 33 button = Button(g.interior(),text='Auto-generate Conditions', 34 width=32) 35 button.grid(row=0,column=0,padx=5,pady=5,sticky='ew') 36 button.configure(command=self.generateLHS) 37 if isinstance(self.entity,PWLAgent): 38 button.configure(state='disabled') 39 if self['balloon']: 40 msg = 'Automatically generate the possible situations for '\ 41 'this agent to consider.' 42 self['balloon'].bind(button,msg) 43 # Button for adding a LHS attributes 44 button = Button(g.interior(),text='Add Condition...',width=32) 45 button.grid(row=1,column=0,padx=5,pady=5,sticky='ew') 46 button.configure(command=self.newAttribute) 47 if self['balloon']: 48 msg = 'Add an additional condition to the left-hand side '\ 49 'of the rules.' 50 self['balloon'].bind(button,msg) 51 # Button for removing a LHS attributes 52 button = self.createcomponent('delete',(),None,Button, 53 (g.interior(),), 54 text='Delete Condition',width=32, 55 state='disabled') 56 button.grid(row=2,column=0,padx=5,pady=5,sticky='ew') 57 button.configure(command=self.delAttribute) 58 if self['balloon']: 59 msg = 'Removes the selected condition from the left-hand '\ 60 'side of the rules.' 61 self['balloon'].bind(button,msg) 62 g.grid(row=0,column=0,sticky='nsew') 63 g = Pmw.Group(self.interior(),tag_text='Edit Rule Actions') 64 # Counter for horizon 65 self.horizon = self.createcomponent('Horizon', 66 (),None,Pmw.Counter, 67 (g.interior(),), 68 labelpos='w', 69 label_text='Horizon:',) 70 button = self.horizon.component('entryfield') 71 button.configure(modifiedcommand=self.getHorizon, 72 validate={'validator':'integer','min':1}, 73 ) 74 button.setentry(self.entity.policy.horizon) 75 self.horizon.grid(row=0,column=0,padx=5,pady=5,sticky='ew') 76 if self['balloon']: 77 msg = 'The number of turns into the future this agent '\ 78 'considers when choosing an action.' 79 self['balloon'].bind(self.horizon,msg) 80 # Button for policy iteration 81 button = Button(g.interior(),text='Optimize Actions',width=32) 82 button.grid(row=1,column=0,padx=5,pady=5,sticky='ew') 83 button.configure(command=self.policyIteration) 84 if self['balloon']: 85 msg = 'Generate a human-readable specification of this '\ 86 'agent\'s behavior, over all possible situations.' 87 self['balloon'].bind(button,msg) 88 # Button for seeding 89 button = Button(g.interior(),text='Randomize Actions',width=32) 90 button.grid(row=2,column=0,padx=5,pady=5,sticky='ew') 91 button.configure(command=self.seed) 92 if self['balloon']: 93 msg = 'Seed the rules with a random initial set of actions.' 94 self['balloon'].bind(button,msg) 95 # Button for viewing current rule 96 button = Button(g.interior(),text='View Current Action',width=32) 97 button.grid(row=3,column=0,padx=5,pady=5,sticky='ew') 98 button.configure(command=self.open) 99 if self['balloon']: 100 msg = 'Opens a dialog box for viewing or editing the action ranking that will be applied in the current state.' 101 self['balloon'].bind(button,msg) 102 g.grid(row=0,column=1,sticky='nsew') 103 # Box for displaying policy 104 widget = self.createcomponent('Policy',(),None,MultiListbox, 105 (self.interior(), 106 [('Action',32)]), 107 rowselectcommand=self.clickRow, 108 colselectcommand=self.clickCol, 109 doublecommand=self.double, 110 ) 111 widget.grid(row=1,column=0,columnspan=2,sticky='snew') 112 self.interior().columnconfigure(0,weight=1) 113 self.interior().columnconfigure(1,weight=1) 114 self.interior().rowconfigure(1,weight=1) 115 self.createcomponent('new attribute',(),None,AttributeDialog, 116 (self.interior(),self.entity), 117 title='New Policy Attribute', 118 command=self.addAttribute, 119 buttons=('OK','Cancel'), 120 ).withdraw() 121 self.createcomponent('order',(),None,TurnDialog, 122 (self.interior(),), 123 serial=True,editor_editable=True, 124 title='Policy of %s' % (self.entity.ancestry()), 125 command=self.setOrder).withdraw() 126 self.initialiseoptions() 127 if len(self.entity.policy.attributes) > 0: 128 self.displayPolicy()
129
130 - def setExpert(self):
131 pass
132
133 - def getOptions(self):
134 if self['actions']: 135 options = self['actions'].getActions() 136 else: 137 options = self.entity.actions.getOptions() 138 if len(options) == 0: 139 tkMessageBox.showerror('Agent Action Error','The agent has no allowable actions! Please go to the Action pane and select at least one possible choice.') 140 return options
141
142 - def generateLHS(self):
143 options = self.getOptions() 144 if options: 145 policy = self.entity.policy 146 policy.reset() 147 policy.initialize() 148 for index in range(len(policy.attributes)): 149 obj,values = policy.attributes[index] 150 self.addList(index,obj) 151 self.displayPolicy() 152 self.propAttributes()
153
154 - def policyIteration(self):
155 if len(self.entity.policy.attributes) == 0: 156 tkMessageBox.showerror('Empty Policy','Please add some conditions (either manually or automatically) first!') 157 elif self['command']: 158 self['command'](self.entity)
159
160 - def displayPolicy(self,policy=None):
161 self.component('Policy').delete(0,'end') 162 if policy is None: 163 policy = self.entity.policy 164 attributes = policy.attributes[:] 165 for index in range(len(attributes)): 166 obj,values = attributes[index] 167 if not self.lists.has_key(obj.simpleText()): 168 self.addList(index,obj) 169 attributes.reverse() 170 for index,rhs in policy.rules.items(): 171 entry = [] 172 for obj,values in attributes: 173 if isinstance(obj,KeyedVector): 174 subIndex = index % (len(values)+1) 175 if subIndex < len(values): 176 entry.append('< %5.3f' % (values[subIndex])) 177 else: 178 entry.append('>=%5.3f' % (values[subIndex-1])) 179 index /= (len(values)+1) 180 else: 181 subIndex = index % (len(values)) 182 entry.append(str(values[subIndex])) 183 index /= len(values) 184 # Add the RHS 185 if rhs is None: 186 label = '???' 187 else: 188 rhs = rhs[0] 189 if isinstance(rhs,list): 190 rhs = rhs[0] 191 label = rhs['type'] 192 if rhs['object']: 193 label += ' %s' % (rhs['object']) 194 entry.append(label) 195 entry.reverse() 196 # Add entry to listboxes 197 self.component('Policy').insert('end',tuple(entry))
198
199 - def getHorizon(self):
200 widget = self.component('Horizon') 201 horizon = int(widget.get()) 202 self.entity.horizon = horizon 203 self.entity.policy.horizon = horizon
204
205 - def newAttribute(self):
206 """Activates dialog for adding a new attribute 207 """ 208 self.component('new attribute').activate()
209
210 - def addAttribute(self,button):
211 """Callback for finishing with new attribute dialog 212 """ 213 if button == 'OK': 214 plane = self.component('new attribute')['plane'] 215 keyList = self.entity.state.domain()[0].keys() 216 keyList.sort() 217 plane.weights.fill(keyList) 218 for obj,values in self.entity.policy.attributes: 219 if obj == plane.weights: 220 break 221 else: 222 obj = plane.weights 223 values = [plane.threshold] 224 self.entity.policy.attributes.append((obj,values)) 225 self.addList(len(self.entity.policy.attributes)-1,obj) 226 if not plane.threshold in values: 227 values.append(plane.threshold) 228 values.sort() 229 self.propAttributes() 230 self.component('new attribute').deactivate() 231 self.displayPolicy()
232
233 - def delAttribute(self):
234 """Removes the selected attribute from the LHS 235 """ 236 assert self.selected is not None 237 policy = self.entity.policy 238 for index in range(len(policy.attributes)): 239 obj,values = policy.attributes[index] 240 if obj.simpleText() == self.selected: 241 break 242 else: 243 raise UserWarning,'Trying to delete unknown attribute: %s' % \ 244 (self.selected) 245 del policy.attributes[index] 246 self.component('Policy').delList(self.selected) 247 self.component('delete').configure(state='disabled') 248 self.selected = None 249 self.displayPolicy() 250 self.propAttributes()
251
252 - def addList(self,index,attr):
253 widget = self.component('Policy') 254 msg = attr.simpleText() 255 widget.addList(msg,16) 256 self.lists[msg] = index 257 if self['balloon']: 258 self['balloon'].bind(widget.component('label %s' % (msg)),msg)
259
260 - def propAttributes(self):
261 """Sets all of the agents in this entity's beliefs to use the current LHS attributes 262 """ 263 entities = self.entity.entities.activeMembers() 264 root = self.entity 265 while root.parent: 266 root = root.parent 267 while len(entities) > 0: 268 entity = entities.pop() 269 entities += entity.entities.activeMembers() 270 entity.policy.attributes = [] 271 for obj,values in self.entity.policy.attributes: 272 entity.policy.attributes.append((obj,values[:])) 273 entity.policy.rules = [] 274 entity.policy.initialize() 275 label = '%s Policy' % (entity.ancestry()) 276 try: 277 widget = root.attributes['window'].component(label) 278 except KeyError: 279 widget = None 280 if widget: 281 widget.displayPolicy()
282
283 - def clickRow(self,row):
284 self.component('delete').configure(state='disabled') 285 self.selected = None
286
287 - def clickCol(self,col):
288 self.component('delete').configure(state='normal') 289 self.selected = col
290
291 - def double(self,row,event=None):
292 root = self.entity 293 while root.parent: 294 root = root.parent 295 window = root.attributes['window'] 296 if self.entity.parent: 297 options = window.component('%s Actions' % (self.entity.ancestry())).getActions()[:] 298 else: 299 options = window.component('Actions').getActions()[:] 300 rules = self.entity.policy.rules 301 if rules[row] is None: 302 rhs = options 303 else: 304 rhs = rules[row][:] 305 try: 306 try: 307 values = self.entity.policy.values[row] 308 except KeyError: 309 values = {} 310 for index in range(len(rhs)): 311 option = rhs[index] 312 try: 313 value = values[self.entity.name][str(option)] 314 except KeyError: 315 value = None 316 rhs[index] = str(option) 317 if not value is None: 318 rhs[index] += ' (%5.3f)' % (str(value)) 319 try: 320 options[options.index(option)] = rhs[index] 321 except ValueError: 322 print self.entity.ancestry(),option 323 raise ValueError 324 except IndexError: 325 pass 326 dialog = self.component('order') 327 dialog.configure(elements=options,order=rhs) 328 dialog.activate()
329
330 - def open(self):
331 if isinstance(self.entity,PWLAgent): 332 state = self.beliefs 333 else: 334 state = self.entity.entities.getState() 335 row = self.entity.policy.index(state.expectation(),{}) 336 self.component('Policy').selection_set(row) 337 self.double(row)
338
339 - def setOrder(self,button):
340 dialog = self.component('order') 341 if button == 'OK': 342 for row in self.component('Policy').curselection(): 343 order = dialog.cget('order') 344 if isinstance(order[0],str): 345 # Probably shouldn't happen, but sometimes the RHS are str 346 for index in range(len(order)): 347 for option in self.entity.actions.getOptions(): 348 if str(option) == order[index]: 349 break 350 else: 351 raise NameError,'Unknown action: %s' % (order[index]) 352 order[index] = option 353 if int(row) < len(self.entity.policy.values): 354 order = map(lambda l:l[:l.rfind('(')-1],order) 355 rhs = self.entity.policy.rules[int(row)] 356 for option in rhs: 357 rhs[order.index(str(option))] = option 358 else: 359 self.entity.policy.rules[int(row)] = order[:] 360 self.displayPolicy() 361 self.component('Policy').selection_set(row) 362 dialog.deactivate()
363
364 - def seed(self):
365 """Randomly rearranges the right-hand sides of all of the rules 366 """ 367 choices = self.getOptions() 368 for index in xrange(len(self.entity.policy.rules)): 369 rhs = self.entity.policy.rules[index] 370 if rhs is None: 371 self.entity.policy.rules[index] = choices[:] 372 rhs = self.entity.policy.rules[index] 373 if len(rhs) > 1: 374 options = rhs[:] 375 for index in range(len(rhs)): 376 option = random.choice(options) 377 rhs[index] = option 378 options.remove(option) 379 self.displayPolicy()
380
381 - def unpost(self,event):
382 event.widget.unpost()
383