corrct.data_terms

Data fidelity classes.

@author: Nicola VIGANÒ, Computational Imaging group, CWI, The Netherlands, and ESRF - The European Synchrotron, Grenoble, France

Module Contents

Classes

DataFidelityBase

Define the DataFidelity classes interface.

DataFidelity_l2

l2-norm data-fidelity class.

DataFidelity_l2w

Weighted l2-norm data-fidelity class.

DataFidelity_l2b

l2-norm ball data-fidelity class.

DataFidelity_Huber

Huber-norm data-fidelity class. Given a parameter a: l2-norm for x < a, and l1-norm for x > a.

DataFidelity_l1

l1-norm data-fidelity class.

DataFidelity_l21

l12-norm data-fidelity class.

DataFidelity_l21w

l12-norm data-fidelity class.

DataFidelity_l1b

l1-norm ball data-fidelity class.

DataFidelity_KL

Kullback-Leibler data-fidelity class.

DataFidelity_ln

nuclear-norm data-fidelity class.

Functions

_soft_threshold

Data

eps

NDArrayFloat

API

corrct.data_terms.eps

None

corrct.data_terms.NDArrayFloat

None

corrct.data_terms._soft_threshold(values: corrct.data_terms.NDArrayFloat, threshold: float | corrct.data_terms.NDArrayFloat) None[source]
class corrct.data_terms.DataFidelityBase(background: float | corrct.data_terms.NDArrayFloat | None = None)[source]

Bases: abc.ABC

Define the DataFidelity classes interface.

Initialization

Initialize the base data-fidelity class.

Parameters

background : float | NDArrayFloat | None, optional The data background. The default is None.

data: corrct.data_terms.NDArrayFloat | None

None

sigma: float | corrct.data_terms.NDArrayFloat

None

background: corrct.data_terms.NDArrayFloat | None

None

sigma_data: corrct.data_terms.NDArrayFloat | None

None

__data_fidelity_name__ = <Multiline-String>
_slice_attr(attr: str, ind: Any) None[source]
__getitem__(ind: Any) corrct.data_terms.DataFidelityBase[source]

Slice the norm and all its attributes.

Parameters

ind : Any Slicing indices.

Returns

DataFidelityBase The sliced norm.

info() str[source]

Return the data-fidelity info.

Returns

str Data fidelity info string.

upper() str[source]

Return the upper case name of the data-fidelity.

Returns

str Upper case string name of the data-fidelity.

lower() str[source]

Return the lower case name of the data-fidelity.

Returns

str Lower case string name of the data-fidelity.

assign_data(data: float | corrct.data_terms.NDArrayFloat | None = None, sigma: float | corrct.data_terms.NDArrayFloat = 1.0) None[source]

Initialize the data bias, and sigma of the data term.

Parameters

data : float | NDArrayFloat | None, optional The data bias, by default None sigma : float | NDArrayFloat, optional The sigma, by default 1.0

compute_residual(proj_primal: corrct.data_terms.NDArrayFloat, mask: corrct.data_terms.NDArrayFloat | None = None) corrct.data_terms.NDArrayFloat[source]

Compute the residual in the dual domain.

Parameters

proj_primal : NDArrayFloat Projection of the primal solution mask : NDArrayFloat | None, optional Mask of the dual domain, by default None

Returns

NDArrayFloat The residual

abstract compute_residual_norm(dual: corrct.data_terms.NDArrayFloat) float[source]

Compute the norm of the residual.

Parameters

dual : NDArrayFloat The residual in the dual domain.

Returns

float The residual norm.

_compute_sigma_data()[source]
compute_data_dual_dot(dual: corrct.data_terms.NDArrayFloat, mask: corrct.data_terms.NDArrayFloat | None = None) float[source]

Compute the dot product of the data bias and the dual solution.

Parameters

dual : NDArrayFloat The dual solution. mask : NDArrayFloat | None, optional Mask of the dual domain, by default None

Returns

float The dot product between the data bias and the dual solution

initialize_dual() corrct.data_terms.NDArrayFloat[source]

Initialize the dual domain solution.

Returns

NDArrayFloat A zero array with the dimensions of the dual domain.

