1use super::{
5 LatticeExpansionFromTableResidual, LatticeExpansionResidual, blocks, validate_expansion,
6};
7use crate::{
8 Result,
9 lattice::BlochLattice,
10 numerics::finite,
11 saved::{self, Reader, SavedState, Writer},
12};
13
14fn basis_pair_size(dm: usize, dp: usize, sm: usize, sp: usize, extra: usize) -> Result<usize> {
15 saved::sw_basis_size(dm, dp)?
16 .checked_add(saved::sw_basis_size(sm, sp)?)
17 .and_then(|size| size.checked_add(extra))
18 .ok_or_else(saved::invalid)
19}
20
21impl LatticeExpansionResidual {
22 pub fn state_size(
24 destination_modes: usize,
25 destination_positions: usize,
26 source_modes: usize,
27 source_positions: usize,
28 ) -> Result<usize> {
29 basis_pair_size(
30 destination_modes,
31 destination_positions,
32 source_modes,
33 source_positions,
34 BlochLattice::STATE_SIZE + 49,
35 )
36 }
37}
38
39impl SavedState for LatticeExpansionResidual {
40 fn save_state(&self) -> Result<Vec<u8>> {
41 let mut writer = Writer::new(Self::state_size(
42 self.destination.modes.len(),
43 self.destination.positions.len(),
44 self.source.modes.len(),
45 self.source.positions.len(),
46 )?);
47 saved::write_sw_basis(&mut writer, &self.destination);
48 saved::write_sw_basis(&mut writer, &self.source);
49 for k in self.ks {
50 writer.complex(k);
51 }
52 writer.complex(self.eta);
53 writer.byte(u8::from(self.helicity));
54 self.lattice.write_state(&mut writer);
55 Ok(writer.finish())
56 }
57
58 fn from_state(bytes: &[u8]) -> Result<Self> {
59 let mut shape = Reader::new(bytes);
60 let (dm, dp) = saved::read_sw_basis_dimensions(&mut shape)?;
61 let (sm, sp) = saved::read_sw_basis_dimensions(&mut shape)?;
62 if bytes.len() != Self::state_size(dm, dp, sm, sp)? {
63 return Err(saved::invalid());
64 }
65 let mut reader = Reader::new(bytes);
66 let destination = saved::read_sw_basis(&mut reader)?;
67 let source = saved::read_sw_basis(&mut reader)?;
68 let ks = [reader.complex()?, reader.complex()?];
69 let eta = reader.complex()?;
70 let helicity = match reader.byte()? {
71 0 => false,
72 1 => true,
73 _ => return Err(saved::invalid()),
74 };
75 let lattice = BlochLattice::read_state(&mut reader)?;
76 reader.finish()?;
77 validate_expansion(&destination, &source, ks, helicity)?;
78 if !finite(eta) {
79 return Err(saved::invalid());
80 }
81 let blocks = blocks(&destination, &source, helicity, false)?;
82 Ok(Self {
83 destination,
84 source,
85 ks,
86 lattice,
87 eta,
88 helicity,
89 blocks,
90 })
91 }
92}
93
94impl LatticeExpansionFromTableResidual {
95 pub fn state_size(
97 destination_modes: usize,
98 destination_positions: usize,
99 source_modes: usize,
100 source_positions: usize,
101 ) -> Result<usize> {
102 basis_pair_size(
103 destination_modes,
104 destination_positions,
105 source_modes,
106 source_positions,
107 33,
108 )
109 }
110}
111
112impl SavedState for LatticeExpansionFromTableResidual {
113 fn save_state(&self) -> Result<Vec<u8>> {
114 let mut writer = Writer::new(Self::state_size(
115 self.destination.modes.len(),
116 self.destination.positions.len(),
117 self.source.modes.len(),
118 self.source.positions.len(),
119 )?);
120 saved::write_sw_basis(&mut writer, &self.destination);
121 saved::write_sw_basis(&mut writer, &self.source);
122 writer.byte(u8::from(self.helicity));
123 for size in self.table_shape {
124 writer.usize(size);
125 }
126 Ok(writer.finish())
127 }
128
129 fn from_state(bytes: &[u8]) -> Result<Self> {
130 let mut shape = Reader::new(bytes);
131 let (dm, dp) = saved::read_sw_basis_dimensions(&mut shape)?;
132 let (sm, sp) = saved::read_sw_basis_dimensions(&mut shape)?;
133 if bytes.len() != Self::state_size(dm, dp, sm, sp)? {
134 return Err(saved::invalid());
135 }
136 let mut reader = Reader::new(bytes);
137 let destination = saved::read_sw_basis(&mut reader)?;
138 let source = saved::read_sw_basis(&mut reader)?;
139 let helicity = match reader.byte()? {
140 0 => false,
141 1 => true,
142 _ => return Err(saved::invalid()),
143 };
144 let table_shape = [
145 reader.usize()?,
146 reader.usize()?,
147 reader.usize()?,
148 reader.usize()?,
149 ];
150 reader.finish()?;
151 let [destinations, sources, channels, harmonics] = table_shape;
152 let order = destination
153 .modes
154 .iter()
155 .map(|(_, mode)| mode.l)
156 .max()
157 .unwrap_or(0)
158 + source
159 .modes
160 .iter()
161 .map(|(_, mode)| mode.l)
162 .max()
163 .unwrap_or(0);
164 if destinations != dp
165 || sources != sp
166 || !(1..=2).contains(&channels)
167 || (!helicity && channels != 1)
168 || usize::try_from((order + 1).pow(2)) != Ok(harmonics)
169 {
170 return Err(saved::invalid());
171 }
172 let blocks = blocks(&destination, &source, helicity, true)?;
173 Ok(Self {
174 destination,
175 source,
176 helicity,
177 blocks,
178 table_shape,
179 shape: (dm, sm),
180 })
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use crate::{
188 Complex,
189 sw::{Basis, Mode, lattice_expansion},
190 };
191 use nalgebra::DMatrix;
192
193 #[test]
194 fn extreme_saved_split_returns_an_error_without_panicking() {
195 let destination = Basis {
196 modes: vec![(0, Mode { l: 1, m: 0, pol: 0 })],
197 positions: vec![[0.0; 3]],
198 };
199 let source = Basis {
200 positions: vec![[0.1, 0.0, 0.0]],
201 ..destination.clone()
202 };
203 let lattice = BlochLattice::new(&[vec![1.5, 0.0], vec![0.3, 1.4]], &[0.1, 0.2]).unwrap();
204 let (_, mut residual) = lattice_expansion(
205 destination,
206 source,
207 [Complex::new(1.2, 0.1); 2],
208 true,
209 lattice,
210 Complex::new(0.9, 0.1),
211 )
212 .unwrap();
213 for eta in [
214 Complex::new(1e200, 0.0),
215 Complex::new(1e-200, 0.0),
216 Complex::new(0.0, 1e200),
217 Complex::new(1e200, 1e200),
218 Complex::new(f64::MAX, 0.0),
219 Complex::new(0.0, f64::MAX),
220 ] {
221 residual.eta = eta;
222 let restored =
223 LatticeExpansionResidual::from_state(&residual.save_state().unwrap()).unwrap();
224 assert!(
225 restored
226 .pullback(&DMatrix::from_element(1, 1, Complex::new(1.0, 0.0)))
227 .is_err(),
228 "eta={eta}"
229 );
230 }
231 }
232}