Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Address linting and test errors #5

Merged
merged 7 commits into from
Oct 3, 2024
Merged
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
12 changes: 6 additions & 6 deletions .github/workflows/test-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ on:
jobs:
linter-check:
runs-on: ubuntu-latest
steps:
- name: Checkout
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up Python "3.10"
uses: actions/setup-python@v4
Expand All @@ -26,8 +26,8 @@ jobs:
run: black . --diff --color
- name: ruff Check
shell: bash
run: ruff src
run: ruff check src

test-suite:
runs-on: ${{ matrix.os }}
needs: linter-check
Expand All @@ -36,7 +36,7 @@ jobs:
matrix:
os: [ubuntu-latest]
python-version: ["3.10", "3.8"]

steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -51,5 +51,5 @@ jobs:
python -m pip install .[test,optional]
- name: Run Tests
shell: bash
run: |
run: |
pytest -n auto -x
4 changes: 2 additions & 2 deletions docs/denoisers.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
LLR Denosing methods
LLR Denoising Methods
=====================

Patch-denoise implemement several local-low-rank methods, based on singular values thresholding.


Singular Value thresholding
Singular Value Thresholding
---------------------------

General Procedure
Expand Down
6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,19 @@ omit = ["*tests*"]
precision = 2
exclude_lines = ["pragma: no cover", "raise NotImplementedError"]


# Formatting using black.
[tool.black]

#linting using ruff
[tool.ruff]
src = ["src", "tests"]
select = ["E", "F", "B", "Q", "UP", "D"]

[tool.ruff.lint]
ignore = ["B905"]
exclude = ["examples/", "tests/"]
select = ["E", "F", "B", "Q", "UP", "D"]

[tool.ruff.pydocstyle]
[tool.ruff.lint.pydocstyle]
convention="numpy"

[tool.isort]
Expand Down
3 changes: 2 additions & 1 deletion src/patch_denoise/bindings/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,8 @@ def main():
]:
extra_kwargs["noise_std"] = noise_map
if noise_map is None:
raise RuntimeError("A noise map must me specified for this method.")
raise RuntimeError("A noise map must be specified for this method.")

