fpm_rs/algorithms/
fpie.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)]
37pub struct Fpie {
38 pub iterations: usize,
40 pub object_step: f64,
42 pub stability: f64,
45 pub batch_size: usize,
47 pub epsilon: f64,
49 pub loss_type: LossType,
52}
53
54impl Default for Fpie {
55 fn default() -> Self {
56 Self {
57 iterations: 50,
58 object_step: 0.8,
59 stability: 0.1,
60 batch_size: 1,
61 epsilon: 1e-10,
62 loss_type: LossType::AmplitudeMse,
63 }
64 }
65}
66
67impl Fpie {
68 pub fn iterations(mut self, iterations: usize) -> Self {
69 self.iterations = iterations;
70 self
71 }
72
73 pub fn object_step(mut self, step: f64) -> Self {
74 self.object_step = step;
75 self
76 }
77
78 pub fn stability(mut self, stability: f64) -> Self {
79 self.stability = stability.clamp(0.0, 1.0);
80 self
81 }
82}
83
84impl ReconstructionAlgorithm for Fpie {
85 fn validate(&self) -> Result<()> {
86 if !self.object_step.is_finite() || self.object_step <= 0.0 {
87 return Err(Error::InvalidParameter {
88 name: "object_step",
89 reason: "must be finite and positive".into(),
90 });
91 }
92 if !self.stability.is_finite() || !(0.0..=1.0).contains(&self.stability) {
93 return Err(Error::InvalidParameter {
94 name: "stability",
95 reason: "must be finite and between zero and one".into(),
96 });
97 }
98 if !self.epsilon.is_finite() || self.epsilon <= 0.0 || self.batch_size == 0 {
99 return Err(Error::InvalidParameter {
100 name: "epsilon/batch_size",
101 reason: "epsilon must be positive and batch size non-zero".into(),
102 });
103 }
104 Ok(())
105 }
106
107 fn step<M: MeasurementRead>(
108 &mut self,
109 problem: &ReconstructionProblem<M>,
110 state: &mut ReconstructionState,
111 batch: &Batch,
112 _iteration: usize,
113 ) -> Result<StepDiagnostics> {
114 projection_update(
115 problem,
116 state,
117 batch,
118 UpdateConfiguration {
119 object_step: self.object_step,
120 pupil_step: None,
121 epsilon: self.epsilon,
122 loss_type: self.loss_type,
123 object_denominator: ObjectDenominator::Rpie(self.stability),
124 constrain_pupil: true,
125 gain_update: None,
126 background_update: None,
127 },
128 )
129 }
130
131 fn iterations(&self) -> usize {
132 self.iterations
133 }
134
135 fn batch_size(&self) -> usize {
136 self.batch_size
137 }
138}