Skip to main content

fpm_rs/algorithms/
mod.rs

1//! Iterative reconstruction algorithms for compiled image-plane models.
2//!
3//! Choose a concrete solver such as [`crate::algorithms::AlternatingProjection`],
4//! [`crate::algorithms::AdaptiveAlternatingProjection`],
5//! [`crate::algorithms::Fpie`], [`crate::algorithms::Mpie`], [`crate::algorithms::Epry`],
6//! [`crate::algorithms::Admm`], [`crate::algorithms::GradientDescent`], or
7//! [`crate::algorithms::GlobalGaussNewton`]. All
8//! implement [`crate::algorithms::ReconstructionAlgorithm`] and consume a validated
9//! [`crate::reconstruction::ReconstructionProblem`]; illumination geometry is compiled
10//! beforehand into the problem's [`crate::model::ImagePlaneModel`].
11
12mod adaptive_alternating_projection;
13mod admm;
14mod alternating_projection;
15mod common;
16mod epry;
17mod fpie;
18mod gauge;
19mod global_gauss_newton;
20mod gradient_descent;
21mod joint_reconstruction;
22mod metrics;
23mod mpie;
24pub mod objective;
25mod regularization;
26
27pub use adaptive_alternating_projection::{
28    AdaptiveAlternatingProjection, AdaptiveAlternatingProjectionIterationMetrics,
29};
30pub use admm::{Admm, AdmmIterationMetrics};
31pub use alternating_projection::AlternatingProjection;
32pub use epry::Epry;
33pub use fpie::Fpie;
34pub use global_gauss_newton::{GlobalGaussNewton, GlobalGaussNewtonIterationMetrics};
35pub use gradient_descent::{GradientDescent, GradientDescentIterationMetrics};
36pub use joint_reconstruction::{
37    JointIterationMetrics, JointReconstruction, JointReconstructionResult,
38};
39pub use metrics::{AlgorithmIterationMetrics, NoIterationMetrics, StepOutput, StepSummary};
40pub use mpie::Mpie;
41
42use crate::{
43    Result,
44    backend::Backend,
45    callbacks::Callback,
46    measurements::MeasurementRead,
47    reconstruction::{
48        Batch, ReconstructionCheckpoint, ReconstructionProblem, ReconstructionResult,
49        ReconstructionState, RunOptions, Runner,
50    },
51};
52use std::sync::Arc;
53
54/// Contract implemented by iterative image-plane reconstruction solvers.
55///
56/// Implementors validate their configuration, initialize a [`ReconstructionState`],
57/// and update one scheduled [`Batch`] at a time. The trait's convenience methods own
58/// the algorithm, borrow the problem for the duration of the run, and return an owned
59/// [`ReconstructionResult`].
60pub trait ReconstructionAlgorithm {
61    /// Algorithm-specific metrics emitted by each step and appended to the trace.
62    type IterationMetrics: AlgorithmIterationMetrics;
63
64    /// Validates solver parameters independently of a reconstruction problem.
65    fn validate(&self) -> Result<()> {
66        Ok(())
67    }
68
69    /// Validates solver requirements that depend on `problem`.
70    fn validate_problem<M: MeasurementRead>(
71        &self,
72        _problem: &ReconstructionProblem<M>,
73    ) -> Result<()> {
74        Ok(())
75    }
76
77    /// Creates the default CPU-backed state for `problem`.
78    fn initialize<M: MeasurementRead>(
79        &self,
80        problem: &ReconstructionProblem<M>,
81    ) -> Result<ReconstructionState> {
82        ReconstructionState::initialize(problem)
83    }
84
85    /// Creates reconstruction state using the supplied execution `backend`.
86    fn initialize_with_backend<M: MeasurementRead>(
87        &self,
88        problem: &ReconstructionProblem<M>,
89        backend: Arc<dyn Backend>,
90    ) -> Result<ReconstructionState> {
91        ReconstructionState::initialize_with_backend(problem, backend)
92    }
93
94    /// Projects algorithm-owned ambiguities into a stable reported convention.
95    ///
96    /// [`Runner`] calls this after initialization or checkpoint restoration and
97    /// after every completed iteration, before iteration diagnostics and
98    /// callbacks, checkpoints, and final result construction. The default
99    /// implementation leaves state unchanged. Algorithms that jointly recover
100    /// coupled fields can override it without requiring external implementations
101    /// to add a lifecycle method. Implementations must preserve the represented
102    /// forward prediction and make repeated projection numerically idempotent.
103    fn canonicalize_state<M: MeasurementRead>(
104        &self,
105        _problem: &ReconstructionProblem<M>,
106        _state: &mut ReconstructionState,
107    ) -> Result<()> {
108        Ok(())
109    }
110
111    /// Reports whether the algorithm may run inside physical joint calibration.
112    ///
113    /// The default permits wrapping. Stateful methods whose internal variables
114    /// would become invalid when the calibrated forward model is recompiled can
115    /// return `false`; [`JointReconstruction`] then rejects them during
116    /// validation.
117    fn supports_joint_reconstruction(&self) -> bool {
118        true
119    }
120
121    /// Updates `state` for one scheduled batch in zero-based `iteration`.
122    fn step<M: MeasurementRead>(
123        &mut self,
124        problem: &ReconstructionProblem<M>,
125        state: &mut ReconstructionState,
126        batch: &Batch,
127        iteration: usize,
128    ) -> Result<StepOutput<Self::IterationMetrics>>;
129
130    /// Returns the requested number of complete schedule passes.
131    fn iterations(&self) -> usize;
132
133    /// Returns the number of measured frames combined into one step.
134    fn batch_size(&self) -> usize {
135        1
136    }
137
138    /// Runs the algorithm with default sequential scheduling and no callbacks.
139    fn run<M: MeasurementRead>(
140        self,
141        problem: &ReconstructionProblem<M>,
142    ) -> Result<ReconstructionResult>
143    where
144        Self: Sized,
145    {
146        let options = RunOptions {
147            max_iterations: self.iterations(),
148            batch_size: self.batch_size(),
149            ..RunOptions::default()
150        };
151        Runner::new(self, options).run(problem)
152    }
153
154    /// Runs the algorithm and invokes `callbacks` at their declared hooks.
155    fn run_with_callbacks<M: MeasurementRead>(
156        self,
157        problem: &ReconstructionProblem<M>,
158        callbacks: Vec<Box<dyn Callback>>,
159    ) -> Result<ReconstructionResult>
160    where
161        Self: Sized,
162    {
163        let options = RunOptions {
164            max_iterations: self.iterations(),
165            batch_size: self.batch_size(),
166            ..RunOptions::default()
167        };
168        Runner::new(self, options)
169            .with_callbacks(callbacks)
170            .run(problem)
171    }
172
173    /// Resumes a run from a checkpoint after validating it against `problem`.
174    fn run_from_checkpoint<M: MeasurementRead>(
175        self,
176        problem: &ReconstructionProblem<M>,
177        checkpoint: ReconstructionCheckpoint,
178    ) -> Result<ReconstructionResult>
179    where
180        Self: Sized,
181    {
182        let options = RunOptions {
183            max_iterations: self.iterations(),
184            batch_size: self.batch_size(),
185            ..RunOptions::default()
186        };
187        Runner::new(self, options)
188            .resume_from(checkpoint)
189            .run(problem)
190    }
191}