From fea6debdaf127764e614795ff47616e29ac24444 Mon Sep 17 00:00:00 2001 From: fjosw Date: Tue, 20 Dec 2022 16:11:23 +0000 Subject: [PATCH] Documentation updated --- docs/pyerrors/correlators.html | 6499 ++++++++++++++++---------------- 1 file changed, 3245 insertions(+), 3254 deletions(-) diff --git a/docs/pyerrors/correlators.html b/docs/pyerrors/correlators.html index a02c18ba..f4a2c4c3 100644 --- a/docs/pyerrors/correlators.html +++ b/docs/pyerrors/correlators.html @@ -282,1248 +282,1245 @@ 69 70 if isinstance(data_input, list): 71 - 72 if all([isinstance(item, (Obs, CObs)) for item in data_input]): - 73 _assert_equal_properties(data_input) - 74 self.content = [np.asarray([item]) for item in data_input] - 75 if all([isinstance(item, (Obs, CObs)) or item is None for item in data_input]): - 76 _assert_equal_properties([o for o in data_input if o is not None]) - 77 self.content = [np.asarray([item]) if item is not None else None for item in data_input] - 78 self.N = 1 - 79 - 80 elif all([isinstance(item, np.ndarray) or item is None for item in data_input]) and any([isinstance(item, np.ndarray) for item in data_input]): - 81 self.content = data_input - 82 noNull = [a for a in self.content if not (a is None)] # To check if the matrices are correct for all undefined elements - 83 self.N = noNull[0].shape[0] - 84 if self.N > 1 and noNull[0].shape[0] != noNull[0].shape[1]: - 85 raise Exception("Smearing matrices are not NxN") - 86 if (not all([item.shape == noNull[0].shape for item in noNull])): - 87 raise Exception("Items in data_input are not of identical shape." + str(noNull)) - 88 else: - 89 raise Exception("data_input contains item of wrong type") - 90 else: - 91 raise Exception("Data input was not given as list or correct array") - 92 - 93 self.tag = None - 94 - 95 # An undefined timeslice is represented by the None object - 96 self.content = [None] * padding[0] + self.content + [None] * padding[1] - 97 self.T = len(self.content) - 98 self.prange = prange - 99 - 100 def __getitem__(self, idx): - 101 """Return the content of timeslice idx""" - 102 if self.content[idx] is None: - 103 return None - 104 elif len(self.content[idx]) == 1: - 105 return self.content[idx][0] - 106 else: - 107 return self.content[idx] - 108 - 109 @property - 110 def reweighted(self): - 111 bool_array = np.array([list(map(lambda x: x.reweighted, o)) for o in [x for x in self.content if x is not None]]) - 112 if np.all(bool_array == 1): - 113 return True - 114 elif np.all(bool_array == 0): - 115 return False - 116 else: - 117 raise Exception("Reweighting status of correlator corrupted.") - 118 - 119 def gamma_method(self, **kwargs): - 120 """Apply the gamma method to the content of the Corr.""" - 121 for item in self.content: - 122 if not (item is None): - 123 if self.N == 1: - 124 item[0].gamma_method(**kwargs) - 125 else: - 126 for i in range(self.N): - 127 for j in range(self.N): - 128 item[i, j].gamma_method(**kwargs) + 72 if all([isinstance(item, (Obs, CObs)) or item is None for item in data_input]): + 73 _assert_equal_properties([o for o in data_input if o is not None]) + 74 self.content = [np.asarray([item]) if item is not None else None for item in data_input] + 75 self.N = 1 + 76 + 77 elif all([isinstance(item, np.ndarray) or item is None for item in data_input]) and any([isinstance(item, np.ndarray) for item in data_input]): + 78 self.content = data_input + 79 noNull = [a for a in self.content if not (a is None)] # To check if the matrices are correct for all undefined elements + 80 self.N = noNull[0].shape[0] + 81 if self.N > 1 and noNull[0].shape[0] != noNull[0].shape[1]: + 82 raise Exception("Smearing matrices are not NxN") + 83 if (not all([item.shape == noNull[0].shape for item in noNull])): + 84 raise Exception("Items in data_input are not of identical shape." + str(noNull)) + 85 else: + 86 raise Exception("data_input contains item of wrong type") + 87 else: + 88 raise Exception("Data input was not given as list or correct array") + 89 + 90 self.tag = None + 91 + 92 # An undefined timeslice is represented by the None object + 93 self.content = [None] * padding[0] + self.content + [None] * padding[1] + 94 self.T = len(self.content) + 95 self.prange = prange + 96 + 97 def __getitem__(self, idx): + 98 """Return the content of timeslice idx""" + 99 if self.content[idx] is None: + 100 return None + 101 elif len(self.content[idx]) == 1: + 102 return self.content[idx][0] + 103 else: + 104 return self.content[idx] + 105 + 106 @property + 107 def reweighted(self): + 108 bool_array = np.array([list(map(lambda x: x.reweighted, o)) for o in [x for x in self.content if x is not None]]) + 109 if np.all(bool_array == 1): + 110 return True + 111 elif np.all(bool_array == 0): + 112 return False + 113 else: + 114 raise Exception("Reweighting status of correlator corrupted.") + 115 + 116 def gamma_method(self, **kwargs): + 117 """Apply the gamma method to the content of the Corr.""" + 118 for item in self.content: + 119 if not (item is None): + 120 if self.N == 1: + 121 item[0].gamma_method(**kwargs) + 122 else: + 123 for i in range(self.N): + 124 for j in range(self.N): + 125 item[i, j].gamma_method(**kwargs) + 126 + 127 def projected(self, vector_l=None, vector_r=None, normalize=False): + 128 """We need to project the Correlator with a Vector to get a single value at each timeslice. 129 - 130 def projected(self, vector_l=None, vector_r=None, normalize=False): - 131 """We need to project the Correlator with a Vector to get a single value at each timeslice. - 132 - 133 The method can use one or two vectors. - 134 If two are specified it returns v1@G@v2 (the order might be very important.) - 135 By default it will return the lowest source, which usually means unsmeared-unsmeared (0,0), but it does not have to - 136 """ - 137 if self.N == 1: - 138 raise Exception("Trying to project a Corr, that already has N=1.") - 139 - 140 if vector_l is None: - 141 vector_l, vector_r = np.asarray([1.] + (self.N - 1) * [0.]), np.asarray([1.] + (self.N - 1) * [0.]) - 142 elif (vector_r is None): - 143 vector_r = vector_l - 144 if isinstance(vector_l, list) and not isinstance(vector_r, list): - 145 if len(vector_l) != self.T: - 146 raise Exception("Length of vector list must be equal to T") - 147 vector_r = [vector_r] * self.T - 148 if isinstance(vector_r, list) and not isinstance(vector_l, list): - 149 if len(vector_r) != self.T: - 150 raise Exception("Length of vector list must be equal to T") - 151 vector_l = [vector_l] * self.T - 152 - 153 if not isinstance(vector_l, list): - 154 if not vector_l.shape == vector_r.shape == (self.N,): - 155 raise Exception("Vectors are of wrong shape!") - 156 if normalize: - 157 vector_l, vector_r = vector_l / np.sqrt((vector_l @ vector_l)), vector_r / np.sqrt(vector_r @ vector_r) - 158 newcontent = [None if _check_for_none(self, item) else np.asarray([vector_l.T @ item @ vector_r]) for item in self.content] - 159 - 160 else: - 161 # There are no checks here yet. There are so many possible scenarios, where this can go wrong. - 162 if normalize: - 163 for t in range(self.T): - 164 vector_l[t], vector_r[t] = vector_l[t] / np.sqrt((vector_l[t] @ vector_l[t])), vector_r[t] / np.sqrt(vector_r[t] @ vector_r[t]) + 130 The method can use one or two vectors. + 131 If two are specified it returns v1@G@v2 (the order might be very important.) + 132 By default it will return the lowest source, which usually means unsmeared-unsmeared (0,0), but it does not have to + 133 """ + 134 if self.N == 1: + 135 raise Exception("Trying to project a Corr, that already has N=1.") + 136 + 137 if vector_l is None: + 138 vector_l, vector_r = np.asarray([1.] + (self.N - 1) * [0.]), np.asarray([1.] + (self.N - 1) * [0.]) + 139 elif (vector_r is None): + 140 vector_r = vector_l + 141 if isinstance(vector_l, list) and not isinstance(vector_r, list): + 142 if len(vector_l) != self.T: + 143 raise Exception("Length of vector list must be equal to T") + 144 vector_r = [vector_r] * self.T + 145 if isinstance(vector_r, list) and not isinstance(vector_l, list): + 146 if len(vector_r) != self.T: + 147 raise Exception("Length of vector list must be equal to T") + 148 vector_l = [vector_l] * self.T + 149 + 150 if not isinstance(vector_l, list): + 151 if not vector_l.shape == vector_r.shape == (self.N,): + 152 raise Exception("Vectors are of wrong shape!") + 153 if normalize: + 154 vector_l, vector_r = vector_l / np.sqrt((vector_l @ vector_l)), vector_r / np.sqrt(vector_r @ vector_r) + 155 newcontent = [None if _check_for_none(self, item) else np.asarray([vector_l.T @ item @ vector_r]) for item in self.content] + 156 + 157 else: + 158 # There are no checks here yet. There are so many possible scenarios, where this can go wrong. + 159 if normalize: + 160 for t in range(self.T): + 161 vector_l[t], vector_r[t] = vector_l[t] / np.sqrt((vector_l[t] @ vector_l[t])), vector_r[t] / np.sqrt(vector_r[t] @ vector_r[t]) + 162 + 163 newcontent = [None if (_check_for_none(self, self.content[t]) or vector_l[t] is None or vector_r[t] is None) else np.asarray([vector_l[t].T @ self.content[t] @ vector_r[t]]) for t in range(self.T)] + 164 return Corr(newcontent) 165 - 166 newcontent = [None if (_check_for_none(self, self.content[t]) or vector_l[t] is None or vector_r[t] is None) else np.asarray([vector_l[t].T @ self.content[t] @ vector_r[t]]) for t in range(self.T)] - 167 return Corr(newcontent) + 166 def item(self, i, j): + 167 """Picks the element [i,j] from every matrix and returns a correlator containing one Obs per timeslice. 168 - 169 def item(self, i, j): - 170 """Picks the element [i,j] from every matrix and returns a correlator containing one Obs per timeslice. - 171 - 172 Parameters - 173 ---------- - 174 i : int - 175 First index to be picked. - 176 j : int - 177 Second index to be picked. - 178 """ - 179 if self.N == 1: - 180 raise Exception("Trying to pick item from projected Corr") - 181 newcontent = [None if (item is None) else item[i, j] for item in self.content] - 182 return Corr(newcontent) + 169 Parameters + 170 ---------- + 171 i : int + 172 First index to be picked. + 173 j : int + 174 Second index to be picked. + 175 """ + 176 if self.N == 1: + 177 raise Exception("Trying to pick item from projected Corr") + 178 newcontent = [None if (item is None) else item[i, j] for item in self.content] + 179 return Corr(newcontent) + 180 + 181 def plottable(self): + 182 """Outputs the correlator in a plotable format. 183 - 184 def plottable(self): - 185 """Outputs the correlator in a plotable format. - 186 - 187 Outputs three lists containing the timeslice index, the value on each - 188 timeslice and the error on each timeslice. - 189 """ - 190 if self.N != 1: - 191 raise Exception("Can only make Corr[N=1] plottable") - 192 x_list = [x for x in range(self.T) if not self.content[x] is None] - 193 y_list = [y[0].value for y in self.content if y is not None] - 194 y_err_list = [y[0].dvalue for y in self.content if y is not None] - 195 - 196 return x_list, y_list, y_err_list - 197 - 198 def symmetric(self): - 199 """ Symmetrize the correlator around x0=0.""" - 200 if self.N != 1: - 201 raise Exception('symmetric cannot be safely applied to multi-dimensional correlators.') - 202 if self.T % 2 != 0: - 203 raise Exception("Can not symmetrize odd T") + 184 Outputs three lists containing the timeslice index, the value on each + 185 timeslice and the error on each timeslice. + 186 """ + 187 if self.N != 1: + 188 raise Exception("Can only make Corr[N=1] plottable") + 189 x_list = [x for x in range(self.T) if not self.content[x] is None] + 190 y_list = [y[0].value for y in self.content if y is not None] + 191 y_err_list = [y[0].dvalue for y in self.content if y is not None] + 192 + 193 return x_list, y_list, y_err_list + 194 + 195 def symmetric(self): + 196 """ Symmetrize the correlator around x0=0.""" + 197 if self.N != 1: + 198 raise Exception('symmetric cannot be safely applied to multi-dimensional correlators.') + 199 if self.T % 2 != 0: + 200 raise Exception("Can not symmetrize odd T") + 201 + 202 if np.argmax(np.abs(self.content)) != 0: + 203 warnings.warn("Correlator does not seem to be symmetric around x0=0.", RuntimeWarning) 204 - 205 if np.argmax(np.abs(self.content)) != 0: - 206 warnings.warn("Correlator does not seem to be symmetric around x0=0.", RuntimeWarning) - 207 - 208 newcontent = [self.content[0]] - 209 for t in range(1, self.T): - 210 if (self.content[t] is None) or (self.content[self.T - t] is None): - 211 newcontent.append(None) - 212 else: - 213 newcontent.append(0.5 * (self.content[t] + self.content[self.T - t])) - 214 if (all([x is None for x in newcontent])): - 215 raise Exception("Corr could not be symmetrized: No redundant values") - 216 return Corr(newcontent, prange=self.prange) - 217 - 218 def anti_symmetric(self): - 219 """Anti-symmetrize the correlator around x0=0.""" - 220 if self.N != 1: - 221 raise Exception('anti_symmetric cannot be safely applied to multi-dimensional correlators.') - 222 if self.T % 2 != 0: - 223 raise Exception("Can not symmetrize odd T") - 224 - 225 test = 1 * self - 226 test.gamma_method() - 227 if not all([o.is_zero_within_error(3) for o in test.content[0]]): - 228 warnings.warn("Correlator does not seem to be anti-symmetric around x0=0.", RuntimeWarning) - 229 - 230 newcontent = [self.content[0]] - 231 for t in range(1, self.T): - 232 if (self.content[t] is None) or (self.content[self.T - t] is None): - 233 newcontent.append(None) - 234 else: - 235 newcontent.append(0.5 * (self.content[t] - self.content[self.T - t])) - 236 if (all([x is None for x in newcontent])): - 237 raise Exception("Corr could not be symmetrized: No redundant values") - 238 return Corr(newcontent, prange=self.prange) - 239 - 240 def is_matrix_symmetric(self): - 241 """Checks whether a correlator matrices is symmetric on every timeslice.""" - 242 if self.N == 1: - 243 raise Exception("Only works for correlator matrices.") - 244 for t in range(self.T): - 245 if self[t] is None: - 246 continue - 247 for i in range(self.N): - 248 for j in range(i + 1, self.N): - 249 if self[t][i, j] is self[t][j, i]: - 250 continue - 251 if hash(self[t][i, j]) != hash(self[t][j, i]): - 252 return False - 253 return True - 254 - 255 def matrix_symmetric(self): - 256 """Symmetrizes the correlator matrices on every timeslice.""" - 257 if self.N == 1: - 258 raise Exception("Trying to symmetrize a correlator matrix, that already has N=1.") - 259 if self.is_matrix_symmetric(): - 260 return 1.0 * self - 261 else: - 262 transposed = [None if _check_for_none(self, G) else G.T for G in self.content] - 263 return 0.5 * (Corr(transposed) + self) + 205 newcontent = [self.content[0]] + 206 for t in range(1, self.T): + 207 if (self.content[t] is None) or (self.content[self.T - t] is None): + 208 newcontent.append(None) + 209 else: + 210 newcontent.append(0.5 * (self.content[t] + self.content[self.T - t])) + 211 if (all([x is None for x in newcontent])): + 212 raise Exception("Corr could not be symmetrized: No redundant values") + 213 return Corr(newcontent, prange=self.prange) + 214 + 215 def anti_symmetric(self): + 216 """Anti-symmetrize the correlator around x0=0.""" + 217 if self.N != 1: + 218 raise Exception('anti_symmetric cannot be safely applied to multi-dimensional correlators.') + 219 if self.T % 2 != 0: + 220 raise Exception("Can not symmetrize odd T") + 221 + 222 test = 1 * self + 223 test.gamma_method() + 224 if not all([o.is_zero_within_error(3) for o in test.content[0]]): + 225 warnings.warn("Correlator does not seem to be anti-symmetric around x0=0.", RuntimeWarning) + 226 + 227 newcontent = [self.content[0]] + 228 for t in range(1, self.T): + 229 if (self.content[t] is None) or (self.content[self.T - t] is None): + 230 newcontent.append(None) + 231 else: + 232 newcontent.append(0.5 * (self.content[t] - self.content[self.T - t])) + 233 if (all([x is None for x in newcontent])): + 234 raise Exception("Corr could not be symmetrized: No redundant values") + 235 return Corr(newcontent, prange=self.prange) + 236 + 237 def is_matrix_symmetric(self): + 238 """Checks whether a correlator matrices is symmetric on every timeslice.""" + 239 if self.N == 1: + 240 raise Exception("Only works for correlator matrices.") + 241 for t in range(self.T): + 242 if self[t] is None: + 243 continue + 244 for i in range(self.N): + 245 for j in range(i + 1, self.N): + 246 if self[t][i, j] is self[t][j, i]: + 247 continue + 248 if hash(self[t][i, j]) != hash(self[t][j, i]): + 249 return False + 250 return True + 251 + 252 def matrix_symmetric(self): + 253 """Symmetrizes the correlator matrices on every timeslice.""" + 254 if self.N == 1: + 255 raise Exception("Trying to symmetrize a correlator matrix, that already has N=1.") + 256 if self.is_matrix_symmetric(): + 257 return 1.0 * self + 258 else: + 259 transposed = [None if _check_for_none(self, G) else G.T for G in self.content] + 260 return 0.5 * (Corr(transposed) + self) + 261 + 262 def GEVP(self, t0, ts=None, sort="Eigenvalue", **kwargs): + 263 r'''Solve the generalized eigenvalue problem on the correlator matrix and returns the corresponding eigenvectors. 264 - 265 def GEVP(self, t0, ts=None, sort="Eigenvalue", **kwargs): - 266 r'''Solve the generalized eigenvalue problem on the correlator matrix and returns the corresponding eigenvectors. - 267 - 268 The eigenvectors are sorted according to the descending eigenvalues, the zeroth eigenvector(s) correspond to the - 269 largest eigenvalue(s). The eigenvector(s) for the individual states can be accessed via slicing - 270 ```python - 271 C.GEVP(t0=2)[0] # Ground state vector(s) - 272 C.GEVP(t0=2)[:3] # Vectors for the lowest three states - 273 ``` - 274 - 275 Parameters - 276 ---------- - 277 t0 : int - 278 The time t0 for the right hand side of the GEVP according to $G(t)v_i=\lambda_i G(t_0)v_i$ - 279 ts : int - 280 fixed time $G(t_s)v_i=\lambda_i G(t_0)v_i$ if sort=None. - 281 If sort="Eigenvector" it gives a reference point for the sorting method. - 282 sort : string - 283 If this argument is set, a list of self.T vectors per state is returned. If it is set to None, only one vector is returned. - 284 - "Eigenvalue": The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice. - 285 - "Eigenvector": Use the method described in arXiv:2004.10472 to find the set of v(t) belonging to the state. - 286 The reference state is identified by its eigenvalue at $t=t_s$. - 287 - 288 Other Parameters - 289 ---------------- - 290 state : int - 291 Returns only the vector(s) for a specified state. The lowest state is zero. - 292 ''' - 293 - 294 if self.N == 1: - 295 raise Exception("GEVP methods only works on correlator matrices and not single correlators.") - 296 if ts is not None: - 297 if (ts <= t0): - 298 raise Exception("ts has to be larger than t0.") - 299 - 300 if "sorted_list" in kwargs: - 301 warnings.warn("Argument 'sorted_list' is deprecated, use 'sort' instead.", DeprecationWarning) - 302 sort = kwargs.get("sorted_list") - 303 - 304 if self.is_matrix_symmetric(): - 305 symmetric_corr = self - 306 else: - 307 symmetric_corr = self.matrix_symmetric() + 265 The eigenvectors are sorted according to the descending eigenvalues, the zeroth eigenvector(s) correspond to the + 266 largest eigenvalue(s). The eigenvector(s) for the individual states can be accessed via slicing + 267 ```python + 268 C.GEVP(t0=2)[0] # Ground state vector(s) + 269 C.GEVP(t0=2)[:3] # Vectors for the lowest three states + 270 ``` + 271 + 272 Parameters + 273 ---------- + 274 t0 : int + 275 The time t0 for the right hand side of the GEVP according to $G(t)v_i=\lambda_i G(t_0)v_i$ + 276 ts : int + 277 fixed time $G(t_s)v_i=\lambda_i G(t_0)v_i$ if sort=None. + 278 If sort="Eigenvector" it gives a reference point for the sorting method. + 279 sort : string + 280 If this argument is set, a list of self.T vectors per state is returned. If it is set to None, only one vector is returned. + 281 - "Eigenvalue": The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice. + 282 - "Eigenvector": Use the method described in arXiv:2004.10472 to find the set of v(t) belonging to the state. + 283 The reference state is identified by its eigenvalue at $t=t_s$. + 284 + 285 Other Parameters + 286 ---------------- + 287 state : int + 288 Returns only the vector(s) for a specified state. The lowest state is zero. + 289 ''' + 290 + 291 if self.N == 1: + 292 raise Exception("GEVP methods only works on correlator matrices and not single correlators.") + 293 if ts is not None: + 294 if (ts <= t0): + 295 raise Exception("ts has to be larger than t0.") + 296 + 297 if "sorted_list" in kwargs: + 298 warnings.warn("Argument 'sorted_list' is deprecated, use 'sort' instead.", DeprecationWarning) + 299 sort = kwargs.get("sorted_list") + 300 + 301 if self.is_matrix_symmetric(): + 302 symmetric_corr = self + 303 else: + 304 symmetric_corr = self.matrix_symmetric() + 305 + 306 G0 = np.vectorize(lambda x: x.value)(symmetric_corr[t0]) + 307 np.linalg.cholesky(G0) # Check if matrix G0 is positive-semidefinite. 308 - 309 G0 = np.vectorize(lambda x: x.value)(symmetric_corr[t0]) - 310 np.linalg.cholesky(G0) # Check if matrix G0 is positive-semidefinite. - 311 - 312 if sort is None: - 313 if (ts is None): - 314 raise Exception("ts is required if sort=None.") - 315 if (self.content[t0] is None) or (self.content[ts] is None): - 316 raise Exception("Corr not defined at t0/ts.") - 317 Gt = np.vectorize(lambda x: x.value)(symmetric_corr[ts]) - 318 reordered_vecs = _GEVP_solver(Gt, G0) - 319 - 320 elif sort in ["Eigenvalue", "Eigenvector"]: - 321 if sort == "Eigenvalue" and ts is not None: - 322 warnings.warn("ts has no effect when sorting by eigenvalue is chosen.", RuntimeWarning) - 323 all_vecs = [None] * (t0 + 1) - 324 for t in range(t0 + 1, self.T): - 325 try: - 326 Gt = np.vectorize(lambda x: x.value)(symmetric_corr[t]) - 327 all_vecs.append(_GEVP_solver(Gt, G0)) - 328 except Exception: - 329 all_vecs.append(None) - 330 if sort == "Eigenvector": - 331 if ts is None: - 332 raise Exception("ts is required for the Eigenvector sorting method.") - 333 all_vecs = _sort_vectors(all_vecs, ts) - 334 - 335 reordered_vecs = [[v[s] if v is not None else None for v in all_vecs] for s in range(self.N)] - 336 else: - 337 raise Exception("Unkown value for 'sort'.") - 338 - 339 if "state" in kwargs: - 340 return reordered_vecs[kwargs.get("state")] - 341 else: - 342 return reordered_vecs + 309 if sort is None: + 310 if (ts is None): + 311 raise Exception("ts is required if sort=None.") + 312 if (self.content[t0] is None) or (self.content[ts] is None): + 313 raise Exception("Corr not defined at t0/ts.") + 314 Gt = np.vectorize(lambda x: x.value)(symmetric_corr[ts]) + 315 reordered_vecs = _GEVP_solver(Gt, G0) + 316 + 317 elif sort in ["Eigenvalue", "Eigenvector"]: + 318 if sort == "Eigenvalue" and ts is not None: + 319 warnings.warn("ts has no effect when sorting by eigenvalue is chosen.", RuntimeWarning) + 320 all_vecs = [None] * (t0 + 1) + 321 for t in range(t0 + 1, self.T): + 322 try: + 323 Gt = np.vectorize(lambda x: x.value)(symmetric_corr[t]) + 324 all_vecs.append(_GEVP_solver(Gt, G0)) + 325 except Exception: + 326 all_vecs.append(None) + 327 if sort == "Eigenvector": + 328 if ts is None: + 329 raise Exception("ts is required for the Eigenvector sorting method.") + 330 all_vecs = _sort_vectors(all_vecs, ts) + 331 + 332 reordered_vecs = [[v[s] if v is not None else None for v in all_vecs] for s in range(self.N)] + 333 else: + 334 raise Exception("Unkown value for 'sort'.") + 335 + 336 if "state" in kwargs: + 337 return reordered_vecs[kwargs.get("state")] + 338 else: + 339 return reordered_vecs + 340 + 341 def Eigenvalue(self, t0, ts=None, state=0, sort="Eigenvalue"): + 342 """Determines the eigenvalue of the GEVP by solving and projecting the correlator 343 - 344 def Eigenvalue(self, t0, ts=None, state=0, sort="Eigenvalue"): - 345 """Determines the eigenvalue of the GEVP by solving and projecting the correlator - 346 - 347 Parameters - 348 ---------- - 349 state : int - 350 The state one is interested in ordered by energy. The lowest state is zero. - 351 - 352 All other parameters are identical to the ones of Corr.GEVP. - 353 """ - 354 vec = self.GEVP(t0, ts=ts, sort=sort)[state] - 355 return self.projected(vec) + 344 Parameters + 345 ---------- + 346 state : int + 347 The state one is interested in ordered by energy. The lowest state is zero. + 348 + 349 All other parameters are identical to the ones of Corr.GEVP. + 350 """ + 351 vec = self.GEVP(t0, ts=ts, sort=sort)[state] + 352 return self.projected(vec) + 353 + 354 def Hankel(self, N, periodic=False): + 355 """Constructs an NxN Hankel matrix 356 - 357 def Hankel(self, N, periodic=False): - 358 """Constructs an NxN Hankel matrix - 359 - 360 C(t) c(t+1) ... c(t+n-1) - 361 C(t+1) c(t+2) ... c(t+n) - 362 ................. - 363 C(t+(n-1)) c(t+n) ... c(t+2(n-1)) - 364 - 365 Parameters - 366 ---------- - 367 N : int - 368 Dimension of the Hankel matrix - 369 periodic : bool, optional - 370 determines whether the matrix is extended periodically - 371 """ + 357 C(t) c(t+1) ... c(t+n-1) + 358 C(t+1) c(t+2) ... c(t+n) + 359 ................. + 360 C(t+(n-1)) c(t+n) ... c(t+2(n-1)) + 361 + 362 Parameters + 363 ---------- + 364 N : int + 365 Dimension of the Hankel matrix + 366 periodic : bool, optional + 367 determines whether the matrix is extended periodically + 368 """ + 369 + 370 if self.N != 1: + 371 raise Exception("Multi-operator Prony not implemented!") 372 - 373 if self.N != 1: - 374 raise Exception("Multi-operator Prony not implemented!") - 375 - 376 array = np.empty([N, N], dtype="object") - 377 new_content = [] - 378 for t in range(self.T): - 379 new_content.append(array.copy()) - 380 - 381 def wrap(i): - 382 while i >= self.T: - 383 i -= self.T - 384 return i - 385 - 386 for t in range(self.T): - 387 for i in range(N): - 388 for j in range(N): - 389 if periodic: - 390 new_content[t][i, j] = self.content[wrap(t + i + j)][0] - 391 elif (t + i + j) >= self.T: - 392 new_content[t] = None - 393 else: - 394 new_content[t][i, j] = self.content[t + i + j][0] - 395 - 396 return Corr(new_content) + 373 array = np.empty([N, N], dtype="object") + 374 new_content = [] + 375 for t in range(self.T): + 376 new_content.append(array.copy()) + 377 + 378 def wrap(i): + 379 while i >= self.T: + 380 i -= self.T + 381 return i + 382 + 383 for t in range(self.T): + 384 for i in range(N): + 385 for j in range(N): + 386 if periodic: + 387 new_content[t][i, j] = self.content[wrap(t + i + j)][0] + 388 elif (t + i + j) >= self.T: + 389 new_content[t] = None + 390 else: + 391 new_content[t][i, j] = self.content[t + i + j][0] + 392 + 393 return Corr(new_content) + 394 + 395 def roll(self, dt): + 396 """Periodically shift the correlator by dt timeslices 397 - 398 def roll(self, dt): - 399 """Periodically shift the correlator by dt timeslices - 400 - 401 Parameters - 402 ---------- - 403 dt : int - 404 number of timeslices - 405 """ - 406 return Corr(list(np.roll(np.array(self.content, dtype=object), dt))) - 407 - 408 def reverse(self): - 409 """Reverse the time ordering of the Corr""" - 410 return Corr(self.content[:: -1]) + 398 Parameters + 399 ---------- + 400 dt : int + 401 number of timeslices + 402 """ + 403 return Corr(list(np.roll(np.array(self.content, dtype=object), dt))) + 404 + 405 def reverse(self): + 406 """Reverse the time ordering of the Corr""" + 407 return Corr(self.content[:: -1]) + 408 + 409 def thin(self, spacing=2, offset=0): + 410 """Thin out a correlator to suppress correlations 411 - 412 def thin(self, spacing=2, offset=0): - 413 """Thin out a correlator to suppress correlations - 414 - 415 Parameters - 416 ---------- - 417 spacing : int - 418 Keep only every 'spacing'th entry of the correlator - 419 offset : int - 420 Offset the equal spacing - 421 """ - 422 new_content = [] - 423 for t in range(self.T): - 424 if (offset + t) % spacing != 0: - 425 new_content.append(None) - 426 else: - 427 new_content.append(self.content[t]) - 428 return Corr(new_content) + 412 Parameters + 413 ---------- + 414 spacing : int + 415 Keep only every 'spacing'th entry of the correlator + 416 offset : int + 417 Offset the equal spacing + 418 """ + 419 new_content = [] + 420 for t in range(self.T): + 421 if (offset + t) % spacing != 0: + 422 new_content.append(None) + 423 else: + 424 new_content.append(self.content[t]) + 425 return Corr(new_content) + 426 + 427 def correlate(self, partner): + 428 """Correlate the correlator with another correlator or Obs 429 - 430 def correlate(self, partner): - 431 """Correlate the correlator with another correlator or Obs - 432 - 433 Parameters - 434 ---------- - 435 partner : Obs or Corr - 436 partner to correlate the correlator with. - 437 Can either be an Obs which is correlated with all entries of the - 438 correlator or a Corr of same length. - 439 """ - 440 if self.N != 1: - 441 raise Exception("Only one-dimensional correlators can be safely correlated.") - 442 new_content = [] - 443 for x0, t_slice in enumerate(self.content): - 444 if _check_for_none(self, t_slice): - 445 new_content.append(None) - 446 else: - 447 if isinstance(partner, Corr): - 448 if _check_for_none(partner, partner.content[x0]): - 449 new_content.append(None) - 450 else: - 451 new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice])) - 452 elif isinstance(partner, Obs): # Should this include CObs? - 453 new_content.append(np.array([correlate(o, partner) for o in t_slice])) - 454 else: - 455 raise Exception("Can only correlate with an Obs or a Corr.") - 456 - 457 return Corr(new_content) + 430 Parameters + 431 ---------- + 432 partner : Obs or Corr + 433 partner to correlate the correlator with. + 434 Can either be an Obs which is correlated with all entries of the + 435 correlator or a Corr of same length. + 436 """ + 437 if self.N != 1: + 438 raise Exception("Only one-dimensional correlators can be safely correlated.") + 439 new_content = [] + 440 for x0, t_slice in enumerate(self.content): + 441 if _check_for_none(self, t_slice): + 442 new_content.append(None) + 443 else: + 444 if isinstance(partner, Corr): + 445 if _check_for_none(partner, partner.content[x0]): + 446 new_content.append(None) + 447 else: + 448 new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice])) + 449 elif isinstance(partner, Obs): # Should this include CObs? + 450 new_content.append(np.array([correlate(o, partner) for o in t_slice])) + 451 else: + 452 raise Exception("Can only correlate with an Obs or a Corr.") + 453 + 454 return Corr(new_content) + 455 + 456 def reweight(self, weight, **kwargs): + 457 """Reweight the correlator. 458 - 459 def reweight(self, weight, **kwargs): - 460 """Reweight the correlator. - 461 - 462 Parameters - 463 ---------- - 464 weight : Obs - 465 Reweighting factor. An Observable that has to be defined on a superset of the - 466 configurations in obs[i].idl for all i. - 467 all_configs : bool - 468 if True, the reweighted observables are normalized by the average of - 469 the reweighting factor on all configurations in weight.idl and not - 470 on the configurations in obs[i].idl. - 471 """ - 472 if self.N != 1: - 473 raise Exception("Reweighting only implemented for one-dimensional correlators.") - 474 new_content = [] - 475 for t_slice in self.content: - 476 if _check_for_none(self, t_slice): - 477 new_content.append(None) - 478 else: - 479 new_content.append(np.array(reweight(weight, t_slice, **kwargs))) - 480 return Corr(new_content) + 459 Parameters + 460 ---------- + 461 weight : Obs + 462 Reweighting factor. An Observable that has to be defined on a superset of the + 463 configurations in obs[i].idl for all i. + 464 all_configs : bool + 465 if True, the reweighted observables are normalized by the average of + 466 the reweighting factor on all configurations in weight.idl and not + 467 on the configurations in obs[i].idl. + 468 """ + 469 if self.N != 1: + 470 raise Exception("Reweighting only implemented for one-dimensional correlators.") + 471 new_content = [] + 472 for t_slice in self.content: + 473 if _check_for_none(self, t_slice): + 474 new_content.append(None) + 475 else: + 476 new_content.append(np.array(reweight(weight, t_slice, **kwargs))) + 477 return Corr(new_content) + 478 + 479 def T_symmetry(self, partner, parity=+1): + 480 """Return the time symmetry average of the correlator and its partner 481 - 482 def T_symmetry(self, partner, parity=+1): - 483 """Return the time symmetry average of the correlator and its partner - 484 - 485 Parameters - 486 ---------- - 487 partner : Corr - 488 Time symmetry partner of the Corr - 489 partity : int - 490 Parity quantum number of the correlator, can be +1 or -1 - 491 """ - 492 if self.N != 1: - 493 raise Exception("T_symmetry only implemented for one-dimensional correlators.") - 494 if not isinstance(partner, Corr): - 495 raise Exception("T partner has to be a Corr object.") - 496 if parity not in [+1, -1]: - 497 raise Exception("Parity has to be +1 or -1.") - 498 T_partner = parity * partner.reverse() - 499 - 500 t_slices = [] - 501 test = (self - T_partner) - 502 test.gamma_method() - 503 for x0, t_slice in enumerate(test.content): - 504 if t_slice is not None: - 505 if not t_slice[0].is_zero_within_error(5): - 506 t_slices.append(x0) - 507 if t_slices: - 508 warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning) - 509 - 510 return (self + T_partner) / 2 + 482 Parameters + 483 ---------- + 484 partner : Corr + 485 Time symmetry partner of the Corr + 486 partity : int + 487 Parity quantum number of the correlator, can be +1 or -1 + 488 """ + 489 if self.N != 1: + 490 raise Exception("T_symmetry only implemented for one-dimensional correlators.") + 491 if not isinstance(partner, Corr): + 492 raise Exception("T partner has to be a Corr object.") + 493 if parity not in [+1, -1]: + 494 raise Exception("Parity has to be +1 or -1.") + 495 T_partner = parity * partner.reverse() + 496 + 497 t_slices = [] + 498 test = (self - T_partner) + 499 test.gamma_method() + 500 for x0, t_slice in enumerate(test.content): + 501 if t_slice is not None: + 502 if not t_slice[0].is_zero_within_error(5): + 503 t_slices.append(x0) + 504 if t_slices: + 505 warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning) + 506 + 507 return (self + T_partner) / 2 + 508 + 509 def deriv(self, variant="symmetric"): + 510 """Return the first derivative of the correlator with respect to x0. 511 - 512 def deriv(self, variant="symmetric"): - 513 """Return the first derivative of the correlator with respect to x0. - 514 - 515 Parameters - 516 ---------- - 517 variant : str - 518 decides which definition of the finite differences derivative is used. - 519 Available choice: symmetric, forward, backward, improved, log, default: symmetric - 520 """ - 521 if self.N != 1: - 522 raise Exception("deriv only implemented for one-dimensional correlators.") - 523 if variant == "symmetric": - 524 newcontent = [] - 525 for t in range(1, self.T - 1): - 526 if (self.content[t - 1] is None) or (self.content[t + 1] is None): - 527 newcontent.append(None) - 528 else: - 529 newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1])) - 530 if (all([x is None for x in newcontent])): - 531 raise Exception('Derivative is undefined at all timeslices') - 532 return Corr(newcontent, padding=[1, 1]) - 533 elif variant == "forward": - 534 newcontent = [] - 535 for t in range(self.T - 1): - 536 if (self.content[t] is None) or (self.content[t + 1] is None): - 537 newcontent.append(None) - 538 else: - 539 newcontent.append(self.content[t + 1] - self.content[t]) - 540 if (all([x is None for x in newcontent])): - 541 raise Exception("Derivative is undefined at all timeslices") - 542 return Corr(newcontent, padding=[0, 1]) - 543 elif variant == "backward": - 544 newcontent = [] - 545 for t in range(1, self.T): - 546 if (self.content[t - 1] is None) or (self.content[t] is None): - 547 newcontent.append(None) - 548 else: - 549 newcontent.append(self.content[t] - self.content[t - 1]) - 550 if (all([x is None for x in newcontent])): - 551 raise Exception("Derivative is undefined at all timeslices") - 552 return Corr(newcontent, padding=[1, 0]) - 553 elif variant == "improved": - 554 newcontent = [] - 555 for t in range(2, self.T - 2): - 556 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): - 557 newcontent.append(None) - 558 else: - 559 newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2])) - 560 if (all([x is None for x in newcontent])): - 561 raise Exception('Derivative is undefined at all timeslices') - 562 return Corr(newcontent, padding=[2, 2]) - 563 elif variant == 'log': - 564 newcontent = [] - 565 for t in range(self.T): - 566 if (self.content[t] is None) or (self.content[t] <= 0): - 567 newcontent.append(None) - 568 else: - 569 newcontent.append(np.log(self.content[t])) - 570 if (all([x is None for x in newcontent])): - 571 raise Exception("Log is undefined at all timeslices") - 572 logcorr = Corr(newcontent) - 573 return self * logcorr.deriv('symmetric') - 574 else: - 575 raise Exception("Unknown variant.") + 512 Parameters + 513 ---------- + 514 variant : str + 515 decides which definition of the finite differences derivative is used. + 516 Available choice: symmetric, forward, backward, improved, log, default: symmetric + 517 """ + 518 if self.N != 1: + 519 raise Exception("deriv only implemented for one-dimensional correlators.") + 520 if variant == "symmetric": + 521 newcontent = [] + 522 for t in range(1, self.T - 1): + 523 if (self.content[t - 1] is None) or (self.content[t + 1] is None): + 524 newcontent.append(None) + 525 else: + 526 newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1])) + 527 if (all([x is None for x in newcontent])): + 528 raise Exception('Derivative is undefined at all timeslices') + 529 return Corr(newcontent, padding=[1, 1]) + 530 elif variant == "forward": + 531 newcontent = [] + 532 for t in range(self.T - 1): + 533 if (self.content[t] is None) or (self.content[t + 1] is None): + 534 newcontent.append(None) + 535 else: + 536 newcontent.append(self.content[t + 1] - self.content[t]) + 537 if (all([x is None for x in newcontent])): + 538 raise Exception("Derivative is undefined at all timeslices") + 539 return Corr(newcontent, padding=[0, 1]) + 540 elif variant == "backward": + 541 newcontent = [] + 542 for t in range(1, self.T): + 543 if (self.content[t - 1] is None) or (self.content[t] is None): + 544 newcontent.append(None) + 545 else: + 546 newcontent.append(self.content[t] - self.content[t - 1]) + 547 if (all([x is None for x in newcontent])): + 548 raise Exception("Derivative is undefined at all timeslices") + 549 return Corr(newcontent, padding=[1, 0]) + 550 elif variant == "improved": + 551 newcontent = [] + 552 for t in range(2, self.T - 2): + 553 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): + 554 newcontent.append(None) + 555 else: + 556 newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2])) + 557 if (all([x is None for x in newcontent])): + 558 raise Exception('Derivative is undefined at all timeslices') + 559 return Corr(newcontent, padding=[2, 2]) + 560 elif variant == 'log': + 561 newcontent = [] + 562 for t in range(self.T): + 563 if (self.content[t] is None) or (self.content[t] <= 0): + 564 newcontent.append(None) + 565 else: + 566 newcontent.append(np.log(self.content[t])) + 567 if (all([x is None for x in newcontent])): + 568 raise Exception("Log is undefined at all timeslices") + 569 logcorr = Corr(newcontent) + 570 return self * logcorr.deriv('symmetric') + 571 else: + 572 raise Exception("Unknown variant.") + 573 + 574 def second_deriv(self, variant="symmetric"): + 575 """Return the second derivative of the correlator with respect to x0. 576 - 577 def second_deriv(self, variant="symmetric"): - 578 """Return the second derivative of the correlator with respect to x0. - 579 - 580 Parameters - 581 ---------- - 582 variant : str - 583 decides which definition of the finite differences derivative is used. - 584 Available choice: symmetric, improved, log, default: symmetric - 585 """ - 586 if self.N != 1: - 587 raise Exception("second_deriv only implemented for one-dimensional correlators.") - 588 if variant == "symmetric": - 589 newcontent = [] - 590 for t in range(1, self.T - 1): - 591 if (self.content[t - 1] is None) or (self.content[t + 1] is None): - 592 newcontent.append(None) - 593 else: - 594 newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1])) - 595 if (all([x is None for x in newcontent])): - 596 raise Exception("Derivative is undefined at all timeslices") - 597 return Corr(newcontent, padding=[1, 1]) - 598 elif variant == "improved": - 599 newcontent = [] - 600 for t in range(2, self.T - 2): - 601 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): - 602 newcontent.append(None) - 603 else: - 604 newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2])) - 605 if (all([x is None for x in newcontent])): - 606 raise Exception("Derivative is undefined at all timeslices") - 607 return Corr(newcontent, padding=[2, 2]) - 608 elif variant == 'log': - 609 newcontent = [] - 610 for t in range(self.T): - 611 if (self.content[t] is None) or (self.content[t] <= 0): - 612 newcontent.append(None) - 613 else: - 614 newcontent.append(np.log(self.content[t])) - 615 if (all([x is None for x in newcontent])): - 616 raise Exception("Log is undefined at all timeslices") - 617 logcorr = Corr(newcontent) - 618 return self * (logcorr.second_deriv('symmetric') + (logcorr.deriv('symmetric'))**2) - 619 else: - 620 raise Exception("Unknown variant.") + 577 Parameters + 578 ---------- + 579 variant : str + 580 decides which definition of the finite differences derivative is used. + 581 Available choice: symmetric, improved, log, default: symmetric + 582 """ + 583 if self.N != 1: + 584 raise Exception("second_deriv only implemented for one-dimensional correlators.") + 585 if variant == "symmetric": + 586 newcontent = [] + 587 for t in range(1, self.T - 1): + 588 if (self.content[t - 1] is None) or (self.content[t + 1] is None): + 589 newcontent.append(None) + 590 else: + 591 newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1])) + 592 if (all([x is None for x in newcontent])): + 593 raise Exception("Derivative is undefined at all timeslices") + 594 return Corr(newcontent, padding=[1, 1]) + 595 elif variant == "improved": + 596 newcontent = [] + 597 for t in range(2, self.T - 2): + 598 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): + 599 newcontent.append(None) + 600 else: + 601 newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2])) + 602 if (all([x is None for x in newcontent])): + 603 raise Exception("Derivative is undefined at all timeslices") + 604 return Corr(newcontent, padding=[2, 2]) + 605 elif variant == 'log': + 606 newcontent = [] + 607 for t in range(self.T): + 608 if (self.content[t] is None) or (self.content[t] <= 0): + 609 newcontent.append(None) + 610 else: + 611 newcontent.append(np.log(self.content[t])) + 612 if (all([x is None for x in newcontent])): + 613 raise Exception("Log is undefined at all timeslices") + 614 logcorr = Corr(newcontent) + 615 return self * (logcorr.second_deriv('symmetric') + (logcorr.deriv('symmetric'))**2) + 616 else: + 617 raise Exception("Unknown variant.") + 618 + 619 def m_eff(self, variant='log', guess=1.0): + 620 """Returns the effective mass of the correlator as correlator object 621 - 622 def m_eff(self, variant='log', guess=1.0): - 623 """Returns the effective mass of the correlator as correlator object - 624 - 625 Parameters - 626 ---------- - 627 variant : str - 628 log : uses the standard effective mass log(C(t) / C(t+1)) - 629 cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m. - 630 sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m. - 631 See, e.g., arXiv:1205.5380 - 632 arccosh : Uses the explicit form of the symmetrized correlator (not recommended) - 633 logsym: uses the symmetric effective mass log(C(t-1) / C(t+1))/2 - 634 guess : float - 635 guess for the root finder, only relevant for the root variant - 636 """ - 637 if self.N != 1: - 638 raise Exception('Correlator must be projected before getting m_eff') - 639 if variant == 'log': - 640 newcontent = [] - 641 for t in range(self.T - 1): - 642 if ((self.content[t] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0): - 643 newcontent.append(None) - 644 elif self.content[t][0].value / self.content[t + 1][0].value < 0: - 645 newcontent.append(None) - 646 else: - 647 newcontent.append(self.content[t] / self.content[t + 1]) - 648 if (all([x is None for x in newcontent])): - 649 raise Exception('m_eff is undefined at all timeslices') - 650 - 651 return np.log(Corr(newcontent, padding=[0, 1])) - 652 - 653 elif variant == 'logsym': - 654 newcontent = [] - 655 for t in range(1, self.T - 1): - 656 if ((self.content[t - 1] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0): - 657 newcontent.append(None) - 658 elif self.content[t - 1][0].value / self.content[t + 1][0].value < 0: - 659 newcontent.append(None) - 660 else: - 661 newcontent.append(self.content[t - 1] / self.content[t + 1]) - 662 if (all([x is None for x in newcontent])): - 663 raise Exception('m_eff is undefined at all timeslices') - 664 - 665 return np.log(Corr(newcontent, padding=[1, 1])) / 2 - 666 - 667 elif variant in ['periodic', 'cosh', 'sinh']: - 668 if variant in ['periodic', 'cosh']: - 669 func = anp.cosh - 670 else: - 671 func = anp.sinh + 622 Parameters + 623 ---------- + 624 variant : str + 625 log : uses the standard effective mass log(C(t) / C(t+1)) + 626 cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m. + 627 sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m. + 628 See, e.g., arXiv:1205.5380 + 629 arccosh : Uses the explicit form of the symmetrized correlator (not recommended) + 630 logsym: uses the symmetric effective mass log(C(t-1) / C(t+1))/2 + 631 guess : float + 632 guess for the root finder, only relevant for the root variant + 633 """ + 634 if self.N != 1: + 635 raise Exception('Correlator must be projected before getting m_eff') + 636 if variant == 'log': + 637 newcontent = [] + 638 for t in range(self.T - 1): + 639 if ((self.content[t] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0): + 640 newcontent.append(None) + 641 elif self.content[t][0].value / self.content[t + 1][0].value < 0: + 642 newcontent.append(None) + 643 else: + 644 newcontent.append(self.content[t] / self.content[t + 1]) + 645 if (all([x is None for x in newcontent])): + 646 raise Exception('m_eff is undefined at all timeslices') + 647 + 648 return np.log(Corr(newcontent, padding=[0, 1])) + 649 + 650 elif variant == 'logsym': + 651 newcontent = [] + 652 for t in range(1, self.T - 1): + 653 if ((self.content[t - 1] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0): + 654 newcontent.append(None) + 655 elif self.content[t - 1][0].value / self.content[t + 1][0].value < 0: + 656 newcontent.append(None) + 657 else: + 658 newcontent.append(self.content[t - 1] / self.content[t + 1]) + 659 if (all([x is None for x in newcontent])): + 660 raise Exception('m_eff is undefined at all timeslices') + 661 + 662 return np.log(Corr(newcontent, padding=[1, 1])) / 2 + 663 + 664 elif variant in ['periodic', 'cosh', 'sinh']: + 665 if variant in ['periodic', 'cosh']: + 666 func = anp.cosh + 667 else: + 668 func = anp.sinh + 669 + 670 def root_function(x, d): + 671 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d 672 - 673 def root_function(x, d): - 674 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d - 675 - 676 newcontent = [] - 677 for t in range(self.T - 1): - 678 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0): - 679 newcontent.append(None) - 680 # Fill the two timeslices in the middle of the lattice with their predecessors - 681 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: - 682 newcontent.append(newcontent[-1]) - 683 elif self.content[t][0].value / self.content[t + 1][0].value < 0: - 684 newcontent.append(None) - 685 else: - 686 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) - 687 if (all([x is None for x in newcontent])): - 688 raise Exception('m_eff is undefined at all timeslices') - 689 - 690 return Corr(newcontent, padding=[0, 1]) - 691 - 692 elif variant == 'arccosh': - 693 newcontent = [] - 694 for t in range(1, self.T - 1): - 695 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): - 696 newcontent.append(None) - 697 else: - 698 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) - 699 if (all([x is None for x in newcontent])): - 700 raise Exception("m_eff is undefined at all timeslices") - 701 return np.arccosh(Corr(newcontent, padding=[1, 1])) + 673 newcontent = [] + 674 for t in range(self.T - 1): + 675 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0): + 676 newcontent.append(None) + 677 # Fill the two timeslices in the middle of the lattice with their predecessors + 678 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: + 679 newcontent.append(newcontent[-1]) + 680 elif self.content[t][0].value / self.content[t + 1][0].value < 0: + 681 newcontent.append(None) + 682 else: + 683 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) + 684 if (all([x is None for x in newcontent])): + 685 raise Exception('m_eff is undefined at all timeslices') + 686 + 687 return Corr(newcontent, padding=[0, 1]) + 688 + 689 elif variant == 'arccosh': + 690 newcontent = [] + 691 for t in range(1, self.T - 1): + 692 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): + 693 newcontent.append(None) + 694 else: + 695 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) + 696 if (all([x is None for x in newcontent])): + 697 raise Exception("m_eff is undefined at all timeslices") + 698 return np.arccosh(Corr(newcontent, padding=[1, 1])) + 699 + 700 else: + 701 raise Exception('Unknown variant.') 702 - 703 else: - 704 raise Exception('Unknown variant.') + 703 def fit(self, function, fitrange=None, silent=False, **kwargs): + 704 r'''Fits function to the data 705 - 706 def fit(self, function, fitrange=None, silent=False, **kwargs): - 707 r'''Fits function to the data - 708 - 709 Parameters - 710 ---------- - 711 function : obj - 712 function to fit to the data. See fits.least_squares for details. - 713 fitrange : list - 714 Two element list containing the timeslices on which the fit is supposed to start and stop. - 715 Caution: This range is inclusive as opposed to standard python indexing. - 716 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. - 717 If not specified, self.prange or all timeslices are used. - 718 silent : bool - 719 Decides whether output is printed to the standard output. - 720 ''' - 721 if self.N != 1: - 722 raise Exception("Correlator must be projected before fitting") - 723 - 724 if fitrange is None: - 725 if self.prange: - 726 fitrange = self.prange - 727 else: - 728 fitrange = [0, self.T - 1] - 729 else: - 730 if not isinstance(fitrange, list): - 731 raise Exception("fitrange has to be a list with two elements") - 732 if len(fitrange) != 2: - 733 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") - 734 - 735 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 736 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 737 result = least_squares(xs, ys, function, silent=silent, **kwargs) - 738 return result + 706 Parameters + 707 ---------- + 708 function : obj + 709 function to fit to the data. See fits.least_squares for details. + 710 fitrange : list + 711 Two element list containing the timeslices on which the fit is supposed to start and stop. + 712 Caution: This range is inclusive as opposed to standard python indexing. + 713 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. + 714 If not specified, self.prange or all timeslices are used. + 715 silent : bool + 716 Decides whether output is printed to the standard output. + 717 ''' + 718 if self.N != 1: + 719 raise Exception("Correlator must be projected before fitting") + 720 + 721 if fitrange is None: + 722 if self.prange: + 723 fitrange = self.prange + 724 else: + 725 fitrange = [0, self.T - 1] + 726 else: + 727 if not isinstance(fitrange, list): + 728 raise Exception("fitrange has to be a list with two elements") + 729 if len(fitrange) != 2: + 730 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") + 731 + 732 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 733 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 734 result = least_squares(xs, ys, function, silent=silent, **kwargs) + 735 return result + 736 + 737 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): + 738 """ Extract a plateau value from a Corr object 739 - 740 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): - 741 """ Extract a plateau value from a Corr object - 742 - 743 Parameters - 744 ---------- - 745 plateau_range : list - 746 list with two entries, indicating the first and the last timeslice - 747 of the plateau region. - 748 method : str - 749 method to extract the plateau. - 750 'fit' fits a constant to the plateau region - 751 'avg', 'average' or 'mean' just average over the given timeslices. - 752 auto_gamma : bool - 753 apply gamma_method with default parameters to the Corr. Defaults to None - 754 """ - 755 if not plateau_range: - 756 if self.prange: - 757 plateau_range = self.prange - 758 else: - 759 raise Exception("no plateau range provided") - 760 if self.N != 1: - 761 raise Exception("Correlator must be projected before getting a plateau.") - 762 if (all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): - 763 raise Exception("plateau is undefined at all timeslices in plateaurange.") - 764 if auto_gamma: - 765 self.gamma_method() - 766 if method == "fit": - 767 def const_func(a, t): - 768 return a[0] - 769 return self.fit(const_func, plateau_range)[0] - 770 elif method in ["avg", "average", "mean"]: - 771 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) - 772 return returnvalue + 740 Parameters + 741 ---------- + 742 plateau_range : list + 743 list with two entries, indicating the first and the last timeslice + 744 of the plateau region. + 745 method : str + 746 method to extract the plateau. + 747 'fit' fits a constant to the plateau region + 748 'avg', 'average' or 'mean' just average over the given timeslices. + 749 auto_gamma : bool + 750 apply gamma_method with default parameters to the Corr. Defaults to None + 751 """ + 752 if not plateau_range: + 753 if self.prange: + 754 plateau_range = self.prange + 755 else: + 756 raise Exception("no plateau range provided") + 757 if self.N != 1: + 758 raise Exception("Correlator must be projected before getting a plateau.") + 759 if (all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): + 760 raise Exception("plateau is undefined at all timeslices in plateaurange.") + 761 if auto_gamma: + 762 self.gamma_method() + 763 if method == "fit": + 764 def const_func(a, t): + 765 return a[0] + 766 return self.fit(const_func, plateau_range)[0] + 767 elif method in ["avg", "average", "mean"]: + 768 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) + 769 return returnvalue + 770 + 771 else: + 772 raise Exception("Unsupported plateau method: " + method) 773 - 774 else: - 775 raise Exception("Unsupported plateau method: " + method) - 776 - 777 def set_prange(self, prange): - 778 """Sets the attribute prange of the Corr object.""" - 779 if not len(prange) == 2: - 780 raise Exception("prange must be a list or array with two values") - 781 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): - 782 raise Exception("Start and end point must be integers") - 783 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): - 784 raise Exception("Start and end point must define a range in the interval 0,T") + 774 def set_prange(self, prange): + 775 """Sets the attribute prange of the Corr object.""" + 776 if not len(prange) == 2: + 777 raise Exception("prange must be a list or array with two values") + 778 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): + 779 raise Exception("Start and end point must be integers") + 780 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): + 781 raise Exception("Start and end point must define a range in the interval 0,T") + 782 + 783 self.prange = prange + 784 return 785 - 786 self.prange = prange - 787 return + 786 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): + 787 """Plots the correlator using the tag of the correlator as label if available. 788 - 789 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): - 790 """Plots the correlator using the tag of the correlator as label if available. - 791 - 792 Parameters - 793 ---------- - 794 x_range : list - 795 list of two values, determining the range of the x-axis e.g. [4, 8]. - 796 comp : Corr or list of Corr - 797 Correlator or list of correlators which are plotted for comparison. - 798 The tags of these correlators are used as labels if available. - 799 logscale : bool - 800 Sets y-axis to logscale. - 801 plateau : Obs - 802 Plateau value to be visualized in the figure. - 803 fit_res : Fit_result - 804 Fit_result object to be visualized. - 805 ylabel : str - 806 Label for the y-axis. - 807 save : str - 808 path to file in which the figure should be saved. - 809 auto_gamma : bool - 810 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. - 811 hide_sigma : float - 812 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. - 813 references : list - 814 List of floating point values that are displayed as horizontal lines for reference. - 815 title : string - 816 Optional title of the figure. - 817 """ - 818 if self.N != 1: - 819 raise Exception("Correlator must be projected before plotting") + 789 Parameters + 790 ---------- + 791 x_range : list + 792 list of two values, determining the range of the x-axis e.g. [4, 8]. + 793 comp : Corr or list of Corr + 794 Correlator or list of correlators which are plotted for comparison. + 795 The tags of these correlators are used as labels if available. + 796 logscale : bool + 797 Sets y-axis to logscale. + 798 plateau : Obs + 799 Plateau value to be visualized in the figure. + 800 fit_res : Fit_result + 801 Fit_result object to be visualized. + 802 ylabel : str + 803 Label for the y-axis. + 804 save : str + 805 path to file in which the figure should be saved. + 806 auto_gamma : bool + 807 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. + 808 hide_sigma : float + 809 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. + 810 references : list + 811 List of floating point values that are displayed as horizontal lines for reference. + 812 title : string + 813 Optional title of the figure. + 814 """ + 815 if self.N != 1: + 816 raise Exception("Correlator must be projected before plotting") + 817 + 818 if auto_gamma: + 819 self.gamma_method() 820 - 821 if auto_gamma: - 822 self.gamma_method() + 821 if x_range is None: + 822 x_range = [0, self.T - 1] 823 - 824 if x_range is None: - 825 x_range = [0, self.T - 1] + 824 fig = plt.figure() + 825 ax1 = fig.add_subplot(111) 826 - 827 fig = plt.figure() - 828 ax1 = fig.add_subplot(111) - 829 - 830 x, y, y_err = self.plottable() - 831 if hide_sigma: - 832 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 - 833 else: - 834 hide_from = None - 835 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) - 836 if logscale: - 837 ax1.set_yscale('log') - 838 else: - 839 if y_range is None: - 840 try: - 841 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)]) - 842 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)]) - 843 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) - 844 except Exception: - 845 pass - 846 else: - 847 ax1.set_ylim(y_range) - 848 if comp: - 849 if isinstance(comp, (Corr, list)): - 850 for corr in comp if isinstance(comp, list) else [comp]: - 851 if auto_gamma: - 852 corr.gamma_method() - 853 x, y, y_err = corr.plottable() - 854 if hide_sigma: - 855 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 - 856 else: - 857 hide_from = None - 858 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) - 859 else: - 860 raise Exception("'comp' must be a correlator or a list of correlators.") - 861 - 862 if plateau: - 863 if isinstance(plateau, Obs): - 864 if auto_gamma: - 865 plateau.gamma_method() - 866 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) - 867 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') - 868 else: - 869 raise Exception("'plateau' must be an Obs") - 870 - 871 if references: - 872 if isinstance(references, list): - 873 for ref in references: - 874 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') - 875 else: - 876 raise Exception("'references' must be a list of floating pint values.") - 877 - 878 if self.prange: - 879 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') - 880 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') - 881 - 882 if fit_res: - 883 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) - 884 ax1.plot(x_samples, - 885 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), - 886 ls='-', marker=',', lw=2) - 887 - 888 ax1.set_xlabel(r'$x_0 / a$') - 889 if ylabel: - 890 ax1.set_ylabel(ylabel) - 891 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) - 892 - 893 handles, labels = ax1.get_legend_handles_labels() - 894 if labels: - 895 ax1.legend() + 827 x, y, y_err = self.plottable() + 828 if hide_sigma: + 829 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 + 830 else: + 831 hide_from = None + 832 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) + 833 if logscale: + 834 ax1.set_yscale('log') + 835 else: + 836 if y_range is None: + 837 try: + 838 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)]) + 839 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)]) + 840 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) + 841 except Exception: + 842 pass + 843 else: + 844 ax1.set_ylim(y_range) + 845 if comp: + 846 if isinstance(comp, (Corr, list)): + 847 for corr in comp if isinstance(comp, list) else [comp]: + 848 if auto_gamma: + 849 corr.gamma_method() + 850 x, y, y_err = corr.plottable() + 851 if hide_sigma: + 852 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 + 853 else: + 854 hide_from = None + 855 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) + 856 else: + 857 raise Exception("'comp' must be a correlator or a list of correlators.") + 858 + 859 if plateau: + 860 if isinstance(plateau, Obs): + 861 if auto_gamma: + 862 plateau.gamma_method() + 863 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) + 864 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') + 865 else: + 866 raise Exception("'plateau' must be an Obs") + 867 + 868 if references: + 869 if isinstance(references, list): + 870 for ref in references: + 871 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') + 872 else: + 873 raise Exception("'references' must be a list of floating pint values.") + 874 + 875 if self.prange: + 876 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') + 877 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') + 878 + 879 if fit_res: + 880 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) + 881 ax1.plot(x_samples, + 882 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), + 883 ls='-', marker=',', lw=2) + 884 + 885 ax1.set_xlabel(r'$x_0 / a$') + 886 if ylabel: + 887 ax1.set_ylabel(ylabel) + 888 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) + 889 + 890 handles, labels = ax1.get_legend_handles_labels() + 891 if labels: + 892 ax1.legend() + 893 + 894 if title: + 895 plt.title(title) 896 - 897 if title: - 898 plt.title(title) - 899 - 900 plt.draw() - 901 - 902 if save: - 903 if isinstance(save, str): - 904 fig.savefig(save, bbox_inches='tight') - 905 else: - 906 raise Exception("'save' has to be a string.") + 897 plt.draw() + 898 + 899 if save: + 900 if isinstance(save, str): + 901 fig.savefig(save, bbox_inches='tight') + 902 else: + 903 raise Exception("'save' has to be a string.") + 904 + 905 def spaghetti_plot(self, logscale=True): + 906 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. 907 - 908 def spaghetti_plot(self, logscale=True): - 909 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. - 910 - 911 Parameters - 912 ---------- - 913 logscale : bool - 914 Determines whether the scale of the y-axis is logarithmic or standard. - 915 """ - 916 if self.N != 1: - 917 raise Exception("Correlator needs to be projected first.") + 908 Parameters + 909 ---------- + 910 logscale : bool + 911 Determines whether the scale of the y-axis is logarithmic or standard. + 912 """ + 913 if self.N != 1: + 914 raise Exception("Correlator needs to be projected first.") + 915 + 916 mc_names = list(set([item for sublist in [sum(map(o[0].e_content.get, o[0].mc_names), []) for o in self.content if o is not None] for item in sublist])) + 917 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] 918 - 919 mc_names = list(set([item for sublist in [sum(map(o[0].e_content.get, o[0].mc_names), []) for o in self.content if o is not None] for item in sublist])) - 920 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] + 919 for name in mc_names: + 920 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T 921 - 922 for name in mc_names: - 923 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T - 924 - 925 fig = plt.figure() - 926 ax = fig.add_subplot(111) - 927 for dat in data: - 928 ax.plot(x0_vals, dat, ls='-', marker='') + 922 fig = plt.figure() + 923 ax = fig.add_subplot(111) + 924 for dat in data: + 925 ax.plot(x0_vals, dat, ls='-', marker='') + 926 + 927 if logscale is True: + 928 ax.set_yscale('log') 929 - 930 if logscale is True: - 931 ax.set_yscale('log') - 932 - 933 ax.set_xlabel(r'$x_0 / a$') - 934 plt.title(name) - 935 plt.draw() - 936 - 937 def dump(self, filename, datatype="json.gz", **kwargs): - 938 """Dumps the Corr into a file of chosen type - 939 Parameters - 940 ---------- - 941 filename : str - 942 Name of the file to be saved. - 943 datatype : str - 944 Format of the exported file. Supported formats include - 945 "json.gz" and "pickle" - 946 path : str - 947 specifies a custom path for the file (default '.') - 948 """ - 949 if datatype == "json.gz": - 950 from .input.json import dump_to_json - 951 if 'path' in kwargs: - 952 file_name = kwargs.get('path') + '/' + filename - 953 else: - 954 file_name = filename - 955 dump_to_json(self, file_name) - 956 elif datatype == "pickle": - 957 dump_object(self, filename, **kwargs) - 958 else: - 959 raise Exception("Unknown datatype " + str(datatype)) + 930 ax.set_xlabel(r'$x_0 / a$') + 931 plt.title(name) + 932 plt.draw() + 933 + 934 def dump(self, filename, datatype="json.gz", **kwargs): + 935 """Dumps the Corr into a file of chosen type + 936 Parameters + 937 ---------- + 938 filename : str + 939 Name of the file to be saved. + 940 datatype : str + 941 Format of the exported file. Supported formats include + 942 "json.gz" and "pickle" + 943 path : str + 944 specifies a custom path for the file (default '.') + 945 """ + 946 if datatype == "json.gz": + 947 from .input.json import dump_to_json + 948 if 'path' in kwargs: + 949 file_name = kwargs.get('path') + '/' + filename + 950 else: + 951 file_name = filename + 952 dump_to_json(self, file_name) + 953 elif datatype == "pickle": + 954 dump_object(self, filename, **kwargs) + 955 else: + 956 raise Exception("Unknown datatype " + str(datatype)) + 957 + 958 def print(self, print_range=None): + 959 print(self.__repr__(print_range)) 960 - 961 def print(self, print_range=None): - 962 print(self.__repr__(print_range)) - 963 - 964 def __repr__(self, print_range=None): - 965 if print_range is None: - 966 print_range = [0, None] + 961 def __repr__(self, print_range=None): + 962 if print_range is None: + 963 print_range = [0, None] + 964 + 965 content_string = "" + 966 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 967 - 968 content_string = "" - 969 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 - 970 - 971 if self.tag is not None: - 972 content_string += "Description: " + self.tag + "\n" - 973 if self.N != 1: - 974 return content_string - 975 - 976 if print_range[1]: - 977 print_range[1] += 1 - 978 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' - 979 for i, sub_corr in enumerate(self.content[print_range[0]:print_range[1]]): - 980 if sub_corr is None: - 981 content_string += str(i + print_range[0]) + '\n' - 982 else: - 983 content_string += str(i + print_range[0]) - 984 for element in sub_corr: - 985 content_string += '\t' + ' ' * int(element >= 0) + str(element) - 986 content_string += '\n' - 987 return content_string + 968 if self.tag is not None: + 969 content_string += "Description: " + self.tag + "\n" + 970 if self.N != 1: + 971 return content_string + 972 + 973 if print_range[1]: + 974 print_range[1] += 1 + 975 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' + 976 for i, sub_corr in enumerate(self.content[print_range[0]:print_range[1]]): + 977 if sub_corr is None: + 978 content_string += str(i + print_range[0]) + '\n' + 979 else: + 980 content_string += str(i + print_range[0]) + 981 for element in sub_corr: + 982 content_string += '\t' + ' ' * int(element >= 0) + str(element) + 983 content_string += '\n' + 984 return content_string + 985 + 986 def __str__(self): + 987 return self.__repr__() 988 - 989 def __str__(self): - 990 return self.__repr__() - 991 - 992 # We define the basic operations, that can be performed with correlators. - 993 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. - 994 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. - 995 # One could try and tell Obs to check if the y in __mul__ is a Corr and - 996 - 997 def __add__(self, y): - 998 if isinstance(y, Corr): - 999 if ((self.N != y.N) or (self.T != y.T)): -1000 raise Exception("Addition of Corrs with different shape") -1001 newcontent = [] -1002 for t in range(self.T): -1003 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): -1004 newcontent.append(None) -1005 else: -1006 newcontent.append(self.content[t] + y.content[t]) -1007 return Corr(newcontent) -1008 -1009 elif isinstance(y, (Obs, int, float, CObs)): -1010 newcontent = [] -1011 for t in range(self.T): -1012 if _check_for_none(self, self.content[t]): -1013 newcontent.append(None) -1014 else: -1015 newcontent.append(self.content[t] + y) -1016 return Corr(newcontent, prange=self.prange) -1017 elif isinstance(y, np.ndarray): -1018 if y.shape == (self.T,): -1019 return Corr(list((np.array(self.content).T + y).T)) -1020 else: -1021 raise ValueError("operands could not be broadcast together") -1022 else: -1023 raise TypeError("Corr + wrong type") -1024 -1025 def __mul__(self, y): -1026 if isinstance(y, Corr): -1027 if not ((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): -1028 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") -1029 newcontent = [] -1030 for t in range(self.T): -1031 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): -1032 newcontent.append(None) -1033 else: -1034 newcontent.append(self.content[t] * y.content[t]) -1035 return Corr(newcontent) -1036 -1037 elif isinstance(y, (Obs, int, float, CObs)): -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 __truediv__(self, y): -1054 if isinstance(y, Corr): -1055 if not ((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): -1056 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") -1057 newcontent = [] -1058 for t in range(self.T): -1059 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): -1060 newcontent.append(None) -1061 else: -1062 newcontent.append(self.content[t] / y.content[t]) -1063 for t in range(self.T): -1064 if _check_for_none(self, newcontent[t]): -1065 continue -1066 if np.isnan(np.sum(newcontent[t]).value): -1067 newcontent[t] = None -1068 -1069 if all([item is None for item in newcontent]): -1070 raise Exception("Division returns completely undefined correlator") -1071 return Corr(newcontent) -1072 -1073 elif isinstance(y, (Obs, CObs)): -1074 if isinstance(y, Obs): -1075 if y.value == 0: + 989 # We define the basic operations, that can be performed with correlators. + 990 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. + 991 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. + 992 # One could try and tell Obs to check if the y in __mul__ is a Corr and + 993 + 994 def __add__(self, y): + 995 if isinstance(y, Corr): + 996 if ((self.N != y.N) or (self.T != y.T)): + 997 raise Exception("Addition of Corrs with different shape") + 998 newcontent = [] + 999 for t in range(self.T): +1000 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): +1001 newcontent.append(None) +1002 else: +1003 newcontent.append(self.content[t] + y.content[t]) +1004 return Corr(newcontent) +1005 +1006 elif isinstance(y, (Obs, int, float, CObs)): +1007 newcontent = [] +1008 for t in range(self.T): +1009 if _check_for_none(self, self.content[t]): +1010 newcontent.append(None) +1011 else: +1012 newcontent.append(self.content[t] + y) +1013 return Corr(newcontent, prange=self.prange) +1014 elif isinstance(y, np.ndarray): +1015 if y.shape == (self.T,): +1016 return Corr(list((np.array(self.content).T + y).T)) +1017 else: +1018 raise ValueError("operands could not be broadcast together") +1019 else: +1020 raise TypeError("Corr + wrong type") +1021 +1022 def __mul__(self, y): +1023 if isinstance(y, Corr): +1024 if not ((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): +1025 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") +1026 newcontent = [] +1027 for t in range(self.T): +1028 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): +1029 newcontent.append(None) +1030 else: +1031 newcontent.append(self.content[t] * y.content[t]) +1032 return Corr(newcontent) +1033 +1034 elif isinstance(y, (Obs, int, float, CObs)): +1035 newcontent = [] +1036 for t in range(self.T): +1037 if _check_for_none(self, self.content[t]): +1038 newcontent.append(None) +1039 else: +1040 newcontent.append(self.content[t] * y) +1041 return Corr(newcontent, prange=self.prange) +1042 elif isinstance(y, np.ndarray): +1043 if y.shape == (self.T,): +1044 return Corr(list((np.array(self.content).T * y).T)) +1045 else: +1046 raise ValueError("operands could not be broadcast together") +1047 else: +1048 raise TypeError("Corr * wrong type") +1049 +1050 def __truediv__(self, y): +1051 if isinstance(y, Corr): +1052 if not ((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): +1053 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") +1054 newcontent = [] +1055 for t in range(self.T): +1056 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): +1057 newcontent.append(None) +1058 else: +1059 newcontent.append(self.content[t] / y.content[t]) +1060 for t in range(self.T): +1061 if _check_for_none(self, newcontent[t]): +1062 continue +1063 if np.isnan(np.sum(newcontent[t]).value): +1064 newcontent[t] = None +1065 +1066 if all([item is None for item in newcontent]): +1067 raise Exception("Division returns completely undefined correlator") +1068 return Corr(newcontent) +1069 +1070 elif isinstance(y, (Obs, CObs)): +1071 if isinstance(y, Obs): +1072 if y.value == 0: +1073 raise Exception('Division by zero will return undefined correlator') +1074 if isinstance(y, CObs): +1075 if y.is_zero(): 1076 raise Exception('Division by zero will return undefined correlator') -1077 if isinstance(y, CObs): -1078 if y.is_zero(): -1079 raise Exception('Division by zero will return undefined correlator') -1080 -1081 newcontent = [] -1082 for t in range(self.T): -1083 if _check_for_none(self, self.content[t]): -1084 newcontent.append(None) -1085 else: -1086 newcontent.append(self.content[t] / y) -1087 return Corr(newcontent, prange=self.prange) -1088 -1089 elif isinstance(y, (int, float)): -1090 if y == 0: -1091 raise Exception('Division by zero will return undefined correlator') -1092 newcontent = [] -1093 for t in range(self.T): -1094 if _check_for_none(self, self.content[t]): -1095 newcontent.append(None) -1096 else: -1097 newcontent.append(self.content[t] / y) -1098 return Corr(newcontent, prange=self.prange) -1099 elif isinstance(y, np.ndarray): -1100 if y.shape == (self.T,): -1101 return Corr(list((np.array(self.content).T / y).T)) -1102 else: -1103 raise ValueError("operands could not be broadcast together") -1104 else: -1105 raise TypeError('Corr / wrong type') -1106 -1107 def __neg__(self): -1108 newcontent = [None if _check_for_none(self, item) else -1. * item for item in self.content] -1109 return Corr(newcontent, prange=self.prange) +1077 +1078 newcontent = [] +1079 for t in range(self.T): +1080 if _check_for_none(self, self.content[t]): +1081 newcontent.append(None) +1082 else: +1083 newcontent.append(self.content[t] / y) +1084 return Corr(newcontent, prange=self.prange) +1085 +1086 elif isinstance(y, (int, float)): +1087 if y == 0: +1088 raise Exception('Division by zero will return undefined correlator') +1089 newcontent = [] +1090 for t in range(self.T): +1091 if _check_for_none(self, self.content[t]): +1092 newcontent.append(None) +1093 else: +1094 newcontent.append(self.content[t] / y) +1095 return Corr(newcontent, prange=self.prange) +1096 elif isinstance(y, np.ndarray): +1097 if y.shape == (self.T,): +1098 return Corr(list((np.array(self.content).T / y).T)) +1099 else: +1100 raise ValueError("operands could not be broadcast together") +1101 else: +1102 raise TypeError('Corr / wrong type') +1103 +1104 def __neg__(self): +1105 newcontent = [None if _check_for_none(self, item) else -1. * item for item in self.content] +1106 return Corr(newcontent, prange=self.prange) +1107 +1108 def __sub__(self, y): +1109 return self + (-y) 1110 -1111 def __sub__(self, y): -1112 return self + (-y) -1113 -1114 def __pow__(self, y): -1115 if isinstance(y, (Obs, int, float, CObs)): -1116 newcontent = [None if _check_for_none(self, item) else item**y for item in self.content] -1117 return Corr(newcontent, prange=self.prange) -1118 else: -1119 raise TypeError('Type of exponent not supported') -1120 -1121 def __abs__(self): -1122 newcontent = [None if _check_for_none(self, item) else np.abs(item) for item in self.content] -1123 return Corr(newcontent, prange=self.prange) -1124 -1125 # The numpy functions: -1126 def sqrt(self): -1127 return self ** 0.5 -1128 -1129 def log(self): -1130 newcontent = [None if _check_for_none(self, item) else np.log(item) for item in self.content] -1131 return Corr(newcontent, prange=self.prange) -1132 -1133 def exp(self): -1134 newcontent = [None if _check_for_none(self, item) else np.exp(item) for item in self.content] -1135 return Corr(newcontent, prange=self.prange) -1136 -1137 def _apply_func_to_corr(self, func): -1138 newcontent = [None if _check_for_none(self, item) else func(item) for item in self.content] -1139 for t in range(self.T): -1140 if _check_for_none(self, newcontent[t]): -1141 continue -1142 if np.isnan(np.sum(newcontent[t]).value): -1143 newcontent[t] = None -1144 if all([item is None for item in newcontent]): -1145 raise Exception('Operation returns undefined correlator') -1146 return Corr(newcontent) +1111 def __pow__(self, y): +1112 if isinstance(y, (Obs, int, float, CObs)): +1113 newcontent = [None if _check_for_none(self, item) else item**y for item in self.content] +1114 return Corr(newcontent, prange=self.prange) +1115 else: +1116 raise TypeError('Type of exponent not supported') +1117 +1118 def __abs__(self): +1119 newcontent = [None if _check_for_none(self, item) else np.abs(item) for item in self.content] +1120 return Corr(newcontent, prange=self.prange) +1121 +1122 # The numpy functions: +1123 def sqrt(self): +1124 return self ** 0.5 +1125 +1126 def log(self): +1127 newcontent = [None if _check_for_none(self, item) else np.log(item) for item in self.content] +1128 return Corr(newcontent, prange=self.prange) +1129 +1130 def exp(self): +1131 newcontent = [None if _check_for_none(self, item) else np.exp(item) for item in self.content] +1132 return Corr(newcontent, prange=self.prange) +1133 +1134 def _apply_func_to_corr(self, func): +1135 newcontent = [None if _check_for_none(self, item) else func(item) for item in self.content] +1136 for t in range(self.T): +1137 if _check_for_none(self, newcontent[t]): +1138 continue +1139 if np.isnan(np.sum(newcontent[t]).value): +1140 newcontent[t] = None +1141 if all([item is None for item in newcontent]): +1142 raise Exception('Operation returns undefined correlator') +1143 return Corr(newcontent) +1144 +1145 def sin(self): +1146 return self._apply_func_to_corr(np.sin) 1147 -1148 def sin(self): -1149 return self._apply_func_to_corr(np.sin) +1148 def cos(self): +1149 return self._apply_func_to_corr(np.cos) 1150 -1151 def cos(self): -1152 return self._apply_func_to_corr(np.cos) +1151 def tan(self): +1152 return self._apply_func_to_corr(np.tan) 1153 -1154 def tan(self): -1155 return self._apply_func_to_corr(np.tan) +1154 def sinh(self): +1155 return self._apply_func_to_corr(np.sinh) 1156 -1157 def sinh(self): -1158 return self._apply_func_to_corr(np.sinh) +1157 def cosh(self): +1158 return self._apply_func_to_corr(np.cosh) 1159 -1160 def cosh(self): -1161 return self._apply_func_to_corr(np.cosh) +1160 def tanh(self): +1161 return self._apply_func_to_corr(np.tanh) 1162 -1163 def tanh(self): -1164 return self._apply_func_to_corr(np.tanh) +1163 def arcsin(self): +1164 return self._apply_func_to_corr(np.arcsin) 1165 -1166 def arcsin(self): -1167 return self._apply_func_to_corr(np.arcsin) +1166 def arccos(self): +1167 return self._apply_func_to_corr(np.arccos) 1168 -1169 def arccos(self): -1170 return self._apply_func_to_corr(np.arccos) +1169 def arctan(self): +1170 return self._apply_func_to_corr(np.arctan) 1171 -1172 def arctan(self): -1173 return self._apply_func_to_corr(np.arctan) +1172 def arcsinh(self): +1173 return self._apply_func_to_corr(np.arcsinh) 1174 -1175 def arcsinh(self): -1176 return self._apply_func_to_corr(np.arcsinh) +1175 def arccosh(self): +1176 return self._apply_func_to_corr(np.arccosh) 1177 -1178 def arccosh(self): -1179 return self._apply_func_to_corr(np.arccosh) +1178 def arctanh(self): +1179 return self._apply_func_to_corr(np.arctanh) 1180 -1181 def arctanh(self): -1182 return self._apply_func_to_corr(np.arctanh) -1183 -1184 # Right hand side operations (require tweak in main module to work) -1185 def __radd__(self, y): -1186 return self + y +1181 # Right hand side operations (require tweak in main module to work) +1182 def __radd__(self, y): +1183 return self + y +1184 +1185 def __rsub__(self, y): +1186 return -self + y 1187 -1188 def __rsub__(self, y): -1189 return -self + y +1188 def __rmul__(self, y): +1189 return self * y 1190 -1191 def __rmul__(self, y): -1192 return self * y +1191 def __rtruediv__(self, y): +1192 return (self / y) ** (-1) 1193 -1194 def __rtruediv__(self, y): -1195 return (self / y) ** (-1) -1196 -1197 @property -1198 def real(self): -1199 def return_real(obs_OR_cobs): -1200 if isinstance(obs_OR_cobs, CObs): -1201 return obs_OR_cobs.real -1202 else: -1203 return obs_OR_cobs -1204 -1205 return self._apply_func_to_corr(return_real) -1206 -1207 @property -1208 def imag(self): -1209 def return_imag(obs_OR_cobs): -1210 if isinstance(obs_OR_cobs, CObs): -1211 return obs_OR_cobs.imag -1212 else: -1213 return obs_OR_cobs * 0 # So it stays the right type -1214 -1215 return self._apply_func_to_corr(return_imag) +1194 @property +1195 def real(self): +1196 def return_real(obs_OR_cobs): +1197 if isinstance(obs_OR_cobs, CObs): +1198 return obs_OR_cobs.real +1199 else: +1200 return obs_OR_cobs +1201 +1202 return self._apply_func_to_corr(return_real) +1203 +1204 @property +1205 def imag(self): +1206 def return_imag(obs_OR_cobs): +1207 if isinstance(obs_OR_cobs, CObs): +1208 return obs_OR_cobs.imag +1209 else: +1210 return obs_OR_cobs * 0 # So it stays the right type +1211 +1212 return self._apply_func_to_corr(return_imag) +1213 +1214 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): +1215 r''' Project large correlation matrix to lowest states 1216 -1217 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): -1218 r''' Project large correlation matrix to lowest states -1219 -1220 This method can be used to reduce the size of an (N x N) correlation matrix -1221 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise -1222 is still small. -1223 -1224 Parameters -1225 ---------- -1226 Ntrunc: int -1227 Rank of the target matrix. -1228 tproj: int -1229 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. -1230 The default value is 3. -1231 t0proj: int -1232 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly -1233 discouraged for O(a) improved theories, since the correctness of the procedure -1234 cannot be granted in this case. The default value is 2. -1235 basematrix : Corr -1236 Correlation matrix that is used to determine the eigenvectors of the -1237 lowest states based on a GEVP. basematrix is taken to be the Corr itself if -1238 is is not specified. -1239 -1240 Notes -1241 ----- -1242 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving -1243 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}$ -1244 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the -1245 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via -1246 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large -1247 correlation matrix and to remove some noise that is added by irrelevant operators. -1248 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated -1249 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. -1250 ''' -1251 -1252 if self.N == 1: -1253 raise Exception('Method cannot be applied to one-dimensional correlators.') -1254 if basematrix is None: -1255 basematrix = self -1256 if Ntrunc >= basematrix.N: -1257 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) -1258 if basematrix.N != self.N: -1259 raise Exception('basematrix and targetmatrix have to be of the same size.') -1260 -1261 evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc] -1262 -1263 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) -1264 rmat = [] -1265 for t in range(basematrix.T): -1266 for i in range(Ntrunc): -1267 for j in range(Ntrunc): -1268 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] -1269 rmat.append(np.copy(tmpmat)) +1217 This method can be used to reduce the size of an (N x N) correlation matrix +1218 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise +1219 is still small. +1220 +1221 Parameters +1222 ---------- +1223 Ntrunc: int +1224 Rank of the target matrix. +1225 tproj: int +1226 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. +1227 The default value is 3. +1228 t0proj: int +1229 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly +1230 discouraged for O(a) improved theories, since the correctness of the procedure +1231 cannot be granted in this case. The default value is 2. +1232 basematrix : Corr +1233 Correlation matrix that is used to determine the eigenvectors of the +1234 lowest states based on a GEVP. basematrix is taken to be the Corr itself if +1235 is is not specified. +1236 +1237 Notes +1238 ----- +1239 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving +1240 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}$ +1241 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the +1242 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via +1243 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large +1244 correlation matrix and to remove some noise that is added by irrelevant operators. +1245 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated +1246 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. +1247 ''' +1248 +1249 if self.N == 1: +1250 raise Exception('Method cannot be applied to one-dimensional correlators.') +1251 if basematrix is None: +1252 basematrix = self +1253 if Ntrunc >= basematrix.N: +1254 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) +1255 if basematrix.N != self.N: +1256 raise Exception('basematrix and targetmatrix have to be of the same size.') +1257 +1258 evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc] +1259 +1260 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) +1261 rmat = [] +1262 for t in range(basematrix.T): +1263 for i in range(Ntrunc): +1264 for j in range(Ntrunc): +1265 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] +1266 rmat.append(np.copy(tmpmat)) +1267 +1268 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] +1269 return Corr(newcontent) 1270 -1271 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] -1272 return Corr(newcontent) -1273 -1274 -1275def _sort_vectors(vec_set, ts): -1276 """Helper function used to find a set of Eigenvectors consistent over all timeslices""" -1277 reference_sorting = np.array(vec_set[ts]) -1278 N = reference_sorting.shape[0] -1279 sorted_vec_set = [] -1280 for t in range(len(vec_set)): -1281 if vec_set[t] is None: -1282 sorted_vec_set.append(None) -1283 elif not t == ts: -1284 perms = [list(o) for o in permutations([i for i in range(N)], N)] -1285 best_score = 0 -1286 for perm in perms: -1287 current_score = 1 -1288 for k in range(N): -1289 new_sorting = reference_sorting.copy() -1290 new_sorting[perm[k], :] = vec_set[t][k] -1291 current_score *= abs(np.linalg.det(new_sorting)) -1292 if current_score > best_score: -1293 best_score = current_score -1294 best_perm = perm -1295 sorted_vec_set.append([vec_set[t][k] for k in best_perm]) -1296 else: -1297 sorted_vec_set.append(vec_set[t]) +1271 +1272def _sort_vectors(vec_set, ts): +1273 """Helper function used to find a set of Eigenvectors consistent over all timeslices""" +1274 reference_sorting = np.array(vec_set[ts]) +1275 N = reference_sorting.shape[0] +1276 sorted_vec_set = [] +1277 for t in range(len(vec_set)): +1278 if vec_set[t] is None: +1279 sorted_vec_set.append(None) +1280 elif not t == ts: +1281 perms = [list(o) for o in permutations([i for i in range(N)], N)] +1282 best_score = 0 +1283 for perm in perms: +1284 current_score = 1 +1285 for k in range(N): +1286 new_sorting = reference_sorting.copy() +1287 new_sorting[perm[k], :] = vec_set[t][k] +1288 current_score *= abs(np.linalg.det(new_sorting)) +1289 if current_score > best_score: +1290 best_score = current_score +1291 best_perm = perm +1292 sorted_vec_set.append([vec_set[t][k] for k in best_perm]) +1293 else: +1294 sorted_vec_set.append(vec_set[t]) +1295 +1296 return sorted_vec_set +1297 1298 -1299 return sorted_vec_set -1300 -1301 -1302def _check_for_none(corr, entry): -1303 """Checks if entry for correlator corr is None""" -1304 return len(list(filter(None, np.asarray(entry).flatten()))) < corr.N ** 2 -1305 +1299def _check_for_none(corr, entry): +1300 """Checks if entry for correlator corr is None""" +1301 return len(list(filter(None, np.asarray(entry).flatten()))) < corr.N ** 2 +1302 +1303 +1304def _GEVP_solver(Gt, G0): +1305 """Helper function for solving the GEVP and sorting the eigenvectors. 1306 -1307def _GEVP_solver(Gt, G0): -1308 """Helper function for solving the GEVP and sorting the eigenvectors. -1309 -1310 The helper function assumes that both provided matrices are symmetric and -1311 only processes the lower triangular part of both matrices. In case the matrices -1312 are not symmetric the upper triangular parts are effectively discarded.""" -1313 return scipy.linalg.eigh(Gt, G0, lower=True)[1].T[::-1] +1307 The helper function assumes that both provided matrices are symmetric and +1308 only processes the lower triangular part of both matrices. In case the matrices +1309 are not symmetric the upper triangular parts are effectively discarded.""" +1310 return scipy.linalg.eigh(Gt, G0, lower=True)[1].T[::-1] @@ -1598,1207 +1595,1204 @@ 70 71 if isinstance(data_input, list): 72 - 73 if all([isinstance(item, (Obs, CObs)) for item in data_input]): - 74 _assert_equal_properties(data_input) - 75 self.content = [np.asarray([item]) for item in data_input] - 76 if all([isinstance(item, (Obs, CObs)) or item is None for item in data_input]): - 77 _assert_equal_properties([o for o in data_input if o is not None]) - 78 self.content = [np.asarray([item]) if item is not None else None for item in data_input] - 79 self.N = 1 - 80 - 81 elif all([isinstance(item, np.ndarray) or item is None for item in data_input]) and any([isinstance(item, np.ndarray) for item in data_input]): - 82 self.content = data_input - 83 noNull = [a for a in self.content if not (a is None)] # To check if the matrices are correct for all undefined elements - 84 self.N = noNull[0].shape[0] - 85 if self.N > 1 and noNull[0].shape[0] != noNull[0].shape[1]: - 86 raise Exception("Smearing matrices are not NxN") - 87 if (not all([item.shape == noNull[0].shape for item in noNull])): - 88 raise Exception("Items in data_input are not of identical shape." + str(noNull)) - 89 else: - 90 raise Exception("data_input contains item of wrong type") - 91 else: - 92 raise Exception("Data input was not given as list or correct array") - 93 - 94 self.tag = None - 95 - 96 # An undefined timeslice is represented by the None object - 97 self.content = [None] * padding[0] + self.content + [None] * padding[1] - 98 self.T = len(self.content) - 99 self.prange = prange - 100 - 101 def __getitem__(self, idx): - 102 """Return the content of timeslice idx""" - 103 if self.content[idx] is None: - 104 return None - 105 elif len(self.content[idx]) == 1: - 106 return self.content[idx][0] - 107 else: - 108 return self.content[idx] - 109 - 110 @property - 111 def reweighted(self): - 112 bool_array = np.array([list(map(lambda x: x.reweighted, o)) for o in [x for x in self.content if x is not None]]) - 113 if np.all(bool_array == 1): - 114 return True - 115 elif np.all(bool_array == 0): - 116 return False - 117 else: - 118 raise Exception("Reweighting status of correlator corrupted.") - 119 - 120 def gamma_method(self, **kwargs): - 121 """Apply the gamma method to the content of the Corr.""" - 122 for item in self.content: - 123 if not (item is None): - 124 if self.N == 1: - 125 item[0].gamma_method(**kwargs) - 126 else: - 127 for i in range(self.N): - 128 for j in range(self.N): - 129 item[i, j].gamma_method(**kwargs) + 73 if all([isinstance(item, (Obs, CObs)) or item is None for item in data_input]): + 74 _assert_equal_properties([o for o in data_input if o is not None]) + 75 self.content = [np.asarray([item]) if item is not None else None for item in data_input] + 76 self.N = 1 + 77 + 78 elif all([isinstance(item, np.ndarray) or item is None for item in data_input]) and any([isinstance(item, np.ndarray) for item in data_input]): + 79 self.content = data_input + 80 noNull = [a for a in self.content if not (a is None)] # To check if the matrices are correct for all undefined elements + 81 self.N = noNull[0].shape[0] + 82 if self.N > 1 and noNull[0].shape[0] != noNull[0].shape[1]: + 83 raise Exception("Smearing matrices are not NxN") + 84 if (not all([item.shape == noNull[0].shape for item in noNull])): + 85 raise Exception("Items in data_input are not of identical shape." + str(noNull)) + 86 else: + 87 raise Exception("data_input contains item of wrong type") + 88 else: + 89 raise Exception("Data input was not given as list or correct array") + 90 + 91 self.tag = None + 92 + 93 # An undefined timeslice is represented by the None object + 94 self.content = [None] * padding[0] + self.content + [None] * padding[1] + 95 self.T = len(self.content) + 96 self.prange = prange + 97 + 98 def __getitem__(self, idx): + 99 """Return the content of timeslice idx""" + 100 if self.content[idx] is None: + 101 return None + 102 elif len(self.content[idx]) == 1: + 103 return self.content[idx][0] + 104 else: + 105 return self.content[idx] + 106 + 107 @property + 108 def reweighted(self): + 109 bool_array = np.array([list(map(lambda x: x.reweighted, o)) for o in [x for x in self.content if x is not None]]) + 110 if np.all(bool_array == 1): + 111 return True + 112 elif np.all(bool_array == 0): + 113 return False + 114 else: + 115 raise Exception("Reweighting status of correlator corrupted.") + 116 + 117 def gamma_method(self, **kwargs): + 118 """Apply the gamma method to the content of the Corr.""" + 119 for item in self.content: + 120 if not (item is None): + 121 if self.N == 1: + 122 item[0].gamma_method(**kwargs) + 123 else: + 124 for i in range(self.N): + 125 for j in range(self.N): + 126 item[i, j].gamma_method(**kwargs) + 127 + 128 def projected(self, vector_l=None, vector_r=None, normalize=False): + 129 """We need to project the Correlator with a Vector to get a single value at each timeslice. 130 - 131 def projected(self, vector_l=None, vector_r=None, normalize=False): - 132 """We need to project the Correlator with a Vector to get a single value at each timeslice. - 133 - 134 The method can use one or two vectors. - 135 If two are specified it returns v1@G@v2 (the order might be very important.) - 136 By default it will return the lowest source, which usually means unsmeared-unsmeared (0,0), but it does not have to - 137 """ - 138 if self.N == 1: - 139 raise Exception("Trying to project a Corr, that already has N=1.") - 140 - 141 if vector_l is None: - 142 vector_l, vector_r = np.asarray([1.] + (self.N - 1) * [0.]), np.asarray([1.] + (self.N - 1) * [0.]) - 143 elif (vector_r is None): - 144 vector_r = vector_l - 145 if isinstance(vector_l, list) and not isinstance(vector_r, list): - 146 if len(vector_l) != self.T: - 147 raise Exception("Length of vector list must be equal to T") - 148 vector_r = [vector_r] * self.T - 149 if isinstance(vector_r, list) and not isinstance(vector_l, list): - 150 if len(vector_r) != self.T: - 151 raise Exception("Length of vector list must be equal to T") - 152 vector_l = [vector_l] * self.T - 153 - 154 if not isinstance(vector_l, list): - 155 if not vector_l.shape == vector_r.shape == (self.N,): - 156 raise Exception("Vectors are of wrong shape!") - 157 if normalize: - 158 vector_l, vector_r = vector_l / np.sqrt((vector_l @ vector_l)), vector_r / np.sqrt(vector_r @ vector_r) - 159 newcontent = [None if _check_for_none(self, item) else np.asarray([vector_l.T @ item @ vector_r]) for item in self.content] - 160 - 161 else: - 162 # There are no checks here yet. There are so many possible scenarios, where this can go wrong. - 163 if normalize: - 164 for t in range(self.T): - 165 vector_l[t], vector_r[t] = vector_l[t] / np.sqrt((vector_l[t] @ vector_l[t])), vector_r[t] / np.sqrt(vector_r[t] @ vector_r[t]) + 131 The method can use one or two vectors. + 132 If two are specified it returns v1@G@v2 (the order might be very important.) + 133 By default it will return the lowest source, which usually means unsmeared-unsmeared (0,0), but it does not have to + 134 """ + 135 if self.N == 1: + 136 raise Exception("Trying to project a Corr, that already has N=1.") + 137 + 138 if vector_l is None: + 139 vector_l, vector_r = np.asarray([1.] + (self.N - 1) * [0.]), np.asarray([1.] + (self.N - 1) * [0.]) + 140 elif (vector_r is None): + 141 vector_r = vector_l + 142 if isinstance(vector_l, list) and not isinstance(vector_r, list): + 143 if len(vector_l) != self.T: + 144 raise Exception("Length of vector list must be equal to T") + 145 vector_r = [vector_r] * self.T + 146 if isinstance(vector_r, list) and not isinstance(vector_l, list): + 147 if len(vector_r) != self.T: + 148 raise Exception("Length of vector list must be equal to T") + 149 vector_l = [vector_l] * self.T + 150 + 151 if not isinstance(vector_l, list): + 152 if not vector_l.shape == vector_r.shape == (self.N,): + 153 raise Exception("Vectors are of wrong shape!") + 154 if normalize: + 155 vector_l, vector_r = vector_l / np.sqrt((vector_l @ vector_l)), vector_r / np.sqrt(vector_r @ vector_r) + 156 newcontent = [None if _check_for_none(self, item) else np.asarray([vector_l.T @ item @ vector_r]) for item in self.content] + 157 + 158 else: + 159 # There are no checks here yet. There are so many possible scenarios, where this can go wrong. + 160 if normalize: + 161 for t in range(self.T): + 162 vector_l[t], vector_r[t] = vector_l[t] / np.sqrt((vector_l[t] @ vector_l[t])), vector_r[t] / np.sqrt(vector_r[t] @ vector_r[t]) + 163 + 164 newcontent = [None if (_check_for_none(self, self.content[t]) or vector_l[t] is None or vector_r[t] is None) else np.asarray([vector_l[t].T @ self.content[t] @ vector_r[t]]) for t in range(self.T)] + 165 return Corr(newcontent) 166 - 167 newcontent = [None if (_check_for_none(self, self.content[t]) or vector_l[t] is None or vector_r[t] is None) else np.asarray([vector_l[t].T @ self.content[t] @ vector_r[t]]) for t in range(self.T)] - 168 return Corr(newcontent) + 167 def item(self, i, j): + 168 """Picks the element [i,j] from every matrix and returns a correlator containing one Obs per timeslice. 169 - 170 def item(self, i, j): - 171 """Picks the element [i,j] from every matrix and returns a correlator containing one Obs per timeslice. - 172 - 173 Parameters - 174 ---------- - 175 i : int - 176 First index to be picked. - 177 j : int - 178 Second index to be picked. - 179 """ - 180 if self.N == 1: - 181 raise Exception("Trying to pick item from projected Corr") - 182 newcontent = [None if (item is None) else item[i, j] for item in self.content] - 183 return Corr(newcontent) + 170 Parameters + 171 ---------- + 172 i : int + 173 First index to be picked. + 174 j : int + 175 Second index to be picked. + 176 """ + 177 if self.N == 1: + 178 raise Exception("Trying to pick item from projected Corr") + 179 newcontent = [None if (item is None) else item[i, j] for item in self.content] + 180 return Corr(newcontent) + 181 + 182 def plottable(self): + 183 """Outputs the correlator in a plotable format. 184 - 185 def plottable(self): - 186 """Outputs the correlator in a plotable format. - 187 - 188 Outputs three lists containing the timeslice index, the value on each - 189 timeslice and the error on each timeslice. - 190 """ - 191 if self.N != 1: - 192 raise Exception("Can only make Corr[N=1] plottable") - 193 x_list = [x for x in range(self.T) if not self.content[x] is None] - 194 y_list = [y[0].value for y in self.content if y is not None] - 195 y_err_list = [y[0].dvalue for y in self.content if y is not None] - 196 - 197 return x_list, y_list, y_err_list - 198 - 199 def symmetric(self): - 200 """ Symmetrize the correlator around x0=0.""" - 201 if self.N != 1: - 202 raise Exception('symmetric cannot be safely applied to multi-dimensional correlators.') - 203 if self.T % 2 != 0: - 204 raise Exception("Can not symmetrize odd T") + 185 Outputs three lists containing the timeslice index, the value on each + 186 timeslice and the error on each timeslice. + 187 """ + 188 if self.N != 1: + 189 raise Exception("Can only make Corr[N=1] plottable") + 190 x_list = [x for x in range(self.T) if not self.content[x] is None] + 191 y_list = [y[0].value for y in self.content if y is not None] + 192 y_err_list = [y[0].dvalue for y in self.content if y is not None] + 193 + 194 return x_list, y_list, y_err_list + 195 + 196 def symmetric(self): + 197 """ Symmetrize the correlator around x0=0.""" + 198 if self.N != 1: + 199 raise Exception('symmetric cannot be safely applied to multi-dimensional correlators.') + 200 if self.T % 2 != 0: + 201 raise Exception("Can not symmetrize odd T") + 202 + 203 if np.argmax(np.abs(self.content)) != 0: + 204 warnings.warn("Correlator does not seem to be symmetric around x0=0.", RuntimeWarning) 205 - 206 if np.argmax(np.abs(self.content)) != 0: - 207 warnings.warn("Correlator does not seem to be symmetric around x0=0.", RuntimeWarning) - 208 - 209 newcontent = [self.content[0]] - 210 for t in range(1, self.T): - 211 if (self.content[t] is None) or (self.content[self.T - t] is None): - 212 newcontent.append(None) - 213 else: - 214 newcontent.append(0.5 * (self.content[t] + self.content[self.T - t])) - 215 if (all([x is None for x in newcontent])): - 216 raise Exception("Corr could not be symmetrized: No redundant values") - 217 return Corr(newcontent, prange=self.prange) - 218 - 219 def anti_symmetric(self): - 220 """Anti-symmetrize the correlator around x0=0.""" - 221 if self.N != 1: - 222 raise Exception('anti_symmetric cannot be safely applied to multi-dimensional correlators.') - 223 if self.T % 2 != 0: - 224 raise Exception("Can not symmetrize odd T") - 225 - 226 test = 1 * self - 227 test.gamma_method() - 228 if not all([o.is_zero_within_error(3) for o in test.content[0]]): - 229 warnings.warn("Correlator does not seem to be anti-symmetric around x0=0.", RuntimeWarning) - 230 - 231 newcontent = [self.content[0]] - 232 for t in range(1, self.T): - 233 if (self.content[t] is None) or (self.content[self.T - t] is None): - 234 newcontent.append(None) - 235 else: - 236 newcontent.append(0.5 * (self.content[t] - self.content[self.T - t])) - 237 if (all([x is None for x in newcontent])): - 238 raise Exception("Corr could not be symmetrized: No redundant values") - 239 return Corr(newcontent, prange=self.prange) - 240 - 241 def is_matrix_symmetric(self): - 242 """Checks whether a correlator matrices is symmetric on every timeslice.""" - 243 if self.N == 1: - 244 raise Exception("Only works for correlator matrices.") - 245 for t in range(self.T): - 246 if self[t] is None: - 247 continue - 248 for i in range(self.N): - 249 for j in range(i + 1, self.N): - 250 if self[t][i, j] is self[t][j, i]: - 251 continue - 252 if hash(self[t][i, j]) != hash(self[t][j, i]): - 253 return False - 254 return True - 255 - 256 def matrix_symmetric(self): - 257 """Symmetrizes the correlator matrices on every timeslice.""" - 258 if self.N == 1: - 259 raise Exception("Trying to symmetrize a correlator matrix, that already has N=1.") - 260 if self.is_matrix_symmetric(): - 261 return 1.0 * self - 262 else: - 263 transposed = [None if _check_for_none(self, G) else G.T for G in self.content] - 264 return 0.5 * (Corr(transposed) + self) + 206 newcontent = [self.content[0]] + 207 for t in range(1, self.T): + 208 if (self.content[t] is None) or (self.content[self.T - t] is None): + 209 newcontent.append(None) + 210 else: + 211 newcontent.append(0.5 * (self.content[t] + self.content[self.T - t])) + 212 if (all([x is None for x in newcontent])): + 213 raise Exception("Corr could not be symmetrized: No redundant values") + 214 return Corr(newcontent, prange=self.prange) + 215 + 216 def anti_symmetric(self): + 217 """Anti-symmetrize the correlator around x0=0.""" + 218 if self.N != 1: + 219 raise Exception('anti_symmetric cannot be safely applied to multi-dimensional correlators.') + 220 if self.T % 2 != 0: + 221 raise Exception("Can not symmetrize odd T") + 222 + 223 test = 1 * self + 224 test.gamma_method() + 225 if not all([o.is_zero_within_error(3) for o in test.content[0]]): + 226 warnings.warn("Correlator does not seem to be anti-symmetric around x0=0.", RuntimeWarning) + 227 + 228 newcontent = [self.content[0]] + 229 for t in range(1, self.T): + 230 if (self.content[t] is None) or (self.content[self.T - t] is None): + 231 newcontent.append(None) + 232 else: + 233 newcontent.append(0.5 * (self.content[t] - self.content[self.T - t])) + 234 if (all([x is None for x in newcontent])): + 235 raise Exception("Corr could not be symmetrized: No redundant values") + 236 return Corr(newcontent, prange=self.prange) + 237 + 238 def is_matrix_symmetric(self): + 239 """Checks whether a correlator matrices is symmetric on every timeslice.""" + 240 if self.N == 1: + 241 raise Exception("Only works for correlator matrices.") + 242 for t in range(self.T): + 243 if self[t] is None: + 244 continue + 245 for i in range(self.N): + 246 for j in range(i + 1, self.N): + 247 if self[t][i, j] is self[t][j, i]: + 248 continue + 249 if hash(self[t][i, j]) != hash(self[t][j, i]): + 250 return False + 251 return True + 252 + 253 def matrix_symmetric(self): + 254 """Symmetrizes the correlator matrices on every timeslice.""" + 255 if self.N == 1: + 256 raise Exception("Trying to symmetrize a correlator matrix, that already has N=1.") + 257 if self.is_matrix_symmetric(): + 258 return 1.0 * self + 259 else: + 260 transposed = [None if _check_for_none(self, G) else G.T for G in self.content] + 261 return 0.5 * (Corr(transposed) + self) + 262 + 263 def GEVP(self, t0, ts=None, sort="Eigenvalue", **kwargs): + 264 r'''Solve the generalized eigenvalue problem on the correlator matrix and returns the corresponding eigenvectors. 265 - 266 def GEVP(self, t0, ts=None, sort="Eigenvalue", **kwargs): - 267 r'''Solve the generalized eigenvalue problem on the correlator matrix and returns the corresponding eigenvectors. - 268 - 269 The eigenvectors are sorted according to the descending eigenvalues, the zeroth eigenvector(s) correspond to the - 270 largest eigenvalue(s). The eigenvector(s) for the individual states can be accessed via slicing - 271 ```python - 272 C.GEVP(t0=2)[0] # Ground state vector(s) - 273 C.GEVP(t0=2)[:3] # Vectors for the lowest three states - 274 ``` - 275 - 276 Parameters - 277 ---------- - 278 t0 : int - 279 The time t0 for the right hand side of the GEVP according to $G(t)v_i=\lambda_i G(t_0)v_i$ - 280 ts : int - 281 fixed time $G(t_s)v_i=\lambda_i G(t_0)v_i$ if sort=None. - 282 If sort="Eigenvector" it gives a reference point for the sorting method. - 283 sort : string - 284 If this argument is set, a list of self.T vectors per state is returned. If it is set to None, only one vector is returned. - 285 - "Eigenvalue": The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice. - 286 - "Eigenvector": Use the method described in arXiv:2004.10472 to find the set of v(t) belonging to the state. - 287 The reference state is identified by its eigenvalue at $t=t_s$. - 288 - 289 Other Parameters - 290 ---------------- - 291 state : int - 292 Returns only the vector(s) for a specified state. The lowest state is zero. - 293 ''' - 294 - 295 if self.N == 1: - 296 raise Exception("GEVP methods only works on correlator matrices and not single correlators.") - 297 if ts is not None: - 298 if (ts <= t0): - 299 raise Exception("ts has to be larger than t0.") - 300 - 301 if "sorted_list" in kwargs: - 302 warnings.warn("Argument 'sorted_list' is deprecated, use 'sort' instead.", DeprecationWarning) - 303 sort = kwargs.get("sorted_list") - 304 - 305 if self.is_matrix_symmetric(): - 306 symmetric_corr = self - 307 else: - 308 symmetric_corr = self.matrix_symmetric() + 266 The eigenvectors are sorted according to the descending eigenvalues, the zeroth eigenvector(s) correspond to the + 267 largest eigenvalue(s). The eigenvector(s) for the individual states can be accessed via slicing + 268 ```python + 269 C.GEVP(t0=2)[0] # Ground state vector(s) + 270 C.GEVP(t0=2)[:3] # Vectors for the lowest three states + 271 ``` + 272 + 273 Parameters + 274 ---------- + 275 t0 : int + 276 The time t0 for the right hand side of the GEVP according to $G(t)v_i=\lambda_i G(t_0)v_i$ + 277 ts : int + 278 fixed time $G(t_s)v_i=\lambda_i G(t_0)v_i$ if sort=None. + 279 If sort="Eigenvector" it gives a reference point for the sorting method. + 280 sort : string + 281 If this argument is set, a list of self.T vectors per state is returned. If it is set to None, only one vector is returned. + 282 - "Eigenvalue": The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice. + 283 - "Eigenvector": Use the method described in arXiv:2004.10472 to find the set of v(t) belonging to the state. + 284 The reference state is identified by its eigenvalue at $t=t_s$. + 285 + 286 Other Parameters + 287 ---------------- + 288 state : int + 289 Returns only the vector(s) for a specified state. The lowest state is zero. + 290 ''' + 291 + 292 if self.N == 1: + 293 raise Exception("GEVP methods only works on correlator matrices and not single correlators.") + 294 if ts is not None: + 295 if (ts <= t0): + 296 raise Exception("ts has to be larger than t0.") + 297 + 298 if "sorted_list" in kwargs: + 299 warnings.warn("Argument 'sorted_list' is deprecated, use 'sort' instead.", DeprecationWarning) + 300 sort = kwargs.get("sorted_list") + 301 + 302 if self.is_matrix_symmetric(): + 303 symmetric_corr = self + 304 else: + 305 symmetric_corr = self.matrix_symmetric() + 306 + 307 G0 = np.vectorize(lambda x: x.value)(symmetric_corr[t0]) + 308 np.linalg.cholesky(G0) # Check if matrix G0 is positive-semidefinite. 309 - 310 G0 = np.vectorize(lambda x: x.value)(symmetric_corr[t0]) - 311 np.linalg.cholesky(G0) # Check if matrix G0 is positive-semidefinite. - 312 - 313 if sort is None: - 314 if (ts is None): - 315 raise Exception("ts is required if sort=None.") - 316 if (self.content[t0] is None) or (self.content[ts] is None): - 317 raise Exception("Corr not defined at t0/ts.") - 318 Gt = np.vectorize(lambda x: x.value)(symmetric_corr[ts]) - 319 reordered_vecs = _GEVP_solver(Gt, G0) - 320 - 321 elif sort in ["Eigenvalue", "Eigenvector"]: - 322 if sort == "Eigenvalue" and ts is not None: - 323 warnings.warn("ts has no effect when sorting by eigenvalue is chosen.", RuntimeWarning) - 324 all_vecs = [None] * (t0 + 1) - 325 for t in range(t0 + 1, self.T): - 326 try: - 327 Gt = np.vectorize(lambda x: x.value)(symmetric_corr[t]) - 328 all_vecs.append(_GEVP_solver(Gt, G0)) - 329 except Exception: - 330 all_vecs.append(None) - 331 if sort == "Eigenvector": - 332 if ts is None: - 333 raise Exception("ts is required for the Eigenvector sorting method.") - 334 all_vecs = _sort_vectors(all_vecs, ts) - 335 - 336 reordered_vecs = [[v[s] if v is not None else None for v in all_vecs] for s in range(self.N)] - 337 else: - 338 raise Exception("Unkown value for 'sort'.") - 339 - 340 if "state" in kwargs: - 341 return reordered_vecs[kwargs.get("state")] - 342 else: - 343 return reordered_vecs + 310 if sort is None: + 311 if (ts is None): + 312 raise Exception("ts is required if sort=None.") + 313 if (self.content[t0] is None) or (self.content[ts] is None): + 314 raise Exception("Corr not defined at t0/ts.") + 315 Gt = np.vectorize(lambda x: x.value)(symmetric_corr[ts]) + 316 reordered_vecs = _GEVP_solver(Gt, G0) + 317 + 318 elif sort in ["Eigenvalue", "Eigenvector"]: + 319 if sort == "Eigenvalue" and ts is not None: + 320 warnings.warn("ts has no effect when sorting by eigenvalue is chosen.", RuntimeWarning) + 321 all_vecs = [None] * (t0 + 1) + 322 for t in range(t0 + 1, self.T): + 323 try: + 324 Gt = np.vectorize(lambda x: x.value)(symmetric_corr[t]) + 325 all_vecs.append(_GEVP_solver(Gt, G0)) + 326 except Exception: + 327 all_vecs.append(None) + 328 if sort == "Eigenvector": + 329 if ts is None: + 330 raise Exception("ts is required for the Eigenvector sorting method.") + 331 all_vecs = _sort_vectors(all_vecs, ts) + 332 + 333 reordered_vecs = [[v[s] if v is not None else None for v in all_vecs] for s in range(self.N)] + 334 else: + 335 raise Exception("Unkown value for 'sort'.") + 336 + 337 if "state" in kwargs: + 338 return reordered_vecs[kwargs.get("state")] + 339 else: + 340 return reordered_vecs + 341 + 342 def Eigenvalue(self, t0, ts=None, state=0, sort="Eigenvalue"): + 343 """Determines the eigenvalue of the GEVP by solving and projecting the correlator 344 - 345 def Eigenvalue(self, t0, ts=None, state=0, sort="Eigenvalue"): - 346 """Determines the eigenvalue of the GEVP by solving and projecting the correlator - 347 - 348 Parameters - 349 ---------- - 350 state : int - 351 The state one is interested in ordered by energy. The lowest state is zero. - 352 - 353 All other parameters are identical to the ones of Corr.GEVP. - 354 """ - 355 vec = self.GEVP(t0, ts=ts, sort=sort)[state] - 356 return self.projected(vec) + 345 Parameters + 346 ---------- + 347 state : int + 348 The state one is interested in ordered by energy. The lowest state is zero. + 349 + 350 All other parameters are identical to the ones of Corr.GEVP. + 351 """ + 352 vec = self.GEVP(t0, ts=ts, sort=sort)[state] + 353 return self.projected(vec) + 354 + 355 def Hankel(self, N, periodic=False): + 356 """Constructs an NxN Hankel matrix 357 - 358 def Hankel(self, N, periodic=False): - 359 """Constructs an NxN Hankel matrix - 360 - 361 C(t) c(t+1) ... c(t+n-1) - 362 C(t+1) c(t+2) ... c(t+n) - 363 ................. - 364 C(t+(n-1)) c(t+n) ... c(t+2(n-1)) - 365 - 366 Parameters - 367 ---------- - 368 N : int - 369 Dimension of the Hankel matrix - 370 periodic : bool, optional - 371 determines whether the matrix is extended periodically - 372 """ + 358 C(t) c(t+1) ... c(t+n-1) + 359 C(t+1) c(t+2) ... c(t+n) + 360 ................. + 361 C(t+(n-1)) c(t+n) ... c(t+2(n-1)) + 362 + 363 Parameters + 364 ---------- + 365 N : int + 366 Dimension of the Hankel matrix + 367 periodic : bool, optional + 368 determines whether the matrix is extended periodically + 369 """ + 370 + 371 if self.N != 1: + 372 raise Exception("Multi-operator Prony not implemented!") 373 - 374 if self.N != 1: - 375 raise Exception("Multi-operator Prony not implemented!") - 376 - 377 array = np.empty([N, N], dtype="object") - 378 new_content = [] - 379 for t in range(self.T): - 380 new_content.append(array.copy()) - 381 - 382 def wrap(i): - 383 while i >= self.T: - 384 i -= self.T - 385 return i - 386 - 387 for t in range(self.T): - 388 for i in range(N): - 389 for j in range(N): - 390 if periodic: - 391 new_content[t][i, j] = self.content[wrap(t + i + j)][0] - 392 elif (t + i + j) >= self.T: - 393 new_content[t] = None - 394 else: - 395 new_content[t][i, j] = self.content[t + i + j][0] - 396 - 397 return Corr(new_content) + 374 array = np.empty([N, N], dtype="object") + 375 new_content = [] + 376 for t in range(self.T): + 377 new_content.append(array.copy()) + 378 + 379 def wrap(i): + 380 while i >= self.T: + 381 i -= self.T + 382 return i + 383 + 384 for t in range(self.T): + 385 for i in range(N): + 386 for j in range(N): + 387 if periodic: + 388 new_content[t][i, j] = self.content[wrap(t + i + j)][0] + 389 elif (t + i + j) >= self.T: + 390 new_content[t] = None + 391 else: + 392 new_content[t][i, j] = self.content[t + i + j][0] + 393 + 394 return Corr(new_content) + 395 + 396 def roll(self, dt): + 397 """Periodically shift the correlator by dt timeslices 398 - 399 def roll(self, dt): - 400 """Periodically shift the correlator by dt timeslices - 401 - 402 Parameters - 403 ---------- - 404 dt : int - 405 number of timeslices - 406 """ - 407 return Corr(list(np.roll(np.array(self.content, dtype=object), dt))) - 408 - 409 def reverse(self): - 410 """Reverse the time ordering of the Corr""" - 411 return Corr(self.content[:: -1]) + 399 Parameters + 400 ---------- + 401 dt : int + 402 number of timeslices + 403 """ + 404 return Corr(list(np.roll(np.array(self.content, dtype=object), dt))) + 405 + 406 def reverse(self): + 407 """Reverse the time ordering of the Corr""" + 408 return Corr(self.content[:: -1]) + 409 + 410 def thin(self, spacing=2, offset=0): + 411 """Thin out a correlator to suppress correlations 412 - 413 def thin(self, spacing=2, offset=0): - 414 """Thin out a correlator to suppress correlations - 415 - 416 Parameters - 417 ---------- - 418 spacing : int - 419 Keep only every 'spacing'th entry of the correlator - 420 offset : int - 421 Offset the equal spacing - 422 """ - 423 new_content = [] - 424 for t in range(self.T): - 425 if (offset + t) % spacing != 0: - 426 new_content.append(None) - 427 else: - 428 new_content.append(self.content[t]) - 429 return Corr(new_content) + 413 Parameters + 414 ---------- + 415 spacing : int + 416 Keep only every 'spacing'th entry of the correlator + 417 offset : int + 418 Offset the equal spacing + 419 """ + 420 new_content = [] + 421 for t in range(self.T): + 422 if (offset + t) % spacing != 0: + 423 new_content.append(None) + 424 else: + 425 new_content.append(self.content[t]) + 426 return Corr(new_content) + 427 + 428 def correlate(self, partner): + 429 """Correlate the correlator with another correlator or Obs 430 - 431 def correlate(self, partner): - 432 """Correlate the correlator with another correlator or Obs - 433 - 434 Parameters - 435 ---------- - 436 partner : Obs or Corr - 437 partner to correlate the correlator with. - 438 Can either be an Obs which is correlated with all entries of the - 439 correlator or a Corr of same length. - 440 """ - 441 if self.N != 1: - 442 raise Exception("Only one-dimensional correlators can be safely correlated.") - 443 new_content = [] - 444 for x0, t_slice in enumerate(self.content): - 445 if _check_for_none(self, t_slice): - 446 new_content.append(None) - 447 else: - 448 if isinstance(partner, Corr): - 449 if _check_for_none(partner, partner.content[x0]): - 450 new_content.append(None) - 451 else: - 452 new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice])) - 453 elif isinstance(partner, Obs): # Should this include CObs? - 454 new_content.append(np.array([correlate(o, partner) for o in t_slice])) - 455 else: - 456 raise Exception("Can only correlate with an Obs or a Corr.") - 457 - 458 return Corr(new_content) + 431 Parameters + 432 ---------- + 433 partner : Obs or Corr + 434 partner to correlate the correlator with. + 435 Can either be an Obs which is correlated with all entries of the + 436 correlator or a Corr of same length. + 437 """ + 438 if self.N != 1: + 439 raise Exception("Only one-dimensional correlators can be safely correlated.") + 440 new_content = [] + 441 for x0, t_slice in enumerate(self.content): + 442 if _check_for_none(self, t_slice): + 443 new_content.append(None) + 444 else: + 445 if isinstance(partner, Corr): + 446 if _check_for_none(partner, partner.content[x0]): + 447 new_content.append(None) + 448 else: + 449 new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice])) + 450 elif isinstance(partner, Obs): # Should this include CObs? + 451 new_content.append(np.array([correlate(o, partner) for o in t_slice])) + 452 else: + 453 raise Exception("Can only correlate with an Obs or a Corr.") + 454 + 455 return Corr(new_content) + 456 + 457 def reweight(self, weight, **kwargs): + 458 """Reweight the correlator. 459 - 460 def reweight(self, weight, **kwargs): - 461 """Reweight the correlator. - 462 - 463 Parameters - 464 ---------- - 465 weight : Obs - 466 Reweighting factor. An Observable that has to be defined on a superset of the - 467 configurations in obs[i].idl for all i. - 468 all_configs : bool - 469 if True, the reweighted observables are normalized by the average of - 470 the reweighting factor on all configurations in weight.idl and not - 471 on the configurations in obs[i].idl. - 472 """ - 473 if self.N != 1: - 474 raise Exception("Reweighting only implemented for one-dimensional correlators.") - 475 new_content = [] - 476 for t_slice in self.content: - 477 if _check_for_none(self, t_slice): - 478 new_content.append(None) - 479 else: - 480 new_content.append(np.array(reweight(weight, t_slice, **kwargs))) - 481 return Corr(new_content) + 460 Parameters + 461 ---------- + 462 weight : Obs + 463 Reweighting factor. An Observable that has to be defined on a superset of the + 464 configurations in obs[i].idl for all i. + 465 all_configs : bool + 466 if True, the reweighted observables are normalized by the average of + 467 the reweighting factor on all configurations in weight.idl and not + 468 on the configurations in obs[i].idl. + 469 """ + 470 if self.N != 1: + 471 raise Exception("Reweighting only implemented for one-dimensional correlators.") + 472 new_content = [] + 473 for t_slice in self.content: + 474 if _check_for_none(self, t_slice): + 475 new_content.append(None) + 476 else: + 477 new_content.append(np.array(reweight(weight, t_slice, **kwargs))) + 478 return Corr(new_content) + 479 + 480 def T_symmetry(self, partner, parity=+1): + 481 """Return the time symmetry average of the correlator and its partner 482 - 483 def T_symmetry(self, partner, parity=+1): - 484 """Return the time symmetry average of the correlator and its partner - 485 - 486 Parameters - 487 ---------- - 488 partner : Corr - 489 Time symmetry partner of the Corr - 490 partity : int - 491 Parity quantum number of the correlator, can be +1 or -1 - 492 """ - 493 if self.N != 1: - 494 raise Exception("T_symmetry only implemented for one-dimensional correlators.") - 495 if not isinstance(partner, Corr): - 496 raise Exception("T partner has to be a Corr object.") - 497 if parity not in [+1, -1]: - 498 raise Exception("Parity has to be +1 or -1.") - 499 T_partner = parity * partner.reverse() - 500 - 501 t_slices = [] - 502 test = (self - T_partner) - 503 test.gamma_method() - 504 for x0, t_slice in enumerate(test.content): - 505 if t_slice is not None: - 506 if not t_slice[0].is_zero_within_error(5): - 507 t_slices.append(x0) - 508 if t_slices: - 509 warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning) - 510 - 511 return (self + T_partner) / 2 + 483 Parameters + 484 ---------- + 485 partner : Corr + 486 Time symmetry partner of the Corr + 487 partity : int + 488 Parity quantum number of the correlator, can be +1 or -1 + 489 """ + 490 if self.N != 1: + 491 raise Exception("T_symmetry only implemented for one-dimensional correlators.") + 492 if not isinstance(partner, Corr): + 493 raise Exception("T partner has to be a Corr object.") + 494 if parity not in [+1, -1]: + 495 raise Exception("Parity has to be +1 or -1.") + 496 T_partner = parity * partner.reverse() + 497 + 498 t_slices = [] + 499 test = (self - T_partner) + 500 test.gamma_method() + 501 for x0, t_slice in enumerate(test.content): + 502 if t_slice is not None: + 503 if not t_slice[0].is_zero_within_error(5): + 504 t_slices.append(x0) + 505 if t_slices: + 506 warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning) + 507 + 508 return (self + T_partner) / 2 + 509 + 510 def deriv(self, variant="symmetric"): + 511 """Return the first derivative of the correlator with respect to x0. 512 - 513 def deriv(self, variant="symmetric"): - 514 """Return the first derivative of the correlator with respect to x0. - 515 - 516 Parameters - 517 ---------- - 518 variant : str - 519 decides which definition of the finite differences derivative is used. - 520 Available choice: symmetric, forward, backward, improved, log, default: symmetric - 521 """ - 522 if self.N != 1: - 523 raise Exception("deriv only implemented for one-dimensional correlators.") - 524 if variant == "symmetric": - 525 newcontent = [] - 526 for t in range(1, self.T - 1): - 527 if (self.content[t - 1] is None) or (self.content[t + 1] is None): - 528 newcontent.append(None) - 529 else: - 530 newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1])) - 531 if (all([x is None for x in newcontent])): - 532 raise Exception('Derivative is undefined at all timeslices') - 533 return Corr(newcontent, padding=[1, 1]) - 534 elif variant == "forward": - 535 newcontent = [] - 536 for t in range(self.T - 1): - 537 if (self.content[t] is None) or (self.content[t + 1] is None): - 538 newcontent.append(None) - 539 else: - 540 newcontent.append(self.content[t + 1] - self.content[t]) - 541 if (all([x is None for x in newcontent])): - 542 raise Exception("Derivative is undefined at all timeslices") - 543 return Corr(newcontent, padding=[0, 1]) - 544 elif variant == "backward": - 545 newcontent = [] - 546 for t in range(1, self.T): - 547 if (self.content[t - 1] is None) or (self.content[t] is None): - 548 newcontent.append(None) - 549 else: - 550 newcontent.append(self.content[t] - self.content[t - 1]) - 551 if (all([x is None for x in newcontent])): - 552 raise Exception("Derivative is undefined at all timeslices") - 553 return Corr(newcontent, padding=[1, 0]) - 554 elif variant == "improved": - 555 newcontent = [] - 556 for t in range(2, self.T - 2): - 557 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): - 558 newcontent.append(None) - 559 else: - 560 newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2])) - 561 if (all([x is None for x in newcontent])): - 562 raise Exception('Derivative is undefined at all timeslices') - 563 return Corr(newcontent, padding=[2, 2]) - 564 elif variant == 'log': - 565 newcontent = [] - 566 for t in range(self.T): - 567 if (self.content[t] is None) or (self.content[t] <= 0): - 568 newcontent.append(None) - 569 else: - 570 newcontent.append(np.log(self.content[t])) - 571 if (all([x is None for x in newcontent])): - 572 raise Exception("Log is undefined at all timeslices") - 573 logcorr = Corr(newcontent) - 574 return self * logcorr.deriv('symmetric') - 575 else: - 576 raise Exception("Unknown variant.") + 513 Parameters + 514 ---------- + 515 variant : str + 516 decides which definition of the finite differences derivative is used. + 517 Available choice: symmetric, forward, backward, improved, log, default: symmetric + 518 """ + 519 if self.N != 1: + 520 raise Exception("deriv only implemented for one-dimensional correlators.") + 521 if variant == "symmetric": + 522 newcontent = [] + 523 for t in range(1, self.T - 1): + 524 if (self.content[t - 1] is None) or (self.content[t + 1] is None): + 525 newcontent.append(None) + 526 else: + 527 newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1])) + 528 if (all([x is None for x in newcontent])): + 529 raise Exception('Derivative is undefined at all timeslices') + 530 return Corr(newcontent, padding=[1, 1]) + 531 elif variant == "forward": + 532 newcontent = [] + 533 for t in range(self.T - 1): + 534 if (self.content[t] is None) or (self.content[t + 1] is None): + 535 newcontent.append(None) + 536 else: + 537 newcontent.append(self.content[t + 1] - self.content[t]) + 538 if (all([x is None for x in newcontent])): + 539 raise Exception("Derivative is undefined at all timeslices") + 540 return Corr(newcontent, padding=[0, 1]) + 541 elif variant == "backward": + 542 newcontent = [] + 543 for t in range(1, self.T): + 544 if (self.content[t - 1] is None) or (self.content[t] is None): + 545 newcontent.append(None) + 546 else: + 547 newcontent.append(self.content[t] - self.content[t - 1]) + 548 if (all([x is None for x in newcontent])): + 549 raise Exception("Derivative is undefined at all timeslices") + 550 return Corr(newcontent, padding=[1, 0]) + 551 elif variant == "improved": + 552 newcontent = [] + 553 for t in range(2, self.T - 2): + 554 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): + 555 newcontent.append(None) + 556 else: + 557 newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2])) + 558 if (all([x is None for x in newcontent])): + 559 raise Exception('Derivative is undefined at all timeslices') + 560 return Corr(newcontent, padding=[2, 2]) + 561 elif variant == 'log': + 562 newcontent = [] + 563 for t in range(self.T): + 564 if (self.content[t] is None) or (self.content[t] <= 0): + 565 newcontent.append(None) + 566 else: + 567 newcontent.append(np.log(self.content[t])) + 568 if (all([x is None for x in newcontent])): + 569 raise Exception("Log is undefined at all timeslices") + 570 logcorr = Corr(newcontent) + 571 return self * logcorr.deriv('symmetric') + 572 else: + 573 raise Exception("Unknown variant.") + 574 + 575 def second_deriv(self, variant="symmetric"): + 576 """Return the second derivative of the correlator with respect to x0. 577 - 578 def second_deriv(self, variant="symmetric"): - 579 """Return the second derivative of the correlator with respect to x0. - 580 - 581 Parameters - 582 ---------- - 583 variant : str - 584 decides which definition of the finite differences derivative is used. - 585 Available choice: symmetric, improved, log, default: symmetric - 586 """ - 587 if self.N != 1: - 588 raise Exception("second_deriv only implemented for one-dimensional correlators.") - 589 if variant == "symmetric": - 590 newcontent = [] - 591 for t in range(1, self.T - 1): - 592 if (self.content[t - 1] is None) or (self.content[t + 1] is None): - 593 newcontent.append(None) - 594 else: - 595 newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1])) - 596 if (all([x is None for x in newcontent])): - 597 raise Exception("Derivative is undefined at all timeslices") - 598 return Corr(newcontent, padding=[1, 1]) - 599 elif variant == "improved": - 600 newcontent = [] - 601 for t in range(2, self.T - 2): - 602 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): - 603 newcontent.append(None) - 604 else: - 605 newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2])) - 606 if (all([x is None for x in newcontent])): - 607 raise Exception("Derivative is undefined at all timeslices") - 608 return Corr(newcontent, padding=[2, 2]) - 609 elif variant == 'log': - 610 newcontent = [] - 611 for t in range(self.T): - 612 if (self.content[t] is None) or (self.content[t] <= 0): - 613 newcontent.append(None) - 614 else: - 615 newcontent.append(np.log(self.content[t])) - 616 if (all([x is None for x in newcontent])): - 617 raise Exception("Log is undefined at all timeslices") - 618 logcorr = Corr(newcontent) - 619 return self * (logcorr.second_deriv('symmetric') + (logcorr.deriv('symmetric'))**2) - 620 else: - 621 raise Exception("Unknown variant.") + 578 Parameters + 579 ---------- + 580 variant : str + 581 decides which definition of the finite differences derivative is used. + 582 Available choice: symmetric, improved, log, default: symmetric + 583 """ + 584 if self.N != 1: + 585 raise Exception("second_deriv only implemented for one-dimensional correlators.") + 586 if variant == "symmetric": + 587 newcontent = [] + 588 for t in range(1, self.T - 1): + 589 if (self.content[t - 1] is None) or (self.content[t + 1] is None): + 590 newcontent.append(None) + 591 else: + 592 newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1])) + 593 if (all([x is None for x in newcontent])): + 594 raise Exception("Derivative is undefined at all timeslices") + 595 return Corr(newcontent, padding=[1, 1]) + 596 elif variant == "improved": + 597 newcontent = [] + 598 for t in range(2, self.T - 2): + 599 if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None): + 600 newcontent.append(None) + 601 else: + 602 newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2])) + 603 if (all([x is None for x in newcontent])): + 604 raise Exception("Derivative is undefined at all timeslices") + 605 return Corr(newcontent, padding=[2, 2]) + 606 elif variant == 'log': + 607 newcontent = [] + 608 for t in range(self.T): + 609 if (self.content[t] is None) or (self.content[t] <= 0): + 610 newcontent.append(None) + 611 else: + 612 newcontent.append(np.log(self.content[t])) + 613 if (all([x is None for x in newcontent])): + 614 raise Exception("Log is undefined at all timeslices") + 615 logcorr = Corr(newcontent) + 616 return self * (logcorr.second_deriv('symmetric') + (logcorr.deriv('symmetric'))**2) + 617 else: + 618 raise Exception("Unknown variant.") + 619 + 620 def m_eff(self, variant='log', guess=1.0): + 621 """Returns the effective mass of the correlator as correlator object 622 - 623 def m_eff(self, variant='log', guess=1.0): - 624 """Returns the effective mass of the correlator as correlator object - 625 - 626 Parameters - 627 ---------- - 628 variant : str - 629 log : uses the standard effective mass log(C(t) / C(t+1)) - 630 cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m. - 631 sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m. - 632 See, e.g., arXiv:1205.5380 - 633 arccosh : Uses the explicit form of the symmetrized correlator (not recommended) - 634 logsym: uses the symmetric effective mass log(C(t-1) / C(t+1))/2 - 635 guess : float - 636 guess for the root finder, only relevant for the root variant - 637 """ - 638 if self.N != 1: - 639 raise Exception('Correlator must be projected before getting m_eff') - 640 if variant == 'log': - 641 newcontent = [] - 642 for t in range(self.T - 1): - 643 if ((self.content[t] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0): - 644 newcontent.append(None) - 645 elif self.content[t][0].value / self.content[t + 1][0].value < 0: - 646 newcontent.append(None) - 647 else: - 648 newcontent.append(self.content[t] / self.content[t + 1]) - 649 if (all([x is None for x in newcontent])): - 650 raise Exception('m_eff is undefined at all timeslices') - 651 - 652 return np.log(Corr(newcontent, padding=[0, 1])) - 653 - 654 elif variant == 'logsym': - 655 newcontent = [] - 656 for t in range(1, self.T - 1): - 657 if ((self.content[t - 1] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0): - 658 newcontent.append(None) - 659 elif self.content[t - 1][0].value / self.content[t + 1][0].value < 0: - 660 newcontent.append(None) - 661 else: - 662 newcontent.append(self.content[t - 1] / self.content[t + 1]) - 663 if (all([x is None for x in newcontent])): - 664 raise Exception('m_eff is undefined at all timeslices') - 665 - 666 return np.log(Corr(newcontent, padding=[1, 1])) / 2 - 667 - 668 elif variant in ['periodic', 'cosh', 'sinh']: - 669 if variant in ['periodic', 'cosh']: - 670 func = anp.cosh - 671 else: - 672 func = anp.sinh + 623 Parameters + 624 ---------- + 625 variant : str + 626 log : uses the standard effective mass log(C(t) / C(t+1)) + 627 cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m. + 628 sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m. + 629 See, e.g., arXiv:1205.5380 + 630 arccosh : Uses the explicit form of the symmetrized correlator (not recommended) + 631 logsym: uses the symmetric effective mass log(C(t-1) / C(t+1))/2 + 632 guess : float + 633 guess for the root finder, only relevant for the root variant + 634 """ + 635 if self.N != 1: + 636 raise Exception('Correlator must be projected before getting m_eff') + 637 if variant == 'log': + 638 newcontent = [] + 639 for t in range(self.T - 1): + 640 if ((self.content[t] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0): + 641 newcontent.append(None) + 642 elif self.content[t][0].value / self.content[t + 1][0].value < 0: + 643 newcontent.append(None) + 644 else: + 645 newcontent.append(self.content[t] / self.content[t + 1]) + 646 if (all([x is None for x in newcontent])): + 647 raise Exception('m_eff is undefined at all timeslices') + 648 + 649 return np.log(Corr(newcontent, padding=[0, 1])) + 650 + 651 elif variant == 'logsym': + 652 newcontent = [] + 653 for t in range(1, self.T - 1): + 654 if ((self.content[t - 1] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0): + 655 newcontent.append(None) + 656 elif self.content[t - 1][0].value / self.content[t + 1][0].value < 0: + 657 newcontent.append(None) + 658 else: + 659 newcontent.append(self.content[t - 1] / self.content[t + 1]) + 660 if (all([x is None for x in newcontent])): + 661 raise Exception('m_eff is undefined at all timeslices') + 662 + 663 return np.log(Corr(newcontent, padding=[1, 1])) / 2 + 664 + 665 elif variant in ['periodic', 'cosh', 'sinh']: + 666 if variant in ['periodic', 'cosh']: + 667 func = anp.cosh + 668 else: + 669 func = anp.sinh + 670 + 671 def root_function(x, d): + 672 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d 673 - 674 def root_function(x, d): - 675 return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d - 676 - 677 newcontent = [] - 678 for t in range(self.T - 1): - 679 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0): - 680 newcontent.append(None) - 681 # Fill the two timeslices in the middle of the lattice with their predecessors - 682 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: - 683 newcontent.append(newcontent[-1]) - 684 elif self.content[t][0].value / self.content[t + 1][0].value < 0: - 685 newcontent.append(None) - 686 else: - 687 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) - 688 if (all([x is None for x in newcontent])): - 689 raise Exception('m_eff is undefined at all timeslices') - 690 - 691 return Corr(newcontent, padding=[0, 1]) - 692 - 693 elif variant == 'arccosh': - 694 newcontent = [] - 695 for t in range(1, self.T - 1): - 696 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): - 697 newcontent.append(None) - 698 else: - 699 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) - 700 if (all([x is None for x in newcontent])): - 701 raise Exception("m_eff is undefined at all timeslices") - 702 return np.arccosh(Corr(newcontent, padding=[1, 1])) + 674 newcontent = [] + 675 for t in range(self.T - 1): + 676 if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0): + 677 newcontent.append(None) + 678 # Fill the two timeslices in the middle of the lattice with their predecessors + 679 elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]: + 680 newcontent.append(newcontent[-1]) + 681 elif self.content[t][0].value / self.content[t + 1][0].value < 0: + 682 newcontent.append(None) + 683 else: + 684 newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess))) + 685 if (all([x is None for x in newcontent])): + 686 raise Exception('m_eff is undefined at all timeslices') + 687 + 688 return Corr(newcontent, padding=[0, 1]) + 689 + 690 elif variant == 'arccosh': + 691 newcontent = [] + 692 for t in range(1, self.T - 1): + 693 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): + 694 newcontent.append(None) + 695 else: + 696 newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t])) + 697 if (all([x is None for x in newcontent])): + 698 raise Exception("m_eff is undefined at all timeslices") + 699 return np.arccosh(Corr(newcontent, padding=[1, 1])) + 700 + 701 else: + 702 raise Exception('Unknown variant.') 703 - 704 else: - 705 raise Exception('Unknown variant.') + 704 def fit(self, function, fitrange=None, silent=False, **kwargs): + 705 r'''Fits function to the data 706 - 707 def fit(self, function, fitrange=None, silent=False, **kwargs): - 708 r'''Fits function to the data - 709 - 710 Parameters - 711 ---------- - 712 function : obj - 713 function to fit to the data. See fits.least_squares for details. - 714 fitrange : list - 715 Two element list containing the timeslices on which the fit is supposed to start and stop. - 716 Caution: This range is inclusive as opposed to standard python indexing. - 717 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. - 718 If not specified, self.prange or all timeslices are used. - 719 silent : bool - 720 Decides whether output is printed to the standard output. - 721 ''' - 722 if self.N != 1: - 723 raise Exception("Correlator must be projected before fitting") - 724 - 725 if fitrange is None: - 726 if self.prange: - 727 fitrange = self.prange - 728 else: - 729 fitrange = [0, self.T - 1] - 730 else: - 731 if not isinstance(fitrange, list): - 732 raise Exception("fitrange has to be a list with two elements") - 733 if len(fitrange) != 2: - 734 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") - 735 - 736 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 737 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] - 738 result = least_squares(xs, ys, function, silent=silent, **kwargs) - 739 return result + 707 Parameters + 708 ---------- + 709 function : obj + 710 function to fit to the data. See fits.least_squares for details. + 711 fitrange : list + 712 Two element list containing the timeslices on which the fit is supposed to start and stop. + 713 Caution: This range is inclusive as opposed to standard python indexing. + 714 `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6. + 715 If not specified, self.prange or all timeslices are used. + 716 silent : bool + 717 Decides whether output is printed to the standard output. + 718 ''' + 719 if self.N != 1: + 720 raise Exception("Correlator must be projected before fitting") + 721 + 722 if fitrange is None: + 723 if self.prange: + 724 fitrange = self.prange + 725 else: + 726 fitrange = [0, self.T - 1] + 727 else: + 728 if not isinstance(fitrange, list): + 729 raise Exception("fitrange has to be a list with two elements") + 730 if len(fitrange) != 2: + 731 raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]") + 732 + 733 xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 734 ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None] + 735 result = least_squares(xs, ys, function, silent=silent, **kwargs) + 736 return result + 737 + 738 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): + 739 """ Extract a plateau value from a Corr object 740 - 741 def plateau(self, plateau_range=None, method="fit", auto_gamma=False): - 742 """ Extract a plateau value from a Corr object - 743 - 744 Parameters - 745 ---------- - 746 plateau_range : list - 747 list with two entries, indicating the first and the last timeslice - 748 of the plateau region. - 749 method : str - 750 method to extract the plateau. - 751 'fit' fits a constant to the plateau region - 752 'avg', 'average' or 'mean' just average over the given timeslices. - 753 auto_gamma : bool - 754 apply gamma_method with default parameters to the Corr. Defaults to None - 755 """ - 756 if not plateau_range: - 757 if self.prange: - 758 plateau_range = self.prange - 759 else: - 760 raise Exception("no plateau range provided") - 761 if self.N != 1: - 762 raise Exception("Correlator must be projected before getting a plateau.") - 763 if (all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): - 764 raise Exception("plateau is undefined at all timeslices in plateaurange.") - 765 if auto_gamma: - 766 self.gamma_method() - 767 if method == "fit": - 768 def const_func(a, t): - 769 return a[0] - 770 return self.fit(const_func, plateau_range)[0] - 771 elif method in ["avg", "average", "mean"]: - 772 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) - 773 return returnvalue + 741 Parameters + 742 ---------- + 743 plateau_range : list + 744 list with two entries, indicating the first and the last timeslice + 745 of the plateau region. + 746 method : str + 747 method to extract the plateau. + 748 'fit' fits a constant to the plateau region + 749 'avg', 'average' or 'mean' just average over the given timeslices. + 750 auto_gamma : bool + 751 apply gamma_method with default parameters to the Corr. Defaults to None + 752 """ + 753 if not plateau_range: + 754 if self.prange: + 755 plateau_range = self.prange + 756 else: + 757 raise Exception("no plateau range provided") + 758 if self.N != 1: + 759 raise Exception("Correlator must be projected before getting a plateau.") + 760 if (all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])): + 761 raise Exception("plateau is undefined at all timeslices in plateaurange.") + 762 if auto_gamma: + 763 self.gamma_method() + 764 if method == "fit": + 765 def const_func(a, t): + 766 return a[0] + 767 return self.fit(const_func, plateau_range)[0] + 768 elif method in ["avg", "average", "mean"]: + 769 returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None]) + 770 return returnvalue + 771 + 772 else: + 773 raise Exception("Unsupported plateau method: " + method) 774 - 775 else: - 776 raise Exception("Unsupported plateau method: " + method) - 777 - 778 def set_prange(self, prange): - 779 """Sets the attribute prange of the Corr object.""" - 780 if not len(prange) == 2: - 781 raise Exception("prange must be a list or array with two values") - 782 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): - 783 raise Exception("Start and end point must be integers") - 784 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): - 785 raise Exception("Start and end point must define a range in the interval 0,T") + 775 def set_prange(self, prange): + 776 """Sets the attribute prange of the Corr object.""" + 777 if not len(prange) == 2: + 778 raise Exception("prange must be a list or array with two values") + 779 if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))): + 780 raise Exception("Start and end point must be integers") + 781 if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]): + 782 raise Exception("Start and end point must define a range in the interval 0,T") + 783 + 784 self.prange = prange + 785 return 786 - 787 self.prange = prange - 788 return + 787 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): + 788 """Plots the correlator using the tag of the correlator as label if available. 789 - 790 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): - 791 """Plots the correlator using the tag of the correlator as label if available. - 792 - 793 Parameters - 794 ---------- - 795 x_range : list - 796 list of two values, determining the range of the x-axis e.g. [4, 8]. - 797 comp : Corr or list of Corr - 798 Correlator or list of correlators which are plotted for comparison. - 799 The tags of these correlators are used as labels if available. - 800 logscale : bool - 801 Sets y-axis to logscale. - 802 plateau : Obs - 803 Plateau value to be visualized in the figure. - 804 fit_res : Fit_result - 805 Fit_result object to be visualized. - 806 ylabel : str - 807 Label for the y-axis. - 808 save : str - 809 path to file in which the figure should be saved. - 810 auto_gamma : bool - 811 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. - 812 hide_sigma : float - 813 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. - 814 references : list - 815 List of floating point values that are displayed as horizontal lines for reference. - 816 title : string - 817 Optional title of the figure. - 818 """ - 819 if self.N != 1: - 820 raise Exception("Correlator must be projected before plotting") + 790 Parameters + 791 ---------- + 792 x_range : list + 793 list of two values, determining the range of the x-axis e.g. [4, 8]. + 794 comp : Corr or list of Corr + 795 Correlator or list of correlators which are plotted for comparison. + 796 The tags of these correlators are used as labels if available. + 797 logscale : bool + 798 Sets y-axis to logscale. + 799 plateau : Obs + 800 Plateau value to be visualized in the figure. + 801 fit_res : Fit_result + 802 Fit_result object to be visualized. + 803 ylabel : str + 804 Label for the y-axis. + 805 save : str + 806 path to file in which the figure should be saved. + 807 auto_gamma : bool + 808 Apply the gamma method with standard parameters to all correlators and plateau values before plotting. + 809 hide_sigma : float + 810 Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors. + 811 references : list + 812 List of floating point values that are displayed as horizontal lines for reference. + 813 title : string + 814 Optional title of the figure. + 815 """ + 816 if self.N != 1: + 817 raise Exception("Correlator must be projected before plotting") + 818 + 819 if auto_gamma: + 820 self.gamma_method() 821 - 822 if auto_gamma: - 823 self.gamma_method() + 822 if x_range is None: + 823 x_range = [0, self.T - 1] 824 - 825 if x_range is None: - 826 x_range = [0, self.T - 1] + 825 fig = plt.figure() + 826 ax1 = fig.add_subplot(111) 827 - 828 fig = plt.figure() - 829 ax1 = fig.add_subplot(111) - 830 - 831 x, y, y_err = self.plottable() - 832 if hide_sigma: - 833 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 - 834 else: - 835 hide_from = None - 836 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) - 837 if logscale: - 838 ax1.set_yscale('log') - 839 else: - 840 if y_range is None: - 841 try: - 842 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)]) - 843 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)]) - 844 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) - 845 except Exception: - 846 pass - 847 else: - 848 ax1.set_ylim(y_range) - 849 if comp: - 850 if isinstance(comp, (Corr, list)): - 851 for corr in comp if isinstance(comp, list) else [comp]: - 852 if auto_gamma: - 853 corr.gamma_method() - 854 x, y, y_err = corr.plottable() - 855 if hide_sigma: - 856 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 - 857 else: - 858 hide_from = None - 859 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) - 860 else: - 861 raise Exception("'comp' must be a correlator or a list of correlators.") - 862 - 863 if plateau: - 864 if isinstance(plateau, Obs): - 865 if auto_gamma: - 866 plateau.gamma_method() - 867 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) - 868 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') - 869 else: - 870 raise Exception("'plateau' must be an Obs") - 871 - 872 if references: - 873 if isinstance(references, list): - 874 for ref in references: - 875 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') - 876 else: - 877 raise Exception("'references' must be a list of floating pint values.") - 878 - 879 if self.prange: - 880 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') - 881 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') - 882 - 883 if fit_res: - 884 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) - 885 ax1.plot(x_samples, - 886 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), - 887 ls='-', marker=',', lw=2) - 888 - 889 ax1.set_xlabel(r'$x_0 / a$') - 890 if ylabel: - 891 ax1.set_ylabel(ylabel) - 892 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) - 893 - 894 handles, labels = ax1.get_legend_handles_labels() - 895 if labels: - 896 ax1.legend() + 828 x, y, y_err = self.plottable() + 829 if hide_sigma: + 830 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 + 831 else: + 832 hide_from = None + 833 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag) + 834 if logscale: + 835 ax1.set_yscale('log') + 836 else: + 837 if y_range is None: + 838 try: + 839 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)]) + 840 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)]) + 841 ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)]) + 842 except Exception: + 843 pass + 844 else: + 845 ax1.set_ylim(y_range) + 846 if comp: + 847 if isinstance(comp, (Corr, list)): + 848 for corr in comp if isinstance(comp, list) else [comp]: + 849 if auto_gamma: + 850 corr.gamma_method() + 851 x, y, y_err = corr.plottable() + 852 if hide_sigma: + 853 hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1 + 854 else: + 855 hide_from = None + 856 ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor']) + 857 else: + 858 raise Exception("'comp' must be a correlator or a list of correlators.") + 859 + 860 if plateau: + 861 if isinstance(plateau, Obs): + 862 if auto_gamma: + 863 plateau.gamma_method() + 864 ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau)) + 865 ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-') + 866 else: + 867 raise Exception("'plateau' must be an Obs") + 868 + 869 if references: + 870 if isinstance(references, list): + 871 for ref in references: + 872 ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--') + 873 else: + 874 raise Exception("'references' must be a list of floating pint values.") + 875 + 876 if self.prange: + 877 ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',') + 878 ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',') + 879 + 880 if fit_res: + 881 x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05) + 882 ax1.plot(x_samples, + 883 fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples), + 884 ls='-', marker=',', lw=2) + 885 + 886 ax1.set_xlabel(r'$x_0 / a$') + 887 if ylabel: + 888 ax1.set_ylabel(ylabel) + 889 ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5]) + 890 + 891 handles, labels = ax1.get_legend_handles_labels() + 892 if labels: + 893 ax1.legend() + 894 + 895 if title: + 896 plt.title(title) 897 - 898 if title: - 899 plt.title(title) - 900 - 901 plt.draw() - 902 - 903 if save: - 904 if isinstance(save, str): - 905 fig.savefig(save, bbox_inches='tight') - 906 else: - 907 raise Exception("'save' has to be a string.") + 898 plt.draw() + 899 + 900 if save: + 901 if isinstance(save, str): + 902 fig.savefig(save, bbox_inches='tight') + 903 else: + 904 raise Exception("'save' has to be a string.") + 905 + 906 def spaghetti_plot(self, logscale=True): + 907 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. 908 - 909 def spaghetti_plot(self, logscale=True): - 910 """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations. - 911 - 912 Parameters - 913 ---------- - 914 logscale : bool - 915 Determines whether the scale of the y-axis is logarithmic or standard. - 916 """ - 917 if self.N != 1: - 918 raise Exception("Correlator needs to be projected first.") + 909 Parameters + 910 ---------- + 911 logscale : bool + 912 Determines whether the scale of the y-axis is logarithmic or standard. + 913 """ + 914 if self.N != 1: + 915 raise Exception("Correlator needs to be projected first.") + 916 + 917 mc_names = list(set([item for sublist in [sum(map(o[0].e_content.get, o[0].mc_names), []) for o in self.content if o is not None] for item in sublist])) + 918 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] 919 - 920 mc_names = list(set([item for sublist in [sum(map(o[0].e_content.get, o[0].mc_names), []) for o in self.content if o is not None] for item in sublist])) - 921 x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None] + 920 for name in mc_names: + 921 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T 922 - 923 for name in mc_names: - 924 data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T - 925 - 926 fig = plt.figure() - 927 ax = fig.add_subplot(111) - 928 for dat in data: - 929 ax.plot(x0_vals, dat, ls='-', marker='') + 923 fig = plt.figure() + 924 ax = fig.add_subplot(111) + 925 for dat in data: + 926 ax.plot(x0_vals, dat, ls='-', marker='') + 927 + 928 if logscale is True: + 929 ax.set_yscale('log') 930 - 931 if logscale is True: - 932 ax.set_yscale('log') - 933 - 934 ax.set_xlabel(r'$x_0 / a$') - 935 plt.title(name) - 936 plt.draw() - 937 - 938 def dump(self, filename, datatype="json.gz", **kwargs): - 939 """Dumps the Corr into a file of chosen type - 940 Parameters - 941 ---------- - 942 filename : str - 943 Name of the file to be saved. - 944 datatype : str - 945 Format of the exported file. Supported formats include - 946 "json.gz" and "pickle" - 947 path : str - 948 specifies a custom path for the file (default '.') - 949 """ - 950 if datatype == "json.gz": - 951 from .input.json import dump_to_json - 952 if 'path' in kwargs: - 953 file_name = kwargs.get('path') + '/' + filename - 954 else: - 955 file_name = filename - 956 dump_to_json(self, file_name) - 957 elif datatype == "pickle": - 958 dump_object(self, filename, **kwargs) - 959 else: - 960 raise Exception("Unknown datatype " + str(datatype)) + 931 ax.set_xlabel(r'$x_0 / a$') + 932 plt.title(name) + 933 plt.draw() + 934 + 935 def dump(self, filename, datatype="json.gz", **kwargs): + 936 """Dumps the Corr into a file of chosen type + 937 Parameters + 938 ---------- + 939 filename : str + 940 Name of the file to be saved. + 941 datatype : str + 942 Format of the exported file. Supported formats include + 943 "json.gz" and "pickle" + 944 path : str + 945 specifies a custom path for the file (default '.') + 946 """ + 947 if datatype == "json.gz": + 948 from .input.json import dump_to_json + 949 if 'path' in kwargs: + 950 file_name = kwargs.get('path') + '/' + filename + 951 else: + 952 file_name = filename + 953 dump_to_json(self, file_name) + 954 elif datatype == "pickle": + 955 dump_object(self, filename, **kwargs) + 956 else: + 957 raise Exception("Unknown datatype " + str(datatype)) + 958 + 959 def print(self, print_range=None): + 960 print(self.__repr__(print_range)) 961 - 962 def print(self, print_range=None): - 963 print(self.__repr__(print_range)) - 964 - 965 def __repr__(self, print_range=None): - 966 if print_range is None: - 967 print_range = [0, None] + 962 def __repr__(self, print_range=None): + 963 if print_range is None: + 964 print_range = [0, None] + 965 + 966 content_string = "" + 967 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 968 - 969 content_string = "" - 970 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 - 971 - 972 if self.tag is not None: - 973 content_string += "Description: " + self.tag + "\n" - 974 if self.N != 1: - 975 return content_string - 976 - 977 if print_range[1]: - 978 print_range[1] += 1 - 979 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' - 980 for i, sub_corr in enumerate(self.content[print_range[0]:print_range[1]]): - 981 if sub_corr is None: - 982 content_string += str(i + print_range[0]) + '\n' - 983 else: - 984 content_string += str(i + print_range[0]) - 985 for element in sub_corr: - 986 content_string += '\t' + ' ' * int(element >= 0) + str(element) - 987 content_string += '\n' - 988 return content_string + 969 if self.tag is not None: + 970 content_string += "Description: " + self.tag + "\n" + 971 if self.N != 1: + 972 return content_string + 973 + 974 if print_range[1]: + 975 print_range[1] += 1 + 976 content_string += 'x0/a\tCorr(x0/a)\n------------------\n' + 977 for i, sub_corr in enumerate(self.content[print_range[0]:print_range[1]]): + 978 if sub_corr is None: + 979 content_string += str(i + print_range[0]) + '\n' + 980 else: + 981 content_string += str(i + print_range[0]) + 982 for element in sub_corr: + 983 content_string += '\t' + ' ' * int(element >= 0) + str(element) + 984 content_string += '\n' + 985 return content_string + 986 + 987 def __str__(self): + 988 return self.__repr__() 989 - 990 def __str__(self): - 991 return self.__repr__() - 992 - 993 # We define the basic operations, that can be performed with correlators. - 994 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. - 995 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. - 996 # One could try and tell Obs to check if the y in __mul__ is a Corr and - 997 - 998 def __add__(self, y): - 999 if isinstance(y, Corr): -1000 if ((self.N != y.N) or (self.T != y.T)): -1001 raise Exception("Addition of Corrs with different shape") -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 return Corr(newcontent) -1009 -1010 elif isinstance(y, (Obs, int, float, CObs)): -1011 newcontent = [] -1012 for t in range(self.T): -1013 if _check_for_none(self, self.content[t]): -1014 newcontent.append(None) -1015 else: -1016 newcontent.append(self.content[t] + y) -1017 return Corr(newcontent, prange=self.prange) -1018 elif isinstance(y, np.ndarray): -1019 if y.shape == (self.T,): -1020 return Corr(list((np.array(self.content).T + y).T)) -1021 else: -1022 raise ValueError("operands could not be broadcast together") -1023 else: -1024 raise TypeError("Corr + wrong type") -1025 -1026 def __mul__(self, y): -1027 if isinstance(y, Corr): -1028 if not ((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): -1029 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") -1030 newcontent = [] -1031 for t in range(self.T): -1032 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): -1033 newcontent.append(None) -1034 else: -1035 newcontent.append(self.content[t] * y.content[t]) -1036 return Corr(newcontent) -1037 -1038 elif isinstance(y, (Obs, int, float, CObs)): -1039 newcontent = [] -1040 for t in range(self.T): -1041 if _check_for_none(self, self.content[t]): -1042 newcontent.append(None) -1043 else: -1044 newcontent.append(self.content[t] * y) -1045 return Corr(newcontent, prange=self.prange) -1046 elif isinstance(y, np.ndarray): -1047 if y.shape == (self.T,): -1048 return Corr(list((np.array(self.content).T * y).T)) -1049 else: -1050 raise ValueError("operands could not be broadcast together") -1051 else: -1052 raise TypeError("Corr * wrong type") -1053 -1054 def __truediv__(self, y): -1055 if isinstance(y, Corr): -1056 if not ((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): -1057 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") -1058 newcontent = [] -1059 for t in range(self.T): -1060 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): -1061 newcontent.append(None) -1062 else: -1063 newcontent.append(self.content[t] / y.content[t]) -1064 for t in range(self.T): -1065 if _check_for_none(self, newcontent[t]): -1066 continue -1067 if np.isnan(np.sum(newcontent[t]).value): -1068 newcontent[t] = None -1069 -1070 if all([item is None for item in newcontent]): -1071 raise Exception("Division returns completely undefined correlator") -1072 return Corr(newcontent) -1073 -1074 elif isinstance(y, (Obs, CObs)): -1075 if isinstance(y, Obs): -1076 if y.value == 0: + 990 # We define the basic operations, that can be performed with correlators. + 991 # While */+- get defined here, they only work for Corr*Obs and not Obs*Corr. + 992 # This is because Obs*Corr checks Obs.__mul__ first and does not catch an exception. + 993 # One could try and tell Obs to check if the y in __mul__ is a Corr and + 994 + 995 def __add__(self, y): + 996 if isinstance(y, Corr): + 997 if ((self.N != y.N) or (self.T != y.T)): + 998 raise Exception("Addition of Corrs with different shape") + 999 newcontent = [] +1000 for t in range(self.T): +1001 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): +1002 newcontent.append(None) +1003 else: +1004 newcontent.append(self.content[t] + y.content[t]) +1005 return Corr(newcontent) +1006 +1007 elif isinstance(y, (Obs, int, float, CObs)): +1008 newcontent = [] +1009 for t in range(self.T): +1010 if _check_for_none(self, self.content[t]): +1011 newcontent.append(None) +1012 else: +1013 newcontent.append(self.content[t] + y) +1014 return Corr(newcontent, prange=self.prange) +1015 elif isinstance(y, np.ndarray): +1016 if y.shape == (self.T,): +1017 return Corr(list((np.array(self.content).T + y).T)) +1018 else: +1019 raise ValueError("operands could not be broadcast together") +1020 else: +1021 raise TypeError("Corr + wrong type") +1022 +1023 def __mul__(self, y): +1024 if isinstance(y, Corr): +1025 if not ((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): +1026 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") +1027 newcontent = [] +1028 for t in range(self.T): +1029 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): +1030 newcontent.append(None) +1031 else: +1032 newcontent.append(self.content[t] * y.content[t]) +1033 return Corr(newcontent) +1034 +1035 elif isinstance(y, (Obs, int, float, CObs)): +1036 newcontent = [] +1037 for t in range(self.T): +1038 if _check_for_none(self, self.content[t]): +1039 newcontent.append(None) +1040 else: +1041 newcontent.append(self.content[t] * y) +1042 return Corr(newcontent, prange=self.prange) +1043 elif isinstance(y, np.ndarray): +1044 if y.shape == (self.T,): +1045 return Corr(list((np.array(self.content).T * y).T)) +1046 else: +1047 raise ValueError("operands could not be broadcast together") +1048 else: +1049 raise TypeError("Corr * wrong type") +1050 +1051 def __truediv__(self, y): +1052 if isinstance(y, Corr): +1053 if not ((self.N == 1 or y.N == 1 or self.N == y.N) and self.T == y.T): +1054 raise Exception("Multiplication of Corr object requires N=N or N=1 and T=T") +1055 newcontent = [] +1056 for t in range(self.T): +1057 if _check_for_none(self, self.content[t]) or _check_for_none(y, y.content[t]): +1058 newcontent.append(None) +1059 else: +1060 newcontent.append(self.content[t] / y.content[t]) +1061 for t in range(self.T): +1062 if _check_for_none(self, newcontent[t]): +1063 continue +1064 if np.isnan(np.sum(newcontent[t]).value): +1065 newcontent[t] = None +1066 +1067 if all([item is None for item in newcontent]): +1068 raise Exception("Division returns completely undefined correlator") +1069 return Corr(newcontent) +1070 +1071 elif isinstance(y, (Obs, CObs)): +1072 if isinstance(y, Obs): +1073 if y.value == 0: +1074 raise Exception('Division by zero will return undefined correlator') +1075 if isinstance(y, CObs): +1076 if y.is_zero(): 1077 raise Exception('Division by zero will return undefined correlator') -1078 if isinstance(y, CObs): -1079 if y.is_zero(): -1080 raise Exception('Division by zero will return undefined correlator') -1081 -1082 newcontent = [] -1083 for t in range(self.T): -1084 if _check_for_none(self, self.content[t]): -1085 newcontent.append(None) -1086 else: -1087 newcontent.append(self.content[t] / y) -1088 return Corr(newcontent, prange=self.prange) -1089 -1090 elif isinstance(y, (int, float)): -1091 if y == 0: -1092 raise Exception('Division by zero will return undefined correlator') -1093 newcontent = [] -1094 for t in range(self.T): -1095 if _check_for_none(self, self.content[t]): -1096 newcontent.append(None) -1097 else: -1098 newcontent.append(self.content[t] / y) -1099 return Corr(newcontent, prange=self.prange) -1100 elif isinstance(y, np.ndarray): -1101 if y.shape == (self.T,): -1102 return Corr(list((np.array(self.content).T / y).T)) -1103 else: -1104 raise ValueError("operands could not be broadcast together") -1105 else: -1106 raise TypeError('Corr / wrong type') -1107 -1108 def __neg__(self): -1109 newcontent = [None if _check_for_none(self, item) else -1. * item for item in self.content] -1110 return Corr(newcontent, prange=self.prange) +1078 +1079 newcontent = [] +1080 for t in range(self.T): +1081 if _check_for_none(self, self.content[t]): +1082 newcontent.append(None) +1083 else: +1084 newcontent.append(self.content[t] / y) +1085 return Corr(newcontent, prange=self.prange) +1086 +1087 elif isinstance(y, (int, float)): +1088 if y == 0: +1089 raise Exception('Division by zero will return undefined correlator') +1090 newcontent = [] +1091 for t in range(self.T): +1092 if _check_for_none(self, self.content[t]): +1093 newcontent.append(None) +1094 else: +1095 newcontent.append(self.content[t] / y) +1096 return Corr(newcontent, prange=self.prange) +1097 elif isinstance(y, np.ndarray): +1098 if y.shape == (self.T,): +1099 return Corr(list((np.array(self.content).T / y).T)) +1100 else: +1101 raise ValueError("operands could not be broadcast together") +1102 else: +1103 raise TypeError('Corr / wrong type') +1104 +1105 def __neg__(self): +1106 newcontent = [None if _check_for_none(self, item) else -1. * item for item in self.content] +1107 return Corr(newcontent, prange=self.prange) +1108 +1109 def __sub__(self, y): +1110 return self + (-y) 1111 -1112 def __sub__(self, y): -1113 return self + (-y) -1114 -1115 def __pow__(self, y): -1116 if isinstance(y, (Obs, int, float, CObs)): -1117 newcontent = [None if _check_for_none(self, item) else item**y for item in self.content] -1118 return Corr(newcontent, prange=self.prange) -1119 else: -1120 raise TypeError('Type of exponent not supported') -1121 -1122 def __abs__(self): -1123 newcontent = [None if _check_for_none(self, item) else np.abs(item) for item in self.content] -1124 return Corr(newcontent, prange=self.prange) -1125 -1126 # The numpy functions: -1127 def sqrt(self): -1128 return self ** 0.5 -1129 -1130 def log(self): -1131 newcontent = [None if _check_for_none(self, item) else np.log(item) for item in self.content] -1132 return Corr(newcontent, prange=self.prange) -1133 -1134 def exp(self): -1135 newcontent = [None if _check_for_none(self, item) else np.exp(item) for item in self.content] -1136 return Corr(newcontent, prange=self.prange) -1137 -1138 def _apply_func_to_corr(self, func): -1139 newcontent = [None if _check_for_none(self, item) else func(item) for item in self.content] -1140 for t in range(self.T): -1141 if _check_for_none(self, newcontent[t]): -1142 continue -1143 if np.isnan(np.sum(newcontent[t]).value): -1144 newcontent[t] = None -1145 if all([item is None for item in newcontent]): -1146 raise Exception('Operation returns undefined correlator') -1147 return Corr(newcontent) +1112 def __pow__(self, y): +1113 if isinstance(y, (Obs, int, float, CObs)): +1114 newcontent = [None if _check_for_none(self, item) else item**y for item in self.content] +1115 return Corr(newcontent, prange=self.prange) +1116 else: +1117 raise TypeError('Type of exponent not supported') +1118 +1119 def __abs__(self): +1120 newcontent = [None if _check_for_none(self, item) else np.abs(item) for item in self.content] +1121 return Corr(newcontent, prange=self.prange) +1122 +1123 # The numpy functions: +1124 def sqrt(self): +1125 return self ** 0.5 +1126 +1127 def log(self): +1128 newcontent = [None if _check_for_none(self, item) else np.log(item) for item in self.content] +1129 return Corr(newcontent, prange=self.prange) +1130 +1131 def exp(self): +1132 newcontent = [None if _check_for_none(self, item) else np.exp(item) for item in self.content] +1133 return Corr(newcontent, prange=self.prange) +1134 +1135 def _apply_func_to_corr(self, func): +1136 newcontent = [None if _check_for_none(self, item) else func(item) for item in self.content] +1137 for t in range(self.T): +1138 if _check_for_none(self, newcontent[t]): +1139 continue +1140 if np.isnan(np.sum(newcontent[t]).value): +1141 newcontent[t] = None +1142 if all([item is None for item in newcontent]): +1143 raise Exception('Operation returns undefined correlator') +1144 return Corr(newcontent) +1145 +1146 def sin(self): +1147 return self._apply_func_to_corr(np.sin) 1148 -1149 def sin(self): -1150 return self._apply_func_to_corr(np.sin) +1149 def cos(self): +1150 return self._apply_func_to_corr(np.cos) 1151 -1152 def cos(self): -1153 return self._apply_func_to_corr(np.cos) +1152 def tan(self): +1153 return self._apply_func_to_corr(np.tan) 1154 -1155 def tan(self): -1156 return self._apply_func_to_corr(np.tan) +1155 def sinh(self): +1156 return self._apply_func_to_corr(np.sinh) 1157 -1158 def sinh(self): -1159 return self._apply_func_to_corr(np.sinh) +1158 def cosh(self): +1159 return self._apply_func_to_corr(np.cosh) 1160 -1161 def cosh(self): -1162 return self._apply_func_to_corr(np.cosh) +1161 def tanh(self): +1162 return self._apply_func_to_corr(np.tanh) 1163 -1164 def tanh(self): -1165 return self._apply_func_to_corr(np.tanh) +1164 def arcsin(self): +1165 return self._apply_func_to_corr(np.arcsin) 1166 -1167 def arcsin(self): -1168 return self._apply_func_to_corr(np.arcsin) +1167 def arccos(self): +1168 return self._apply_func_to_corr(np.arccos) 1169 -1170 def arccos(self): -1171 return self._apply_func_to_corr(np.arccos) +1170 def arctan(self): +1171 return self._apply_func_to_corr(np.arctan) 1172 -1173 def arctan(self): -1174 return self._apply_func_to_corr(np.arctan) +1173 def arcsinh(self): +1174 return self._apply_func_to_corr(np.arcsinh) 1175 -1176 def arcsinh(self): -1177 return self._apply_func_to_corr(np.arcsinh) +1176 def arccosh(self): +1177 return self._apply_func_to_corr(np.arccosh) 1178 -1179 def arccosh(self): -1180 return self._apply_func_to_corr(np.arccosh) +1179 def arctanh(self): +1180 return self._apply_func_to_corr(np.arctanh) 1181 -1182 def arctanh(self): -1183 return self._apply_func_to_corr(np.arctanh) -1184 -1185 # Right hand side operations (require tweak in main module to work) -1186 def __radd__(self, y): -1187 return self + y +1182 # Right hand side operations (require tweak in main module to work) +1183 def __radd__(self, y): +1184 return self + y +1185 +1186 def __rsub__(self, y): +1187 return -self + y 1188 -1189 def __rsub__(self, y): -1190 return -self + y +1189 def __rmul__(self, y): +1190 return self * y 1191 -1192 def __rmul__(self, y): -1193 return self * y +1192 def __rtruediv__(self, y): +1193 return (self / y) ** (-1) 1194 -1195 def __rtruediv__(self, y): -1196 return (self / y) ** (-1) -1197 -1198 @property -1199 def real(self): -1200 def return_real(obs_OR_cobs): -1201 if isinstance(obs_OR_cobs, CObs): -1202 return obs_OR_cobs.real -1203 else: -1204 return obs_OR_cobs -1205 -1206 return self._apply_func_to_corr(return_real) -1207 -1208 @property -1209 def imag(self): -1210 def return_imag(obs_OR_cobs): -1211 if isinstance(obs_OR_cobs, CObs): -1212 return obs_OR_cobs.imag -1213 else: -1214 return obs_OR_cobs * 0 # So it stays the right type -1215 -1216 return self._apply_func_to_corr(return_imag) +1195 @property +1196 def real(self): +1197 def return_real(obs_OR_cobs): +1198 if isinstance(obs_OR_cobs, CObs): +1199 return obs_OR_cobs.real +1200 else: +1201 return obs_OR_cobs +1202 +1203 return self._apply_func_to_corr(return_real) +1204 +1205 @property +1206 def imag(self): +1207 def return_imag(obs_OR_cobs): +1208 if isinstance(obs_OR_cobs, CObs): +1209 return obs_OR_cobs.imag +1210 else: +1211 return obs_OR_cobs * 0 # So it stays the right type +1212 +1213 return self._apply_func_to_corr(return_imag) +1214 +1215 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): +1216 r''' Project large correlation matrix to lowest states 1217 -1218 def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None): -1219 r''' Project large correlation matrix to lowest states -1220 -1221 This method can be used to reduce the size of an (N x N) correlation matrix -1222 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise -1223 is still small. -1224 -1225 Parameters -1226 ---------- -1227 Ntrunc: int -1228 Rank of the target matrix. -1229 tproj: int -1230 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. -1231 The default value is 3. -1232 t0proj: int -1233 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly -1234 discouraged for O(a) improved theories, since the correctness of the procedure -1235 cannot be granted in this case. The default value is 2. -1236 basematrix : Corr -1237 Correlation matrix that is used to determine the eigenvectors of the -1238 lowest states based on a GEVP. basematrix is taken to be the Corr itself if -1239 is is not specified. -1240 -1241 Notes -1242 ----- -1243 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving -1244 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}$ -1245 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the -1246 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via -1247 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large -1248 correlation matrix and to remove some noise that is added by irrelevant operators. -1249 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated -1250 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. -1251 ''' -1252 -1253 if self.N == 1: -1254 raise Exception('Method cannot be applied to one-dimensional correlators.') -1255 if basematrix is None: -1256 basematrix = self -1257 if Ntrunc >= basematrix.N: -1258 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) -1259 if basematrix.N != self.N: -1260 raise Exception('basematrix and targetmatrix have to be of the same size.') -1261 -1262 evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc] -1263 -1264 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) -1265 rmat = [] -1266 for t in range(basematrix.T): -1267 for i in range(Ntrunc): -1268 for j in range(Ntrunc): -1269 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] -1270 rmat.append(np.copy(tmpmat)) -1271 -1272 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] -1273 return Corr(newcontent) +1218 This method can be used to reduce the size of an (N x N) correlation matrix +1219 to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise +1220 is still small. +1221 +1222 Parameters +1223 ---------- +1224 Ntrunc: int +1225 Rank of the target matrix. +1226 tproj: int +1227 Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method. +1228 The default value is 3. +1229 t0proj: int +1230 Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly +1231 discouraged for O(a) improved theories, since the correctness of the procedure +1232 cannot be granted in this case. The default value is 2. +1233 basematrix : Corr +1234 Correlation matrix that is used to determine the eigenvectors of the +1235 lowest states based on a GEVP. basematrix is taken to be the Corr itself if +1236 is is not specified. +1237 +1238 Notes +1239 ----- +1240 We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving +1241 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}$ +1242 and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the +1243 resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via +1244 $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large +1245 correlation matrix and to remove some noise that is added by irrelevant operators. +1246 This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated +1247 bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$. +1248 ''' +1249 +1250 if self.N == 1: +1251 raise Exception('Method cannot be applied to one-dimensional correlators.') +1252 if basematrix is None: +1253 basematrix = self +1254 if Ntrunc >= basematrix.N: +1255 raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N)) +1256 if basematrix.N != self.N: +1257 raise Exception('basematrix and targetmatrix have to be of the same size.') +1258 +1259 evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc] +1260 +1261 tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object) +1262 rmat = [] +1263 for t in range(basematrix.T): +1264 for i in range(Ntrunc): +1265 for j in range(Ntrunc): +1266 tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j] +1267 rmat.append(np.copy(tmpmat)) +1268 +1269 newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)] +1270 return Corr(newcontent) @@ -2870,33 +2864,30 @@ matrix at every timeslice. Other dependency (eg. spatial) are not supported.

