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

Contents of /trunk/pygtk/diagnose.py

Parent Directory Parent Directory | Revision Log Revision Log


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

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