denoised_data, patchs_weight, noise_std_map, rank_map = denoise_func(
input_data,
patch_shape=d_par.patch_shape,
Expand Down
2 changes: 1 addition & 1 deletion src/patch_denoise/bindings/modopt.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def __init__(
**kwargs,
)
self.op = self._op_method
self.cost = lambda *args, **kw: np.NaN
self.cost = lambda *args, **kw: np.nan
self.time_dimension = time_dimension

def _op_method(self, data, **kwargs):
Expand Down
5 changes: 4 additions & 1 deletion src/patch_denoise/bindings/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
"""Common utilities for bindings."""
from dataclasses import dataclass

from __future__ import annotations

import logging
from dataclasses import dataclass

import numpy as np

Expand Down
6 changes: 4 additions & 2 deletions src/patch_denoise/space_time/base.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Base Structure for patch-based denoising on spatio-temporal dimension."""

import abc
from functools import partial, cached_property
import logging

import numpy as np
from tqdm.auto import tqdm

Expand Down Expand Up @@ -43,7 +44,8 @@ def __init__(

if self._ps.size != dimensions or step.size != dimensions:
raise ValueError(
"self._ps and step must have the same number of dimensions as the input self._array."
"self._ps and step must have the same number of dimensions as the "
"input self._array."
)

# Ensure patch size is not larger than self._array size along each axis
Expand Down
27 changes: 14 additions & 13 deletions src/patch_denoise/space_time/lowrank.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Low Rank methods."""
"""Low Rank methods."""

from types import MappingProxyType

import numpy as np
Expand All @@ -9,7 +10,7 @@
from .utils import (
eig_analysis,
eig_synthesis,
marshenko_pastur_median,
marchenko_pastur_median,
svd_analysis,
svd_synthesis,
)
Expand All @@ -25,7 +26,7 @@

@fill_doc
class MPPCADenoiser(BaseSpaceTimeDenoiser):
"""Denoising using the MP-PCA threshoding.
"""Denoising using Marchenko-Pastur principal components analysis thresholding.

Parameters
----------
Expand Down Expand Up @@ -127,7 +128,7 @@ class RawSVDDenoiser(BaseSpaceTimeDenoiser):
----------
$patch_config
threshold_vlue: float
treshold value for the singular values.
threshold value for the singular values.
"""

def __init__(
Expand Down Expand Up @@ -180,7 +181,7 @@ def _patch_processing(self, patch, patch_idx=None, **kwargs):

# Equation (3) in Manjon 2013

return p_new, maxidx, np.NaN
return p_new, maxidx, np.nan


@fill_doc
Expand All @@ -204,7 +205,7 @@ def denoise(
):
"""Denoise using the NORDIC method.

Along with the input data a noise stp map or value should be provided.
Along with the input data a noise std map or value should be provided.

Parameters
----------
Expand Down Expand Up @@ -291,7 +292,7 @@ class OptimalSVDDenoiser(BaseSpaceTimeDenoiser):
----------
$patch_config
loss: str
The loss determines the choise of the optimal thresholding function
The loss determines the choice of the optimal thresholding function
associated to it. The losses `"fro"`, `"nuc"` and `"op"` are supported,
for the frobenius, nuclear and operator norm, respectively.
"""
Expand Down Expand Up @@ -335,7 +336,7 @@ def denoise(
$mask_config
$noise_std
loss: str
The loss for which the optimal thresholding is perform.
The loss for which the optimal thresholding is performed.
eps_marshenko_pastur: float
The precision with which the optimal threshold is computed.

Expand All @@ -345,7 +346,7 @@ def denoise(

Notes
-----
Reimplement of the original Matlab code [#]_ in python.
Reimplementation of the original Matlab code [#]_ in python.

References
----------
Expand All @@ -356,7 +357,7 @@ def denoise(
"""
p_s, p_o = self._get_patch_param(input_data.shape)

self.input_denoising_kwargs["mp_median"] = marshenko_pastur_median(
self.input_denoising_kwargs["mp_median"] = marchenko_pastur_median(
beta=input_data.shape[-1] / np.prod(p_s),
eps=eps_marshenko_pastur,
)
Expand Down Expand Up @@ -402,7 +403,7 @@ def _patch_processing(
maxidx = 0
p_new = np.zeros_like(patch) + p_tmean

return p_new, maxidx, np.NaN
return p_new, maxidx, np.nan


def _sure_atn_cost(X, method, sing_vals, gamma, sigma=None, tau=None):
Expand Down Expand Up @@ -500,7 +501,7 @@ def sure_tau(tau, *args):

if tau0 is None:
tau0 = np.log(np.median(sing_vals))
cost_glob = np.Inf
cost_glob = np.inf
for g in gamma0:
res_opti = minimize(
lambda x: _sure_atn_cost(
Expand Down Expand Up @@ -630,4 +631,4 @@ def _patch_processing(
maxidx = 0
p_new = np.zeros_like(patch) + p_tmean

return p_new, maxidx, np.NaN
return p_new, maxidx, np.nan
24 changes: 22 additions & 2 deletions src/patch_denoise/space_time/utils.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Utilities for space-time denoising."""

import numpy as np
from scipy.integrate import quad
from scipy.linalg import eigh, svd
Expand Down Expand Up @@ -145,7 +146,7 @@ def eig_synthesis(data_centered, eig_vec, mean, max_val):
return ((data_centered @ eig_vec) @ eig_vec.conj().T) + mean


def marshenko_pastur_median(beta, eps=1e-7):
def marchenko_pastur_median(beta, eps=1e-7):
r"""Compute the median of the Marchenko-Pastur Distribution.

Parameters
Expand Down Expand Up @@ -204,19 +205,38 @@ def mp_pdf(x):


def estimate_noise(noise_sequence, block_size=1):
"""Estimate the temporal noise standard deviation of a noise only sequence."""
"""Estimate a noise map from a noise only sequence.

The noise map is the standard deviation of the noise in each patch.

Parameters
----------
noise_sequence : np.ndarray of shape (X, Y, Z, T)
The noise-only data.
block_size : int
The size of the patch used to estimate the noise.

Returns
-------
np.ndarray of shape (X, Y, Z)
The estimated noise map.
"""
volume_shape = noise_sequence.shape[:-1]
noise_map = np.empty(volume_shape)
patch_shape = (block_size,) * len(volume_shape)
patch_overlap = (block_size - 1,) * len(volume_shape)

for patch_tl in get_patch_locs(patch_shape, patch_overlap, volume_shape):
# Get the index of voxels in the patch
patch_slice = tuple(
slice(ptl, ptl + ps) for ptl, ps in zip(patch_tl, patch_shape)
)
# Identify the voxel in the center of the patch
patch_center_img = tuple(
slice(ptl + ps // 2, ptl + ps // 2 + 1)
for ptl, ps in zip(patch_tl, patch_shape)
)
# Set the value of the voxel in the center of the patch to the SD of
# the patch
noise_map[patch_center_img] = np.std(noise_sequence[patch_slice])
return noise_map
3 changes: 2 additions & 1 deletion tests/test_bindings.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Test for the binding module."""

import os

import numpy as np
import numpy.testing as npt
import pytest
Expand All @@ -16,7 +18,6 @@
except ImportError as e:
NIPYPE_AVAILABLE = False


from patch_denoise.bindings.modopt import LLRDenoiserOperator
from patch_denoise.bindings.nipype import PatchDenoise
from patch_denoise.bindings.utils import DenoiseParameters
Expand Down
4 changes: 2 additions & 2 deletions tests/test_spacetime_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
eig_analysis,
eig_synthesis,
estimate_noise,
marshenko_pastur_median,
marchenko_pastur_median,
svd_analysis,
svd_synthesis,
)
Expand Down Expand Up @@ -55,7 +55,7 @@ def f(x):
else:
return 0

integral_median = marshenko_pastur_median(beta, eps=1e-7)
integral_median = marchenko_pastur_median(beta, eps=1e-7)

vals = np.linspace(beta_m, beta_p, n_samples)
proba = np.array(list(map(f, vals)))
Expand Down
Loading