70 71 if isinstance(data_input, list): 72 -73 if all([isinstance(item, (Obs, CObs)) for item in data_input]): -74 _assert_equal_properties(data_input) -75 self.content = [np.asarray([item]) for item in data_input] -76 if all([isinstance(item, (Obs, CObs)) or item is None for item in data_input]): -77 _assert_equal_properties([o for o in data_input if o is not None]) -78 self.content = [np.asarray([item]) if item is not None else None for item in data_input] -79 self.N = 1 -80 -81 elif all([isinstance(item, np.ndarray) or item is None for item in data_input]) and any([isinstance(item, np.ndarray) for item in data_input]): -82 self.content = data_input -83 noNull = [a for a in self.content if not (a is None)] # To check if the matrices are correct for all undefined elements -84 self.N = noNull[0].shape[0] -85 if self.N > 1 and noNull[0].shape[0] != noNull[0].shape[1]: -86 raise Exception("Smearing matrices are not NxN") -87 if (not all([item.shape == noNull[0].shape for item in noNull])): -88 raise Exception("Items in data_input are not of identical shape." + str(noNull)) -89 else: -90 raise Exception("data_input contains item of wrong type") -91 else: -92 raise Exception("Data input was not given as list or correct array") -93 -94 self.tag = None -95 -96 # An undefined timeslice is represented by the None object -97 self.content = [None] * padding[0] + self.content + [None] * padding[1] -98 self.T = len(self.content) -99 self.prange = prange +73 if all([isinstance(item, (Obs, CObs)) or item is None for item in data_input]): +74 _assert_equal_properties([o for o in data_input if o is not None]) +75 self.content = [np.asarray([item]) if item is not None else None for item in data_input] +76 self.N = 1 +77 +78 elif all([isinstance(item, np.ndarray) or item is None for item in data_input]) and any([isinstance(item, np.ndarray) for item in data_input]): +79 self.content = data_input +80 noNull = [a for a in self.content if not (a is None)] # To check if the matrices are correct for all undefined elements +81 self.N = noNull[0].shape[0] +82 if self.N > 1 and noNull[0].shape[0] != noNull[0].shape[1]: +83 raise Exception("Smearing matrices are not NxN") +84 if (not all([item.shape == noNull[0].shape for item in noNull])): +85 raise Exception("Items in data_input are not of identical shape." + str(noNull)) +86 else: +87 raise Exception("data_input contains item of wrong type") +88 else: +89 raise Exception("Data input was not given as list or correct array") +90 +91 self.tag = None +92 +93 # An undefined timeslice is represented by the None object +94 self.content = [None] * padding[0] + self.content + [None] * padding[1] +95 self.T = len(self.content) +96 self.prange = prange @@ -2930,16 +2921,16 @@ region indentified for this correlator. -
120    def gamma_method(self, **kwargs):
-121        """Apply the gamma method to the content of the Corr."""
-122        for item in self.content:
-123            if not (item is None):
-124                if self.N == 1:
-125                    item[0].gamma_method(**kwargs)
-126                else:
-127                    for i in range(self.N):
-128                        for j in range(self.N):
-129                            item[i, j].gamma_method(**kwargs)
+            
117    def gamma_method(self, **kwargs):
+118        """Apply the gamma method to the content of the Corr."""
+119        for item in self.content:
+120            if not (item is None):
+121                if self.N == 1:
+122                    item[0].gamma_method(**kwargs)
+123                else:
+124                    for i in range(self.N):
+125                        for j in range(self.N):
+126                            item[i, j].gamma_method(**kwargs)
 
