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

Contents of /trunk/pygtk/diagnose.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 737 - (show annotations) (download) (as text)
Wed Jul 5 12:36:29 2006 UTC (12 years, 3 months ago) by johnpye
File MIME type: text/x-python
File size: 13588 byte(s)
DSG model converges, using 3 external functions :-)
Added more info in 'diagnose' varinfo and relinfo popups, plus tabstops in display.
Allowed parameters to be used with instantiation_error in instantiate.c.
Fixed up some error messages in bintoken.c.
Renamed 'newcalc_done' to 'evaluation_required' in rel.c.
Other minor changes to error messages and commenting.

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 = 2000
14 MAX_ZOOM_RATIO = 16
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.imagescroll = _xml.get_widget("imagescroll")
37 self.image = _xml.get_widget("image")
38 self.blockentry = _xml.get_widget("blockentry")
39 self.zoomentry = _xml.get_widget("zoomentry")
40
41 self.var = None; self.rel = None
42 self.varname = _xml.get_widget("varname")
43 self.varval = _xml.get_widget("varval")
44 self.varinfobutton = _xml.get_widget("varinfobutton")
45 self.relname = _xml.get_widget("relname")
46 self.relresid = _xml.get_widget("relresid")
47 self.relinfobutton = _xml.get_widget("relinfobutton")
48
49 self.varview = _xml.get_widget("varview")
50 self.varbuf = gtk.TextBuffer()
51 self.varview.set_buffer(self.varbuf)
52 self.varcollapsed = _xml.get_widget("varcollapsed")
53 self.relview = _xml.get_widget("relview")
54 self.relcollapsed = _xml.get_widget("relcollapsed")
55 self.relvalues = _xml.get_widget("relvalues")
56 self.rellabels = _xml.get_widget("rellabels")
57 self.relrels = _xml.get_widget("relrels")
58 self.relresids = _xml.get_widget("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"
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
193 self.fill_selection_info()
194
195 print "DONE FILL VALUES"
196
197 def fill_selection_info(self):
198 if self.var:
199 self.varname.set_text(self.var.getName())
200 self.varval.set_text(str(self.var.getValue()))
201 self.varinfobutton.set_sensitive(True)
202 else:
203 self.varname.set_text("")
204 self.varval.set_text("")
205 self.varinfobutton.set_sensitive(False)
206
207 if self.rel:
208 self.relname.set_text(self.rel.getName())
209 self.relresid.set_text(str(self.rel.getResidual()))
210 self.relinfobutton.set_sensitive(True)
211 else:
212 self.relname.set_text("")
213 self.relresid.set_text("")
214 self.relinfobutton.set_sensitive(False)
215
216 def do_zoom(self):
217 if self.zoom == -1:
218 w, h = self.imagescroll.size_request()
219 #print "SCALE TO FIX, w=%d, h=%d" % (w,h)
220 if self.nc/self.nr > w/h:
221 # a 'wide' image
222 self.zoom = w / self.nc
223 else:
224 self.zoom = h / self.nr
225
226 if self.zoom > MAX_ZOOM_RATIO:
227 self.zoom = MAX_ZOOM_RATIO
228
229 if self.zoom * self.nc > MAX_ZOOM_SIZE or self.zoom * self.nr > MAX_ZOOM_SIZE:
230 self.zoom = MAX_ZOOM_SIZE / max(self.nc,self.nr)
231
232 w = int(self.zoom * self.nc);
233 h = int(self.zoom * self.nr);
234
235 self.zoomentry.set_text("%d %%" % (int(self.zoom*100)) )
236
237 if self.zoom < 2:
238 pb1 = self.pixbuf.scale_simple(w,h,gtk.gdk.INTERP_BILINEAR)
239 else:
240 pb1 = self.pixbuf.scale_simple(w,h,gtk.gdk.INTERP_NEAREST)
241
242 self.image.set_from_pixbuf(pb1)
243
244 def fill_var_names(self):
245 print "FILL VAR NAMES"
246
247 names = [str(i) for i in self.im.getBlockVars(self.block)]
248
249 print "NAMES:",names
250
251 if self.varcollapsed.get_active():
252 res = reduce(names)
253 rows = []
254 for k in res:
255 if k=="":
256 for r in res[k]:
257 rows.append(r)
258 else:
259 rows.append( '%s:\n\t%s' % (k, "\n\t".join(res[k])) )
260 text = "\n".join(rows)
261 else:
262 text = "\n".join(names)
263 self.varbuf.set_text(text)
264
265 print "DONE VAR NAMES"
266
267 def fill_rel_names(self):
268 print "REL NAMES"
269
270 rels = self.im.getBlockRels(self.block)
271
272 print "GOT RELS, NOW GETTING NAMES"
273
274 names = [str(i) for i in rels]
275
276 print "NAMES =",names
277
278 if self.relcollapsed.get_active():
279 res = reduce(names)
280 rows = []
281 for k in res:
282 if k=="":
283 for r in res[k]:
284 rows.append(r)
285 else:
286 rows.append( '%s:\n\t%s' % (k, "\n\t".join(res[k])) )
287 text = "\n".join(rows)
288 else:
289 text = "\n".join(names)
290 self.relbuf.set_text(text)
291
292 print "DONE REL NAMES"
293
294 def set_block(self, block):
295 self.fill_values(block)
296
297 def set_zoom(self,zoom):
298 self.zoom = zoom
299 self.do_zoom()
300
301 def show_cursor(self,x,y):
302 c = self.cl + int(x/self.zoom)
303 r = self.rl + int(y / self.zoom)
304 if c > self.ch or r > self.rh:
305 #print "OUT OF RANGE"
306 return
307 self.var = self.im.getVariable(c)
308 self.rel = self.im.getRelation(r)
309 self.fill_selection_info()
310
311 # GUI EVENT HOOKS-----------------------------------------------------------
312
313 def on_diagnosewin_close(self,*args):
314 self.window.response(gtk.RESPONSE_CLOSE);
315
316 # incidence data view
317
318 def on_varcollapsed_toggled(self,*args):
319 vc = self.varcollapsed.get_active()
320 self.browser.prefs.setBoolPref("Diagnose","varcollapsed",vc)
321 if self.im:
322 self.fill_var_names()
323
324 def on_relcollapsed_toggled(self,*args):
325 rc = self.varcollapsed.get_active()
326 self.browser.prefs.setBoolPref("Diagnose","relcollapsed",rc)
327 if self.im:
328 self.fill_rel_names()
329
330 # detailed information about vars and rels (solver-side information!)
331
332 def on_varinfobutton_clicked(self,*args):
333 title = "Variable '%s'" % self.var
334 text = "%s\n%s\n" % (title,"(from the solver's view)")
335
336 _rows = {
337 "Value": self.var.getValue()
338 ,"Nominal": self.var.getNominal()
339 ,"Lower bound": self.var.getLowerBound()
340 ,"Upper bound": self.var.getUpperBound()
341 }
342 for k,v in _rows.iteritems():
343 text += "\n %s\t%s" % (k,value_human(v))
344
345 text += "\n\nIncident with %d relations:" % self.var.getNumIncidentRelations()
346 for r in self.var.getIncidentRelations():
347 text += "\n %s" % r.getName()
348
349 _dialog = InfoDialog(self.browser,self.window,text,title,tabs=(150,300))
350 _dialog.run()
351
352 def on_relinfobutton_clicked(self,*args):
353 title = "Relation '%s'" % self.rel
354 text = "%s\n%s\n" % (title,"(from the solver's view)")
355 text += "\n %s\t%15f" % ("Residual", self.rel.getResidual())
356
357 text += "\n\nRelation expression:\n"
358 text += self.rel.getRelationAsString()
359
360 text += "\n\nIncident with %d variables:" % self.rel.getNumIncidentVariables()
361 for v in self.rel.getIncidentVariables():
362 text += "\n %s\t= %s" % ( v.getName(),value_human(v.getValue()) )
363
364 _dialog = InfoDialog(self.browser,self.window,text,title,tabs=(150,300))
365 _dialog.run()
366
367
368 # block navigation
369
370 def on_nextbutton_clicked(self,*args):
371 self.set_block(self.block + 1)
372
373 def on_prevbutton_clicked(self,*args):
374 self.set_block(self.block - 1)
375
376 def on_prevbigbutton_clicked(self,*args):
377 b = self.block - 1
378 while b >= 0:
379 rl,cl,rh,ch = self.im.getBlockLocation(b)
380 if rh-rl > 0 or ch-cl>0:
381 self.set_block(b)
382 b = b - 1
383 print "NO PRECEDING 'BIG' BLOCKS"
384
385 def on_nextbigbutton_clicked(self,*args):
386 b = self.block + 1
387 n = self.im.getNumBlocks()
388 while b < n:
389 rl,cl,rh,ch = self.im.getBlockLocation(b)
390 if rh-rl > 0 or ch-cl>0:
391 self.set_block(b)
392 b = b + 1
393 print "NO FOLLOWING 'BIG' BLOCKS"
394
395 def on_blockentry_key_press_event(self,widget,event):
396 keyname = gtk.gdk.keyval_name(event.keyval)
397 print "KEY ",keyname
398 if keyname=="Return":
399 self.set_block( int(self.blockentry.get_text()) )
400
401 # zoom in and out
402
403 def on_zoominbutton_clicked(self,*args):
404 z = int( math.log(self.zoom)/math.log(2) )
405 z = pow(2,z + 1);
406 self.set_zoom(z)
407
408 def on_zoomoutbutton_clicked(self,*args):
409 z = int( math.log(self.zoom)/math.log(2) + 0.999)
410 z = pow(2,z - 1);
411 self.set_zoom(z)
412
413 def on_zoomentry_key_press_event(self,widget,event):
414 keyname = gtk.gdk.keyval_name(event.keyval)
415 print "KEY ",keyname
416 if keyname=="Return":
417 t = self.zoomentry.get_text()
418 m = ZOOM_RE.match(t)
419 if not m:
420 self.zoomentry.set_text("%d %%" % int(self.zoom*100))
421 for mm in m:
422 print m
423 self.set_zoom( int(self.zoomentry.get_text()) )
424
425 # clicking in incidence matrix to get updated information at RHS
426
427 def on_imageevent_motion_notify_event(self,widget,event):
428 self.show_cursor(event.x, event.y)
429
430 def on_imageevent_button_press_event(self,widget,event):
431 self.show_cursor(event.x, event.y)
432
433
434 def value_human(v):
435 if v==0 or abs( math.log10(abs(v)) )<8:
436 return "%f" % v
437 return "%e" % v
438
439 #---------------------------------------
440 # Procedures to 'fold' a list of items from a hierarchy
441 # http://www.experts-exchange.com/Programming/Programming_Languages/Python/Q_21719649.html
442 # It's still buggy, I think
443
444 def fold(data):
445 """ fold sorted numeric sequence data into ranged representation:
446 >>> fold([1, 4,5,6, 10, 15,16,17,18, 22, 25,26,27,28])
447 '[1,4-6,10,15-18,22,25-28]'
448 """
449 folded = []
450 for k, g in groupby(enumerate(sorted(data)), lambda (i,x):i-x):
451 seq = map(itemgetter(1), g)
452 if len(seq) > 1:
453 x = '%s-%s' % (seq[0], seq[-1])
454 else:
455 x = str(seq[0])
456 folded.append(x)
457 return folded and '[%s]' % ','.join(folded) or ''
458
459 def reduce(names):
460 """reduce a list of items nto something more readable:
461 >>> 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()
462 >>> res = reduce(data)
463 >>> for k in sorted(res):
464 ... print '%s: %s' % (k, res[k])
465 C: T, delta[1-3,5], h, p, x
466 C.sat: p, x
467 """
468 data = sorted([n.split('.') for n in sorted(names)], key=len)
469 res = {}
470 for k, g in groupby(data, lambda x: len(x)):
471 if k == 1:
472 indexed = {}
473 seq = set(get(indexed, item) for item in g)
474 res['[global]'] = [ i+fold(indexed.get(i, [])) for i in sorted(seq) ]
475 else:
476 for key, g1 in groupby(g, lambda x: '.'.join(x[:-1])):
477 indexed = {}
478 seq = set(get(indexed, item) for item in g1)
479 res[key] = [ i+fold(indexed.get(i, [])) for i in sorted(seq) ]
480 return res
481
482 def get(indexed, item):
483 item = item[-1]
484 if item.endswith(']'):
485 item, idx = item[:-1].split('[')
486 indexed.setdefault(item, []).append(int(idx))
487 return item
488

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