treams_core/smatrix/solve/
saved.rs1use super::{InternalFactor, InternalSolve};
7use crate::{
8 Result,
9 linalg::Lu,
10 saved::{Reader, SavedState, Writer},
11 smatrix::saved::{invalid, product, read_matrix, total, write_matrix},
12};
13
14impl InternalSolve {
15 pub(in crate::smatrix) fn state_size(n: usize, columns: usize) -> Result<usize> {
16 if n == 0 || columns == 0 {
17 return Err(invalid());
18 }
19 total(&[17, product(&[16, n, columns])?, Lu::state_size(n)?])
20 }
21}
22
23fn write_zeros(writer: &mut Writer, count: usize) {
24 const ZEROES: [u8; 256] = [0; 256];
25 for _ in 0..count / ZEROES.len() {
26 writer.raw(&ZEROES);
27 }
28 writer.raw(&ZEROES[..count % ZEROES.len()]);
29}
30
31impl SavedState for InternalSolve {
32 fn save_state(&self) -> Result<Vec<u8>> {
33 let (n, columns) = self.value.shape();
34 let mut writer = Writer::new(Self::state_size(n, columns)?);
35 writer.usize(n);
36 writer.usize(columns);
37 writer.byte(match &self.factor {
38 InternalFactor::Reflections => 0,
39 InternalFactor::Krylov(_) => 1,
40 InternalFactor::Lu(_) => 2,
41 });
42 write_matrix(&mut writer, &self.value);
43 match &self.factor {
44 InternalFactor::Reflections => write_zeros(&mut writer, Lu::state_size(n)?),
45 InternalFactor::Krylov(operator) => {
46 write_matrix(&mut writer, operator);
47 write_zeros(&mut writer, Lu::state_size(n)? - product(&[16, n, n])?);
48 }
49 InternalFactor::Lu(lu) => lu.write_state(&mut writer),
50 }
51 Ok(writer.finish())
52 }
53
54 fn from_state(bytes: &[u8]) -> Result<Self> {
55 let mut reader = Reader::new(bytes);
56 let (n, columns, tag) = (reader.usize()?, reader.usize()?, reader.byte()?);
57 if bytes.len() != Self::state_size(n, columns)? || tag > 2 {
58 return Err(invalid());
59 }
60 let value = read_matrix(&mut reader, n, columns)?;
61 let factor = match tag {
62 0 => InternalFactor::Reflections,
63 1 => InternalFactor::Krylov(read_matrix(&mut reader, n, n)?),
64 _ => InternalFactor::Lu(Lu::read_state(&mut reader, n)?),
65 };
66 if reader
68 .raw(reader.remaining_len())?
69 .iter()
70 .any(|&byte| byte != 0)
71 {
72 return Err(invalid());
73 }
74 reader.finish()?;
75 Ok(Self { value, factor })
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::{Complex, linalg::view, test_support::patterned};
83 use nalgebra::DMatrix;
84
85 #[test]
86 fn saved_state_preserves_lu_and_both_krylov_strategies() {
87 let n = 24;
88 let weak = DMatrix::identity(n, n) * Complex::new(0.1, 0.03);
89 let cancellation = DMatrix::from_fn(n, n, |_, j| {
90 Complex::new(if j % 2 == 0 { 0.1 } else { -0.1 }, 0.0)
91 });
92 let constant = DMatrix::from_element(n, n, Complex::new(0.1, 0.0));
93 let rhs = patterned(n, 2, 0.4);
94 let direction = patterned(n, 2, 0.9);
95 for (lower, upper, threshold, tag) in [
96 (&weak, &weak, n + 1, 2),
97 (&weak, &weak, n, 0),
98 (&cancellation, &constant, n, 1),
99 ] {
100 let original =
101 InternalSolve::with_threshold(view(lower), view(upper), rhs.clone(), threshold)
102 .unwrap();
103 let bytes = original.save_state().unwrap();
104 assert_eq!(bytes.len(), InternalSolve::state_size(n, 2).unwrap());
105 assert_eq!(bytes[16], tag);
106 let loaded = InternalSolve::from_state(&bytes).unwrap();
107 assert_eq!(loaded.save_state().unwrap(), bytes);
108 assert_eq!(loaded.value, original.value);
109 assert_eq!(
110 loaded
111 .solve_forward(view(lower), view(upper), direction.clone())
112 .unwrap(),
113 original
114 .solve_forward(view(lower), view(upper), direction.clone())
115 .unwrap(),
116 );
117 assert_eq!(
118 loaded
119 .solve_adjoint(view(lower), view(upper), direction.clone())
120 .unwrap()
121 .adjoint,
122 original
123 .solve_adjoint(view(lower), view(upper), direction.clone())
124 .unwrap()
125 .adjoint,
126 );
127 assert!(InternalSolve::from_state(&bytes[..bytes.len() - 1]).is_err());
128 let mut extended = bytes.clone();
129 extended.push(0);
130 assert!(InternalSolve::from_state(&extended).is_err());
131 let mut oversized = bytes;
132 oversized[..8].fill(u8::MAX);
133 assert!(InternalSolve::from_state(&oversized).is_err());
134 }
135 }
136}