@@ -2959,44 +2950,44 @@ region indentified for this correlator.
-
131    def projected(self, vector_l=None, vector_r=None, normalize=False):
-132        """We need to project the Correlator with a Vector to get a single value at each timeslice.
-133
-134        The method can use one or two vectors.
-135        If two are specified it returns v1@G@v2 (the order might be very important.)
-136        By default it will return the lowest source, which usually means unsmeared-unsmeared (0,0), but it does not have to
-137        """
-138        if self.N == 1:
-139            raise Exception("Trying to project a Corr, that already has N=1.")
-140
-141        if vector_l is None:
-142            vector_l, vector_r = np.asarray([1.] + (self.N - 1) * [0.]), np.asarray([1.] + (self.N - 1) * [0.])
-143        elif (vector_r is None):
-144            vector_r = vector_l
-145        if isinstance(vector_l, list) and not isinstance(vector_r, list):
-146            if len(vector_l) != self.T:
-147                raise Exception("Length of vector list must be equal to T")
-148            vector_r = [vector_r] * self.T
-149        if isinstance(vector_r, list) and not isinstance(vector_l, list):
-150            if len(vector_r) != self.T:
-151                raise Exception("Length of vector list must be equal to T")
-152            vector_l = [vector_l] * self.T
-153
-154        if not isinstance(vector_l, list):
-155            if not vector_l.shape == vector_r.shape == (self.N,):
-156                raise Exception("Vectors are of wrong shape!")
-157            if normalize:
-158                vector_l, vector_r = vector_l / np.sqrt((vector_l @ vector_l)), vector_r / np.sqrt(vector_r @ vector_r)
-159            newcontent = [None if _check_for_none(self, item) else np.asarray([vector_l.T @ item @ vector_r]) for item in self.content]
-160
-161        else:
-162            # There are no checks here yet. There are so many possible scenarios, where this can go wrong.
-163            if normalize:
-164                for t in range(self.T):
-165                    vector_l[t], vector_r[t] = vector_l[t] / np.sqrt((vector_l[t] @ vector_l[t])), vector_r[t] / np.sqrt(vector_r[t] @ vector_r[t])
-166
-167            newcontent = [None if (_check_for_none(self, self.content[t]) or vector_l[t] is None or vector_r[t] is None) else np.asarray([vector_l[t].T @ self.content[t] @ vector_r[t]]) for t in range(self.T)]
-168        return Corr(newcontent)
+            
128    def projected(self, vector_l=None, vector_r=None, normalize=False):
+129        """We need to project the Correlator with a Vector to get a single value at each timeslice.
+130
+131        The method can use one or two vectors.
+132        If two are specified it returns v1@G@v2 (the order might be very important.)
+133        By default it will return the lowest source, which usually means unsmeared-unsmeared (0,0), but it does not have to
+134        """
+135        if self.N == 1:
+136            raise Exception("Trying to project a Corr, that already has N=1.")
+137
+138        if vector_l is None:
+139            vector_l, vector_r = np.asarray([1.] + (self.N - 1) * [0.]), np.asarray([1.] + (self.N - 1) * [0.])
+140        elif (vector_r is None):
+141            vector_r = vector_l
+142        if isinstance(vector_l, list) and not isinstance(vector_r, list):
+143            if len(vector_l) != self.T:
+144                raise Exception("Length of vector list must be equal to T")
+145            vector_r = [vector_r] * self.T
+146        if isinstance(vector_r, list) and not isinstance(vector_l, list):
+147            if len(vector_r) != self.T:
+148                raise Exception("Length of vector list must be equal to T")
+149            vector_l = [vector_l] * self.T
+150
+151        if not isinstance(vector_l, list):
+152            if not vector_l.shape == vector_r.shape == (self.N,):
+153                raise Exception("Vectors are of wrong shape!")
+154            if normalize:
+155                vector_l, vector_r = vector_l / np.sqrt((vector_l @ vector_l)), vector_r / np.sqrt(vector_r @ vector_r)
+156            newcontent = [None if _check_for_none(self, item) else np.asarray([vector_l.T @ item @ vector_r]) for item in self.content]
+157
+158        else:
+159            # There are no checks here yet. There are so many possible scenarios, where this can go wrong.
+160            if normalize:
+161                for t in range(self.T):
+162                    vector_l[t], vector_r[t] = vector_l[t] / np.sqrt((vector_l[t] @ vector_l[t])), vector_r[t] / np.sqrt(vector_r[t] @ vector_r[t])
+163
+164            newcontent = [None if (_check_for_none(self, self.content[t]) or vector_l[t] is None or vector_r[t] is None) else np.asarray([vector_l[t].T @ self.content[t] @ vector_r[t]]) for t in range(self.T)]
+165        return Corr(newcontent)
 
