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