diff --git a/docs/pyerrors/correlators.html b/docs/pyerrors/correlators.html index 2cfd37dc..3a73ce43 100644 --- a/docs/pyerrors/correlators.html +++ b/docs/pyerrors/correlators.html @@ -818,658 +818,662 @@ 604 for t in range(self.T - 1): 605 if ((self.content[t] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0): 606 newcontent.append(None) - 607 else: - 608 newcontent.append(self.content[t] / self.content[t + 1]) - 609 if(all([x is None for x in newcontent])): - 610 raise Exception('m_eff is undefined at all timeslices') - 611 - 612 return np.log(Corr(newcontent, padding=[0, 1])) + 607 elif self.content[t][0].value / self.content[t + 1][0].value < 0: + 608 newcontent.append(None) + 609 else: + 610 newcontent.append(self.content[t] / self.content[t + 1]) + 611 if(all([x is None for x in newcontent])): + 612 raise Exception('m_eff is undefined at all timeslices') 613 - 614 elif variant in ['periodic', 'cosh', 'sinh']: - 615 if variant in ['periodic', 'cosh']: - 616 func = anp.cosh - 617 else: - 618 func = anp.sinh - 619 - 620 def root_function(x, d): - 621 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d - 622 - 623 newcontent = [] - 624 for t in range(self.T - 1): - 625 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0): - 626 newcontent.append(None) - 627 # Fill the two timeslices in the middle of the lattice with their predecessors - 628 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: - 629 newcontent.append(newcontent[-1]) - 630 else: - 631 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) - 632 if(all([x is None for x in newcontent])): - 633 raise Exception('m_eff is undefined at all timeslices') - 634 - 635 return Corr(newcontent, padding=[0, 1]) - 636 - 637 elif variant == 'arccosh': - 638 newcontent = [] - 639 for t in range(1, self.T - 1): - 640 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None) or (self.content[t][0].value == 0): - 641 newcontent.append(None) - 642 else: - 643 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) - 644 if(all([x is None for x in newcontent])): - 645 raise Exception("m_eff is undefined at all timeslices") - 646 return np.arccosh(Corr(newcontent, padding=[1, 1])) - 647 - 648 else: - 649 raise Exception('Unknown variant.') - 650 - 651 def fit(self, function, fitrange=None, silent=False, **kwargs): - 652 r'''Fits function to the data - 653 - 654 Parameters - 655 ---------- - 656 function : obj - 657 function to fit to the data. See fits.least_squares for details. - 658 fitrange : list - 659 Two element list containing the timeslices on which the fit is supposed to start and stop. - 660 Caution: This range is inclusive as opposed to standard python indexing. - 661 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. - 662 If not specified, self.prange or all timeslices are used. - 663 silent : bool - 664 Decides whether output is printed to the standard output. - 665 ''' - 666 if self.N != 1: - 667 raise Exception("Correlator must be projected before fitting") - 668 - 669 if fitrange is None: - 670 if self.prange: - 671 fitrange = self.prange - 672 else: - 673 fitrange = [0, self.T - 1] - 674 else: - 675 if not isinstance(fitrange, list): - 676 raise Exception("fitrange has to be a list with two elements") - 677 if len(fitrange) != 2: - 678 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") - 679 - 680 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 681 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 682 result = least_squares(xs, ys, function, silent=silent, **kwargs) - 683 return result - 684 - 685 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): - 686 """ Extract a plateau value from a Corr object - 687 - 688 Parameters - 689 ---------- - 690 plateau_range : list - 691 list with two entries, indicating the first and the last timeslice - 692 of the plateau region. - 693 method : str - 694 method to extract the plateau. - 695 'fit' fits a constant to the plateau region - 696 'avg', 'average' or 'mean' just average over the given timeslices. - 697 auto_gamma : bool - 698 apply gamma_method with default parameters to the Corr. Defaults to None - 699 """ - 700 if not plateau_range: - 701 if self.prange: - 702 plateau_range = self.prange - 703 else: - 704 raise Exception("no plateau range provided") - 705 if self.N != 1: - 706 raise Exception("Correlator must be projected before getting a plateau.") - 707 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): - 708 raise Exception("plateau is undefined at all timeslices in plateaurange.") - 709 if auto_gamma: - 710 self.gamma_method() - 711 if method == "fit": - 712 def const_func(a, t): - 713 return a[0] - 714 return self.fit(const_func, plateau_range)[0] - 715 elif method in ["avg", "average", "mean"]: - 716 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) - 717 return returnvalue - 718 - 719 else: - 720 raise Exception("Unsupported plateau method: " + method) - 721 - 722 def set_prange(self, prange): - 723 """Sets the attribute prange of the Corr object.""" - 724 if not len(prange) == 2: - 725 raise Exception("prange must be a list or array with two values") - 726 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): - 727 raise Exception("Start and end point must be integers") - 728 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): - 729 raise Exception("Start and end point must define a range in the interval 0,T") - 730 - 731 self.prange = prange - 732 return - 733 - 734 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, title=None): - 735 """Plots the correlator using the tag of the correlator as label if available. - 736 - 737 Parameters - 738 ---------- - 739 x_range : list - 740 list of two values, determining the range of the x-axis e.g. [4, 8]. - 741 comp : Corr or list of Corr - 742 Correlator or list of correlators which are plotted for comparison. - 743 The tags of these correlators are used as labels if available. - 744 logscale : bool - 745 Sets y-axis to logscale. - 746 plateau : Obs - 747 Plateau value to be visualized in the figure. - 748 fit_res : Fit_result - 749 Fit_result object to be visualized. - 750 ylabel : str - 751 Label for the y-axis. - 752 save : str - 753 path to file in which the figure should be saved. - 754 auto_gamma : bool - 755 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. - 756 hide_sigma : float - 757 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. - 758 references : list - 759 List of floating point values that are displayed as horizontal lines for reference. - 760 title : string - 761 Optional title of the figure. - 762 """ - 763 if self.N != 1: - 764 raise Exception("Correlator must be projected before plotting") - 765 - 766 if auto_gamma: - 767 self.gamma_method() - 768 - 769 if x_range is None: - 770 x_range = [0, self.T - 1] - 771 - 772 fig = plt.figure() - 773 ax1 = fig.add_subplot(111) - 774 - 775 x, y, y_err = self.plottable() - 776 if hide_sigma: - 777 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 - 778 else: - 779 hide_from = None - 780 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) - 781 if logscale: - 782 ax1.set_yscale('log') - 783 else: - 784 if y_range is None: - 785 try: - 786 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)]) - 787 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)]) - 788 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) - 789 except Exception: - 790 pass - 791 else: - 792 ax1.set_ylim(y_range) - 793 if comp: - 794 if isinstance(comp, (Corr, list)): - 795 for corr in comp if isinstance(comp, list) else [comp]: - 796 if auto_gamma: - 797 corr.gamma_method() - 798 x, y, y_err = corr.plottable() - 799 if hide_sigma: - 800 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 - 801 else: - 802 hide_from = None - 803 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) - 804 else: - 805 raise Exception("'comp' must be a correlator or a list of correlators.") - 806 - 807 if plateau: - 808 if isinstance(plateau, Obs): - 809 if auto_gamma: - 810 plateau.gamma_method() - 811 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) - 812 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') - 813 else: - 814 raise Exception("'plateau' must be an Obs") - 815 - 816 if references: - 817 if isinstance(references, list): - 818 for ref in references: - 819 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') - 820 else: - 821 raise Exception("'references' must be a list of floating pint values.") - 822 - 823 if self.prange: - 824 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') - 825 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') + 614 return np.log(Corr(newcontent, padding=[0, 1])) + 615 + 616 elif variant in ['periodic', 'cosh', 'sinh']: + 617 if variant in ['periodic', 'cosh']: + 618 func = anp.cosh + 619 else: + 620 func = anp.sinh + 621 + 622 def root_function(x, d): + 623 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d + 624 + 625 newcontent = [] + 626 for t in range(self.T - 1): + 627 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0): + 628 newcontent.append(None) + 629 # Fill the two timeslices in the middle of the lattice with their predecessors + 630 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: + 631 newcontent.append(newcontent[-1]) + 632 elif self.content[t][0].value / self.content[t + 1][0].value < 0: + 633 newcontent.append(None) + 634 else: + 635 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) + 636 if(all([x is None for x in newcontent])): + 637 raise Exception('m_eff is undefined at all timeslices') + 638 + 639 return Corr(newcontent, padding=[0, 1]) + 640 + 641 elif variant == 'arccosh': + 642 newcontent = [] + 643 for t in range(1, self.T - 1): + 644 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None) or (self.content[t][0].value == 0): + 645 newcontent.append(None) + 646 else: + 647 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) + 648 if(all([x is None for x in newcontent])): + 649 raise Exception("m_eff is undefined at all timeslices") + 650 return np.arccosh(Corr(newcontent, padding=[1, 1])) + 651 + 652 else: + 653 raise Exception('Unknown variant.') + 654 + 655 def fit(self, function, fitrange=None, silent=False, **kwargs): + 656 r'''Fits function to the data + 657 + 658 Parameters + 659 ---------- + 660 function : obj + 661 function to fit to the data. See fits.least_squares for details. + 662 fitrange : list + 663 Two element list containing the timeslices on which the fit is supposed to start and stop. + 664 Caution: This range is inclusive as opposed to standard python indexing. + 665 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. + 666 If not specified, self.prange or all timeslices are used. + 667 silent : bool + 668 Decides whether output is printed to the standard output. + 669 ''' + 670 if self.N != 1: + 671 raise Exception("Correlator must be projected before fitting") + 672 + 673 if fitrange is None: + 674 if self.prange: + 675 fitrange = self.prange + 676 else: + 677 fitrange = [0, self.T - 1] + 678 else: + 679 if not isinstance(fitrange, list): + 680 raise Exception("fitrange has to be a list with two elements") + 681 if len(fitrange) != 2: + 682 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") + 683 + 684 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 685 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 686 result = least_squares(xs, ys, function, silent=silent, **kwargs) + 687 return result + 688 + 689 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): + 690 """ Extract a plateau value from a Corr object + 691 + 692 Parameters + 693 ---------- + 694 plateau_range : list + 695 list with two entries, indicating the first and the last timeslice + 696 of the plateau region. + 697 method : str + 698 method to extract the plateau. + 699 'fit' fits a constant to the plateau region + 700 'avg', 'average' or 'mean' just average over the given timeslices. + 701 auto_gamma : bool + 702 apply gamma_method with default parameters to the Corr. Defaults to None + 703 """ + 704 if not plateau_range: + 705 if self.prange: + 706 plateau_range = self.prange + 707 else: + 708 raise Exception("no plateau range provided") + 709 if self.N != 1: + 710 raise Exception("Correlator must be projected before getting a plateau.") + 711 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): + 712 raise Exception("plateau is undefined at all timeslices in plateaurange.") + 713 if auto_gamma: + 714 self.gamma_method() + 715 if method == "fit": + 716 def const_func(a, t): + 717 return a[0] + 718 return self.fit(const_func, plateau_range)[0] + 719 elif method in ["avg", "average", "mean"]: + 720 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) + 721 return returnvalue + 722 + 723 else: + 724 raise Exception("Unsupported plateau method: " + method) + 725 + 726 def set_prange(self, prange): + 727 """Sets the attribute prange of the Corr object.""" + 728 if not len(prange) == 2: + 729 raise Exception("prange must be a list or array with two values") + 730 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): + 731 raise Exception("Start and end point must be integers") + 732 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): + 733 raise Exception("Start and end point must define a range in the interval 0,T") + 734 + 735 self.prange = prange + 736 return + 737 + 738 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, title=None): + 739 """Plots the correlator using the tag of the correlator as label if available. + 740 + 741 Parameters + 742 ---------- + 743 x_range : list + 744 list of two values, determining the range of the x-axis e.g. [4, 8]. + 745 comp : Corr or list of Corr + 746 Correlator or list of correlators which are plotted for comparison. + 747 The tags of these correlators are used as labels if available. + 748 logscale : bool + 749 Sets y-axis to logscale. + 750 plateau : Obs + 751 Plateau value to be visualized in the figure. + 752 fit_res : Fit_result + 753 Fit_result object to be visualized. + 754 ylabel : str + 755 Label for the y-axis. + 756 save : str + 757 path to file in which the figure should be saved. + 758 auto_gamma : bool + 759 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. + 760 hide_sigma : float + 761 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. + 762 references : list + 763 List of floating point values that are displayed as horizontal lines for reference. + 764 title : string + 765 Optional title of the figure. + 766 """ + 767 if self.N != 1: + 768 raise Exception("Correlator must be projected before plotting") + 769 + 770 if auto_gamma: + 771 self.gamma_method() + 772 + 773 if x_range is None: + 774 x_range = [0, self.T - 1] + 775 + 776 fig = plt.figure() + 777 ax1 = fig.add_subplot(111) + 778 + 779 x, y, y_err = self.plottable() + 780 if hide_sigma: + 781 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 + 782 else: + 783 hide_from = None + 784 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) + 785 if logscale: + 786 ax1.set_yscale('log') + 787 else: + 788 if y_range is None: + 789 try: + 790 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)]) + 791 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)]) + 792 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) + 793 except Exception: + 794 pass + 795 else: + 796 ax1.set_ylim(y_range) + 797 if comp: + 798 if isinstance(comp, (Corr, list)): + 799 for corr in comp if isinstance(comp, list) else [comp]: + 800 if auto_gamma: + 801 corr.gamma_method() + 802 x, y, y_err = corr.plottable() + 803 if hide_sigma: + 804 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 + 805 else: + 806 hide_from = None + 807 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) + 808 else: + 809 raise Exception("'comp' must be a correlator or a list of correlators.") + 810 + 811 if plateau: + 812 if isinstance(plateau, Obs): + 813 if auto_gamma: + 814 plateau.gamma_method() + 815 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) + 816 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') + 817 else: + 818 raise Exception("'plateau' must be an Obs") + 819 + 820 if references: + 821 if isinstance(references, list): + 822 for ref in references: + 823 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') + 824 else: + 825 raise Exception("'references' must be a list of floating pint values.") 826 - 827 if fit_res: - 828 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) - 829 ax1.plot(x_samples, - 830 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), - 831 ls='-', marker=',', lw=2) - 832 - 833 ax1.set_xlabel(r'$x_0 / a$') - 834 if ylabel: - 835 ax1.set_ylabel(ylabel) - 836 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) - 837 - 838 handles, labels = ax1.get_legend_handles_labels() - 839 if labels: - 840 ax1.legend() + 827 if self.prange: + 828 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') + 829 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') + 830 + 831 if fit_res: + 832 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) + 833 ax1.plot(x_samples, + 834 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), + 835 ls='-', marker=',', lw=2) + 836 + 837 ax1.set_xlabel(r'$x_0 / a$') + 838 if ylabel: + 839 ax1.set_ylabel(ylabel) + 840 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) 841 - 842 if title: - 843 plt.title(title) - 844 - 845 plt.draw() - 846 - 847 if save: - 848 if isinstance(save, str): - 849 fig.savefig(save, bbox_inches='tight') - 850 else: - 851 raise Exception("'save' has to be a string.") - 852 - 853 def spaghetti_plot(self, logscale=True): - 854 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. - 855 - 856 Parameters - 857 ---------- - 858 logscale : bool - 859 Determines whether the scale of the y-axis is logarithmic or standard. - 860 """ - 861 if self.N != 1: - 862 raise Exception("Correlator needs to be projected first.") - 863 - 864 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])) - 865 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] - 866 - 867 for name in mc_names: - 868 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T - 869 - 870 fig = plt.figure() - 871 ax = fig.add_subplot(111) - 872 for dat in data: - 873 ax.plot(x0_vals, dat, ls='-', marker='') - 874 - 875 if logscale is True: - 876 ax.set_yscale('log') - 877 - 878 ax.set_xlabel(r'$x_0 / a$') - 879 plt.title(name) - 880 plt.draw() + 842 handles, labels = ax1.get_legend_handles_labels() + 843 if labels: + 844 ax1.legend() + 845 + 846 if title: + 847 plt.title(title) + 848 + 849 plt.draw() + 850 + 851 if save: + 852 if isinstance(save, str): + 853 fig.savefig(save, bbox_inches='tight') + 854 else: + 855 raise Exception("'save' has to be a string.") + 856 + 857 def spaghetti_plot(self, logscale=True): + 858 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. + 859 + 860 Parameters + 861 ---------- + 862 logscale : bool + 863 Determines whether the scale of the y-axis is logarithmic or standard. + 864 """ + 865 if self.N != 1: + 866 raise Exception("Correlator needs to be projected first.") + 867 + 868 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])) + 869 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] + 870 + 871 for name in mc_names: + 872 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T + 873 + 874 fig = plt.figure() + 875 ax = fig.add_subplot(111) + 876 for dat in data: + 877 ax.plot(x0_vals, dat, ls='-', marker='') + 878 + 879 if logscale is True: + 880 ax.set_yscale('log') 881 - 882 def dump(self, filename, datatype="json.gz", **kwargs): - 883 """Dumps the Corr into a file of chosen type - 884 Parameters - 885 ---------- - 886 filename : str - 887 Name of the file to be saved. - 888 datatype : str - 889 Format of the exported file. Supported formats include - 890 "json.gz" and "pickle" - 891 path : str - 892 specifies a custom path for the file (default '.') - 893 """ - 894 if datatype == "json.gz": - 895 from .input.json import dump_to_json - 896 if 'path' in kwargs: - 897 file_name = kwargs.get('path') + '/' + filename - 898 else: - 899 file_name = filename - 900 dump_to_json(self, file_name) - 901 elif datatype == "pickle": - 902 dump_object(self, filename, **kwargs) - 903 else: - 904 raise Exception("Unknown datatype " + str(datatype)) - 905 - 906 def print(self, print_range=None): - 907 print(self.__repr__(print_range)) - 908 - 909 def __repr__(self, print_range=None): - 910 if print_range is None: - 911 print_range = [0, None] + 882 ax.set_xlabel(r'$x_0 / a$') + 883 plt.title(name) + 884 plt.draw() + 885 + 886 def dump(self, filename, datatype="json.gz", **kwargs): + 887 """Dumps the Corr into a file of chosen type + 888 Parameters + 889 ---------- + 890 filename : str + 891 Name of the file to be saved. + 892 datatype : str + 893 Format of the exported file. Supported formats include + 894 "json.gz" and "pickle" + 895 path : str + 896 specifies a custom path for the file (default '.') + 897 """ + 898 if datatype == "json.gz": + 899 from .input.json import dump_to_json + 900 if 'path' in kwargs: + 901 file_name = kwargs.get('path') + '/' + filename + 902 else: + 903 file_name = filename + 904 dump_to_json(self, file_name) + 905 elif datatype == "pickle": + 906 dump_object(self, filename, **kwargs) + 907 else: + 908 raise Exception("Unknown datatype " + str(datatype)) + 909 + 910 def print(self, print_range=None): + 911 print(self.__repr__(print_range)) 912 - 913 content_string = "" - 914 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 - 915 - 916 if self.tag is not None: - 917 content_string += "Description: " + self.tag + "\n" - 918 if self.N != 1: - 919 return content_string - 920 - 921 if print_range[1]: - 922 print_range[1] += 1 - 923 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' - 924 for i, sub_corr in enumerate(self.content[print_range[0]:print_range[1]]): - 925 if sub_corr is None: - 926 content_string += str(i + print_range[0]) + '\n' - 927 else: - 928 content_string += str(i + print_range[0]) - 929 for element in sub_corr: - 930 content_string += '\t' + ' ' * int(element >= 0) + str(element) - 931 content_string += '\n' - 932 return content_string - 933 - 934 def __str__(self): - 935 return self.__repr__() - 936 - 937 # We define the basic operations, that can be performed with correlators. - 938 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. - 939 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. - 940 # One could try and tell Obs to check if the y in __mul__ is a Corr and - 941 - 942 def __add__(self, y): - 943 if isinstance(y, Corr): - 944 if ((self.N != y.N) or (self.T != y.T)): - 945 raise Exception("Addition of Corrs with different shape") - 946 newcontent = [] - 947 for t in range(self.T): - 948 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): - 949 newcontent.append(None) - 950 else: - 951 newcontent.append(self.content[t] + y.content[t]) - 952 return Corr(newcontent) - 953 - 954 elif isinstance(y, (Obs, int, float, CObs)): - 955 newcontent = [] - 956 for t in range(self.T): - 957 if _check_for_none(self, self.content[t]): - 958 newcontent.append(None) - 959 else: - 960 newcontent.append(self.content[t] + y) - 961 return Corr(newcontent, prange=self.prange) - 962 elif isinstance(y, np.ndarray): - 963 if y.shape == (self.T,): - 964 return Corr(list((np.array(self.content).T + y).T)) - 965 else: - 966 raise ValueError("operands could not be broadcast together") - 967 else: - 968 raise TypeError("Corr + wrong type") - 969 - 970 def __mul__(self, y): - 971 if isinstance(y, Corr): - 972 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): - 973 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") - 974 newcontent = [] - 975 for t in range(self.T): - 976 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): - 977 newcontent.append(None) - 978 else: - 979 newcontent.append(self.content[t] * y.content[t]) - 980 return Corr(newcontent) - 981 - 982 elif isinstance(y, (Obs, int, float, CObs)): - 983 newcontent = [] - 984 for t in range(self.T): - 985 if _check_for_none(self, self.content[t]): - 986 newcontent.append(None) - 987 else: - 988 newcontent.append(self.content[t] * y) - 989 return Corr(newcontent, prange=self.prange) - 990 elif isinstance(y, np.ndarray): - 991 if y.shape == (self.T,): - 992 return Corr(list((np.array(self.content).T * y).T)) - 993 else: - 994 raise ValueError("operands could not be broadcast together") - 995 else: - 996 raise TypeError("Corr * wrong type") - 997 - 998 def __truediv__(self, y): - 999 if isinstance(y, Corr): -1000 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): -1001 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") -1002 newcontent = [] -1003 for t in range(self.T): -1004 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): -1005 newcontent.append(None) -1006 else: -1007 newcontent.append(self.content[t] / y.content[t]) -1008 for t in range(self.T): -1009 if _check_for_none(self, newcontent[t]): -1010 continue -1011 if np.isnan(np.sum(newcontent[t]).value): -1012 newcontent[t] = None -1013 -1014 if all([item is None for item in newcontent]): -1015 raise Exception("Division returns completely undefined correlator") -1016 return Corr(newcontent) + 913 def __repr__(self, print_range=None): + 914 if print_range is None: + 915 print_range = [0, None] + 916 + 917 content_string = "" + 918 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 + 919 + 920 if self.tag is not None: + 921 content_string += "Description: " + self.tag + "\n" + 922 if self.N != 1: + 923 return content_string + 924 + 925 if print_range[1]: + 926 print_range[1] += 1 + 927 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' + 928 for i, sub_corr in enumerate(self.content[print_range[0]:print_range[1]]): + 929 if sub_corr is None: + 930 content_string += str(i + print_range[0]) + '\n' + 931 else: + 932 content_string += str(i + print_range[0]) + 933 for element in sub_corr: + 934 content_string += '\t' + ' ' * int(element >= 0) + str(element) + 935 content_string += '\n' + 936 return content_string + 937 + 938 def __str__(self): + 939 return self.__repr__() + 940 + 941 # We define the basic operations, that can be performed with correlators. + 942 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. + 943 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. + 944 # One could try and tell Obs to check if the y in __mul__ is a Corr and + 945 + 946 def __add__(self, y): + 947 if isinstance(y, Corr): + 948 if ((self.N != y.N) or (self.T != y.T)): + 949 raise Exception("Addition of Corrs with different shape") + 950 newcontent = [] + 951 for t in range(self.T): + 952 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): + 953 newcontent.append(None) + 954 else: + 955 newcontent.append(self.content[t] + y.content[t]) + 956 return Corr(newcontent) + 957 + 958 elif isinstance(y, (Obs, int, float, CObs)): + 959 newcontent = [] + 960 for t in range(self.T): + 961 if _check_for_none(self, self.content[t]): + 962 newcontent.append(None) + 963 else: + 964 newcontent.append(self.content[t] + y) + 965 return Corr(newcontent, prange=self.prange) + 966 elif isinstance(y, np.ndarray): + 967 if y.shape == (self.T,): + 968 return Corr(list((np.array(self.content).T + y).T)) + 969 else: + 970 raise ValueError("operands could not be broadcast together") + 971 else: + 972 raise TypeError("Corr + wrong type") + 973 + 974 def __mul__(self, y): + 975 if isinstance(y, Corr): + 976 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): + 977 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") + 978 newcontent = [] + 979 for t in range(self.T): + 980 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): + 981 newcontent.append(None) + 982 else: + 983 newcontent.append(self.content[t] * y.content[t]) + 984 return Corr(newcontent) + 985 + 986 elif isinstance(y, (Obs, int, float, CObs)): + 987 newcontent = [] + 988 for t in range(self.T): + 989 if _check_for_none(self, self.content[t]): + 990 newcontent.append(None) + 991 else: + 992 newcontent.append(self.content[t] * y) + 993 return Corr(newcontent, prange=self.prange) + 994 elif isinstance(y, np.ndarray): + 995 if y.shape == (self.T,): + 996 return Corr(list((np.array(self.content).T * y).T)) + 997 else: + 998 raise ValueError("operands could not be broadcast together") + 999 else: +1000 raise TypeError("Corr * wrong type") +1001 +1002 def __truediv__(self, y): +1003 if isinstance(y, Corr): +1004 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): +1005 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") +1006 newcontent = [] +1007 for t in range(self.T): +1008 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): +1009 newcontent.append(None) +1010 else: +1011 newcontent.append(self.content[t] / y.content[t]) +1012 for t in range(self.T): +1013 if _check_for_none(self, newcontent[t]): +1014 continue +1015 if np.isnan(np.sum(newcontent[t]).value): +1016 newcontent[t] = None 1017 -1018 elif isinstance(y, (Obs, CObs)): -1019 if isinstance(y, Obs): -1020 if y.value == 0: -1021 raise Exception('Division by zero will return undefined correlator') -1022 if isinstance(y, CObs): -1023 if y.is_zero(): -1024 raise Exception('Division by zero will return undefined correlator') -1025 -1026 newcontent = [] -1027 for t in range(self.T): -1028 if _check_for_none(self, self.content[t]): -1029 newcontent.append(None) -1030 else: -1031 newcontent.append(self.content[t] / y) -1032 return Corr(newcontent, prange=self.prange) -1033 -1034 elif isinstance(y, (int, float)): -1035 if y == 0: -1036 raise Exception('Division by zero will return undefined correlator') -1037 newcontent = [] -1038 for t in range(self.T): -1039 if _check_for_none(self, self.content[t]): -1040 newcontent.append(None) -1041 else: -1042 newcontent.append(self.content[t] / y) -1043 return Corr(newcontent, prange=self.prange) -1044 elif isinstance(y, np.ndarray): -1045 if y.shape == (self.T,): -1046 return Corr(list((np.array(self.content).T / y).T)) -1047 else: -1048 raise ValueError("operands could not be broadcast together") -1049 else: -1050 raise TypeError('Corr / wrong type') -1051 -1052 def __neg__(self): -1053 newcontent = [None if _check_for_none(self, item) else -1. * item for item in self.content] -1054 return Corr(newcontent, prange=self.prange) +1018 if all([item is None for item in newcontent]): +1019 raise Exception("Division returns completely undefined correlator") +1020 return Corr(newcontent) +1021 +1022 elif isinstance(y, (Obs, CObs)): +1023 if isinstance(y, Obs): +1024 if y.value == 0: +1025 raise Exception('Division by zero will return undefined correlator') +1026 if isinstance(y, CObs): +1027 if y.is_zero(): +1028 raise Exception('Division by zero will return undefined correlator') +1029 +1030 newcontent = [] +1031 for t in range(self.T): +1032 if _check_for_none(self, self.content[t]): +1033 newcontent.append(None) +1034 else: +1035 newcontent.append(self.content[t] / y) +1036 return Corr(newcontent, prange=self.prange) +1037 +1038 elif isinstance(y, (int, float)): +1039 if y == 0: +1040 raise Exception('Division by zero will return undefined correlator') +1041 newcontent = [] +1042 for t in range(self.T): +1043 if _check_for_none(self, self.content[t]): +1044 newcontent.append(None) +1045 else: +1046 newcontent.append(self.content[t] / y) +1047 return Corr(newcontent, prange=self.prange) +1048 elif isinstance(y, np.ndarray): +1049 if y.shape == (self.T,): +1050 return Corr(list((np.array(self.content).T / y).T)) +1051 else: +1052 raise ValueError("operands could not be broadcast together") +1053 else: +1054 raise TypeError('Corr / wrong type') 1055 -1056 def __sub__(self, y): -1057 return self + (-y) -1058 -1059 def __pow__(self, y): -1060 if isinstance(y, (Obs, int, float, CObs)): -1061 newcontent = [None if _check_for_none(self, item) else item**y for item in self.content] -1062 return Corr(newcontent, prange=self.prange) -1063 else: -1064 raise TypeError('Type of exponent not supported') -1065 -1066 def __abs__(self): -1067 newcontent = [None if _check_for_none(self, item) else np.abs(item) for item in self.content] -1068 return Corr(newcontent, prange=self.prange) +1056 def __neg__(self): +1057 newcontent = [None if _check_for_none(self, item) else -1. * item for item in self.content] +1058 return Corr(newcontent, prange=self.prange) +1059 +1060 def __sub__(self, y): +1061 return self + (-y) +1062 +1063 def __pow__(self, y): +1064 if isinstance(y, (Obs, int, float, CObs)): +1065 newcontent = [None if _check_for_none(self, item) else item**y for item in self.content] +1066 return Corr(newcontent, prange=self.prange) +1067 else: +1068 raise TypeError('Type of exponent not supported') 1069 -1070 # The numpy functions: -1071 def sqrt(self): -1072 return self ** 0.5 +1070 def __abs__(self): +1071 newcontent = [None if _check_for_none(self, item) else np.abs(item) for item in self.content] +1072 return Corr(newcontent, prange=self.prange) 1073 -1074 def log(self): -1075 newcontent = [None if _check_for_none(self, item) else np.log(item) for item in self.content] -1076 return Corr(newcontent, prange=self.prange) +1074 # The numpy functions: +1075 def sqrt(self): +1076 return self ** 0.5 1077 -1078 def exp(self): -1079 newcontent = [None if _check_for_none(self, item) else np.exp(item) for item in self.content] +1078 def log(self): +1079 newcontent = [None if _check_for_none(self, item) else np.log(item) for item in self.content] 1080 return Corr(newcontent, prange=self.prange) 1081 -1082 def _apply_func_to_corr(self, func): -1083 newcontent = [None if _check_for_none(self, item) else func(item) for item in self.content] -1084 for t in range(self.T): -1085 if _check_for_none(self, newcontent[t]): -1086 continue -1087 if np.isnan(np.sum(newcontent[t]).value): -1088 newcontent[t] = None -1089 if all([item is None for item in newcontent]): -1090 raise Exception('Operation returns undefined correlator') -1091 return Corr(newcontent) -1092 -1093 def sin(self): -1094 return self._apply_func_to_corr(np.sin) -1095 -1096 def cos(self): -1097 return self._apply_func_to_corr(np.cos) -1098 -1099 def tan(self): -1100 return self._apply_func_to_corr(np.tan) -1101 -1102 def sinh(self): -1103 return self._apply_func_to_corr(np.sinh) -1104 -1105 def cosh(self): -1106 return self._apply_func_to_corr(np.cosh) -1107 -1108 def tanh(self): -1109 return self._apply_func_to_corr(np.tanh) -1110 -1111 def arcsin(self): -1112 return self._apply_func_to_corr(np.arcsin) -1113 -1114 def arccos(self): -1115 return self._apply_func_to_corr(np.arccos) -1116 -1117 def arctan(self): -1118 return self._apply_func_to_corr(np.arctan) -1119 -1120 def arcsinh(self): -1121 return self._apply_func_to_corr(np.arcsinh) -1122 -1123 def arccosh(self): -1124 return self._apply_func_to_corr(np.arccosh) -1125 -1126 def arctanh(self): -1127 return self._apply_func_to_corr(np.arctanh) -1128 -1129 # Right hand side operations (require tweak in main module to work) -1130 def __radd__(self, y): -1131 return self + y +1082 def exp(self): +1083 newcontent = [None if _check_for_none(self, item) else np.exp(item) for item in self.content] +1084 return Corr(newcontent, prange=self.prange) +1085 +1086 def _apply_func_to_corr(self, func): +1087 newcontent = [None if _check_for_none(self, item) else func(item) for item in self.content] +1088 for t in range(self.T): +1089 if _check_for_none(self, newcontent[t]): +1090 continue +1091 if np.isnan(np.sum(newcontent[t]).value): +1092 newcontent[t] = None +1093 if all([item is None for item in newcontent]): +1094 raise Exception('Operation returns undefined correlator') +1095 return Corr(newcontent) +1096 +1097 def sin(self): +1098 return self._apply_func_to_corr(np.sin) +1099 +1100 def cos(self): +1101 return self._apply_func_to_corr(np.cos) +1102 +1103 def tan(self): +1104 return self._apply_func_to_corr(np.tan) +1105 +1106 def sinh(self): +1107 return self._apply_func_to_corr(np.sinh) +1108 +1109 def cosh(self): +1110 return self._apply_func_to_corr(np.cosh) +1111 +1112 def tanh(self): +1113 return self._apply_func_to_corr(np.tanh) +1114 +1115 def arcsin(self): +1116 return self._apply_func_to_corr(np.arcsin) +1117 +1118 def arccos(self): +1119 return self._apply_func_to_corr(np.arccos) +1120 +1121 def arctan(self): +1122 return self._apply_func_to_corr(np.arctan) +1123 +1124 def arcsinh(self): +1125 return self._apply_func_to_corr(np.arcsinh) +1126 +1127 def arccosh(self): +1128 return self._apply_func_to_corr(np.arccosh) +1129 +1130 def arctanh(self): +1131 return self._apply_func_to_corr(np.arctanh) 1132 -1133 def __rsub__(self, y): -1134 return -self + y -1135 -1136 def __rmul__(self, y): -1137 return self * y -1138 -1139 def __rtruediv__(self, y): -1140 return (self / y) ** (-1) -1141 -1142 @property -1143 def real(self): -1144 def return_real(obs_OR_cobs): -1145 if isinstance(obs_OR_cobs, CObs): -1146 return obs_OR_cobs.real -1147 else: -1148 return obs_OR_cobs -1149 -1150 return self._apply_func_to_corr(return_real) -1151 -1152 @property -1153 def imag(self): -1154 def return_imag(obs_OR_cobs): -1155 if isinstance(obs_OR_cobs, CObs): -1156 return obs_OR_cobs.imag -1157 else: -1158 return obs_OR_cobs * 0 # So it stays the right type -1159 -1160 return self._apply_func_to_corr(return_imag) -1161 -1162 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): -1163 r''' Project large correlation matrix to lowest states -1164 -1165 This method can be used to reduce the size of an (N x N) correlation matrix -1166 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise -1167 is still small. +1133 # Right hand side operations (require tweak in main module to work) +1134 def __radd__(self, y): +1135 return self + y +1136 +1137 def __rsub__(self, y): +1138 return -self + y +1139 +1140 def __rmul__(self, y): +1141 return self * y +1142 +1143 def __rtruediv__(self, y): +1144 return (self / y) ** (-1) +1145 +1146 @property +1147 def real(self): +1148 def return_real(obs_OR_cobs): +1149 if isinstance(obs_OR_cobs, CObs): +1150 return obs_OR_cobs.real +1151 else: +1152 return obs_OR_cobs +1153 +1154 return self._apply_func_to_corr(return_real) +1155 +1156 @property +1157 def imag(self): +1158 def return_imag(obs_OR_cobs): +1159 if isinstance(obs_OR_cobs, CObs): +1160 return obs_OR_cobs.imag +1161 else: +1162 return obs_OR_cobs * 0 # So it stays the right type +1163 +1164 return self._apply_func_to_corr(return_imag) +1165 +1166 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): +1167 r''' Project large correlation matrix to lowest states 1168 -1169 Parameters -1170 ---------- -1171 Ntrunc: int -1172 Rank of the target matrix. -1173 tproj: int -1174 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. -1175 The default value is 3. -1176 t0proj: int -1177 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly -1178 discouraged for O(a) improved theories, since the correctness of the procedure -1179 cannot be granted in this case. The default value is 2. -1180 basematrix : Corr -1181 Correlation matrix that is used to determine the eigenvectors of the -1182 lowest states based on a GEVP. basematrix is taken to be the Corr itself if -1183 is is not specified. -1184 -1185 Notes -1186 ----- -1187 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving -1188 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}$ -1189 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the -1190 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via -1191 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large -1192 correlation matrix and to remove some noise that is added by irrelevant operators. -1193 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated -1194 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. -1195 ''' -1196 -1197 if self.N == 1: -1198 raise Exception('Method cannot be applied to one-dimensional correlators.') -1199 if basematrix is None: -1200 basematrix = self -1201 if Ntrunc >= basematrix.N: -1202 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) -1203 if basematrix.N != self.N: -1204 raise Exception('basematrix and targetmatrix have to be of the same size.') -1205 -1206 evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc] -1207 -1208 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) -1209 rmat = [] -1210 for t in range(basematrix.T): -1211 for i in range(Ntrunc): -1212 for j in range(Ntrunc): -1213 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] -1214 rmat.append(np.copy(tmpmat)) -1215 -1216 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] -1217 return Corr(newcontent) -1218 +1169 This method can be used to reduce the size of an (N x N) correlation matrix +1170 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise +1171 is still small. +1172 +1173 Parameters +1174 ---------- +1175 Ntrunc: int +1176 Rank of the target matrix. +1177 tproj: int +1178 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. +1179 The default value is 3. +1180 t0proj: int +1181 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly +1182 discouraged for O(a) improved theories, since the correctness of the procedure +1183 cannot be granted in this case. The default value is 2. +1184 basematrix : Corr +1185 Correlation matrix that is used to determine the eigenvectors of the +1186 lowest states based on a GEVP. basematrix is taken to be the Corr itself if +1187 is is not specified. +1188 +1189 Notes +1190 ----- +1191 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving +1192 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}$ +1193 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the +1194 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via +1195 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large +1196 correlation matrix and to remove some noise that is added by irrelevant operators. +1197 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated +1198 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. +1199 ''' +1200 +1201 if self.N == 1: +1202 raise Exception('Method cannot be applied to one-dimensional correlators.') +1203 if basematrix is None: +1204 basematrix = self +1205 if Ntrunc >= basematrix.N: +1206 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) +1207 if basematrix.N != self.N: +1208 raise Exception('basematrix and targetmatrix have to be of the same size.') +1209 +1210 evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc] +1211 +1212 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) +1213 rmat = [] +1214 for t in range(basematrix.T): +1215 for i in range(Ntrunc): +1216 for j in range(Ntrunc): +1217 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] +1218 rmat.append(np.copy(tmpmat)) 1219 -1220def _sort_vectors(vec_set, ts): -1221 """Helper function used to find a set of Eigenvectors consistent over all timeslices""" -1222 reference_sorting = np.array(vec_set[ts]) -1223 N = reference_sorting.shape[0] -1224 sorted_vec_set = [] -1225 for t in range(len(vec_set)): -1226 if vec_set[t] is None: -1227 sorted_vec_set.append(None) -1228 elif not t == ts: -1229 perms = [list(o) for o in permutations([i for i in range(N)], N)] -1230 best_score = 0 -1231 for perm in perms: -1232 current_score = 1 -1233 for k in range(N): -1234 new_sorting = reference_sorting.copy() -1235 new_sorting[perm[k], :] = vec_set[t][k] -1236 current_score *= abs(np.linalg.det(new_sorting)) -1237 if current_score > best_score: -1238 best_score = current_score -1239 best_perm = perm -1240 sorted_vec_set.append([vec_set[t][k] for k in best_perm]) -1241 else: -1242 sorted_vec_set.append(vec_set[t]) -1243 -1244 return sorted_vec_set -1245 -1246 -1247def _check_for_none(corr, entry): -1248 """Checks if entry for correlator corr is None""" -1249 return len(list(filter(None, np.asarray(entry).flatten()))) < corr.N ** 2 +1220 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] +1221 return Corr(newcontent) +1222 +1223 +1224def _sort_vectors(vec_set, ts): +1225 """Helper function used to find a set of Eigenvectors consistent over all timeslices""" +1226 reference_sorting = np.array(vec_set[ts]) +1227 N = reference_sorting.shape[0] +1228 sorted_vec_set = [] +1229 for t in range(len(vec_set)): +1230 if vec_set[t] is None: +1231 sorted_vec_set.append(None) +1232 elif not t == ts: +1233 perms = [list(o) for o in permutations([i for i in range(N)], N)] +1234 best_score = 0 +1235 for perm in perms: +1236 current_score = 1 +1237 for k in range(N): +1238 new_sorting = reference_sorting.copy() +1239 new_sorting[perm[k], :] = vec_set[t][k] +1240 current_score *= abs(np.linalg.det(new_sorting)) +1241 if current_score > best_score: +1242 best_score = current_score +1243 best_perm = perm +1244 sorted_vec_set.append([vec_set[t][k] for k in best_perm]) +1245 else: +1246 sorted_vec_set.append(vec_set[t]) +1247 +1248 return sorted_vec_set +1249 1250 -1251 -1252def _GEVP_solver(Gt, G0): -1253 """Helper function for solving the GEVP and sorting the eigenvectors. +1251def _check_for_none(corr, entry): +1252 """Checks if entry for correlator corr is None""" +1253 return len(list(filter(None, np.asarray(entry).flatten()))) < corr.N ** 2 1254 -1255 The helper function assumes that both provided matrices are symmetric and -1256 only processes the lower triangular part of both matrices. In case the matrices -1257 are not symmetric the upper triangular parts are effectively discarded.""" -1258 return scipy.linalg.eigh(Gt, G0, lower=True)[1].T[::-1] +1255 +1256def _GEVP_solver(Gt, G0): +1257 """Helper function for solving the GEVP and sorting the eigenvectors. +1258 +1259 The helper function assumes that both provided matrices are symmetric and +1260 only processes the lower triangular part of both matrices. In case the matrices +1261 are not symmetric the upper triangular parts are effectively discarded.""" +1262 return scipy.linalg.eigh(Gt, G0, lower=True)[1].T[::-1] @@ -2079,617 +2083,621 @@ 605 for t in range(self.T - 1): 606 if ((self.content[t] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0): 607 newcontent.append(None) - 608 else: - 609 newcontent.append(self.content[t] / self.content[t + 1]) - 610 if(all([x is None for x in newcontent])): - 611 raise Exception('m_eff is undefined at all timeslices') - 612 - 613 return np.log(Corr(newcontent, padding=[0, 1])) + 608 elif self.content[t][0].value / self.content[t + 1][0].value < 0: + 609 newcontent.append(None) + 610 else: + 611 newcontent.append(self.content[t] / self.content[t + 1]) + 612 if(all([x is None for x in newcontent])): + 613 raise Exception('m_eff is undefined at all timeslices') 614 - 615 elif variant in ['periodic', 'cosh', 'sinh']: - 616 if variant in ['periodic', 'cosh']: - 617 func = anp.cosh - 618 else: - 619 func = anp.sinh - 620 - 621 def root_function(x, d): - 622 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d - 623 - 624 newcontent = [] - 625 for t in range(self.T - 1): - 626 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0): - 627 newcontent.append(None) - 628 # Fill the two timeslices in the middle of the lattice with their predecessors - 629 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: - 630 newcontent.append(newcontent[-1]) - 631 else: - 632 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) - 633 if(all([x is None for x in newcontent])): - 634 raise Exception('m_eff is undefined at all timeslices') - 635 - 636 return Corr(newcontent, padding=[0, 1]) - 637 - 638 elif variant == 'arccosh': - 639 newcontent = [] - 640 for t in range(1, self.T - 1): - 641 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None) or (self.content[t][0].value == 0): - 642 newcontent.append(None) - 643 else: - 644 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) - 645 if(all([x is None for x in newcontent])): - 646 raise Exception("m_eff is undefined at all timeslices") - 647 return np.arccosh(Corr(newcontent, padding=[1, 1])) - 648 - 649 else: - 650 raise Exception('Unknown variant.') - 651 - 652 def fit(self, function, fitrange=None, silent=False, **kwargs): - 653 r'''Fits function to the data - 654 - 655 Parameters - 656 ---------- - 657 function : obj - 658 function to fit to the data. See fits.least_squares for details. - 659 fitrange : list - 660 Two element list containing the timeslices on which the fit is supposed to start and stop. - 661 Caution: This range is inclusive as opposed to standard python indexing. - 662 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. - 663 If not specified, self.prange or all timeslices are used. - 664 silent : bool - 665 Decides whether output is printed to the standard output. - 666 ''' - 667 if self.N != 1: - 668 raise Exception("Correlator must be projected before fitting") - 669 - 670 if fitrange is None: - 671 if self.prange: - 672 fitrange = self.prange - 673 else: - 674 fitrange = [0, self.T - 1] - 675 else: - 676 if not isinstance(fitrange, list): - 677 raise Exception("fitrange has to be a list with two elements") - 678 if len(fitrange) != 2: - 679 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") - 680 - 681 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 682 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 683 result = least_squares(xs, ys, function, silent=silent, **kwargs) - 684 return result - 685 - 686 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): - 687 """ Extract a plateau value from a Corr object - 688 - 689 Parameters - 690 ---------- - 691 plateau_range : list - 692 list with two entries, indicating the first and the last timeslice - 693 of the plateau region. - 694 method : str - 695 method to extract the plateau. - 696 'fit' fits a constant to the plateau region - 697 'avg', 'average' or 'mean' just average over the given timeslices. - 698 auto_gamma : bool - 699 apply gamma_method with default parameters to the Corr. Defaults to None - 700 """ - 701 if not plateau_range: - 702 if self.prange: - 703 plateau_range = self.prange - 704 else: - 705 raise Exception("no plateau range provided") - 706 if self.N != 1: - 707 raise Exception("Correlator must be projected before getting a plateau.") - 708 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): - 709 raise Exception("plateau is undefined at all timeslices in plateaurange.") - 710 if auto_gamma: - 711 self.gamma_method() - 712 if method == "fit": - 713 def const_func(a, t): - 714 return a[0] - 715 return self.fit(const_func, plateau_range)[0] - 716 elif method in ["avg", "average", "mean"]: - 717 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) - 718 return returnvalue - 719 - 720 else: - 721 raise Exception("Unsupported plateau method: " + method) - 722 - 723 def set_prange(self, prange): - 724 """Sets the attribute prange of the Corr object.""" - 725 if not len(prange) == 2: - 726 raise Exception("prange must be a list or array with two values") - 727 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): - 728 raise Exception("Start and end point must be integers") - 729 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): - 730 raise Exception("Start and end point must define a range in the interval 0,T") - 731 - 732 self.prange = prange - 733 return - 734 - 735 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, title=None): - 736 """Plots the correlator using the tag of the correlator as label if available. - 737 - 738 Parameters - 739 ---------- - 740 x_range : list - 741 list of two values, determining the range of the x-axis e.g. [4, 8]. - 742 comp : Corr or list of Corr - 743 Correlator or list of correlators which are plotted for comparison. - 744 The tags of these correlators are used as labels if available. - 745 logscale : bool - 746 Sets y-axis to logscale. - 747 plateau : Obs - 748 Plateau value to be visualized in the figure. - 749 fit_res : Fit_result - 750 Fit_result object to be visualized. - 751 ylabel : str - 752 Label for the y-axis. - 753 save : str - 754 path to file in which the figure should be saved. - 755 auto_gamma : bool - 756 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. - 757 hide_sigma : float - 758 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. - 759 references : list - 760 List of floating point values that are displayed as horizontal lines for reference. - 761 title : string - 762 Optional title of the figure. - 763 """ - 764 if self.N != 1: - 765 raise Exception("Correlator must be projected before plotting") - 766 - 767 if auto_gamma: - 768 self.gamma_method() - 769 - 770 if x_range is None: - 771 x_range = [0, self.T - 1] - 772 - 773 fig = plt.figure() - 774 ax1 = fig.add_subplot(111) - 775 - 776 x, y, y_err = self.plottable() - 777 if hide_sigma: - 778 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 - 779 else: - 780 hide_from = None - 781 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) - 782 if logscale: - 783 ax1.set_yscale('log') - 784 else: - 785 if y_range is None: - 786 try: - 787 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)]) - 788 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)]) - 789 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) - 790 except Exception: - 791 pass - 792 else: - 793 ax1.set_ylim(y_range) - 794 if comp: - 795 if isinstance(comp, (Corr, list)): - 796 for corr in comp if isinstance(comp, list) else [comp]: - 797 if auto_gamma: - 798 corr.gamma_method() - 799 x, y, y_err = corr.plottable() - 800 if hide_sigma: - 801 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 - 802 else: - 803 hide_from = None - 804 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) - 805 else: - 806 raise Exception("'comp' must be a correlator or a list of correlators.") - 807 - 808 if plateau: - 809 if isinstance(plateau, Obs): - 810 if auto_gamma: - 811 plateau.gamma_method() - 812 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) - 813 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') - 814 else: - 815 raise Exception("'plateau' must be an Obs") - 816 - 817 if references: - 818 if isinstance(references, list): - 819 for ref in references: - 820 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') - 821 else: - 822 raise Exception("'references' must be a list of floating pint values.") - 823 - 824 if self.prange: - 825 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') - 826 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') + 615 return np.log(Corr(newcontent, padding=[0, 1])) + 616 + 617 elif variant in ['periodic', 'cosh', 'sinh']: + 618 if variant in ['periodic', 'cosh']: + 619 func = anp.cosh + 620 else: + 621 func = anp.sinh + 622 + 623 def root_function(x, d): + 624 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d + 625 + 626 newcontent = [] + 627 for t in range(self.T - 1): + 628 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0): + 629 newcontent.append(None) + 630 # Fill the two timeslices in the middle of the lattice with their predecessors + 631 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: + 632 newcontent.append(newcontent[-1]) + 633 elif self.content[t][0].value / self.content[t + 1][0].value < 0: + 634 newcontent.append(None) + 635 else: + 636 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) + 637 if(all([x is None for x in newcontent])): + 638 raise Exception('m_eff is undefined at all timeslices') + 639 + 640 return Corr(newcontent, padding=[0, 1]) + 641 + 642 elif variant == 'arccosh': + 643 newcontent = [] + 644 for t in range(1, self.T - 1): + 645 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None) or (self.content[t][0].value == 0): + 646 newcontent.append(None) + 647 else: + 648 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) + 649 if(all([x is None for x in newcontent])): + 650 raise Exception("m_eff is undefined at all timeslices") + 651 return np.arccosh(Corr(newcontent, padding=[1, 1])) + 652 + 653 else: + 654 raise Exception('Unknown variant.') + 655 + 656 def fit(self, function, fitrange=None, silent=False, **kwargs): + 657 r'''Fits function to the data + 658 + 659 Parameters + 660 ---------- + 661 function : obj + 662 function to fit to the data. See fits.least_squares for details. + 663 fitrange : list + 664 Two element list containing the timeslices on which the fit is supposed to start and stop. + 665 Caution: This range is inclusive as opposed to standard python indexing. + 666 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. + 667 If not specified, self.prange or all timeslices are used. + 668 silent : bool + 669 Decides whether output is printed to the standard output. + 670 ''' + 671 if self.N != 1: + 672 raise Exception("Correlator must be projected before fitting") + 673 + 674 if fitrange is None: + 675 if self.prange: + 676 fitrange = self.prange + 677 else: + 678 fitrange = [0, self.T - 1] + 679 else: + 680 if not isinstance(fitrange, list): + 681 raise Exception("fitrange has to be a list with two elements") + 682 if len(fitrange) != 2: + 683 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") + 684 + 685 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 686 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 687 result = least_squares(xs, ys, function, silent=silent, **kwargs) + 688 return result + 689 + 690 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): + 691 """ Extract a plateau value from a Corr object + 692 + 693 Parameters + 694 ---------- + 695 plateau_range : list + 696 list with two entries, indicating the first and the last timeslice + 697 of the plateau region. + 698 method : str + 699 method to extract the plateau. + 700 'fit' fits a constant to the plateau region + 701 'avg', 'average' or 'mean' just average over the given timeslices. + 702 auto_gamma : bool + 703 apply gamma_method with default parameters to the Corr. Defaults to None + 704 """ + 705 if not plateau_range: + 706 if self.prange: + 707 plateau_range = self.prange + 708 else: + 709 raise Exception("no plateau range provided") + 710 if self.N != 1: + 711 raise Exception("Correlator must be projected before getting a plateau.") + 712 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): + 713 raise Exception("plateau is undefined at all timeslices in plateaurange.") + 714 if auto_gamma: + 715 self.gamma_method() + 716 if method == "fit": + 717 def const_func(a, t): + 718 return a[0] + 719 return self.fit(const_func, plateau_range)[0] + 720 elif method in ["avg", "average", "mean"]: + 721 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) + 722 return returnvalue + 723 + 724 else: + 725 raise Exception("Unsupported plateau method: " + method) + 726 + 727 def set_prange(self, prange): + 728 """Sets the attribute prange of the Corr object.""" + 729 if not len(prange) == 2: + 730 raise Exception("prange must be a list or array with two values") + 731 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): + 732 raise Exception("Start and end point must be integers") + 733 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): + 734 raise Exception("Start and end point must define a range in the interval 0,T") + 735 + 736 self.prange = prange + 737 return + 738 + 739 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, title=None): + 740 """Plots the correlator using the tag of the correlator as label if available. + 741 + 742 Parameters + 743 ---------- + 744 x_range : list + 745 list of two values, determining the range of the x-axis e.g. [4, 8]. + 746 comp : Corr or list of Corr + 747 Correlator or list of correlators which are plotted for comparison. + 748 The tags of these correlators are used as labels if available. + 749 logscale : bool + 750 Sets y-axis to logscale. + 751 plateau : Obs + 752 Plateau value to be visualized in the figure. + 753 fit_res : Fit_result + 754 Fit_result object to be visualized. + 755 ylabel : str + 756 Label for the y-axis. + 757 save : str + 758 path to file in which the figure should be saved. + 759 auto_gamma : bool + 760 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. + 761 hide_sigma : float + 762 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. + 763 references : list + 764 List of floating point values that are displayed as horizontal lines for reference. + 765 title : string + 766 Optional title of the figure. + 767 """ + 768 if self.N != 1: + 769 raise Exception("Correlator must be projected before plotting") + 770 + 771 if auto_gamma: + 772 self.gamma_method() + 773 + 774 if x_range is None: + 775 x_range = [0, self.T - 1] + 776 + 777 fig = plt.figure() + 778 ax1 = fig.add_subplot(111) + 779 + 780 x, y, y_err = self.plottable() + 781 if hide_sigma: + 782 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 + 783 else: + 784 hide_from = None + 785 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) + 786 if logscale: + 787 ax1.set_yscale('log') + 788 else: + 789 if y_range is None: + 790 try: + 791 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)]) + 792 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)]) + 793 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) + 794 except Exception: + 795 pass + 796 else: + 797 ax1.set_ylim(y_range) + 798 if comp: + 799 if isinstance(comp, (Corr, list)): + 800 for corr in comp if isinstance(comp, list) else [comp]: + 801 if auto_gamma: + 802 corr.gamma_method() + 803 x, y, y_err = corr.plottable() + 804 if hide_sigma: + 805 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 + 806 else: + 807 hide_from = None + 808 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) + 809 else: + 810 raise Exception("'comp' must be a correlator or a list of correlators.") + 811 + 812 if plateau: + 813 if isinstance(plateau, Obs): + 814 if auto_gamma: + 815 plateau.gamma_method() + 816 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) + 817 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') + 818 else: + 819 raise Exception("'plateau' must be an Obs") + 820 + 821 if references: + 822 if isinstance(references, list): + 823 for ref in references: + 824 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') + 825 else: + 826 raise Exception("'references' must be a list of floating pint values.") 827 - 828 if fit_res: - 829 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) - 830 ax1.plot(x_samples, - 831 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), - 832 ls='-', marker=',', lw=2) - 833 - 834 ax1.set_xlabel(r'$x_0 / a$') - 835 if ylabel: - 836 ax1.set_ylabel(ylabel) - 837 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) - 838 - 839 handles, labels = ax1.get_legend_handles_labels() - 840 if labels: - 841 ax1.legend() + 828 if self.prange: + 829 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') + 830 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') + 831 + 832 if fit_res: + 833 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) + 834 ax1.plot(x_samples, + 835 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), + 836 ls='-', marker=',', lw=2) + 837 + 838 ax1.set_xlabel(r'$x_0 / a$') + 839 if ylabel: + 840 ax1.set_ylabel(ylabel) + 841 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) 842 - 843 if title: - 844 plt.title(title) - 845 - 846 plt.draw() - 847 - 848 if save: - 849 if isinstance(save, str): - 850 fig.savefig(save, bbox_inches='tight') - 851 else: - 852 raise Exception("'save' has to be a string.") - 853 - 854 def spaghetti_plot(self, logscale=True): - 855 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. - 856 - 857 Parameters - 858 ---------- - 859 logscale : bool - 860 Determines whether the scale of the y-axis is logarithmic or standard. - 861 """ - 862 if self.N != 1: - 863 raise Exception("Correlator needs to be projected first.") - 864 - 865 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])) - 866 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] - 867 - 868 for name in mc_names: - 869 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T - 870 - 871 fig = plt.figure() - 872 ax = fig.add_subplot(111) - 873 for dat in data: - 874 ax.plot(x0_vals, dat, ls='-', marker='') - 875 - 876 if logscale is True: - 877 ax.set_yscale('log') - 878 - 879 ax.set_xlabel(r'$x_0 / a$') - 880 plt.title(name) - 881 plt.draw() + 843 handles, labels = ax1.get_legend_handles_labels() + 844 if labels: + 845 ax1.legend() + 846 + 847 if title: + 848 plt.title(title) + 849 + 850 plt.draw() + 851 + 852 if save: + 853 if isinstance(save, str): + 854 fig.savefig(save, bbox_inches='tight') + 855 else: + 856 raise Exception("'save' has to be a string.") + 857 + 858 def spaghetti_plot(self, logscale=True): + 859 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. + 860 + 861 Parameters + 862 ---------- + 863 logscale : bool + 864 Determines whether the scale of the y-axis is logarithmic or standard. + 865 """ + 866 if self.N != 1: + 867 raise Exception("Correlator needs to be projected first.") + 868 + 869 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])) + 870 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] + 871 + 872 for name in mc_names: + 873 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T + 874 + 875 fig = plt.figure() + 876 ax = fig.add_subplot(111) + 877 for dat in data: + 878 ax.plot(x0_vals, dat, ls='-', marker='') + 879 + 880 if logscale is True: + 881 ax.set_yscale('log') 882 - 883 def dump(self, filename, datatype="json.gz", **kwargs): - 884 """Dumps the Corr into a file of chosen type - 885 Parameters - 886 ---------- - 887 filename : str - 888 Name of the file to be saved. - 889 datatype : str - 890 Format of the exported file. Supported formats include - 891 "json.gz" and "pickle" - 892 path : str - 893 specifies a custom path for the file (default '.') - 894 """ - 895 if datatype == "json.gz": - 896 from .input.json import dump_to_json - 897 if 'path' in kwargs: - 898 file_name = kwargs.get('path') + '/' + filename - 899 else: - 900 file_name = filename - 901 dump_to_json(self, file_name) - 902 elif datatype == "pickle": - 903 dump_object(self, filename, **kwargs) - 904 else: - 905 raise Exception("Unknown datatype " + str(datatype)) - 906 - 907 def print(self, print_range=None): - 908 print(self.__repr__(print_range)) - 909 - 910 def __repr__(self, print_range=None): - 911 if print_range is None: - 912 print_range = [0, None] + 883 ax.set_xlabel(r'$x_0 / a$') + 884 plt.title(name) + 885 plt.draw() + 886 + 887 def dump(self, filename, datatype="json.gz", **kwargs): + 888 """Dumps the Corr into a file of chosen type + 889 Parameters + 890 ---------- + 891 filename : str + 892 Name of the file to be saved. + 893 datatype : str + 894 Format of the exported file. Supported formats include + 895 "json.gz" and "pickle" + 896 path : str + 897 specifies a custom path for the file (default '.') + 898 """ + 899 if datatype == "json.gz": + 900 from .input.json import dump_to_json + 901 if 'path' in kwargs: + 902 file_name = kwargs.get('path') + '/' + filename + 903 else: + 904 file_name = filename + 905 dump_to_json(self, file_name) + 906 elif datatype == "pickle": + 907 dump_object(self, filename, **kwargs) + 908 else: + 909 raise Exception("Unknown datatype " + str(datatype)) + 910 + 911 def print(self, print_range=None): + 912 print(self.__repr__(print_range)) 913 - 914 content_string = "" - 915 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 - 916 - 917 if self.tag is not None: - 918 content_string += "Description: " + self.tag + "\n" - 919 if self.N != 1: - 920 return content_string - 921 - 922 if print_range[1]: - 923 print_range[1] += 1 - 924 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' - 925 for i, sub_corr in enumerate(self.content[print_range[0]:print_range[1]]): - 926 if sub_corr is None: - 927 content_string += str(i + print_range[0]) + '\n' - 928 else: - 929 content_string += str(i + print_range[0]) - 930 for element in sub_corr: - 931 content_string += '\t' + ' ' * int(element >= 0) + str(element) - 932 content_string += '\n' - 933 return content_string - 934 - 935 def __str__(self): - 936 return self.__repr__() - 937 - 938 # We define the basic operations, that can be performed with correlators. - 939 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. - 940 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. - 941 # One could try and tell Obs to check if the y in __mul__ is a Corr and - 942 - 943 def __add__(self, y): - 944 if isinstance(y, Corr): - 945 if ((self.N != y.N) or (self.T != y.T)): - 946 raise Exception("Addition of Corrs with different shape") - 947 newcontent = [] - 948 for t in range(self.T): - 949 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): - 950 newcontent.append(None) - 951 else: - 952 newcontent.append(self.content[t] + y.content[t]) - 953 return Corr(newcontent) - 954 - 955 elif isinstance(y, (Obs, int, float, CObs)): - 956 newcontent = [] - 957 for t in range(self.T): - 958 if _check_for_none(self, self.content[t]): - 959 newcontent.append(None) - 960 else: - 961 newcontent.append(self.content[t] + y) - 962 return Corr(newcontent, prange=self.prange) - 963 elif isinstance(y, np.ndarray): - 964 if y.shape == (self.T,): - 965 return Corr(list((np.array(self.content).T + y).T)) - 966 else: - 967 raise ValueError("operands could not be broadcast together") - 968 else: - 969 raise TypeError("Corr + wrong type") - 970 - 971 def __mul__(self, y): - 972 if isinstance(y, Corr): - 973 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): - 974 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") - 975 newcontent = [] - 976 for t in range(self.T): - 977 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): - 978 newcontent.append(None) - 979 else: - 980 newcontent.append(self.content[t] * y.content[t]) - 981 return Corr(newcontent) - 982 - 983 elif isinstance(y, (Obs, int, float, CObs)): - 984 newcontent = [] - 985 for t in range(self.T): - 986 if _check_for_none(self, self.content[t]): - 987 newcontent.append(None) - 988 else: - 989 newcontent.append(self.content[t] * y) - 990 return Corr(newcontent, prange=self.prange) - 991 elif isinstance(y, np.ndarray): - 992 if y.shape == (self.T,): - 993 return Corr(list((np.array(self.content).T * y).T)) - 994 else: - 995 raise ValueError("operands could not be broadcast together") - 996 else: - 997 raise TypeError("Corr * wrong type") - 998 - 999 def __truediv__(self, y): -1000 if isinstance(y, Corr): -1001 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): -1002 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") -1003 newcontent = [] -1004 for t in range(self.T): -1005 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): -1006 newcontent.append(None) -1007 else: -1008 newcontent.append(self.content[t] / y.content[t]) -1009 for t in range(self.T): -1010 if _check_for_none(self, newcontent[t]): -1011 continue -1012 if np.isnan(np.sum(newcontent[t]).value): -1013 newcontent[t] = None -1014 -1015 if all([item is None for item in newcontent]): -1016 raise Exception("Division returns completely undefined correlator") -1017 return Corr(newcontent) + 914 def __repr__(self, print_range=None): + 915 if print_range is None: + 916 print_range = [0, None] + 917 + 918 content_string = "" + 919 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 + 920 + 921 if self.tag is not None: + 922 content_string += "Description: " + self.tag + "\n" + 923 if self.N != 1: + 924 return content_string + 925 + 926 if print_range[1]: + 927 print_range[1] += 1 + 928 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' + 929 for i, sub_corr in enumerate(self.content[print_range[0]:print_range[1]]): + 930 if sub_corr is None: + 931 content_string += str(i + print_range[0]) + '\n' + 932 else: + 933 content_string += str(i + print_range[0]) + 934 for element in sub_corr: + 935 content_string += '\t' + ' ' * int(element >= 0) + str(element) + 936 content_string += '\n' + 937 return content_string + 938 + 939 def __str__(self): + 940 return self.__repr__() + 941 + 942 # We define the basic operations, that can be performed with correlators. + 943 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. + 944 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. + 945 # One could try and tell Obs to check if the y in __mul__ is a Corr and + 946 + 947 def __add__(self, y): + 948 if isinstance(y, Corr): + 949 if ((self.N != y.N) or (self.T != y.T)): + 950 raise Exception("Addition of Corrs with different shape") + 951 newcontent = [] + 952 for t in range(self.T): + 953 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): + 954 newcontent.append(None) + 955 else: + 956 newcontent.append(self.content[t] + y.content[t]) + 957 return Corr(newcontent) + 958 + 959 elif isinstance(y, (Obs, int, float, CObs)): + 960 newcontent = [] + 961 for t in range(self.T): + 962 if _check_for_none(self, self.content[t]): + 963 newcontent.append(None) + 964 else: + 965 newcontent.append(self.content[t] + y) + 966 return Corr(newcontent, prange=self.prange) + 967 elif isinstance(y, np.ndarray): + 968 if y.shape == (self.T,): + 969 return Corr(list((np.array(self.content).T + y).T)) + 970 else: + 971 raise ValueError("operands could not be broadcast together") + 972 else: + 973 raise TypeError("Corr + wrong type") + 974 + 975 def __mul__(self, y): + 976 if isinstance(y, Corr): + 977 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): + 978 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") + 979 newcontent = [] + 980 for t in range(self.T): + 981 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): + 982 newcontent.append(None) + 983 else: + 984 newcontent.append(self.content[t] * y.content[t]) + 985 return Corr(newcontent) + 986 + 987 elif isinstance(y, (Obs, int, float, CObs)): + 988 newcontent = [] + 989 for t in range(self.T): + 990 if _check_for_none(self, self.content[t]): + 991 newcontent.append(None) + 992 else: + 993 newcontent.append(self.content[t] * y) + 994 return Corr(newcontent, prange=self.prange) + 995 elif isinstance(y, np.ndarray): + 996 if y.shape == (self.T,): + 997 return Corr(list((np.array(self.content).T * y).T)) + 998 else: + 999 raise ValueError("operands could not be broadcast together") +1000 else: +1001 raise TypeError("Corr * wrong type") +1002 +1003 def __truediv__(self, y): +1004 if isinstance(y, Corr): +1005 if not((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): +1006 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") +1007 newcontent = [] +1008 for t in range(self.T): +1009 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): +1010 newcontent.append(None) +1011 else: +1012 newcontent.append(self.content[t] / y.content[t]) +1013 for t in range(self.T): +1014 if _check_for_none(self, newcontent[t]): +1015 continue +1016 if np.isnan(np.sum(newcontent[t]).value): +1017 newcontent[t] = None 1018 -1019 elif isinstance(y, (Obs, CObs)): -1020 if isinstance(y, Obs): -1021 if y.value == 0: -1022 raise Exception('Division by zero will return undefined correlator') -1023 if isinstance(y, CObs): -1024 if y.is_zero(): -1025 raise Exception('Division by zero will return undefined correlator') -1026 -1027 newcontent = [] -1028 for t in range(self.T): -1029 if _check_for_none(self, self.content[t]): -1030 newcontent.append(None) -1031 else: -1032 newcontent.append(self.content[t] / y) -1033 return Corr(newcontent, prange=self.prange) -1034 -1035 elif isinstance(y, (int, float)): -1036 if y == 0: -1037 raise Exception('Division by zero will return undefined correlator') -1038 newcontent = [] -1039 for t in range(self.T): -1040 if _check_for_none(self, self.content[t]): -1041 newcontent.append(None) -1042 else: -1043 newcontent.append(self.content[t] / y) -1044 return Corr(newcontent, prange=self.prange) -1045 elif isinstance(y, np.ndarray): -1046 if y.shape == (self.T,): -1047 return Corr(list((np.array(self.content).T / y).T)) -1048 else: -1049 raise ValueError("operands could not be broadcast together") -1050 else: -1051 raise TypeError('Corr / wrong type') -1052 -1053 def __neg__(self): -1054 newcontent = [None if _check_for_none(self, item) else -1. * item for item in self.content] -1055 return Corr(newcontent, prange=self.prange) +1019 if all([item is None for item in newcontent]): +1020 raise Exception("Division returns completely undefined correlator") +1021 return Corr(newcontent) +1022 +1023 elif isinstance(y, (Obs, CObs)): +1024 if isinstance(y, Obs): +1025 if y.value == 0: +1026 raise Exception('Division by zero will return undefined correlator') +1027 if isinstance(y, CObs): +1028 if y.is_zero(): +1029 raise Exception('Division by zero will return undefined correlator') +1030 +1031 newcontent = [] +1032 for t in range(self.T): +1033 if _check_for_none(self, self.content[t]): +1034 newcontent.append(None) +1035 else: +1036 newcontent.append(self.content[t] / y) +1037 return Corr(newcontent, prange=self.prange) +1038 +1039 elif isinstance(y, (int, float)): +1040 if y == 0: +1041 raise Exception('Division by zero will return undefined correlator') +1042 newcontent = [] +1043 for t in range(self.T): +1044 if _check_for_none(self, self.content[t]): +1045 newcontent.append(None) +1046 else: +1047 newcontent.append(self.content[t] / y) +1048 return Corr(newcontent, prange=self.prange) +1049 elif isinstance(y, np.ndarray): +1050 if y.shape == (self.T,): +1051 return Corr(list((np.array(self.content).T / y).T)) +1052 else: +1053 raise ValueError("operands could not be broadcast together") +1054 else: +1055 raise TypeError('Corr / wrong type') 1056 -1057 def __sub__(self, y): -1058 return self + (-y) -1059 -1060 def __pow__(self, y): -1061 if isinstance(y, (Obs, int, float, CObs)): -1062 newcontent = [None if _check_for_none(self, item) else item**y for item in self.content] -1063 return Corr(newcontent, prange=self.prange) -1064 else: -1065 raise TypeError('Type of exponent not supported') -1066 -1067 def __abs__(self): -1068 newcontent = [None if _check_for_none(self, item) else np.abs(item) for item in self.content] -1069 return Corr(newcontent, prange=self.prange) +1057 def __neg__(self): +1058 newcontent = [None if _check_for_none(self, item) else -1. * item for item in self.content] +1059 return Corr(newcontent, prange=self.prange) +1060 +1061 def __sub__(self, y): +1062 return self + (-y) +1063 +1064 def __pow__(self, y): +1065 if isinstance(y, (Obs, int, float, CObs)): +1066 newcontent = [None if _check_for_none(self, item) else item**y for item in self.content] +1067 return Corr(newcontent, prange=self.prange) +1068 else: +1069 raise TypeError('Type of exponent not supported') 1070 -1071 # The numpy functions: -1072 def sqrt(self): -1073 return self ** 0.5 +1071 def __abs__(self): +1072 newcontent = [None if _check_for_none(self, item) else np.abs(item) for item in self.content] +1073 return Corr(newcontent, prange=self.prange) 1074 -1075 def log(self): -1076 newcontent = [None if _check_for_none(self, item) else np.log(item) for item in self.content] -1077 return Corr(newcontent, prange=self.prange) +1075 # The numpy functions: +1076 def sqrt(self): +1077 return self ** 0.5 1078 -1079 def exp(self): -1080 newcontent = [None if _check_for_none(self, item) else np.exp(item) for item in self.content] +1079 def log(self): +1080 newcontent = [None if _check_for_none(self, item) else np.log(item) for item in self.content] 1081 return Corr(newcontent, prange=self.prange) 1082 -1083 def _apply_func_to_corr(self, func): -1084 newcontent = [None if _check_for_none(self, item) else func(item) for item in self.content] -1085 for t in range(self.T): -1086 if _check_for_none(self, newcontent[t]): -1087 continue -1088 if np.isnan(np.sum(newcontent[t]).value): -1089 newcontent[t] = None -1090 if all([item is None for item in newcontent]): -1091 raise Exception('Operation returns undefined correlator') -1092 return Corr(newcontent) -1093 -1094 def sin(self): -1095 return self._apply_func_to_corr(np.sin) -1096 -1097 def cos(self): -1098 return self._apply_func_to_corr(np.cos) -1099 -1100 def tan(self): -1101 return self._apply_func_to_corr(np.tan) -1102 -1103 def sinh(self): -1104 return self._apply_func_to_corr(np.sinh) -1105 -1106 def cosh(self): -1107 return self._apply_func_to_corr(np.cosh) -1108 -1109 def tanh(self): -1110 return self._apply_func_to_corr(np.tanh) -1111 -1112 def arcsin(self): -1113 return self._apply_func_to_corr(np.arcsin) -1114 -1115 def arccos(self): -1116 return self._apply_func_to_corr(np.arccos) -1117 -1118 def arctan(self): -1119 return self._apply_func_to_corr(np.arctan) -1120 -1121 def arcsinh(self): -1122 return self._apply_func_to_corr(np.arcsinh) -1123 -1124 def arccosh(self): -1125 return self._apply_func_to_corr(np.arccosh) -1126 -1127 def arctanh(self): -1128 return self._apply_func_to_corr(np.arctanh) -1129 -1130 # Right hand side operations (require tweak in main module to work) -1131 def __radd__(self, y): -1132 return self + y +1083 def exp(self): +1084 newcontent = [None if _check_for_none(self, item) else np.exp(item) for item in self.content] +1085 return Corr(newcontent, prange=self.prange) +1086 +1087 def _apply_func_to_corr(self, func): +1088 newcontent = [None if _check_for_none(self, item) else func(item) for item in self.content] +1089 for t in range(self.T): +1090 if _check_for_none(self, newcontent[t]): +1091 continue +1092 if np.isnan(np.sum(newcontent[t]).value): +1093 newcontent[t] = None +1094 if all([item is None for item in newcontent]): +1095 raise Exception('Operation returns undefined correlator') +1096 return Corr(newcontent) +1097 +1098 def sin(self): +1099 return self._apply_func_to_corr(np.sin) +1100 +1101 def cos(self): +1102 return self._apply_func_to_corr(np.cos) +1103 +1104 def tan(self): +1105 return self._apply_func_to_corr(np.tan) +1106 +1107 def sinh(self): +1108 return self._apply_func_to_corr(np.sinh) +1109 +1110 def cosh(self): +1111 return self._apply_func_to_corr(np.cosh) +1112 +1113 def tanh(self): +1114 return self._apply_func_to_corr(np.tanh) +1115 +1116 def arcsin(self): +1117 return self._apply_func_to_corr(np.arcsin) +1118 +1119 def arccos(self): +1120 return self._apply_func_to_corr(np.arccos) +1121 +1122 def arctan(self): +1123 return self._apply_func_to_corr(np.arctan) +1124 +1125 def arcsinh(self): +1126 return self._apply_func_to_corr(np.arcsinh) +1127 +1128 def arccosh(self): +1129 return self._apply_func_to_corr(np.arccosh) +1130 +1131 def arctanh(self): +1132 return self._apply_func_to_corr(np.arctanh) 1133 -1134 def __rsub__(self, y): -1135 return -self + y -1136 -1137 def __rmul__(self, y): -1138 return self * y -1139 -1140 def __rtruediv__(self, y): -1141 return (self / y) ** (-1) -1142 -1143 @property -1144 def real(self): -1145 def return_real(obs_OR_cobs): -1146 if isinstance(obs_OR_cobs, CObs): -1147 return obs_OR_cobs.real -1148 else: -1149 return obs_OR_cobs -1150 -1151 return self._apply_func_to_corr(return_real) -1152 -1153 @property -1154 def imag(self): -1155 def return_imag(obs_OR_cobs): -1156 if isinstance(obs_OR_cobs, CObs): -1157 return obs_OR_cobs.imag -1158 else: -1159 return obs_OR_cobs * 0 # So it stays the right type -1160 -1161 return self._apply_func_to_corr(return_imag) -1162 -1163 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): -1164 r''' Project large correlation matrix to lowest states -1165 -1166 This method can be used to reduce the size of an (N x N) correlation matrix -1167 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise -1168 is still small. +1134 # Right hand side operations (require tweak in main module to work) +1135 def __radd__(self, y): +1136 return self + y +1137 +1138 def __rsub__(self, y): +1139 return -self + y +1140 +1141 def __rmul__(self, y): +1142 return self * y +1143 +1144 def __rtruediv__(self, y): +1145 return (self / y) ** (-1) +1146 +1147 @property +1148 def real(self): +1149 def return_real(obs_OR_cobs): +1150 if isinstance(obs_OR_cobs, CObs): +1151 return obs_OR_cobs.real +1152 else: +1153 return obs_OR_cobs +1154 +1155 return self._apply_func_to_corr(return_real) +1156 +1157 @property +1158 def imag(self): +1159 def return_imag(obs_OR_cobs): +1160 if isinstance(obs_OR_cobs, CObs): +1161 return obs_OR_cobs.imag +1162 else: +1163 return obs_OR_cobs * 0 # So it stays the right type +1164 +1165 return self._apply_func_to_corr(return_imag) +1166 +1167 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): +1168 r''' Project large correlation matrix to lowest states 1169 -1170 Parameters -1171 ---------- -1172 Ntrunc: int -1173 Rank of the target matrix. -1174 tproj: int -1175 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. -1176 The default value is 3. -1177 t0proj: int -1178 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly -1179 discouraged for O(a) improved theories, since the correctness of the procedure -1180 cannot be granted in this case. The default value is 2. -1181 basematrix : Corr -1182 Correlation matrix that is used to determine the eigenvectors of the -1183 lowest states based on a GEVP. basematrix is taken to be the Corr itself if -1184 is is not specified. -1185 -1186 Notes -1187 ----- -1188 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving -1189 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}$ -1190 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the -1191 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via -1192 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large -1193 correlation matrix and to remove some noise that is added by irrelevant operators. -1194 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated -1195 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. -1196 ''' -1197 -1198 if self.N == 1: -1199 raise Exception('Method cannot be applied to one-dimensional correlators.') -1200 if basematrix is None: -1201 basematrix = self -1202 if Ntrunc >= basematrix.N: -1203 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) -1204 if basematrix.N != self.N: -1205 raise Exception('basematrix and targetmatrix have to be of the same size.') -1206 -1207 evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc] -1208 -1209 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) -1210 rmat = [] -1211 for t in range(basematrix.T): -1212 for i in range(Ntrunc): -1213 for j in range(Ntrunc): -1214 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] -1215 rmat.append(np.copy(tmpmat)) -1216 -1217 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] -1218 return Corr(newcontent) +1170 This method can be used to reduce the size of an (N x N) correlation matrix +1171 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise +1172 is still small. +1173 +1174 Parameters +1175 ---------- +1176 Ntrunc: int +1177 Rank of the target matrix. +1178 tproj: int +1179 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. +1180 The default value is 3. +1181 t0proj: int +1182 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly +1183 discouraged for O(a) improved theories, since the correctness of the procedure +1184 cannot be granted in this case. The default value is 2. +1185 basematrix : Corr +1186 Correlation matrix that is used to determine the eigenvectors of the +1187 lowest states based on a GEVP. basematrix is taken to be the Corr itself if +1188 is is not specified. +1189 +1190 Notes +1191 ----- +1192 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving +1193 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}$ +1194 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the +1195 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via +1196 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large +1197 correlation matrix and to remove some noise that is added by irrelevant operators. +1198 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated +1199 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. +1200 ''' +1201 +1202 if self.N == 1: +1203 raise Exception('Method cannot be applied to one-dimensional correlators.') +1204 if basematrix is None: +1205 basematrix = self +1206 if Ntrunc >= basematrix.N: +1207 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) +1208 if basematrix.N != self.N: +1209 raise Exception('basematrix and targetmatrix have to be of the same size.') +1210 +1211 evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc] +1212 +1213 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) +1214 rmat = [] +1215 for t in range(basematrix.T): +1216 for i in range(Ntrunc): +1217 for j in range(Ntrunc): +1218 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] +1219 rmat.append(np.copy(tmpmat)) +1220 +1221 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] +1222 return Corr(newcontent) @@ -3775,49 +3783,53 @@ Available choice: symmetric, improved, default: symmetric 605 for t in range(self.T - 1): 606 if ((self.content[t] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0): 607 newcontent.append(None) -608 else: -609 newcontent.append(self.content[t] / self.content[t + 1]) -610 if(all([x is None for x in newcontent])): -611 raise Exception('m_eff is undefined at all timeslices') -612 -613 return np.log(Corr(newcontent, padding=[0, 1])) +608 elif self.content[t][0].value / self.content[t + 1][0].value < 0: +609 newcontent.append(None) +610 else: +611 newcontent.append(self.content[t] / self.content[t + 1]) +612 if(all([x is None for x in newcontent])): +613 raise Exception('m_eff is undefined at all timeslices') 614 -615 elif variant in ['periodic', 'cosh', 'sinh']: -616 if variant in ['periodic', 'cosh']: -617 func = anp.cosh -618 else: -619 func = anp.sinh -620 -621 def root_function(x, d): -622 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d -623 -624 newcontent = [] -625 for t in range(self.T - 1): -626 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0): -627 newcontent.append(None) -628 # Fill the two timeslices in the middle of the lattice with their predecessors -629 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: -630 newcontent.append(newcontent[-1]) -631 else: -632 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) -633 if(all([x is None for x in newcontent])): -634 raise Exception('m_eff is undefined at all timeslices') -635 -636 return Corr(newcontent, padding=[0, 1]) -637 -638 elif variant == 'arccosh': -639 newcontent = [] -640 for t in range(1, self.T - 1): -641 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None) or (self.content[t][0].value == 0): -642 newcontent.append(None) -643 else: -644 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) -645 if(all([x is None for x in newcontent])): -646 raise Exception("m_eff is undefined at all timeslices") -647 return np.arccosh(Corr(newcontent, padding=[1, 1])) -648 -649 else: -650 raise Exception('Unknown variant.') +615 return np.log(Corr(newcontent, padding=[0, 1])) +616 +617 elif variant in ['periodic', 'cosh', 'sinh']: +618 if variant in ['periodic', 'cosh']: +619 func = anp.cosh +620 else: +621 func = anp.sinh +622 +623 def root_function(x, d): +624 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d +625 +626 newcontent = [] +627 for t in range(self.T - 1): +628 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0): +629 newcontent.append(None) +630 # Fill the two timeslices in the middle of the lattice with their predecessors +631 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: +632 newcontent.append(newcontent[-1]) +633 elif self.content[t][0].value / self.content[t + 1][0].value < 0: +634 newcontent.append(None) +635 else: +636 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) +637 if(all([x is None for x in newcontent])): +638 raise Exception('m_eff is undefined at all timeslices') +639 +640 return Corr(newcontent, padding=[0, 1]) +641 +642 elif variant == 'arccosh': +643 newcontent = [] +644 for t in range(1, self.T - 1): +645 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t - 1] is None) or (self.content[t][0].value == 0): +646 newcontent.append(None) +647 else: +648 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) +649 if(all([x is None for x in newcontent])): +650 raise Exception("m_eff is undefined at all timeslices") +651 return np.arccosh(Corr(newcontent, padding=[1, 1])) +652 +653 else: +654 raise Exception('Unknown variant.') @@ -3850,39 +3862,39 @@ guess for the root finder, only relevant for the root variant -
652 def fit(self, function, fitrange=None, silent=False, **kwargs): -653 r'''Fits function to the data -654 -655 Parameters -656 ---------- -657 function : obj -658 function to fit to the data. See fits.least_squares for details. -659 fitrange : list -660 Two element list containing the timeslices on which the fit is supposed to start and stop. -661 Caution: This range is inclusive as opposed to standard python indexing. -662 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. -663 If not specified, self.prange or all timeslices are used. -664 silent : bool -665 Decides whether output is printed to the standard output. -666 ''' -667 if self.N != 1: -668 raise Exception("Correlator must be projected before fitting") -669 -670 if fitrange is None: -671 if self.prange: -672 fitrange = self.prange -673 else: -674 fitrange = [0, self.T - 1] -675 else: -676 if not isinstance(fitrange, list): -677 raise Exception("fitrange has to be a list with two elements") -678 if len(fitrange) != 2: -679 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") -680 -681 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] -682 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] -683 result = least_squares(xs, ys, function, silent=silent, **kwargs) -684 return result +@@ -3916,42 +3928,42 @@ Decides whether output is printed to the standard output.656 def fit(self, function, fitrange=None, silent=False, **kwargs): +657 r'''Fits function to the data +658 +659 Parameters +660 ---------- +661 function : obj +662 function to fit to the data. See fits.least_squares for details. +663 fitrange : list +664 Two element list containing the timeslices on which the fit is supposed to start and stop. +665 Caution: This range is inclusive as opposed to standard python indexing. +666 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. +667 If not specified, self.prange or all timeslices are used. +668 silent : bool +669 Decides whether output is printed to the standard output. +670 ''' +671 if self.N != 1: +672 raise Exception("Correlator must be projected before fitting") +673 +674 if fitrange is None: +675 if self.prange: +676 fitrange = self.prange +677 else: +678 fitrange = [0, self.T - 1] +679 else: +680 if not isinstance(fitrange, list): +681 raise Exception("fitrange has to be a list with two elements") +682 if len(fitrange) != 2: +683 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") +684 +685 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] +686 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] +687 result = least_squares(xs, ys, function, silent=silent, **kwargs) +688 return result
686 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): -687 """ Extract a plateau value from a Corr object -688 -689 Parameters -690 ---------- -691 plateau_range : list -692 list with two entries, indicating the first and the last timeslice -693 of the plateau region. -694 method : str -695 method to extract the plateau. -696 'fit' fits a constant to the plateau region -697 'avg', 'average' or 'mean' just average over the given timeslices. -698 auto_gamma : bool -699 apply gamma_method with default parameters to the Corr. Defaults to None -700 """ -701 if not plateau_range: -702 if self.prange: -703 plateau_range = self.prange -704 else: -705 raise Exception("no plateau range provided") -706 if self.N != 1: -707 raise Exception("Correlator must be projected before getting a plateau.") -708 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): -709 raise Exception("plateau is undefined at all timeslices in plateaurange.") -710 if auto_gamma: -711 self.gamma_method() -712 if method == "fit": -713 def const_func(a, t): -714 return a[0] -715 return self.fit(const_func, plateau_range)[0] -716 elif method in ["avg", "average", "mean"]: -717 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) -718 return returnvalue -719 -720 else: -721 raise Exception("Unsupported plateau method: " + method) +@@ -3985,17 +3997,17 @@ apply gamma_method with default parameters to the Corr. Defaults to None690 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): +691 """ Extract a plateau value from a Corr object +692 +693 Parameters +694 ---------- +695 plateau_range : list +696 list with two entries, indicating the first and the last timeslice +697 of the plateau region. +698 method : str +699 method to extract the plateau. +700 'fit' fits a constant to the plateau region +701 'avg', 'average' or 'mean' just average over the given timeslices. +702 auto_gamma : bool +703 apply gamma_method with default parameters to the Corr. Defaults to None +704 """ +705 if not plateau_range: +706 if self.prange: +707 plateau_range = self.prange +708 else: +709 raise Exception("no plateau range provided") +710 if self.N != 1: +711 raise Exception("Correlator must be projected before getting a plateau.") +712 if(all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): +713 raise Exception("plateau is undefined at all timeslices in plateaurange.") +714 if auto_gamma: +715 self.gamma_method() +716 if method == "fit": +717 def const_func(a, t): +718 return a[0] +719 return self.fit(const_func, plateau_range)[0] +720 elif method in ["avg", "average", "mean"]: +721 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) +722 return returnvalue +723 +724 else: +725 raise Exception("Unsupported plateau method: " + method)
723 def set_prange(self, prange): -724 """Sets the attribute prange of the Corr object.""" -725 if not len(prange) == 2: -726 raise Exception("prange must be a list or array with two values") -727 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): -728 raise Exception("Start and end point must be integers") -729 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): -730 raise Exception("Start and end point must define a range in the interval 0,T") -731 -732 self.prange = prange -733 return +@@ -4015,124 +4027,124 @@ apply gamma_method with default parameters to the Corr. Defaults to None727 def set_prange(self, prange): +728 """Sets the attribute prange of the Corr object.""" +729 if not len(prange) == 2: +730 raise Exception("prange must be a list or array with two values") +731 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): +732 raise Exception("Start and end point must be integers") +733 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): +734 raise Exception("Start and end point must define a range in the interval 0,T") +735 +736 self.prange = prange +737 return
735 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, title=None): -736 """Plots the correlator using the tag of the correlator as label if available. -737 -738 Parameters -739 ---------- -740 x_range : list -741 list of two values, determining the range of the x-axis e.g. [4, 8]. -742 comp : Corr or list of Corr -743 Correlator or list of correlators which are plotted for comparison. -744 The tags of these correlators are used as labels if available. -745 logscale : bool -746 Sets y-axis to logscale. -747 plateau : Obs -748 Plateau value to be visualized in the figure. -749 fit_res : Fit_result -750 Fit_result object to be visualized. -751 ylabel : str -752 Label for the y-axis. -753 save : str -754 path to file in which the figure should be saved. -755 auto_gamma : bool -756 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. -757 hide_sigma : float -758 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. -759 references : list -760 List of floating point values that are displayed as horizontal lines for reference. -761 title : string -762 Optional title of the figure. -763 """ -764 if self.N != 1: -765 raise Exception("Correlator must be projected before plotting") -766 -767 if auto_gamma: -768 self.gamma_method() -769 -770 if x_range is None: -771 x_range = [0, self.T - 1] -772 -773 fig = plt.figure() -774 ax1 = fig.add_subplot(111) -775 -776 x, y, y_err = self.plottable() -777 if hide_sigma: -778 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 -779 else: -780 hide_from = None -781 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) -782 if logscale: -783 ax1.set_yscale('log') -784 else: -785 if y_range is None: -786 try: -787 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)]) -788 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)]) -789 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) -790 except Exception: -791 pass -792 else: -793 ax1.set_ylim(y_range) -794 if comp: -795 if isinstance(comp, (Corr, list)): -796 for corr in comp if isinstance(comp, list) else [comp]: -797 if auto_gamma: -798 corr.gamma_method() -799 x, y, y_err = corr.plottable() -800 if hide_sigma: -801 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 -802 else: -803 hide_from = None -804 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) -805 else: -806 raise Exception("'comp' must be a correlator or a list of correlators.") -807 -808 if plateau: -809 if isinstance(plateau, Obs): -810 if auto_gamma: -811 plateau.gamma_method() -812 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) -813 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') -814 else: -815 raise Exception("'plateau' must be an Obs") -816 -817 if references: -818 if isinstance(references, list): -819 for ref in references: -820 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') -821 else: -822 raise Exception("'references' must be a list of floating pint values.") -823 -824 if self.prange: -825 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') -826 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') +@@ -4180,34 +4192,34 @@ Optional title of the figure.739 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, title=None): +740 """Plots the correlator using the tag of the correlator as label if available. +741 +742 Parameters +743 ---------- +744 x_range : list +745 list of two values, determining the range of the x-axis e.g. [4, 8]. +746 comp : Corr or list of Corr +747 Correlator or list of correlators which are plotted for comparison. +748 The tags of these correlators are used as labels if available. +749 logscale : bool +750 Sets y-axis to logscale. +751 plateau : Obs +752 Plateau value to be visualized in the figure. +753 fit_res : Fit_result +754 Fit_result object to be visualized. +755 ylabel : str +756 Label for the y-axis. +757 save : str +758 path to file in which the figure should be saved. +759 auto_gamma : bool +760 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. +761 hide_sigma : float +762 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. +763 references : list +764 List of floating point values that are displayed as horizontal lines for reference. +765 title : string +766 Optional title of the figure. +767 """ +768 if self.N != 1: +769 raise Exception("Correlator must be projected before plotting") +770 +771 if auto_gamma: +772 self.gamma_method() +773 +774 if x_range is None: +775 x_range = [0, self.T - 1] +776 +777 fig = plt.figure() +778 ax1 = fig.add_subplot(111) +779 +780 x, y, y_err = self.plottable() +781 if hide_sigma: +782 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 +783 else: +784 hide_from = None +785 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) +786 if logscale: +787 ax1.set_yscale('log') +788 else: +789 if y_range is None: +790 try: +791 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)]) +792 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)]) +793 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) +794 except Exception: +795 pass +796 else: +797 ax1.set_ylim(y_range) +798 if comp: +799 if isinstance(comp, (Corr, list)): +800 for corr in comp if isinstance(comp, list) else [comp]: +801 if auto_gamma: +802 corr.gamma_method() +803 x, y, y_err = corr.plottable() +804 if hide_sigma: +805 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 +806 else: +807 hide_from = None +808 plt.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) +809 else: +810 raise Exception("'comp' must be a correlator or a list of correlators.") +811 +812 if plateau: +813 if isinstance(plateau, Obs): +814 if auto_gamma: +815 plateau.gamma_method() +816 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) +817 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') +818 else: +819 raise Exception("'plateau' must be an Obs") +820 +821 if references: +822 if isinstance(references, list): +823 for ref in references: +824 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') +825 else: +826 raise Exception("'references' must be a list of floating pint values.") 827 -828 if fit_res: -829 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) -830 ax1.plot(x_samples, -831 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), -832 ls='-', marker=',', lw=2) -833 -834 ax1.set_xlabel(r'$x_0 / a$') -835 if ylabel: -836 ax1.set_ylabel(ylabel) -837 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) -838 -839 handles, labels = ax1.get_legend_handles_labels() -840 if labels: -841 ax1.legend() +828 if self.prange: +829 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') +830 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') +831 +832 if fit_res: +833 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) +834 ax1.plot(x_samples, +835 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), +836 ls='-', marker=',', lw=2) +837 +838 ax1.set_xlabel(r'$x_0 / a$') +839 if ylabel: +840 ax1.set_ylabel(ylabel) +841 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) 842 -843 if title: -844 plt.title(title) -845 -846 plt.draw() -847 -848 if save: -849 if isinstance(save, str): -850 fig.savefig(save, bbox_inches='tight') -851 else: -852 raise Exception("'save' has to be a string.") +843 handles, labels = ax1.get_legend_handles_labels() +844 if labels: +845 ax1.legend() +846 +847 if title: +848 plt.title(title) +849 +850 plt.draw() +851 +852 if save: +853 if isinstance(save, str): +854 fig.savefig(save, bbox_inches='tight') +855 else: +856 raise Exception("'save' has to be a string.")
854 def spaghetti_plot(self, logscale=True): -855 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. -856 -857 Parameters -858 ---------- -859 logscale : bool -860 Determines whether the scale of the y-axis is logarithmic or standard. -861 """ -862 if self.N != 1: -863 raise Exception("Correlator needs to be projected first.") -864 -865 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])) -866 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] -867 -868 for name in mc_names: -869 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T -870 -871 fig = plt.figure() -872 ax = fig.add_subplot(111) -873 for dat in data: -874 ax.plot(x0_vals, dat, ls='-', marker='') -875 -876 if logscale is True: -877 ax.set_yscale('log') -878 -879 ax.set_xlabel(r'$x_0 / a$') -880 plt.title(name) -881 plt.draw() +@@ -4234,29 +4246,29 @@ Determines whether the scale of the y-axis is logarithmic or standard.858 def spaghetti_plot(self, logscale=True): +859 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. +860 +861 Parameters +862 ---------- +863 logscale : bool +864 Determines whether the scale of the y-axis is logarithmic or standard. +865 """ +866 if self.N != 1: +867 raise Exception("Correlator needs to be projected first.") +868 +869 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])) +870 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] +871 +872 for name in mc_names: +873 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T +874 +875 fig = plt.figure() +876 ax = fig.add_subplot(111) +877 for dat in data: +878 ax.plot(x0_vals, dat, ls='-', marker='') +879 +880 if logscale is True: +881 ax.set_yscale('log') +882 +883 ax.set_xlabel(r'$x_0 / a$') +884 plt.title(name) +885 plt.draw()
883 def dump(self, filename, datatype="json.gz", **kwargs): -884 """Dumps the Corr into a file of chosen type -885 Parameters -886 ---------- -887 filename : str -888 Name of the file to be saved. -889 datatype : str -890 Format of the exported file. Supported formats include -891 "json.gz" and "pickle" -892 path : str -893 specifies a custom path for the file (default '.') -894 """ -895 if datatype == "json.gz": -896 from .input.json import dump_to_json -897 if 'path' in kwargs: -898 file_name = kwargs.get('path') + '/' + filename -899 else: -900 file_name = filename -901 dump_to_json(self, file_name) -902 elif datatype == "pickle": -903 dump_object(self, filename, **kwargs) -904 else: -905 raise Exception("Unknown datatype " + str(datatype)) +@@ -4288,8 +4300,8 @@ specifies a custom path for the file (default '.')887 def dump(self, filename, datatype="json.gz", **kwargs): +888 """Dumps the Corr into a file of chosen type +889 Parameters +890 ---------- +891 filename : str +892 Name of the file to be saved. +893 datatype : str +894 Format of the exported file. Supported formats include +895 "json.gz" and "pickle" +896 path : str +897 specifies a custom path for the file (default '.') +898 """ +899 if datatype == "json.gz": +900 from .input.json import dump_to_json +901 if 'path' in kwargs: +902 file_name = kwargs.get('path') + '/' + filename +903 else: +904 file_name = filename +905 dump_to_json(self, file_name) +906 elif datatype == "pickle": +907 dump_object(self, filename, **kwargs) +908 else: +909 raise Exception("Unknown datatype " + str(datatype))
907 def print(self, print_range=None): -908 print(self.__repr__(print_range)) + @@ -4307,8 +4319,8 @@ specifies a custom path for the file (default '.')
1072 def sqrt(self): -1073 return self ** 0.5 + @@ -4326,9 +4338,9 @@ specifies a custom path for the file (default '.')
1075 def log(self): -1076 newcontent = [None if _check_for_none(self, item) else np.log(item) for item in self.content] -1077 return Corr(newcontent, prange=self.prange) + @@ -4346,9 +4358,9 @@ specifies a custom path for the file (default '.')
1079 def exp(self): -1080 newcontent = [None if _check_for_none(self, item) else np.exp(item) for item in self.content] -1081 return Corr(newcontent, prange=self.prange) + @@ -4366,8 +4378,8 @@ specifies a custom path for the file (default '.')
1094 def sin(self): -1095 return self._apply_func_to_corr(np.sin) + @@ -4385,8 +4397,8 @@ specifies a custom path for the file (default '.')
1097 def cos(self): -1098 return self._apply_func_to_corr(np.cos) + @@ -4404,8 +4416,8 @@ specifies a custom path for the file (default '.')
1100 def tan(self): -1101 return self._apply_func_to_corr(np.tan) + @@ -4423,8 +4435,8 @@ specifies a custom path for the file (default '.')
1103 def sinh(self): -1104 return self._apply_func_to_corr(np.sinh) + @@ -4442,8 +4454,8 @@ specifies a custom path for the file (default '.')
1106 def cosh(self): -1107 return self._apply_func_to_corr(np.cosh) + @@ -4461,8 +4473,8 @@ specifies a custom path for the file (default '.')
1109 def tanh(self): -1110 return self._apply_func_to_corr(np.tanh) + @@ -4480,8 +4492,8 @@ specifies a custom path for the file (default '.')
1112 def arcsin(self): -1113 return self._apply_func_to_corr(np.arcsin) + @@ -4499,8 +4511,8 @@ specifies a custom path for the file (default '.')
1115 def arccos(self): -1116 return self._apply_func_to_corr(np.arccos) + @@ -4518,8 +4530,8 @@ specifies a custom path for the file (default '.')
1118 def arctan(self): -1119 return self._apply_func_to_corr(np.arctan) + @@ -4537,8 +4549,8 @@ specifies a custom path for the file (default '.')
1121 def arcsinh(self): -1122 return self._apply_func_to_corr(np.arcsinh) + @@ -4556,8 +4568,8 @@ specifies a custom path for the file (default '.')
1124 def arccosh(self): -1125 return self._apply_func_to_corr(np.arccosh) + @@ -4575,8 +4587,8 @@ specifies a custom path for the file (default '.')
1127 def arctanh(self): -1128 return self._apply_func_to_corr(np.arctanh) + @@ -4616,62 +4628,62 @@ specifies a custom path for the file (default '.')
1163 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): -1164 r''' Project large correlation matrix to lowest states -1165 -1166 This method can be used to reduce the size of an (N x N) correlation matrix -1167 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise -1168 is still small. +1167 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): +1168 r''' Project large correlation matrix to lowest states 1169 -1170 Parameters -1171 ---------- -1172 Ntrunc: int -1173 Rank of the target matrix. -1174 tproj: int -1175 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. -1176 The default value is 3. -1177 t0proj: int -1178 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly -1179 discouraged for O(a) improved theories, since the correctness of the procedure -1180 cannot be granted in this case. The default value is 2. -1181 basematrix : Corr -1182 Correlation matrix that is used to determine the eigenvectors of the -1183 lowest states based on a GEVP. basematrix is taken to be the Corr itself if -1184 is is not specified. -1185 -1186 Notes -1187 ----- -1188 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving -1189 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}$ -1190 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the -1191 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via -1192 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large -1193 correlation matrix and to remove some noise that is added by irrelevant operators. -1194 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated -1195 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. -1196 ''' -1197 -1198 if self.N == 1: -1199 raise Exception('Method cannot be applied to one-dimensional correlators.') -1200 if basematrix is None: -1201 basematrix = self -1202 if Ntrunc >= basematrix.N: -1203 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) -1204 if basematrix.N != self.N: -1205 raise Exception('basematrix and targetmatrix have to be of the same size.') -1206 -1207 evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc] -1208 -1209 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) -1210 rmat = [] -1211 for t in range(basematrix.T): -1212 for i in range(Ntrunc): -1213 for j in range(Ntrunc): -1214 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] -1215 rmat.append(np.copy(tmpmat)) -1216 -1217 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] -1218 return Corr(newcontent) +1170 This method can be used to reduce the size of an (N x N) correlation matrix +1171 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise +1172 is still small. +1173 +1174 Parameters +1175 ---------- +1176 Ntrunc: int +1177 Rank of the target matrix. +1178 tproj: int +1179 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. +1180 The default value is 3. +1181 t0proj: int +1182 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly +1183 discouraged for O(a) improved theories, since the correctness of the procedure +1184 cannot be granted in this case. The default value is 2. +1185 basematrix : Corr +1186 Correlation matrix that is used to determine the eigenvectors of the +1187 lowest states based on a GEVP. basematrix is taken to be the Corr itself if +1188 is is not specified. +1189 +1190 Notes +1191 ----- +1192 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving +1193 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}$ +1194 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the +1195 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via +1196 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large +1197 correlation matrix and to remove some noise that is added by irrelevant operators. +1198 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated +1199 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. +1200 ''' +1201 +1202 if self.N == 1: +1203 raise Exception('Method cannot be applied to one-dimensional correlators.') +1204 if basematrix is None: +1205 basematrix = self +1206 if Ntrunc >= basematrix.N: +1207 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) +1208 if basematrix.N != self.N: +1209 raise Exception('basematrix and targetmatrix have to be of the same size.') +1210 +1211 evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc] +1212 +1213 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) +1214 rmat = [] +1215 for t in range(basematrix.T): +1216 for i in range(Ntrunc): +1217 for j in range(Ntrunc): +1218 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] +1219 rmat.append(np.copy(tmpmat)) +1220 +1221 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] +1222 return Corr(newcontent)