/[ascend]/trunk/pygtk/diagnose.py
ViewVC logotype

Annotation of /trunk/pygtk/diagnose.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 735 - (hide annotations) (download) (as text)
Wed Jul 5 02:42:19 2006 UTC (13 years, 1 month ago) by johnpye
File MIME type: text/x-python
File size: 12815 byte(s)
Improved implementation of 'diagnose' window in PyGTK interface.
You can now view solver-side details about variables and relations, see the '(i)' icons.
1 johnpye 280 import gtk
2     import gtk.glade
3 johnpye 463 import ascpy
4 johnpye 280 from itertools import groupby
5     from operator import itemgetter
6 johnpye 283 import math
7 johnpye 284 import re
8 johnpye 280
9 johnpye 351 import config
10 johnpye 735 from infodialog import *
11 johnpye 351
12 johnpye 284 ZOOM_RE = re.compile(r"([0-9]+)\s*%?")
13     MAX_ZOOM_SIZE = 2000
14     MAX_ZOOM_RATIO = 16
15 johnpye 287 AT_BOUND_TOL = 0.0001;
16 johnpye 284
17 johnpye 280 class DiagnoseWindow:
18 johnpye 351 def __init__(self,browser,block=0):
19 johnpye 280 self.browser=browser
20 johnpye 437 _xml = gtk.glade.XML(browser.glade_file,"diagnosewin")
21 johnpye 280 _xml.signal_autoconnect(self)
22    
23     self.window = _xml.get_widget("diagnosewin")
24 johnpye 328 self.window.set_transient_for(self.browser.window)
25    
26 johnpye 533 try:
27     _icon = gtk.Image()
28     _iconpath = browser.assets_dir+'diagnose'+config.ICON_EXTENSION
29     print "ICON PATH =",_iconpath
30     _icon.set_from_file(_iconpath)
31     print "ICON = ",_icon
32     self.window.set_icon(_icon)
33     except:
34     pass
35 johnpye 455
36 johnpye 284 self.imagescroll = _xml.get_widget("imagescroll")
37 johnpye 282 self.image = _xml.get_widget("image")
38 johnpye 280 self.blockentry = _xml.get_widget("blockentry")
39 johnpye 284 self.zoomentry = _xml.get_widget("zoomentry")
40 johnpye 280
41 johnpye 286 self.varname = _xml.get_widget("varname");
42     self.varval = _xml.get_widget("varval");
43 johnpye 735 self.varinfobutton = _xml.get_widget("varinfobutton");
44 johnpye 286 self.relname = _xml.get_widget("relname");
45     self.relresid = _xml.get_widget("relresid");
46 johnpye 735 self.relinfobutton = _xml.get_widget("relinfobutton")
47 johnpye 286
48 johnpye 280 self.varview = _xml.get_widget("varview")
49     self.varbuf = gtk.TextBuffer()
50     self.varview.set_buffer(self.varbuf)
51     self.varcollapsed = _xml.get_widget("varcollapsed")
52     self.relview = _xml.get_widget("relview")
53     self.relcollapsed = _xml.get_widget("relcollapsed")
54     self.relvalues = _xml.get_widget("relvalues")
55     self.rellabels = _xml.get_widget("rellabels")
56     self.relrels = _xml.get_widget("relrels")
57     self.relresids = _xml.get_widget("relresids")
58     self.relbuf = gtk.TextBuffer()
59     self.relview.set_buffer(self.relbuf)
60    
61 johnpye 294 self.im = None
62 johnpye 285 self.block = 0
63 johnpye 294 self.apply_prefs()
64    
65 johnpye 280 self.prepare_data()
66 johnpye 285 self.fill_values(block) # block zero
67 johnpye 280
68     def run(self):
69     self.window.run()
70     self.window.hide()
71    
72 johnpye 294 def apply_prefs(self):
73 johnpye 319 vc = self.browser.prefs.getBoolPref("Diagnose","varcollapsed",True)
74    
75 johnpye 294 print "VARCOLLAPSED =",vc
76     self.varcollapsed.set_active(vc)
77 johnpye 319 self.relcollapsed.set_active(self.browser.prefs.getBoolPref("Diagnose","relcollapsed",True))
78 johnpye 294
79 johnpye 280 def prepare_data(self):
80     # convert incidence map to pylab numarray type:
81     print "PREPARING DATA"
82     self.im = self.browser.sim.getIncidenceMatrix()
83     self.data = self.im.getIncidenceData()
84     print "DATA LOADED"
85    
86 johnpye 284 self.zoom=1;
87 johnpye 280
88     def fill_values(self, block):
89 johnpye 319
90 johnpye 283 try:
91     rl,cl,rh,ch = self.im.getBlockLocation(block)
92     except IndexError:
93 johnpye 319 if block >= self.im.getNumBlocks():
94     block = self.im.getNumBlocks() - 1
95     rl,cl,rh,ch = self.im.getBlockLocation(block)
96     else:
97     print "BLOCK INDEX ERROR: block =",block
98     self.blockentry.set_text(str(self.block))
99     return
100     except RuntimeError,e:
101     print "ERROR GETTING BLOCK LOCATION:",str(e)
102 johnpye 285 self.blockentry.set_text(str(self.block))
103 johnpye 283 return
104 johnpye 285
105 johnpye 280 self.block = block
106     self.blockentry.set_text(str(block))
107 johnpye 283
108 johnpye 286 self.rl = rl
109     self.cl = cl
110     self.rh = rh
111     self.ch = ch
112    
113 johnpye 283 nr = int(rh-rl+1);
114     nc = int(ch-cl+1);
115    
116 johnpye 669 print "STARTING IMAGE CREATION"
117 johnpye 282 # refer http://pygtk.org/pygtk2tutorial/sec-DrawingMethods.html
118     c = chr(255)
119 johnpye 283 b = nr*nc*3*[c]
120     rowstride = 3 * nc
121    
122     blackdot = [chr(0)]*3;
123     reddot = [chr(255), chr(0), chr(0)]
124     pinkdot = [chr(255), chr(127), chr(127)]
125     skydot = [chr(127), chr(127), chr(255)]
126     bluedot = [chr(0), chr(0), chr(255)]
127 johnpye 285 hotpinkdot = [chr(255), chr(47), chr(179)] # very big (+/-)
128     brightbluedot = [chr(71), chr(157), chr(255)] # very small (+/-)
129     greendot = [chr(87), chr(193), chr(70)] # close to 1
130     orangedot = [chr(255), chr(207), chr(61)] # 10-1000
131     bluegreendot = [chr(70), chr(221), chr(181)] # 0.001 - 0.1
132 johnpye 280 for i in self.data:
133 johnpye 283 if i.row < rl or i.row > rh or i.col < cl or i.col > ch:
134     continue
135     r = i.row - rl;
136     c = i.col - cl;
137     pos = rowstride*r + 3*c
138     dot = blackdot;
139     var = self.im.getVariable(i.col);
140 johnpye 287 if abs( (var.getValue()-var.getUpperBound())/ var.getNominal() ) < AT_BOUND_TOL:
141     dot = reddot
142     elif abs( var.getValue() - var.getLowerBound() ) / var.getNominal() < AT_BOUND_TOL:
143     dot = reddot
144     else:
145     rat = var.getValue() / var.getNominal()
146     if rat!=0:
147     try:
148     val = abs(rat)
149     if abs(rat) > 1000:
150     dot = hotpinkdot
151     elif abs(rat) > 10:
152     dot = orangedot
153     elif abs(rat) < 0.001:
154     dot = brightbluedot
155     elif abs(rat) < 10 and abs(rat) > 0.1:
156     dot = greendot
157     elif abs(rat) > 0.001 and abs(rat) < 0.1:
158     dot = bluegreendot
159     else:
160     dot = blackdot
161     except ValueError, e:
162     pass
163 johnpye 284 #print "DOT: ",dot
164 johnpye 283 b[pos], b[pos+1], b[pos+2] = dot
165    
166 johnpye 282 d = ''.join(b)
167 johnpye 283
168 johnpye 669 print "DONE IMAGE CREATION"
169 johnpye 282
170 johnpye 284 self.pixbuf = gtk.gdk.pixbuf_new_from_data(d, gtk.gdk.COLORSPACE_RGB, False, 8 \
171     , nc, nr, rowstride);
172 johnpye 283
173 johnpye 284 self.nr = nr
174     self.nc = nc
175     self.zoom = -1 # to fit, up to max 16x
176     self.do_zoom()
177 johnpye 283
178 johnpye 669 print "DONE IMAGE TRANSFER TO SERVER"
179 johnpye 283
180 johnpye 284 self.fill_var_names()
181     self.fill_rel_names()
182 johnpye 286
183 johnpye 735 self.fill_selection_info()
184 johnpye 280
185 johnpye 669 print "DONE FILL VALUES"
186 johnpye 286
187 johnpye 735 def fill_selection_info(self):
188     if self.var:
189     self.varname.set_text(self.var.getName())
190     self.varval.set_text(str(self.var.getValue()))
191     self.varinfobutton.set_sensitive(True)
192     else:
193     self.varname.set_text("")
194     self.varval.set_text("")
195     self.varinfobutton.set_sensitive(False)
196    
197     if self.rel:
198     self.relname.set_text(self.rel.getName())
199     self.relresid.set_text(str(self.rel.getResidual()))
200     self.relinfobutton.set_sensitive(True)
201     else:
202     self.relname.set_text("")
203     self.relresid.set_text("")
204     self.relinfobutton.set_sensitive(False)
205    
206 johnpye 284 def do_zoom(self):
207     if self.zoom == -1:
208     w, h = self.imagescroll.size_request()
209     #print "SCALE TO FIX, w=%d, h=%d" % (w,h)
210     if self.nc/self.nr > w/h:
211     # a 'wide' image
212     self.zoom = w / self.nc
213     else:
214     self.zoom = h / self.nr
215 johnpye 283
216 johnpye 284 if self.zoom > MAX_ZOOM_RATIO:
217     self.zoom = MAX_ZOOM_RATIO
218 johnpye 280
219 johnpye 284 if self.zoom * self.nc > MAX_ZOOM_SIZE or self.zoom * self.nr > MAX_ZOOM_SIZE:
220     self.zoom = MAX_ZOOM_SIZE / max(self.nc,self.nr)
221 johnpye 283
222 johnpye 284 w = int(self.zoom * self.nc);
223     h = int(self.zoom * self.nr);
224    
225     self.zoomentry.set_text("%d %%" % (int(self.zoom*100)) )
226 johnpye 280
227 johnpye 284 if self.zoom < 2:
228     pb1 = self.pixbuf.scale_simple(w,h,gtk.gdk.INTERP_BILINEAR)
229     else:
230     pb1 = self.pixbuf.scale_simple(w,h,gtk.gdk.INTERP_NEAREST)
231    
232     self.image.set_from_pixbuf(pb1)
233    
234 johnpye 280 def fill_var_names(self):
235 johnpye 669 print "FILL VAR NAMES"
236    
237 johnpye 280 names = [str(i) for i in self.im.getBlockVars(self.block)]
238 johnpye 669
239     print "NAMES:",names
240    
241 johnpye 280 if self.varcollapsed.get_active():
242 johnpye 287 res = reduce(names)
243 johnpye 280 rows = []
244     for k in res:
245     if k=="":
246     for r in res[k]:
247     rows.append(r)
248     else:
249     rows.append( '%s:\n\t%s' % (k, "\n\t".join(res[k])) )
250     text = "\n".join(rows)
251     else:
252     text = "\n".join(names)
253     self.varbuf.set_text(text)
254    
255 johnpye 669 print "DONE VAR NAMES"
256    
257 johnpye 280 def fill_rel_names(self):
258 johnpye 669 print "REL NAMES"
259    
260     rels = self.im.getBlockRels(self.block)
261    
262     print "GOT RELS, NOW GETTING NAMES"
263    
264     names = [str(i) for i in rels]
265    
266     print "NAMES =",names
267    
268 johnpye 280 if self.relcollapsed.get_active():
269 johnpye 287 res = reduce(names)
270     rows = []
271     for k in res:
272     if k=="":
273     for r in res[k]:
274     rows.append(r)
275     else:
276     rows.append( '%s:\n\t%s' % (k, "\n\t".join(res[k])) )
277     text = "\n".join(rows)
278 johnpye 280 else:
279     text = "\n".join(names)
280     self.relbuf.set_text(text)
281    
282 johnpye 669 print "DONE REL NAMES"
283    
284 johnpye 280 def set_block(self, block):
285     self.fill_values(block)
286    
287 johnpye 284 def set_zoom(self,zoom):
288     self.zoom = zoom
289     self.do_zoom()
290    
291 johnpye 286 def show_cursor(self,x,y):
292     c = self.cl + int(x/self.zoom)
293     r = self.rl + int(y / self.zoom)
294     if c > self.ch or r > self.rh:
295     #print "OUT OF RANGE"
296     return
297 johnpye 735 self.var = self.im.getVariable(c)
298     self.rel = self.im.getRelation(r)
299     self.fill_selection_info()
300 johnpye 286
301     # GUI EVENT HOOKS-----------------------------------------------------------
302    
303 johnpye 735 def on_diagnosewin_close(self,*args):
304     self.window.response(gtk.RESPONSE_CLOSE);
305    
306     # incidence data view
307    
308 johnpye 280 def on_varcollapsed_toggled(self,*args):
309 johnpye 294 vc = self.varcollapsed.get_active()
310     self.browser.prefs.setBoolPref("Diagnose","varcollapsed",vc)
311     if self.im:
312     self.fill_var_names()
313 johnpye 280
314     def on_relcollapsed_toggled(self,*args):
315 johnpye 294 rc = self.varcollapsed.get_active()
316     self.browser.prefs.setBoolPref("Diagnose","relcollapsed",rc)
317     if self.im:
318     self.fill_rel_names()
319 johnpye 280
320 johnpye 735 # detailed information about vars and rels (solver-side information!)
321    
322     def on_varinfobutton_clicked(self,*args):
323     title = "Variable '%s'" % self.var
324     text = "%s\n%s\n" % (title,"(from the solver's view)")
325     text += "\n%-30s%15f" % ("Value", self.var.getValue())
326     text += "\n%-30s%15f" % ("Nominal", self.var.getNominal())
327     text += "\n%-30s%15f" % ("Lower bound", self.var.getLowerBound())
328     text += "\n%-30s%15f" % ("Upper bound", self.var.getUpperBound())
329    
330     text += "\n\nIncidence with %d relations:" % self.var.getNumIncidentRelations()
331     for r in self.var.getIncidentRelations():
332     text += "\n%s" % r.getName()
333    
334     _dialog = InfoDialog(self.browser,self.window,text,title)
335     _dialog.run()
336    
337     def on_relinfobutton_clicked(self,*args):
338     title = "Relation '%s'" % self.rel
339     text = "%s\n%s\n" % (title,"(from the solver's view)")
340     text += "\n%-30s%15f" % ("Residual", self.rel.getResidual())
341    
342     _dialog = InfoDialog(self.browser,self.window,text,title)
343     _dialog.run()
344    
345    
346     # block navigation
347    
348 johnpye 280 def on_nextbutton_clicked(self,*args):
349     self.set_block(self.block + 1)
350    
351     def on_prevbutton_clicked(self,*args):
352 johnpye 290 self.set_block(self.block - 1)
353 johnpye 280
354 johnpye 290 def on_prevbigbutton_clicked(self,*args):
355     b = self.block - 1
356 johnpye 291 while b >= 0:
357 johnpye 290 rl,cl,rh,ch = self.im.getBlockLocation(b)
358     if rh-rl > 0 or ch-cl>0:
359     self.set_block(b)
360     b = b - 1
361     print "NO PRECEDING 'BIG' BLOCKS"
362    
363     def on_nextbigbutton_clicked(self,*args):
364     b = self.block + 1
365     n = self.im.getNumBlocks()
366     while b < n:
367     rl,cl,rh,ch = self.im.getBlockLocation(b)
368     if rh-rl > 0 or ch-cl>0:
369     self.set_block(b)
370     b = b + 1
371     print "NO FOLLOWING 'BIG' BLOCKS"
372    
373 johnpye 283 def on_blockentry_key_press_event(self,widget,event):
374     keyname = gtk.gdk.keyval_name(event.keyval)
375     print "KEY ",keyname
376     if keyname=="Return":
377     self.set_block( int(self.blockentry.get_text()) )
378 johnpye 280
379 johnpye 735 # zoom in and out
380    
381 johnpye 284 def on_zoominbutton_clicked(self,*args):
382     z = int( math.log(self.zoom)/math.log(2) )
383     z = pow(2,z + 1);
384     self.set_zoom(z)
385    
386     def on_zoomoutbutton_clicked(self,*args):
387     z = int( math.log(self.zoom)/math.log(2) + 0.999)
388     z = pow(2,z - 1);
389     self.set_zoom(z)
390    
391     def on_zoomentry_key_press_event(self,widget,event):
392     keyname = gtk.gdk.keyval_name(event.keyval)
393     print "KEY ",keyname
394     if keyname=="Return":
395     t = self.zoomentry.get_text()
396     m = ZOOM_RE.match(t)
397     if not m:
398     self.zoomentry.set_text("%d %%" % int(self.zoom*100))
399     for mm in m:
400     print m
401     self.set_zoom( int(self.zoomentry.get_text()) )
402    
403 johnpye 735 # clicking in incidence matrix to get updated information at RHS
404    
405 johnpye 286 def on_imageevent_motion_notify_event(self,widget,event):
406     self.show_cursor(event.x, event.y)
407    
408     def on_imageevent_button_press_event(self,widget,event):
409     self.show_cursor(event.x, event.y)
410    
411    
412 johnpye 280 # The following is from
413     # http://www.experts-exchange.com/Programming/Programming_Languages/Python/Q_21719649.html
414 johnpye 284 # it's still buggy.
415 johnpye 280
416     def fold(data):
417     """ fold sorted numeric sequence data into ranged representation:
418     >>> fold([1, 4,5,6, 10, 15,16,17,18, 22, 25,26,27,28])
419     '[1,4-6,10,15-18,22,25-28]'
420     """
421     folded = []
422 johnpye 287 for k, g in groupby(enumerate(sorted(data)), lambda (i,x):i-x):
423 johnpye 280 seq = map(itemgetter(1), g)
424     if len(seq) > 1:
425     x = '%s-%s' % (seq[0], seq[-1])
426     else:
427     x = str(seq[0])
428     folded.append(x)
429     return folded and '[%s]' % ','.join(folded) or ''
430    
431 johnpye 287 def reduce(names):
432     """reduce a list of items nto something more readable:
433 johnpye 280 >>> data = 'C.x C.p C.T C.delta[1] C.delta[2] C.delta[3] C.sat.x C.sat.p C.h C.delta[5]'.split()
434     >>> res = reduce(data)
435     >>> for k in sorted(res):
436     ... print '%s: %s' % (k, res[k])
437     C: T, delta[1-3,5], h, p, x
438     C.sat: p, x
439     """
440 johnpye 287 data = sorted([n.split('.') for n in sorted(names)], key=len)
441 johnpye 280 res = {}
442     for k, g in groupby(data, lambda x: len(x)):
443 johnpye 287 if k == 1:
444     indexed = {}
445     seq = set(get(indexed, item) for item in g)
446     res['[global]'] = [ i+fold(indexed.get(i, [])) for i in sorted(seq) ]
447     else:
448     for key, g1 in groupby(g, lambda x: '.'.join(x[:-1])):
449     indexed = {}
450     seq = set(get(indexed, item) for item in g1)
451     res[key] = [ i+fold(indexed.get(i, [])) for i in sorted(seq) ]
452 johnpye 280 return res
453    
454     def get(indexed, item):
455     item = item[-1]
456     if item.endswith(']'):
457     item, idx = item[:-1].split('[')
458     indexed.setdefault(item, []).append(int(idx))
459     return item

john.pye@anu.edu.au
ViewVC Help
Powered by ViewVC 1.1.22