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

Contents of /trunk/pygtk/diagnose.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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