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