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