update_dual(dual: corrct.data_terms.NDArrayFloat, proj_primal: corrct.data_terms.NDArrayFloat) None[source]

Update the dual solution.

Parameters

dual : NDArrayFloat The current dual solution proj_primal : NDArrayFloat The projected primal solution

abstract apply_proximal_dual(dual: corrct.data_terms.NDArrayFloat) None[source]

Apply the proximal in the dual domain.

Parameters

dual : NDArrayFloat The dual solution

abstract apply_proximal_primal(primal: corrct.data_terms.NDArrayFloat, tau: float | corrct.data_terms.NDArrayFloat) None[source]

Apply the proximal operator in the primal domain, in-place.

Computes prox_{tau * f}(primal), i.e. the proximal of the data-fidelity f with step size tau, and stores the result back into primal.

Note: in FISTA the data term is handled via a gradient step, so this method is exposed for standalone use or for algorithms that prefer a pure proximal approach (e.g. when A = I).

Parameters

primal : NDArrayFloat The current primal variable (modified in-place). tau : float | NDArrayFloat The proximal step size.

abstract compute_primal_dual_gap(proj_primal: corrct.data_terms.NDArrayFloat, dual: corrct.data_terms.NDArrayFloat, mask: corrct.data_terms.NDArrayFloat | None = None) float[source]

Compute the primal-dual gap of the current solution.

Parameters

proj_primal : NDArrayFloat The projected primal solution (in the dual domain) dual : NDArrayFloat The dual solution mask : NDArrayFloat | None, optional Mask in the dual domain, by default None

Returns

float The primal-dual gap

class corrct.data_terms.DataFidelity_l2(background: float | corrct.data_terms.NDArrayFloat | None = None)[source]

Bases: corrct.data_terms.DataFidelityBase

l2-norm data-fidelity class.

Initialization

Initialize the base data-fidelity class.

Parameters

background : float | NDArrayFloat | None, optional The data background. The default is None.

__data_fidelity_name__

‘l2’

sigma1: float | corrct.data_terms.NDArrayFloat

None

assign_data(data: float | corrct.data_terms.NDArrayFloat | None = None, sigma: float | corrct.data_terms.NDArrayFloat = 1.0) None[source]
compute_residual_norm(dual: corrct.data_terms.NDArrayFloat) float[source]
apply_proximal_dual(dual: corrct.data_terms.NDArrayFloat) None[source]
apply_proximal_primal(primal: corrct.data_terms.NDArrayFloat, tau: float | corrct.data_terms.NDArrayFloat) None[source]

Apply prox_{tau * (1/2) * ||. - b||^2} in-place.

The closed-form solution is: prox(x) = (x + tau * b) / (1 + tau)

When no data has been assigned (b = 0): prox(x) = x / (1 + tau)

Parameters

primal : NDArrayFloat The primal variable to update in-place. tau : float | NDArrayFloat The proximal step size.

compute_primal_dual_gap(proj_primal: corrct.data_terms.NDArrayFloat, dual: corrct.data_terms.NDArrayFloat, mask: corrct.data_terms.NDArrayFloat | None = None) float[source]
class corrct.data_terms.DataFidelity_l2w(weights: float | corrct.data_terms.NDArrayFloat, background: float | corrct.data_terms.NDArrayFloat | None = None)[source]

Bases: corrct.data_terms.DataFidelity_l2

Weighted l2-norm data-fidelity class.

Initialization

Initialize the base data-fidelity class.

Parameters

background : float | NDArrayFloat | None, optional The data background. The default is None.

__data_fidelity_name__

‘l2w’

sigma1: float | corrct.data_terms.NDArrayFloat

None

weights: corrct.data_terms.NDArrayFloat

None

assign_data(data: float | corrct.data_terms.NDArrayFloat | None, sigma: float | corrct.data_terms.NDArrayFloat = 1.0)[source]
compute_residual(proj_primal, mask: float | corrct.data_terms.NDArrayFloat | None = None)[source]
compute_residual_norm(dual: float | corrct.data_terms.NDArrayFloat) float[source]
apply_proximal_primal(primal: corrct.data_terms.NDArrayFloat, tau: float | corrct.data_terms.NDArrayFloat) None[source]

