1 from Tkinter import *
2 import tkMessageBox
3 import Pmw
4
5 from teamwork.math.KeyedVector import *
6 from teamwork.math.KeyedMatrix import *
7 from teamwork.math.KeyedTree import KeyedPlane
8 from teamwork.math.probability import Distribution
9
11 """
12 Widget for editing dynamics trees
13 @cvar probBranch: label for probabilistic branch in type selector
14 @type probBranch: str
15
16 """
17 probBranch = 'Probabilistic'
18
20 optiondefs = (
21 ('states', {}, None),
22 ('roles', {}, None),
23 ('classes', {}, None),
24 ('relations', {}, None),
25 ('actions', {}, None),
26 ('selectorCount',3,None),
27
28 ('key', None, None),
29 ('feature', None, None),
30
31 ('interval', 0.1, Pmw.INITOPT),
32
33 ('leaves', dynamicsTypes.keys(), None),
34 )
35 self.defineoptions(kw, optiondefs)
36 Pmw.MegaWidget.__init__(self,parent)
37 self['leaves'].sort()
38
39
40 palette = Pmw.Color.getdefaultpalette(parent)
41 widget = self.createcomponent('type',(),None,Pmw.ComboBox,
42 (self.component('hull'),),
43 entry_state='disabled',
44 entry_disabledforeground=palette['foreground'],
45 entry_disabledbackground=palette['background'],
46 history=False)
47 widget.pack(side='top',fill='x')
48
49 for index in range(self['selectorCount']):
50 widget = self.createcomponent('feature%d' % (index),
51 (),'feature',Pmw.ComboBox,
52 (self.component('hull'),),
53 entry_state='disabled',
54 entry_disabledforeground=palette['foreground'],
55 entry_disabledbackground=palette['background'],
56 history=False)
57 widget.pack_forget()
58 self.initialiseoptions()
59
61 """
62 @return: the dynamics matrix currently selected
63 """
64 widget = self.component('type')
65 try:
66 cls = dynamicsTypes[widget.get()]
67 except KeyError:
68
69 return widget.get()
70 widget = self.component('feature0')
71 if cls.rowClass.keyClass is StateKey:
72 key = self['states'][widget.get()]
73 elif cls.rowClass.keyClass is ConstantKey:
74 key = keyConstant
75 elif cls.rowClass.keyClass is ActionKey:
76 for key in self['actions'].keys():
77 if str(key) == widget.get():
78 break
79 else:
80 raise NameError,'Unknown action condition: %s' % (widget.get())
81 else:
82 raise NotImplementedError,'Unable to create %s leaves' % \
83 (cls.__name__)
84 value = float(self.component('feature1').get())
85 if self['key']:
86
87 return cls(source=self['key'],key=key,value=value)
88 else:
89 return cls(source=self['feature'],key=key,value=value)
90
92 """
93 @return: the plane currently selected
94 """
95 name = self.component('type').get()
96 if name == self.probBranch:
97
98 widget = self.component('feature%d' % (self['selectorCount']-1))
99 threshold = float(widget.get())
100 return Distribution({'then':threshold,'else':1.-threshold})
101 else:
102
103 widget = self.component('type')
104 cls = slopeTypes[widget.get()]
105 newArgs = []
106 for index in range(len(cls.args)):
107 arg = cls.args[index]
108 widget = self.component('feature%d' % (index))
109 if arg['type'] is StateKey:
110 key = self['states'][widget.get()]
111 elif arg['type'] is ClassKey:
112 key = self['classes'][widget.get()]
113 elif arg['type'] is IdentityKey:
114 key = self['roles'][widget.get()]
115 elif arg['type'] is RelationshipKey:
116 key = self['relations'][widget.get()]
117 else:
118 raise NotImplementedError,'Cannot handle %s keys' % \
119 arg['type'].__name__
120 newArgs.append(key)
121 row = cls(keys=newArgs)
122 if cls.threshold is None:
123 widget = self.component('feature%d' % (self['selectorCount']-1))
124 threshold = float(widget.get())
125 else:
126 threshold = cls.threshold
127 return KeyedPlane(row,threshold,cls.relation)
128
130 """Configures the menus for the given dynamics type
131 """
132 try:
133 cls = dynamicsTypes[rowType]
134 except KeyError:
135
136 cls = None
137 if cls:
138
139 widget = self.component('feature0')
140 widget.pack(fill='x')
141 self.setMenuItems(cls.rowClass.keyClass,widget)
142 widget.configure(entry_state='disabled')
143
144 widget = self.component('feature1')
145 self.setMenuItems(float,widget)
146 widget.pack(fill='x',after=self.component('feature0'))
147 if cls is IdentityMatrix:
148
149 last = 0
150 else:
151 last = 2
152 else:
153
154 last = 0
155
156 for index in range(last,self['selectorCount']):
157 widget = self.component('feature%d' % (index))
158 widget.pack_forget()
159
161 """Configures the menus for the given branch type
162 """
163 try:
164 noThreshold = not (slopeTypes[rowType].threshold is None)
165 except KeyError:
166
167 noThreshold = False
168 last = None
169 for index in range(self['selectorCount']-1):
170 widget = self.component('feature%d' % (index))
171 try:
172 arg = slopeTypes[rowType].args[index]
173 except IndexError:
174 arg = None
175 except KeyError:
176 arg = None
177 if arg:
178 self.setMenuItems(arg['type'],widget)
179 name = 'feature%d' % (self['selectorCount']-1)
180 widget.pack(fill='x')
181 last = widget
182 else:
183
184 widget.pack_forget()
185
186 widget = self.component('feature%d' % (self['selectorCount']-1))
187 if rowType == self.probBranch:
188 self.setMenuItems(float,widget,0.)
189 else:
190 self.setMenuItems(float,widget)
191 widget.selectitem('0.0')
192 if noThreshold:
193 widget.pack_forget()
194 elif last is None:
195 widget.pack(fill='x')
196 else:
197 widget.pack(fill='x',after=last)
198
200 """Sets the menus to the given dynamics matrix
201 """
202 self.component('type').setlist(map(str,self['leaves']))
203 if isinstance(matrix,DynamicsMatrix):
204 current = matrix.__class__.rowClass.label
205 self.setDynamics(current)
206 self.component('type').selectitem(current)
207 row = matrix.values()[0]
208 key = row.deltaKey
209 if self['key']:
210 if key == self['key']:
211 value = row[key] - 1.
212 else:
213 value = row[key]
214 elif isinstance(key,StateKey) and \
215 key['feature'] == self['feature'] and \
216 key['entity'] == 'self':
217 value = row[key] - 1.
218 else:
219 value = row[key]
220 self.component('feature0').selectitem(key.simpleText())
221 self.component('feature1_entryfield').setvalue('%5.3f' % (value))
222 else:
223 self.setDynamics(matrix)
224 self.component('type').selectitem(matrix)
225
226
227
229 """Sets the menus to the given plane
230 """
231 names = self.getSlopes()
232
233 self.component('type').setlist(names)
234 if isinstance(plane,Distribution):
235 row = None
236 current = self.probBranch
237 threshold = dict.__getitem__(plane,'then')
238 else:
239 row = plane.weights
240 current = row.__class__.__name__[:-3]
241 threshold = plane.threshold
242 try:
243 self.component('type').selectitem(current)
244 except IndexError,msg:
245 if current == 'True':
246 self.setBranch(names[0])
247 self.component('type').selectitem(names[0])
248 else:
249 print 'Unable to handle branches of type:',current
250 return
251 self.setBranch(current)
252 if not isinstance(plane,Distribution):
253
254 index = 0
255 keyList = row.keys()[:]
256 for arg in row.__class__.args:
257 widget = self.component('feature%d' % (index))
258 for key in keyList:
259 if row[key] == arg['weight']:
260 break
261 else:
262 raise KeyError,'No key with weight %4.2f' % (arg['weight'])
263 widget.selectitem(key.simpleText())
264 keyList.remove(key)
265 index += 1
266 if isinstance(plane,Distribution):
267
268 widget = self.component('feature%d' % (self['selectorCount']-1))
269 widget.selectitem(self.mapValue(threshold,0.))
270 elif not isinstance(row,ClassRow) and not isinstance(row,TrueRow) \
271 and not isinstance(row,RelationshipRow):
272
273 widget = self.component('feature%d' % (self['selectorCount']-1))
274 widget.selectitem(self.mapValue(threshold))
275
277 """
278 @return: the relevant set of possible branch types
279 @rtype: str[]
280 """
281 names = slopeTypes.keys()
282 names.sort()
283 if not self['classes']:
284 names.remove('Class')
285 if not self['roles']:
286 names.remove('Identity')
287 if not self['relations']:
288 names.remove('Relationship')
289 names += [self.probBranch]
290 return names
291
293 """
294 @param minimum: optional floor value
295 @return: a list of possible values for a variable of the given class
296 @rtype: list
297 """
298 if cls is StateKey:
299 keyList = self['states'].keys()
300 keyList.sort()
301 elif cls is ClassKey:
302 keyList = self['classes'].keys()
303 keyList.sort()
304 elif cls is float:
305 if minimum is None:
306 minimum = -1.
307 maximum = max(1.,minimum)
308 span = maximum - minimum
309 keyList = map(lambda x:'%3.1f' % (x*self['interval']+minimum),
310 range(int(span/self['interval'])+1))
311 elif cls is ConstantKey:
312 keyList = [cls.keyType]
313 elif cls is IdentityKey:
314 keyList = self['roles'].keys()
315 keyList.sort()
316 elif cls is RelationshipKey:
317 keyList = self['relations'].keys()
318 keyList.sort()
319 elif cls is ActionKey:
320 keyList = map(str,self['actions'].keys())
321 keyList.sort()
322 else:
323 raise NotImplementedError,'Cannot handle %s keys' % \
324 cls.__name__
325 return keyList
326
328 keyList = self.getMenuItems(cls,minimum)
329 widget.component('scrolledlist').setlist(keyList)
330 if len(keyList) > 0:
331 widget.selectitem(keyList[0])
332 if cls is float:
333 widget.configure(entry_state='normal')
334 else:
335 widget.configure(entry_state='disabled')
336
338 """
339 @return: index of value in the discretized number space
340 @rtype: int
341 """
342 if minimum is None:
343 minimum = -1.
344 return int((value-minimum)/self['interval'])
345