@@ -3020,20 +3011,20 @@ By default it will return the lowest source, which usually means unsmeared-unsme
-
170    def item(self, i, j):
-171        """Picks the element [i,j] from every matrix and returns a correlator containing one Obs per timeslice.
-172
-173        Parameters
-174        ----------
-175        i : int
-176            First index to be picked.
-177        j : int
-178            Second index to be picked.
-179        """
-180        if self.N == 1:
-181            raise Exception("Trying to pick item from projected Corr")
-182        newcontent = [None if (item is None) else item[i, j] for item in self.content]
-183        return Corr(newcontent)
+            
167    def item(self, i, j):
+168        """Picks the element [i,j] from every matrix and returns a correlator containing one Obs per timeslice.
+169
+170        Parameters
+171        ----------
+172        i : int
+173            First index to be picked.
+174        j : int
+175            Second index to be picked.
+176        """
+177        if self.N == 1:
+178            raise Exception("Trying to pick item from projected Corr")
+179        newcontent = [None if (item is None) else item[i, j] for item in self.content]
+180        return Corr(newcontent)
 
@@ -3062,19 +3053,19 @@ Second index to be picked.
-
185    def plottable(self):
-186        """Outputs the correlator in a plotable format.
-187
-188        Outputs three lists containing the timeslice index, the value on each
-189        timeslice and the error on each timeslice.
-190        """
-191        if self.N != 1:
-192            raise Exception("Can only make Corr[N=1] plottable")
-193        x_list = [x for x in range(self.T) if not self.content[x] is None]
-194        y_list = [y[0].value for y in self.content if y is not None]
-195        y_err_list = [y[0].dvalue for y in self.content if y is not None]
-196
-197        return x_list, y_list, y_err_list
+            
182    def plottable(self):
+183        """Outputs the correlator in a plotable format.
+184
+185        Outputs three lists containing the timeslice index, the value on each
+186        timeslice and the error on each timeslice.
+187        """
+188        if self.N != 1:
+189            raise Exception("Can only make Corr[N=1] plottable")
+190        x_list = [x for x in range(self.T) if not self.content[x] is None]
+191        y_list = [y[0].value for y in self.content if y is not None]
+192        y_err_list = [y[0].dvalue for y in self.content if y is not None]
+193
+194        return x_list, y_list, y_err_list
 
