sim_lib_discrete_algebra/
power.rs1use crate::error::AlgebraError;
5use crate::matrix::{AlgebraLimits, Matrix};
6use crate::semiring::Semiring;
7
8impl<S: Semiring> Matrix<S> {
9 pub fn power(&self, k: usize, limits: AlgebraLimits) -> Result<Self, AlgebraError> {
15 self.validate()?;
16 if !self.is_square() {
17 return Err(AlgebraError::ShapeMismatch(format!(
18 "power requires a square matrix, got {}x{}",
19 self.rows, self.cols
20 )));
21 }
22 if self.rows > limits.max_dim {
23 return Err(AlgebraError::LimitExceeded(format!(
24 "power: dimension {} exceeds max_dim {}",
25 self.rows, limits.max_dim
26 )));
27 }
28 let n = self.rows;
29 let mut result = Matrix::try_identity_with_limits(n, limits)?;
30 let mut base = self.clone();
31 let mut e = k;
32 while e > 0 {
33 if e & 1 == 1 {
34 result = result.matmul(&base)?;
35 }
36 e >>= 1;
37 if e > 0 {
38 base = base.matmul(&base)?;
39 }
40 }
41 Ok(result)
42 }
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48 use crate::Counting;
49
50 #[test]
51 fn power_zero_is_identity() {
52 let a = Matrix::from_rows(vec![
53 vec![Counting::from_u64(1), Counting::from_u64(1)],
54 vec![Counting::from_u64(0), Counting::from_u64(1)],
55 ])
56 .unwrap();
57 assert_eq!(
58 a.power(0, AlgebraLimits::default()).unwrap(),
59 Matrix::identity(2)
60 );
61 }
62
63 #[test]
64 fn power_counts_walks() {
65 let mut a = Matrix::new(3, 3);
67 a.set(0, 1, Counting::from_u64(1)).unwrap();
68 a.set(1, 2, Counting::from_u64(1)).unwrap();
69 a.set(2, 0, Counting::from_u64(1)).unwrap();
70 let a2 = a.power(2, AlgebraLimits::default()).unwrap();
71 assert_eq!(a2.get(0, 2).unwrap(), &Counting::from_u64(1));
73 assert_eq!(a2.get(0, 0).unwrap(), &Counting::from_u64(0));
74 let a3 = a.power(3, AlgebraLimits::default()).unwrap();
76 assert_eq!(a3.get(0, 0).unwrap(), &Counting::from_u64(1));
77 }
78
79 #[test]
80 fn power_non_square_fails() {
81 let a: Matrix<Counting> = Matrix::new(2, 3);
82 assert!(matches!(
83 a.power(2, AlgebraLimits::default()),
84 Err(AlgebraError::ShapeMismatch(_))
85 ));
86 }
87}