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

Contents of /trunk/pygtk/diagnose.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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