Apply prox_{tau * (1/2) * ||. - b||^2_W} in-place.

For the weighted l2 norm (1/2)||x - b||^2_W = (1/2) sum_i w_i (x_i - b_i)^2, the proximal is computed element-wise: prox(x)_i = (x_i + tau * w_i * b_i) / (1 + tau * w_i)

Zero-weight entries are left unchanged (no constraint enforced there).

Parameters

primal : NDArrayFloat The primal variable to update in-place. tau : float | NDArrayFloat The proximal step size.

class corrct.data_terms.DataFidelity_l2b(local_error: float | corrct.data_terms.NDArrayFloat, background: float | corrct.data_terms.NDArrayFloat | None = None)[source]

Bases: corrct.data_terms.DataFidelity_l2

l2-norm ball data-fidelity class.

Initialization

Initialize the base data-fidelity class.

Parameters

background : float | NDArrayFloat | None, optional The data background. The default is None.

__data_fidelity_name__

‘l2b’

sigma1: float | corrct.data_terms.NDArrayFloat

None

sigma_error: float | corrct.data_terms.NDArrayFloat

None

sigma_sqrt_error: float | corrct.data_terms.NDArrayFloat

None

assign_data(data: float | corrct.data_terms.NDArrayFloat | None, sigma: float | corrct.data_terms.NDArrayFloat = 1.0)[source]
compute_residual(proj_primal: corrct.data_terms.NDArrayFloat, mask: corrct.data_terms.NDArrayFloat | None = None) corrct.data_terms.NDArrayFloat[source]
apply_proximal_dual(dual: corrct.data_terms.NDArrayFloat) None[source]
apply_proximal_primal(primal: corrct.data_terms.NDArrayFloat, tau: float | corrct.data_terms.NDArrayFloat) None[source]

Apply prox_{tau * f_{l2b}} in-place.

The l2-ball data fidelity is: f(x) = max(||x - b|| - sqrt(epsilon), 0)^2 / 2

whose proximal is a soft-thresholded then scaled l2 proximal. Specifically: v = x - b soft-threshold v by sqrt(epsilon) * tau / (1 + tau * epsilon) prox(x) = b + v_thresholded / (1 + tau * epsilon)

Parameters

primal : NDArrayFloat The primal variable to update in-place. tau : float | NDArrayFloat The proximal step size.

compute_primal_dual_gap(proj_primal: corrct.data_terms.NDArrayFloat, dual: corrct.data_terms.NDArrayFloat, mask: corrct.data_terms.NDArrayFloat | None = None) float[source]
class corrct.data_terms.DataFidelity_Huber(local_error: float | corrct.data_terms.NDArrayFloat, background: float | corrct.data_terms.NDArrayFloat | None = None, l2_axis: int | None = None)[source]

Bases: corrct.data_terms.DataFidelityBase

Huber-norm data-fidelity class. Given a parameter a: l2-norm for x < a, and l1-norm for x > a.

Initialization

Initialize the base data-fidelity class.

Parameters

background : float | NDArrayFloat | None, optional The data background. The default is None.

__data_fidelity_name__

‘Hub’

one_sigma_error: float | corrct.data_terms.NDArrayFloat

None

assign_data(data: corrct.data_terms.NDArrayFloat, sigma: float | corrct.data_terms.NDArrayFloat = 1.0)[source]
compute_residual_norm(dual: corrct.data_terms.NDArrayFloat) float[source]
apply_proximal_dual(dual: corrct.data_terms.NDArrayFloat) None[source]
abstract apply_proximal_primal(primal: corrct.data_terms.NDArrayFloat, tau: float | corrct.data_terms.NDArrayFloat) None[source]

Not implemented: the Huber proximal in the primal has no simple closed form for general data.

The Huber function is f(x) = (1/2)||x-b||^2 if ||x-b|| <= a, else a*||x-b|| - a^2/2. Its proximal is a smooth interpolation between the l2 and l1 proximals, whose closed form depends on the norm of (x - b) relative to the threshold, making it straightforward only for the scalar case. For vector inputs with l2_axis, a Newton iteration would be required.

Raises

NotImplementedError Always raised; use a gradient step or PDHG instead.

