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