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