info.py (1758:74acd5b23964) info.py (1772:a3a83e812a5e)
1
2# Copyright (c) 2003-2004 The Regents of The University of Michigan
3# All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions are
7# met: redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer;
9# redistributions in binary form must reproduce the above copyright
10# notice, this list of conditions and the following disclaimer in the
11# documentation and/or other materials provided with the distribution;
12# neither the name of the copyright holders nor the names of its
13# contributors may be used to endorse or promote products derived from
14# this software without specific prior written permission.
15#
16# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
1# Copyright (c) 2003-2004 The Regents of The University of Michigan
2# All rights reserved.
3#
4# Redistribution and use in source and binary forms, with or without
5# modification, are permitted provided that the following conditions are
6# met: redistributions of source code must retain the above copyright
7# notice, this list of conditions and the following disclaimer;
8# redistributions in binary form must reproduce the above copyright
9# notice, this list of conditions and the following disclaimer in the
10# documentation and/or other materials provided with the distribution;
11# neither the name of the copyright holders nor the names of its
12# contributors may be used to endorse or promote products derived from
13# this software without specific prior written permission.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
28#Permission is granted to use, copy, create derivative works and
29#redistribute this software and such derivative works for any purpose,
30#so long as the copyright notice above, this grant of permission, and
31#the disclaimer below appear in all copies made; and so long as the
32#name of The University of Michigan is not used in any advertising or
33#publicity pertaining to the use or distribution of this software
34#without specific, written prior authorization.
35#
36#THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE
37#UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND WITHOUT
38#WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER EXPRESS OR
39#IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
40#MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF
41#THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE FOR ANY DAMAGES,
42#INCLUDING DIRECT, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
43#DAMAGES, WITH RESPECT TO ANY CLAIM ARISING OUT OF OR IN CONNECTION
44#WITH THE USE OF THE SOFTWARE, EVEN IF IT HAS BEEN OR IS HEREAFTER
45#ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
46
47from __future__ import division
48import operator, re, types
49
50source = None
51display_run = 0
52global globalTicks
53globalTicks = None
54
55def total(f):
56 if isinstance(f, FormulaStat):
57 v = f.value
58 else:
59 v = f
60
61 f = FormulaStat()
62 if isinstance(v, (list, tuple)):
63 f.value = reduce(operator.add, v)
64 else:
65 f.value = v
66
67 return f
68
69def unaryop(op, f):
70 if isinstance(f, FormulaStat):
71 v = f.value
72 else:
73 v = f
74
75 if isinstance(v, (list, tuple)):
76 return map(op, v)
77 else:
78 return op(v)
79
80def zerodiv(lv, rv):
81 if rv == 0.0:
82 return 0.0
83 else:
84 return operator.truediv(lv, rv)
85
86def wrapop(op, lv, rv):
87 if isinstance(lv, str):
88 return lv
89
90 if isinstance(rv, str):
91 return rv
92
93 return op(lv, rv)
94
95def same(lrun, rrun):
96 for lx,rx in zip(lrun.keys(),rrun.keys()):
97 if lx != rx:
98 print 'lx != rx'
99 print lx, rx
100 print lrun.keys()
101 print rrun.keys()
102 return False
103 for ly,ry in zip(lrun[lx].keys(),rrun[rx].keys()):
104 if ly != ry:
105 print 'ly != ry'
106 print ly, ry
107 print lrun[lx].keys()
108 print rrun[rx].keys()
109 return False
110 return True
111
112
113def binaryop(op, lf, rf):
114 result = {}
115
116 if isinstance(lf, FormulaStat) and isinstance(rf, FormulaStat):
117 lv = lf.value
118 rv = rf.value
119
120 theruns = []
121 for r in lv.keys():
122 if rv.has_key(r):
123 if same(lv[r], rv[r]):
124 theruns.append(r)
125 else:
126 raise AttributeError
127
128 for run in theruns:
129 result[run] = {}
130 for x in lv[run].keys():
131 result[run][x] = {}
132 for y in lv[run][x].keys():
133 result[run][x][y] = wrapop(op, lv[run][x][y],
134 rv[run][x][y])
135 elif isinstance(lf, FormulaStat):
136 lv = lf.value
137 for run in lv.keys():
138 result[run] = {}
139 for x in lv[run].keys():
140 result[run][x] = {}
141 for y in lv[run][x].keys():
142 result[run][x][y] = wrapop(op, lv[run][x][y], rf)
143 elif isinstance(rf, FormulaStat):
144 rv = rf.value
145 for run in rv.keys():
146 result[run] = {}
147 for x in rv[run].keys():
148 result[run][x] = {}
149 for y in rv[run][x].keys():
150 result[run][x][y] = wrapop(op, lf, rv[run][x][y])
151
152 return result
153
154def sums(x, y):
155 if isinstance(x, (list, tuple)):
156 return map(lambda x, y: x + y, x, y)
157 else:
158 return x + y
159
160def alltrue(seq):
161 return reduce(lambda x, y: x and y, seq)
162
163def allfalse(seq):
164 return not reduce(lambda x, y: x or y, seq)
165
166def enumerate(seq):
167 return map(None, range(len(seq)), seq)
168
169def cmp(a, b):
170 if a < b:
171 return -1
172 elif a == b:
173 return 0
174 else:
175 return 1
176
177class Statistic(object):
178
179 def __init__(self, data):
180 self.__dict__.update(data.__dict__)
181 if not self.__dict__.has_key('value'):
182 self.__dict__['value'] = None
183 if not self.__dict__.has_key('bins'):
184 self.__dict__['bins'] = None
185 if not self.__dict__.has_key('ticks'):
186 self.__dict__['ticks'] = None
187 if 'vc' not in self.__dict__:
188 self.vc = {}
189
190 def __getattribute__(self, attr):
191 if attr == 'ticks':
192 if self.__dict__['ticks'] != globalTicks:
193 self.__dict__['value'] = None
194 self.__dict__['ticks'] = globalTicks
195 return self.__dict__['ticks']
196 if attr == 'value':
197 if self.__dict__['ticks'] != globalTicks:
198 if self.__dict__['ticks'] != None and \
199 len(self.__dict__['ticks']) == 1:
200 self.vc[self.__dict__['ticks'][0]] = self.__dict__['value']
201 self.__dict__['ticks'] = globalTicks
202 if len(globalTicks) == 1 and self.vc.has_key(globalTicks[0]):
203 self.__dict__['value'] = self.vc[globalTicks[0]]
204 else:
205 self.__dict__['value'] = None
206 if self.__dict__['value'] == None:
207 self.__dict__['value'] = self.getValue()
208 return self.__dict__['value']
209 else:
210 return super(Statistic, self).__getattribute__(attr)
211
212 def __setattr__(self, attr, value):
213 if attr == 'bins' or attr == 'ticks':
214 if attr == 'bins':
215 if value is not None:
216 value = source.getBin(value)
217 #elif attr == 'ticks' and type(value) is str:
218 # value = [ int(x) for x in value.split() ]
219
220 self.__dict__[attr] = value
221 self.__dict__['value'] = None
222 self.vc = {}
223 else:
224 super(Statistic, self).__setattr__(attr, value)
225
226 def getValue(self):
227 raise AttributeError, 'getValue() must be defined'
228
229 def zero(self):
230 return False
231
232 def __ne__(self, other):
233 return not (self == other)
234
235 def __str__(self):
236 return '%f' % (float(self))
237
238class FormulaStat(object):
239 def __add__(self, other):
240 f = FormulaStat()
241 f.value = binaryop(operator.add, self, other)
242 return f
243 def __sub__(self, other):
244 f = FormulaStat()
245 f.value = binaryop(operator.sub, self, other)
246 return f
247 def __mul__(self, other):
248 f = FormulaStat()
249 f.value = binaryop(operator.mul, self, other)
250 return f
251 def __truediv__(self, other):
252 f = FormulaStat()
253 f.value = binaryop(zerodiv, self, other)
254 return f
255 def __mod__(self, other):
256 f = FormulaStat()
257 f.value = binaryop(operator.mod, self, other)
258 return f
259 def __radd__(self, other):
260 f = FormulaStat()
261 f.value = binaryop(operator.add, other, self)
262 return f
263 def __rsub__(self, other):
264 f = FormulaStat()
265 f.value = binaryop(operator.sub, other, self)
266 return f
267 def __rmul__(self, other):
268 f = FormulaStat()
269 f.value = binaryop(operator.mul, other, self)
270 return f
271 def __rtruediv__(self, other):
272 f = FormulaStat()
273 f.value = binaryop(zerodiv, other, self)
274 return f
275 def __rmod__(self, other):
276 f = FormulaStat()
277 f.value = binaryop(operator.mod, other, self)
278 return f
279 def __neg__(self):
280 f = FormulaStat()
281 f.value = unaryop(operator.neg, self)
282 return f
283 def __getitem__(self, idx):
284 f = FormulaStat()
285 f.value = {}
286 for key in self.value.keys():
287 f.value[key] = {}
288 f.value[key][0] = {}
289 f.value[key][0][0] = self.value[key][idx][0]
290 return f
291
292 def __float__(self):
293 if isinstance(self.value, FormulaStat):
294 return float(self.value)
295 if not self.value.has_key(display_run):
296 return (1e300*1e300)
297 if len(self.value[display_run]) == 1:
298 return self.value[display_run][0][0]
299 else:
300 #print self.value[display_run]
301 return self.value[display_run][4][0]
302 #raise ValueError
303
304 def display(self):
305 import display
306 d = display.VectorDisplay()
307 d.flags = 0
308 d.precision = 1
309 d.name = 'formula'
310 d.desc = 'formula'
311 val = self.value[display_run]
312 d.value = [ val[x][0] for x in val.keys() ]
313 d.display()
314
315
316class Scalar(Statistic,FormulaStat):
317 def getValue(self):
318 return source.data(self, self.bins, self.ticks)
319
320 def display(self):
321 import display
322 p = display.Print()
323 p.name = self.name
324 p.desc = self.desc
325 p.value = float(self)
326 p.flags = self.flags
327 p.precision = self.precision
328 if display.all or (self.flags & flags.printable):
329 p.display()
330
331 def comparable(self, other):
332 return self.name == other.name
333
334 def __eq__(self, other):
335 return self.value == other.value
336
337 def __isub__(self, other):
338 self.value -= other.value
339 return self
340
341 def __iadd__(self, other):
342 self.value += other.value
343 return self
344
345 def __itruediv__(self, other):
346 if not other:
347 return self
348 self.value /= other
349 return self
350
351class Vector(Statistic,FormulaStat):
352 def getValue(self):
353 return source.data(self, self.bins, self.ticks);
354
355 def display(self):
356 import display
357 if not display.all and not (self.flags & flags.printable):
358 return
359
360 d = display.VectorDisplay()
361 d.__dict__.update(self.__dict__)
362 d.display()
363
364 def comparable(self, other):
365 return self.name == other.name and \
366 len(self.value) == len(other.value)
367
368 def __eq__(self, other):
369 if isinstance(self.value, (list, tuple)) != \
370 isinstance(other.value, (list, tuple)):
371 return False
372
373 if isinstance(self.value, (list, tuple)):
374 if len(self.value) != len(other.value):
375 return False
376 else:
377 for v1,v2 in zip(self.value, other.value):
378 if v1 != v2:
379 return False
380 return True
381 else:
382 return self.value == other.value
383
384 def __isub__(self, other):
385 self.value = binaryop(operator.sub, self.value, other.value)
386 return self
387
388 def __iadd__(self, other):
389 self.value = binaryop(operator.add, self.value, other.value)
390 return self
391
392 def __itruediv__(self, other):
393 if not other:
394 return self
395 if isinstance(self.value, (list, tuple)):
396 for i in xrange(len(self.value)):
397 self.value[i] /= other
398 else:
399 self.value /= other
400 return self
401
402class Formula(Vector):
403 def getValue(self):
404 formula = re.sub(':', '__', self.formula)
405 x = eval(formula, source.stattop)
406 return x.value
407
408 def comparable(self, other):
409 return self.name == other.name and \
410 compare(self.dist, other.dist)
411
412 def __eq__(self, other):
413 return self.value == other.value
414
415 def __isub__(self, other):
416 return self
417
418 def __iadd__(self, other):
419 return self
420
421 def __itruediv__(self, other):
422 if not other:
423 return self
424 return self
425
426class SimpleDist(object):
427 def __init__(self, sums, squares, samples):
428 self.sums = sums
429 self.squares = squares
430 self.samples = samples
431
432 def getValue(self):
433 return 0.0
434
435 def display(self, name, desc, flags, precision):
436 import display
437 p = display.Print()
438 p.flags = flags
439 p.precision = precision
440
441 if self.samples > 0:
442 p.name = name + ".mean"
443 p.value = self.sums / self.samples
444 p.display()
445
446 p.name = name + ".stdev"
447 if self.samples > 1:
448 var = (self.samples * self.squares - self.sums ** 2) \
449 / (self.samples * (self.samples - 1))
450 if var >= 0:
451 p.value = math.sqrt(var)
452 else:
453 p.value = 'NaN'
454 else:
455 p.value = 0.0
456 p.display()
457
458 p.name = name + ".samples"
459 p.value = self.samples
460 p.display()
461
462 def comparable(self, other):
463 return True
464
465 def __eq__(self, other):
466 return self.sums == other.sums and self.squares == other.squares and \
467 self.samples == other.samples
468
469 def __isub__(self, other):
470 self.sums -= other.sums
471 self.squares -= other.squares
472 self.samples -= other.samples
473 return self
474
475 def __iadd__(self, other):
476 self.sums += other.sums
477 self.squares += other.squares
478 self.samples += other.samples
479 return self
480
481 def __itruediv__(self, other):
482 if not other:
483 return self
484 self.sums /= other
485 self.squares /= other
486 self.samples /= other
487 return self
488
489class FullDist(SimpleDist):
490 def __init__(self, sums, squares, samples, minval, maxval,
491 under, vec, over, min, max, bsize, size):
492 self.sums = sums
493 self.squares = squares
494 self.samples = samples
495 self.minval = minval
496 self.maxval = maxval
497 self.under = under
498 self.vec = vec
499 self.over = over
500 self.min = min
501 self.max = max
502 self.bsize = bsize
503 self.size = size
504
505 def getValue(self):
506 return 0.0
507
508 def display(self, name, desc, flags, precision):
509 import display
510 p = display.Print()
511 p.flags = flags
512 p.precision = precision
513
514 p.name = name + '.min_val'
515 p.value = self.minval
516 p.display()
517
518 p.name = name + '.max_val'
519 p.value = self.maxval
520 p.display()
521
522 p.name = name + '.underflow'
523 p.value = self.under
524 p.display()
525
526 i = self.min
527 for val in self.vec[:-1]:
528 p.name = name + '[%d:%d]' % (i, i + self.bsize - 1)
529 p.value = val
530 p.display()
531 i += self.bsize
532
533 p.name = name + '[%d:%d]' % (i, self.max)
534 p.value = self.vec[-1]
535 p.display()
536
537
538 p.name = name + '.overflow'
539 p.value = self.over
540 p.display()
541
542 SimpleDist.display(self, name, desc, flags, precision)
543
544 def comparable(self, other):
545 return self.min == other.min and self.max == other.max and \
546 self.bsize == other.bsize and self.size == other.size
547
548 def __eq__(self, other):
549 return self.sums == other.sums and self.squares == other.squares and \
550 self.samples == other.samples
551
552 def __isub__(self, other):
553 self.sums -= other.sums
554 self.squares -= other.squares
555 self.samples -= other.samples
556
557 if other.samples:
558 self.minval = min(self.minval, other.minval)
559 self.maxval = max(self.maxval, other.maxval)
560 self.under -= under
561 self.vec = map(lambda x,y: x - y, self.vec, other.vec)
562 self.over -= over
563 return self
564
565 def __iadd__(self, other):
566 if not self.samples and other.samples:
567 self = other
568 return self
569
570 self.sums += other.sums
571 self.squares += other.squares
572 self.samples += other.samples
573
574 if other.samples:
575 self.minval = min(self.minval, other.minval)
576 self.maxval = max(self.maxval, other.maxval)
577 self.under += other.under
578 self.vec = map(lambda x,y: x + y, self.vec, other.vec)
579 self.over += other.over
580 return self
581
582 def __itruediv__(self, other):
583 if not other:
584 return self
585 self.sums /= other
586 self.squares /= other
587 self.samples /= other
588
589 if self.samples:
590 self.under /= other
591 for i in xrange(len(self.vec)):
592 self.vec[i] /= other
593 self.over /= other
594 return self
595
596class Dist(Statistic):
597 def getValue(self):
598 return 0.0
599
600 def display(self):
601 import display
602 if not display.all and not (self.flags & flags.printable):
603 return
604
605 self.dist.display(self.name, self.desc, self.flags, self.precision)
606
607 def comparable(self, other):
608 return self.name == other.name and \
609 self.dist.compareable(other.dist)
610
611 def __eq__(self, other):
612 return self.dist == other.dist
613
614 def __isub__(self, other):
615 self.dist -= other.dist
616 return self
617
618 def __iadd__(self, other):
619 self.dist += other.dist
620 return self
621
622 def __itruediv__(self, other):
623 if not other:
624 return self
625 self.dist /= other
626 return self
627
628class VectorDist(Statistic):
629 def getValue(self):
630 return 0.0
631
632 def display(self):
633 import display
634 if not display.all and not (self.flags & flags.printable):
635 return
636
637 if isinstance(self.dist, SimpleDist):
638 return
639
640 for dist,sn,sd,i in map(None, self.dist, self.subnames, self.subdescs,
641 range(len(self.dist))):
642 if len(sn) > 0:
643 name = '%s.%s' % (self.name, sn)
644 else:
645 name = '%s[%d]' % (self.name, i)
646
647 if len(sd) > 0:
648 desc = sd
649 else:
650 desc = self.desc
651
652 dist.display(name, desc, self.flags, self.precision)
653
654 if (self.flags & flags.total) or 1:
655 if isinstance(self.dist[0], SimpleDist):
656 disttotal = SimpleDist( \
657 reduce(sums, [d.sums for d in self.dist]),
658 reduce(sums, [d.squares for d in self.dist]),
659 reduce(sums, [d.samples for d in self.dist]))
660 else:
661 disttotal = FullDist( \
662 reduce(sums, [d.sums for d in self.dist]),
663 reduce(sums, [d.squares for d in self.dist]),
664 reduce(sums, [d.samples for d in self.dist]),
665 min([d.minval for d in self.dist]),
666 max([d.maxval for d in self.dist]),
667 reduce(sums, [d.under for d in self.dist]),
668 reduce(sums, [d.vec for d in self.dist]),
669 reduce(sums, [d.over for d in self.dist]),
670 dist[0].min,
671 dist[0].max,
672 dist[0].bsize,
673 dist[0].size)
674
675 name = '%s.total' % (self.name)
676 desc = self.desc
677 disttotal.display(name, desc, self.flags, self.precision)
678
679 def comparable(self, other):
680 return self.name == other.name and \
681 alltrue(map(lambda x, y : x.comparable(y),
682 self.dist,
683 other.dist))
684
685 def __eq__(self, other):
686 return alltrue(map(lambda x, y : x == y, self.dist, other.dist))
687
688 def __isub__(self, other):
689 if isinstance(self.dist, (list, tuple)) and \
690 isinstance(other.dist, (list, tuple)):
691 for sd,od in zip(self.dist, other.dist):
692 sd -= od
693 else:
694 self.dist -= other.dist
695 return self
696
697 def __iadd__(self, other):
698 if isinstance(self.dist, (list, tuple)) and \
699 isinstance(other.dist, (list, tuple)):
700 for sd,od in zip(self.dist, other.dist):
701 sd += od
702 else:
703 self.dist += other.dist
704 return self
705
706 def __itruediv__(self, other):
707 if not other:
708 return self
709 if isinstance(self.dist, (list, tuple)):
710 for dist in self.dist:
711 dist /= other
712 else:
713 self.dist /= other
714 return self
715
716class Vector2d(Statistic):
717 def getValue(self):
718 return 0.0
719
720 def display(self):
721 import display
722 if not display.all and not (self.flags & flags.printable):
723 return
724
725 d = display.VectorDisplay()
726 d.__dict__.update(self.__dict__)
727
728 if self.__dict__.has_key('ysubnames'):
729 ysubnames = list(self.ysubnames)
730 slack = self.x - len(ysubnames)
731 if slack > 0:
732 ysubnames.extend(['']*slack)
733 else:
734 ysubnames = range(self.x)
735
736 for x,sname in enumerate(ysubnames):
737 o = x * self.y
738 d.value = self.value[o:o+self.y]
739 d.name = '%s[%s]' % (self.name, sname)
740 d.display()
741
742 if self.flags & flags.total:
743 d.value = []
744 for y in range(self.y):
745 xtot = 0.0
746 for x in range(self.x):
747 xtot += self.value[y + x * self.x]
748 d.value.append(xtot)
749
750 d.name = self.name + '.total'
751 d.display()
752
753 def comparable(self, other):
754 return self.name == other.name and self.x == other.x and \
755 self.y == other.y
756
757 def __eq__(self, other):
758 return True
759
760 def __isub__(self, other):
761 return self
762
763 def __iadd__(self, other):
764 return self
765
766 def __itruediv__(self, other):
767 if not other:
768 return self
769 return self
770
771def NewStat(data):
772 stat = None
773 if data.type == 'SCALAR':
774 stat = Scalar(data)
775 elif data.type == 'VECTOR':
776 stat = Vector(data)
777 elif data.type == 'DIST':
778 stat = Dist(data)
779 elif data.type == 'VECTORDIST':
780 stat = VectorDist(data)
781 elif data.type == 'VECTOR2D':
782 stat = Vector2d(data)
783 elif data.type == 'FORMULA':
784 stat = Formula(data)
785
786 return stat
787
27from __future__ import division
28import operator, re, types
29
30source = None
31display_run = 0
32global globalTicks
33globalTicks = None
34
35def total(f):
36 if isinstance(f, FormulaStat):
37 v = f.value
38 else:
39 v = f
40
41 f = FormulaStat()
42 if isinstance(v, (list, tuple)):
43 f.value = reduce(operator.add, v)
44 else:
45 f.value = v
46
47 return f
48
49def unaryop(op, f):
50 if isinstance(f, FormulaStat):
51 v = f.value
52 else:
53 v = f
54
55 if isinstance(v, (list, tuple)):
56 return map(op, v)
57 else:
58 return op(v)
59
60def zerodiv(lv, rv):
61 if rv == 0.0:
62 return 0.0
63 else:
64 return operator.truediv(lv, rv)
65
66def wrapop(op, lv, rv):
67 if isinstance(lv, str):
68 return lv
69
70 if isinstance(rv, str):
71 return rv
72
73 return op(lv, rv)
74
75def same(lrun, rrun):
76 for lx,rx in zip(lrun.keys(),rrun.keys()):
77 if lx != rx:
78 print 'lx != rx'
79 print lx, rx
80 print lrun.keys()
81 print rrun.keys()
82 return False
83 for ly,ry in zip(lrun[lx].keys(),rrun[rx].keys()):
84 if ly != ry:
85 print 'ly != ry'
86 print ly, ry
87 print lrun[lx].keys()
88 print rrun[rx].keys()
89 return False
90 return True
91
92
93def binaryop(op, lf, rf):
94 result = {}
95
96 if isinstance(lf, FormulaStat) and isinstance(rf, FormulaStat):
97 lv = lf.value
98 rv = rf.value
99
100 theruns = []
101 for r in lv.keys():
102 if rv.has_key(r):
103 if same(lv[r], rv[r]):
104 theruns.append(r)
105 else:
106 raise AttributeError
107
108 for run in theruns:
109 result[run] = {}
110 for x in lv[run].keys():
111 result[run][x] = {}
112 for y in lv[run][x].keys():
113 result[run][x][y] = wrapop(op, lv[run][x][y],
114 rv[run][x][y])
115 elif isinstance(lf, FormulaStat):
116 lv = lf.value
117 for run in lv.keys():
118 result[run] = {}
119 for x in lv[run].keys():
120 result[run][x] = {}
121 for y in lv[run][x].keys():
122 result[run][x][y] = wrapop(op, lv[run][x][y], rf)
123 elif isinstance(rf, FormulaStat):
124 rv = rf.value
125 for run in rv.keys():
126 result[run] = {}
127 for x in rv[run].keys():
128 result[run][x] = {}
129 for y in rv[run][x].keys():
130 result[run][x][y] = wrapop(op, lf, rv[run][x][y])
131
132 return result
133
134def sums(x, y):
135 if isinstance(x, (list, tuple)):
136 return map(lambda x, y: x + y, x, y)
137 else:
138 return x + y
139
140def alltrue(seq):
141 return reduce(lambda x, y: x and y, seq)
142
143def allfalse(seq):
144 return not reduce(lambda x, y: x or y, seq)
145
146def enumerate(seq):
147 return map(None, range(len(seq)), seq)
148
149def cmp(a, b):
150 if a < b:
151 return -1
152 elif a == b:
153 return 0
154 else:
155 return 1
156
157class Statistic(object):
158
159 def __init__(self, data):
160 self.__dict__.update(data.__dict__)
161 if not self.__dict__.has_key('value'):
162 self.__dict__['value'] = None
163 if not self.__dict__.has_key('bins'):
164 self.__dict__['bins'] = None
165 if not self.__dict__.has_key('ticks'):
166 self.__dict__['ticks'] = None
167 if 'vc' not in self.__dict__:
168 self.vc = {}
169
170 def __getattribute__(self, attr):
171 if attr == 'ticks':
172 if self.__dict__['ticks'] != globalTicks:
173 self.__dict__['value'] = None
174 self.__dict__['ticks'] = globalTicks
175 return self.__dict__['ticks']
176 if attr == 'value':
177 if self.__dict__['ticks'] != globalTicks:
178 if self.__dict__['ticks'] != None and \
179 len(self.__dict__['ticks']) == 1:
180 self.vc[self.__dict__['ticks'][0]] = self.__dict__['value']
181 self.__dict__['ticks'] = globalTicks
182 if len(globalTicks) == 1 and self.vc.has_key(globalTicks[0]):
183 self.__dict__['value'] = self.vc[globalTicks[0]]
184 else:
185 self.__dict__['value'] = None
186 if self.__dict__['value'] == None:
187 self.__dict__['value'] = self.getValue()
188 return self.__dict__['value']
189 else:
190 return super(Statistic, self).__getattribute__(attr)
191
192 def __setattr__(self, attr, value):
193 if attr == 'bins' or attr == 'ticks':
194 if attr == 'bins':
195 if value is not None:
196 value = source.getBin(value)
197 #elif attr == 'ticks' and type(value) is str:
198 # value = [ int(x) for x in value.split() ]
199
200 self.__dict__[attr] = value
201 self.__dict__['value'] = None
202 self.vc = {}
203 else:
204 super(Statistic, self).__setattr__(attr, value)
205
206 def getValue(self):
207 raise AttributeError, 'getValue() must be defined'
208
209 def zero(self):
210 return False
211
212 def __ne__(self, other):
213 return not (self == other)
214
215 def __str__(self):
216 return '%f' % (float(self))
217
218class FormulaStat(object):
219 def __add__(self, other):
220 f = FormulaStat()
221 f.value = binaryop(operator.add, self, other)
222 return f
223 def __sub__(self, other):
224 f = FormulaStat()
225 f.value = binaryop(operator.sub, self, other)
226 return f
227 def __mul__(self, other):
228 f = FormulaStat()
229 f.value = binaryop(operator.mul, self, other)
230 return f
231 def __truediv__(self, other):
232 f = FormulaStat()
233 f.value = binaryop(zerodiv, self, other)
234 return f
235 def __mod__(self, other):
236 f = FormulaStat()
237 f.value = binaryop(operator.mod, self, other)
238 return f
239 def __radd__(self, other):
240 f = FormulaStat()
241 f.value = binaryop(operator.add, other, self)
242 return f
243 def __rsub__(self, other):
244 f = FormulaStat()
245 f.value = binaryop(operator.sub, other, self)
246 return f
247 def __rmul__(self, other):
248 f = FormulaStat()
249 f.value = binaryop(operator.mul, other, self)
250 return f
251 def __rtruediv__(self, other):
252 f = FormulaStat()
253 f.value = binaryop(zerodiv, other, self)
254 return f
255 def __rmod__(self, other):
256 f = FormulaStat()
257 f.value = binaryop(operator.mod, other, self)
258 return f
259 def __neg__(self):
260 f = FormulaStat()
261 f.value = unaryop(operator.neg, self)
262 return f
263 def __getitem__(self, idx):
264 f = FormulaStat()
265 f.value = {}
266 for key in self.value.keys():
267 f.value[key] = {}
268 f.value[key][0] = {}
269 f.value[key][0][0] = self.value[key][idx][0]
270 return f
271
272 def __float__(self):
273 if isinstance(self.value, FormulaStat):
274 return float(self.value)
275 if not self.value.has_key(display_run):
276 return (1e300*1e300)
277 if len(self.value[display_run]) == 1:
278 return self.value[display_run][0][0]
279 else:
280 #print self.value[display_run]
281 return self.value[display_run][4][0]
282 #raise ValueError
283
284 def display(self):
285 import display
286 d = display.VectorDisplay()
287 d.flags = 0
288 d.precision = 1
289 d.name = 'formula'
290 d.desc = 'formula'
291 val = self.value[display_run]
292 d.value = [ val[x][0] for x in val.keys() ]
293 d.display()
294
295
296class Scalar(Statistic,FormulaStat):
297 def getValue(self):
298 return source.data(self, self.bins, self.ticks)
299
300 def display(self):
301 import display
302 p = display.Print()
303 p.name = self.name
304 p.desc = self.desc
305 p.value = float(self)
306 p.flags = self.flags
307 p.precision = self.precision
308 if display.all or (self.flags & flags.printable):
309 p.display()
310
311 def comparable(self, other):
312 return self.name == other.name
313
314 def __eq__(self, other):
315 return self.value == other.value
316
317 def __isub__(self, other):
318 self.value -= other.value
319 return self
320
321 def __iadd__(self, other):
322 self.value += other.value
323 return self
324
325 def __itruediv__(self, other):
326 if not other:
327 return self
328 self.value /= other
329 return self
330
331class Vector(Statistic,FormulaStat):
332 def getValue(self):
333 return source.data(self, self.bins, self.ticks);
334
335 def display(self):
336 import display
337 if not display.all and not (self.flags & flags.printable):
338 return
339
340 d = display.VectorDisplay()
341 d.__dict__.update(self.__dict__)
342 d.display()
343
344 def comparable(self, other):
345 return self.name == other.name and \
346 len(self.value) == len(other.value)
347
348 def __eq__(self, other):
349 if isinstance(self.value, (list, tuple)) != \
350 isinstance(other.value, (list, tuple)):
351 return False
352
353 if isinstance(self.value, (list, tuple)):
354 if len(self.value) != len(other.value):
355 return False
356 else:
357 for v1,v2 in zip(self.value, other.value):
358 if v1 != v2:
359 return False
360 return True
361 else:
362 return self.value == other.value
363
364 def __isub__(self, other):
365 self.value = binaryop(operator.sub, self.value, other.value)
366 return self
367
368 def __iadd__(self, other):
369 self.value = binaryop(operator.add, self.value, other.value)
370 return self
371
372 def __itruediv__(self, other):
373 if not other:
374 return self
375 if isinstance(self.value, (list, tuple)):
376 for i in xrange(len(self.value)):
377 self.value[i] /= other
378 else:
379 self.value /= other
380 return self
381
382class Formula(Vector):
383 def getValue(self):
384 formula = re.sub(':', '__', self.formula)
385 x = eval(formula, source.stattop)
386 return x.value
387
388 def comparable(self, other):
389 return self.name == other.name and \
390 compare(self.dist, other.dist)
391
392 def __eq__(self, other):
393 return self.value == other.value
394
395 def __isub__(self, other):
396 return self
397
398 def __iadd__(self, other):
399 return self
400
401 def __itruediv__(self, other):
402 if not other:
403 return self
404 return self
405
406class SimpleDist(object):
407 def __init__(self, sums, squares, samples):
408 self.sums = sums
409 self.squares = squares
410 self.samples = samples
411
412 def getValue(self):
413 return 0.0
414
415 def display(self, name, desc, flags, precision):
416 import display
417 p = display.Print()
418 p.flags = flags
419 p.precision = precision
420
421 if self.samples > 0:
422 p.name = name + ".mean"
423 p.value = self.sums / self.samples
424 p.display()
425
426 p.name = name + ".stdev"
427 if self.samples > 1:
428 var = (self.samples * self.squares - self.sums ** 2) \
429 / (self.samples * (self.samples - 1))
430 if var >= 0:
431 p.value = math.sqrt(var)
432 else:
433 p.value = 'NaN'
434 else:
435 p.value = 0.0
436 p.display()
437
438 p.name = name + ".samples"
439 p.value = self.samples
440 p.display()
441
442 def comparable(self, other):
443 return True
444
445 def __eq__(self, other):
446 return self.sums == other.sums and self.squares == other.squares and \
447 self.samples == other.samples
448
449 def __isub__(self, other):
450 self.sums -= other.sums
451 self.squares -= other.squares
452 self.samples -= other.samples
453 return self
454
455 def __iadd__(self, other):
456 self.sums += other.sums
457 self.squares += other.squares
458 self.samples += other.samples
459 return self
460
461 def __itruediv__(self, other):
462 if not other:
463 return self
464 self.sums /= other
465 self.squares /= other
466 self.samples /= other
467 return self
468
469class FullDist(SimpleDist):
470 def __init__(self, sums, squares, samples, minval, maxval,
471 under, vec, over, min, max, bsize, size):
472 self.sums = sums
473 self.squares = squares
474 self.samples = samples
475 self.minval = minval
476 self.maxval = maxval
477 self.under = under
478 self.vec = vec
479 self.over = over
480 self.min = min
481 self.max = max
482 self.bsize = bsize
483 self.size = size
484
485 def getValue(self):
486 return 0.0
487
488 def display(self, name, desc, flags, precision):
489 import display
490 p = display.Print()
491 p.flags = flags
492 p.precision = precision
493
494 p.name = name + '.min_val'
495 p.value = self.minval
496 p.display()
497
498 p.name = name + '.max_val'
499 p.value = self.maxval
500 p.display()
501
502 p.name = name + '.underflow'
503 p.value = self.under
504 p.display()
505
506 i = self.min
507 for val in self.vec[:-1]:
508 p.name = name + '[%d:%d]' % (i, i + self.bsize - 1)
509 p.value = val
510 p.display()
511 i += self.bsize
512
513 p.name = name + '[%d:%d]' % (i, self.max)
514 p.value = self.vec[-1]
515 p.display()
516
517
518 p.name = name + '.overflow'
519 p.value = self.over
520 p.display()
521
522 SimpleDist.display(self, name, desc, flags, precision)
523
524 def comparable(self, other):
525 return self.min == other.min and self.max == other.max and \
526 self.bsize == other.bsize and self.size == other.size
527
528 def __eq__(self, other):
529 return self.sums == other.sums and self.squares == other.squares and \
530 self.samples == other.samples
531
532 def __isub__(self, other):
533 self.sums -= other.sums
534 self.squares -= other.squares
535 self.samples -= other.samples
536
537 if other.samples:
538 self.minval = min(self.minval, other.minval)
539 self.maxval = max(self.maxval, other.maxval)
540 self.under -= under
541 self.vec = map(lambda x,y: x - y, self.vec, other.vec)
542 self.over -= over
543 return self
544
545 def __iadd__(self, other):
546 if not self.samples and other.samples:
547 self = other
548 return self
549
550 self.sums += other.sums
551 self.squares += other.squares
552 self.samples += other.samples
553
554 if other.samples:
555 self.minval = min(self.minval, other.minval)
556 self.maxval = max(self.maxval, other.maxval)
557 self.under += other.under
558 self.vec = map(lambda x,y: x + y, self.vec, other.vec)
559 self.over += other.over
560 return self
561
562 def __itruediv__(self, other):
563 if not other:
564 return self
565 self.sums /= other
566 self.squares /= other
567 self.samples /= other
568
569 if self.samples:
570 self.under /= other
571 for i in xrange(len(self.vec)):
572 self.vec[i] /= other
573 self.over /= other
574 return self
575
576class Dist(Statistic):
577 def getValue(self):
578 return 0.0
579
580 def display(self):
581 import display
582 if not display.all and not (self.flags & flags.printable):
583 return
584
585 self.dist.display(self.name, self.desc, self.flags, self.precision)
586
587 def comparable(self, other):
588 return self.name == other.name and \
589 self.dist.compareable(other.dist)
590
591 def __eq__(self, other):
592 return self.dist == other.dist
593
594 def __isub__(self, other):
595 self.dist -= other.dist
596 return self
597
598 def __iadd__(self, other):
599 self.dist += other.dist
600 return self
601
602 def __itruediv__(self, other):
603 if not other:
604 return self
605 self.dist /= other
606 return self
607
608class VectorDist(Statistic):
609 def getValue(self):
610 return 0.0
611
612 def display(self):
613 import display
614 if not display.all and not (self.flags & flags.printable):
615 return
616
617 if isinstance(self.dist, SimpleDist):
618 return
619
620 for dist,sn,sd,i in map(None, self.dist, self.subnames, self.subdescs,
621 range(len(self.dist))):
622 if len(sn) > 0:
623 name = '%s.%s' % (self.name, sn)
624 else:
625 name = '%s[%d]' % (self.name, i)
626
627 if len(sd) > 0:
628 desc = sd
629 else:
630 desc = self.desc
631
632 dist.display(name, desc, self.flags, self.precision)
633
634 if (self.flags & flags.total) or 1:
635 if isinstance(self.dist[0], SimpleDist):
636 disttotal = SimpleDist( \
637 reduce(sums, [d.sums for d in self.dist]),
638 reduce(sums, [d.squares for d in self.dist]),
639 reduce(sums, [d.samples for d in self.dist]))
640 else:
641 disttotal = FullDist( \
642 reduce(sums, [d.sums for d in self.dist]),
643 reduce(sums, [d.squares for d in self.dist]),
644 reduce(sums, [d.samples for d in self.dist]),
645 min([d.minval for d in self.dist]),
646 max([d.maxval for d in self.dist]),
647 reduce(sums, [d.under for d in self.dist]),
648 reduce(sums, [d.vec for d in self.dist]),
649 reduce(sums, [d.over for d in self.dist]),
650 dist[0].min,
651 dist[0].max,
652 dist[0].bsize,
653 dist[0].size)
654
655 name = '%s.total' % (self.name)
656 desc = self.desc
657 disttotal.display(name, desc, self.flags, self.precision)
658
659 def comparable(self, other):
660 return self.name == other.name and \
661 alltrue(map(lambda x, y : x.comparable(y),
662 self.dist,
663 other.dist))
664
665 def __eq__(self, other):
666 return alltrue(map(lambda x, y : x == y, self.dist, other.dist))
667
668 def __isub__(self, other):
669 if isinstance(self.dist, (list, tuple)) and \
670 isinstance(other.dist, (list, tuple)):
671 for sd,od in zip(self.dist, other.dist):
672 sd -= od
673 else:
674 self.dist -= other.dist
675 return self
676
677 def __iadd__(self, other):
678 if isinstance(self.dist, (list, tuple)) and \
679 isinstance(other.dist, (list, tuple)):
680 for sd,od in zip(self.dist, other.dist):
681 sd += od
682 else:
683 self.dist += other.dist
684 return self
685
686 def __itruediv__(self, other):
687 if not other:
688 return self
689 if isinstance(self.dist, (list, tuple)):
690 for dist in self.dist:
691 dist /= other
692 else:
693 self.dist /= other
694 return self
695
696class Vector2d(Statistic):
697 def getValue(self):
698 return 0.0
699
700 def display(self):
701 import display
702 if not display.all and not (self.flags & flags.printable):
703 return
704
705 d = display.VectorDisplay()
706 d.__dict__.update(self.__dict__)
707
708 if self.__dict__.has_key('ysubnames'):
709 ysubnames = list(self.ysubnames)
710 slack = self.x - len(ysubnames)
711 if slack > 0:
712 ysubnames.extend(['']*slack)
713 else:
714 ysubnames = range(self.x)
715
716 for x,sname in enumerate(ysubnames):
717 o = x * self.y
718 d.value = self.value[o:o+self.y]
719 d.name = '%s[%s]' % (self.name, sname)
720 d.display()
721
722 if self.flags & flags.total:
723 d.value = []
724 for y in range(self.y):
725 xtot = 0.0
726 for x in range(self.x):
727 xtot += self.value[y + x * self.x]
728 d.value.append(xtot)
729
730 d.name = self.name + '.total'
731 d.display()
732
733 def comparable(self, other):
734 return self.name == other.name and self.x == other.x and \
735 self.y == other.y
736
737 def __eq__(self, other):
738 return True
739
740 def __isub__(self, other):
741 return self
742
743 def __iadd__(self, other):
744 return self
745
746 def __itruediv__(self, other):
747 if not other:
748 return self
749 return self
750
751def NewStat(data):
752 stat = None
753 if data.type == 'SCALAR':
754 stat = Scalar(data)
755 elif data.type == 'VECTOR':
756 stat = Vector(data)
757 elif data.type == 'DIST':
758 stat = Dist(data)
759 elif data.type == 'VECTORDIST':
760 stat = VectorDist(data)
761 elif data.type == 'VECTOR2D':
762 stat = Vector2d(data)
763 elif data.type == 'FORMULA':
764 stat = Formula(data)
765
766 return stat
767