fpm_rs/algorithms/
alternating_projection.rs1use crate::{
2 Result,
3 algorithms::objective::LossType,
4 diagnostics::StepDiagnostics,
5 error::Error,
6 measurements::MeasurementRead,
7 reconstruction::{Batch, ReconstructionProblem, ReconstructionState},
8};
9
10use super::{
11 ReconstructionAlgorithm,
12 common::{ObjectDenominator, UpdateConfiguration, projection_update},
13};
14
15#[derive(Clone, Debug)]
38pub struct AlternatingProjection {
39 pub iterations: usize,
41 pub object_step: f64,
43 pub batch_size: usize,
45 pub epsilon: f64,
47 pub loss_type: LossType,
50}
51
52impl Default for AlternatingProjection {
53 fn default() -> Self {
54 Self {
55 iterations: 50,
56 object_step: 1.0,
57 batch_size: 1,
58 epsilon: 1e-10,
59 loss_type: LossType::AmplitudeMse,
60 }
61 }
62}
63
64impl AlternatingProjection {
65 pub fn iterations(mut self, iterations: usize) -> Self {
66 self.iterations = iterations;
67 self
68 }
69
70 pub fn object_step(mut self, object_step: f64) -> Self {
71 self.object_step = object_step;
72 self
73 }
74
75 pub fn batch_size(mut self, batch_size: usize) -> Self {
76 self.batch_size = batch_size;
77 self
78 }
79}
80
81impl ReconstructionAlgorithm for AlternatingProjection {
82 fn validate(&self) -> Result<()> {
83 if !self.object_step.is_finite() || self.object_step <= 0.0 {
84 return Err(Error::InvalidParameter {
85 name: "object_step",
86 reason: "must be finite and positive".into(),
87 });
88 }
89 if !self.epsilon.is_finite() || self.epsilon <= 0.0 {
90 return Err(Error::InvalidParameter {
91 name: "epsilon",
92 reason: "must be finite and positive".into(),
93 });
94 }
95 if self.batch_size == 0 {
96 return Err(Error::InvalidParameter {
97 name: "batch_size",
98 reason: "must be greater than zero".into(),
99 });
100 }
101 Ok(())
102 }
103
104 fn step<M: MeasurementRead>(
105 &mut self,
106 problem: &ReconstructionProblem<M>,
107 state: &mut ReconstructionState,
108 batch: &Batch,
109 _iteration: usize,
110 ) -> Result<StepDiagnostics> {
111 projection_update(
112 problem,
113 state,
114 batch,
115 UpdateConfiguration {
116 object_step: self.object_step,
117 pupil_step: None,
118 epsilon: self.epsilon,
119 loss_type: self.loss_type,
120 object_denominator: ObjectDenominator::Local,
121 constrain_pupil: true,
122 gain_update: None,
123 background_update: None,
124 },
125 )
126 }
127
128 fn iterations(&self) -> usize {
129 self.iterations
130 }
131
132 fn batch_size(&self) -> usize {
133 self.batch_size
134 }
135}