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