Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: "3.12"
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Updated documentation
run: |
git config --global user.email "${{ github.actor }}@users.noreply.github.com"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:

steps:
- name: Checkout source
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup python
uses: actions/setup-python@v5
Expand Down
26 changes: 0 additions & 26 deletions .github/workflows/flake8.yml

This file was deleted.

2 changes: 1 addition & 1 deletion .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:

steps:
- name: Checkout source
uses: actions/checkout@v4
uses: actions/checkout@v6

- name: Setup python
uses: actions/setup-python@v5
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
name: Build sdist and wheel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
name: Checkout repository

- uses: actions/setup-python@v5
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ruff.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/ruff-action@v2
- uses: actions/checkout@v6
- uses: astral-sh/ruff-action@v3
with:
src: "./pyerrors"
6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ Please add docstrings to any new function, class or method you implement. The do

### Tests
When implementing a new feature or fixing a bug please add meaningful tests to the files in the `tests` directory which cover the new code.
We follow the [PEP8](https://peps.python.org/pep-0008/) code style which is checked by `flake8`.
We follow the [PEP8](https://peps.python.org/pep-0008/) code style which is checked by `ruff`.
For all pull requests tests are executed for the most recent python releases via
```
pytest -vv -Werror
pytest --nbmake examples/*.ipynb
flake8 --ignore=E501,W503 --exclude=__init__.py pyerrors
ruff check pyerrors
```
The tests require `pytest`, `pytest-cov`, `pytest-benchmark`, `hypothesis`, `nbmake` and `flake8`. To install the test dependencies one can run `pip install pyerrors[test]`.
The tests require `pytest`, `pytest-cov`, `pytest-benchmark`, `hypothesis` and `nbmake`. To install the test dependencies one can run `pip install pyerrors[test]`. Linting is done with `ruff`, which can be installed via `pip install ruff` or run ad-hoc with `uvx ruff check pyerrors`.
Please make sure that all tests pass for a new pull requests.

To get a coverage report in html run
Expand Down
11 changes: 5 additions & 6 deletions pyerrors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,16 +477,15 @@ def func(a, x):

Julia I/O routines for the json.gz format, compatible with [ADerrors.jl](https://gitlab.ift.uam-csic.es/alberto/aderrors.jl), can be found [here](https://github.com/fjosw/ADjson.jl).
'''
from .obs import *
from .correlators import *
from .fits import *
from .misc import *
from . import dirac as dirac
from . import input as input
from . import integrate as integrate
from . import linalg as linalg
from . import mpm as mpm
from . import roots as roots
from . import integrate as integrate
from . import special as special

from .correlators import *
from .fits import *
from .misc import *
from .obs import *
from .version import __version__ as __version__
50 changes: 29 additions & 21 deletions pyerrors/correlators.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import itertools
import warnings
from itertools import permutations
import numpy as np

import autograd.numpy as anp
import matplotlib.pyplot as plt
import numpy as np
import scipy.linalg
from .obs import Obs, reweight, correlate, CObs
from .misc import dump_object, _assert_equal_properties

from . import linalg
from .fits import least_squares
from .misc import _assert_equal_properties, dump_object
from .obs import CObs, Obs, correlate, reweight
from .roots import find_root
from . import linalg


class Corr:
Expand Down Expand Up @@ -40,9 +43,9 @@ class Corr:
the temporal extent of the correlator and N is the dimension of the matrix.
"""

__slots__ = ["content", "N", "T", "tag", "prange"]
__slots__ = ["N", "T", "content", "prange", "tag"]

def __init__(self, data_input, padding=[0, 0], prange=None):
def __init__(self, data_input, padding=None, prange=None):
""" Initialize a Corr object.

Parameters
Expand All @@ -58,6 +61,9 @@ def __init__(self, data_input, padding=[0, 0], prange=None):
region identified for this correlator.
"""

if padding is None:
padding = [0, 0]

if isinstance(data_input, np.ndarray):
if data_input.ndim == 1:
data_input = list(data_input)
Expand All @@ -77,7 +83,7 @@ def __init__(self, data_input, padding=[0, 0], prange=None):
for t in range(T):
if any([(item.content[t] is None) for item in data_input.flatten()]):
if not all([(item.content[t] is None) for item in data_input.flatten()]):
warnings.warn("Input ill-defined at different timeslices. Conversion leads to data loss.!", RuntimeWarning)
warnings.warn("Input ill-defined at different timeslices. Conversion leads to data loss.!", RuntimeWarning, stacklevel=2)
input_as_list.append(None)
else:
array_at_timeslace = np.empty([N, N], dtype="object")
Expand Down Expand Up @@ -178,14 +184,14 @@ def projected(self, vector_l=None, vector_r=None, normalize=False):
if not vector_l.shape == vector_r.shape == (self.N,):
raise ValueError("Vectors are of wrong shape!")
if normalize:
vector_l, vector_r = vector_l / np.sqrt((vector_l @ vector_l)), vector_r / np.sqrt(vector_r @ vector_r)
vector_l, vector_r = vector_l / np.sqrt(vector_l @ vector_l), vector_r / np.sqrt(vector_r @ vector_r)
newcontent = [None if _check_for_none(self, item) else np.asarray([vector_l.T @ item @ vector_r]) for item in self.content]

else:
# There are no checks here yet. There are so many possible scenarios, where this can go wrong.
if normalize:
for t in range(self.T):
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])
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])

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)]
return Corr(newcontent)
Expand Down Expand Up @@ -228,7 +234,7 @@ def symmetric(self):

if self.content[0] is not None:
if np.argmax(np.abs([o[0].value if o is not None else 0 for o in self.content])) != 0:
warnings.warn("Correlator does not seem to be symmetric around x0=0.", RuntimeWarning)
warnings.warn("Correlator does not seem to be symmetric around x0=0.", RuntimeWarning, stacklevel=2)

newcontent = [self.content[0]]
for t in range(1, self.T):
Expand All @@ -250,7 +256,7 @@ def anti_symmetric(self):
test = 1 * self
test.gamma_method()
if not all([o.is_zero_within_error(3) for o in test.content[0]]):
warnings.warn("Correlator does not seem to be anti-symmetric around x0=0.", RuntimeWarning)
warnings.warn("Correlator does not seem to be anti-symmetric around x0=0.", RuntimeWarning, stacklevel=2)

newcontent = [self.content[0]]
for t in range(1, self.T):
Expand Down Expand Up @@ -342,7 +348,7 @@ def GEVP(self, t0, ts=None, sort="Eigenvalue", vector_obs=False, **kwargs):
raise ValueError("ts has to be larger than t0.")

if "sorted_list" in kwargs:
warnings.warn("Argument 'sorted_list' is deprecated, use 'sort' instead.", DeprecationWarning)
warnings.warn("Argument 'sorted_list' is deprecated, use 'sort' instead.", DeprecationWarning, stacklevel=2)
sort = kwargs.get("sorted_list")

if self.is_matrix_symmetric():
Expand Down Expand Up @@ -381,7 +387,7 @@ def _get_mat_at_t(t, vector_obs=vector_obs):

elif sort in ["Eigenvalue", "Eigenvector"]:
if sort == "Eigenvalue" and ts is not None:
warnings.warn("ts has no effect when sorting by eigenvalue is chosen.", RuntimeWarning)
warnings.warn("ts has no effect when sorting by eigenvalue is chosen.", RuntimeWarning, stacklevel=2)
all_vecs = [None] * (t0 + 1)
for t in range(t0 + 1, self.T):
try:
Expand Down Expand Up @@ -439,7 +445,7 @@ def Hankel(self, N, periodic=False):

array = np.empty([N, N], dtype="object")
new_content = []
for t in range(self.T):
for _t in range(self.T):
new_content.append(array.copy())

def wrap(i):
Expand Down Expand Up @@ -569,7 +575,7 @@ def T_symmetry(self, partner, parity=+1):
if not t_slice[0].is_zero_within_error(5):
t_slices.append(x0)
if t_slices:
warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning)
warnings.warn("T symmetry partners do not agree within 5 sigma on time slices " + str(t_slices) + ".", RuntimeWarning, stacklevel=2)

return (self + T_partner) / 2

Expand Down Expand Up @@ -663,7 +669,7 @@ def second_deriv(self, variant="symmetric"):
if (self.content[t - 1] is None) or (self.content[t + 1] is None):
newcontent.append(None)
else:
newcontent.append((self.content[t + 1] - 2 * self.content[t] + self.content[t - 1]))
newcontent.append(self.content[t + 1] - 2 * self.content[t] + self.content[t - 1])
if (all([x is None for x in newcontent])):
raise ValueError("Derivative is undefined at all timeslices")
return Corr(newcontent, padding=[1, 1])
Expand Down Expand Up @@ -978,7 +984,7 @@ def show(self, x_range=None, comp=None, y_range=None, logscale=False, plateau=No
ax1.set_ylabel(ylabel)
ax1.set_xlim([x_range[0] - 0.5, x_range[1] + 0.5])

handles, labels = ax1.get_legend_handles_labels()
_handles, labels = ax1.get_legend_handles_labels()
if labels:
ax1.legend()

Expand All @@ -1004,8 +1010,8 @@ def spaghetti_plot(self, logscale=True):
if self.N != 1:
raise ValueError("Correlator needs to be projected first.")

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]))
x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content) if o is not None]
mc_names = list(set([item for sublist in [list(itertools.chain.from_iterable(map(o[0].e_content.get, o[0].mc_names))) for o in self.content if o is not None] for item in sublist]))
x0_vals = [n for (n, o) in zip(np.arange(self.T), self.content, strict=True) if o is not None]

for name in mc_names:
data = np.array([o[0].deltas[name] + o[0].r_values[name] for o in self.content if o is not None]).T
Expand Down Expand Up @@ -1091,6 +1097,8 @@ def __eq__(self, y):
comp = np.asarray(y)
return np.asarray(self.content, dtype=object) == comp

__hash__ = None

def __add__(self, y):
if isinstance(y, Corr):
if ((self.N != y.N) or (self.T != y.T)):
Expand Down Expand Up @@ -1396,7 +1404,7 @@ def prune(self, Ntrunc, tproj=3, t0proj=2, basematrix=None):
if basematrix is None:
basematrix = self
if Ntrunc >= basematrix.N:
raise ValueError('Cannot truncate using Ntrunc <= %d' % (basematrix.N))
raise ValueError(f'Cannot truncate using Ntrunc <= {basematrix.N}')
if basematrix.N != self.N:
raise ValueError('basematrix and targetmatrix have to be of the same size.')

Expand All @@ -1420,7 +1428,7 @@ def _sort_vectors(vec_set_in, ts):
"""Helper function used to find a set of Eigenvectors consistent over all timeslices"""

if isinstance(vec_set_in[ts][0][0], Obs):
vec_set = [anp.vectorize(lambda x: float(x))(vi) if vi is not None else vi for vi in vec_set_in]
vec_set = [anp.vectorize(float)(vi) if vi is not None else vi for vi in vec_set_in]
else:
vec_set = vec_set_in
reference_sorting = np.array(vec_set[ts])
Expand Down
4 changes: 2 additions & 2 deletions pyerrors/covobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __init__(self, mean, cov, name, pos=None, grad=None):
raise Exception('Have to specify position of cov-element belonging to mean!')
else:
if pos > self.N:
raise Exception('pos %d too large for covariance matrix with dimension %dx%d!' % (pos, self.N, self.N))
raise Exception(f'pos {pos} too large for covariance matrix with dimension {self.N}x{self.N}!')
self._grad = np.zeros((self.N, 1))
self._grad[pos] = 1.
else:
Expand Down Expand Up @@ -72,7 +72,7 @@ def _set_cov(self, cov):
for i in range(self.N):
for j in range(i):
if not self._cov[i][j] == self._cov[j][i]:
raise Exception('Covariance matrix is non-symmetric for (%d, %d' % (i, j))
raise Exception(f'Covariance matrix is non-symmetric for ({i}, {j}')

evals = np.linalg.eigvalsh(self._cov)
for ev in evals:
Expand Down
1 change: 0 additions & 1 deletion pyerrors/dirac.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import numpy as np


gammaX = np.array(
[[0, 0, 0, 1j], [0, 0, 1j, 0], [0, -1j, 0, 0], [-1j, 0, 0, 0]],
dtype=complex)
Expand Down
Loading
Loading