@@ -3097,25 +3088,25 @@ timeslice and the error on each timeslice.

-
199    def symmetric(self):
-200        """ Symmetrize the correlator around x0=0."""
-201        if self.N != 1:
-202            raise Exception('symmetric cannot be safely applied to multi-dimensional correlators.')
-203        if self.T % 2 != 0:
-204            raise Exception("Can not symmetrize odd T")
+            
196    def symmetric(self):
+197        """ Symmetrize the correlator around x0=0."""
+198        if self.N != 1:
+199            raise Exception('symmetric cannot be safely applied to multi-dimensional correlators.')
+200        if self.T % 2 != 0:
+201            raise Exception("Can not symmetrize odd T")
+202
+203        if np.argmax(np.abs(self.content)) != 0:
+204            warnings.warn("Correlator does not seem to be symmetric around x0=0.", RuntimeWarning)
 205
-206        if np.argmax(np.abs(self.content)) != 0:
-207            warnings.warn("Correlator does not seem to be symmetric around x0=0.", RuntimeWarning)
-208
-209        newcontent = [self.content[0]]
-210        for t in range(1, self.T):
-211            if (self.content[t] is None) or (self.content[self.T - t] is None):
-212                newcontent.append(None)
-213            else:
-214                newcontent.append(0.5 * (self.content[t] + self.content[self.T - t]))
-215        if (all([x is None for x in newcontent])):
-216            raise Exception("Corr could not be symmetrized: No redundant values")
-217        return Corr(newcontent, prange=self.prange)
+206        newcontent = [self.content[0]]
+207        for t in range(1, self.T):
+208            if (self.content[t] is None) or (self.content[self.T - t] is None):
+209                newcontent.append(None)
+210            else:
+211                newcontent.append(0.5 * (self.content[t] + self.content[self.T - t]))
+212        if (all([x is None for x in newcontent])):
+213            raise Exception("Corr could not be symmetrized: No redundant values")
+214        return Corr(newcontent, prange=self.prange)
 
