sim_lib_discrete_algebra/
views.rs1use crate::error::AlgebraError;
9use crate::matrix::{AlgebraLimits, Matrix};
10use crate::semiring::Semiring;
11
12fn check_len<S: Semiring>(view_dim: usize, v: &[S]) -> Result<(), AlgebraError> {
13 if v.len() != view_dim {
14 return Err(AlgebraError::ShapeMismatch(format!(
15 "matvec: vector len {} != view dimension {view_dim}",
16 v.len()
17 )));
18 }
19 Ok(())
20}
21
22fn check_dim(n: usize, limits: AlgebraLimits) -> Result<(), AlgebraError> {
23 if n > limits.max_dim {
24 return Err(AlgebraError::LimitExceeded(format!(
25 "materialize: dimension {n} exceeds max_dim {}",
26 limits.max_dim
27 )));
28 }
29 Ok(())
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub struct IdentityView {
35 pub n: usize,
37}
38
39impl IdentityView {
40 pub fn matvec<S: Semiring>(&self, v: &[S]) -> Result<Vec<S>, AlgebraError> {
42 check_len(self.n, v)?;
43 Ok(v.to_vec())
44 }
45
46 pub fn materialize<S: Semiring>(
48 &self,
49 limits: AlgebraLimits,
50 ) -> Result<Matrix<S>, AlgebraError> {
51 check_dim(self.n, limits)?;
52 Matrix::try_identity_with_limits(self.n, limits)
53 }
54}
55
56#[derive(Debug, Clone, PartialEq)]
58pub struct DiagonalView<S: Semiring> {
59 pub diag: Vec<S>,
61}
62
63impl<S: Semiring> DiagonalView<S> {
64 pub fn matvec(&self, v: &[S]) -> Result<Vec<S>, AlgebraError> {
66 check_len(self.diag.len(), v)?;
67 Ok(self
68 .diag
69 .iter()
70 .zip(v.iter())
71 .map(|(d, x)| d.mul(x))
72 .collect())
73 }
74
75 pub fn materialize(&self, limits: AlgebraLimits) -> Result<Matrix<S>, AlgebraError> {
77 let n = self.diag.len();
78 check_dim(n, limits)?;
79 let mut m = Matrix::try_new_with_limits(n, n, limits)?;
80 for (i, d) in self.diag.iter().enumerate() {
81 m.set(i, i, d.clone())?;
82 }
83 Ok(m)
84 }
85}
86
87#[derive(Debug, Clone, PartialEq, Eq)]
89pub struct PermutationView {
90 pub perm: Vec<usize>,
92}
93
94impl PermutationView {
95 pub fn matvec<S: Semiring>(&self, v: &[S]) -> Result<Vec<S>, AlgebraError> {
97 check_len(self.perm.len(), v)?;
98 let mut out = Vec::with_capacity(self.perm.len());
99 for &p in &self.perm {
100 let val = v
101 .get(p)
102 .ok_or(AlgebraError::IndexOutOfBounds {
103 index: p,
104 len: v.len(),
105 })?
106 .clone();
107 out.push(val);
108 }
109 Ok(out)
110 }
111
112 pub fn materialize<S: Semiring>(
114 &self,
115 limits: AlgebraLimits,
116 ) -> Result<Matrix<S>, AlgebraError> {
117 let n = self.perm.len();
118 check_dim(n, limits)?;
119 let mut m: Matrix<S> = Matrix::try_new_with_limits(n, n, limits)?;
120 for (i, &p) in self.perm.iter().enumerate() {
121 if p >= n {
122 return Err(AlgebraError::IndexOutOfBounds { index: p, len: n });
123 }
124 m.set(i, p, S::one())?;
125 }
126 Ok(m)
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use crate::Counting;
134
135 fn vec_u64(xs: &[u64]) -> Vec<Counting> {
136 xs.iter().map(|&x| Counting::from_u64(x)).collect()
137 }
138
139 #[test]
140 fn identity_matvec_returns_input() {
141 let v = vec_u64(&[3, 5, 7]);
142 assert_eq!(IdentityView { n: 3 }.matvec(&v).unwrap(), v);
143 }
144
145 #[test]
146 fn diagonal_matvec_scales() {
147 let d = DiagonalView {
148 diag: vec_u64(&[2, 3]),
149 };
150 assert_eq!(d.matvec(&vec_u64(&[5, 7])).unwrap(), vec_u64(&[10, 21]));
151 }
152
153 #[test]
154 fn permutation_matvec_permutes() {
155 let p = PermutationView {
157 perm: vec![2, 0, 1],
158 };
159 assert_eq!(p.matvec(&vec_u64(&[1, 2, 3])).unwrap(), vec_u64(&[3, 1, 2]));
160 }
161
162 #[test]
163 fn permutation_materialize_matches_matvec() {
164 let p = PermutationView {
165 perm: vec![2, 0, 1],
166 };
167 let m: Matrix<Counting> = p.materialize(AlgebraLimits::default()).unwrap();
168 let v = vec_u64(&[1, 2, 3]);
169 let dense_col = Matrix::from_rows(v.iter().map(|x| vec![x.clone()]).collect()).unwrap();
171 let prod = m.matmul(&dense_col).unwrap();
172 assert_eq!(prod.data, p.matvec(&v).unwrap());
173 }
174
175 #[test]
176 fn materialize_respects_limit() {
177 let id = IdentityView { n: 100 };
178 let limited = AlgebraLimits { max_dim: 10 };
179 assert!(matches!(
180 id.materialize::<Counting>(limited),
181 Err(AlgebraError::LimitExceeded(_))
182 ));
183 }
184}