1 # Copyright (c) 2003-2004 The Regents of The University of Michigan
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.
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.
27 from __future__
import division
28 import operator
, re
, types
36 if isinstance(f
, FormulaStat
):
42 if isinstance(v
, (list, tuple)):
43 f
.value
= reduce(operator
.add
, v
)
50 if isinstance(f
, FormulaStat
):
55 if isinstance(v
, (list, tuple)):
64 return operator
.truediv(lv
, rv
)
66 def wrapop(op
, lv
, rv
):
67 if isinstance(lv
, str):
70 if isinstance(rv
, str):
76 for lx
,rx
in zip(lrun
.keys(),rrun
.keys()):
83 for ly
,ry
in zip(lrun
[lx
].keys(),rrun
[rx
].keys()):
93 def binaryop(op
, lf
, rf
):
96 if isinstance(lf
, FormulaStat
) and isinstance(rf
, FormulaStat
):
103 if same(lv
[r
], rv
[r
]):
110 for x
in lv
[run
].keys():
112 for y
in lv
[run
][x
].keys():
113 result
[run
][x
][y
] = wrapop(op
, lv
[run
][x
][y
],
115 elif isinstance(lf
, FormulaStat
):
117 for run
in lv
.keys():
119 for x
in lv
[run
].keys():
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
):
125 for run
in rv
.keys():
127 for x
in rv
[run
].keys():
129 for y
in rv
[run
][x
].keys():
130 result
[run
][x
][y
] = wrapop(op
, lf
, rv
[run
][x
][y
])
135 if isinstance(x
, (list, tuple)):
136 return map(lambda x
, y
: x
+ y
, x
, y
)
141 return reduce(lambda x
, y
: x
and y
, seq
)
144 return not reduce(lambda x
, y
: x
or y
, seq
)
147 return map(None, range(len(seq
)), seq
)
157 class Statistic(object):
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
__:
170 def __getattribute__(self
, attr
):
172 if self
.__dict
__['ticks'] != globalTicks
:
173 self
.__dict
__['value'] = None
174 self
.__dict
__['ticks'] = globalTicks
175 return self
.__dict
__['ticks']
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]]
185 self
.__dict
__['value'] = None
186 if self
.__dict
__['value'] == None:
187 self
.__dict
__['value'] = self
.getValue()
188 return self
.__dict
__['value']
190 return super(Statistic
, self
).__getattribute
__(attr
)
192 def __setattr__(self
, attr
, value
):
193 if attr
== 'bins' or attr
== 'ticks':
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() ]
200 self
.__dict
__[attr
] = value
201 self
.__dict
__['value'] = None
204 super(Statistic
, self
).__setattr
__(attr
, value
)
207 raise AttributeError, 'getValue() must be defined'
212 def __ne__(self
, other
):
213 return not (self
== other
)
216 return '%f' % (float(self
))
218 class FormulaStat(object):
219 def __add__(self
, other
):
221 f
.value
= binaryop(operator
.add
, self
, other
)
223 def __sub__(self
, other
):
225 f
.value
= binaryop(operator
.sub
, self
, other
)
227 def __mul__(self
, other
):
229 f
.value
= binaryop(operator
.mul
, self
, other
)
231 def __truediv__(self
, other
):
233 f
.value
= binaryop(zerodiv
, self
, other
)
235 def __mod__(self
, other
):
237 f
.value
= binaryop(operator
.mod
, self
, other
)
239 def __radd__(self
, other
):
241 f
.value
= binaryop(operator
.add
, other
, self
)
243 def __rsub__(self
, other
):
245 f
.value
= binaryop(operator
.sub
, other
, self
)
247 def __rmul__(self
, other
):
249 f
.value
= binaryop(operator
.mul
, other
, self
)
251 def __rtruediv__(self
, other
):
253 f
.value
= binaryop(zerodiv
, other
, self
)
255 def __rmod__(self
, other
):
257 f
.value
= binaryop(operator
.mod
, other
, self
)
261 f
.value
= unaryop(operator
.neg
, self
)
263 def __getitem__(self
, idx
):
266 for key
in self
.value
.keys():
269 f
.value
[key
][0][0] = self
.value
[key
][idx
][0]
273 if isinstance(self
.value
, FormulaStat
):
274 return float(self
.value
)
275 if not self
.value
.has_key(display_run
):
277 if len(self
.value
[display_run
]) == 1:
278 return self
.value
[display_run
][0][0]
280 #print self.value[display_run]
281 return self
.value
[display_run
][4][0]
286 d
= display
.VectorDisplay()
291 val
= self
.value
[display_run
]
292 d
.value
= [ val
[x
][0] for x
in val
.keys() ]
296 class Scalar(Statistic
,FormulaStat
):
298 return source
.data(self
, self
.bins
, self
.ticks
)
305 p
.value
= float(self
)
307 p
.precision
= self
.precision
308 if display
.all
or (self
.flags
& flags
.printable
):
311 def comparable(self
, other
):
312 return self
.name
== other
.name
314 def __eq__(self
, other
):
315 return self
.value
== other
.value
317 def __isub__(self
, other
):
318 self
.value
-= other
.value
321 def __iadd__(self
, other
):
322 self
.value
+= other
.value
325 def __itruediv__(self
, other
):
331 class Vector(Statistic
,FormulaStat
):
333 return source
.data(self
, self
.bins
, self
.ticks
);
337 if not display
.all
and not (self
.flags
& flags
.printable
):
340 d
= display
.VectorDisplay()
341 d
.__dict
__.update(self
.__dict
__)
344 def comparable(self
, other
):
345 return self
.name
== other
.name
and \
346 len(self
.value
) == len(other
.value
)
348 def __eq__(self
, other
):
349 if isinstance(self
.value
, (list, tuple)) != \
350 isinstance(other
.value
, (list, tuple)):
353 if isinstance(self
.value
, (list, tuple)):
354 if len(self
.value
) != len(other
.value
):
357 for v1
,v2
in zip(self
.value
, other
.value
):
362 return self
.value
== other
.value
364 def __isub__(self
, other
):
365 self
.value
= binaryop(operator
.sub
, self
.value
, other
.value
)
368 def __iadd__(self
, other
):
369 self
.value
= binaryop(operator
.add
, self
.value
, other
.value
)
372 def __itruediv__(self
, other
):
375 if isinstance(self
.value
, (list, tuple)):
376 for i
in xrange(len(self
.value
)):
377 self
.value
[i
] /= other
382 class Formula(Vector
):
384 formula
= re
.sub(':', '__', self
.formula
)
385 x
= eval(formula
, source
.stattop
)
388 def comparable(self
, other
):
389 return self
.name
== other
.name
and \
390 compare(self
.dist
, other
.dist
)
392 def __eq__(self
, other
):
393 return self
.value
== other
.value
395 def __isub__(self
, other
):
398 def __iadd__(self
, other
):
401 def __itruediv__(self
, other
):
406 class SimpleDist(object):
407 def __init__(self
, sums
, squares
, samples
):
409 self
.squares
= squares
410 self
.samples
= samples
415 def display(self
, name
, desc
, flags
, precision
):
419 p
.precision
= precision
422 p
.name
= name
+ ".mean"
423 p
.value
= self
.sums
/ self
.samples
426 p
.name
= name
+ ".stdev"
428 var
= (self
.samples
* self
.squares
- self
.sums
** 2) \
429 / (self
.samples
* (self
.samples
- 1))
431 p
.value
= math
.sqrt(var
)
438 p
.name
= name
+ ".samples"
439 p
.value
= self
.samples
442 def comparable(self
, other
):
445 def __eq__(self
, other
):
446 return self
.sums
== other
.sums
and self
.squares
== other
.squares
and \
447 self
.samples
== other
.samples
449 def __isub__(self
, other
):
450 self
.sums
-= other
.sums
451 self
.squares
-= other
.squares
452 self
.samples
-= other
.samples
455 def __iadd__(self
, other
):
456 self
.sums
+= other
.sums
457 self
.squares
+= other
.squares
458 self
.samples
+= other
.samples
461 def __itruediv__(self
, other
):
465 self
.squares
/= other
466 self
.samples
/= other
469 class FullDist(SimpleDist
):
470 def __init__(self
, sums
, squares
, samples
, minval
, maxval
,
471 under
, vec
, over
, min, max, bsize
, size
):
473 self
.squares
= squares
474 self
.samples
= samples
488 def display(self
, name
, desc
, flags
, precision
):
492 p
.precision
= precision
494 p
.name
= name
+ '.min_val'
495 p
.value
= self
.minval
498 p
.name
= name
+ '.max_val'
499 p
.value
= self
.maxval
502 p
.name
= name
+ '.underflow'
507 for val
in self
.vec
[:-1]:
508 p
.name
= name
+ '[%d:%d]' % (i
, i
+ self
.bsize
- 1)
513 p
.name
= name
+ '[%d:%d]' % (i
, self
.max)
514 p
.value
= self
.vec
[-1]
518 p
.name
= name
+ '.overflow'
522 SimpleDist
.display(self
, name
, desc
, flags
, precision
)
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
528 def __eq__(self
, other
):
529 return self
.sums
== other
.sums
and self
.squares
== other
.squares
and \
530 self
.samples
== other
.samples
532 def __isub__(self
, other
):
533 self
.sums
-= other
.sums
534 self
.squares
-= other
.squares
535 self
.samples
-= other
.samples
538 self
.minval
= min(self
.minval
, other
.minval
)
539 self
.maxval
= max(self
.maxval
, other
.maxval
)
541 self
.vec
= map(lambda x
,y
: x
- y
, self
.vec
, other
.vec
)
545 def __iadd__(self
, other
):
546 if not self
.samples
and other
.samples
:
550 self
.sums
+= other
.sums
551 self
.squares
+= other
.squares
552 self
.samples
+= 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
562 def __itruediv__(self
, other
):
566 self
.squares
/= other
567 self
.samples
/= other
571 for i
in xrange(len(self
.vec
)):
576 class Dist(Statistic
):
582 if not display
.all
and not (self
.flags
& flags
.printable
):
585 self
.dist
.display(self
.name
, self
.desc
, self
.flags
, self
.precision
)
587 def comparable(self
, other
):
588 return self
.name
== other
.name
and \
589 self
.dist
.compareable(other
.dist
)
591 def __eq__(self
, other
):
592 return self
.dist
== other
.dist
594 def __isub__(self
, other
):
595 self
.dist
-= other
.dist
598 def __iadd__(self
, other
):
599 self
.dist
+= other
.dist
602 def __itruediv__(self
, other
):
608 class VectorDist(Statistic
):
614 if not display
.all
and not (self
.flags
& flags
.printable
):
617 if isinstance(self
.dist
, SimpleDist
):
620 for dist
,sn
,sd
,i
in map(None, self
.dist
, self
.subnames
, self
.subdescs
,
621 range(len(self
.dist
))):
623 name
= '%s.%s' % (self
.name
, sn
)
625 name
= '%s[%d]' % (self
.name
, i
)
632 dist
.display(name
, desc
, self
.flags
, self
.precision
)
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
]))
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
]),
655 name
= '%s.total' % (self
.name
)
657 disttotal
.display(name
, desc
, self
.flags
, self
.precision
)
659 def comparable(self
, other
):
660 return self
.name
== other
.name
and \
661 alltrue(map(lambda x
, y
: x
.comparable(y
),
665 def __eq__(self
, other
):
666 return alltrue(map(lambda x
, y
: x
== y
, self
.dist
, other
.dist
))
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
):
674 self
.dist
-= other
.dist
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
):
683 self
.dist
+= other
.dist
686 def __itruediv__(self
, other
):
689 if isinstance(self
.dist
, (list, tuple)):
690 for dist
in self
.dist
:
696 class Vector2d(Statistic
):
702 if not display
.all
and not (self
.flags
& flags
.printable
):
705 d
= display
.VectorDisplay()
706 d
.__dict
__.update(self
.__dict
__)
708 if self
.__dict
__.has_key('ysubnames'):
709 ysubnames
= list(self
.ysubnames
)
710 slack
= self
.x
- len(ysubnames
)
712 ysubnames
.extend(['']*slack
)
714 ysubnames
= range(self
.x
)
716 for x
,sname
in enumerate(ysubnames
):
718 d
.value
= self
.value
[o
:o
+self
.y
]
719 d
.name
= '%s[%s]' % (self
.name
, sname
)
722 if self
.flags
& flags
.total
:
724 for y
in range(self
.y
):
726 for x
in range(self
.x
):
727 xtot
+= self
.value
[y
+ x
* self
.x
]
730 d
.name
= self
.name
+ '.total'
733 def comparable(self
, other
):
734 return self
.name
== other
.name
and self
.x
== other
.x
and \
737 def __eq__(self
, other
):
740 def __isub__(self
, other
):
743 def __iadd__(self
, other
):
746 def __itruediv__(self
, other
):
753 if data
.type == 'SCALAR':
755 elif data
.type == 'VECTOR':
757 elif data
.type == 'DIST':
759 elif data
.type == 'VECTORDIST':
760 stat
= VectorDist(data
)
761 elif data
.type == 'VECTOR2D':
762 stat
= Vector2d(data
)
763 elif data
.type == 'FORMULA':