1use crate::solvers::SolversError as ExecutionError;
8use crate::solvers::{SolverConfig, SolverResult, SolverState};
9
10pub mod cholesky;
12pub mod eigen;
14pub mod gemm;
17pub mod lu;
19pub mod qr;
21pub mod spectral;
23pub mod svd;
25pub mod vector;
27
28#[repr(C)]
30#[derive(Clone, Copy)]
31pub struct Matrix4x4 {
32 pub data: [[f64; 4]; 4],
34}
35
36#[repr(C)]
38#[derive(Clone, Copy)]
39pub struct Vector4 {
40 pub data: [f64; 4],
42}
43
44#[repr(C)]
46#[derive(Clone, Copy)]
47pub struct Tensor3x3x3 {
48 pub data: [[[f64; 3]; 3]; 3],
50}
51
52#[repr(C)]
54pub struct FixedLanczosEigensolver {
55 pub iteration: u32,
57 pub alpha: [f64; 100],
59 pub beta: [f64; 100],
60 pub vectors: [Vector4; 3],
62 pub eigenvalues: [f64; 4],
64 pub config: SolverConfig,
66 pub solver_state: SolverState,
68}
69
70#[repr(C)]
72pub struct StaticLuDecomposition {
73 pub matrix: Matrix4x4,
75 pub permutation: [usize; 4],
77 pub parity: i32,
79 pub config: SolverConfig,
81 pub solver_state: SolverState,
83}
84
85#[repr(C)]
87pub struct ConstTensorContractor {
88 pub tensor_a: Tensor3x3x3,
90 pub tensor_b: Tensor3x3x3,
92 pub result: Tensor3x3x3,
94 pub contraction_indices: [(usize, usize); 3],
96 pub config: SolverConfig,
98 pub solver_state: SolverState,
100}
101
102impl Matrix4x4 {
103 pub const fn zero() -> Self {
105 Self {
106 data: [[0.0; 4]; 4],
107 }
108 }
109
110 pub const fn identity() -> Self {
112 Self {
113 data: [
114 [1.0, 0.0, 0.0, 0.0],
115 [0.0, 1.0, 0.0, 0.0],
116 [0.0, 0.0, 1.0, 0.0],
117 [0.0, 0.0, 0.0, 1.0],
118 ],
119 }
120 }
121
122 pub fn get(&self, i: usize, j: usize) -> f64 {
124 self.data[i][j]
125 }
126
127 pub fn set(&mut self, i: usize, j: usize, value: f64) {
129 self.data[i][j] = value;
130 }
131
132 pub fn multiply_vector(&self, v: &Vector4) -> Vector4 {
134 let mut result = Vector4::zero();
135
136 for i in 0..4 {
137 let mut sum = 0.0;
138 for j in 0..4 {
139 sum += self.data[i][j] * v.data[j];
140 }
141 result.data[i] = sum;
142 }
143
144 result
145 }
146
147 pub fn multiply_matrix(&self, other: &Matrix4x4) -> Matrix4x4 {
149 let mut result = Matrix4x4::zero();
150
151 for i in 0..4 {
152 for j in 0..4 {
153 let mut sum = 0.0;
154 for k in 0..4 {
155 sum += self.data[i][k] * other.data[k][j];
156 }
157 result.data[i][j] = sum;
158 }
159 }
160
161 result
162 }
163
164 pub fn transpose(&self) -> Matrix4x4 {
166 let mut result = Matrix4x4::zero();
167
168 for i in 0..4 {
169 for j in 0..4 {
170 result.data[i][j] = self.data[j][i];
171 }
172 }
173
174 result
175 }
176
177 pub fn determinant(&self) -> f64 {
179 let mut det = 0.0;
181
182 for i in 0..4 {
183 let sign = if i % 2 == 0 { 1.0 } else { -1.0 };
184 let minor = self.minor(0, i);
185 det += sign * self.data[0][i] * minor.determinant_3x3();
186 }
187
188 det
189 }
190
191 fn minor(&self, row: usize, col: usize) -> Matrix4x4 {
193 let mut result = Matrix4x4::zero();
194 let mut r = 0;
195
196 for i in 0..4 {
197 if i == row {
198 continue;
199 }
200 let mut c = 0;
201 for j in 0..4 {
202 if j == col {
203 continue;
204 }
205 result.data[r][c] = self.data[i][j];
206 c += 1;
207 }
208 r += 1;
209 }
210
211 result
212 }
213
214 fn determinant_3x3(&self) -> f64 {
216 self.data[0][0] * (self.data[1][1] * self.data[2][2] - self.data[1][2] * self.data[2][1])
217 - self.data[0][1]
218 * (self.data[1][0] * self.data[2][2] - self.data[1][2] * self.data[2][0])
219 + self.data[0][2]
220 * (self.data[1][0] * self.data[2][1] - self.data[1][1] * self.data[2][0])
221 }
222}
223
224impl Vector4 {
225 pub const fn zero() -> Self {
227 Self { data: [0.0; 4] }
228 }
229
230 pub const fn from_array(data: [f64; 4]) -> Self {
232 Self { data }
233 }
234
235 pub fn get(&self, i: usize) -> f64 {
237 self.data[i]
238 }
239
240 pub fn set(&mut self, i: usize, value: f64) {
242 self.data[i] = value;
243 }
244
245 pub fn dot(&self, other: &Vector4) -> f64 {
247 let mut sum = 0.0;
248 for i in 0..4 {
249 sum += self.data[i] * other.data[i];
250 }
251 sum
252 }
253
254 pub fn norm(&self) -> f64 {
256 self.dot(self).sqrt()
257 }
258
259 pub fn normalize(&self) -> Vector4 {
261 let norm = self.norm();
262 if norm > 1e-10 {
263 Vector4::from_array([
264 self.data[0] / norm,
265 self.data[1] / norm,
266 self.data[2] / norm,
267 self.data[3] / norm,
268 ])
269 } else {
270 *self
271 }
272 }
273
274 pub fn add(&self, other: &Vector4) -> Vector4 {
276 Vector4::from_array([
277 self.data[0] + other.data[0],
278 self.data[1] + other.data[1],
279 self.data[2] + other.data[2],
280 self.data[3] + other.data[3],
281 ])
282 }
283
284 pub fn subtract(&self, other: &Vector4) -> Vector4 {
286 Vector4::from_array([
287 self.data[0] - other.data[0],
288 self.data[1] - other.data[1],
289 self.data[2] - other.data[2],
290 self.data[3] - other.data[3],
291 ])
292 }
293
294 pub fn scale(&self, scalar: f64) -> Vector4 {
296 Vector4::from_array([
297 self.data[0] * scalar,
298 self.data[1] * scalar,
299 self.data[2] * scalar,
300 self.data[3] * scalar,
301 ])
302 }
303}
304
305impl Tensor3x3x3 {
306 pub const fn zero() -> Self {
308 Self {
309 data: [[[0.0; 3]; 3]; 3],
310 }
311 }
312
313 pub fn get(&self, i: usize, j: usize, k: usize) -> f64 {
315 self.data[i][j][k]
316 }
317
318 pub fn set(&mut self, i: usize, j: usize, k: usize, value: f64) {
320 self.data[i][j][k] = value;
321 }
322
323 pub fn contract(&self, other: &Tensor3x3x3, indices: &[(usize, usize); 3]) -> Tensor3x3x3 {
325 let mut result = Tensor3x3x3::zero();
326
327 for i in 0..3 {
329 for j in 0..3 {
330 for k in 0..3 {
331 let mut sum = 0.0;
332 for (idx_a, idx_b) in indices {
333 sum += self.get(i, j, *idx_a) * other.get(*idx_b, j, k);
334 }
335 result.set(i, j, k, sum);
336 }
337 }
338 }
339
340 result
341 }
342}
343
344impl FixedLanczosEigensolver {
345 pub fn new(config: SolverConfig) -> Self {
347 Self {
348 iteration: 0,
349 alpha: [0.0; 100],
350 beta: [0.0; 100],
351 vectors: [Vector4::zero(); 3],
352 eigenvalues: [0.0; 4],
353 config,
354 solver_state: SolverState::default(),
355 }
356 }
357
358 pub fn find_lowest_eigenvalues(
360 &mut self,
361 matrix: &Matrix4x4,
362 num_eigenvalues: usize,
363 ) -> SolverResult<[f64; 4]> {
364 self.iteration = 0;
365 self.solver_state.converged = false;
366
367 self.vectors[0] = Vector4::from_array([1.0, 0.0, 0.0, 0.0]);
369 self.vectors[0] = self.vectors[0].normalize();
370
371 while self.iteration < self.config.max_iterations.min(100) {
373 let w = matrix.multiply_vector(&self.vectors[0]);
375
376 let alpha_i = self.vectors[0].dot(&w);
378 self.alpha[self.iteration as usize] = alpha_i;
379
380 let mut w_new = w.subtract(&self.vectors[0].scale(alpha_i));
382 if self.iteration > 0 {
383 w_new = w_new
384 .subtract(&self.vectors[1].scale(self.beta[(self.iteration - 1) as usize]));
385 }
386
387 let beta_i = w_new.norm();
389 self.beta[self.iteration as usize] = beta_i;
390
391 self.iteration += 1;
393
394 if beta_i < self.config.tolerance {
395 self.solver_state.converged = true;
396 break;
397 }
398
399 self.vectors[2] = self.vectors[1];
401 self.vectors[1] = self.vectors[0];
402 self.vectors[0] = w_new.normalize();
403 }
404
405 self.extract_eigenvalues_from_tridiagonal(num_eigenvalues)?;
407
408 Ok(self.eigenvalues)
409 }
410
411 fn extract_eigenvalues_from_tridiagonal(&mut self, num_eigenvalues: usize) -> SolverResult<()> {
413 let n = self.iteration as usize;
414 if n == 0 {
415 return Err(ExecutionError::InvalidParameters);
416 }
417 if n > 100 {
418 return Err(ExecutionError::InvalidDimension);
419 }
420
421 let mut tridiag = [0.0; 100 * 100];
423 for i in 0..n {
424 tridiag[i * n + i] = self.alpha[i];
425 if i < n - 1 {
426 tridiag[i * n + i + 1] = self.beta[i];
427 tridiag[(i + 1) * n + i] = self.beta[i];
428 }
429 }
430
431 let mut eigvecs = [0.0; 100 * 100];
432
433 crate::solvers::linear_algebra::eigen::symmetric_eigen(
435 n,
436 &mut tridiag[..n * n],
437 &mut eigvecs[..n * n],
438 )?;
439
440 let mut eigs = [0.0; 100];
442 for i in 0..n {
443 eigs[i] = tridiag[i * n + i];
444 }
445
446 eigs[..n].sort_by(|a, b| a.partial_cmp(b).unwrap_or(core::cmp::Ordering::Equal));
448
449 for i in 0..num_eigenvalues.min(4).min(n) {
450 self.eigenvalues[i] = eigs[i];
451 }
452
453 Ok(())
454 }
455}
456
457impl StaticLuDecomposition {
458 pub fn new(config: SolverConfig) -> Self {
460 Self {
461 matrix: Matrix4x4::zero(),
462 permutation: [0, 1, 2, 3],
463 parity: 1,
464 config,
465 solver_state: SolverState::default(),
466 }
467 }
468
469 pub fn solve(&mut self, matrix: &Matrix4x4, b: &Vector4) -> SolverResult<Vector4> {
471 self.matrix = *matrix;
473
474 self.lu_decompose()?;
476
477 self.solve_lu(b)
479 }
480
481 fn lu_decompose(&mut self) -> SolverResult<()> {
483 self.parity = 1;
484
485 for i in 0..4 {
486 let pivot_row = self.find_pivot(i)?;
488
489 if pivot_row != i {
491 self.swap_rows(i, pivot_row);
492 self.parity = -self.parity;
493 }
494
495 for j in i + 1..4 {
497 let multiplier = self.matrix.data[j][i] / self.matrix.data[i][i];
498 self.matrix.data[j][i] = multiplier;
499
500 for k in i + 1..4 {
501 self.matrix.data[j][k] -= multiplier * self.matrix.data[i][k];
502 }
503 }
504 }
505
506 Ok(())
507 }
508
509 fn find_pivot(&self, col: usize) -> SolverResult<usize> {
511 let mut max_row = col;
512 let mut max_val = self.matrix.data[col][col].abs();
513
514 for i in col + 1..4 {
515 let val = self.matrix.data[i][col].abs();
516 if val > max_val {
517 max_val = val;
518 max_row = i;
519 }
520 }
521
522 if max_val < 1e-10 {
523 return Err(ExecutionError::SingularMatrix);
524 }
525
526 Ok(max_row)
527 }
528
529 fn swap_rows(&mut self, i: usize, j: usize) {
531 for k in 0..4 {
532 let temp = self.matrix.data[i][k];
533 self.matrix.data[i][k] = self.matrix.data[j][k];
534 self.matrix.data[j][k] = temp;
535 }
536
537 self.permutation.swap(i, j);
539 }
540
541 fn solve_lu(&self, b: &Vector4) -> SolverResult<Vector4> {
543 let mut x = *b;
544
545 for i in 0..4 {
547 let mut sum = 0.0;
548 for j in 0..i {
549 sum += self.matrix.data[i][j] * x.data[j];
550 }
551 x.data[i] -= sum;
552 }
553
554 for i in (0..4).rev() {
556 let mut sum = 0.0;
557 for j in i + 1..4 {
558 sum += self.matrix.data[i][j] * x.data[j];
559 }
560 x.data[i] = (x.data[i] - sum) / self.matrix.data[i][i];
561 }
562
563 Ok(x)
564 }
565
566 pub fn determinant(&self) -> f64 {
568 let mut det = 1.0;
569 for i in 0..4 {
570 det *= self.matrix.data[i][i];
571 }
572 det * self.parity as f64
573 }
574}
575
576impl ConstTensorContractor {
577 pub fn new(config: SolverConfig) -> Self {
579 Self {
580 tensor_a: Tensor3x3x3::zero(),
581 tensor_b: Tensor3x3x3::zero(),
582 result: Tensor3x3x3::zero(),
583 contraction_indices: [(0, 0), (1, 1), (2, 2)],
584 config,
585 solver_state: SolverState::default(),
586 }
587 }
588
589 pub fn contract(
591 &mut self,
592 tensor_a: &Tensor3x3x3,
593 tensor_b: &Tensor3x3x3,
594 indices: &[(usize, usize); 3],
595 ) -> SolverResult<Tensor3x3x3> {
596 self.tensor_a = *tensor_a;
597 self.tensor_b = *tensor_b;
598 self.contraction_indices = *indices;
599
600 self.result = self
602 .tensor_a
603 .contract(&self.tensor_b, &self.contraction_indices);
604
605 self.solver_state.converged = true;
606
607 Ok(self.result)
608 }
609
610 pub fn get_result(&self) -> Tensor3x3x3 {
612 self.result
613 }
614}
615
616impl Default for Matrix4x4 {
617 fn default() -> Self {
618 Self::identity()
619 }
620}
621
622impl Default for Vector4 {
623 fn default() -> Self {
624 Self::zero()
625 }
626}
627
628impl Default for Tensor3x3x3 {
629 fn default() -> Self {
630 Self::zero()
631 }
632}
633
634impl Default for FixedLanczosEigensolver {
635 fn default() -> Self {
636 Self::new(SolverConfig::default())
637 }
638}
639
640impl Default for StaticLuDecomposition {
641 fn default() -> Self {
642 Self::new(SolverConfig::default())
643 }
644}
645
646impl Default for ConstTensorContractor {
647 fn default() -> Self {
648 Self::new(SolverConfig::default())
649 }
650}
651
652#[cfg(test)]
653mod tests {
654 use super::*;
655
656 #[test]
657 fn test_matrix4x4_operations() {
658 let mut m = Matrix4x4::identity();
659 m.set(0, 1, 2.0);
660 m.set(1, 0, 3.0);
661
662 let v = Vector4::from_array([1.0, 2.0, 3.0, 4.0]);
663 let result = m.multiply_vector(&v);
664
665 assert_eq!(result.data[0], 1.0 + 2.0 * 2.0); assert_eq!(result.data[1], 3.0 * 1.0 + 2.0); }
668
669 #[test]
670 fn test_vector_operations() {
671 let v1 = Vector4::from_array([1.0, 2.0, 3.0, 4.0]);
672 let v2 = Vector4::from_array([2.0, 3.0, 4.0, 5.0]);
673
674 let dot = v1.dot(&v2);
675 assert_eq!(dot, 1.0 * 2.0 + 2.0 * 3.0 + 3.0 * 4.0 + 4.0 * 5.0);
676
677 let norm = v1.norm();
678 assert!((norm - (1.0_f64 * 1.0 + 2.0 * 2.0 + 3.0 * 3.0 + 4.0 * 4.0).sqrt()).abs() < 1e-10);
679 }
680
681 #[test]
682 fn test_lu_decomposition() {
683 let mut lu = StaticLuDecomposition::new(SolverConfig::default());
684
685 let mut m = Matrix4x4::identity();
687 m.set(0, 0, 2.0);
688 m.set(0, 1, 1.0);
689 m.set(1, 0, 1.0);
690 m.set(1, 1, 2.0);
691
692 let b = Vector4::from_array([3.0, 3.0, 0.0, 0.0]);
693 let result = lu.solve(&m, &b);
694
695 assert!(result.is_ok());
696 let x = result.unwrap();
697 assert!((x.data[0] - 1.0).abs() < 1e-10);
698 assert!((x.data[1] - 1.0).abs() < 1e-10);
699 }
700
701 #[test]
702 fn test_tensor_contraction() {
703 let mut contractor = ConstTensorContractor::new(SolverConfig::default());
704
705 let mut tensor_a = Tensor3x3x3::zero();
706 let mut tensor_b = Tensor3x3x3::zero();
707
708 tensor_a.set(0, 0, 0, 1.0);
710 tensor_a.set(1, 1, 1, 2.0);
711 tensor_b.set(0, 0, 0, 3.0);
712 tensor_b.set(1, 1, 1, 4.0);
713
714 let indices = [(0, 0), (1, 1), (2, 2)];
715 let result = contractor.contract(&tensor_a, &tensor_b, &indices);
716
717 assert!(result.is_ok());
718 }
719
720 #[test]
721 fn test_zero_allocation_guarantee() {
722 }
729}