Source code for pct_tools.recon
"""Steepest descent on ``1/2 ||A x - b||^2`` for a system stored as blocks on disk.
The system matrix ``A`` and the measurement vector ``b`` are split into row blocks
``(A_i, b_i)``, one pair of files per projection, written by :mod:`pct_tools.matrix` and
the preprocessing. Each call here streams through every block in parallel and returns one
quantity for the whole system: one descent step, or the squared residual norm. The iteration
itself, including the step size (see :mod:`pct_tools.lipschitz`) and the stopping rule, is
left to the caller.
"""
from __future__ import annotations
from typing import TYPE_CHECKING
import numpy as np
import pct_tools._ext
from ._arrays import require_dtype
if TYPE_CHECKING:
from collections.abc import Sequence
from numpy.typing import NDArray
[docs]
def gradient_descent(
x: NDArray[np.float32],
step_size: float,
matrix_filenames: Sequence[str],
vector_filenames: Sequence[str],
*,
verbosity_level: int = 0,
n_threads: int = 1,
) -> NDArray[np.float32]:
"""Perform one steepest-descent step on ``1/2 ||A x - b||^2``.
The system is split into blocks ``(A_i, b_i)`` that are stored on disk and processed in
parallel; the result is ``x - step_size * sum_i A_i^T (A_i x - b_i)``.
Args:
x: The current estimate, a float32 array of shape ``(n_voxels,)`` where ``n_voxels``
is the number of columns of ``A``.
step_size: The step size to be used in the descent, typically ``1 / L`` with ``L`` the
Lipschitz constant estimated via :mod:`pct_tools.lipschitz`.
matrix_filenames: The filenames of the compressed matrix blocks.
vector_filenames: The filenames of the matching b-vector blocks.
verbosity_level: The verbosity level.
n_threads: The number of threads to use.
Returns:
The updated vector after one step of steepest descent, with the same shape as ``x``.
Raises:
TypeError: If ``x`` is not a float32 array.
"""
require_dtype(x, np.float32, "x")
return pct_tools._ext.gradient_descent(
x,
step_size,
matrix_filenames,
vector_filenames,
verbosity_level,
n_threads,
)
[docs]
def squared_residuals(
x: NDArray[np.float32],
matrix_filenames: Sequence[str],
vector_filenames: Sequence[str],
*,
verbosity_level: int = 0,
n_threads: int = 1,
) -> float:
"""Compute the squared residual norm ``||A x - b||^2`` for a given vector.
Args:
x: The current estimate, a float32 array of shape ``(n_voxels,)``.
matrix_filenames: The filenames of the compressed matrix blocks.
vector_filenames: The filenames of the matching b-vector blocks.
verbosity_level: The verbosity level.
n_threads: The number of threads to use.
Returns:
The squared residual norm.
Raises:
TypeError: If ``x`` is not a float32 array.
"""
require_dtype(x, np.float32, "x")
return pct_tools._ext.squared_residuals(x, matrix_filenames, vector_filenames, verbosity_level, n_threads)