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