@@ -3135,27 +3126,27 @@ timeslice and the error on each timeslice.

-
219    def anti_symmetric(self):
-220        """Anti-symmetrize the correlator around x0=0."""
-221        if self.N != 1:
-222            raise Exception('anti_symmetric cannot be safely applied to multi-dimensional correlators.')
-223        if self.T % 2 != 0:
-224            raise Exception("Can not symmetrize odd T")
-225
-226        test = 1 * self
-227        test.gamma_method()
-228        if not all([o.is_zero_within_error(3) for o in test.content[0]]):
-229            warnings.warn("Correlator does not seem to be anti-symmetric around x0=0.", RuntimeWarning)
-230
-231        newcontent = [self.content[0]]
-232        for t in range(1, self.T):
-233            if (self.content[t] is None) or (self.content[self.T - t] is None):
-234                newcontent.append(None)
-235            else:
-236                newcontent.append(0.5 * (self.content[t] - self.content[self.T - t]))
-237        if (all([x is None for x in newcontent])):
-238            raise Exception("Corr could not be symmetrized: No redundant values")
-239        return Corr(newcontent, prange=self.prange)
+            
216    def anti_symmetric(self):
+217        """Anti-symmetrize the correlator around x0=0."""
+218        if self.N != 1:
+219            raise Exception('anti_symmetric cannot be safely applied to multi-dimensional correlators.')
+220        if self.T % 2 != 0:
+221            raise Exception("Can not symmetrize odd T")
+222
+223        test = 1 * self
+224        test.gamma_method()
+225        if not all([o.is_zero_within_error(3) for o in test.content[0]]):
+226            warnings.warn("Correlator does not seem to be anti-symmetric around x0=0.", RuntimeWarning)
+227
+228        newcontent = [self.content[0]]
+229        for t in range(1, self.T):
+230            if (self.content[t] is None) or (self.content[self.T - t] is None):
+231                newcontent.append(None)
+232            else:
+233                newcontent.append(0.5 * (self.content[t] - self.content[self.T - t]))
+234        if (all([x is None for x in newcontent])):
+235            raise Exception("Corr could not be symmetrized: No redundant values")
+236        return Corr(newcontent, prange=self.prange)
 
@@ -3175,20 +3166,20 @@ timeslice and the error on each timeslice.

-
241    def is_matrix_symmetric(self):
-242        """Checks whether a correlator matrices is symmetric on every timeslice."""
-243        if self.N == 1:
-244            raise Exception("Only works for correlator matrices.")
-245        for t in range(self.T):
-246            if self[t] is None:
-247                continue
-248            for i in range(self.N):
-249                for j in range(i + 1, self.N):
-250                    if self[t][i, j] is self[t][j, i]:
-251                        continue
-252                    if hash(self[t][i, j]) != hash(self[t][j, i]):
-253                        return False
-254        return True
+            
238    def is_matrix_symmetric(self):
+239        """Checks whether a correlator matrices is symmetric on every timeslice."""
+240        if self.N == 1:
+241            raise Exception("Only works for correlator matrices.")
+242        for t in range(self.T):
+243            if self[t] is None:
+244                continue
+245            for i in range(self.N):
+246                for j in range(i + 1, self.N):
+247                    if self[t][i, j] is self[t][j, i]:
+248                        continue
+249                    if hash(self[t][i, j]) != hash(self[t][j, i]):
+250                        return False
+251        return True
 
