info.py revision 1772:a3a83e812a5e
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 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 768