compute_primal_dual_gap(proj_primal: corrct.data_terms.NDArrayFloat, dual: corrct.data_terms.NDArrayFloat, mask: corrct.data_terms.NDArrayFloat | None = None) float[source]
class corrct.data_terms.DataFidelity_l1(background=None)[source]

Bases: corrct.data_terms.DataFidelityBase

l1-norm data-fidelity class.

Initialization

Initialize the base data-fidelity class.

Parameters

background : float | NDArrayFloat | None, optional The data background. The default is None.

__data_fidelity_name__

‘l1’

_get_inner_norm(dual: corrct.data_terms.NDArrayFloat) corrct.data_terms.NDArrayFloat[source]
_apply_threshold(dual: corrct.data_terms.NDArrayFloat)[source]
apply_proximal_dual(dual: corrct.data_terms.NDArrayFloat, weight: float | corrct.data_terms.NDArrayFloat = 1.0)[source]
apply_proximal_primal(primal: corrct.data_terms.NDArrayFloat, tau: float | corrct.data_terms.NDArrayFloat) None[source]

Apply prox_{tau * ||. - b||_1} in-place via soft-thresholding.

For f(x) = ||x - b||_1, the proximal is element-wise soft-thresholding centered on b: prox(x)_i = b_i + sign(x_i - b_i) * max(|x_i - b_i| - tau, 0)

When no data has been assigned (b = 0), this reduces to plain soft-thresholding with threshold tau.

Parameters

primal : NDArrayFloat The primal variable to update in-place. tau : float | NDArrayFloat The proximal step size (soft-threshold level).

compute_residual_norm(dual: corrct.data_terms.NDArrayFloat) float[source]
compute_primal_dual_gap(proj_primal: corrct.data_terms.NDArrayFloat, dual: corrct.data_terms.NDArrayFloat, mask: corrct.data_terms.NDArrayFloat | None = None) float[source]
class corrct.data_terms.DataFidelity_l21(background: float | corrct.data_terms.NDArrayFloat | None = None, l2_axis: int = 0)[source]

Bases: corrct.data_terms.DataFidelity_l1

l12-norm data-fidelity class.

Initialization

Initialize the base data-fidelity class.

Parameters

background : float | NDArrayFloat | None, optional The data background. The default is None.

__data_fidelity_name__

‘l12’

l2_axis: int

None

_get_inner_norm(dual: corrct.data_terms.NDArrayFloat) corrct.data_terms.NDArrayFloat[source]
abstract apply_proximal_primal(primal: corrct.data_terms.NDArrayFloat, tau: float | corrct.data_terms.NDArrayFloat) None[source]

Not implemented: the l12 proximal in the primal domain requires a group soft-threshold along l2_axis, which is straightforward only when the l2_axis corresponds to independent groups that do not interact through A. For general use, apply PDHG or provide a custom group-soft-threshold.

Raises

NotImplementedError Always raised.

class corrct.data_terms.DataFidelity_l21w(axis_weights: corrct.data_terms.NDArrayFloat, background: float | corrct.data_terms.NDArrayFloat | None = None, l2_axis: int = 0, inner_norm: float = 2)[source]

Bases: corrct.data_terms.DataFidelity_l21

l12-norm data-fidelity class.

Initialization

Initialize the base data-fidelity class.

Parameters

background : float | NDArrayFloat | None, optional The data background. The default is None.

__data_fidelity_name__

‘l21w’

axis_weights: corrct.data_terms.NDArrayFloat

None

inner_norm: float

None

_get_inner_norm(dual: corrct.data_terms.NDArrayFloat) corrct.data_terms.NDArrayFloat[source]
class corrct.data_terms.DataFidelity_l1b(local_error: float | corrct.data_terms.NDArrayFloat, background: float | corrct.data_terms.NDArrayFloat | None = None)[source]

Bases: corrct.data_terms.DataFidelity_l1

l1-norm ball data-fidelity class.

Initialization

Initialize the base data-fidelity class.

Parameters

background : float | NDArrayFloat | None, optional The data background. The default is None.

__data_fidelity_name__

‘l1b’

sigma_error: float | corrct.data_terms.NDArrayFloat

None