@@ -3208,15 +3199,15 @@ timeslice and the error on each timeslice.

-
256    def matrix_symmetric(self):
-257        """Symmetrizes the correlator matrices on every timeslice."""
-258        if self.N == 1:
-259            raise Exception("Trying to symmetrize a correlator matrix, that already has N=1.")
-260        if self.is_matrix_symmetric():
-261            return 1.0 * self
-262        else:
-263            transposed = [None if _check_for_none(self, G) else G.T for G in self.content]
-264            return 0.5 * (Corr(transposed) + self)
+            
253    def matrix_symmetric(self):
+254        """Symmetrizes the correlator matrices on every timeslice."""
+255        if self.N == 1:
+256            raise Exception("Trying to symmetrize a correlator matrix, that already has N=1.")
+257        if self.is_matrix_symmetric():
+258            return 1.0 * self
+259        else:
+260            transposed = [None if _check_for_none(self, G) else G.T for G in self.content]
+261            return 0.5 * (Corr(transposed) + self)
 
@@ -3236,84 +3227,84 @@ timeslice and the error on each timeslice.

-
266    def GEVP(self, t0, ts=None, sort="Eigenvalue", **kwargs):
-267        r'''Solve the generalized eigenvalue problem on the correlator matrix and returns the corresponding eigenvectors.
-268
-269        The eigenvectors are sorted according to the descending eigenvalues, the zeroth eigenvector(s) correspond to the
-270        largest eigenvalue(s). The eigenvector(s) for the individual states can be accessed via slicing
-271        ```python
-272        C.GEVP(t0=2)[0]  # Ground state vector(s)
-273        C.GEVP(t0=2)[:3]  # Vectors for the lowest three states
-274        ```
-275
-276        Parameters
-277        ----------
-278        t0 : int
-279            The time t0 for the right hand side of the GEVP according to $G(t)v_i=\lambda_i G(t_0)v_i$
-280        ts : int
-281            fixed time $G(t_s)v_i=\lambda_i G(t_0)v_i$ if sort=None.
-282            If sort="Eigenvector" it gives a reference point for the sorting method.
-283        sort : string
-284            If this argument is set, a list of self.T vectors per state is returned. If it is set to None, only one vector is returned.
-285            - "Eigenvalue": The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice.
-286            - "Eigenvector": Use the method described in arXiv:2004.10472 to find the set of v(t) belonging to the state.
-287              The reference state is identified by its eigenvalue at $t=t_s$.
-288
-289        Other Parameters
-290        ----------------
-291        state : int
-292           Returns only the vector(s) for a specified state. The lowest state is zero.
-293        '''
-294
-295        if self.N == 1:
-296            raise Exception("GEVP methods only works on correlator matrices and not single correlators.")
-297        if ts is not None:
-298            if (ts <= t0):
-299                raise Exception("ts has to be larger than t0.")
-300
-301        if "sorted_list" in kwargs:
-302            warnings.warn("Argument 'sorted_list' is deprecated, use 'sort' instead.", DeprecationWarning)
-303            sort = kwargs.get("sorted_list")
-304
-305        if self.is_matrix_symmetric():
-306            symmetric_corr = self
-307        else:
-308            symmetric_corr = self.matrix_symmetric()
+            
263    def GEVP(self, t0, ts=None, sort="Eigenvalue", **kwargs):
+264        r'''Solve the generalized eigenvalue problem on the correlator matrix and returns the corresponding eigenvectors.
+265
+266        The eigenvectors are sorted according to the descending eigenvalues, the zeroth eigenvector(s) correspond to the
+267        largest eigenvalue(s). The eigenvector(s) for the individual states can be accessed via slicing
+268        ```python
+269        C.GEVP(t0=2)[0]  # Ground state vector(s)
+270        C.GEVP(t0=2)[:3]  # Vectors for the lowest three states
+271        ```
+272
+273        Parameters
+274        ----------
+275        t0 : int
+276            The time t0 for the right hand side of the GEVP according to $G(t)v_i=\lambda_i G(t_0)v_i$
+277        ts : int
+278            fixed time $G(t_s)v_i=\lambda_i G(t_0)v_i$ if sort=None.
+279            If sort="Eigenvector" it gives a reference point for the sorting method.
+280        sort : string
+281            If this argument is set, a list of self.T vectors per state is returned. If it is set to None, only one vector is returned.
+282            - "Eigenvalue": The eigenvector is chosen according to which eigenvalue it belongs individually on every timeslice.
+283            - "Eigenvector": Use the method described in arXiv:2004.10472 to find the set of v(t) belonging to the state.
+284              The reference state is identified by its eigenvalue at $t=t_s$.
+285
+286        Other Parameters
+287        ----------------
+288        state : int
+289           Returns only the vector(s) for a specified state. The lowest state is zero.
+290        '''
+291
+292        if self.N == 1:
+293            raise Exception("GEVP methods only works on correlator matrices and not single correlators.")
+294        if ts is not None:
+295            if (ts <= t0):
+296                raise Exception("ts has to be larger than t0.")
+297
+298        if "sorted_list" in kwargs:
+299            warnings.warn("Argument 'sorted_list' is deprecated, use 'sort' instead.", DeprecationWarning)
+300            sort = kwargs.get("sorted_list")
+301
+302        if self.is_matrix_symmetric():
+303            symmetric_corr = self
+304        else:
+305            symmetric_corr = self.matrix_symmetric()
+306
+307        G0 = np.vectorize(lambda x: x.value)(symmetric_corr[t0])
+308        np.linalg.cholesky(G0)  # Check if matrix G0 is positive-semidefinite.
 309
-310        G0 = np.vectorize(lambda x: x.value)(symmetric_corr[t0])
-311        np.linalg.cholesky(G0)  # Check if matrix G0 is positive-semidefinite.
-312
-313        if sort is None:
-314            if (ts is None):
-315                raise Exception("ts is required if sort=None.")
-316            if (self.content[t0] is None) or (self.content[ts] is None):
-317                raise Exception("Corr not defined at t0/ts.")
-318            Gt = np.vectorize(lambda x: x.value)(symmetric_corr[ts])
-319            reordered_vecs = _GEVP_solver(Gt, G0)
-320
-321        elif sort in ["Eigenvalue", "Eigenvector"]:
-322            if sort == "Eigenvalue" and ts is not None:
-323                warnings.warn("ts has no effect when sorting by eigenvalue is chosen.", RuntimeWarning)
-324            all_vecs = [None] * (t0 + 1)
-325            for t in range(t0 + 1, self.T):
-326                try:
-327                    Gt = np.vectorize(lambda x: x.value)(symmetric_corr[t])
-328                    all_vecs.append(_GEVP_solver(Gt, G0))
-329                except Exception:
-330                    all_vecs.append(None)
-331            if sort == "Eigenvector":
-332                if ts is None:
-333                    raise Exception("ts is required for the Eigenvector sorting method.")
-334                all_vecs = _sort_vectors(all_vecs, ts)
-335
-336            reordered_vecs = [[v[s] if v is not None else None for v in all_vecs] for s in range(self.N)]
-337        else:
-338            raise Exception("Unkown value for 'sort'.")
-339
-340        if "state" in kwargs:
-341            return reordered_vecs[kwargs.get("state")]
-342        else:
-343            return reordered_vecs
+310        if sort is None:
+311            if (ts is None):
+312                raise Exception("ts is required if sort=None.")
+313            if (self.content[t0] is None) or (self.content[ts] is None):
+314                raise Exception("Corr not defined at t0/ts.")
+315            Gt = np.vectorize(lambda x: x.value)(symmetric_corr[ts])
+316            reordered_vecs = _GEVP_solver(Gt, G0)
+317
+318        elif sort in ["Eigenvalue", "Eigenvector"]:
+319            if sort == "Eigenvalue" and ts is not None:
+320                warnings.warn("ts has no effect when sorting by eigenvalue is chosen.", RuntimeWarning)
+321            all_vecs = [None] * (t0 + 1)
+322            for t in range(t0 + 1, self.T):
+323                try:
+324                    Gt = np.vectorize(lambda x: x.value)(symmetric_corr[t])
+325                    all_vecs.append(_GEVP_solver(Gt, G0))
+326                except Exception:
+327                    all_vecs.append(None)
+328            if sort == "Eigenvector":
+329                if ts is None:
+330                    raise Exception("ts is required for the Eigenvector sorting method.")
+331                all_vecs = _sort_vectors(all_vecs, ts)
+332
+333            reordered_vecs = [[v[s] if v is not None else None for v in all_vecs] for s in range(self.N)]
+334        else:
+335            raise Exception("Unkown value for 'sort'.")
+336
+337        if "state" in kwargs:
+338            return reordered_vecs[kwargs.get("state")]
+339        else:
+340            return reordered_vecs
 
@@ -3366,18 +3357,18 @@ Returns only the vector(s) for a specified state. The lowest state is zero.
-
345    def Eigenvalue(self, t0, ts=None, state=0, sort="Eigenvalue"):
-346        """Determines the eigenvalue of the GEVP by solving and projecting the correlator
-347
-348        Parameters
-349        ----------
-350        state : int
-351            The state one is interested in ordered by energy. The lowest state is zero.
-352
-353        All other parameters are identical to the ones of Corr.GEVP.
-354        """
-355        vec = self.GEVP(t0, ts=ts, sort=sort)[state]
-356        return self.projected(vec)
+            
342    def Eigenvalue(self, t0, ts=None, state=0, sort="Eigenvalue"):
+343        """Determines the eigenvalue of the GEVP by solving and projecting the correlator
+344
+345        Parameters
+346        ----------
+347        state : int
+348            The state one is interested in ordered by energy. The lowest state is zero.
+349
+350        All other parameters are identical to the ones of Corr.GEVP.
+351        """
+352        vec = self.GEVP(t0, ts=ts, sort=sort)[state]
+353        return self.projected(vec)
 
@@ -3405,46 +3396,46 @@ The state one is interested in ordered by energy. The lowest state is zero.
-
358    def Hankel(self, N, periodic=False):
-359        """Constructs an NxN Hankel matrix
-360
-361        C(t) c(t+1) ... c(t+n-1)
-362        C(t+1) c(t+2) ... c(t+n)
-363        .................
-364        C(t+(n-1)) c(t+n) ... c(t+2(n-1))
-365
-366        Parameters
-367        ----------
-368        N : int
-369            Dimension of the Hankel matrix
-370        periodic : bool, optional
-371            determines whether the matrix is extended periodically
-372        """
+            
355    def Hankel(self, N, periodic=False):
+356        """Constructs an NxN Hankel matrix
+357
+358        C(t) c(t+1) ... c(t+n-1)
+359        C(t+1) c(t+2) ... c(t+n)
+360        .................
+361        C(t+(n-1)) c(t+n) ... c(t+2(n-1))
+362
+363        Parameters
+364        ----------
+365        N : int
+366            Dimension of the Hankel matrix
+367        periodic : bool, optional
+368            determines whether the matrix is extended periodically
+369        """
+370
+371        if self.N != 1:
+372            raise Exception("Multi-operator Prony not implemented!")
 373
-374        if self.N != 1:
-375            raise Exception("Multi-operator Prony not implemented!")
-376
-377        array = np.empty([N, N], dtype="object")
-378        new_content = []
-379        for t in range(self.T):
-380            new_content.append(array.copy())
-381
-382        def wrap(i):
-383            while i >= self.T:
-384                i -= self.T
-385            return i
-386
-387        for t in range(self.T):
-388            for i in range(N):
-389                for j in range(N):
-390                    if periodic:
-391                        new_content[t][i, j] = self.content[wrap(t + i + j)][0]
-392                    elif (t + i + j) >= self.T:
-393                        new_content[t] = None
-394                    else:
-395                        new_content[t][i, j] = self.content[t + i + j][0]
-396
-397        return Corr(new_content)
+374        array = np.empty([N, N], dtype="object")
+375        new_content = []
+376        for t in range(self.T):
+377            new_content.append(array.copy())
+378
+379        def wrap(i):
+380            while i >= self.T:
+381                i -= self.T
+382            return i
+383
+384        for t in range(self.T):
+385            for i in range(N):
+386                for j in range(N):
+387                    if periodic:
+388                        new_content[t][i, j] = self.content[wrap(t + i + j)][0]
+389                    elif (t + i + j) >= self.T:
+390                        new_content[t] = None
+391                    else:
+392                        new_content[t][i, j] = self.content[t + i + j][0]
+393
+394        return Corr(new_content)
 
@@ -3478,15 +3469,15 @@ determines whether the matrix is extended periodically
-
399    def roll(self, dt):
-400        """Periodically shift the correlator by dt timeslices
-401
-402        Parameters
-403        ----------
-404        dt : int
-405            number of timeslices
-406        """
-407        return Corr(list(np.roll(np.array(self.content, dtype=object), dt)))
+            
396    def roll(self, dt):
+397        """Periodically shift the correlator by dt timeslices
+398
+399        Parameters
+400        ----------
+401        dt : int
+402            number of timeslices
+403        """
+404        return Corr(list(np.roll(np.array(self.content, dtype=object), dt)))
 
@@ -3513,9 +3504,9 @@ number of timeslices
-
409    def reverse(self):
-410        """Reverse the time ordering of the Corr"""
-411        return Corr(self.content[:: -1])
+            
406    def reverse(self):
+407        """Reverse the time ordering of the Corr"""
+408        return Corr(self.content[:: -1])
 
@@ -3535,23 +3526,23 @@ number of timeslices
-
413    def thin(self, spacing=2, offset=0):
-414        """Thin out a correlator to suppress correlations
-415
-416        Parameters
-417        ----------
-418        spacing : int
-419            Keep only every 'spacing'th entry of the correlator
-420        offset : int
-421            Offset the equal spacing
-422        """
-423        new_content = []
-424        for t in range(self.T):
-425            if (offset + t) % spacing != 0:
-426                new_content.append(None)
-427            else:
-428                new_content.append(self.content[t])
-429        return Corr(new_content)
+            
410    def thin(self, spacing=2, offset=0):
+411        """Thin out a correlator to suppress correlations
+412
+413        Parameters
+414        ----------
+415        spacing : int
+416            Keep only every 'spacing'th entry of the correlator
+417        offset : int
+418            Offset the equal spacing
+419        """
+420        new_content = []
+421        for t in range(self.T):
+422            if (offset + t) % spacing != 0:
+423                new_content.append(None)
+424            else:
+425                new_content.append(self.content[t])
+426        return Corr(new_content)
 
@@ -3580,34 +3571,34 @@ Offset the equal spacing
-
431    def correlate(self, partner):
-432        """Correlate the correlator with another correlator or Obs
-433
-434        Parameters
-435        ----------
-436        partner : Obs or Corr
-437            partner to correlate the correlator with.
-438            Can either be an Obs which is correlated with all entries of the
-439            correlator or a Corr of same length.
-440        """
-441        if self.N != 1:
-442            raise Exception("Only one-dimensional correlators can be safely correlated.")
-443        new_content = []
-444        for x0, t_slice in enumerate(self.content):
-445            if _check_for_none(self, t_slice):
-446                new_content.append(None)
-447            else:
-448                if isinstance(partner, Corr):
-449                    if _check_for_none(partner, partner.content[x0]):
-450                        new_content.append(None)
-451                    else:
-452                        new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice]))
-453                elif isinstance(partner, Obs):  # Should this include CObs?
-454                    new_content.append(np.array([correlate(o, partner) for o in t_slice]))
-455                else:
-456                    raise Exception("Can only correlate with an Obs or a Corr.")
-457
-458        return Corr(new_content)
+            
428    def correlate(self, partner):
+429        """Correlate the correlator with another correlator or Obs
+430
+431        Parameters
+432        ----------
+433        partner : Obs or Corr
+434            partner to correlate the correlator with.
+435            Can either be an Obs which is correlated with all entries of the
+436            correlator or a Corr of same length.
+437        """
+438        if self.N != 1:
+439            raise Exception("Only one-dimensional correlators can be safely correlated.")
+440        new_content = []
+441        for x0, t_slice in enumerate(self.content):
+442            if _check_for_none(self, t_slice):
+443                new_content.append(None)
+444            else:
+445                if isinstance(partner, Corr):
+446                    if _check_for_none(partner, partner.content[x0]):
+447                        new_content.append(None)
+448                    else:
+449                        new_content.append(np.array([correlate(o, partner.content[x0][0]) for o in t_slice]))
+450                elif isinstance(partner, Obs):  # Should this include CObs?
+451                    new_content.append(np.array([correlate(o, partner) for o in t_slice]))
+452                else:
+453                    raise Exception("Can only correlate with an Obs or a Corr.")
+454
+455        return Corr(new_content)
 
@@ -3636,28 +3627,28 @@ correlator or a Corr of same length.
-
460    def reweight(self, weight, **kwargs):
-461        """Reweight the correlator.
-462
-463        Parameters
-464        ----------
-465        weight : Obs
-466            Reweighting factor. An Observable that has to be defined on a superset of the
-467            configurations in obs[i].idl for all i.
-468        all_configs : bool
-469            if True, the reweighted observables are normalized by the average of
-470            the reweighting factor on all configurations in weight.idl and not
-471            on the configurations in obs[i].idl.
-472        """
-473        if self.N != 1:
-474            raise Exception("Reweighting only implemented for one-dimensional correlators.")
-475        new_content = []
-476        for t_slice in self.content:
-477            if _check_for_none(self, t_slice):
-478                new_content.append(None)
-479            else:
-480                new_content.append(np.array(reweight(weight, t_slice, **kwargs)))
-481        return Corr(new_content)
+            
457    def reweight(self, weight, **kwargs):
+458        """Reweight the correlator.
+459
+460        Parameters
+461        ----------
+462        weight : Obs
+463            Reweighting factor. An Observable that has to be defined on a superset of the
+464            configurations in obs[i].idl for all i.
+465        all_configs : bool
+466            if True, the reweighted observables are normalized by the average of
+467            the reweighting factor on all configurations in weight.idl and not
+468            on the configurations in obs[i].idl.
+469        """
+470        if self.N != 1:
+471            raise Exception("Reweighting only implemented for one-dimensional correlators.")
+472        new_content = []
+473        for t_slice in self.content:
+474            if _check_for_none(self, t_slice):
+475                new_content.append(None)
+476            else:
+477                new_content.append(np.array(reweight(weight, t_slice, **kwargs)))
+478        return Corr(new_content)
 
@@ -3689,35 +3680,35 @@ on the configurations in obs[i].idl.
-
483    def T_symmetry(self, partner, parity=+1):
-484        """Return the time symmetry average of the correlator and its partner
-485
-486        Parameters
-487        ----------
-488        partner : Corr
-489            Time symmetry partner of the Corr
-490        partity : int
-491            Parity quantum number of the correlator, can be +1 or -1
-492        """
-493        if self.N != 1:
-494            raise Exception("T_symmetry only implemented for one-dimensional correlators.")
-495        if not isinstance(partner, Corr):
-496            raise Exception("T partner has to be a Corr object.")
-497        if parity not in [+1, -1]:
-498            raise Exception("Parity has to be +1 or -1.")
-499        T_partner = parity * partner.reverse()
-500
-501        t_slices = []
-502        test = (self - T_partner)
-503        test.gamma_method()
-504        for x0, t_slice in enumerate(test.content):
-505            if t_slice is not None:
-506                if not t_slice[0].is_zero_within_error(5):
-507                    t_slices.append(x0)
-508        if t_slices:
-509            warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning)
-510
-511        return (self + T_partner) / 2
+            
480    def T_symmetry(self, partner, parity=+1):
+481        """Return the time symmetry average of the correlator and its partner
+482
+483        Parameters
+484        ----------
+485        partner : Corr
+486            Time symmetry partner of the Corr
+487        partity : int
+488            Parity quantum number of the correlator, can be +1 or -1
+489        """
+490        if self.N != 1:
+491            raise Exception("T_symmetry only implemented for one-dimensional correlators.")
+492        if not isinstance(partner, Corr):
+493            raise Exception("T partner has to be a Corr object.")
+494        if parity not in [+1, -1]:
+495            raise Exception("Parity has to be +1 or -1.")
+496        T_partner = parity * partner.reverse()
+497
+498        t_slices = []
+499        test = (self - T_partner)
+500        test.gamma_method()
+501        for x0, t_slice in enumerate(test.content):
+502            if t_slice is not None:
+503                if not t_slice[0].is_zero_within_error(5):
+504                    t_slices.append(x0)
+505        if t_slices:
+506            warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning)
+507
+508        return (self + T_partner) / 2
 
@@ -3746,70 +3737,70 @@ Parity quantum number of the correlator, can be +1 or -1
-
513    def deriv(self, variant="symmetric"):
-514        """Return the first derivative of the correlator with respect to x0.
-515
-516        Parameters
-517        ----------
-518        variant : str
-519            decides which definition of the finite differences derivative is used.
-520            Available choice: symmetric, forward, backward, improved, log, default: symmetric
-521        """
-522        if self.N != 1:
-523            raise Exception("deriv only implemented for one-dimensional correlators.")
-524        if variant == "symmetric":
-525            newcontent = []
-526            for t in range(1, self.T - 1):
-527                if (self.content[t - 1] is None) or (self.content[t + 1] is None):
-528                    newcontent.append(None)
-529                else:
-530                    newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1]))
-531            if (all([x is None for x in newcontent])):
-532                raise Exception('Derivative is undefined at all timeslices')
-533            return Corr(newcontent, padding=[1, 1])
-534        elif variant == "forward":
-535            newcontent = []
-536            for t in range(self.T - 1):
-537                if (self.content[t] is None) or (self.content[t + 1] is None):
-538                    newcontent.append(None)
-539                else:
-540                    newcontent.append(self.content[t + 1] - self.content[t])
-541            if (all([x is None for x in newcontent])):
-542                raise Exception("Derivative is undefined at all timeslices")
-543            return Corr(newcontent, padding=[0, 1])
-544        elif variant == "backward":
-545            newcontent = []
-546            for t in range(1, self.T):
-547                if (self.content[t - 1] is None) or (self.content[t] is None):
-548                    newcontent.append(None)
-549                else:
-550                    newcontent.append(self.content[t] - self.content[t - 1])
-551            if (all([x is None for x in newcontent])):
-552                raise Exception("Derivative is undefined at all timeslices")
-553            return Corr(newcontent, padding=[1, 0])
-554        elif variant == "improved":
-555            newcontent = []
-556            for t in range(2, self.T - 2):
-557                if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None):
-558                    newcontent.append(None)
-559                else:
-560                    newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2]))
-561            if (all([x is None for x in newcontent])):
-562                raise Exception('Derivative is undefined at all timeslices')
-563            return Corr(newcontent, padding=[2, 2])
-564        elif variant == 'log':
-565            newcontent = []
-566            for t in range(self.T):
-567                if (self.content[t] is None) or (self.content[t] <= 0):
-568                    newcontent.append(None)
-569                else:
-570                    newcontent.append(np.log(self.content[t]))
-571            if (all([x is None for x in newcontent])):
-572                raise Exception("Log is undefined at all timeslices")
-573            logcorr = Corr(newcontent)
-574            return self * logcorr.deriv('symmetric')
-575        else:
-576            raise Exception("Unknown variant.")
+            
510    def deriv(self, variant="symmetric"):
+511        """Return the first derivative of the correlator with respect to x0.
+512
+513        Parameters
+514        ----------
+515        variant : str
+516            decides which definition of the finite differences derivative is used.
+517            Available choice: symmetric, forward, backward, improved, log, default: symmetric
+518        """
+519        if self.N != 1:
+520            raise Exception("deriv only implemented for one-dimensional correlators.")
+521        if variant == "symmetric":
+522            newcontent = []
+523            for t in range(1, self.T - 1):
+524                if (self.content[t - 1] is None) or (self.content[t + 1] is None):
+525                    newcontent.append(None)
+526                else:
+527                    newcontent.append(0.5 * (self.content[t + 1] - self.content[t - 1]))
+528            if (all([x is None for x in newcontent])):
+529                raise Exception('Derivative is undefined at all timeslices')
+530            return Corr(newcontent, padding=[1, 1])
+531        elif variant == "forward":
+532            newcontent = []
+533            for t in range(self.T - 1):
+534                if (self.content[t] is None) or (self.content[t + 1] is None):
+535                    newcontent.append(None)
+536                else:
+537                    newcontent.append(self.content[t + 1] - self.content[t])
+538            if (all([x is None for x in newcontent])):
+539                raise Exception("Derivative is undefined at all timeslices")
+540            return Corr(newcontent, padding=[0, 1])
+541        elif variant == "backward":
+542            newcontent = []
+543            for t in range(1, self.T):
+544                if (self.content[t - 1] is None) or (self.content[t] is None):
+545                    newcontent.append(None)
+546                else:
+547                    newcontent.append(self.content[t] - self.content[t - 1])
+548            if (all([x is None for x in newcontent])):
+549                raise Exception("Derivative is undefined at all timeslices")
+550            return Corr(newcontent, padding=[1, 0])
+551        elif variant == "improved":
+552            newcontent = []
+553            for t in range(2, self.T - 2):
+554                if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None):
+555                    newcontent.append(None)
+556                else:
+557                    newcontent.append((1 / 12) * (self.content[t - 2] - 8 * self.content[t - 1] + 8 * self.content[t + 1] - self.content[t + 2]))
+558            if (all([x is None for x in newcontent])):
+559                raise Exception('Derivative is undefined at all timeslices')
+560            return Corr(newcontent, padding=[2, 2])
+561        elif variant == 'log':
+562            newcontent = []
+563            for t in range(self.T):
+564                if (self.content[t] is None) or (self.content[t] <= 0):
+565                    newcontent.append(None)
+566                else:
+567                    newcontent.append(np.log(self.content[t]))
+568            if (all([x is None for x in newcontent])):
+569                raise Exception("Log is undefined at all timeslices")
+570            logcorr = Corr(newcontent)
+571            return self * logcorr.deriv('symmetric')
+572        else:
+573            raise Exception("Unknown variant.")
 
@@ -3837,50 +3828,50 @@ Available choice: symmetric, forward, backward, improved, log, default: symmetri
-
578    def second_deriv(self, variant="symmetric"):
-579        """Return the second derivative of the correlator with respect to x0.
-580
-581        Parameters
-582        ----------
-583        variant : str
-584            decides which definition of the finite differences derivative is used.
-585            Available choice: symmetric, improved, log, default: symmetric
-586        """
-587        if self.N != 1:
-588            raise Exception("second_deriv only implemented for one-dimensional correlators.")
-589        if variant == "symmetric":
-590            newcontent = []
-591            for t in range(1, self.T - 1):
-592                if (self.content[t - 1] is None) or (self.content[t + 1] is None):
-593                    newcontent.append(None)
-594                else:
-595                    newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1]))
-596            if (all([x is None for x in newcontent])):
-597                raise Exception("Derivative is undefined at all timeslices")
-598            return Corr(newcontent, padding=[1, 1])
-599        elif variant == "improved":
-600            newcontent = []
-601            for t in range(2, self.T - 2):
-602                if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None):
-603                    newcontent.append(None)
-604                else:
-605                    newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2]))
-606            if (all([x is None for x in newcontent])):
-607                raise Exception("Derivative is undefined at all timeslices")
-608            return Corr(newcontent, padding=[2, 2])
-609        elif variant == 'log':
-610            newcontent = []
-611            for t in range(self.T):
-612                if (self.content[t] is None) or (self.content[t] <= 0):
-613                    newcontent.append(None)
-614                else:
-615                    newcontent.append(np.log(self.content[t]))
-616            if (all([x is None for x in newcontent])):
-617                raise Exception("Log is undefined at all timeslices")
-618            logcorr = Corr(newcontent)
-619            return self * (logcorr.second_deriv('symmetric') + (logcorr.deriv('symmetric'))**2)
-620        else:
-621            raise Exception("Unknown variant.")
+            
575    def second_deriv(self, variant="symmetric"):
+576        """Return the second derivative of the correlator with respect to x0.
+577
+578        Parameters
+579        ----------
+580        variant : str
+581            decides which definition of the finite differences derivative is used.
+582            Available choice: symmetric, improved, log, default: symmetric
+583        """
+584        if self.N != 1:
+585            raise Exception("second_deriv only implemented for one-dimensional correlators.")
+586        if variant == "symmetric":
+587            newcontent = []
+588            for t in range(1, self.T - 1):
+589                if (self.content[t - 1] is None) or (self.content[t + 1] is None):
+590                    newcontent.append(None)
+591                else:
+592                    newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1]))
+593            if (all([x is None for x in newcontent])):
+594                raise Exception("Derivative is undefined at all timeslices")
+595            return Corr(newcontent, padding=[1, 1])
+596        elif variant == "improved":
+597            newcontent = []
+598            for t in range(2, self.T - 2):
+599                if (self.content[t - 2] is None) or (self.content[t - 1] is None) or (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 2] is None):
+600                    newcontent.append(None)
+601                else:
+602                    newcontent.append((1 / 12) * (-self.content[t + 2] + 16 * self.content[t + 1] - 30 * self.content[t] + 16 * self.content[t - 1] - self.content[t - 2]))
+603            if (all([x is None for x in newcontent])):
+604                raise Exception("Derivative is undefined at all timeslices")
+605            return Corr(newcontent, padding=[2, 2])
+606        elif variant == 'log':
+607            newcontent = []
+608            for t in range(self.T):
+609                if (self.content[t] is None) or (self.content[t] <= 0):
+610                    newcontent.append(None)
+611                else:
+612                    newcontent.append(np.log(self.content[t]))
+613            if (all([x is None for x in newcontent])):
+614                raise Exception("Log is undefined at all timeslices")
+615            logcorr = Corr(newcontent)
+616            return self * (logcorr.second_deriv('symmetric') + (logcorr.deriv('symmetric'))**2)
+617        else:
+618            raise Exception("Unknown variant.")
 
