diff --git a/docs/pyerrors/correlators.html b/docs/pyerrors/correlators.html index 3ee8379c..e5a8d81c 100644 --- a/docs/pyerrors/correlators.html +++ b/docs/pyerrors/correlators.html @@ -471,963 +471,967 @@ 258 "Eigenvector" - Use the method described in arXiv:2004.10472 [hep-lat] to find the set of v(t) belonging to the state. 259 The reference state is identified by its eigenvalue at t=ts 260 """ - 261 symmetric_corr = self.matrix_symmetric() - 262 if sorted_list is None: - 263 if (ts is None): - 264 raise Exception("ts is required if sorted_list=None") - 265 if (self.content[t0] is None) or (self.content[ts] is None): - 266 raise Exception("Corr not defined at t0/ts") - 267 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") - 268 for i in range(self.N): - 269 for j in range(self.N): - 270 G0[i, j] = symmetric_corr[t0][i, j].value - 271 Gt[i, j] = symmetric_corr[ts][i, j].value - 272 - 273 sp_vecs = _GEVP_solver(Gt, G0) - 274 sp_vec = sp_vecs[state] - 275 return sp_vec - 276 elif sorted_list in ["Eigenvalue", "Eigenvector"]: - 277 all_vecs = [] - 278 for t in range(self.T): - 279 try: - 280 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") - 281 for i in range(self.N): - 282 for j in range(self.N): - 283 G0[i, j] = symmetric_corr[t0][i, j].value - 284 Gt[i, j] = symmetric_corr[t][i, j].value - 285 - 286 sp_vecs = _GEVP_solver(Gt, G0) - 287 if sorted_list == "Eigenvalue": - 288 sp_vec = sp_vecs[state] - 289 all_vecs.append(sp_vec) - 290 else: - 291 all_vecs.append(sp_vecs) - 292 except Exception: - 293 all_vecs.append(None) - 294 if sorted_list == "Eigenvector": - 295 if (ts is None): - 296 raise Exception("ts is required for the Eigenvector sorting method.") - 297 all_vecs = _sort_vectors(all_vecs, ts) - 298 all_vecs = [a[state] for a in all_vecs] - 299 else: - 300 raise Exception("Unkown value for 'sorted_list'.") - 301 - 302 return all_vecs - 303 - 304 def Eigenvalue(self, t0, ts=None, state=0, sorted_list=None): - 305 """Determines the eigenvalue of the GEVP by solving and projecting the correlator - 306 - 307 Parameters - 308 ---------- - 309 t0 : int - 310 The time t0 for G(t)v= lambda G(t_0)v - 311 ts : int - 312 fixed time G(t_s)v= lambda G(t_0)v if return_list=False - 313 If return_list=True and sorting=Eigenvector it gives a reference point for the sorting method. - 314 state : int - 315 The state one is interested in ordered by energy. The lowest state is zero. - 316 sorted_list : string - 317 if this argument is set, a list of vectors (len=self.T) is returned. If it is left as None, only one vector is returned. - 318 "Eigenvalue" - The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice. - 319 "Eigenvector" - Use the method described in arXiv:2004.10472 [hep-lat] to find the set of v(t) belonging to the state. - 320 The reference state is identified by its eigenvalue at t=ts - 321 """ - 322 vec = self.GEVP(t0, ts=ts, state=state, sorted_list=sorted_list) - 323 return self.projected(vec) - 324 - 325 def Hankel(self, N, periodic=False): - 326 """Constructs an NxN Hankel matrix - 327 - 328 C(t) c(t+1) ... c(t+n-1) - 329 C(t+1) c(t+2) ... c(t+n) - 330 ................. - 331 C(t+(n-1)) c(t+n) ... c(t+2(n-1)) - 332 - 333 Parameters - 334 ---------- - 335 N : int - 336 Dimension of the Hankel matrix - 337 periodic : bool, optional - 338 determines whether the matrix is extended periodically - 339 """ - 340 - 341 if self.N != 1: - 342 raise Exception("Multi-operator Prony not implemented!") - 343 - 344 array = np.empty([N, N], dtype="object") - 345 new_content = [] - 346 for t in range(self.T): - 347 new_content.append(array.copy()) - 348 - 349 def wrap(i): - 350 while i >= self.T: - 351 i -= self.T - 352 return i - 353 - 354 for t in range(self.T): - 355 for i in range(N): - 356 for j in range(N): - 357 if periodic: - 358 new_content[t][i, j] = self.content[wrap(t + i + j)][0] - 359 elif (t + i + j) >= self.T: - 360 new_content[t] = None - 361 else: - 362 new_content[t][i, j] = self.content[t + i + j][0] - 363 - 364 return Corr(new_content) - 365 - 366 def roll(self, dt): - 367 """Periodically shift the correlator by dt timeslices - 368 - 369 Parameters - 370 ---------- - 371 dt : int - 372 number of timeslices - 373 """ - 374 return Corr(list(np.roll(np.array(self.content, dtype=object), dt))) - 375 - 376 def reverse(self): - 377 """Reverse the time ordering of the Corr""" - 378 return Corr(self.content[:: -1]) + 261 + 262 if self.N == 1: + 263 raise Exception("GEVP methods only works on correlator matrices and not single correlators.") + 264 + 265 symmetric_corr = self.matrix_symmetric() + 266 if sorted_list is None: + 267 if (ts is None): + 268 raise Exception("ts is required if sorted_list=None") + 269 if (self.content[t0] is None) or (self.content[ts] is None): + 270 raise Exception("Corr not defined at t0/ts") + 271 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") + 272 for i in range(self.N): + 273 for j in range(self.N): + 274 G0[i, j] = symmetric_corr[t0][i, j].value + 275 Gt[i, j] = symmetric_corr[ts][i, j].value + 276 + 277 sp_vecs = _GEVP_solver(Gt, G0) + 278 sp_vec = sp_vecs[state] + 279 return sp_vec + 280 elif sorted_list in ["Eigenvalue", "Eigenvector"]: + 281 all_vecs = [] + 282 for t in range(self.T): + 283 try: + 284 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") + 285 for i in range(self.N): + 286 for j in range(self.N): + 287 G0[i, j] = symmetric_corr[t0][i, j].value + 288 Gt[i, j] = symmetric_corr[t][i, j].value + 289 + 290 sp_vecs = _GEVP_solver(Gt, G0) + 291 if sorted_list == "Eigenvalue": + 292 sp_vec = sp_vecs[state] + 293 all_vecs.append(sp_vec) + 294 else: + 295 all_vecs.append(sp_vecs) + 296 except Exception: + 297 all_vecs.append(None) + 298 if sorted_list == "Eigenvector": + 299 if (ts is None): + 300 raise Exception("ts is required for the Eigenvector sorting method.") + 301 all_vecs = _sort_vectors(all_vecs, ts) + 302 all_vecs = [a[state] for a in all_vecs] + 303 else: + 304 raise Exception("Unkown value for 'sorted_list'.") + 305 + 306 return all_vecs + 307 + 308 def Eigenvalue(self, t0, ts=None, state=0, sorted_list=None): + 309 """Determines the eigenvalue of the GEVP by solving and projecting the correlator + 310 + 311 Parameters + 312 ---------- + 313 t0 : int + 314 The time t0 for G(t)v= lambda G(t_0)v + 315 ts : int + 316 fixed time G(t_s)v= lambda G(t_0)v if return_list=False + 317 If return_list=True and sorting=Eigenvector it gives a reference point for the sorting method. + 318 state : int + 319 The state one is interested in ordered by energy. The lowest state is zero. + 320 sorted_list : string + 321 if this argument is set, a list of vectors (len=self.T) is returned. If it is left as None, only one vector is returned. + 322 "Eigenvalue" - The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice. + 323 "Eigenvector" - Use the method described in arXiv:2004.10472 [hep-lat] to find the set of v(t) belonging to the state. + 324 The reference state is identified by its eigenvalue at t=ts + 325 """ + 326 vec = self.GEVP(t0, ts=ts, state=state, sorted_list=sorted_list) + 327 return self.projected(vec) + 328 + 329 def Hankel(self, N, periodic=False): + 330 """Constructs an NxN Hankel matrix + 331 + 332 C(t) c(t+1) ... c(t+n-1) + 333 C(t+1) c(t+2) ... c(t+n) + 334 ................. + 335 C(t+(n-1)) c(t+n) ... c(t+2(n-1)) + 336 + 337 Parameters + 338 ---------- + 339 N : int + 340 Dimension of the Hankel matrix + 341 periodic : bool, optional + 342 determines whether the matrix is extended periodically + 343 """ + 344 + 345 if self.N != 1: + 346 raise Exception("Multi-operator Prony not implemented!") + 347 + 348 array = np.empty([N, N], dtype="object") + 349 new_content = [] + 350 for t in range(self.T): + 351 new_content.append(array.copy()) + 352 + 353 def wrap(i): + 354 while i >= self.T: + 355 i -= self.T + 356 return i + 357 + 358 for t in range(self.T): + 359 for i in range(N): + 360 for j in range(N): + 361 if periodic: + 362 new_content[t][i, j] = self.content[wrap(t + i + j)][0] + 363 elif (t + i + j) >= self.T: + 364 new_content[t] = None + 365 else: + 366 new_content[t][i, j] = self.content[t + i + j][0] + 367 + 368 return Corr(new_content) + 369 + 370 def roll(self, dt): + 371 """Periodically shift the correlator by dt timeslices + 372 + 373 Parameters + 374 ---------- + 375 dt : int + 376 number of timeslices + 377 """ + 378 return Corr(list(np.roll(np.array(self.content, dtype=object), dt))) 379 - 380 def thin(self, spacing=2, offset=0): - 381 """Thin out a correlator to suppress correlations - 382 - 383 Parameters - 384 ---------- - 385 spacing : int - 386 Keep only every 'spacing'th entry of the correlator - 387 offset : int - 388 Offset the equal spacing - 389 """ - 390 new_content = [] - 391 for t in range(self.T): - 392 if (offset + t) % spacing != 0: - 393 new_content.append(None) - 394 else: - 395 new_content.append(self.content[t]) - 396 return Corr(new_content) - 397 - 398 def correlate(self, partner): - 399 """Correlate the correlator with another correlator or Obs - 400 - 401 Parameters - 402 ---------- - 403 partner : Obs or Corr - 404 partner to correlate the correlator with. - 405 Can either be an Obs which is correlated with all entries of the - 406 correlator or a Corr of same length. - 407 """ - 408 new_content = [] - 409 for x0, t_slice in enumerate(self.content): - 410 if t_slice is None: - 411 new_content.append(None) - 412 else: - 413 if isinstance(partner, Corr): - 414 if partner.content[x0] is None: - 415 new_content.append(None) - 416 else: - 417 new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice])) - 418 elif isinstance(partner, Obs): # Should this include CObs? - 419 new_content.append(np.array([correlate(o, partner) for o in t_slice])) - 420 else: - 421 raise Exception("Can only correlate with an Obs or a Corr.") - 422 - 423 return Corr(new_content) - 424 - 425 def reweight(self, weight, **kwargs): - 426 """Reweight the correlator. - 427 - 428 Parameters - 429 ---------- - 430 weight : Obs - 431 Reweighting factor. An Observable that has to be defined on a superset of the - 432 configurations in obs[i].idl for all i. - 433 all_configs : bool - 434 if True, the reweighted observables are normalized by the average of - 435 the reweighting factor on all configurations in weight.idl and not - 436 on the configurations in obs[i].idl. - 437 """ - 438 new_content = [] - 439 for t_slice in self.content: - 440 if t_slice is None: - 441 new_content.append(None) - 442 else: - 443 new_content.append(np.array(reweight(weight, t_slice, **kwargs))) - 444 return Corr(new_content) - 445 - 446 def T_symmetry(self, partner, parity=+1): - 447 """Return the time symmetry average of the correlator and its partner - 448 - 449 Parameters - 450 ---------- - 451 partner : Corr - 452 Time symmetry partner of the Corr - 453 partity : int - 454 Parity quantum number of the correlator, can be +1 or -1 - 455 """ - 456 if not isinstance(partner, Corr): - 457 raise Exception("T partner has to be a Corr object.") - 458 if parity not in [+1, -1]: - 459 raise Exception("Parity has to be +1 or -1.") - 460 T_partner = parity * partner.reverse() - 461 - 462 t_slices = [] - 463 test = (self - T_partner) - 464 test.gamma_method() - 465 for x0, t_slice in enumerate(test.content): - 466 if t_slice is not None: - 467 if not t_slice[0].is_zero_within_error(5): - 468 t_slices.append(x0) - 469 if t_slices: - 470 warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning) - 471 - 472 return (self + T_partner) / 2 - 473 - 474 def deriv(self, variant="symmetric"): - 475 """Return the first derivative of the correlator with respect to x0. - 476 - 477 Parameters - 478 ---------- - 479 variant : str - 480 decides which definition of the finite differences derivative is used. - 481 Available choice: symmetric, forward, backward, improved, default: symmetric - 482 """ - 483 if variant == "symmetric": - 484 newcontent = [] - 485 for t in range(1, self.T - 1): - 486 if (self.content[t - 1] is None) or (self.content[t + 1] is None): - 487 newcontent.append(None) - 488 else: - 489 newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1])) - 490 if(all([x is None for x in newcontent])): - 491 raise Exception('Derivative is undefined at all timeslices') - 492 return Corr(newcontent, padding=[1, 1]) - 493 elif variant == "forward": - 494 newcontent = [] - 495 for t in range(self.T - 1): - 496 if (self.content[t] is None) or (self.content[t + 1] is None): - 497 newcontent.append(None) - 498 else: - 499 newcontent.append(self.content[t + 1] - self.content[t]) - 500 if(all([x is None for x in newcontent])): - 501 raise Exception("Derivative is undefined at all timeslices") - 502 return Corr(newcontent, padding=[0, 1]) - 503 elif variant == "backward": - 504 newcontent = [] - 505 for t in range(1, self.T): - 506 if (self.content[t - 1] is None) or (self.content[t] is None): - 507 newcontent.append(None) - 508 else: - 509 newcontent.append(self.content[t] - self.content[t - 1]) - 510 if(all([x is None for x in newcontent])): - 511 raise Exception("Derivative is undefined at all timeslices") - 512 return Corr(newcontent, padding=[1, 0]) - 513 elif variant == "improved": - 514 newcontent = [] - 515 for t in range(2, self.T - 2): - 516 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): - 517 newcontent.append(None) - 518 else: - 519 newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2])) - 520 if(all([x is None for x in newcontent])): - 521 raise Exception('Derivative is undefined at all timeslices') - 522 return Corr(newcontent, padding=[2, 2]) - 523 else: - 524 raise Exception("Unknown variant.") - 525 - 526 def second_deriv(self, variant="symmetric"): - 527 """Return the second derivative of the correlator with respect to x0. - 528 - 529 Parameters - 530 ---------- - 531 variant : str - 532 decides which definition of the finite differences derivative is used. - 533 Available choice: symmetric, improved, default: symmetric - 534 """ - 535 if variant == "symmetric": - 536 newcontent = [] - 537 for t in range(1, self.T - 1): - 538 if (self.content[t - 1] is None) or (self.content[t + 1] is None): - 539 newcontent.append(None) - 540 else: - 541 newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1])) - 542 if(all([x is None for x in newcontent])): - 543 raise Exception("Derivative is undefined at all timeslices") - 544 return Corr(newcontent, padding=[1, 1]) - 545 elif variant == "improved": - 546 newcontent = [] - 547 for t in range(2, self.T - 2): - 548 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): - 549 newcontent.append(None) - 550 else: - 551 newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2])) - 552 if(all([x is None for x in newcontent])): - 553 raise Exception("Derivative is undefined at all timeslices") - 554 return Corr(newcontent, padding=[2, 2]) - 555 else: - 556 raise Exception("Unknown variant.") - 557 - 558 def m_eff(self, variant='log', guess=1.0): - 559 """Returns the effective mass of the correlator as correlator object - 560 - 561 Parameters - 562 ---------- - 563 variant : str - 564 log : uses the standard effective mass log(C(t) / C(t+1)) - 565 cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m. - 566 sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m. - 567 See, e.g., arXiv:1205.5380 - 568 arccosh : Uses the explicit form of the symmetrized correlator (not recommended) - 569 guess : float - 570 guess for the root finder, only relevant for the root variant - 571 """ - 572 if self.N != 1: - 573 raise Exception('Correlator must be projected before getting m_eff') - 574 if variant == 'log': - 575 newcontent = [] - 576 for t in range(self.T - 1): - 577 if (self.content[t] is None) or (self.content[t + 1] is None): - 578 newcontent.append(None) - 579 else: - 580 newcontent.append(self.content[t] / self.content[t + 1]) - 581 if(all([x is None for x in newcontent])): - 582 raise Exception('m_eff is undefined at all timeslices') - 583 - 584 return np.log(Corr(newcontent, padding=[0, 1])) - 585 - 586 elif variant in ['periodic', 'cosh', 'sinh']: - 587 if variant in ['periodic', 'cosh']: - 588 func = anp.cosh - 589 else: - 590 func = anp.sinh - 591 - 592 def root_function(x, d): - 593 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d - 594 - 595 newcontent = [] - 596 for t in range(self.T - 1): - 597 if (self.content[t] is None) or (self.content[t + 1] is None): - 598 newcontent.append(None) - 599 # Fill the two timeslices in the middle of the lattice with their predecessors - 600 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: - 601 newcontent.append(newcontent[-1]) - 602 else: - 603 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) - 604 if(all([x is None for x in newcontent])): - 605 raise Exception('m_eff is undefined at all timeslices') - 606 - 607 return Corr(newcontent, padding=[0, 1]) - 608 - 609 elif variant == 'arccosh': - 610 newcontent = [] - 611 for t in range(1, self.T - 1): - 612 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None): - 613 newcontent.append(None) - 614 else: - 615 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) - 616 if(all([x is None for x in newcontent])): - 617 raise Exception("m_eff is undefined at all timeslices") - 618 return np.arccosh(Corr(newcontent, padding=[1, 1])) - 619 - 620 else: - 621 raise Exception('Unknown variant.') - 622 - 623 def fit(self, function, fitrange=None, silent=False, **kwargs): - 624 r'''Fits function to the data - 625 - 626 Parameters - 627 ---------- - 628 function : obj - 629 function to fit to the data. See fits.least_squares for details. - 630 fitrange : list - 631 Two element list containing the timeslices on which the fit is supposed to start and stop. - 632 Caution: This range is inclusive as opposed to standard python indexing. - 633 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. - 634 If not specified, self.prange or all timeslices are used. - 635 silent : bool - 636 Decides whether output is printed to the standard output. - 637 ''' - 638 if self.N != 1: - 639 raise Exception("Correlator must be projected before fitting") - 640 - 641 if fitrange is None: - 642 if self.prange: - 643 fitrange = self.prange - 644 else: - 645 fitrange = [0, self.T - 1] - 646 else: - 647 if not isinstance(fitrange, list): - 648 raise Exception("fitrange has to be a list with two elements") - 649 if len(fitrange) != 2: - 650 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") - 651 - 652 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 653 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 654 result = least_squares(xs, ys, function, silent=silent, **kwargs) - 655 return result - 656 - 657 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): - 658 """ Extract a plateau value from a Corr object - 659 - 660 Parameters - 661 ---------- - 662 plateau_range : list - 663 list with two entries, indicating the first and the last timeslice - 664 of the plateau region. - 665 method : str - 666 method to extract the plateau. - 667 'fit' fits a constant to the plateau region - 668 'avg', 'average' or 'mean' just average over the given timeslices. - 669 auto_gamma : bool - 670 apply gamma_method with default parameters to the Corr. Defaults to None - 671 """ - 672 if not plateau_range: - 673 if self.prange: - 674 plateau_range = self.prange - 675 else: - 676 raise Exception("no plateau range provided") - 677 if self.N != 1: - 678 raise Exception("Correlator must be projected before getting a plateau.") - 679 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): - 680 raise Exception("plateau is undefined at all timeslices in plateaurange.") - 681 if auto_gamma: - 682 self.gamma_method() - 683 if method == "fit": - 684 def const_func(a, t): - 685 return a[0] - 686 return self.fit(const_func, plateau_range)[0] - 687 elif method in ["avg", "average", "mean"]: - 688 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) - 689 return returnvalue - 690 - 691 else: - 692 raise Exception("Unsupported plateau method: " + method) - 693 - 694 def set_prange(self, prange): - 695 """Sets the attribute prange of the Corr object.""" - 696 if not len(prange) == 2: - 697 raise Exception("prange must be a list or array with two values") - 698 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): - 699 raise Exception("Start and end point must be integers") - 700 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): - 701 raise Exception("Start and end point must define a range in the interval 0,T") - 702 - 703 self.prange = prange - 704 return - 705 - 706 def show(self, x_range=None, comp=None, y_range=None, logscale=False, plateau=None, fit_res=None, ylabel=None, save=None, auto_gamma=False, hide_sigma=None, references=None): - 707 """Plots the correlator using the tag of the correlator as label if available. - 708 - 709 Parameters - 710 ---------- - 711 x_range : list - 712 list of two values, determining the range of the x-axis e.g. [4, 8] - 713 comp : Corr or list of Corr - 714 Correlator or list of correlators which are plotted for comparison. - 715 The tags of these correlators are used as labels if available. - 716 logscale : bool - 717 Sets y-axis to logscale - 718 plateau : Obs - 719 Plateau value to be visualized in the figure - 720 fit_res : Fit_result - 721 Fit_result object to be visualized - 722 ylabel : str - 723 Label for the y-axis - 724 save : str - 725 path to file in which the figure should be saved - 726 auto_gamma : bool - 727 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. - 728 hide_sigma : float - 729 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. - 730 references : list - 731 List of floating point values that are displayed as horizontal lines for reference. - 732 """ - 733 if self.N != 1: - 734 raise Exception("Correlator must be projected before plotting") - 735 - 736 if auto_gamma: - 737 self.gamma_method() - 738 - 739 if x_range is None: - 740 x_range = [0, self.T - 1] - 741 - 742 fig = plt.figure() - 743 ax1 = fig.add_subplot(111) - 744 - 745 x, y, y_err = self.plottable() - 746 if hide_sigma: - 747 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 - 748 else: - 749 hide_from = None - 750 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) - 751 if logscale: - 752 ax1.set_yscale('log') - 753 else: - 754 if y_range is None: - 755 try: - 756 y_min = min([(x[0].value - x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) - 757 y_max = max([(x[0].value + x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) - 758 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) - 759 except Exception: - 760 pass - 761 else: - 762 ax1.set_ylim(y_range) - 763 if comp: - 764 if isinstance(comp, (Corr, list)): - 765 for corr in comp if isinstance(comp, list) else [comp]: - 766 if auto_gamma: - 767 corr.gamma_method() - 768 x, y, y_err = corr.plottable() - 769 if hide_sigma: - 770 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 - 771 else: - 772 hide_from = None - 773 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) - 774 else: - 775 raise Exception("'comp' must be a correlator or a list of correlators.") - 776 - 777 if plateau: - 778 if isinstance(plateau, Obs): - 779 if auto_gamma: - 780 plateau.gamma_method() - 781 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) - 782 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') - 783 else: - 784 raise Exception("'plateau' must be an Obs") - 785 - 786 if references: - 787 if isinstance(references, list): - 788 for ref in references: - 789 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') - 790 else: - 791 raise Exception("'references' must be a list of floating pint values.") - 792 - 793 if self.prange: - 794 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') - 795 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') + 380 def reverse(self): + 381 """Reverse the time ordering of the Corr""" + 382 return Corr(self.content[:: -1]) + 383 + 384 def thin(self, spacing=2, offset=0): + 385 """Thin out a correlator to suppress correlations + 386 + 387 Parameters + 388 ---------- + 389 spacing : int + 390 Keep only every 'spacing'th entry of the correlator + 391 offset : int + 392 Offset the equal spacing + 393 """ + 394 new_content = [] + 395 for t in range(self.T): + 396 if (offset + t) % spacing != 0: + 397 new_content.append(None) + 398 else: + 399 new_content.append(self.content[t]) + 400 return Corr(new_content) + 401 + 402 def correlate(self, partner): + 403 """Correlate the correlator with another correlator or Obs + 404 + 405 Parameters + 406 ---------- + 407 partner : Obs or Corr + 408 partner to correlate the correlator with. + 409 Can either be an Obs which is correlated with all entries of the + 410 correlator or a Corr of same length. + 411 """ + 412 new_content = [] + 413 for x0, t_slice in enumerate(self.content): + 414 if t_slice is None: + 415 new_content.append(None) + 416 else: + 417 if isinstance(partner, Corr): + 418 if partner.content[x0] is None: + 419 new_content.append(None) + 420 else: + 421 new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice])) + 422 elif isinstance(partner, Obs): # Should this include CObs? + 423 new_content.append(np.array([correlate(o, partner) for o in t_slice])) + 424 else: + 425 raise Exception("Can only correlate with an Obs or a Corr.") + 426 + 427 return Corr(new_content) + 428 + 429 def reweight(self, weight, **kwargs): + 430 """Reweight the correlator. + 431 + 432 Parameters + 433 ---------- + 434 weight : Obs + 435 Reweighting factor. An Observable that has to be defined on a superset of the + 436 configurations in obs[i].idl for all i. + 437 all_configs : bool + 438 if True, the reweighted observables are normalized by the average of + 439 the reweighting factor on all configurations in weight.idl and not + 440 on the configurations in obs[i].idl. + 441 """ + 442 new_content = [] + 443 for t_slice in self.content: + 444 if t_slice is None: + 445 new_content.append(None) + 446 else: + 447 new_content.append(np.array(reweight(weight, t_slice, **kwargs))) + 448 return Corr(new_content) + 449 + 450 def T_symmetry(self, partner, parity=+1): + 451 """Return the time symmetry average of the correlator and its partner + 452 + 453 Parameters + 454 ---------- + 455 partner : Corr + 456 Time symmetry partner of the Corr + 457 partity : int + 458 Parity quantum number of the correlator, can be +1 or -1 + 459 """ + 460 if not isinstance(partner, Corr): + 461 raise Exception("T partner has to be a Corr object.") + 462 if parity not in [+1, -1]: + 463 raise Exception("Parity has to be +1 or -1.") + 464 T_partner = parity * partner.reverse() + 465 + 466 t_slices = [] + 467 test = (self - T_partner) + 468 test.gamma_method() + 469 for x0, t_slice in enumerate(test.content): + 470 if t_slice is not None: + 471 if not t_slice[0].is_zero_within_error(5): + 472 t_slices.append(x0) + 473 if t_slices: + 474 warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning) + 475 + 476 return (self + T_partner) / 2 + 477 + 478 def deriv(self, variant="symmetric"): + 479 """Return the first derivative of the correlator with respect to x0. + 480 + 481 Parameters + 482 ---------- + 483 variant : str + 484 decides which definition of the finite differences derivative is used. + 485 Available choice: symmetric, forward, backward, improved, default: symmetric + 486 """ + 487 if variant == "symmetric": + 488 newcontent = [] + 489 for t in range(1, self.T - 1): + 490 if (self.content[t - 1] is None) or (self.content[t + 1] is None): + 491 newcontent.append(None) + 492 else: + 493 newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1])) + 494 if(all([x is None for x in newcontent])): + 495 raise Exception('Derivative is undefined at all timeslices') + 496 return Corr(newcontent, padding=[1, 1]) + 497 elif variant == "forward": + 498 newcontent = [] + 499 for t in range(self.T - 1): + 500 if (self.content[t] is None) or (self.content[t + 1] is None): + 501 newcontent.append(None) + 502 else: + 503 newcontent.append(self.content[t + 1] - self.content[t]) + 504 if(all([x is None for x in newcontent])): + 505 raise Exception("Derivative is undefined at all timeslices") + 506 return Corr(newcontent, padding=[0, 1]) + 507 elif variant == "backward": + 508 newcontent = [] + 509 for t in range(1, self.T): + 510 if (self.content[t - 1] is None) or (self.content[t] is None): + 511 newcontent.append(None) + 512 else: + 513 newcontent.append(self.content[t] - self.content[t - 1]) + 514 if(all([x is None for x in newcontent])): + 515 raise Exception("Derivative is undefined at all timeslices") + 516 return Corr(newcontent, padding=[1, 0]) + 517 elif variant == "improved": + 518 newcontent = [] + 519 for t in range(2, self.T - 2): + 520 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): + 521 newcontent.append(None) + 522 else: + 523 newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2])) + 524 if(all([x is None for x in newcontent])): + 525 raise Exception('Derivative is undefined at all timeslices') + 526 return Corr(newcontent, padding=[2, 2]) + 527 else: + 528 raise Exception("Unknown variant.") + 529 + 530 def second_deriv(self, variant="symmetric"): + 531 """Return the second derivative of the correlator with respect to x0. + 532 + 533 Parameters + 534 ---------- + 535 variant : str + 536 decides which definition of the finite differences derivative is used. + 537 Available choice: symmetric, improved, default: symmetric + 538 """ + 539 if variant == "symmetric": + 540 newcontent = [] + 541 for t in range(1, self.T - 1): + 542 if (self.content[t - 1] is None) or (self.content[t + 1] is None): + 543 newcontent.append(None) + 544 else: + 545 newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1])) + 546 if(all([x is None for x in newcontent])): + 547 raise Exception("Derivative is undefined at all timeslices") + 548 return Corr(newcontent, padding=[1, 1]) + 549 elif variant == "improved": + 550 newcontent = [] + 551 for t in range(2, self.T - 2): + 552 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): + 553 newcontent.append(None) + 554 else: + 555 newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2])) + 556 if(all([x is None for x in newcontent])): + 557 raise Exception("Derivative is undefined at all timeslices") + 558 return Corr(newcontent, padding=[2, 2]) + 559 else: + 560 raise Exception("Unknown variant.") + 561 + 562 def m_eff(self, variant='log', guess=1.0): + 563 """Returns the effective mass of the correlator as correlator object + 564 + 565 Parameters + 566 ---------- + 567 variant : str + 568 log : uses the standard effective mass log(C(t) / C(t+1)) + 569 cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m. + 570 sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m. + 571 See, e.g., arXiv:1205.5380 + 572 arccosh : Uses the explicit form of the symmetrized correlator (not recommended) + 573 guess : float + 574 guess for the root finder, only relevant for the root variant + 575 """ + 576 if self.N != 1: + 577 raise Exception('Correlator must be projected before getting m_eff') + 578 if variant == 'log': + 579 newcontent = [] + 580 for t in range(self.T - 1): + 581 if (self.content[t] is None) or (self.content[t + 1] is None): + 582 newcontent.append(None) + 583 else: + 584 newcontent.append(self.content[t] / self.content[t + 1]) + 585 if(all([x is None for x in newcontent])): + 586 raise Exception('m_eff is undefined at all timeslices') + 587 + 588 return np.log(Corr(newcontent, padding=[0, 1])) + 589 + 590 elif variant in ['periodic', 'cosh', 'sinh']: + 591 if variant in ['periodic', 'cosh']: + 592 func = anp.cosh + 593 else: + 594 func = anp.sinh + 595 + 596 def root_function(x, d): + 597 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d + 598 + 599 newcontent = [] + 600 for t in range(self.T - 1): + 601 if (self.content[t] is None) or (self.content[t + 1] is None): + 602 newcontent.append(None) + 603 # Fill the two timeslices in the middle of the lattice with their predecessors + 604 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: + 605 newcontent.append(newcontent[-1]) + 606 else: + 607 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) + 608 if(all([x is None for x in newcontent])): + 609 raise Exception('m_eff is undefined at all timeslices') + 610 + 611 return Corr(newcontent, padding=[0, 1]) + 612 + 613 elif variant == 'arccosh': + 614 newcontent = [] + 615 for t in range(1, self.T - 1): + 616 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None): + 617 newcontent.append(None) + 618 else: + 619 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) + 620 if(all([x is None for x in newcontent])): + 621 raise Exception("m_eff is undefined at all timeslices") + 622 return np.arccosh(Corr(newcontent, padding=[1, 1])) + 623 + 624 else: + 625 raise Exception('Unknown variant.') + 626 + 627 def fit(self, function, fitrange=None, silent=False, **kwargs): + 628 r'''Fits function to the data + 629 + 630 Parameters + 631 ---------- + 632 function : obj + 633 function to fit to the data. See fits.least_squares for details. + 634 fitrange : list + 635 Two element list containing the timeslices on which the fit is supposed to start and stop. + 636 Caution: This range is inclusive as opposed to standard python indexing. + 637 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. + 638 If not specified, self.prange or all timeslices are used. + 639 silent : bool + 640 Decides whether output is printed to the standard output. + 641 ''' + 642 if self.N != 1: + 643 raise Exception("Correlator must be projected before fitting") + 644 + 645 if fitrange is None: + 646 if self.prange: + 647 fitrange = self.prange + 648 else: + 649 fitrange = [0, self.T - 1] + 650 else: + 651 if not isinstance(fitrange, list): + 652 raise Exception("fitrange has to be a list with two elements") + 653 if len(fitrange) != 2: + 654 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") + 655 + 656 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 657 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 658 result = least_squares(xs, ys, function, silent=silent, **kwargs) + 659 return result + 660 + 661 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): + 662 """ Extract a plateau value from a Corr object + 663 + 664 Parameters + 665 ---------- + 666 plateau_range : list + 667 list with two entries, indicating the first and the last timeslice + 668 of the plateau region. + 669 method : str + 670 method to extract the plateau. + 671 'fit' fits a constant to the plateau region + 672 'avg', 'average' or 'mean' just average over the given timeslices. + 673 auto_gamma : bool + 674 apply gamma_method with default parameters to the Corr. Defaults to None + 675 """ + 676 if not plateau_range: + 677 if self.prange: + 678 plateau_range = self.prange + 679 else: + 680 raise Exception("no plateau range provided") + 681 if self.N != 1: + 682 raise Exception("Correlator must be projected before getting a plateau.") + 683 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): + 684 raise Exception("plateau is undefined at all timeslices in plateaurange.") + 685 if auto_gamma: + 686 self.gamma_method() + 687 if method == "fit": + 688 def const_func(a, t): + 689 return a[0] + 690 return self.fit(const_func, plateau_range)[0] + 691 elif method in ["avg", "average", "mean"]: + 692 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) + 693 return returnvalue + 694 + 695 else: + 696 raise Exception("Unsupported plateau method: " + method) + 697 + 698 def set_prange(self, prange): + 699 """Sets the attribute prange of the Corr object.""" + 700 if not len(prange) == 2: + 701 raise Exception("prange must be a list or array with two values") + 702 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): + 703 raise Exception("Start and end point must be integers") + 704 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): + 705 raise Exception("Start and end point must define a range in the interval 0,T") + 706 + 707 self.prange = prange + 708 return + 709 + 710 def show(self, x_range=None, comp=None, y_range=None, logscale=False, plateau=None, fit_res=None, ylabel=None, save=None, auto_gamma=False, hide_sigma=None, references=None): + 711 """Plots the correlator using the tag of the correlator as label if available. + 712 + 713 Parameters + 714 ---------- + 715 x_range : list + 716 list of two values, determining the range of the x-axis e.g. [4, 8] + 717 comp : Corr or list of Corr + 718 Correlator or list of correlators which are plotted for comparison. + 719 The tags of these correlators are used as labels if available. + 720 logscale : bool + 721 Sets y-axis to logscale + 722 plateau : Obs + 723 Plateau value to be visualized in the figure + 724 fit_res : Fit_result + 725 Fit_result object to be visualized + 726 ylabel : str + 727 Label for the y-axis + 728 save : str + 729 path to file in which the figure should be saved + 730 auto_gamma : bool + 731 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. + 732 hide_sigma : float + 733 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. + 734 references : list + 735 List of floating point values that are displayed as horizontal lines for reference. + 736 """ + 737 if self.N != 1: + 738 raise Exception("Correlator must be projected before plotting") + 739 + 740 if auto_gamma: + 741 self.gamma_method() + 742 + 743 if x_range is None: + 744 x_range = [0, self.T - 1] + 745 + 746 fig = plt.figure() + 747 ax1 = fig.add_subplot(111) + 748 + 749 x, y, y_err = self.plottable() + 750 if hide_sigma: + 751 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 + 752 else: + 753 hide_from = None + 754 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) + 755 if logscale: + 756 ax1.set_yscale('log') + 757 else: + 758 if y_range is None: + 759 try: + 760 y_min = min([(x[0].value - x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) + 761 y_max = max([(x[0].value + x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) + 762 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) + 763 except Exception: + 764 pass + 765 else: + 766 ax1.set_ylim(y_range) + 767 if comp: + 768 if isinstance(comp, (Corr, list)): + 769 for corr in comp if isinstance(comp, list) else [comp]: + 770 if auto_gamma: + 771 corr.gamma_method() + 772 x, y, y_err = corr.plottable() + 773 if hide_sigma: + 774 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 + 775 else: + 776 hide_from = None + 777 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) + 778 else: + 779 raise Exception("'comp' must be a correlator or a list of correlators.") + 780 + 781 if plateau: + 782 if isinstance(plateau, Obs): + 783 if auto_gamma: + 784 plateau.gamma_method() + 785 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) + 786 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') + 787 else: + 788 raise Exception("'plateau' must be an Obs") + 789 + 790 if references: + 791 if isinstance(references, list): + 792 for ref in references: + 793 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') + 794 else: + 795 raise Exception("'references' must be a list of floating pint values.") 796 - 797 if fit_res: - 798 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) - 799 ax1.plot(x_samples, - 800 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), - 801 ls='-', marker=',', lw=2) - 802 - 803 ax1.set_xlabel(r'$x_0 / a$') - 804 if ylabel: - 805 ax1.set_ylabel(ylabel) - 806 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) - 807 - 808 handles, labels = ax1.get_legend_handles_labels() - 809 if labels: - 810 ax1.legend() - 811 plt.draw() - 812 - 813 if save: - 814 if isinstance(save, str): - 815 fig.savefig(save) - 816 else: - 817 raise Exception("'save' has to be a string.") - 818 - 819 def spaghetti_plot(self, logscale=True): - 820 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. - 821 - 822 Parameters - 823 ---------- - 824 logscale : bool - 825 Determines whether the scale of the y-axis is logarithmic or standard. - 826 """ - 827 if self.N != 1: - 828 raise Exception("Correlator needs to be projected first.") - 829 - 830 mc_names = list(set([item for sublist in [o[0].mc_names for o in self.content if o is not None] for item in sublist])) - 831 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] - 832 - 833 for name in mc_names: - 834 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T - 835 - 836 fig = plt.figure() - 837 ax = fig.add_subplot(111) - 838 for dat in data: - 839 ax.plot(x0_vals, dat, ls='-', marker='') - 840 - 841 if logscale is True: - 842 ax.set_yscale('log') - 843 - 844 ax.set_xlabel(r'$x_0 / a$') - 845 plt.title(name) - 846 plt.draw() + 797 if self.prange: + 798 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') + 799 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') + 800 + 801 if fit_res: + 802 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) + 803 ax1.plot(x_samples, + 804 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), + 805 ls='-', marker=',', lw=2) + 806 + 807 ax1.set_xlabel(r'$x_0 / a$') + 808 if ylabel: + 809 ax1.set_ylabel(ylabel) + 810 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) + 811 + 812 handles, labels = ax1.get_legend_handles_labels() + 813 if labels: + 814 ax1.legend() + 815 plt.draw() + 816 + 817 if save: + 818 if isinstance(save, str): + 819 fig.savefig(save) + 820 else: + 821 raise Exception("'save' has to be a string.") + 822 + 823 def spaghetti_plot(self, logscale=True): + 824 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. + 825 + 826 Parameters + 827 ---------- + 828 logscale : bool + 829 Determines whether the scale of the y-axis is logarithmic or standard. + 830 """ + 831 if self.N != 1: + 832 raise Exception("Correlator needs to be projected first.") + 833 + 834 mc_names = list(set([item for sublist in [o[0].mc_names for o in self.content if o is not None] for item in sublist])) + 835 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] + 836 + 837 for name in mc_names: + 838 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T + 839 + 840 fig = plt.figure() + 841 ax = fig.add_subplot(111) + 842 for dat in data: + 843 ax.plot(x0_vals, dat, ls='-', marker='') + 844 + 845 if logscale is True: + 846 ax.set_yscale('log') 847 - 848 def dump(self, filename, datatype="json.gz", **kwargs): - 849 """Dumps the Corr into a file of chosen type - 850 Parameters - 851 ---------- - 852 filename : str - 853 Name of the file to be saved. - 854 datatype : str - 855 Format of the exported file. Supported formats include - 856 "json.gz" and "pickle" - 857 path : str - 858 specifies a custom path for the file (default '.') - 859 """ - 860 if datatype == "json.gz": - 861 from .input.json import dump_to_json - 862 if 'path' in kwargs: - 863 file_name = kwargs.get('path') + '/' + filename - 864 else: - 865 file_name = filename - 866 dump_to_json(self, file_name) - 867 elif datatype == "pickle": - 868 dump_object(self, filename, **kwargs) - 869 else: - 870 raise Exception("Unknown datatype " + str(datatype)) - 871 - 872 def print(self, range=[0, None]): - 873 print(self.__repr__(range)) - 874 - 875 def __repr__(self, range=[0, None]): - 876 content_string = "" - 877 - 878 content_string += "Corr T=" + str(self.T) + " N=" + str(self.N) + "\n" # +" filled with"+ str(type(self.content[0][0])) there should be a good solution here - 879 - 880 if self.tag is not None: - 881 content_string += "Description: " + self.tag + "\n" - 882 if self.N != 1: - 883 return content_string - 884 - 885 if range[1]: - 886 range[1] += 1 - 887 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' - 888 for i, sub_corr in enumerate(self.content[range[0]:range[1]]): - 889 if sub_corr is None: - 890 content_string += str(i + range[0]) + '\n' - 891 else: - 892 content_string += str(i + range[0]) - 893 for element in sub_corr: - 894 content_string += '\t' + ' ' * int(element >= 0) + str(element) - 895 content_string += '\n' - 896 return content_string - 897 - 898 def __str__(self): - 899 return self.__repr__() - 900 - 901 # We define the basic operations, that can be performed with correlators. - 902 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. - 903 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. - 904 # One could try and tell Obs to check if the y in __mul__ is a Corr and - 905 - 906 def __add__(self, y): - 907 if isinstance(y, Corr): - 908 if ((self.N != y.N) or (self.T != y.T)): - 909 raise Exception("Addition of Corrs with different shape") - 910 newcontent = [] - 911 for t in range(self.T): - 912 if (self.content[t] is None) or (y.content[t] is None): - 913 newcontent.append(None) - 914 else: - 915 newcontent.append(self.content[t] + y.content[t]) - 916 return Corr(newcontent) - 917 - 918 elif isinstance(y, (Obs, int, float, CObs)): - 919 newcontent = [] - 920 for t in range(self.T): - 921 if (self.content[t] is None): - 922 newcontent.append(None) - 923 else: - 924 newcontent.append(self.content[t] + y) - 925 return Corr(newcontent, prange=self.prange) - 926 elif isinstance(y, np.ndarray): - 927 if y.shape == (self.T,): - 928 return Corr(list((np.array(self.content).T + y).T)) - 929 else: - 930 raise ValueError("operands could not be broadcast together") - 931 else: - 932 raise TypeError("Corr + wrong type") - 933 - 934 def __mul__(self, y): - 935 if isinstance(y, Corr): - 936 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): - 937 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") - 938 newcontent = [] - 939 for t in range(self.T): - 940 if (self.content[t] is None) or (y.content[t] is None): - 941 newcontent.append(None) - 942 else: - 943 newcontent.append(self.content[t] * y.content[t]) - 944 return Corr(newcontent) - 945 - 946 elif isinstance(y, (Obs, int, float, CObs)): - 947 newcontent = [] - 948 for t in range(self.T): - 949 if (self.content[t] is None): - 950 newcontent.append(None) - 951 else: - 952 newcontent.append(self.content[t] * y) - 953 return Corr(newcontent, prange=self.prange) - 954 elif isinstance(y, np.ndarray): - 955 if y.shape == (self.T,): - 956 return Corr(list((np.array(self.content).T * y).T)) - 957 else: - 958 raise ValueError("operands could not be broadcast together") - 959 else: - 960 raise TypeError("Corr * wrong type") - 961 - 962 def __truediv__(self, y): - 963 if isinstance(y, Corr): - 964 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): - 965 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") - 966 newcontent = [] - 967 for t in range(self.T): - 968 if (self.content[t] is None) or (y.content[t] is None): - 969 newcontent.append(None) - 970 else: - 971 newcontent.append(self.content[t] / y.content[t]) - 972 for t in range(self.T): - 973 if newcontent[t] is None: - 974 continue - 975 if np.isnan(np.sum(newcontent[t]).value): - 976 newcontent[t] = None - 977 - 978 if all([item is None for item in newcontent]): - 979 raise Exception("Division returns completely undefined correlator") - 980 return Corr(newcontent) + 848 ax.set_xlabel(r'$x_0 / a$') + 849 plt.title(name) + 850 plt.draw() + 851 + 852 def dump(self, filename, datatype="json.gz", **kwargs): + 853 """Dumps the Corr into a file of chosen type + 854 Parameters + 855 ---------- + 856 filename : str + 857 Name of the file to be saved. + 858 datatype : str + 859 Format of the exported file. Supported formats include + 860 "json.gz" and "pickle" + 861 path : str + 862 specifies a custom path for the file (default '.') + 863 """ + 864 if datatype == "json.gz": + 865 from .input.json import dump_to_json + 866 if 'path' in kwargs: + 867 file_name = kwargs.get('path') + '/' + filename + 868 else: + 869 file_name = filename + 870 dump_to_json(self, file_name) + 871 elif datatype == "pickle": + 872 dump_object(self, filename, **kwargs) + 873 else: + 874 raise Exception("Unknown datatype " + str(datatype)) + 875 + 876 def print(self, range=[0, None]): + 877 print(self.__repr__(range)) + 878 + 879 def __repr__(self, range=[0, None]): + 880 content_string = "" + 881 + 882 content_string += "Corr T=" + str(self.T) + " N=" + str(self.N) + "\n" # +" filled with"+ str(type(self.content[0][0])) there should be a good solution here + 883 + 884 if self.tag is not None: + 885 content_string += "Description: " + self.tag + "\n" + 886 if self.N != 1: + 887 return content_string + 888 + 889 if range[1]: + 890 range[1] += 1 + 891 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' + 892 for i, sub_corr in enumerate(self.content[range[0]:range[1]]): + 893 if sub_corr is None: + 894 content_string += str(i + range[0]) + '\n' + 895 else: + 896 content_string += str(i + range[0]) + 897 for element in sub_corr: + 898 content_string += '\t' + ' ' * int(element >= 0) + str(element) + 899 content_string += '\n' + 900 return content_string + 901 + 902 def __str__(self): + 903 return self.__repr__() + 904 + 905 # We define the basic operations, that can be performed with correlators. + 906 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. + 907 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. + 908 # One could try and tell Obs to check if the y in __mul__ is a Corr and + 909 + 910 def __add__(self, y): + 911 if isinstance(y, Corr): + 912 if ((self.N != y.N) or (self.T != y.T)): + 913 raise Exception("Addition of Corrs with different shape") + 914 newcontent = [] + 915 for t in range(self.T): + 916 if (self.content[t] is None) or (y.content[t] is None): + 917 newcontent.append(None) + 918 else: + 919 newcontent.append(self.content[t] + y.content[t]) + 920 return Corr(newcontent) + 921 + 922 elif isinstance(y, (Obs, int, float, CObs)): + 923 newcontent = [] + 924 for t in range(self.T): + 925 if (self.content[t] is None): + 926 newcontent.append(None) + 927 else: + 928 newcontent.append(self.content[t] + y) + 929 return Corr(newcontent, prange=self.prange) + 930 elif isinstance(y, np.ndarray): + 931 if y.shape == (self.T,): + 932 return Corr(list((np.array(self.content).T + y).T)) + 933 else: + 934 raise ValueError("operands could not be broadcast together") + 935 else: + 936 raise TypeError("Corr + wrong type") + 937 + 938 def __mul__(self, y): + 939 if isinstance(y, Corr): + 940 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): + 941 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") + 942 newcontent = [] + 943 for t in range(self.T): + 944 if (self.content[t] is None) or (y.content[t] is None): + 945 newcontent.append(None) + 946 else: + 947 newcontent.append(self.content[t] * y.content[t]) + 948 return Corr(newcontent) + 949 + 950 elif isinstance(y, (Obs, int, float, CObs)): + 951 newcontent = [] + 952 for t in range(self.T): + 953 if (self.content[t] is None): + 954 newcontent.append(None) + 955 else: + 956 newcontent.append(self.content[t] * y) + 957 return Corr(newcontent, prange=self.prange) + 958 elif isinstance(y, np.ndarray): + 959 if y.shape == (self.T,): + 960 return Corr(list((np.array(self.content).T * y).T)) + 961 else: + 962 raise ValueError("operands could not be broadcast together") + 963 else: + 964 raise TypeError("Corr * wrong type") + 965 + 966 def __truediv__(self, y): + 967 if isinstance(y, Corr): + 968 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): + 969 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") + 970 newcontent = [] + 971 for t in range(self.T): + 972 if (self.content[t] is None) or (y.content[t] is None): + 973 newcontent.append(None) + 974 else: + 975 newcontent.append(self.content[t] / y.content[t]) + 976 for t in range(self.T): + 977 if newcontent[t] is None: + 978 continue + 979 if np.isnan(np.sum(newcontent[t]).value): + 980 newcontent[t] = None 981 - 982 elif isinstance(y, (Obs, CObs)): - 983 if isinstance(y, Obs): - 984 if y.value == 0: - 985 raise Exception('Division by zero will return undefined correlator') - 986 if isinstance(y, CObs): - 987 if y.is_zero(): - 988 raise Exception('Division by zero will return undefined correlator') - 989 - 990 newcontent = [] - 991 for t in range(self.T): - 992 if (self.content[t] is None): - 993 newcontent.append(None) - 994 else: - 995 newcontent.append(self.content[t] / y) - 996 return Corr(newcontent, prange=self.prange) - 997 - 998 elif isinstance(y, (int, float)): - 999 if y == 0: -1000 raise Exception('Division by zero will return undefined correlator') -1001 newcontent = [] -1002 for t in range(self.T): -1003 if (self.content[t] is None): -1004 newcontent.append(None) -1005 else: -1006 newcontent.append(self.content[t] / y) -1007 return Corr(newcontent, prange=self.prange) -1008 elif isinstance(y, np.ndarray): -1009 if y.shape == (self.T,): -1010 return Corr(list((np.array(self.content).T / y).T)) -1011 else: -1012 raise ValueError("operands could not be broadcast together") -1013 else: -1014 raise TypeError('Corr / wrong type') -1015 -1016 def __neg__(self): -1017 newcontent = [None if (item is None) else -1. * item for item in self.content] -1018 return Corr(newcontent, prange=self.prange) + 982 if all([item is None for item in newcontent]): + 983 raise Exception("Division returns completely undefined correlator") + 984 return Corr(newcontent) + 985 + 986 elif isinstance(y, (Obs, CObs)): + 987 if isinstance(y, Obs): + 988 if y.value == 0: + 989 raise Exception('Division by zero will return undefined correlator') + 990 if isinstance(y, CObs): + 991 if y.is_zero(): + 992 raise Exception('Division by zero will return undefined correlator') + 993 + 994 newcontent = [] + 995 for t in range(self.T): + 996 if (self.content[t] is None): + 997 newcontent.append(None) + 998 else: + 999 newcontent.append(self.content[t] / y) +1000 return Corr(newcontent, prange=self.prange) +1001 +1002 elif isinstance(y, (int, float)): +1003 if y == 0: +1004 raise Exception('Division by zero will return undefined correlator') +1005 newcontent = [] +1006 for t in range(self.T): +1007 if (self.content[t] is None): +1008 newcontent.append(None) +1009 else: +1010 newcontent.append(self.content[t] / y) +1011 return Corr(newcontent, prange=self.prange) +1012 elif isinstance(y, np.ndarray): +1013 if y.shape == (self.T,): +1014 return Corr(list((np.array(self.content).T / y).T)) +1015 else: +1016 raise ValueError("operands could not be broadcast together") +1017 else: +1018 raise TypeError('Corr / wrong type') 1019 -1020 def __sub__(self, y): -1021 return self + (-y) -1022 -1023 def __pow__(self, y): -1024 if isinstance(y, (Obs, int, float, CObs)): -1025 newcontent = [None if (item is None) else item**y for item in self.content] -1026 return Corr(newcontent, prange=self.prange) -1027 else: -1028 raise TypeError('Type of exponent not supported') -1029 -1030 def __abs__(self): -1031 newcontent = [None if (item is None) else np.abs(item) for item in self.content] -1032 return Corr(newcontent, prange=self.prange) +1020 def __neg__(self): +1021 newcontent = [None if (item is None) else -1. * item for item in self.content] +1022 return Corr(newcontent, prange=self.prange) +1023 +1024 def __sub__(self, y): +1025 return self + (-y) +1026 +1027 def __pow__(self, y): +1028 if isinstance(y, (Obs, int, float, CObs)): +1029 newcontent = [None if (item is None) else item**y for item in self.content] +1030 return Corr(newcontent, prange=self.prange) +1031 else: +1032 raise TypeError('Type of exponent not supported') 1033 -1034 # The numpy functions: -1035 def sqrt(self): -1036 return self**0.5 +1034 def __abs__(self): +1035 newcontent = [None if (item is None) else np.abs(item) for item in self.content] +1036 return Corr(newcontent, prange=self.prange) 1037 -1038 def log(self): -1039 newcontent = [None if (item is None) else np.log(item) for item in self.content] -1040 return Corr(newcontent, prange=self.prange) +1038 # The numpy functions: +1039 def sqrt(self): +1040 return self**0.5 1041 -1042 def exp(self): -1043 newcontent = [None if (item is None) else np.exp(item) for item in self.content] +1042 def log(self): +1043 newcontent = [None if (item is None) else np.log(item) for item in self.content] 1044 return Corr(newcontent, prange=self.prange) 1045 -1046 def _apply_func_to_corr(self, func): -1047 newcontent = [None if (item is None) else func(item) for item in self.content] -1048 for t in range(self.T): -1049 if newcontent[t] is None: -1050 continue -1051 if np.isnan(np.sum(newcontent[t]).value): -1052 newcontent[t] = None -1053 if all([item is None for item in newcontent]): -1054 raise Exception('Operation returns undefined correlator') -1055 return Corr(newcontent) -1056 -1057 def sin(self): -1058 return self._apply_func_to_corr(np.sin) -1059 -1060 def cos(self): -1061 return self._apply_func_to_corr(np.cos) -1062 -1063 def tan(self): -1064 return self._apply_func_to_corr(np.tan) -1065 -1066 def sinh(self): -1067 return self._apply_func_to_corr(np.sinh) -1068 -1069 def cosh(self): -1070 return self._apply_func_to_corr(np.cosh) -1071 -1072 def tanh(self): -1073 return self._apply_func_to_corr(np.tanh) -1074 -1075 def arcsin(self): -1076 return self._apply_func_to_corr(np.arcsin) -1077 -1078 def arccos(self): -1079 return self._apply_func_to_corr(np.arccos) -1080 -1081 def arctan(self): -1082 return self._apply_func_to_corr(np.arctan) -1083 -1084 def arcsinh(self): -1085 return self._apply_func_to_corr(np.arcsinh) -1086 -1087 def arccosh(self): -1088 return self._apply_func_to_corr(np.arccosh) -1089 -1090 def arctanh(self): -1091 return self._apply_func_to_corr(np.arctanh) -1092 -1093 # Right hand side operations (require tweak in main module to work) -1094 def __radd__(self, y): -1095 return self + y +1046 def exp(self): +1047 newcontent = [None if (item is None) else np.exp(item) for item in self.content] +1048 return Corr(newcontent, prange=self.prange) +1049 +1050 def _apply_func_to_corr(self, func): +1051 newcontent = [None if (item is None) else func(item) for item in self.content] +1052 for t in range(self.T): +1053 if newcontent[t] is None: +1054 continue +1055 if np.isnan(np.sum(newcontent[t]).value): +1056 newcontent[t] = None +1057 if all([item is None for item in newcontent]): +1058 raise Exception('Operation returns undefined correlator') +1059 return Corr(newcontent) +1060 +1061 def sin(self): +1062 return self._apply_func_to_corr(np.sin) +1063 +1064 def cos(self): +1065 return self._apply_func_to_corr(np.cos) +1066 +1067 def tan(self): +1068 return self._apply_func_to_corr(np.tan) +1069 +1070 def sinh(self): +1071 return self._apply_func_to_corr(np.sinh) +1072 +1073 def cosh(self): +1074 return self._apply_func_to_corr(np.cosh) +1075 +1076 def tanh(self): +1077 return self._apply_func_to_corr(np.tanh) +1078 +1079 def arcsin(self): +1080 return self._apply_func_to_corr(np.arcsin) +1081 +1082 def arccos(self): +1083 return self._apply_func_to_corr(np.arccos) +1084 +1085 def arctan(self): +1086 return self._apply_func_to_corr(np.arctan) +1087 +1088 def arcsinh(self): +1089 return self._apply_func_to_corr(np.arcsinh) +1090 +1091 def arccosh(self): +1092 return self._apply_func_to_corr(np.arccosh) +1093 +1094 def arctanh(self): +1095 return self._apply_func_to_corr(np.arctanh) 1096 -1097 def __rsub__(self, y): -1098 return -self + y -1099 -1100 def __rmul__(self, y): -1101 return self * y -1102 -1103 def __rtruediv__(self, y): -1104 return (self / y) ** (-1) -1105 -1106 @property -1107 def real(self): -1108 def return_real(obs_OR_cobs): -1109 if isinstance(obs_OR_cobs, CObs): -1110 return obs_OR_cobs.real -1111 else: -1112 return obs_OR_cobs -1113 -1114 return self._apply_func_to_corr(return_real) -1115 -1116 @property -1117 def imag(self): -1118 def return_imag(obs_OR_cobs): -1119 if isinstance(obs_OR_cobs, CObs): -1120 return obs_OR_cobs.imag -1121 else: -1122 return obs_OR_cobs * 0 # So it stays the right type -1123 -1124 return self._apply_func_to_corr(return_imag) -1125 -1126 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): -1127 r''' Project large correlation matrix to lowest states -1128 -1129 This method can be used to reduce the size of an (N x N) correlation matrix -1130 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise -1131 is still small. +1097 # Right hand side operations (require tweak in main module to work) +1098 def __radd__(self, y): +1099 return self + y +1100 +1101 def __rsub__(self, y): +1102 return -self + y +1103 +1104 def __rmul__(self, y): +1105 return self * y +1106 +1107 def __rtruediv__(self, y): +1108 return (self / y) ** (-1) +1109 +1110 @property +1111 def real(self): +1112 def return_real(obs_OR_cobs): +1113 if isinstance(obs_OR_cobs, CObs): +1114 return obs_OR_cobs.real +1115 else: +1116 return obs_OR_cobs +1117 +1118 return self._apply_func_to_corr(return_real) +1119 +1120 @property +1121 def imag(self): +1122 def return_imag(obs_OR_cobs): +1123 if isinstance(obs_OR_cobs, CObs): +1124 return obs_OR_cobs.imag +1125 else: +1126 return obs_OR_cobs * 0 # So it stays the right type +1127 +1128 return self._apply_func_to_corr(return_imag) +1129 +1130 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): +1131 r''' Project large correlation matrix to lowest states 1132 -1133 Parameters -1134 ---------- -1135 Ntrunc: int -1136 Rank of the target matrix. -1137 tproj: int -1138 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. -1139 The default value is 3. -1140 t0proj: int -1141 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly -1142 discouraged for O(a) improved theories, since the correctness of the procedure -1143 cannot be granted in this case. The default value is 2. -1144 basematrix : Corr -1145 Correlation matrix that is used to determine the eigenvectors of the -1146 lowest states based on a GEVP. basematrix is taken to be the Corr itself if -1147 is is not specified. -1148 -1149 Notes -1150 ----- -1151 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving -1152 the GEVP $$C(t) v_n(t, t_0) = \lambda_n(t, t_0) C(t_0) v_n(t, t_0)$$ where $t \equiv t_\mathrm{proj}$ -1153 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the -1154 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via -1155 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large -1156 correlation matrix and to remove some noise that is added by irrelevant operators. -1157 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated -1158 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. -1159 ''' -1160 -1161 if self.N == 1: -1162 raise Exception('Method cannot be applied to one-dimensional correlators.') -1163 if basematrix is None: -1164 basematrix = self -1165 if Ntrunc >= basematrix.N: -1166 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) -1167 if basematrix.N != self.N: -1168 raise Exception('basematrix and targetmatrix have to be of the same size.') -1169 -1170 evecs = [] -1171 for i in range(Ntrunc): -1172 evecs.append(basematrix.GEVP(t0proj, tproj, state=i, sorted_list=None)) +1133 This method can be used to reduce the size of an (N x N) correlation matrix +1134 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise +1135 is still small. +1136 +1137 Parameters +1138 ---------- +1139 Ntrunc: int +1140 Rank of the target matrix. +1141 tproj: int +1142 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. +1143 The default value is 3. +1144 t0proj: int +1145 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly +1146 discouraged for O(a) improved theories, since the correctness of the procedure +1147 cannot be granted in this case. The default value is 2. +1148 basematrix : Corr +1149 Correlation matrix that is used to determine the eigenvectors of the +1150 lowest states based on a GEVP. basematrix is taken to be the Corr itself if +1151 is is not specified. +1152 +1153 Notes +1154 ----- +1155 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving +1156 the GEVP $$C(t) v_n(t, t_0) = \lambda_n(t, t_0) C(t_0) v_n(t, t_0)$$ where $t \equiv t_\mathrm{proj}$ +1157 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the +1158 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via +1159 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large +1160 correlation matrix and to remove some noise that is added by irrelevant operators. +1161 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated +1162 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. +1163 ''' +1164 +1165 if self.N == 1: +1166 raise Exception('Method cannot be applied to one-dimensional correlators.') +1167 if basematrix is None: +1168 basematrix = self +1169 if Ntrunc >= basematrix.N: +1170 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) +1171 if basematrix.N != self.N: +1172 raise Exception('basematrix and targetmatrix have to be of the same size.') 1173 -1174 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) -1175 rmat = [] -1176 for t in range(basematrix.T): -1177 for i in range(Ntrunc): -1178 for j in range(Ntrunc): -1179 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] -1180 rmat.append(np.copy(tmpmat)) -1181 -1182 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] -1183 return Corr(newcontent) -1184 +1174 evecs = [] +1175 for i in range(Ntrunc): +1176 evecs.append(basematrix.GEVP(t0proj, tproj, state=i, sorted_list=None)) +1177 +1178 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) +1179 rmat = [] +1180 for t in range(basematrix.T): +1181 for i in range(Ntrunc): +1182 for j in range(Ntrunc): +1183 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] +1184 rmat.append(np.copy(tmpmat)) 1185 -1186def _sort_vectors(vec_set, ts): -1187 """Helper function used to find a set of Eigenvectors consistent over all timeslices""" -1188 reference_sorting = np.array(vec_set[ts]) -1189 N = reference_sorting.shape[0] -1190 sorted_vec_set = [] -1191 for t in range(len(vec_set)): -1192 if vec_set[t] is None: -1193 sorted_vec_set.append(None) -1194 elif not t == ts: -1195 perms = [list(o) for o in permutations([i for i in range(N)], N)] -1196 best_score = 0 -1197 for perm in perms: -1198 current_score = 1 -1199 for k in range(N): -1200 new_sorting = reference_sorting.copy() -1201 new_sorting[perm[k], :] = vec_set[t][k] -1202 current_score *= abs(np.linalg.det(new_sorting)) -1203 if current_score > best_score: -1204 best_score = current_score -1205 best_perm = perm -1206 sorted_vec_set.append([vec_set[t][k] for k in best_perm]) -1207 else: -1208 sorted_vec_set.append(vec_set[t]) -1209 -1210 return sorted_vec_set -1211 -1212 -1213def _GEVP_solver(Gt, G0): # Just so normalization an sorting does not need to be repeated. Here we could later put in some checks -1214 sp_val, sp_vecs = scipy.linalg.eigh(Gt, G0) -1215 sp_vecs = [sp_vecs[:, np.argsort(sp_val)[-i]] for i in range(1, sp_vecs.shape[0] + 1)] -1216 sp_vecs = [v / np.sqrt((v.T @ G0 @ v)) for v in sp_vecs] -1217 return sp_vecs +1186 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] +1187 return Corr(newcontent) +1188 +1189 +1190def _sort_vectors(vec_set, ts): +1191 """Helper function used to find a set of Eigenvectors consistent over all timeslices""" +1192 reference_sorting = np.array(vec_set[ts]) +1193 N = reference_sorting.shape[0] +1194 sorted_vec_set = [] +1195 for t in range(len(vec_set)): +1196 if vec_set[t] is None: +1197 sorted_vec_set.append(None) +1198 elif not t == ts: +1199 perms = [list(o) for o in permutations([i for i in range(N)], N)] +1200 best_score = 0 +1201 for perm in perms: +1202 current_score = 1 +1203 for k in range(N): +1204 new_sorting = reference_sorting.copy() +1205 new_sorting[perm[k], :] = vec_set[t][k] +1206 current_score *= abs(np.linalg.det(new_sorting)) +1207 if current_score > best_score: +1208 best_score = current_score +1209 best_perm = perm +1210 sorted_vec_set.append([vec_set[t][k] for k in best_perm]) +1211 else: +1212 sorted_vec_set.append(vec_set[t]) +1213 +1214 return sorted_vec_set +1215 +1216 +1217def _GEVP_solver(Gt, G0): # Just so normalization an sorting does not need to be repeated. Here we could later put in some checks +1218 sp_val, sp_vecs = scipy.linalg.eigh(Gt, G0) +1219 sp_vecs = [sp_vecs[:, np.argsort(sp_val)[-i]] for i in range(1, sp_vecs.shape[0] + 1)] +1220 sp_vecs = [v / np.sqrt((v.T @ G0 @ v)) for v in sp_vecs] +1221 return sp_vecs @@ -1693,929 +1697,933 @@ 259 "Eigenvector" - Use the method described in arXiv:2004.10472 [hep-lat] to find the set of v(t) belonging to the state. 260 The reference state is identified by its eigenvalue at t=ts 261 """ - 262 symmetric_corr = self.matrix_symmetric() - 263 if sorted_list is None: - 264 if (ts is None): - 265 raise Exception("ts is required if sorted_list=None") - 266 if (self.content[t0] is None) or (self.content[ts] is None): - 267 raise Exception("Corr not defined at t0/ts") - 268 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") - 269 for i in range(self.N): - 270 for j in range(self.N): - 271 G0[i, j] = symmetric_corr[t0][i, j].value - 272 Gt[i, j] = symmetric_corr[ts][i, j].value - 273 - 274 sp_vecs = _GEVP_solver(Gt, G0) - 275 sp_vec = sp_vecs[state] - 276 return sp_vec - 277 elif sorted_list in ["Eigenvalue", "Eigenvector"]: - 278 all_vecs = [] - 279 for t in range(self.T): - 280 try: - 281 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") - 282 for i in range(self.N): - 283 for j in range(self.N): - 284 G0[i, j] = symmetric_corr[t0][i, j].value - 285 Gt[i, j] = symmetric_corr[t][i, j].value - 286 - 287 sp_vecs = _GEVP_solver(Gt, G0) - 288 if sorted_list == "Eigenvalue": - 289 sp_vec = sp_vecs[state] - 290 all_vecs.append(sp_vec) - 291 else: - 292 all_vecs.append(sp_vecs) - 293 except Exception: - 294 all_vecs.append(None) - 295 if sorted_list == "Eigenvector": - 296 if (ts is None): - 297 raise Exception("ts is required for the Eigenvector sorting method.") - 298 all_vecs = _sort_vectors(all_vecs, ts) - 299 all_vecs = [a[state] for a in all_vecs] - 300 else: - 301 raise Exception("Unkown value for 'sorted_list'.") - 302 - 303 return all_vecs - 304 - 305 def Eigenvalue(self, t0, ts=None, state=0, sorted_list=None): - 306 """Determines the eigenvalue of the GEVP by solving and projecting the correlator - 307 - 308 Parameters - 309 ---------- - 310 t0 : int - 311 The time t0 for G(t)v= lambda G(t_0)v - 312 ts : int - 313 fixed time G(t_s)v= lambda G(t_0)v if return_list=False - 314 If return_list=True and sorting=Eigenvector it gives a reference point for the sorting method. - 315 state : int - 316 The state one is interested in ordered by energy. The lowest state is zero. - 317 sorted_list : string - 318 if this argument is set, a list of vectors (len=self.T) is returned. If it is left as None, only one vector is returned. - 319 "Eigenvalue" - The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice. - 320 "Eigenvector" - Use the method described in arXiv:2004.10472 [hep-lat] to find the set of v(t) belonging to the state. - 321 The reference state is identified by its eigenvalue at t=ts - 322 """ - 323 vec = self.GEVP(t0, ts=ts, state=state, sorted_list=sorted_list) - 324 return self.projected(vec) - 325 - 326 def Hankel(self, N, periodic=False): - 327 """Constructs an NxN Hankel matrix - 328 - 329 C(t) c(t+1) ... c(t+n-1) - 330 C(t+1) c(t+2) ... c(t+n) - 331 ................. - 332 C(t+(n-1)) c(t+n) ... c(t+2(n-1)) - 333 - 334 Parameters - 335 ---------- - 336 N : int - 337 Dimension of the Hankel matrix - 338 periodic : bool, optional - 339 determines whether the matrix is extended periodically - 340 """ - 341 - 342 if self.N != 1: - 343 raise Exception("Multi-operator Prony not implemented!") - 344 - 345 array = np.empty([N, N], dtype="object") - 346 new_content = [] - 347 for t in range(self.T): - 348 new_content.append(array.copy()) - 349 - 350 def wrap(i): - 351 while i >= self.T: - 352 i -= self.T - 353 return i - 354 - 355 for t in range(self.T): - 356 for i in range(N): - 357 for j in range(N): - 358 if periodic: - 359 new_content[t][i, j] = self.content[wrap(t + i + j)][0] - 360 elif (t + i + j) >= self.T: - 361 new_content[t] = None - 362 else: - 363 new_content[t][i, j] = self.content[t + i + j][0] - 364 - 365 return Corr(new_content) - 366 - 367 def roll(self, dt): - 368 """Periodically shift the correlator by dt timeslices - 369 - 370 Parameters - 371 ---------- - 372 dt : int - 373 number of timeslices - 374 """ - 375 return Corr(list(np.roll(np.array(self.content, dtype=object), dt))) - 376 - 377 def reverse(self): - 378 """Reverse the time ordering of the Corr""" - 379 return Corr(self.content[:: -1]) + 262 + 263 if self.N == 1: + 264 raise Exception("GEVP methods only works on correlator matrices and not single correlators.") + 265 + 266 symmetric_corr = self.matrix_symmetric() + 267 if sorted_list is None: + 268 if (ts is None): + 269 raise Exception("ts is required if sorted_list=None") + 270 if (self.content[t0] is None) or (self.content[ts] is None): + 271 raise Exception("Corr not defined at t0/ts") + 272 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") + 273 for i in range(self.N): + 274 for j in range(self.N): + 275 G0[i, j] = symmetric_corr[t0][i, j].value + 276 Gt[i, j] = symmetric_corr[ts][i, j].value + 277 + 278 sp_vecs = _GEVP_solver(Gt, G0) + 279 sp_vec = sp_vecs[state] + 280 return sp_vec + 281 elif sorted_list in ["Eigenvalue", "Eigenvector"]: + 282 all_vecs = [] + 283 for t in range(self.T): + 284 try: + 285 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") + 286 for i in range(self.N): + 287 for j in range(self.N): + 288 G0[i, j] = symmetric_corr[t0][i, j].value + 289 Gt[i, j] = symmetric_corr[t][i, j].value + 290 + 291 sp_vecs = _GEVP_solver(Gt, G0) + 292 if sorted_list == "Eigenvalue": + 293 sp_vec = sp_vecs[state] + 294 all_vecs.append(sp_vec) + 295 else: + 296 all_vecs.append(sp_vecs) + 297 except Exception: + 298 all_vecs.append(None) + 299 if sorted_list == "Eigenvector": + 300 if (ts is None): + 301 raise Exception("ts is required for the Eigenvector sorting method.") + 302 all_vecs = _sort_vectors(all_vecs, ts) + 303 all_vecs = [a[state] for a in all_vecs] + 304 else: + 305 raise Exception("Unkown value for 'sorted_list'.") + 306 + 307 return all_vecs + 308 + 309 def Eigenvalue(self, t0, ts=None, state=0, sorted_list=None): + 310 """Determines the eigenvalue of the GEVP by solving and projecting the correlator + 311 + 312 Parameters + 313 ---------- + 314 t0 : int + 315 The time t0 for G(t)v= lambda G(t_0)v + 316 ts : int + 317 fixed time G(t_s)v= lambda G(t_0)v if return_list=False + 318 If return_list=True and sorting=Eigenvector it gives a reference point for the sorting method. + 319 state : int + 320 The state one is interested in ordered by energy. The lowest state is zero. + 321 sorted_list : string + 322 if this argument is set, a list of vectors (len=self.T) is returned. If it is left as None, only one vector is returned. + 323 "Eigenvalue" - The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice. + 324 "Eigenvector" - Use the method described in arXiv:2004.10472 [hep-lat] to find the set of v(t) belonging to the state. + 325 The reference state is identified by its eigenvalue at t=ts + 326 """ + 327 vec = self.GEVP(t0, ts=ts, state=state, sorted_list=sorted_list) + 328 return self.projected(vec) + 329 + 330 def Hankel(self, N, periodic=False): + 331 """Constructs an NxN Hankel matrix + 332 + 333 C(t) c(t+1) ... c(t+n-1) + 334 C(t+1) c(t+2) ... c(t+n) + 335 ................. + 336 C(t+(n-1)) c(t+n) ... c(t+2(n-1)) + 337 + 338 Parameters + 339 ---------- + 340 N : int + 341 Dimension of the Hankel matrix + 342 periodic : bool, optional + 343 determines whether the matrix is extended periodically + 344 """ + 345 + 346 if self.N != 1: + 347 raise Exception("Multi-operator Prony not implemented!") + 348 + 349 array = np.empty([N, N], dtype="object") + 350 new_content = [] + 351 for t in range(self.T): + 352 new_content.append(array.copy()) + 353 + 354 def wrap(i): + 355 while i >= self.T: + 356 i -= self.T + 357 return i + 358 + 359 for t in range(self.T): + 360 for i in range(N): + 361 for j in range(N): + 362 if periodic: + 363 new_content[t][i, j] = self.content[wrap(t + i + j)][0] + 364 elif (t + i + j) >= self.T: + 365 new_content[t] = None + 366 else: + 367 new_content[t][i, j] = self.content[t + i + j][0] + 368 + 369 return Corr(new_content) + 370 + 371 def roll(self, dt): + 372 """Periodically shift the correlator by dt timeslices + 373 + 374 Parameters + 375 ---------- + 376 dt : int + 377 number of timeslices + 378 """ + 379 return Corr(list(np.roll(np.array(self.content, dtype=object), dt))) 380 - 381 def thin(self, spacing=2, offset=0): - 382 """Thin out a correlator to suppress correlations - 383 - 384 Parameters - 385 ---------- - 386 spacing : int - 387 Keep only every 'spacing'th entry of the correlator - 388 offset : int - 389 Offset the equal spacing - 390 """ - 391 new_content = [] - 392 for t in range(self.T): - 393 if (offset + t) % spacing != 0: - 394 new_content.append(None) - 395 else: - 396 new_content.append(self.content[t]) - 397 return Corr(new_content) - 398 - 399 def correlate(self, partner): - 400 """Correlate the correlator with another correlator or Obs - 401 - 402 Parameters - 403 ---------- - 404 partner : Obs or Corr - 405 partner to correlate the correlator with. - 406 Can either be an Obs which is correlated with all entries of the - 407 correlator or a Corr of same length. - 408 """ - 409 new_content = [] - 410 for x0, t_slice in enumerate(self.content): - 411 if t_slice is None: - 412 new_content.append(None) - 413 else: - 414 if isinstance(partner, Corr): - 415 if partner.content[x0] is None: - 416 new_content.append(None) - 417 else: - 418 new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice])) - 419 elif isinstance(partner, Obs): # Should this include CObs? - 420 new_content.append(np.array([correlate(o, partner) for o in t_slice])) - 421 else: - 422 raise Exception("Can only correlate with an Obs or a Corr.") - 423 - 424 return Corr(new_content) - 425 - 426 def reweight(self, weight, **kwargs): - 427 """Reweight the correlator. - 428 - 429 Parameters - 430 ---------- - 431 weight : Obs - 432 Reweighting factor. An Observable that has to be defined on a superset of the - 433 configurations in obs[i].idl for all i. - 434 all_configs : bool - 435 if True, the reweighted observables are normalized by the average of - 436 the reweighting factor on all configurations in weight.idl and not - 437 on the configurations in obs[i].idl. - 438 """ - 439 new_content = [] - 440 for t_slice in self.content: - 441 if t_slice is None: - 442 new_content.append(None) - 443 else: - 444 new_content.append(np.array(reweight(weight, t_slice, **kwargs))) - 445 return Corr(new_content) - 446 - 447 def T_symmetry(self, partner, parity=+1): - 448 """Return the time symmetry average of the correlator and its partner - 449 - 450 Parameters - 451 ---------- - 452 partner : Corr - 453 Time symmetry partner of the Corr - 454 partity : int - 455 Parity quantum number of the correlator, can be +1 or -1 - 456 """ - 457 if not isinstance(partner, Corr): - 458 raise Exception("T partner has to be a Corr object.") - 459 if parity not in [+1, -1]: - 460 raise Exception("Parity has to be +1 or -1.") - 461 T_partner = parity * partner.reverse() - 462 - 463 t_slices = [] - 464 test = (self - T_partner) - 465 test.gamma_method() - 466 for x0, t_slice in enumerate(test.content): - 467 if t_slice is not None: - 468 if not t_slice[0].is_zero_within_error(5): - 469 t_slices.append(x0) - 470 if t_slices: - 471 warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning) - 472 - 473 return (self + T_partner) / 2 - 474 - 475 def deriv(self, variant="symmetric"): - 476 """Return the first derivative of the correlator with respect to x0. - 477 - 478 Parameters - 479 ---------- - 480 variant : str - 481 decides which definition of the finite differences derivative is used. - 482 Available choice: symmetric, forward, backward, improved, default: symmetric - 483 """ - 484 if variant == "symmetric": - 485 newcontent = [] - 486 for t in range(1, self.T - 1): - 487 if (self.content[t - 1] is None) or (self.content[t + 1] is None): - 488 newcontent.append(None) - 489 else: - 490 newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1])) - 491 if(all([x is None for x in newcontent])): - 492 raise Exception('Derivative is undefined at all timeslices') - 493 return Corr(newcontent, padding=[1, 1]) - 494 elif variant == "forward": - 495 newcontent = [] - 496 for t in range(self.T - 1): - 497 if (self.content[t] is None) or (self.content[t + 1] is None): - 498 newcontent.append(None) - 499 else: - 500 newcontent.append(self.content[t + 1] - self.content[t]) - 501 if(all([x is None for x in newcontent])): - 502 raise Exception("Derivative is undefined at all timeslices") - 503 return Corr(newcontent, padding=[0, 1]) - 504 elif variant == "backward": - 505 newcontent = [] - 506 for t in range(1, self.T): - 507 if (self.content[t - 1] is None) or (self.content[t] is None): - 508 newcontent.append(None) - 509 else: - 510 newcontent.append(self.content[t] - self.content[t - 1]) - 511 if(all([x is None for x in newcontent])): - 512 raise Exception("Derivative is undefined at all timeslices") - 513 return Corr(newcontent, padding=[1, 0]) - 514 elif variant == "improved": - 515 newcontent = [] - 516 for t in range(2, self.T - 2): - 517 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): - 518 newcontent.append(None) - 519 else: - 520 newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2])) - 521 if(all([x is None for x in newcontent])): - 522 raise Exception('Derivative is undefined at all timeslices') - 523 return Corr(newcontent, padding=[2, 2]) - 524 else: - 525 raise Exception("Unknown variant.") - 526 - 527 def second_deriv(self, variant="symmetric"): - 528 """Return the second derivative of the correlator with respect to x0. - 529 - 530 Parameters - 531 ---------- - 532 variant : str - 533 decides which definition of the finite differences derivative is used. - 534 Available choice: symmetric, improved, default: symmetric - 535 """ - 536 if variant == "symmetric": - 537 newcontent = [] - 538 for t in range(1, self.T - 1): - 539 if (self.content[t - 1] is None) or (self.content[t + 1] is None): - 540 newcontent.append(None) - 541 else: - 542 newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1])) - 543 if(all([x is None for x in newcontent])): - 544 raise Exception("Derivative is undefined at all timeslices") - 545 return Corr(newcontent, padding=[1, 1]) - 546 elif variant == "improved": - 547 newcontent = [] - 548 for t in range(2, self.T - 2): - 549 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): - 550 newcontent.append(None) - 551 else: - 552 newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2])) - 553 if(all([x is None for x in newcontent])): - 554 raise Exception("Derivative is undefined at all timeslices") - 555 return Corr(newcontent, padding=[2, 2]) - 556 else: - 557 raise Exception("Unknown variant.") - 558 - 559 def m_eff(self, variant='log', guess=1.0): - 560 """Returns the effective mass of the correlator as correlator object - 561 - 562 Parameters - 563 ---------- - 564 variant : str - 565 log : uses the standard effective mass log(C(t) / C(t+1)) - 566 cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m. - 567 sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m. - 568 See, e.g., arXiv:1205.5380 - 569 arccosh : Uses the explicit form of the symmetrized correlator (not recommended) - 570 guess : float - 571 guess for the root finder, only relevant for the root variant - 572 """ - 573 if self.N != 1: - 574 raise Exception('Correlator must be projected before getting m_eff') - 575 if variant == 'log': - 576 newcontent = [] - 577 for t in range(self.T - 1): - 578 if (self.content[t] is None) or (self.content[t + 1] is None): - 579 newcontent.append(None) - 580 else: - 581 newcontent.append(self.content[t] / self.content[t + 1]) - 582 if(all([x is None for x in newcontent])): - 583 raise Exception('m_eff is undefined at all timeslices') - 584 - 585 return np.log(Corr(newcontent, padding=[0, 1])) - 586 - 587 elif variant in ['periodic', 'cosh', 'sinh']: - 588 if variant in ['periodic', 'cosh']: - 589 func = anp.cosh - 590 else: - 591 func = anp.sinh - 592 - 593 def root_function(x, d): - 594 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d - 595 - 596 newcontent = [] - 597 for t in range(self.T - 1): - 598 if (self.content[t] is None) or (self.content[t + 1] is None): - 599 newcontent.append(None) - 600 # Fill the two timeslices in the middle of the lattice with their predecessors - 601 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: - 602 newcontent.append(newcontent[-1]) - 603 else: - 604 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) - 605 if(all([x is None for x in newcontent])): - 606 raise Exception('m_eff is undefined at all timeslices') - 607 - 608 return Corr(newcontent, padding=[0, 1]) - 609 - 610 elif variant == 'arccosh': - 611 newcontent = [] - 612 for t in range(1, self.T - 1): - 613 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None): - 614 newcontent.append(None) - 615 else: - 616 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) - 617 if(all([x is None for x in newcontent])): - 618 raise Exception("m_eff is undefined at all timeslices") - 619 return np.arccosh(Corr(newcontent, padding=[1, 1])) - 620 - 621 else: - 622 raise Exception('Unknown variant.') - 623 - 624 def fit(self, function, fitrange=None, silent=False, **kwargs): - 625 r'''Fits function to the data - 626 - 627 Parameters - 628 ---------- - 629 function : obj - 630 function to fit to the data. See fits.least_squares for details. - 631 fitrange : list - 632 Two element list containing the timeslices on which the fit is supposed to start and stop. - 633 Caution: This range is inclusive as opposed to standard python indexing. - 634 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. - 635 If not specified, self.prange or all timeslices are used. - 636 silent : bool - 637 Decides whether output is printed to the standard output. - 638 ''' - 639 if self.N != 1: - 640 raise Exception("Correlator must be projected before fitting") - 641 - 642 if fitrange is None: - 643 if self.prange: - 644 fitrange = self.prange - 645 else: - 646 fitrange = [0, self.T - 1] - 647 else: - 648 if not isinstance(fitrange, list): - 649 raise Exception("fitrange has to be a list with two elements") - 650 if len(fitrange) != 2: - 651 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") - 652 - 653 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 654 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 655 result = least_squares(xs, ys, function, silent=silent, **kwargs) - 656 return result - 657 - 658 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): - 659 """ Extract a plateau value from a Corr object - 660 - 661 Parameters - 662 ---------- - 663 plateau_range : list - 664 list with two entries, indicating the first and the last timeslice - 665 of the plateau region. - 666 method : str - 667 method to extract the plateau. - 668 'fit' fits a constant to the plateau region - 669 'avg', 'average' or 'mean' just average over the given timeslices. - 670 auto_gamma : bool - 671 apply gamma_method with default parameters to the Corr. Defaults to None - 672 """ - 673 if not plateau_range: - 674 if self.prange: - 675 plateau_range = self.prange - 676 else: - 677 raise Exception("no plateau range provided") - 678 if self.N != 1: - 679 raise Exception("Correlator must be projected before getting a plateau.") - 680 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): - 681 raise Exception("plateau is undefined at all timeslices in plateaurange.") - 682 if auto_gamma: - 683 self.gamma_method() - 684 if method == "fit": - 685 def const_func(a, t): - 686 return a[0] - 687 return self.fit(const_func, plateau_range)[0] - 688 elif method in ["avg", "average", "mean"]: - 689 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) - 690 return returnvalue - 691 - 692 else: - 693 raise Exception("Unsupported plateau method: " + method) - 694 - 695 def set_prange(self, prange): - 696 """Sets the attribute prange of the Corr object.""" - 697 if not len(prange) == 2: - 698 raise Exception("prange must be a list or array with two values") - 699 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): - 700 raise Exception("Start and end point must be integers") - 701 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): - 702 raise Exception("Start and end point must define a range in the interval 0,T") - 703 - 704 self.prange = prange - 705 return - 706 - 707 def show(self, x_range=None, comp=None, y_range=None, logscale=False, plateau=None, fit_res=None, ylabel=None, save=None, auto_gamma=False, hide_sigma=None, references=None): - 708 """Plots the correlator using the tag of the correlator as label if available. - 709 - 710 Parameters - 711 ---------- - 712 x_range : list - 713 list of two values, determining the range of the x-axis e.g. [4, 8] - 714 comp : Corr or list of Corr - 715 Correlator or list of correlators which are plotted for comparison. - 716 The tags of these correlators are used as labels if available. - 717 logscale : bool - 718 Sets y-axis to logscale - 719 plateau : Obs - 720 Plateau value to be visualized in the figure - 721 fit_res : Fit_result - 722 Fit_result object to be visualized - 723 ylabel : str - 724 Label for the y-axis - 725 save : str - 726 path to file in which the figure should be saved - 727 auto_gamma : bool - 728 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. - 729 hide_sigma : float - 730 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. - 731 references : list - 732 List of floating point values that are displayed as horizontal lines for reference. - 733 """ - 734 if self.N != 1: - 735 raise Exception("Correlator must be projected before plotting") - 736 - 737 if auto_gamma: - 738 self.gamma_method() - 739 - 740 if x_range is None: - 741 x_range = [0, self.T - 1] - 742 - 743 fig = plt.figure() - 744 ax1 = fig.add_subplot(111) - 745 - 746 x, y, y_err = self.plottable() - 747 if hide_sigma: - 748 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 - 749 else: - 750 hide_from = None - 751 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) - 752 if logscale: - 753 ax1.set_yscale('log') - 754 else: - 755 if y_range is None: - 756 try: - 757 y_min = min([(x[0].value - x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) - 758 y_max = max([(x[0].value + x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) - 759 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) - 760 except Exception: - 761 pass - 762 else: - 763 ax1.set_ylim(y_range) - 764 if comp: - 765 if isinstance(comp, (Corr, list)): - 766 for corr in comp if isinstance(comp, list) else [comp]: - 767 if auto_gamma: - 768 corr.gamma_method() - 769 x, y, y_err = corr.plottable() - 770 if hide_sigma: - 771 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 - 772 else: - 773 hide_from = None - 774 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) - 775 else: - 776 raise Exception("'comp' must be a correlator or a list of correlators.") - 777 - 778 if plateau: - 779 if isinstance(plateau, Obs): - 780 if auto_gamma: - 781 plateau.gamma_method() - 782 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) - 783 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') - 784 else: - 785 raise Exception("'plateau' must be an Obs") - 786 - 787 if references: - 788 if isinstance(references, list): - 789 for ref in references: - 790 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') - 791 else: - 792 raise Exception("'references' must be a list of floating pint values.") - 793 - 794 if self.prange: - 795 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') - 796 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') + 381 def reverse(self): + 382 """Reverse the time ordering of the Corr""" + 383 return Corr(self.content[:: -1]) + 384 + 385 def thin(self, spacing=2, offset=0): + 386 """Thin out a correlator to suppress correlations + 387 + 388 Parameters + 389 ---------- + 390 spacing : int + 391 Keep only every 'spacing'th entry of the correlator + 392 offset : int + 393 Offset the equal spacing + 394 """ + 395 new_content = [] + 396 for t in range(self.T): + 397 if (offset + t) % spacing != 0: + 398 new_content.append(None) + 399 else: + 400 new_content.append(self.content[t]) + 401 return Corr(new_content) + 402 + 403 def correlate(self, partner): + 404 """Correlate the correlator with another correlator or Obs + 405 + 406 Parameters + 407 ---------- + 408 partner : Obs or Corr + 409 partner to correlate the correlator with. + 410 Can either be an Obs which is correlated with all entries of the + 411 correlator or a Corr of same length. + 412 """ + 413 new_content = [] + 414 for x0, t_slice in enumerate(self.content): + 415 if t_slice is None: + 416 new_content.append(None) + 417 else: + 418 if isinstance(partner, Corr): + 419 if partner.content[x0] is None: + 420 new_content.append(None) + 421 else: + 422 new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice])) + 423 elif isinstance(partner, Obs): # Should this include CObs? + 424 new_content.append(np.array([correlate(o, partner) for o in t_slice])) + 425 else: + 426 raise Exception("Can only correlate with an Obs or a Corr.") + 427 + 428 return Corr(new_content) + 429 + 430 def reweight(self, weight, **kwargs): + 431 """Reweight the correlator. + 432 + 433 Parameters + 434 ---------- + 435 weight : Obs + 436 Reweighting factor. An Observable that has to be defined on a superset of the + 437 configurations in obs[i].idl for all i. + 438 all_configs : bool + 439 if True, the reweighted observables are normalized by the average of + 440 the reweighting factor on all configurations in weight.idl and not + 441 on the configurations in obs[i].idl. + 442 """ + 443 new_content = [] + 444 for t_slice in self.content: + 445 if t_slice is None: + 446 new_content.append(None) + 447 else: + 448 new_content.append(np.array(reweight(weight, t_slice, **kwargs))) + 449 return Corr(new_content) + 450 + 451 def T_symmetry(self, partner, parity=+1): + 452 """Return the time symmetry average of the correlator and its partner + 453 + 454 Parameters + 455 ---------- + 456 partner : Corr + 457 Time symmetry partner of the Corr + 458 partity : int + 459 Parity quantum number of the correlator, can be +1 or -1 + 460 """ + 461 if not isinstance(partner, Corr): + 462 raise Exception("T partner has to be a Corr object.") + 463 if parity not in [+1, -1]: + 464 raise Exception("Parity has to be +1 or -1.") + 465 T_partner = parity * partner.reverse() + 466 + 467 t_slices = [] + 468 test = (self - T_partner) + 469 test.gamma_method() + 470 for x0, t_slice in enumerate(test.content): + 471 if t_slice is not None: + 472 if not t_slice[0].is_zero_within_error(5): + 473 t_slices.append(x0) + 474 if t_slices: + 475 warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning) + 476 + 477 return (self + T_partner) / 2 + 478 + 479 def deriv(self, variant="symmetric"): + 480 """Return the first derivative of the correlator with respect to x0. + 481 + 482 Parameters + 483 ---------- + 484 variant : str + 485 decides which definition of the finite differences derivative is used. + 486 Available choice: symmetric, forward, backward, improved, default: symmetric + 487 """ + 488 if variant == "symmetric": + 489 newcontent = [] + 490 for t in range(1, self.T - 1): + 491 if (self.content[t - 1] is None) or (self.content[t + 1] is None): + 492 newcontent.append(None) + 493 else: + 494 newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1])) + 495 if(all([x is None for x in newcontent])): + 496 raise Exception('Derivative is undefined at all timeslices') + 497 return Corr(newcontent, padding=[1, 1]) + 498 elif variant == "forward": + 499 newcontent = [] + 500 for t in range(self.T - 1): + 501 if (self.content[t] is None) or (self.content[t + 1] is None): + 502 newcontent.append(None) + 503 else: + 504 newcontent.append(self.content[t + 1] - self.content[t]) + 505 if(all([x is None for x in newcontent])): + 506 raise Exception("Derivative is undefined at all timeslices") + 507 return Corr(newcontent, padding=[0, 1]) + 508 elif variant == "backward": + 509 newcontent = [] + 510 for t in range(1, self.T): + 511 if (self.content[t - 1] is None) or (self.content[t] is None): + 512 newcontent.append(None) + 513 else: + 514 newcontent.append(self.content[t] - self.content[t - 1]) + 515 if(all([x is None for x in newcontent])): + 516 raise Exception("Derivative is undefined at all timeslices") + 517 return Corr(newcontent, padding=[1, 0]) + 518 elif variant == "improved": + 519 newcontent = [] + 520 for t in range(2, self.T - 2): + 521 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): + 522 newcontent.append(None) + 523 else: + 524 newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2])) + 525 if(all([x is None for x in newcontent])): + 526 raise Exception('Derivative is undefined at all timeslices') + 527 return Corr(newcontent, padding=[2, 2]) + 528 else: + 529 raise Exception("Unknown variant.") + 530 + 531 def second_deriv(self, variant="symmetric"): + 532 """Return the second derivative of the correlator with respect to x0. + 533 + 534 Parameters + 535 ---------- + 536 variant : str + 537 decides which definition of the finite differences derivative is used. + 538 Available choice: symmetric, improved, default: symmetric + 539 """ + 540 if variant == "symmetric": + 541 newcontent = [] + 542 for t in range(1, self.T - 1): + 543 if (self.content[t - 1] is None) or (self.content[t + 1] is None): + 544 newcontent.append(None) + 545 else: + 546 newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1])) + 547 if(all([x is None for x in newcontent])): + 548 raise Exception("Derivative is undefined at all timeslices") + 549 return Corr(newcontent, padding=[1, 1]) + 550 elif variant == "improved": + 551 newcontent = [] + 552 for t in range(2, self.T - 2): + 553 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): + 554 newcontent.append(None) + 555 else: + 556 newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2])) + 557 if(all([x is None for x in newcontent])): + 558 raise Exception("Derivative is undefined at all timeslices") + 559 return Corr(newcontent, padding=[2, 2]) + 560 else: + 561 raise Exception("Unknown variant.") + 562 + 563 def m_eff(self, variant='log', guess=1.0): + 564 """Returns the effective mass of the correlator as correlator object + 565 + 566 Parameters + 567 ---------- + 568 variant : str + 569 log : uses the standard effective mass log(C(t) / C(t+1)) + 570 cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m. + 571 sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m. + 572 See, e.g., arXiv:1205.5380 + 573 arccosh : Uses the explicit form of the symmetrized correlator (not recommended) + 574 guess : float + 575 guess for the root finder, only relevant for the root variant + 576 """ + 577 if self.N != 1: + 578 raise Exception('Correlator must be projected before getting m_eff') + 579 if variant == 'log': + 580 newcontent = [] + 581 for t in range(self.T - 1): + 582 if (self.content[t] is None) or (self.content[t + 1] is None): + 583 newcontent.append(None) + 584 else: + 585 newcontent.append(self.content[t] / self.content[t + 1]) + 586 if(all([x is None for x in newcontent])): + 587 raise Exception('m_eff is undefined at all timeslices') + 588 + 589 return np.log(Corr(newcontent, padding=[0, 1])) + 590 + 591 elif variant in ['periodic', 'cosh', 'sinh']: + 592 if variant in ['periodic', 'cosh']: + 593 func = anp.cosh + 594 else: + 595 func = anp.sinh + 596 + 597 def root_function(x, d): + 598 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d + 599 + 600 newcontent = [] + 601 for t in range(self.T - 1): + 602 if (self.content[t] is None) or (self.content[t + 1] is None): + 603 newcontent.append(None) + 604 # Fill the two timeslices in the middle of the lattice with their predecessors + 605 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: + 606 newcontent.append(newcontent[-1]) + 607 else: + 608 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) + 609 if(all([x is None for x in newcontent])): + 610 raise Exception('m_eff is undefined at all timeslices') + 611 + 612 return Corr(newcontent, padding=[0, 1]) + 613 + 614 elif variant == 'arccosh': + 615 newcontent = [] + 616 for t in range(1, self.T - 1): + 617 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None): + 618 newcontent.append(None) + 619 else: + 620 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) + 621 if(all([x is None for x in newcontent])): + 622 raise Exception("m_eff is undefined at all timeslices") + 623 return np.arccosh(Corr(newcontent, padding=[1, 1])) + 624 + 625 else: + 626 raise Exception('Unknown variant.') + 627 + 628 def fit(self, function, fitrange=None, silent=False, **kwargs): + 629 r'''Fits function to the data + 630 + 631 Parameters + 632 ---------- + 633 function : obj + 634 function to fit to the data. See fits.least_squares for details. + 635 fitrange : list + 636 Two element list containing the timeslices on which the fit is supposed to start and stop. + 637 Caution: This range is inclusive as opposed to standard python indexing. + 638 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. + 639 If not specified, self.prange or all timeslices are used. + 640 silent : bool + 641 Decides whether output is printed to the standard output. + 642 ''' + 643 if self.N != 1: + 644 raise Exception("Correlator must be projected before fitting") + 645 + 646 if fitrange is None: + 647 if self.prange: + 648 fitrange = self.prange + 649 else: + 650 fitrange = [0, self.T - 1] + 651 else: + 652 if not isinstance(fitrange, list): + 653 raise Exception("fitrange has to be a list with two elements") + 654 if len(fitrange) != 2: + 655 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") + 656 + 657 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 658 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 659 result = least_squares(xs, ys, function, silent=silent, **kwargs) + 660 return result + 661 + 662 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): + 663 """ Extract a plateau value from a Corr object + 664 + 665 Parameters + 666 ---------- + 667 plateau_range : list + 668 list with two entries, indicating the first and the last timeslice + 669 of the plateau region. + 670 method : str + 671 method to extract the plateau. + 672 'fit' fits a constant to the plateau region + 673 'avg', 'average' or 'mean' just average over the given timeslices. + 674 auto_gamma : bool + 675 apply gamma_method with default parameters to the Corr. Defaults to None + 676 """ + 677 if not plateau_range: + 678 if self.prange: + 679 plateau_range = self.prange + 680 else: + 681 raise Exception("no plateau range provided") + 682 if self.N != 1: + 683 raise Exception("Correlator must be projected before getting a plateau.") + 684 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): + 685 raise Exception("plateau is undefined at all timeslices in plateaurange.") + 686 if auto_gamma: + 687 self.gamma_method() + 688 if method == "fit": + 689 def const_func(a, t): + 690 return a[0] + 691 return self.fit(const_func, plateau_range)[0] + 692 elif method in ["avg", "average", "mean"]: + 693 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) + 694 return returnvalue + 695 + 696 else: + 697 raise Exception("Unsupported plateau method: " + method) + 698 + 699 def set_prange(self, prange): + 700 """Sets the attribute prange of the Corr object.""" + 701 if not len(prange) == 2: + 702 raise Exception("prange must be a list or array with two values") + 703 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): + 704 raise Exception("Start and end point must be integers") + 705 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): + 706 raise Exception("Start and end point must define a range in the interval 0,T") + 707 + 708 self.prange = prange + 709 return + 710 + 711 def show(self, x_range=None, comp=None, y_range=None, logscale=False, plateau=None, fit_res=None, ylabel=None, save=None, auto_gamma=False, hide_sigma=None, references=None): + 712 """Plots the correlator using the tag of the correlator as label if available. + 713 + 714 Parameters + 715 ---------- + 716 x_range : list + 717 list of two values, determining the range of the x-axis e.g. [4, 8] + 718 comp : Corr or list of Corr + 719 Correlator or list of correlators which are plotted for comparison. + 720 The tags of these correlators are used as labels if available. + 721 logscale : bool + 722 Sets y-axis to logscale + 723 plateau : Obs + 724 Plateau value to be visualized in the figure + 725 fit_res : Fit_result + 726 Fit_result object to be visualized + 727 ylabel : str + 728 Label for the y-axis + 729 save : str + 730 path to file in which the figure should be saved + 731 auto_gamma : bool + 732 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. + 733 hide_sigma : float + 734 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. + 735 references : list + 736 List of floating point values that are displayed as horizontal lines for reference. + 737 """ + 738 if self.N != 1: + 739 raise Exception("Correlator must be projected before plotting") + 740 + 741 if auto_gamma: + 742 self.gamma_method() + 743 + 744 if x_range is None: + 745 x_range = [0, self.T - 1] + 746 + 747 fig = plt.figure() + 748 ax1 = fig.add_subplot(111) + 749 + 750 x, y, y_err = self.plottable() + 751 if hide_sigma: + 752 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 + 753 else: + 754 hide_from = None + 755 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) + 756 if logscale: + 757 ax1.set_yscale('log') + 758 else: + 759 if y_range is None: + 760 try: + 761 y_min = min([(x[0].value - x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) + 762 y_max = max([(x[0].value + x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) + 763 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) + 764 except Exception: + 765 pass + 766 else: + 767 ax1.set_ylim(y_range) + 768 if comp: + 769 if isinstance(comp, (Corr, list)): + 770 for corr in comp if isinstance(comp, list) else [comp]: + 771 if auto_gamma: + 772 corr.gamma_method() + 773 x, y, y_err = corr.plottable() + 774 if hide_sigma: + 775 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 + 776 else: + 777 hide_from = None + 778 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) + 779 else: + 780 raise Exception("'comp' must be a correlator or a list of correlators.") + 781 + 782 if plateau: + 783 if isinstance(plateau, Obs): + 784 if auto_gamma: + 785 plateau.gamma_method() + 786 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) + 787 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') + 788 else: + 789 raise Exception("'plateau' must be an Obs") + 790 + 791 if references: + 792 if isinstance(references, list): + 793 for ref in references: + 794 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') + 795 else: + 796 raise Exception("'references' must be a list of floating pint values.") 797 - 798 if fit_res: - 799 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) - 800 ax1.plot(x_samples, - 801 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), - 802 ls='-', marker=',', lw=2) - 803 - 804 ax1.set_xlabel(r'$x_0 / a$') - 805 if ylabel: - 806 ax1.set_ylabel(ylabel) - 807 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) - 808 - 809 handles, labels = ax1.get_legend_handles_labels() - 810 if labels: - 811 ax1.legend() - 812 plt.draw() - 813 - 814 if save: - 815 if isinstance(save, str): - 816 fig.savefig(save) - 817 else: - 818 raise Exception("'save' has to be a string.") - 819 - 820 def spaghetti_plot(self, logscale=True): - 821 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. - 822 - 823 Parameters - 824 ---------- - 825 logscale : bool - 826 Determines whether the scale of the y-axis is logarithmic or standard. - 827 """ - 828 if self.N != 1: - 829 raise Exception("Correlator needs to be projected first.") - 830 - 831 mc_names = list(set([item for sublist in [o[0].mc_names for o in self.content if o is not None] for item in sublist])) - 832 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] - 833 - 834 for name in mc_names: - 835 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T - 836 - 837 fig = plt.figure() - 838 ax = fig.add_subplot(111) - 839 for dat in data: - 840 ax.plot(x0_vals, dat, ls='-', marker='') - 841 - 842 if logscale is True: - 843 ax.set_yscale('log') - 844 - 845 ax.set_xlabel(r'$x_0 / a$') - 846 plt.title(name) - 847 plt.draw() + 798 if self.prange: + 799 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') + 800 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') + 801 + 802 if fit_res: + 803 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) + 804 ax1.plot(x_samples, + 805 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), + 806 ls='-', marker=',', lw=2) + 807 + 808 ax1.set_xlabel(r'$x_0 / a$') + 809 if ylabel: + 810 ax1.set_ylabel(ylabel) + 811 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) + 812 + 813 handles, labels = ax1.get_legend_handles_labels() + 814 if labels: + 815 ax1.legend() + 816 plt.draw() + 817 + 818 if save: + 819 if isinstance(save, str): + 820 fig.savefig(save) + 821 else: + 822 raise Exception("'save' has to be a string.") + 823 + 824 def spaghetti_plot(self, logscale=True): + 825 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. + 826 + 827 Parameters + 828 ---------- + 829 logscale : bool + 830 Determines whether the scale of the y-axis is logarithmic or standard. + 831 """ + 832 if self.N != 1: + 833 raise Exception("Correlator needs to be projected first.") + 834 + 835 mc_names = list(set([item for sublist in [o[0].mc_names for o in self.content if o is not None] for item in sublist])) + 836 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] + 837 + 838 for name in mc_names: + 839 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T + 840 + 841 fig = plt.figure() + 842 ax = fig.add_subplot(111) + 843 for dat in data: + 844 ax.plot(x0_vals, dat, ls='-', marker='') + 845 + 846 if logscale is True: + 847 ax.set_yscale('log') 848 - 849 def dump(self, filename, datatype="json.gz", **kwargs): - 850 """Dumps the Corr into a file of chosen type - 851 Parameters - 852 ---------- - 853 filename : str - 854 Name of the file to be saved. - 855 datatype : str - 856 Format of the exported file. Supported formats include - 857 "json.gz" and "pickle" - 858 path : str - 859 specifies a custom path for the file (default '.') - 860 """ - 861 if datatype == "json.gz": - 862 from .input.json import dump_to_json - 863 if 'path' in kwargs: - 864 file_name = kwargs.get('path') + '/' + filename - 865 else: - 866 file_name = filename - 867 dump_to_json(self, file_name) - 868 elif datatype == "pickle": - 869 dump_object(self, filename, **kwargs) - 870 else: - 871 raise Exception("Unknown datatype " + str(datatype)) - 872 - 873 def print(self, range=[0, None]): - 874 print(self.__repr__(range)) - 875 - 876 def __repr__(self, range=[0, None]): - 877 content_string = "" - 878 - 879 content_string += "Corr T=" + str(self.T) + " N=" + str(self.N) + "\n" # +" filled with"+ str(type(self.content[0][0])) there should be a good solution here - 880 - 881 if self.tag is not None: - 882 content_string += "Description: " + self.tag + "\n" - 883 if self.N != 1: - 884 return content_string - 885 - 886 if range[1]: - 887 range[1] += 1 - 888 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' - 889 for i, sub_corr in enumerate(self.content[range[0]:range[1]]): - 890 if sub_corr is None: - 891 content_string += str(i + range[0]) + '\n' - 892 else: - 893 content_string += str(i + range[0]) - 894 for element in sub_corr: - 895 content_string += '\t' + ' ' * int(element >= 0) + str(element) - 896 content_string += '\n' - 897 return content_string - 898 - 899 def __str__(self): - 900 return self.__repr__() - 901 - 902 # We define the basic operations, that can be performed with correlators. - 903 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. - 904 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. - 905 # One could try and tell Obs to check if the y in __mul__ is a Corr and - 906 - 907 def __add__(self, y): - 908 if isinstance(y, Corr): - 909 if ((self.N != y.N) or (self.T != y.T)): - 910 raise Exception("Addition of Corrs with different shape") - 911 newcontent = [] - 912 for t in range(self.T): - 913 if (self.content[t] is None) or (y.content[t] is None): - 914 newcontent.append(None) - 915 else: - 916 newcontent.append(self.content[t] + y.content[t]) - 917 return Corr(newcontent) - 918 - 919 elif isinstance(y, (Obs, int, float, CObs)): - 920 newcontent = [] - 921 for t in range(self.T): - 922 if (self.content[t] is None): - 923 newcontent.append(None) - 924 else: - 925 newcontent.append(self.content[t] + y) - 926 return Corr(newcontent, prange=self.prange) - 927 elif isinstance(y, np.ndarray): - 928 if y.shape == (self.T,): - 929 return Corr(list((np.array(self.content).T + y).T)) - 930 else: - 931 raise ValueError("operands could not be broadcast together") - 932 else: - 933 raise TypeError("Corr + wrong type") - 934 - 935 def __mul__(self, y): - 936 if isinstance(y, Corr): - 937 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): - 938 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") - 939 newcontent = [] - 940 for t in range(self.T): - 941 if (self.content[t] is None) or (y.content[t] is None): - 942 newcontent.append(None) - 943 else: - 944 newcontent.append(self.content[t] * y.content[t]) - 945 return Corr(newcontent) - 946 - 947 elif isinstance(y, (Obs, int, float, CObs)): - 948 newcontent = [] - 949 for t in range(self.T): - 950 if (self.content[t] is None): - 951 newcontent.append(None) - 952 else: - 953 newcontent.append(self.content[t] * y) - 954 return Corr(newcontent, prange=self.prange) - 955 elif isinstance(y, np.ndarray): - 956 if y.shape == (self.T,): - 957 return Corr(list((np.array(self.content).T * y).T)) - 958 else: - 959 raise ValueError("operands could not be broadcast together") - 960 else: - 961 raise TypeError("Corr * wrong type") - 962 - 963 def __truediv__(self, y): - 964 if isinstance(y, Corr): - 965 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): - 966 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") - 967 newcontent = [] - 968 for t in range(self.T): - 969 if (self.content[t] is None) or (y.content[t] is None): - 970 newcontent.append(None) - 971 else: - 972 newcontent.append(self.content[t] / y.content[t]) - 973 for t in range(self.T): - 974 if newcontent[t] is None: - 975 continue - 976 if np.isnan(np.sum(newcontent[t]).value): - 977 newcontent[t] = None - 978 - 979 if all([item is None for item in newcontent]): - 980 raise Exception("Division returns completely undefined correlator") - 981 return Corr(newcontent) + 849 ax.set_xlabel(r'$x_0 / a$') + 850 plt.title(name) + 851 plt.draw() + 852 + 853 def dump(self, filename, datatype="json.gz", **kwargs): + 854 """Dumps the Corr into a file of chosen type + 855 Parameters + 856 ---------- + 857 filename : str + 858 Name of the file to be saved. + 859 datatype : str + 860 Format of the exported file. Supported formats include + 861 "json.gz" and "pickle" + 862 path : str + 863 specifies a custom path for the file (default '.') + 864 """ + 865 if datatype == "json.gz": + 866 from .input.json import dump_to_json + 867 if 'path' in kwargs: + 868 file_name = kwargs.get('path') + '/' + filename + 869 else: + 870 file_name = filename + 871 dump_to_json(self, file_name) + 872 elif datatype == "pickle": + 873 dump_object(self, filename, **kwargs) + 874 else: + 875 raise Exception("Unknown datatype " + str(datatype)) + 876 + 877 def print(self, range=[0, None]): + 878 print(self.__repr__(range)) + 879 + 880 def __repr__(self, range=[0, None]): + 881 content_string = "" + 882 + 883 content_string += "Corr T=" + str(self.T) + " N=" + str(self.N) + "\n" # +" filled with"+ str(type(self.content[0][0])) there should be a good solution here + 884 + 885 if self.tag is not None: + 886 content_string += "Description: " + self.tag + "\n" + 887 if self.N != 1: + 888 return content_string + 889 + 890 if range[1]: + 891 range[1] += 1 + 892 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' + 893 for i, sub_corr in enumerate(self.content[range[0]:range[1]]): + 894 if sub_corr is None: + 895 content_string += str(i + range[0]) + '\n' + 896 else: + 897 content_string += str(i + range[0]) + 898 for element in sub_corr: + 899 content_string += '\t' + ' ' * int(element >= 0) + str(element) + 900 content_string += '\n' + 901 return content_string + 902 + 903 def __str__(self): + 904 return self.__repr__() + 905 + 906 # We define the basic operations, that can be performed with correlators. + 907 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. + 908 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. + 909 # One could try and tell Obs to check if the y in __mul__ is a Corr and + 910 + 911 def __add__(self, y): + 912 if isinstance(y, Corr): + 913 if ((self.N != y.N) or (self.T != y.T)): + 914 raise Exception("Addition of Corrs with different shape") + 915 newcontent = [] + 916 for t in range(self.T): + 917 if (self.content[t] is None) or (y.content[t] is None): + 918 newcontent.append(None) + 919 else: + 920 newcontent.append(self.content[t] + y.content[t]) + 921 return Corr(newcontent) + 922 + 923 elif isinstance(y, (Obs, int, float, CObs)): + 924 newcontent = [] + 925 for t in range(self.T): + 926 if (self.content[t] is None): + 927 newcontent.append(None) + 928 else: + 929 newcontent.append(self.content[t] + y) + 930 return Corr(newcontent, prange=self.prange) + 931 elif isinstance(y, np.ndarray): + 932 if y.shape == (self.T,): + 933 return Corr(list((np.array(self.content).T + y).T)) + 934 else: + 935 raise ValueError("operands could not be broadcast together") + 936 else: + 937 raise TypeError("Corr + wrong type") + 938 + 939 def __mul__(self, y): + 940 if isinstance(y, Corr): + 941 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): + 942 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") + 943 newcontent = [] + 944 for t in range(self.T): + 945 if (self.content[t] is None) or (y.content[t] is None): + 946 newcontent.append(None) + 947 else: + 948 newcontent.append(self.content[t] * y.content[t]) + 949 return Corr(newcontent) + 950 + 951 elif isinstance(y, (Obs, int, float, CObs)): + 952 newcontent = [] + 953 for t in range(self.T): + 954 if (self.content[t] is None): + 955 newcontent.append(None) + 956 else: + 957 newcontent.append(self.content[t] * y) + 958 return Corr(newcontent, prange=self.prange) + 959 elif isinstance(y, np.ndarray): + 960 if y.shape == (self.T,): + 961 return Corr(list((np.array(self.content).T * y).T)) + 962 else: + 963 raise ValueError("operands could not be broadcast together") + 964 else: + 965 raise TypeError("Corr * wrong type") + 966 + 967 def __truediv__(self, y): + 968 if isinstance(y, Corr): + 969 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): + 970 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") + 971 newcontent = [] + 972 for t in range(self.T): + 973 if (self.content[t] is None) or (y.content[t] is None): + 974 newcontent.append(None) + 975 else: + 976 newcontent.append(self.content[t] / y.content[t]) + 977 for t in range(self.T): + 978 if newcontent[t] is None: + 979 continue + 980 if np.isnan(np.sum(newcontent[t]).value): + 981 newcontent[t] = None 982 - 983 elif isinstance(y, (Obs, CObs)): - 984 if isinstance(y, Obs): - 985 if y.value == 0: - 986 raise Exception('Division by zero will return undefined correlator') - 987 if isinstance(y, CObs): - 988 if y.is_zero(): - 989 raise Exception('Division by zero will return undefined correlator') - 990 - 991 newcontent = [] - 992 for t in range(self.T): - 993 if (self.content[t] is None): - 994 newcontent.append(None) - 995 else: - 996 newcontent.append(self.content[t] / y) - 997 return Corr(newcontent, prange=self.prange) - 998 - 999 elif isinstance(y, (int, float)): -1000 if y == 0: -1001 raise Exception('Division by zero will return undefined correlator') -1002 newcontent = [] -1003 for t in range(self.T): -1004 if (self.content[t] is None): -1005 newcontent.append(None) -1006 else: -1007 newcontent.append(self.content[t] / y) -1008 return Corr(newcontent, prange=self.prange) -1009 elif isinstance(y, np.ndarray): -1010 if y.shape == (self.T,): -1011 return Corr(list((np.array(self.content).T / y).T)) -1012 else: -1013 raise ValueError("operands could not be broadcast together") -1014 else: -1015 raise TypeError('Corr / wrong type') -1016 -1017 def __neg__(self): -1018 newcontent = [None if (item is None) else -1. * item for item in self.content] -1019 return Corr(newcontent, prange=self.prange) + 983 if all([item is None for item in newcontent]): + 984 raise Exception("Division returns completely undefined correlator") + 985 return Corr(newcontent) + 986 + 987 elif isinstance(y, (Obs, CObs)): + 988 if isinstance(y, Obs): + 989 if y.value == 0: + 990 raise Exception('Division by zero will return undefined correlator') + 991 if isinstance(y, CObs): + 992 if y.is_zero(): + 993 raise Exception('Division by zero will return undefined correlator') + 994 + 995 newcontent = [] + 996 for t in range(self.T): + 997 if (self.content[t] is None): + 998 newcontent.append(None) + 999 else: +1000 newcontent.append(self.content[t] / y) +1001 return Corr(newcontent, prange=self.prange) +1002 +1003 elif isinstance(y, (int, float)): +1004 if y == 0: +1005 raise Exception('Division by zero will return undefined correlator') +1006 newcontent = [] +1007 for t in range(self.T): +1008 if (self.content[t] is None): +1009 newcontent.append(None) +1010 else: +1011 newcontent.append(self.content[t] / y) +1012 return Corr(newcontent, prange=self.prange) +1013 elif isinstance(y, np.ndarray): +1014 if y.shape == (self.T,): +1015 return Corr(list((np.array(self.content).T / y).T)) +1016 else: +1017 raise ValueError("operands could not be broadcast together") +1018 else: +1019 raise TypeError('Corr / wrong type') 1020 -1021 def __sub__(self, y): -1022 return self + (-y) -1023 -1024 def __pow__(self, y): -1025 if isinstance(y, (Obs, int, float, CObs)): -1026 newcontent = [None if (item is None) else item**y for item in self.content] -1027 return Corr(newcontent, prange=self.prange) -1028 else: -1029 raise TypeError('Type of exponent not supported') -1030 -1031 def __abs__(self): -1032 newcontent = [None if (item is None) else np.abs(item) for item in self.content] -1033 return Corr(newcontent, prange=self.prange) +1021 def __neg__(self): +1022 newcontent = [None if (item is None) else -1. * item for item in self.content] +1023 return Corr(newcontent, prange=self.prange) +1024 +1025 def __sub__(self, y): +1026 return self + (-y) +1027 +1028 def __pow__(self, y): +1029 if isinstance(y, (Obs, int, float, CObs)): +1030 newcontent = [None if (item is None) else item**y for item in self.content] +1031 return Corr(newcontent, prange=self.prange) +1032 else: +1033 raise TypeError('Type of exponent not supported') 1034 -1035 # The numpy functions: -1036 def sqrt(self): -1037 return self**0.5 +1035 def __abs__(self): +1036 newcontent = [None if (item is None) else np.abs(item) for item in self.content] +1037 return Corr(newcontent, prange=self.prange) 1038 -1039 def log(self): -1040 newcontent = [None if (item is None) else np.log(item) for item in self.content] -1041 return Corr(newcontent, prange=self.prange) +1039 # The numpy functions: +1040 def sqrt(self): +1041 return self**0.5 1042 -1043 def exp(self): -1044 newcontent = [None if (item is None) else np.exp(item) for item in self.content] +1043 def log(self): +1044 newcontent = [None if (item is None) else np.log(item) for item in self.content] 1045 return Corr(newcontent, prange=self.prange) 1046 -1047 def _apply_func_to_corr(self, func): -1048 newcontent = [None if (item is None) else func(item) for item in self.content] -1049 for t in range(self.T): -1050 if newcontent[t] is None: -1051 continue -1052 if np.isnan(np.sum(newcontent[t]).value): -1053 newcontent[t] = None -1054 if all([item is None for item in newcontent]): -1055 raise Exception('Operation returns undefined correlator') -1056 return Corr(newcontent) -1057 -1058 def sin(self): -1059 return self._apply_func_to_corr(np.sin) -1060 -1061 def cos(self): -1062 return self._apply_func_to_corr(np.cos) -1063 -1064 def tan(self): -1065 return self._apply_func_to_corr(np.tan) -1066 -1067 def sinh(self): -1068 return self._apply_func_to_corr(np.sinh) -1069 -1070 def cosh(self): -1071 return self._apply_func_to_corr(np.cosh) -1072 -1073 def tanh(self): -1074 return self._apply_func_to_corr(np.tanh) -1075 -1076 def arcsin(self): -1077 return self._apply_func_to_corr(np.arcsin) -1078 -1079 def arccos(self): -1080 return self._apply_func_to_corr(np.arccos) -1081 -1082 def arctan(self): -1083 return self._apply_func_to_corr(np.arctan) -1084 -1085 def arcsinh(self): -1086 return self._apply_func_to_corr(np.arcsinh) -1087 -1088 def arccosh(self): -1089 return self._apply_func_to_corr(np.arccosh) -1090 -1091 def arctanh(self): -1092 return self._apply_func_to_corr(np.arctanh) -1093 -1094 # Right hand side operations (require tweak in main module to work) -1095 def __radd__(self, y): -1096 return self + y +1047 def exp(self): +1048 newcontent = [None if (item is None) else np.exp(item) for item in self.content] +1049 return Corr(newcontent, prange=self.prange) +1050 +1051 def _apply_func_to_corr(self, func): +1052 newcontent = [None if (item is None) else func(item) for item in self.content] +1053 for t in range(self.T): +1054 if newcontent[t] is None: +1055 continue +1056 if np.isnan(np.sum(newcontent[t]).value): +1057 newcontent[t] = None +1058 if all([item is None for item in newcontent]): +1059 raise Exception('Operation returns undefined correlator') +1060 return Corr(newcontent) +1061 +1062 def sin(self): +1063 return self._apply_func_to_corr(np.sin) +1064 +1065 def cos(self): +1066 return self._apply_func_to_corr(np.cos) +1067 +1068 def tan(self): +1069 return self._apply_func_to_corr(np.tan) +1070 +1071 def sinh(self): +1072 return self._apply_func_to_corr(np.sinh) +1073 +1074 def cosh(self): +1075 return self._apply_func_to_corr(np.cosh) +1076 +1077 def tanh(self): +1078 return self._apply_func_to_corr(np.tanh) +1079 +1080 def arcsin(self): +1081 return self._apply_func_to_corr(np.arcsin) +1082 +1083 def arccos(self): +1084 return self._apply_func_to_corr(np.arccos) +1085 +1086 def arctan(self): +1087 return self._apply_func_to_corr(np.arctan) +1088 +1089 def arcsinh(self): +1090 return self._apply_func_to_corr(np.arcsinh) +1091 +1092 def arccosh(self): +1093 return self._apply_func_to_corr(np.arccosh) +1094 +1095 def arctanh(self): +1096 return self._apply_func_to_corr(np.arctanh) 1097 -1098 def __rsub__(self, y): -1099 return -self + y -1100 -1101 def __rmul__(self, y): -1102 return self * y -1103 -1104 def __rtruediv__(self, y): -1105 return (self / y) ** (-1) -1106 -1107 @property -1108 def real(self): -1109 def return_real(obs_OR_cobs): -1110 if isinstance(obs_OR_cobs, CObs): -1111 return obs_OR_cobs.real -1112 else: -1113 return obs_OR_cobs -1114 -1115 return self._apply_func_to_corr(return_real) -1116 -1117 @property -1118 def imag(self): -1119 def return_imag(obs_OR_cobs): -1120 if isinstance(obs_OR_cobs, CObs): -1121 return obs_OR_cobs.imag -1122 else: -1123 return obs_OR_cobs * 0 # So it stays the right type -1124 -1125 return self._apply_func_to_corr(return_imag) -1126 -1127 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): -1128 r''' Project large correlation matrix to lowest states -1129 -1130 This method can be used to reduce the size of an (N x N) correlation matrix -1131 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise -1132 is still small. +1098 # Right hand side operations (require tweak in main module to work) +1099 def __radd__(self, y): +1100 return self + y +1101 +1102 def __rsub__(self, y): +1103 return -self + y +1104 +1105 def __rmul__(self, y): +1106 return self * y +1107 +1108 def __rtruediv__(self, y): +1109 return (self / y) ** (-1) +1110 +1111 @property +1112 def real(self): +1113 def return_real(obs_OR_cobs): +1114 if isinstance(obs_OR_cobs, CObs): +1115 return obs_OR_cobs.real +1116 else: +1117 return obs_OR_cobs +1118 +1119 return self._apply_func_to_corr(return_real) +1120 +1121 @property +1122 def imag(self): +1123 def return_imag(obs_OR_cobs): +1124 if isinstance(obs_OR_cobs, CObs): +1125 return obs_OR_cobs.imag +1126 else: +1127 return obs_OR_cobs * 0 # So it stays the right type +1128 +1129 return self._apply_func_to_corr(return_imag) +1130 +1131 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): +1132 r''' Project large correlation matrix to lowest states 1133 -1134 Parameters -1135 ---------- -1136 Ntrunc: int -1137 Rank of the target matrix. -1138 tproj: int -1139 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. -1140 The default value is 3. -1141 t0proj: int -1142 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly -1143 discouraged for O(a) improved theories, since the correctness of the procedure -1144 cannot be granted in this case. The default value is 2. -1145 basematrix : Corr -1146 Correlation matrix that is used to determine the eigenvectors of the -1147 lowest states based on a GEVP. basematrix is taken to be the Corr itself if -1148 is is not specified. -1149 -1150 Notes -1151 ----- -1152 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving -1153 the GEVP $$C(t) v_n(t, t_0) = \lambda_n(t, t_0) C(t_0) v_n(t, t_0)$$ where $t \equiv t_\mathrm{proj}$ -1154 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the -1155 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via -1156 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large -1157 correlation matrix and to remove some noise that is added by irrelevant operators. -1158 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated -1159 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. -1160 ''' -1161 -1162 if self.N == 1: -1163 raise Exception('Method cannot be applied to one-dimensional correlators.') -1164 if basematrix is None: -1165 basematrix = self -1166 if Ntrunc >= basematrix.N: -1167 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) -1168 if basematrix.N != self.N: -1169 raise Exception('basematrix and targetmatrix have to be of the same size.') -1170 -1171 evecs = [] -1172 for i in range(Ntrunc): -1173 evecs.append(basematrix.GEVP(t0proj, tproj, state=i, sorted_list=None)) +1134 This method can be used to reduce the size of an (N x N) correlation matrix +1135 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise +1136 is still small. +1137 +1138 Parameters +1139 ---------- +1140 Ntrunc: int +1141 Rank of the target matrix. +1142 tproj: int +1143 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. +1144 The default value is 3. +1145 t0proj: int +1146 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly +1147 discouraged for O(a) improved theories, since the correctness of the procedure +1148 cannot be granted in this case. The default value is 2. +1149 basematrix : Corr +1150 Correlation matrix that is used to determine the eigenvectors of the +1151 lowest states based on a GEVP. basematrix is taken to be the Corr itself if +1152 is is not specified. +1153 +1154 Notes +1155 ----- +1156 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving +1157 the GEVP $$C(t) v_n(t, t_0) = \lambda_n(t, t_0) C(t_0) v_n(t, t_0)$$ where $t \equiv t_\mathrm{proj}$ +1158 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the +1159 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via +1160 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large +1161 correlation matrix and to remove some noise that is added by irrelevant operators. +1162 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated +1163 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. +1164 ''' +1165 +1166 if self.N == 1: +1167 raise Exception('Method cannot be applied to one-dimensional correlators.') +1168 if basematrix is None: +1169 basematrix = self +1170 if Ntrunc >= basematrix.N: +1171 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) +1172 if basematrix.N != self.N: +1173 raise Exception('basematrix and targetmatrix have to be of the same size.') 1174 -1175 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) -1176 rmat = [] -1177 for t in range(basematrix.T): -1178 for i in range(Ntrunc): -1179 for j in range(Ntrunc): -1180 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] -1181 rmat.append(np.copy(tmpmat)) -1182 -1183 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] -1184 return Corr(newcontent) +1175 evecs = [] +1176 for i in range(Ntrunc): +1177 evecs.append(basematrix.GEVP(t0proj, tproj, state=i, sorted_list=None)) +1178 +1179 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) +1180 rmat = [] +1181 for t in range(basematrix.T): +1182 for i in range(Ntrunc): +1183 for j in range(Ntrunc): +1184 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] +1185 rmat.append(np.copy(tmpmat)) +1186 +1187 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] +1188 return Corr(newcontent) @@ -3042,48 +3050,52 @@ timeslice and the error on each timeslice.
259 "Eigenvector" - Use the method described in arXiv:2004.10472 [hep-lat] to find the set of v(t) belonging to the state. 260 The reference state is identified by its eigenvalue at t=ts 261 """ -262 symmetric_corr = self.matrix_symmetric() -263 if sorted_list is None: -264 if (ts is None): -265 raise Exception("ts is required if sorted_list=None") -266 if (self.content[t0] is None) or (self.content[ts] is None): -267 raise Exception("Corr not defined at t0/ts") -268 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") -269 for i in range(self.N): -270 for j in range(self.N): -271 G0[i, j] = symmetric_corr[t0][i, j].value -272 Gt[i, j] = symmetric_corr[ts][i, j].value -273 -274 sp_vecs = _GEVP_solver(Gt, G0) -275 sp_vec = sp_vecs[state] -276 return sp_vec -277 elif sorted_list in ["Eigenvalue", "Eigenvector"]: -278 all_vecs = [] -279 for t in range(self.T): -280 try: -281 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") -282 for i in range(self.N): -283 for j in range(self.N): -284 G0[i, j] = symmetric_corr[t0][i, j].value -285 Gt[i, j] = symmetric_corr[t][i, j].value -286 -287 sp_vecs = _GEVP_solver(Gt, G0) -288 if sorted_list == "Eigenvalue": -289 sp_vec = sp_vecs[state] -290 all_vecs.append(sp_vec) -291 else: -292 all_vecs.append(sp_vecs) -293 except Exception: -294 all_vecs.append(None) -295 if sorted_list == "Eigenvector": -296 if (ts is None): -297 raise Exception("ts is required for the Eigenvector sorting method.") -298 all_vecs = _sort_vectors(all_vecs, ts) -299 all_vecs = [a[state] for a in all_vecs] -300 else: -301 raise Exception("Unkown value for 'sorted_list'.") -302 -303 return all_vecs +262 +263 if self.N == 1: +264 raise Exception("GEVP methods only works on correlator matrices and not single correlators.") +265 +266 symmetric_corr = self.matrix_symmetric() +267 if sorted_list is None: +268 if (ts is None): +269 raise Exception("ts is required if sorted_list=None") +270 if (self.content[t0] is None) or (self.content[ts] is None): +271 raise Exception("Corr not defined at t0/ts") +272 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") +273 for i in range(self.N): +274 for j in range(self.N): +275 G0[i, j] = symmetric_corr[t0][i, j].value +276 Gt[i, j] = symmetric_corr[ts][i, j].value +277 +278 sp_vecs = _GEVP_solver(Gt, G0) +279 sp_vec = sp_vecs[state] +280 return sp_vec +281 elif sorted_list in ["Eigenvalue", "Eigenvector"]: +282 all_vecs = [] +283 for t in range(self.T): +284 try: +285 G0, Gt = np.empty([self.N, self.N], dtype="double"), np.empty([self.N, self.N], dtype="double") +286 for i in range(self.N): +287 for j in range(self.N): +288 G0[i, j] = symmetric_corr[t0][i, j].value +289 Gt[i, j] = symmetric_corr[t][i, j].value +290 +291 sp_vecs = _GEVP_solver(Gt, G0) +292 if sorted_list == "Eigenvalue": +293 sp_vec = sp_vecs[state] +294 all_vecs.append(sp_vec) +295 else: +296 all_vecs.append(sp_vecs) +297 except Exception: +298 all_vecs.append(None) +299 if sorted_list == "Eigenvector": +300 if (ts is None): +301 raise Exception("ts is required for the Eigenvector sorting method.") +302 all_vecs = _sort_vectors(all_vecs, ts) +303 all_vecs = [a[state] for a in all_vecs] +304 else: +305 raise Exception("Unkown value for 'sorted_list'.") +306 +307 return all_vecs @@ -3120,26 +3132,26 @@ if this argument is set, a list of vectors (len=self.T) is returned. If it is le305 def Eigenvalue(self, t0, ts=None, state=0, sorted_list=None): -306 """Determines the eigenvalue of the GEVP by solving and projecting the correlator -307 -308 Parameters -309 ---------- -310 t0 : int -311 The time t0 for G(t)v= lambda G(t_0)v -312 ts : int -313 fixed time G(t_s)v= lambda G(t_0)v if return_list=False -314 If return_list=True and sorting=Eigenvector it gives a reference point for the sorting method. -315 state : int -316 The state one is interested in ordered by energy. The lowest state is zero. -317 sorted_list : string -318 if this argument is set, a list of vectors (len=self.T) is returned. If it is left as None, only one vector is returned. -319 "Eigenvalue" - The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice. -320 "Eigenvector" - Use the method described in arXiv:2004.10472 [hep-lat] to find the set of v(t) belonging to the state. -321 The reference state is identified by its eigenvalue at t=ts -322 """ -323 vec = self.GEVP(t0, ts=ts, state=state, sorted_list=sorted_list) -324 return self.projected(vec) +@@ -3176,46 +3188,46 @@ if this argument is set, a list of vectors (len=self.T) is returned. If it is le309 def Eigenvalue(self, t0, ts=None, state=0, sorted_list=None): +310 """Determines the eigenvalue of the GEVP by solving and projecting the correlator +311 +312 Parameters +313 ---------- +314 t0 : int +315 The time t0 for G(t)v= lambda G(t_0)v +316 ts : int +317 fixed time G(t_s)v= lambda G(t_0)v if return_list=False +318 If return_list=True and sorting=Eigenvector it gives a reference point for the sorting method. +319 state : int +320 The state one is interested in ordered by energy. The lowest state is zero. +321 sorted_list : string +322 if this argument is set, a list of vectors (len=self.T) is returned. If it is left as None, only one vector is returned. +323 "Eigenvalue" - The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice. +324 "Eigenvector" - Use the method described in arXiv:2004.10472 [hep-lat] to find the set of v(t) belonging to the state. +325 The reference state is identified by its eigenvalue at t=ts +326 """ +327 vec = self.GEVP(t0, ts=ts, state=state, sorted_list=sorted_list) +328 return self.projected(vec)View Source
-326 def Hankel(self, N, periodic=False): -327 """Constructs an NxN Hankel matrix -328 -329 C(t) c(t+1) ... c(t+n-1) -330 C(t+1) c(t+2) ... c(t+n) -331 ................. -332 C(t+(n-1)) c(t+n) ... c(t+2(n-1)) -333 -334 Parameters -335 ---------- -336 N : int -337 Dimension of the Hankel matrix -338 periodic : bool, optional -339 determines whether the matrix is extended periodically -340 """ -341 -342 if self.N != 1: -343 raise Exception("Multi-operator Prony not implemented!") -344 -345 array = np.empty([N, N], dtype="object") -346 new_content = [] -347 for t in range(self.T): -348 new_content.append(array.copy()) -349 -350 def wrap(i): -351 while i >= self.T: -352 i -= self.T -353 return i -354 -355 for t in range(self.T): -356 for i in range(N): -357 for j in range(N): -358 if periodic: -359 new_content[t][i, j] = self.content[wrap(t + i + j)][0] -360 elif (t + i + j) >= self.T: -361 new_content[t] = None -362 else: -363 new_content[t][i, j] = self.content[t + i + j][0] -364 -365 return Corr(new_content) +@@ -3249,15 +3261,15 @@ determines whether the matrix is extended periodically330 def Hankel(self, N, periodic=False): +331 """Constructs an NxN Hankel matrix +332 +333 C(t) c(t+1) ... c(t+n-1) +334 C(t+1) c(t+2) ... c(t+n) +335 ................. +336 C(t+(n-1)) c(t+n) ... c(t+2(n-1)) +337 +338 Parameters +339 ---------- +340 N : int +341 Dimension of the Hankel matrix +342 periodic : bool, optional +343 determines whether the matrix is extended periodically +344 """ +345 +346 if self.N != 1: +347 raise Exception("Multi-operator Prony not implemented!") +348 +349 array = np.empty([N, N], dtype="object") +350 new_content = [] +351 for t in range(self.T): +352 new_content.append(array.copy()) +353 +354 def wrap(i): +355 while i >= self.T: +356 i -= self.T +357 return i +358 +359 for t in range(self.T): +360 for i in range(N): +361 for j in range(N): +362 if periodic: +363 new_content[t][i, j] = self.content[wrap(t + i + j)][0] +364 elif (t + i + j) >= self.T: +365 new_content[t] = None +366 else: +367 new_content[t][i, j] = self.content[t + i + j][0] +368 +369 return Corr(new_content)View Source
-367 def roll(self, dt): -368 """Periodically shift the correlator by dt timeslices -369 -370 Parameters -371 ---------- -372 dt : int -373 number of timeslices -374 """ -375 return Corr(list(np.roll(np.array(self.content, dtype=object), dt))) +@@ -3284,9 +3296,9 @@ number of timeslices371 def roll(self, dt): +372 """Periodically shift the correlator by dt timeslices +373 +374 Parameters +375 ---------- +376 dt : int +377 number of timeslices +378 """ +379 return Corr(list(np.roll(np.array(self.content, dtype=object), dt)))View Source
-377 def reverse(self): -378 """Reverse the time ordering of the Corr""" -379 return Corr(self.content[:: -1]) +@@ -3306,23 +3318,23 @@ number of timeslices381 def reverse(self): +382 """Reverse the time ordering of the Corr""" +383 return Corr(self.content[:: -1])View Source
-381 def thin(self, spacing=2, offset=0): -382 """Thin out a correlator to suppress correlations -383 -384 Parameters -385 ---------- -386 spacing : int -387 Keep only every 'spacing'th entry of the correlator -388 offset : int -389 Offset the equal spacing -390 """ -391 new_content = [] -392 for t in range(self.T): -393 if (offset + t) % spacing != 0: -394 new_content.append(None) -395 else: -396 new_content.append(self.content[t]) -397 return Corr(new_content) +@@ -3351,32 +3363,32 @@ Offset the equal spacing385 def thin(self, spacing=2, offset=0): +386 """Thin out a correlator to suppress correlations +387 +388 Parameters +389 ---------- +390 spacing : int +391 Keep only every 'spacing'th entry of the correlator +392 offset : int +393 Offset the equal spacing +394 """ +395 new_content = [] +396 for t in range(self.T): +397 if (offset + t) % spacing != 0: +398 new_content.append(None) +399 else: +400 new_content.append(self.content[t]) +401 return Corr(new_content)View Source
-399 def correlate(self, partner): -400 """Correlate the correlator with another correlator or Obs -401 -402 Parameters -403 ---------- -404 partner : Obs or Corr -405 partner to correlate the correlator with. -406 Can either be an Obs which is correlated with all entries of the -407 correlator or a Corr of same length. -408 """ -409 new_content = [] -410 for x0, t_slice in enumerate(self.content): -411 if t_slice is None: -412 new_content.append(None) -413 else: -414 if isinstance(partner, Corr): -415 if partner.content[x0] is None: -416 new_content.append(None) -417 else: -418 new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice])) -419 elif isinstance(partner, Obs): # Should this include CObs? -420 new_content.append(np.array([correlate(o, partner) for o in t_slice])) -421 else: -422 raise Exception("Can only correlate with an Obs or a Corr.") -423 -424 return Corr(new_content) +@@ -3405,26 +3417,26 @@ correlator or a Corr of same length.403 def correlate(self, partner): +404 """Correlate the correlator with another correlator or Obs +405 +406 Parameters +407 ---------- +408 partner : Obs or Corr +409 partner to correlate the correlator with. +410 Can either be an Obs which is correlated with all entries of the +411 correlator or a Corr of same length. +412 """ +413 new_content = [] +414 for x0, t_slice in enumerate(self.content): +415 if t_slice is None: +416 new_content.append(None) +417 else: +418 if isinstance(partner, Corr): +419 if partner.content[x0] is None: +420 new_content.append(None) +421 else: +422 new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice])) +423 elif isinstance(partner, Obs): # Should this include CObs? +424 new_content.append(np.array([correlate(o, partner) for o in t_slice])) +425 else: +426 raise Exception("Can only correlate with an Obs or a Corr.") +427 +428 return Corr(new_content)View Source
-426 def reweight(self, weight, **kwargs): -427 """Reweight the correlator. -428 -429 Parameters -430 ---------- -431 weight : Obs -432 Reweighting factor. An Observable that has to be defined on a superset of the -433 configurations in obs[i].idl for all i. -434 all_configs : bool -435 if True, the reweighted observables are normalized by the average of -436 the reweighting factor on all configurations in weight.idl and not -437 on the configurations in obs[i].idl. -438 """ -439 new_content = [] -440 for t_slice in self.content: -441 if t_slice is None: -442 new_content.append(None) -443 else: -444 new_content.append(np.array(reweight(weight, t_slice, **kwargs))) -445 return Corr(new_content) +@@ -3456,33 +3468,33 @@ on the configurations in obs[i].idl.430 def reweight(self, weight, **kwargs): +431 """Reweight the correlator. +432 +433 Parameters +434 ---------- +435 weight : Obs +436 Reweighting factor. An Observable that has to be defined on a superset of the +437 configurations in obs[i].idl for all i. +438 all_configs : bool +439 if True, the reweighted observables are normalized by the average of +440 the reweighting factor on all configurations in weight.idl and not +441 on the configurations in obs[i].idl. +442 """ +443 new_content = [] +444 for t_slice in self.content: +445 if t_slice is None: +446 new_content.append(None) +447 else: +448 new_content.append(np.array(reweight(weight, t_slice, **kwargs))) +449 return Corr(new_content)View Source
-447 def T_symmetry(self, partner, parity=+1): -448 """Return the time symmetry average of the correlator and its partner -449 -450 Parameters -451 ---------- -452 partner : Corr -453 Time symmetry partner of the Corr -454 partity : int -455 Parity quantum number of the correlator, can be +1 or -1 -456 """ -457 if not isinstance(partner, Corr): -458 raise Exception("T partner has to be a Corr object.") -459 if parity not in [+1, -1]: -460 raise Exception("Parity has to be +1 or -1.") -461 T_partner = parity * partner.reverse() -462 -463 t_slices = [] -464 test = (self - T_partner) -465 test.gamma_method() -466 for x0, t_slice in enumerate(test.content): -467 if t_slice is not None: -468 if not t_slice[0].is_zero_within_error(5): -469 t_slices.append(x0) -470 if t_slices: -471 warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning) -472 -473 return (self + T_partner) / 2 +@@ -3511,57 +3523,57 @@ Parity quantum number of the correlator, can be +1 or -1451 def T_symmetry(self, partner, parity=+1): +452 """Return the time symmetry average of the correlator and its partner +453 +454 Parameters +455 ---------- +456 partner : Corr +457 Time symmetry partner of the Corr +458 partity : int +459 Parity quantum number of the correlator, can be +1 or -1 +460 """ +461 if not isinstance(partner, Corr): +462 raise Exception("T partner has to be a Corr object.") +463 if parity not in [+1, -1]: +464 raise Exception("Parity has to be +1 or -1.") +465 T_partner = parity * partner.reverse() +466 +467 t_slices = [] +468 test = (self - T_partner) +469 test.gamma_method() +470 for x0, t_slice in enumerate(test.content): +471 if t_slice is not None: +472 if not t_slice[0].is_zero_within_error(5): +473 t_slices.append(x0) +474 if t_slices: +475 warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning) +476 +477 return (self + T_partner) / 2View Source
-475 def deriv(self, variant="symmetric"): -476 """Return the first derivative of the correlator with respect to x0. -477 -478 Parameters -479 ---------- -480 variant : str -481 decides which definition of the finite differences derivative is used. -482 Available choice: symmetric, forward, backward, improved, default: symmetric -483 """ -484 if variant == "symmetric": -485 newcontent = [] -486 for t in range(1, self.T - 1): -487 if (self.content[t - 1] is None) or (self.content[t + 1] is None): -488 newcontent.append(None) -489 else: -490 newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1])) -491 if(all([x is None for x in newcontent])): -492 raise Exception('Derivative is undefined at all timeslices') -493 return Corr(newcontent, padding=[1, 1]) -494 elif variant == "forward": -495 newcontent = [] -496 for t in range(self.T - 1): -497 if (self.content[t] is None) or (self.content[t + 1] is None): -498 newcontent.append(None) -499 else: -500 newcontent.append(self.content[t + 1] - self.content[t]) -501 if(all([x is None for x in newcontent])): -502 raise Exception("Derivative is undefined at all timeslices") -503 return Corr(newcontent, padding=[0, 1]) -504 elif variant == "backward": -505 newcontent = [] -506 for t in range(1, self.T): -507 if (self.content[t - 1] is None) or (self.content[t] is None): -508 newcontent.append(None) -509 else: -510 newcontent.append(self.content[t] - self.content[t - 1]) -511 if(all([x is None for x in newcontent])): -512 raise Exception("Derivative is undefined at all timeslices") -513 return Corr(newcontent, padding=[1, 0]) -514 elif variant == "improved": -515 newcontent = [] -516 for t in range(2, self.T - 2): -517 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): -518 newcontent.append(None) -519 else: -520 newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2])) -521 if(all([x is None for x in newcontent])): -522 raise Exception('Derivative is undefined at all timeslices') -523 return Corr(newcontent, padding=[2, 2]) -524 else: -525 raise Exception("Unknown variant.") +@@ -3589,37 +3601,37 @@ Available choice: symmetric, forward, backward, improved, default: symmetric479 def deriv(self, variant="symmetric"): +480 """Return the first derivative of the correlator with respect to x0. +481 +482 Parameters +483 ---------- +484 variant : str +485 decides which definition of the finite differences derivative is used. +486 Available choice: symmetric, forward, backward, improved, default: symmetric +487 """ +488 if variant == "symmetric": +489 newcontent = [] +490 for t in range(1, self.T - 1): +491 if (self.content[t - 1] is None) or (self.content[t + 1] is None): +492 newcontent.append(None) +493 else: +494 newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1])) +495 if(all([x is None for x in newcontent])): +496 raise Exception('Derivative is undefined at all timeslices') +497 return Corr(newcontent, padding=[1, 1]) +498 elif variant == "forward": +499 newcontent = [] +500 for t in range(self.T - 1): +501 if (self.content[t] is None) or (self.content[t + 1] is None): +502 newcontent.append(None) +503 else: +504 newcontent.append(self.content[t + 1] - self.content[t]) +505 if(all([x is None for x in newcontent])): +506 raise Exception("Derivative is undefined at all timeslices") +507 return Corr(newcontent, padding=[0, 1]) +508 elif variant == "backward": +509 newcontent = [] +510 for t in range(1, self.T): +511 if (self.content[t - 1] is None) or (self.content[t] is None): +512 newcontent.append(None) +513 else: +514 newcontent.append(self.content[t] - self.content[t - 1]) +515 if(all([x is None for x in newcontent])): +516 raise Exception("Derivative is undefined at all timeslices") +517 return Corr(newcontent, padding=[1, 0]) +518 elif variant == "improved": +519 newcontent = [] +520 for t in range(2, self.T - 2): +521 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): +522 newcontent.append(None) +523 else: +524 newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2])) +525 if(all([x is None for x in newcontent])): +526 raise Exception('Derivative is undefined at all timeslices') +527 return Corr(newcontent, padding=[2, 2]) +528 else: +529 raise Exception("Unknown variant.")View Source
-527 def second_deriv(self, variant="symmetric"): -528 """Return the second derivative of the correlator with respect to x0. -529 -530 Parameters -531 ---------- -532 variant : str -533 decides which definition of the finite differences derivative is used. -534 Available choice: symmetric, improved, default: symmetric -535 """ -536 if variant == "symmetric": -537 newcontent = [] -538 for t in range(1, self.T - 1): -539 if (self.content[t - 1] is None) or (self.content[t + 1] is None): -540 newcontent.append(None) -541 else: -542 newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1])) -543 if(all([x is None for x in newcontent])): -544 raise Exception("Derivative is undefined at all timeslices") -545 return Corr(newcontent, padding=[1, 1]) -546 elif variant == "improved": -547 newcontent = [] -548 for t in range(2, self.T - 2): -549 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): -550 newcontent.append(None) -551 else: -552 newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2])) -553 if(all([x is None for x in newcontent])): -554 raise Exception("Derivative is undefined at all timeslices") -555 return Corr(newcontent, padding=[2, 2]) -556 else: -557 raise Exception("Unknown variant.") +@@ -3647,70 +3659,70 @@ Available choice: symmetric, improved, default: symmetric531 def second_deriv(self, variant="symmetric"): +532 """Return the second derivative of the correlator with respect to x0. +533 +534 Parameters +535 ---------- +536 variant : str +537 decides which definition of the finite differences derivative is used. +538 Available choice: symmetric, improved, default: symmetric +539 """ +540 if variant == "symmetric": +541 newcontent = [] +542 for t in range(1, self.T - 1): +543 if (self.content[t - 1] is None) or (self.content[t + 1] is None): +544 newcontent.append(None) +545 else: +546 newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1])) +547 if(all([x is None for x in newcontent])): +548 raise Exception("Derivative is undefined at all timeslices") +549 return Corr(newcontent, padding=[1, 1]) +550 elif variant == "improved": +551 newcontent = [] +552 for t in range(2, self.T - 2): +553 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): +554 newcontent.append(None) +555 else: +556 newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2])) +557 if(all([x is None for x in newcontent])): +558 raise Exception("Derivative is undefined at all timeslices") +559 return Corr(newcontent, padding=[2, 2]) +560 else: +561 raise Exception("Unknown variant.")View Source
-559 def m_eff(self, variant='log', guess=1.0): -560 """Returns the effective mass of the correlator as correlator object -561 -562 Parameters -563 ---------- -564 variant : str -565 log : uses the standard effective mass log(C(t) / C(t+1)) -566 cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m. -567 sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m. -568 See, e.g., arXiv:1205.5380 -569 arccosh : Uses the explicit form of the symmetrized correlator (not recommended) -570 guess : float -571 guess for the root finder, only relevant for the root variant -572 """ -573 if self.N != 1: -574 raise Exception('Correlator must be projected before getting m_eff') -575 if variant == 'log': -576 newcontent = [] -577 for t in range(self.T - 1): -578 if (self.content[t] is None) or (self.content[t + 1] is None): -579 newcontent.append(None) -580 else: -581 newcontent.append(self.content[t] / self.content[t + 1]) -582 if(all([x is None for x in newcontent])): -583 raise Exception('m_eff is undefined at all timeslices') -584 -585 return np.log(Corr(newcontent, padding=[0, 1])) -586 -587 elif variant in ['periodic', 'cosh', 'sinh']: -588 if variant in ['periodic', 'cosh']: -589 func = anp.cosh -590 else: -591 func = anp.sinh -592 -593 def root_function(x, d): -594 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d -595 -596 newcontent = [] -597 for t in range(self.T - 1): -598 if (self.content[t] is None) or (self.content[t + 1] is None): -599 newcontent.append(None) -600 # Fill the two timeslices in the middle of the lattice with their predecessors -601 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: -602 newcontent.append(newcontent[-1]) -603 else: -604 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) -605 if(all([x is None for x in newcontent])): -606 raise Exception('m_eff is undefined at all timeslices') -607 -608 return Corr(newcontent, padding=[0, 1]) -609 -610 elif variant == 'arccosh': -611 newcontent = [] -612 for t in range(1, self.T - 1): -613 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None): -614 newcontent.append(None) -615 else: -616 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) -617 if(all([x is None for x in newcontent])): -618 raise Exception("m_eff is undefined at all timeslices") -619 return np.arccosh(Corr(newcontent, padding=[1, 1])) -620 -621 else: -622 raise Exception('Unknown variant.') +@@ -3743,39 +3755,39 @@ guess for the root finder, only relevant for the root variant563 def m_eff(self, variant='log', guess=1.0): +564 """Returns the effective mass of the correlator as correlator object +565 +566 Parameters +567 ---------- +568 variant : str +569 log : uses the standard effective mass log(C(t) / C(t+1)) +570 cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m. +571 sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m. +572 See, e.g., arXiv:1205.5380 +573 arccosh : Uses the explicit form of the symmetrized correlator (not recommended) +574 guess : float +575 guess for the root finder, only relevant for the root variant +576 """ +577 if self.N != 1: +578 raise Exception('Correlator must be projected before getting m_eff') +579 if variant == 'log': +580 newcontent = [] +581 for t in range(self.T - 1): +582 if (self.content[t] is None) or (self.content[t + 1] is None): +583 newcontent.append(None) +584 else: +585 newcontent.append(self.content[t] / self.content[t + 1]) +586 if(all([x is None for x in newcontent])): +587 raise Exception('m_eff is undefined at all timeslices') +588 +589 return np.log(Corr(newcontent, padding=[0, 1])) +590 +591 elif variant in ['periodic', 'cosh', 'sinh']: +592 if variant in ['periodic', 'cosh']: +593 func = anp.cosh +594 else: +595 func = anp.sinh +596 +597 def root_function(x, d): +598 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d +599 +600 newcontent = [] +601 for t in range(self.T - 1): +602 if (self.content[t] is None) or (self.content[t + 1] is None): +603 newcontent.append(None) +604 # Fill the two timeslices in the middle of the lattice with their predecessors +605 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: +606 newcontent.append(newcontent[-1]) +607 else: +608 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) +609 if(all([x is None for x in newcontent])): +610 raise Exception('m_eff is undefined at all timeslices') +611 +612 return Corr(newcontent, padding=[0, 1]) +613 +614 elif variant == 'arccosh': +615 newcontent = [] +616 for t in range(1, self.T - 1): +617 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None): +618 newcontent.append(None) +619 else: +620 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) +621 if(all([x is None for x in newcontent])): +622 raise Exception("m_eff is undefined at all timeslices") +623 return np.arccosh(Corr(newcontent, padding=[1, 1])) +624 +625 else: +626 raise Exception('Unknown variant.')View Source
-624 def fit(self, function, fitrange=None, silent=False, **kwargs): -625 r'''Fits function to the data -626 -627 Parameters -628 ---------- -629 function : obj -630 function to fit to the data. See fits.least_squares for details. -631 fitrange : list -632 Two element list containing the timeslices on which the fit is supposed to start and stop. -633 Caution: This range is inclusive as opposed to standard python indexing. -634 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. -635 If not specified, self.prange or all timeslices are used. -636 silent : bool -637 Decides whether output is printed to the standard output. -638 ''' -639 if self.N != 1: -640 raise Exception("Correlator must be projected before fitting") -641 -642 if fitrange is None: -643 if self.prange: -644 fitrange = self.prange -645 else: -646 fitrange = [0, self.T - 1] -647 else: -648 if not isinstance(fitrange, list): -649 raise Exception("fitrange has to be a list with two elements") -650 if len(fitrange) != 2: -651 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") -652 -653 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] -654 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] -655 result = least_squares(xs, ys, function, silent=silent, **kwargs) -656 return result +@@ -3809,42 +3821,42 @@ Decides whether output is printed to the standard output.628 def fit(self, function, fitrange=None, silent=False, **kwargs): +629 r'''Fits function to the data +630 +631 Parameters +632 ---------- +633 function : obj +634 function to fit to the data. See fits.least_squares for details. +635 fitrange : list +636 Two element list containing the timeslices on which the fit is supposed to start and stop. +637 Caution: This range is inclusive as opposed to standard python indexing. +638 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. +639 If not specified, self.prange or all timeslices are used. +640 silent : bool +641 Decides whether output is printed to the standard output. +642 ''' +643 if self.N != 1: +644 raise Exception("Correlator must be projected before fitting") +645 +646 if fitrange is None: +647 if self.prange: +648 fitrange = self.prange +649 else: +650 fitrange = [0, self.T - 1] +651 else: +652 if not isinstance(fitrange, list): +653 raise Exception("fitrange has to be a list with two elements") +654 if len(fitrange) != 2: +655 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") +656 +657 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] +658 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] +659 result = least_squares(xs, ys, function, silent=silent, **kwargs) +660 return resultView Source
-658 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): -659 """ Extract a plateau value from a Corr object -660 -661 Parameters -662 ---------- -663 plateau_range : list -664 list with two entries, indicating the first and the last timeslice -665 of the plateau region. -666 method : str -667 method to extract the plateau. -668 'fit' fits a constant to the plateau region -669 'avg', 'average' or 'mean' just average over the given timeslices. -670 auto_gamma : bool -671 apply gamma_method with default parameters to the Corr. Defaults to None -672 """ -673 if not plateau_range: -674 if self.prange: -675 plateau_range = self.prange -676 else: -677 raise Exception("no plateau range provided") -678 if self.N != 1: -679 raise Exception("Correlator must be projected before getting a plateau.") -680 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): -681 raise Exception("plateau is undefined at all timeslices in plateaurange.") -682 if auto_gamma: -683 self.gamma_method() -684 if method == "fit": -685 def const_func(a, t): -686 return a[0] -687 return self.fit(const_func, plateau_range)[0] -688 elif method in ["avg", "average", "mean"]: -689 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) -690 return returnvalue -691 -692 else: -693 raise Exception("Unsupported plateau method: " + method) +@@ -3878,17 +3890,17 @@ apply gamma_method with default parameters to the Corr. Defaults to None662 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): +663 """ Extract a plateau value from a Corr object +664 +665 Parameters +666 ---------- +667 plateau_range : list +668 list with two entries, indicating the first and the last timeslice +669 of the plateau region. +670 method : str +671 method to extract the plateau. +672 'fit' fits a constant to the plateau region +673 'avg', 'average' or 'mean' just average over the given timeslices. +674 auto_gamma : bool +675 apply gamma_method with default parameters to the Corr. Defaults to None +676 """ +677 if not plateau_range: +678 if self.prange: +679 plateau_range = self.prange +680 else: +681 raise Exception("no plateau range provided") +682 if self.N != 1: +683 raise Exception("Correlator must be projected before getting a plateau.") +684 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): +685 raise Exception("plateau is undefined at all timeslices in plateaurange.") +686 if auto_gamma: +687 self.gamma_method() +688 if method == "fit": +689 def const_func(a, t): +690 return a[0] +691 return self.fit(const_func, plateau_range)[0] +692 elif method in ["avg", "average", "mean"]: +693 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) +694 return returnvalue +695 +696 else: +697 raise Exception("Unsupported plateau method: " + method)View Source
-695 def set_prange(self, prange): -696 """Sets the attribute prange of the Corr object.""" -697 if not len(prange) == 2: -698 raise Exception("prange must be a list or array with two values") -699 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): -700 raise Exception("Start and end point must be integers") -701 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): -702 raise Exception("Start and end point must define a range in the interval 0,T") -703 -704 self.prange = prange -705 return +@@ -3921,118 +3933,118 @@ apply gamma_method with default parameters to the Corr. Defaults to None699 def set_prange(self, prange): +700 """Sets the attribute prange of the Corr object.""" +701 if not len(prange) == 2: +702 raise Exception("prange must be a list or array with two values") +703 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): +704 raise Exception("Start and end point must be integers") +705 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): +706 raise Exception("Start and end point must define a range in the interval 0,T") +707 +708 self.prange = prange +709 returnView Source
-707 def show(self, x_range=None, comp=None, y_range=None, logscale=False, plateau=None, fit_res=None, ylabel=None, save=None, auto_gamma=False, hide_sigma=None, references=None): -708 """Plots the correlator using the tag of the correlator as label if available. -709 -710 Parameters -711 ---------- -712 x_range : list -713 list of two values, determining the range of the x-axis e.g. [4, 8] -714 comp : Corr or list of Corr -715 Correlator or list of correlators which are plotted for comparison. -716 The tags of these correlators are used as labels if available. -717 logscale : bool -718 Sets y-axis to logscale -719 plateau : Obs -720 Plateau value to be visualized in the figure -721 fit_res : Fit_result -722 Fit_result object to be visualized -723 ylabel : str -724 Label for the y-axis -725 save : str -726 path to file in which the figure should be saved -727 auto_gamma : bool -728 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. -729 hide_sigma : float -730 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. -731 references : list -732 List of floating point values that are displayed as horizontal lines for reference. -733 """ -734 if self.N != 1: -735 raise Exception("Correlator must be projected before plotting") -736 -737 if auto_gamma: -738 self.gamma_method() -739 -740 if x_range is None: -741 x_range = [0, self.T - 1] -742 -743 fig = plt.figure() -744 ax1 = fig.add_subplot(111) -745 -746 x, y, y_err = self.plottable() -747 if hide_sigma: -748 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 -749 else: -750 hide_from = None -751 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) -752 if logscale: -753 ax1.set_yscale('log') -754 else: -755 if y_range is None: -756 try: -757 y_min = min([(x[0].value - x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) -758 y_max = max([(x[0].value + x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) -759 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) -760 except Exception: -761 pass -762 else: -763 ax1.set_ylim(y_range) -764 if comp: -765 if isinstance(comp, (Corr, list)): -766 for corr in comp if isinstance(comp, list) else [comp]: -767 if auto_gamma: -768 corr.gamma_method() -769 x, y, y_err = corr.plottable() -770 if hide_sigma: -771 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 -772 else: -773 hide_from = None -774 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) -775 else: -776 raise Exception("'comp' must be a correlator or a list of correlators.") -777 -778 if plateau: -779 if isinstance(plateau, Obs): -780 if auto_gamma: -781 plateau.gamma_method() -782 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) -783 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') -784 else: -785 raise Exception("'plateau' must be an Obs") -786 -787 if references: -788 if isinstance(references, list): -789 for ref in references: -790 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') -791 else: -792 raise Exception("'references' must be a list of floating pint values.") -793 -794 if self.prange: -795 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') -796 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') +@@ -4078,34 +4090,34 @@ List of floating point values that are displayed as horizontal lines for referen711 def show(self, x_range=None, comp=None, y_range=None, logscale=False, plateau=None, fit_res=None, ylabel=None, save=None, auto_gamma=False, hide_sigma=None, references=None): +712 """Plots the correlator using the tag of the correlator as label if available. +713 +714 Parameters +715 ---------- +716 x_range : list +717 list of two values, determining the range of the x-axis e.g. [4, 8] +718 comp : Corr or list of Corr +719 Correlator or list of correlators which are plotted for comparison. +720 The tags of these correlators are used as labels if available. +721 logscale : bool +722 Sets y-axis to logscale +723 plateau : Obs +724 Plateau value to be visualized in the figure +725 fit_res : Fit_result +726 Fit_result object to be visualized +727 ylabel : str +728 Label for the y-axis +729 save : str +730 path to file in which the figure should be saved +731 auto_gamma : bool +732 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. +733 hide_sigma : float +734 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. +735 references : list +736 List of floating point values that are displayed as horizontal lines for reference. +737 """ +738 if self.N != 1: +739 raise Exception("Correlator must be projected before plotting") +740 +741 if auto_gamma: +742 self.gamma_method() +743 +744 if x_range is None: +745 x_range = [0, self.T - 1] +746 +747 fig = plt.figure() +748 ax1 = fig.add_subplot(111) +749 +750 x, y, y_err = self.plottable() +751 if hide_sigma: +752 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 +753 else: +754 hide_from = None +755 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) +756 if logscale: +757 ax1.set_yscale('log') +758 else: +759 if y_range is None: +760 try: +761 y_min = min([(x[0].value - x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) +762 y_max = max([(x[0].value + x[0].dvalue) for x in self.content[x_range[0]: x_range[1] + 1] if (x is not None) and x[0].dvalue < 2 * np.abs(x[0].value)]) +763 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) +764 except Exception: +765 pass +766 else: +767 ax1.set_ylim(y_range) +768 if comp: +769 if isinstance(comp, (Corr, list)): +770 for corr in comp if isinstance(comp, list) else [comp]: +771 if auto_gamma: +772 corr.gamma_method() +773 x, y, y_err = corr.plottable() +774 if hide_sigma: +775 hide_from = np.argmax((hide_sigma * np.array(y_err)) > np.abs(y)) - 1 +776 else: +777 hide_from = None +778 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) +779 else: +780 raise Exception("'comp' must be a correlator or a list of correlators.") +781 +782 if plateau: +783 if isinstance(plateau, Obs): +784 if auto_gamma: +785 plateau.gamma_method() +786 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) +787 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') +788 else: +789 raise Exception("'plateau' must be an Obs") +790 +791 if references: +792 if isinstance(references, list): +793 for ref in references: +794 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') +795 else: +796 raise Exception("'references' must be a list of floating pint values.") 797 -798 if fit_res: -799 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) -800 ax1.plot(x_samples, -801 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), -802 ls='-', marker=',', lw=2) -803 -804 ax1.set_xlabel(r'$x_0 / a$') -805 if ylabel: -806 ax1.set_ylabel(ylabel) -807 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) -808 -809 handles, labels = ax1.get_legend_handles_labels() -810 if labels: -811 ax1.legend() -812 plt.draw() -813 -814 if save: -815 if isinstance(save, str): -816 fig.savefig(save) -817 else: -818 raise Exception("'save' has to be a string.") +798 if self.prange: +799 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') +800 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') +801 +802 if fit_res: +803 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) +804 ax1.plot(x_samples, +805 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), +806 ls='-', marker=',', lw=2) +807 +808 ax1.set_xlabel(r'$x_0 / a$') +809 if ylabel: +810 ax1.set_ylabel(ylabel) +811 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) +812 +813 handles, labels = ax1.get_legend_handles_labels() +814 if labels: +815 ax1.legend() +816 plt.draw() +817 +818 if save: +819 if isinstance(save, str): +820 fig.savefig(save) +821 else: +822 raise Exception("'save' has to be a string.")View Source
-820 def spaghetti_plot(self, logscale=True): -821 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. -822 -823 Parameters -824 ---------- -825 logscale : bool -826 Determines whether the scale of the y-axis is logarithmic or standard. -827 """ -828 if self.N != 1: -829 raise Exception("Correlator needs to be projected first.") -830 -831 mc_names = list(set([item for sublist in [o[0].mc_names for o in self.content if o is not None] for item in sublist])) -832 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] -833 -834 for name in mc_names: -835 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T -836 -837 fig = plt.figure() -838 ax = fig.add_subplot(111) -839 for dat in data: -840 ax.plot(x0_vals, dat, ls='-', marker='') -841 -842 if logscale is True: -843 ax.set_yscale('log') -844 -845 ax.set_xlabel(r'$x_0 / a$') -846 plt.title(name) -847 plt.draw() +@@ -4132,29 +4144,29 @@ Determines whether the scale of the y-axis is logarithmic or standard.824 def spaghetti_plot(self, logscale=True): +825 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. +826 +827 Parameters +828 ---------- +829 logscale : bool +830 Determines whether the scale of the y-axis is logarithmic or standard. +831 """ +832 if self.N != 1: +833 raise Exception("Correlator needs to be projected first.") +834 +835 mc_names = list(set([item for sublist in [o[0].mc_names for o in self.content if o is not None] for item in sublist])) +836 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] +837 +838 for name in mc_names: +839 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T +840 +841 fig = plt.figure() +842 ax = fig.add_subplot(111) +843 for dat in data: +844 ax.plot(x0_vals, dat, ls='-', marker='') +845 +846 if logscale is True: +847 ax.set_yscale('log') +848 +849 ax.set_xlabel(r'$x_0 / a$') +850 plt.title(name) +851 plt.draw()View Source
-849 def dump(self, filename, datatype="json.gz", **kwargs): -850 """Dumps the Corr into a file of chosen type -851 Parameters -852 ---------- -853 filename : str -854 Name of the file to be saved. -855 datatype : str -856 Format of the exported file. Supported formats include -857 "json.gz" and "pickle" -858 path : str -859 specifies a custom path for the file (default '.') -860 """ -861 if datatype == "json.gz": -862 from .input.json import dump_to_json -863 if 'path' in kwargs: -864 file_name = kwargs.get('path') + '/' + filename -865 else: -866 file_name = filename -867 dump_to_json(self, file_name) -868 elif datatype == "pickle": -869 dump_object(self, filename, **kwargs) -870 else: -871 raise Exception("Unknown datatype " + str(datatype)) +@@ -4186,8 +4198,8 @@ specifies a custom path for the file (default '.')853 def dump(self, filename, datatype="json.gz", **kwargs): +854 """Dumps the Corr into a file of chosen type +855 Parameters +856 ---------- +857 filename : str +858 Name of the file to be saved. +859 datatype : str +860 Format of the exported file. Supported formats include +861 "json.gz" and "pickle" +862 path : str +863 specifies a custom path for the file (default '.') +864 """ +865 if datatype == "json.gz": +866 from .input.json import dump_to_json +867 if 'path' in kwargs: +868 file_name = kwargs.get('path') + '/' + filename +869 else: +870 file_name = filename +871 dump_to_json(self, file_name) +872 elif datatype == "pickle": +873 dump_object(self, filename, **kwargs) +874 else: +875 raise Exception("Unknown datatype " + str(datatype))View Source
-873 def print(self, range=[0, None]): -874 print(self.__repr__(range)) + @@ -4205,8 +4217,8 @@ specifies a custom path for the file (default '.')View Source
-1036 def sqrt(self): -1037 return self**0.5 + @@ -4224,9 +4236,9 @@ specifies a custom path for the file (default '.')View Source
-1039 def log(self): -1040 newcontent = [None if (item is None) else np.log(item) for item in self.content] -1041 return Corr(newcontent, prange=self.prange) +@@ -4244,9 +4256,9 @@ specifies a custom path for the file (default '.')1043 def log(self): +1044 newcontent = [None if (item is None) else np.log(item) for item in self.content] +1045 return Corr(newcontent, prange=self.prange)View Source
-1043 def exp(self): -1044 newcontent = [None if (item is None) else np.exp(item) for item in self.content] -1045 return Corr(newcontent, prange=self.prange) +@@ -4264,8 +4276,8 @@ specifies a custom path for the file (default '.')1047 def exp(self): +1048 newcontent = [None if (item is None) else np.exp(item) for item in self.content] +1049 return Corr(newcontent, prange=self.prange)View Source
-1058 def sin(self): -1059 return self._apply_func_to_corr(np.sin) + @@ -4283,8 +4295,8 @@ specifies a custom path for the file (default '.')View Source
-1061 def cos(self): -1062 return self._apply_func_to_corr(np.cos) + @@ -4302,8 +4314,8 @@ specifies a custom path for the file (default '.')View Source
-1064 def tan(self): -1065 return self._apply_func_to_corr(np.tan) + @@ -4321,8 +4333,8 @@ specifies a custom path for the file (default '.')View Source
-1067 def sinh(self): -1068 return self._apply_func_to_corr(np.sinh) + @@ -4340,8 +4352,8 @@ specifies a custom path for the file (default '.')View Source
-1070 def cosh(self): -1071 return self._apply_func_to_corr(np.cosh) + @@ -4359,8 +4371,8 @@ specifies a custom path for the file (default '.')View Source
-1073 def tanh(self): -1074 return self._apply_func_to_corr(np.tanh) + @@ -4378,8 +4390,8 @@ specifies a custom path for the file (default '.')View Source
-1076 def arcsin(self): -1077 return self._apply_func_to_corr(np.arcsin) + @@ -4397,8 +4409,8 @@ specifies a custom path for the file (default '.')View Source
-1079 def arccos(self): -1080 return self._apply_func_to_corr(np.arccos) + @@ -4416,8 +4428,8 @@ specifies a custom path for the file (default '.')View Source
-1082 def arctan(self): -1083 return self._apply_func_to_corr(np.arctan) + @@ -4435,8 +4447,8 @@ specifies a custom path for the file (default '.')View Source
-1085 def arcsinh(self): -1086 return self._apply_func_to_corr(np.arcsinh) + @@ -4454,8 +4466,8 @@ specifies a custom path for the file (default '.')View Source
-1088 def arccosh(self): -1089 return self._apply_func_to_corr(np.arccosh) + @@ -4473,8 +4485,8 @@ specifies a custom path for the file (default '.')View Source
-1091 def arctanh(self): -1092 return self._apply_func_to_corr(np.arctanh) + @@ -4512,64 +4524,64 @@ specifies a custom path for the file (default '.')View Source
-1127 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): -1128 r''' Project large correlation matrix to lowest states -1129 -1130 This method can be used to reduce the size of an (N x N) correlation matrix -1131 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise -1132 is still small. +1131 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): +1132 r''' Project large correlation matrix to lowest states 1133 -1134 Parameters -1135 ---------- -1136 Ntrunc: int -1137 Rank of the target matrix. -1138 tproj: int -1139 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. -1140 The default value is 3. -1141 t0proj: int -1142 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly -1143 discouraged for O(a) improved theories, since the correctness of the procedure -1144 cannot be granted in this case. The default value is 2. -1145 basematrix : Corr -1146 Correlation matrix that is used to determine the eigenvectors of the -1147 lowest states based on a GEVP. basematrix is taken to be the Corr itself if -1148 is is not specified. -1149 -1150 Notes -1151 ----- -1152 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving -1153 the GEVP $$C(t) v_n(t, t_0) = \lambda_n(t, t_0) C(t_0) v_n(t, t_0)$$ where $t \equiv t_\mathrm{proj}$ -1154 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the -1155 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via -1156 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large -1157 correlation matrix and to remove some noise that is added by irrelevant operators. -1158 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated -1159 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. -1160 ''' -1161 -1162 if self.N == 1: -1163 raise Exception('Method cannot be applied to one-dimensional correlators.') -1164 if basematrix is None: -1165 basematrix = self -1166 if Ntrunc >= basematrix.N: -1167 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) -1168 if basematrix.N != self.N: -1169 raise Exception('basematrix and targetmatrix have to be of the same size.') -1170 -1171 evecs = [] -1172 for i in range(Ntrunc): -1173 evecs.append(basematrix.GEVP(t0proj, tproj, state=i, sorted_list=None)) +1134 This method can be used to reduce the size of an (N x N) correlation matrix +1135 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise +1136 is still small. +1137 +1138 Parameters +1139 ---------- +1140 Ntrunc: int +1141 Rank of the target matrix. +1142 tproj: int +1143 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. +1144 The default value is 3. +1145 t0proj: int +1146 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly +1147 discouraged for O(a) improved theories, since the correctness of the procedure +1148 cannot be granted in this case. The default value is 2. +1149 basematrix : Corr +1150 Correlation matrix that is used to determine the eigenvectors of the +1151 lowest states based on a GEVP. basematrix is taken to be the Corr itself if +1152 is is not specified. +1153 +1154 Notes +1155 ----- +1156 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving +1157 the GEVP $$C(t) v_n(t, t_0) = \lambda_n(t, t_0) C(t_0) v_n(t, t_0)$$ where $t \equiv t_\mathrm{proj}$ +1158 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the +1159 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via +1160 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large +1161 correlation matrix and to remove some noise that is added by irrelevant operators. +1162 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated +1163 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. +1164 ''' +1165 +1166 if self.N == 1: +1167 raise Exception('Method cannot be applied to one-dimensional correlators.') +1168 if basematrix is None: +1169 basematrix = self +1170 if Ntrunc >= basematrix.N: +1171 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) +1172 if basematrix.N != self.N: +1173 raise Exception('basematrix and targetmatrix have to be of the same size.') 1174 -1175 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) -1176 rmat = [] -1177 for t in range(basematrix.T): -1178 for i in range(Ntrunc): -1179 for j in range(Ntrunc): -1180 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] -1181 rmat.append(np.copy(tmpmat)) -1182 -1183 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] -1184 return Corr(newcontent) +1175 evecs = [] +1176 for i in range(Ntrunc): +1177 evecs.append(basematrix.GEVP(t0proj, tproj, state=i, sorted_list=None)) +1178 +1179 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) +1180 rmat = [] +1181 for t in range(basematrix.T): +1182 for i in range(Ntrunc): +1183 for j in range(Ntrunc): +1184 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] +1185 rmat.append(np.copy(tmpmat)) +1186 +1187 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] +1188 return Corr(newcontent)