assign_data(data: corrct.data_terms.NDArrayFloat, sigma: float | corrct.data_terms.NDArrayFloat = 1.0) None[source]
_apply_threshold(dual: corrct.data_terms.NDArrayFloat) None[source]
apply_proximal_primal(primal: corrct.data_terms.NDArrayFloat, tau: float | corrct.data_terms.NDArrayFloat) None[source]

Apply prox_{tau * f_{l1b}} in-place.

The l1-ball data fidelity is: f(x) = max(||x - b||_1 - epsilon, 0)

Its proximal is a two-stage soft-threshold: v = x - b soft-threshold v by (tau / (1 + tau)) elementwise, with level epsilon prox(x) = b + v_thresholded

This is obtained via Moreau’s identity applied to the indicator of the l1-ball of radius epsilon.

Parameters

primal : NDArrayFloat The primal variable to update in-place. tau : float | NDArrayFloat The proximal step size.

class corrct.data_terms.DataFidelity_KL(background: float | corrct.data_terms.NDArrayFloat | None = None)[source]

Bases: corrct.data_terms.DataFidelityBase

Kullback-Leibler data-fidelity class.

Initialization

Initialize the base data-fidelity class.

Parameters

background : float | NDArrayFloat | None, optional The data background. The default is None.

__data_fidelity_name__

‘KL’

_compute_sigma_data()[source]
apply_proximal_dual(dual: corrct.data_terms.NDArrayFloat)[source]
apply_proximal_primal(primal: corrct.data_terms.NDArrayFloat, tau: float | corrct.data_terms.NDArrayFloat) None[source]

Apply prox_{tau * KL(b, .)} in-place.

The Kullback-Leibler divergence (in the emission-CT convention) is: f(x) = sum_i (x_i - b_i * log(x_i)) (for x_i > 0)

Its proximal has the closed-form solution: prox(x)_i = ((x_i - tau) + sqrt((x_i - tau)^2 + 4 * tau * b_i)) / 2

This is always non-negative when b_i >= 0 and x_i > 0.

Parameters

primal : NDArrayFloat The primal variable to update in-place (must be > 0). tau : float | NDArrayFloat The proximal step size.

compute_residual(proj_primal: numpy.typing.NDArray, mask: numpy.typing.NDArray | None = None, use_proximal: bool = True) corrct.data_terms.NDArrayFloat[source]
compute_residual_norm(dual: corrct.data_terms.NDArrayFloat) float[source]
compute_primal_dual_gap(proj_primal: corrct.data_terms.NDArrayFloat, dual: corrct.data_terms.NDArrayFloat, mask: corrct.data_terms.NDArrayFloat | None = None)[source]
class corrct.data_terms.DataFidelity_ln(background: float | corrct.data_terms.NDArrayFloat | None = None, ln_axes: collections.abc.Sequence[int] = (1, -1), spectral_norm: corrct.data_terms.DataFidelityBase = DataFidelity_l1())[source]

Bases: corrct.data_terms.DataFidelityBase

nuclear-norm data-fidelity class.

Initialization

Initialize the base data-fidelity class.

Parameters

background : float | NDArrayFloat | None, optional The data background. The default is None.

__data_fidelity_name__

‘ln’

ln_axes: collections.abc.Sequence[int]

None

apply_proximal_dual(dual: corrct.data_terms.NDArrayFloat) None[source]
abstract apply_proximal_primal(primal: corrct.data_terms.NDArrayFloat, tau: float | corrct.data_terms.NDArrayFloat) None[source]

Not implemented: the nuclear-norm proximal requires a full SVD and singular-value soft-thresholding, which is only well-defined for the dual formulation used here (where the SVD axes and data structure are set up by the PDHG dual update). Applying it directly in the primal domain would require re-interpreting primal axes as matrix rows/columns, which depends on context not available here.

Raises

NotImplementedError Always raised; use PDHG for nuclear-norm data fidelity.

compute_residual_norm(dual: corrct.data_terms.NDArrayFloat) float[source]
compute_primal_dual_gap(proj_primal: corrct.data_terms.NDArrayFloat, dual: corrct.data_terms.NDArrayFloat, mask: corrct.data_terms.NDArrayFloat | None = None)[source]