@@ -3908,89 +3899,89 @@ Available choice: symmetric, improved, log, default: symmetric
-
623    def m_eff(self, variant='log', guess=1.0):
-624        """Returns the effective mass of the correlator as correlator object
-625
-626        Parameters
-627        ----------
-628        variant : str
-629            log : uses the standard effective mass log(C(t) / C(t+1))
-630            cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m.
-631            sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m.
-632            See, e.g., arXiv:1205.5380
-633            arccosh : Uses the explicit form of the symmetrized correlator (not recommended)
-634            logsym: uses the symmetric effective mass log(C(t-1) / C(t+1))/2
-635        guess : float
-636            guess for the root finder, only relevant for the root variant
-637        """
-638        if self.N != 1:
-639            raise Exception('Correlator must be projected before getting m_eff')
-640        if variant == 'log':
-641            newcontent = []
-642            for t in range(self.T - 1):
-643                if ((self.content[t] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0):
-644                    newcontent.append(None)
-645                elif self.content[t][0].value / self.content[t + 1][0].value < 0:
-646                    newcontent.append(None)
-647                else:
-648                    newcontent.append(self.content[t] / self.content[t + 1])
-649            if (all([x is None for x in newcontent])):
-650                raise Exception('m_eff is undefined at all timeslices')
-651
-652            return np.log(Corr(newcontent, padding=[0, 1]))
-653
-654        elif variant == 'logsym':
-655            newcontent = []
-656            for t in range(1, self.T - 1):
-657                if ((self.content[t - 1] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0):
-658                    newcontent.append(None)
-659                elif self.content[t - 1][0].value / self.content[t + 1][0].value < 0:
-660                    newcontent.append(None)
-661                else:
-662                    newcontent.append(self.content[t - 1] / self.content[t + 1])
-663            if (all([x is None for x in newcontent])):
-664                raise Exception('m_eff is undefined at all timeslices')
-665
-666            return np.log(Corr(newcontent, padding=[1, 1])) / 2
-667
-668        elif variant in ['periodic', 'cosh', 'sinh']:
-669            if variant in ['periodic', 'cosh']:
-670                func = anp.cosh
-671            else:
-672                func = anp.sinh
+            
620    def m_eff(self, variant='log', guess=1.0):
+621        """Returns the effective mass of the correlator as correlator object
+622
+623        Parameters
+624        ----------
+625        variant : str
+626            log : uses the standard effective mass log(C(t) / C(t+1))
+627            cosh, periodic : Use periodicitiy of the correlator by solving C(t) / C(t+1) = cosh(m * (t - T/2)) / cosh(m * (t + 1 - T/2)) for m.
+628            sinh : Use anti-periodicitiy of the correlator by solving C(t) / C(t+1) = sinh(m * (t - T/2)) / sinh(m * (t + 1 - T/2)) for m.
+629            See, e.g., arXiv:1205.5380
+630            arccosh : Uses the explicit form of the symmetrized correlator (not recommended)
+631            logsym: uses the symmetric effective mass log(C(t-1) / C(t+1))/2
+632        guess : float
+633            guess for the root finder, only relevant for the root variant
+634        """
+635        if self.N != 1:
+636            raise Exception('Correlator must be projected before getting m_eff')
+637        if variant == 'log':
+638            newcontent = []
+639            for t in range(self.T - 1):
+640                if ((self.content[t] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0):
+641                    newcontent.append(None)
+642                elif self.content[t][0].value / self.content[t + 1][0].value < 0:
+643                    newcontent.append(None)
+644                else:
+645                    newcontent.append(self.content[t] / self.content[t + 1])
+646            if (all([x is None for x in newcontent])):
+647                raise Exception('m_eff is undefined at all timeslices')
+648
+649            return np.log(Corr(newcontent, padding=[0, 1]))
+650
+651        elif variant == 'logsym':
+652            newcontent = []
+653            for t in range(1, self.T - 1):
+654                if ((self.content[t - 1] is None) or (self.content[t + 1] is None)) or (self.content[t + 1][0].value == 0):
+655                    newcontent.append(None)
+656                elif self.content[t - 1][0].value / self.content[t + 1][0].value < 0:
+657                    newcontent.append(None)
+658                else:
+659                    newcontent.append(self.content[t - 1] / self.content[t + 1])
+660            if (all([x is None for x in newcontent])):
+661                raise Exception('m_eff is undefined at all timeslices')
+662
+663            return np.log(Corr(newcontent, padding=[1, 1])) / 2
+664
+665        elif variant in ['periodic', 'cosh', 'sinh']:
+666            if variant in ['periodic', 'cosh']:
+667                func = anp.cosh
+668            else:
+669                func = anp.sinh
+670
+671            def root_function(x, d):
+672                return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d
 673
-674            def root_function(x, d):
-675                return func(x * (t - self.T / 2)) / func(x * (t + 1 - self.T / 2)) - d
-676
-677            newcontent = []
-678            for t in range(self.T - 1):
-679                if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0):
-680                    newcontent.append(None)
-681                # Fill the two timeslices in the middle of the lattice with their predecessors
-682                elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]:
-683                    newcontent.append(newcontent[-1])
-684                elif self.content[t][0].value / self.content[t + 1][0].value < 0:
-685                    newcontent.append(None)
-686                else:
-687                    newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess)))
-688            if (all([x is None for x in newcontent])):
-689                raise Exception('m_eff is undefined at all timeslices')
-690
-691            return Corr(newcontent, padding=[0, 1])
-692
-693        elif variant == 'arccosh':
-694            newcontent = []
-695            for t in range(1, self.T - 1):
-696                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):
-697                    newcontent.append(None)
-698                else:
-699                    newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t]))
-700            if (all([x is None for x in newcontent])):
-701                raise Exception("m_eff is undefined at all timeslices")
-702            return np.arccosh(Corr(newcontent, padding=[1, 1]))
-703
-704        else:
-705            raise Exception('Unknown variant.')
+674            newcontent = []
+675            for t in range(self.T - 1):
+676                if (self.content[t] is None) or (self.content[t + 1] is None) or (self.content[t + 1][0].value == 0):
+677                    newcontent.append(None)
+678                # Fill the two timeslices in the middle of the lattice with their predecessors
+679                elif variant == 'sinh' and t in [self.T / 2, self.T / 2 - 1]:
+680                    newcontent.append(newcontent[-1])
+681                elif self.content[t][0].value / self.content[t + 1][0].value < 0:
+682                    newcontent.append(None)
+683                else:
+684                    newcontent.append(np.abs(find_root(self.content[t][0] / self.content[t + 1][0], root_function, guess=guess)))
+685            if (all([x is None for x in newcontent])):
+686                raise Exception('m_eff is undefined at all timeslices')
+687
+688            return Corr(newcontent, padding=[0, 1])
+689
+690        elif variant == 'arccosh':
+691            newcontent = []
+692            for t in range(1, self.T - 1):
+693                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):
+694                    newcontent.append(None)
+695                else:
+696                    newcontent.append((self.content[t + 1] + self.content[t - 1]) / (2 * self.content[t]))
+697            if (all([x is None for x in newcontent])):
+698                raise Exception("m_eff is undefined at all timeslices")
+699            return np.arccosh(Corr(newcontent, padding=[1, 1]))
+700
+701        else:
+702            raise Exception('Unknown variant.')
 
@@ -4024,39 +4015,39 @@ guess for the root finder, only relevant for the root variant
-
707    def fit(self, function, fitrange=None, silent=False, **kwargs):
-708        r'''Fits function to the data
-709
-710        Parameters
-711        ----------
-712        function : obj
-713            function to fit to the data. See fits.least_squares for details.
-714        fitrange : list
-715            Two element list containing the timeslices on which the fit is supposed to start and stop.
-716            Caution: This range is inclusive as opposed to standard python indexing.
-717            `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6.
-718            If not specified, self.prange or all timeslices are used.
-719        silent : bool
-720            Decides whether output is printed to the standard output.
-721        '''
-722        if self.N != 1:
-723            raise Exception("Correlator must be projected before fitting")
-724
-725        if fitrange is None:
-726            if self.prange:
-727                fitrange = self.prange
-728            else:
-729                fitrange = [0, self.T - 1]
-730        else:
-731            if not isinstance(fitrange, list):
-732                raise Exception("fitrange has to be a list with two elements")
-733            if len(fitrange) != 2:
-734                raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]")
-735
-736        xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None]
-737        ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None]
-738        result = least_squares(xs, ys, function, silent=silent, **kwargs)
-739        return result
+            
704    def fit(self, function, fitrange=None, silent=False, **kwargs):
+705        r'''Fits function to the data
+706
+707        Parameters
+708        ----------
+709        function : obj
+710            function to fit to the data. See fits.least_squares for details.
+711        fitrange : list
+712            Two element list containing the timeslices on which the fit is supposed to start and stop.
+713            Caution: This range is inclusive as opposed to standard python indexing.
+714            `fitrange=[4, 6]` corresponds to the three entries 4, 5 and 6.
+715            If not specified, self.prange or all timeslices are used.
+716        silent : bool
+717            Decides whether output is printed to the standard output.
+718        '''
+719        if self.N != 1:
+720            raise Exception("Correlator must be projected before fitting")
+721
+722        if fitrange is None:
+723            if self.prange:
+724                fitrange = self.prange
+725            else:
+726                fitrange = [0, self.T - 1]
+727        else:
+728            if not isinstance(fitrange, list):
+729                raise Exception("fitrange has to be a list with two elements")
+730            if len(fitrange) != 2:
+731                raise Exception("fitrange has to have exactly two elements [fit_start, fit_stop]")
+732
+733        xs = [x for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None]
+734        ys = [self.content[x][0] for x in range(fitrange[0], fitrange[1] + 1) if not self.content[x] is None]
+735        result = least_squares(xs, ys, function, silent=silent, **kwargs)
+736        return result
 
@@ -4090,42 +4081,42 @@ Decides whether output is printed to the standard output.
-
741    def plateau(self, plateau_range=None, method="fit", auto_gamma=False):
-742        """ Extract a plateau value from a Corr object
-743
-744        Parameters
-745        ----------
-746        plateau_range : list
-747            list with two entries, indicating the first and the last timeslice
-748            of the plateau region.
-749        method : str
-750            method to extract the plateau.
-751                'fit' fits a constant to the plateau region
-752                'avg', 'average' or 'mean' just average over the given timeslices.
-753        auto_gamma : bool
-754            apply gamma_method with default parameters to the Corr. Defaults to None
-755        """
-756        if not plateau_range:
-757            if self.prange:
-758                plateau_range = self.prange
-759            else:
-760                raise Exception("no plateau range provided")
-761        if self.N != 1:
-762            raise Exception("Correlator must be projected before getting a plateau.")
-763        if (all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])):
-764            raise Exception("plateau is undefined at all timeslices in plateaurange.")
-765        if auto_gamma:
-766            self.gamma_method()
-767        if method == "fit":
-768            def const_func(a, t):
-769                return a[0]
-770            return self.fit(const_func, plateau_range)[0]
-771        elif method in ["avg", "average", "mean"]:
-772            returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None])
-773            return returnvalue
-774
-775        else:
-776            raise Exception("Unsupported plateau method: " + method)
+            
738    def plateau(self, plateau_range=None, method="fit", auto_gamma=False):
+739        """ Extract a plateau value from a Corr object
+740
+741        Parameters
+742        ----------
+743        plateau_range : list
+744            list with two entries, indicating the first and the last timeslice
+745            of the plateau region.
+746        method : str
+747            method to extract the plateau.
+748                'fit' fits a constant to the plateau region
+749                'avg', 'average' or 'mean' just average over the given timeslices.
+750        auto_gamma : bool
+751            apply gamma_method with default parameters to the Corr. Defaults to None
+752        """
+753        if not plateau_range:
+754            if self.prange:
+755                plateau_range = self.prange
+756            else:
+757                raise Exception("no plateau range provided")
+758        if self.N != 1:
+759            raise Exception("Correlator must be projected before getting a plateau.")
+760        if (all([self.content[t] is None for t in range(plateau_range[0], plateau_range[1] + 1)])):
+761            raise Exception("plateau is undefined at all timeslices in plateaurange.")
+762        if auto_gamma:
+763            self.gamma_method()
+764        if method == "fit":
+765            def const_func(a, t):
+766                return a[0]
+767            return self.fit(const_func, plateau_range)[0]
+768        elif method in ["avg", "average", "mean"]:
+769            returnvalue = np.mean([item[0] for item in self.content[plateau_range[0]:plateau_range[1] + 1] if item is not None])
+770            return returnvalue
+771
+772        else:
+773            raise Exception("Unsupported plateau method: " + method)
 
@@ -4159,17 +4150,17 @@ apply gamma_method with default parameters to the Corr. Defaults to None
-
778    def set_prange(self, prange):
-779        """Sets the attribute prange of the Corr object."""
-780        if not len(prange) == 2:
-781            raise Exception("prange must be a list or array with two values")
-782        if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))):
-783            raise Exception("Start and end point must be integers")
-784        if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]):
-785            raise Exception("Start and end point must define a range in the interval 0,T")
-786
-787        self.prange = prange
-788        return
+            
775    def set_prange(self, prange):
+776        """Sets the attribute prange of the Corr object."""
+777        if not len(prange) == 2:
+778            raise Exception("prange must be a list or array with two values")
+779        if not ((isinstance(prange[0], int)) and (isinstance(prange[1], int))):
+780            raise Exception("Start and end point must be integers")
+781        if not (0 <= prange[0] <= self.T and 0 <= prange[1] <= self.T and prange[0] < prange[1]):
+782            raise Exception("Start and end point must define a range in the interval 0,T")
+783
+784        self.prange = prange
+785        return
 
@@ -4189,124 +4180,124 @@ apply gamma_method with default parameters to the Corr. Defaults to None
-
790    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):
-791        """Plots the correlator using the tag of the correlator as label if available.
-792
-793        Parameters
-794        ----------
-795        x_range : list
-796            list of two values, determining the range of the x-axis e.g. [4, 8].
-797        comp : Corr or list of Corr
-798            Correlator or list of correlators which are plotted for comparison.
-799            The tags of these correlators are used as labels if available.
-800        logscale : bool
-801            Sets y-axis to logscale.
-802        plateau : Obs
-803            Plateau value to be visualized in the figure.
-804        fit_res : Fit_result
-805            Fit_result object to be visualized.
-806        ylabel : str
-807            Label for the y-axis.
-808        save : str
-809            path to file in which the figure should be saved.
-810        auto_gamma : bool
-811            Apply the gamma method with standard parameters to all correlators and plateau values before plotting.
-812        hide_sigma : float
-813            Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors.
-814        references : list
-815            List of floating point values that are displayed as horizontal lines for reference.
-816        title : string
-817            Optional title of the figure.
-818        """
-819        if self.N != 1:
-820            raise Exception("Correlator must be projected before plotting")
+            
787    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):
+788        """Plots the correlator using the tag of the correlator as label if available.
+789
+790        Parameters
+791        ----------
+792        x_range : list
+793            list of two values, determining the range of the x-axis e.g. [4, 8].
+794        comp : Corr or list of Corr
+795            Correlator or list of correlators which are plotted for comparison.
+796            The tags of these correlators are used as labels if available.
+797        logscale : bool
+798            Sets y-axis to logscale.
+799        plateau : Obs
+800            Plateau value to be visualized in the figure.
+801        fit_res : Fit_result
+802            Fit_result object to be visualized.
+803        ylabel : str
+804            Label for the y-axis.
+805        save : str
+806            path to file in which the figure should be saved.
+807        auto_gamma : bool
+808            Apply the gamma method with standard parameters to all correlators and plateau values before plotting.
+809        hide_sigma : float
+810            Hides data points from the first value on which is consistent with zero within 'hide_sigma' standard errors.
+811        references : list
+812            List of floating point values that are displayed as horizontal lines for reference.
+813        title : string
+814            Optional title of the figure.
+815        """
+816        if self.N != 1:
+817            raise Exception("Correlator must be projected before plotting")
+818
+819        if auto_gamma:
+820            self.gamma_method()
 821
-822        if auto_gamma:
-823            self.gamma_method()
+822        if x_range is None:
+823            x_range = [0, self.T - 1]
 824
-825        if x_range is None:
-826            x_range = [0, self.T - 1]
+825        fig = plt.figure()
+826        ax1 = fig.add_subplot(111)
 827
-828        fig = plt.figure()
-829        ax1 = fig.add_subplot(111)
-830
-831        x, y, y_err = self.plottable()
-832        if hide_sigma:
-833            hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1
-834        else:
-835            hide_from = None
-836        ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag)
-837        if logscale:
-838            ax1.set_yscale('log')
-839        else:
-840            if y_range is None:
-841                try:
-842                    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)])
-843                    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)])
-844                    ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)])
-845                except Exception:
-846                    pass
-847            else:
-848                ax1.set_ylim(y_range)
-849        if comp:
-850            if isinstance(comp, (Corr, list)):
-851                for corr in comp if isinstance(comp, list) else [comp]:
-852                    if auto_gamma:
-853                        corr.gamma_method()
-854                    x, y, y_err = corr.plottable()
-855                    if hide_sigma:
-856                        hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1
-857                    else:
-858                        hide_from = None
-859                    ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor'])
-860            else:
-861                raise Exception("'comp' must be a correlator or a list of correlators.")
-862
-863        if plateau:
-864            if isinstance(plateau, Obs):
-865                if auto_gamma:
-866                    plateau.gamma_method()
-867                ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau))
-868                ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-')
-869            else:
-870                raise Exception("'plateau' must be an Obs")
-871
-872        if references:
-873            if isinstance(references, list):
-874                for ref in references:
-875                    ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--')
-876            else:
-877                raise Exception("'references' must be a list of floating pint values.")
-878
-879        if self.prange:
-880            ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',')
-881            ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',')
-882
-883        if fit_res:
-884            x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05)
-885            ax1.plot(x_samples,
-886                     fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples),
-887                     ls='-', marker=',', lw=2)
-888
-889        ax1.set_xlabel(r'$x_0 / a$')
-890        if ylabel:
-891            ax1.set_ylabel(ylabel)
-892        ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5])
-893
-894        handles, labels = ax1.get_legend_handles_labels()
-895        if labels:
-896            ax1.legend()
+828        x, y, y_err = self.plottable()
+829        if hide_sigma:
+830            hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1
+831        else:
+832            hide_from = None
+833        ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=self.tag)
+834        if logscale:
+835            ax1.set_yscale('log')
+836        else:
+837            if y_range is None:
+838                try:
+839                    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)])
+840                    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)])
+841                    ax1.set_ylim([y_min - 0.1 * (y_max - y_min), y_max + 0.1 * (y_max - y_min)])
+842                except Exception:
+843                    pass
+844            else:
+845                ax1.set_ylim(y_range)
+846        if comp:
+847            if isinstance(comp, (Corr, list)):
+848                for corr in comp if isinstance(comp, list) else [comp]:
+849                    if auto_gamma:
+850                        corr.gamma_method()
+851                    x, y, y_err = corr.plottable()
+852                    if hide_sigma:
+853                        hide_from = np.argmax((hide_sigma * np.array(y_err[1:])) > np.abs(y[1:])) - 1
+854                    else:
+855                        hide_from = None
+856                    ax1.errorbar(x[:hide_from], y[:hide_from], y_err[:hide_from], label=corr.tag, mfc=plt.rcParams['axes.facecolor'])
+857            else:
+858                raise Exception("'comp' must be a correlator or a list of correlators.")
+859
+860        if plateau:
+861            if isinstance(plateau, Obs):
+862                if auto_gamma:
+863                    plateau.gamma_method()
+864                ax1.axhline(y=plateau.value, linewidth=2, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--', label=str(plateau))
+865                ax1.axhspan(plateau.value - plateau.dvalue, plateau.value + plateau.dvalue, alpha=0.25, color=plt.rcParams['text.color'], ls='-')
+866            else:
+867                raise Exception("'plateau' must be an Obs")
+868
+869        if references:
+870            if isinstance(references, list):
+871                for ref in references:
+872                    ax1.axhline(y=ref, linewidth=1, color=plt.rcParams['text.color'], alpha=0.6, marker=',', ls='--')
+873            else:
+874                raise Exception("'references' must be a list of floating pint values.")
+875
+876        if self.prange:
+877            ax1.axvline(self.prange[0], 0, 1, ls='-', marker=',')
+878            ax1.axvline(self.prange[1], 0, 1, ls='-', marker=',')
+879
+880        if fit_res:
+881            x_samples = np.arange(x_range[0], x_range[1] + 1, 0.05)
+882            ax1.plot(x_samples,
+883                     fit_res.fit_function([o.value for o in fit_res.fit_parameters], x_samples),
+884                     ls='-', marker=',', lw=2)
+885
+886        ax1.set_xlabel(r'$x_0 / a$')
+887        if ylabel:
+888            ax1.set_ylabel(ylabel)
+889        ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5])
+890
+891        handles, labels = ax1.get_legend_handles_labels()
+892        if labels:
+893            ax1.legend()
+894
+895        if title:
+896            plt.title(title)
 897
-898        if title:
-899            plt.title(title)
-900
-901        plt.draw()
-902
-903        if save:
-904            if isinstance(save, str):
-905                fig.savefig(save, bbox_inches='tight')
-906            else:
-907                raise Exception("'save' has to be a string.")
+898        plt.draw()
+899
+900        if save:
+901            if isinstance(save, str):
+902                fig.savefig(save, bbox_inches='tight')
+903            else:
+904                raise Exception("'save' has to be a string.")
 
@@ -4354,34 +4345,34 @@ Optional title of the figure.
-
909    def spaghetti_plot(self, logscale=True):
-910        """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations.
-911
-912        Parameters
-913        ----------
-914        logscale : bool
-915            Determines whether the scale of the y-axis is logarithmic or standard.
-916        """
-917        if self.N != 1:
-918            raise Exception("Correlator needs to be projected first.")
+            
906    def spaghetti_plot(self, logscale=True):
+907        """Produces a spaghetti plot of the correlator suited to monitor exceptional configurations.
+908
+909        Parameters
+910        ----------
+911        logscale : bool
+912            Determines whether the scale of the y-axis is logarithmic or standard.
+913        """
+914        if self.N != 1:
+915            raise Exception("Correlator needs to be projected first.")
+916
+917        mc_names = list(set([item for sublist in [sum(map(o[0].e_content.get, o[0].mc_names), []) for o in self.content if o is not None] for item in sublist]))
+918        x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None]
 919
-920        mc_names = list(set([item for sublist in [sum(map(o[0].e_content.get, o[0].mc_names), []) for o in self.content if o is not None] for item in sublist]))
-921        x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None]
+920        for name in mc_names:
+921            data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T
 922
-923        for name in mc_names:
-924            data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T
-925
-926            fig = plt.figure()
-927            ax = fig.add_subplot(111)
-928            for dat in data:
-929                ax.plot(x0_vals, dat, ls='-', marker='')
+923            fig = plt.figure()
+924            ax = fig.add_subplot(111)
+925            for dat in data:
+926                ax.plot(x0_vals, dat, ls='-', marker='')
+927
+928            if logscale is True:
+929                ax.set_yscale('log')
 930
-931            if logscale is True:
-932                ax.set_yscale('log')
-933
-934            ax.set_xlabel(r'$x_0 / a$')
-935            plt.title(name)
-936            plt.draw()
+931            ax.set_xlabel(r'$x_0 / a$')
+932            plt.title(name)
+933            plt.draw()
 
@@ -4408,29 +4399,29 @@ Determines whether the scale of the y-axis is logarithmic or standard.
-
938    def dump(self, filename, datatype="json.gz", **kwargs):
-939        """Dumps the Corr into a file of chosen type
-940        Parameters
-941        ----------
-942        filename : str
-943            Name of the file to be saved.
-944        datatype : str
-945            Format of the exported file. Supported formats include
-946            "json.gz" and "pickle"
-947        path : str
-948            specifies a custom path for the file (default '.')
-949        """
-950        if datatype == "json.gz":
-951            from .input.json import dump_to_json
-952            if 'path' in kwargs:
-953                file_name = kwargs.get('path') + '/' + filename
-954            else:
-955                file_name = filename
-956            dump_to_json(self, file_name)
-957        elif datatype == "pickle":
-958            dump_object(self, filename, **kwargs)
-959        else:
-960            raise Exception("Unknown datatype " + str(datatype))
+            
935    def dump(self, filename, datatype="json.gz", **kwargs):
+936        """Dumps the Corr into a file of chosen type
+937        Parameters
+938        ----------
+939        filename : str
+940            Name of the file to be saved.
+941        datatype : str
+942            Format of the exported file. Supported formats include
+943            "json.gz" and "pickle"
+944        path : str
+945            specifies a custom path for the file (default '.')
+946        """
+947        if datatype == "json.gz":
+948            from .input.json import dump_to_json
+949            if 'path' in kwargs:
+950                file_name = kwargs.get('path') + '/' + filename
+951            else:
+952                file_name = filename
+953            dump_to_json(self, file_name)
+954        elif datatype == "pickle":
+955            dump_object(self, filename, **kwargs)
+956        else:
+957            raise Exception("Unknown datatype " + str(datatype))
 
@@ -4462,8 +4453,8 @@ specifies a custom path for the file (default '.')
-
962    def print(self, print_range=None):
-963        print(self.__repr__(print_range))
+            
959    def print(self, print_range=None):
+960        print(self.__repr__(print_range))
 
@@ -4481,8 +4472,8 @@ specifies a custom path for the file (default '.')
-
1127    def sqrt(self):
-1128        return self ** 0.5
+            
1124    def sqrt(self):
+1125        return self ** 0.5
 
@@ -4500,9 +4491,9 @@ specifies a custom path for the file (default '.')
-
1130    def log(self):
-1131        newcontent = [None if _check_for_none(self, item) else np.log(item) for item in self.content]
-1132        return Corr(newcontent, prange=self.prange)
+            
1127    def log(self):
+1128        newcontent = [None if _check_for_none(self, item) else np.log(item) for item in self.content]
+1129        return Corr(newcontent, prange=self.prange)
 
@@ -4520,9 +4511,9 @@ specifies a custom path for the file (default '.')
-
1134    def exp(self):
-1135        newcontent = [None if _check_for_none(self, item) else np.exp(item) for item in self.content]
-1136        return Corr(newcontent, prange=self.prange)
+            
1131    def exp(self):
+1132        newcontent = [None if _check_for_none(self, item) else np.exp(item) for item in self.content]
+1133        return Corr(newcontent, prange=self.prange)
 
@@ -4540,8 +4531,8 @@ specifies a custom path for the file (default '.')
-
1149    def sin(self):
-1150        return self._apply_func_to_corr(np.sin)
+            
1146    def sin(self):
+1147        return self._apply_func_to_corr(np.sin)
 
@@ -4559,8 +4550,8 @@ specifies a custom path for the file (default '.')
-
1152    def cos(self):
-1153        return self._apply_func_to_corr(np.cos)
+            
1149    def cos(self):
+1150        return self._apply_func_to_corr(np.cos)
 
@@ -4578,8 +4569,8 @@ specifies a custom path for the file (default '.')
-
1155    def tan(self):
-1156        return self._apply_func_to_corr(np.tan)
+            
1152    def tan(self):
+1153        return self._apply_func_to_corr(np.tan)
 
@@ -4597,8 +4588,8 @@ specifies a custom path for the file (default '.')
-
1158    def sinh(self):
-1159        return self._apply_func_to_corr(np.sinh)
+            
1155    def sinh(self):
+1156        return self._apply_func_to_corr(np.sinh)
 
@@ -4616,8 +4607,8 @@ specifies a custom path for the file (default '.')
-
1161    def cosh(self):
-1162        return self._apply_func_to_corr(np.cosh)
+            
1158    def cosh(self):
+1159        return self._apply_func_to_corr(np.cosh)
 
@@ -4635,8 +4626,8 @@ specifies a custom path for the file (default '.')
-
1164    def tanh(self):
-1165        return self._apply_func_to_corr(np.tanh)
+            
1161    def tanh(self):
+1162        return self._apply_func_to_corr(np.tanh)
 
@@ -4654,8 +4645,8 @@ specifies a custom path for the file (default '.')
-
1167    def arcsin(self):
-1168        return self._apply_func_to_corr(np.arcsin)
+            
1164    def arcsin(self):
+1165        return self._apply_func_to_corr(np.arcsin)
 
@@ -4673,8 +4664,8 @@ specifies a custom path for the file (default '.')
-
1170    def arccos(self):
-1171        return self._apply_func_to_corr(np.arccos)
+            
1167    def arccos(self):
+1168        return self._apply_func_to_corr(np.arccos)
 
@@ -4692,8 +4683,8 @@ specifies a custom path for the file (default '.')
-
1173    def arctan(self):
-1174        return self._apply_func_to_corr(np.arctan)
+            
1170    def arctan(self):
+1171        return self._apply_func_to_corr(np.arctan)
 
@@ -4711,8 +4702,8 @@ specifies a custom path for the file (default '.')
-
1176    def arcsinh(self):
-1177        return self._apply_func_to_corr(np.arcsinh)
+            
1173    def arcsinh(self):
+1174        return self._apply_func_to_corr(np.arcsinh)
 
@@ -4730,8 +4721,8 @@ specifies a custom path for the file (default '.')
-
1179    def arccosh(self):
-1180        return self._apply_func_to_corr(np.arccosh)
+            
1176    def arccosh(self):
+1177        return self._apply_func_to_corr(np.arccosh)
 
@@ -4749,8 +4740,8 @@ specifies a custom path for the file (default '.')
-
1182    def arctanh(self):
-1183        return self._apply_func_to_corr(np.arctanh)
+            
1179    def arctanh(self):
+1180        return self._apply_func_to_corr(np.arctanh)
 
@@ -4768,62 +4759,62 @@ specifies a custom path for the file (default '.')
-
1218    def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None):
-1219        r''' Project large correlation matrix to lowest states
-1220
-1221        This method can be used to reduce the size of an (N x N) correlation matrix
-1222        to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise
-1223        is still small.
-1224
-1225        Parameters
-1226        ----------
-1227        Ntrunc: int
-1228            Rank of the target matrix.
-1229        tproj: int
-1230            Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method.
-1231            The default value is 3.
-1232        t0proj: int
-1233            Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly
-1234            discouraged for O(a) improved theories, since the correctness of the procedure
-1235            cannot be granted in this case. The default value is 2.
-1236        basematrix : Corr
-1237            Correlation matrix that is used to determine the eigenvectors of the
-1238            lowest states based on a GEVP. basematrix is taken to be the Corr itself if
-1239            is is not specified.
-1240
-1241        Notes
-1242        -----
-1243        We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving
-1244        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}$
-1245        and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the
-1246        resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via
-1247        $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large
-1248        correlation matrix and to remove some noise that is added by irrelevant operators.
-1249        This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated
-1250        bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$.
-1251        '''
-1252
-1253        if self.N == 1:
-1254            raise Exception('Method cannot be applied to one-dimensional correlators.')
-1255        if basematrix is None:
-1256            basematrix = self
-1257        if Ntrunc >= basematrix.N:
-1258            raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N))
-1259        if basematrix.N != self.N:
-1260            raise Exception('basematrix and targetmatrix have to be of the same size.')
-1261
-1262        evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc]
-1263
-1264        tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object)
-1265        rmat = []
-1266        for t in range(basematrix.T):
-1267            for i in range(Ntrunc):
-1268                for j in range(Ntrunc):
-1269                    tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j]
-1270            rmat.append(np.copy(tmpmat))
-1271
-1272        newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)]
-1273        return Corr(newcontent)
+            
1215    def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None):
+1216        r''' Project large correlation matrix to lowest states
+1217
+1218        This method can be used to reduce the size of an (N x N) correlation matrix
+1219        to (Ntrunc x Ntrunc) by solving a GEVP at very early times where the noise
+1220        is still small.
+1221
+1222        Parameters
+1223        ----------
+1224        Ntrunc: int
+1225            Rank of the target matrix.
+1226        tproj: int
+1227            Time where the eigenvectors are evaluated, corresponds to ts in the GEVP method.
+1228            The default value is 3.
+1229        t0proj: int
+1230            Time where the correlation matrix is inverted. Choosing t0proj=1 is strongly
+1231            discouraged for O(a) improved theories, since the correctness of the procedure
+1232            cannot be granted in this case. The default value is 2.
+1233        basematrix : Corr
+1234            Correlation matrix that is used to determine the eigenvectors of the
+1235            lowest states based on a GEVP. basematrix is taken to be the Corr itself if
+1236            is is not specified.
+1237
+1238        Notes
+1239        -----
+1240        We have the basematrix $C(t)$ and the target matrix $G(t)$. We start by solving
+1241        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}$
+1242        and $t_0 \equiv t_{0, \mathrm{proj}}$. The target matrix is projected onto the subspace of the
+1243        resulting eigenvectors $v_n, n=1,\dots,N_\mathrm{trunc}$ via
+1244        $$G^\prime_{i, j}(t) = (v_i, G(t) v_j)$$. This allows to reduce the size of a large
+1245        correlation matrix and to remove some noise that is added by irrelevant operators.
+1246        This may allow to use the GEVP on $G(t)$ at late times such that the theoretically motivated
+1247        bound $t_0 \leq t/2$ holds, since the condition number of $G(t)$ is decreased, compared to $C(t)$.
+1248        '''
+1249
+1250        if self.N == 1:
+1251            raise Exception('Method cannot be applied to one-dimensional correlators.')
+1252        if basematrix is None:
+1253            basematrix = self
+1254        if Ntrunc >= basematrix.N:
+1255            raise Exception('Cannot truncate using Ntrunc <= %d' % (basematrix.N))
+1256        if basematrix.N != self.N:
+1257            raise Exception('basematrix and targetmatrix have to be of the same size.')
+1258
+1259        evecs = basematrix.GEVP(t0proj, tproj, sort=None)[:Ntrunc]
+1260
+1261        tmpmat = np.empty((Ntrunc, Ntrunc), dtype=object)
+1262        rmat = []
+1263        for t in range(basematrix.T):
+1264            for i in range(Ntrunc):
+1265                for j in range(Ntrunc):
+1266                    tmpmat[i][j] = evecs[i].T @ self[t] @ evecs[j]
+1267            rmat.append(np.copy(tmpmat))
+1268
+1269        newcontent = [None if (self.content[t] is None) else rmat[t] for t in range(self.T)]
+1270        return Corr(newcontent)