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