1use std::sync::Arc;
4
5use nalgebra::DMatrix;
6
7use super::{IlluminateResidual, InteractionFactor, InteractionResidual, LocalMatrix};
8use crate::{
9 Complex, Error, Result,
10 linalg::Lu,
11 numerics,
12 saved::{Reader, SavedState, Writer, write_matrix},
13};
14
15fn invalid() -> Error {
16 Error::InvalidInput("invalid cluster derivative state".into())
17}
18
19fn add(a: usize, b: usize) -> Result<usize> {
20 a.checked_add(b).ok_or_else(invalid)
21}
22
23fn mul(a: usize, b: usize) -> Result<usize> {
24 a.checked_mul(b).ok_or_else(invalid)
25}
26
27fn matrix_size(rows: usize, columns: usize) -> Result<usize> {
28 mul(16, mul(rows, columns)?)
29}
30
31fn dimensions(sizes: &[usize]) -> Result<(usize, usize)> {
32 if sizes.is_empty() || sizes.contains(&0) {
33 return Err(invalid());
34 }
35 sizes
36 .iter()
37 .try_fold((0, 0), |(dimension, entries), &size| {
38 Ok((add(dimension, size)?, add(entries, mul(size, size)?)?))
39 })
40}
41
42fn factor_size(blocks: usize, dimension: usize, entries: usize) -> Result<usize> {
43 let header = add(8, mul(8, blocks)?)?;
44 let matrices = add(mul(16, entries)?, matrix_size(dimension, dimension)?)?;
45 add(add(header, matrices)?, Lu::state_size(dimension)?)
46}
47
48fn read_matrix(reader: &mut Reader<'_>, rows: usize, columns: usize) -> Result<DMatrix<Complex>> {
49 let mut matrix = numerics::zeros(rows, columns)?;
50 for value in matrix.as_mut_slice() {
51 *value = reader.complex()?;
52 }
53 Ok(matrix)
54}
55
56fn read_sizes(reader: &mut Reader<'_>) -> Result<Vec<usize>> {
59 let count = reader.usize()?;
60 if count == 0 || count > reader.remaining_len() / 8 {
61 return Err(invalid());
62 }
63 (0..count).map(|_| reader.usize()).collect()
64}
65
66impl InteractionFactor {
67 fn write_state(&self, writer: &mut Writer) {
68 writer.usize(self.local.blocks.len());
69 for block in &self.local.blocks {
70 writer.usize(block.nrows());
71 }
72 for block in &self.local.blocks {
73 write_matrix(writer, block);
74 }
75 write_matrix(writer, &self.coupling);
76 self.lu.write_state(writer);
77 }
78
79 fn read_body(reader: &mut Reader<'_>, sizes: &[usize], dimension: usize) -> Result<Self> {
80 let blocks = sizes
81 .iter()
82 .map(|&size| read_matrix(reader, size, size))
83 .collect::<Result<Vec<_>>>()?;
84 let coupling = read_matrix(reader, dimension, dimension)?;
85 let lu = Lu::read_state(reader, dimension)?;
86 Ok(Self {
87 local: LocalMatrix { blocks },
88 coupling,
89 lu,
90 })
91 }
92}
93
94impl InteractionResidual {
95 pub fn state_size(local_sizes: &[usize]) -> Result<usize> {
97 let (dimension, entries) = dimensions(local_sizes)?;
98 add(
99 factor_size(local_sizes.len(), dimension, entries)?,
100 matrix_size(dimension, dimension)?,
101 )
102 }
103
104 pub(crate) fn state_size_uniform(block_size: usize, particles: usize) -> Result<usize> {
106 if block_size == 0 || particles == 0 {
107 return Err(invalid());
108 }
109 let dimension = mul(block_size, particles)?;
110 let entries = mul(mul(block_size, block_size)?, particles)?;
111 add(
112 factor_size(particles, dimension, entries)?,
113 matrix_size(dimension, dimension)?,
114 )
115 }
116
117 pub(crate) fn write_state(&self, writer: &mut Writer) {
118 self.factor.write_state(writer);
119 write_matrix(writer, &self.value);
120 }
121
122 pub(crate) fn read_state(reader: &mut Reader<'_>) -> Result<Self> {
123 let sizes = read_sizes(reader)?;
124 let header = add(8, mul(8, sizes.len())?)?;
125 let expected = Self::state_size(&sizes)?;
126 if expected - header > reader.remaining_len() {
127 return Err(invalid());
128 }
129 let (dimension, _) = dimensions(&sizes)?;
130 let factor = InteractionFactor::read_body(reader, &sizes, dimension)?;
131 let value = read_matrix(reader, dimension, dimension)?;
132 Ok(Self { factor, value })
133 }
134}
135
136impl SavedState for InteractionResidual {
137 fn save_state(&self) -> Result<Vec<u8>> {
138 let sizes: Vec<_> = self.local_shapes().map(|(rows, _)| rows).collect();
139 let mut writer = Writer::new(Self::state_size(&sizes)?);
140 self.write_state(&mut writer);
141 Ok(writer.finish())
142 }
143
144 fn from_state(bytes: &[u8]) -> Result<Self> {
145 let mut reader = Reader::new(bytes);
146 let residual = Self::read_state(&mut reader)?;
147 reader.finish()?;
148 Ok(residual)
149 }
150}
151
152impl IlluminateResidual {
153 pub fn state_size(local_sizes: &[usize], columns: usize) -> Result<usize> {
155 if columns == 0 {
156 return Err(invalid());
157 }
158 let (dimension, entries) = dimensions(local_sizes)?;
159 add(
160 add(8, factor_size(local_sizes.len(), dimension, entries)?)?,
161 mul(2, matrix_size(dimension, columns)?)?,
162 )
163 }
164}
165
166impl SavedState for IlluminateResidual {
167 fn save_state(&self) -> Result<Vec<u8>> {
168 let sizes: Vec<_> = self.local_shapes().map(|(rows, _)| rows).collect();
169 let mut writer = Writer::new(Self::state_size(&sizes, self.value.ncols())?);
170 writer.usize(self.value.ncols());
171 self.factor.write_state(&mut writer);
172 write_matrix(&mut writer, &self.response);
173 write_matrix(&mut writer, &self.value);
174 Ok(writer.finish())
175 }
176
177 fn from_state(bytes: &[u8]) -> Result<Self> {
178 let mut reader = Reader::new(bytes);
179 let columns = reader.usize()?;
180 let sizes = read_sizes(&mut reader)?;
181 if Self::state_size(&sizes, columns)? != bytes.len() {
182 return Err(invalid());
183 }
184 let (dimension, _) = dimensions(&sizes)?;
185 let factor = Arc::new(InteractionFactor::read_body(
186 &mut reader,
187 &sizes,
188 dimension,
189 )?);
190 let response = read_matrix(&mut reader, dimension, columns)?;
191 let value = read_matrix(&mut reader, dimension, columns)?;
192 reader.finish()?;
193 Ok(Self {
194 factor,
195 response,
196 value,
197 })
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204 use crate::{cluster::interaction_blocks, test_support::patterned};
205
206 #[test]
207 fn saved_interactions_retain_blocks_factors_and_both_derivatives() {
208 let blocks = vec![patterned(1, 1, 0.2), patterned(2, 2, 0.4)];
209 let coupling = patterned(3, 3, 0.6) * Complex::from(0.02);
210 let direction = patterned(3, 3, 0.8);
211 let residual = interaction_blocks(blocks.clone(), coupling.clone()).unwrap();
212 let bytes = residual.save_state().unwrap();
213 assert_eq!(
214 bytes.len(),
215 InteractionResidual::state_size(&[1, 2]).unwrap()
216 );
217 let restored = InteractionResidual::from_state(&bytes).unwrap();
218 assert_eq!(restored.save_state().unwrap(), bytes);
219 assert_eq!(restored.value(), residual.value());
220 assert_eq!(
221 restored.pushforward_blocks(&blocks, &direction).unwrap(),
222 residual.pushforward_blocks(&blocks, &direction).unwrap()
223 );
224 let actual = restored.pullback_blocks(&direction).unwrap();
225 let expected = residual.pullback_blocks(&direction).unwrap();
226 assert_eq!(actual.local, expected.local);
227 assert_eq!(actual.coupling, expected.coupling);
228 assert!(InteractionResidual::from_state(&bytes[..bytes.len() - 1]).is_err());
229 let mut malformed = bytes;
230 malformed.extend_from_slice(&[0]);
231 assert!(InteractionResidual::from_state(&malformed).is_err());
232 malformed[..8].fill(255);
233 assert!(InteractionResidual::from_state(&malformed).is_err());
234
235 let factor = Arc::new(InteractionFactor::from_blocks(blocks.clone(), coupling).unwrap());
236 let incident = patterned(3, 2, 1.0);
237 let residual = factor.record(incident.clone()).unwrap();
238 let bytes = residual.save_state().unwrap();
239 assert_eq!(
240 bytes.len(),
241 IlluminateResidual::state_size(&[1, 2], 2).unwrap()
242 );
243 let restored = IlluminateResidual::from_state(&bytes).unwrap();
244 assert_eq!(restored.save_state().unwrap(), bytes);
245 assert_eq!(restored.value(), residual.value());
246 assert_eq!(
247 restored
248 .pushforward(&blocks, &direction, &incident)
249 .unwrap(),
250 residual
251 .pushforward(&blocks, &direction, &incident)
252 .unwrap()
253 );
254 let actual = restored.pullback(&incident).unwrap();
255 let expected = residual.pullback(&incident).unwrap();
256 assert_eq!(actual.local, expected.local);
257 assert_eq!(actual.coupling, expected.coupling);
258 assert_eq!(actual.incident, expected.incident);
259 assert!(IlluminateResidual::from_state(&bytes[..bytes.len() - 1]).is_err());
260 let mut malformed = bytes;
261 malformed[..8].fill(255);
262 assert!(IlluminateResidual::from_state(&malformed).is_err());
263 }
264}