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