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