1pub mod computation;
9pub mod core_types;
10pub mod optimization;
11pub mod performance;
12pub mod privacy;
13pub mod storage;
14
15pub use computation::*;
16pub use core_types::*;
17pub use optimization::*;
18pub use performance::*;
19pub use privacy::*;
20pub use storage::*;
21
22#[cfg(test)]
23mod tests {
24 use super::*;
25
26 #[test]
27 fn test_linear_algebra_library_creation() {
28 let library = LinearAlgebraLibrary::new();
29 assert_eq!(library.list_matrices().len(), 0);
30 }
31
32 #[test]
33 fn test_matrix_creation() {
34 let mut library = LinearAlgebraLibrary::new();
35 library.initialize().unwrap();
36
37 let data = vec![1.0, 2.0, 3.0, 4.0];
38 let matrix = library
39 .create_matrix("test_matrix".to_string(), 2, 2, DataType::Float64, data)
40 .unwrap();
41
42 assert_eq!(matrix.rows, 2);
43 assert_eq!(matrix.cols, 2);
44 assert_eq!(matrix.data.len(), 4);
45 }
46
47 #[test]
48 fn test_matrix_multiplication() {
49 let mut library = LinearAlgebraLibrary::new();
50 library.initialize().unwrap();
51
52 let a_data = vec![1.0, 2.0, 3.0, 4.0];
53 let b_data = vec![5.0, 6.0, 7.0, 8.0];
54
55 library
56 .create_matrix("A".to_string(), 2, 2, DataType::Float64, a_data)
57 .unwrap();
58 library
59 .create_matrix("B".to_string(), 2, 2, DataType::Float64, b_data)
60 .unwrap();
61
62 let result = library.matrix_multiply("A", "B", "C", 1.0, 0.0).unwrap();
63
64 assert_eq!(result.result.rows, 2);
65 assert_eq!(result.result.cols, 2);
66 assert_eq!(result.result.data[0], 19.0); assert_eq!(result.result.data[1], 22.0); assert_eq!(result.result.data[2], 43.0); assert_eq!(result.result.data[3], 50.0); }
71
72 #[test]
73 fn test_matrix_transpose() {
74 let mut library = LinearAlgebraLibrary::new();
75 library.initialize().unwrap();
76
77 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0];
78 library
79 .create_matrix("A".to_string(), 2, 3, DataType::Float64, data)
80 .unwrap();
81
82 let result = library.matrix_transpose("A", "AT").unwrap();
83
84 assert_eq!(result.result.rows, 3);
85 assert_eq!(result.result.cols, 2);
86 assert_eq!(result.result.data[0], 1.0);
87 assert_eq!(result.result.data[1], 4.0);
88 assert_eq!(result.result.data[2], 2.0);
89 assert_eq!(result.result.data[3], 5.0);
90 assert_eq!(result.result.data[4], 3.0);
91 assert_eq!(result.result.data[5], 6.0);
92 }
93
94 #[test]
95 fn test_matrix_inverse() {
96 let mut library = LinearAlgebraLibrary::new();
97 library.initialize().unwrap();
98
99 let data = vec![2.0, 1.0, 1.0, 1.0]; library
101 .create_matrix("A".to_string(), 2, 2, DataType::Float64, data)
102 .unwrap();
103
104 let result = library.matrix_inverse("A", "A_inv").unwrap();
105
106 assert_eq!(result.result.rows, 2);
107 assert_eq!(result.result.cols, 2);
108 assert!((result.result.data[0] - 1.0).abs() < 1e-10);
110 assert!((result.result.data[1] + 1.0).abs() < 1e-10);
111 assert!((result.result.data[2] + 1.0).abs() < 1e-10);
112 assert!((result.result.data[3] - 2.0).abs() < 1e-10);
113 }
114
115 #[test]
116 fn test_solve_linear_system() {
117 let mut library = LinearAlgebraLibrary::new();
118 library.initialize().unwrap();
119
120 let matrix_data = vec![2.0, 1.0, 1.0, 1.0]; let rhs_data = vec![3.0, 2.0]; library
124 .create_matrix("A".to_string(), 2, 2, DataType::Float64, matrix_data)
125 .unwrap();
126 library
127 .create_matrix("b".to_string(), 2, 1, DataType::Float64, rhs_data)
128 .unwrap();
129
130 let result = library.solve_linear_system("A", "b", "x").unwrap();
131
132 assert_eq!(result.result.rows, 2);
133 assert_eq!(result.result.cols, 1);
134 assert!((result.result.data[0] - 1.0).abs() < 1e-10);
136 assert!((result.result.data[1] - 1.0).abs() < 1e-10);
137 }
138
139 #[test]
140 fn test_solve_quadratic_two_real() {
141 match solve_quadratic(1.0, -5.0, 6.0).unwrap() {
143 QuadraticRoots::TwoReal(lo, hi) => {
144 assert!((lo - 2.0).abs() < 1e-12);
145 assert!((hi - 3.0).abs() < 1e-12);
146 }
147 other => panic!("expected two real roots, got {:?}", other),
148 }
149 }
150
151 #[test]
152 fn test_solve_quadratic_double_and_complex_and_linear() {
153 assert_eq!(
155 solve_quadratic(1.0, -2.0, 1.0).unwrap(),
156 QuadraticRoots::DoubleReal(1.0)
157 );
158 match solve_quadratic(1.0, 0.0, 1.0).unwrap() {
160 QuadraticRoots::ComplexPair { re, im } => {
161 assert!(re.abs() < 1e-12 && (im - 1.0).abs() < 1e-12);
162 }
163 other => panic!("expected complex pair, got {:?}", other),
164 }
165 assert_eq!(
167 solve_quadratic(0.0, 2.0, -4.0).unwrap(),
168 QuadraticRoots::Linear(2.0)
169 );
170 }
171
172 #[test]
173 fn test_polynomial_roots_general() {
174 let mut roots = polynomial_roots(&[1.0, -6.0, 11.0, -6.0]).unwrap();
176 assert_eq!(roots.len(), 3);
177 assert!(roots.iter().all(|r| r.is_real(1e-7)));
178 roots.sort_by(|a, b| a.re.partial_cmp(&b.re).unwrap());
179 for (got, want) in roots.iter().zip([1.0, 2.0, 3.0]) {
180 assert!((got.re - want).abs() < 1e-6, "root {:?} != {}", got, want);
181 }
182 }
183
184 #[test]
185 fn test_polynomial_roots_complex_quartic() {
186 let roots = polynomial_roots(&[1.0, 0.0, 0.0, 0.0, -1.0]).unwrap();
188 assert_eq!(roots.len(), 4);
189 let real_count = roots.iter().filter(|r| r.is_real(1e-7)).count();
190 let imag_count = roots.iter().filter(|r| !r.is_real(1e-7)).count();
191 assert_eq!(real_count, 2, "expected ±1 real");
192 assert_eq!(imag_count, 2, "expected ±i imaginary");
193 assert!(roots.iter().all(|r| (r.abs() - 1.0).abs() < 1e-6));
195 }
196
197 #[test]
198 fn test_determinant() {
199 assert!((determinant(2, &[1.0, 2.0, 3.0, 4.0]).unwrap() + 2.0).abs() < 1e-12);
201 let d = determinant(3, &[6.0, 1.0, 1.0, 4.0, -2.0, 5.0, 2.0, 8.0, 7.0]).unwrap();
203 assert!((d + 306.0).abs() < 1e-9, "det = {}", d);
204 assert!(determinant(2, &[1.0, 2.0, 2.0, 4.0]).unwrap().abs() < 1e-12);
206 }
207
208 #[test]
209 fn test_eigen_symmetric() {
210 let a = [2.0, 1.0, 1.0, 2.0];
212 let (mut vals, vecs) = eigen_symmetric(2, &a).unwrap();
213 vals.sort_by(|x, y| x.partial_cmp(y).unwrap());
214 assert!(
215 (vals[0] - 1.0).abs() < 1e-9 && (vals[1] - 3.0).abs() < 1e-9,
216 "vals = {:?}",
217 vals
218 );
219
220 let (vals_u, vecs_u) = eigen_symmetric(2, &a).unwrap();
222 for j in 0..2 {
223 let (v0, v1) = (vecs_u[0 * 2 + j], vecs_u[1 * 2 + j]);
224 let av0 = a[0] * v0 + a[1] * v1;
226 let av1 = a[2] * v0 + a[3] * v1;
227 assert!(
229 (av0 - vals_u[j] * v0).abs() < 1e-7,
230 "A·v != λ·v (row0, col{j})"
231 );
232 assert!(
233 (av1 - vals_u[j] * v1).abs() < 1e-7,
234 "A·v != λ·v (row1, col{j})"
235 );
236 assert!(((v0 * v0 + v1 * v1).sqrt() - 1.0).abs() < 1e-9);
238 }
239 let _ = vecs;
240 }
241
242 #[test]
243 fn test_eigen_symmetric_rejects_asymmetric() {
244 assert!(eigen_symmetric(2, &[1.0, 2.0, 3.0, 4.0]).is_err());
245 }
246
247 #[test]
248 fn test_lu_decompose_reconstructs_and_dets() {
249 let n = 3;
251 let a = [4.0, 3.0, 2.0, 2.0, 1.0, 3.0, 3.0, 2.0, 1.0];
252 let lu = lu_decompose(n, &a).unwrap();
253 assert!(!lu.singular);
254 assert!((lu.determinant() - determinant(n, &a).unwrap()).abs() < 1e-9);
256
257 let mut l = vec![0.0; n * n];
259 let mut u = vec![0.0; n * n];
260 for i in 0..n {
261 l[i * n + i] = 1.0;
262 for j in 0..n {
263 if j < i {
264 l[i * n + j] = lu.lu[i * n + j];
265 } else {
266 u[i * n + j] = lu.lu[i * n + j];
267 }
268 }
269 }
270 for i in 0..n {
271 for j in 0..n {
272 let mut acc = 0.0;
273 for k in 0..n {
274 acc += l[i * n + k] * u[k * n + j];
275 }
276 let orig_row = lu.pivots[i];
278 assert!(
279 (acc - a[orig_row * n + j]).abs() < 1e-9,
280 "LU != P·A at {i},{j}"
281 );
282 }
283 }
284
285 let sing = lu_decompose(2, &[1.0, 2.0, 2.0, 4.0]).unwrap();
287 assert!(sing.singular && sing.determinant() == 0.0);
288 }
289
290 #[test]
291 fn test_eigenvalues_general() {
292 let mut e = eigenvalues_general(2, &[1.0, 2.0, 0.0, 3.0]).unwrap();
294 e.sort_by(|a, b| a.re.partial_cmp(&b.re).unwrap());
295 assert!(e.iter().all(|z| z.is_real(1e-7)));
296 assert!((e[0].re - 1.0).abs() < 1e-6 && (e[1].re - 3.0).abs() < 1e-6);
297
298 let r = eigenvalues_general(2, &[0.0, -1.0, 1.0, 0.0]).unwrap();
300 assert_eq!(r.len(), 2);
301 assert!(r
302 .iter()
303 .all(|z| z.re.abs() < 1e-6 && (z.im.abs() - 1.0).abs() < 1e-6));
304 }
305
306 #[test]
307 fn test_characteristic_polynomial_determinant_link() {
308 let c = characteristic_polynomial(2, &[1.0, 2.0, 3.0, 4.0]).unwrap();
310 assert_eq!(c.len(), 3); assert!((c[1] + 5.0).abs() < 1e-12); let det_from_poly = c[2]; assert!((det_from_poly - determinant(2, &[1.0, 2.0, 3.0, 4.0]).unwrap()).abs() < 1e-9);
314 }
315
316 #[test]
317 fn test_svd_reconstruction() {
318 let m = 3;
320 let n = 2;
321 let a = vec![1.0, 0.0, 0.0, 1.0, 1.0, 1.0];
322 let decomp = svd(m, n, &a).unwrap();
323
324 assert_eq!(decomp.singular_values.len(), n);
325 assert!(decomp.singular_values[0] >= decomp.singular_values[1] - 1e-12);
326 assert!(decomp.singular_values.iter().all(|&s| s >= -1e-12));
327
328 for i in 0..m {
329 for j in 0..n {
330 let mut recon = 0.0;
331 for k in 0..n {
332 recon += decomp.u[i * n + k] * decomp.singular_values[k] * decomp.v[j * n + k];
333 }
334 assert!(
335 (recon - a[i * n + j]).abs() < 1e-9,
336 "reconstruction[{i}][{j}] = {recon} != {}",
337 a[i * n + j]
338 );
339 }
340 }
341 }
342
343 #[test]
344 fn test_private_matrix_multiplication() {
345 let mut library = LinearAlgebraLibrary::new();
346 library.initialize().unwrap();
347
348 let a_data = vec![1.0, 2.0, 3.0, 4.0];
349 let b_data = vec![5.0, 6.0, 7.0, 8.0];
350
351 library
352 .create_matrix("A".to_string(), 2, 2, DataType::Float64, a_data)
353 .unwrap();
354 library
355 .create_matrix("B".to_string(), 2, 2, DataType::Float64, b_data)
356 .unwrap();
357
358 let result = library.private_matrix_multiply("A", "B", "C").unwrap();
359
360 assert!(
361 result.privacy_preserved,
362 "the Groth16 proof of A·B = C must verify"
363 );
364 assert_eq!(result.result.rows, 2);
365 assert_eq!(result.result.cols, 2);
366 assert_eq!(result.result.data, vec![19.0, 22.0, 43.0, 50.0]);
369 }
370
371 #[test]
372 fn test_private_matrix_multiplication_rectangular() {
373 let mut library = LinearAlgebraLibrary::new();
376 library.initialize().unwrap();
377 library
378 .create_matrix(
379 "A".to_string(),
380 2,
381 3,
382 DataType::Float64,
383 vec![1.0, 2.0, 3.0, 4.0, -5.0, 6.0],
384 )
385 .unwrap();
386 library
387 .create_matrix(
388 "B".to_string(),
389 3,
390 2,
391 DataType::Float64,
392 vec![7.0, 8.0, 9.0, 10.0, 11.0, 12.0],
393 )
394 .unwrap();
395
396 let result = library.private_matrix_multiply("A", "B", "C").unwrap();
397
398 assert!(result.privacy_preserved);
399 for (got, want) in result.result.data.iter().zip([58.0, 64.0, 49.0, 54.0]) {
402 assert!((got - want).abs() < 1e-4);
403 }
404 }
405
406 #[test]
407 fn test_private_matrix_multiplication_fractional() {
408 let mut library = LinearAlgebraLibrary::new();
411 library.initialize().unwrap();
412 library
413 .create_matrix(
414 "A".to_string(),
415 2,
416 2,
417 DataType::Float64,
418 vec![0.5, 1.5, 2.5, 0.5],
419 )
420 .unwrap();
421 library
422 .create_matrix(
423 "B".to_string(),
424 2,
425 2,
426 DataType::Float64,
427 vec![1.0, 0.0, 0.0, 2.0],
428 )
429 .unwrap();
430
431 let result = library.private_matrix_multiply("A", "B", "C").unwrap();
432 assert!(result.privacy_preserved);
433 for (got, want) in result.result.data.iter().zip([0.5, 3.0, 2.5, 1.0]) {
434 assert!(
435 (got - want).abs() < 1e-4,
436 "fixed-point ZK result {got} != {want}"
437 );
438 }
439 }
440
441 #[test]
444 fn test_multiply_uses_cache_and_records_metrics() {
445 let mut library = LinearAlgebraLibrary::new();
446 library.initialize().unwrap();
447
448 let a_data = vec![1.0, 2.0, 3.0, 4.0];
449 let b_data = vec![5.0, 6.0, 7.0, 8.0];
450
451 library
452 .create_matrix("A".to_string(), 2, 2, DataType::Float64, a_data)
453 .unwrap();
454 library
455 .create_matrix("B".to_string(), 2, 2, DataType::Float64, b_data)
456 .unwrap();
457
458 let result1 = library.matrix_multiply("A", "B", "C", 1.0, 0.0).unwrap();
460 assert_eq!(result1.result.data, vec![19.0, 22.0, 43.0, 50.0]);
461
462 let stats = library.get_performance_stats();
464 assert!(stats.total_operations > 0);
465
466 let op_metrics = library
468 .performance_monitor
469 .get_operation_metrics("matrix_multiply");
470 assert!(op_metrics.is_some());
471 assert!(op_metrics.unwrap().count > 0);
472
473 let m_metrics = library.performance_monitor.get_matrix_metrics("A");
475 assert!(m_metrics.is_some());
476 assert!(m_metrics.unwrap().access_count > 0);
477 }
478
479 #[test]
480 fn test_cache_populated_after_operation() {
481 let mut library = LinearAlgebraLibrary::new();
482 library.initialize().unwrap();
483
484 library
485 .create_matrix(
486 "A".to_string(),
487 2,
488 2,
489 DataType::Float64,
490 vec![1.0, 2.0, 3.0, 4.0],
491 )
492 .unwrap();
493 library
494 .create_matrix(
495 "B".to_string(),
496 2,
497 2,
498 DataType::Float64,
499 vec![5.0, 6.0, 7.0, 8.0],
500 )
501 .unwrap();
502
503 library.matrix_multiply("A", "B", "C", 1.0, 0.0).unwrap();
505
506 assert!(library.matrix_storage.cache.cache_size() > 0);
508 }
509
510 #[test]
511 fn test_analyze_matrix_method() {
512 let mut library = LinearAlgebraLibrary::new();
513 library.initialize().unwrap();
514
515 library
517 .create_matrix(
518 "S".to_string(),
519 2,
520 2,
521 DataType::Float64,
522 vec![2.0, 1.0, 1.0, 2.0],
523 )
524 .unwrap();
525
526 let analysis = library.analyze_matrix("S").unwrap();
527 assert_eq!(analysis.matrix_id, "S");
528 assert!(analysis
529 .detected_patterns
530 .contains(&MatrixPattern::Symmetric));
531 assert!(analysis
532 .detected_patterns
533 .contains(&MatrixPattern::PositiveDefinite));
534 assert!(!analysis.recommended_algorithms.is_empty());
535 }
536
537 #[test]
538 fn test_analyze_diagonal_matrix() {
539 let mut library = LinearAlgebraLibrary::new();
540 library.initialize().unwrap();
541
542 library
543 .create_matrix(
544 "D".to_string(),
545 3,
546 3,
547 DataType::Float64,
548 vec![1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0],
549 )
550 .unwrap();
551
552 let analysis = library.analyze_matrix("D").unwrap();
553 assert!(analysis
554 .detected_patterns
555 .contains(&MatrixPattern::Diagonal));
556 }
557
558 #[test]
559 fn test_performance_summary() {
560 let mut library = LinearAlgebraLibrary::new();
561 library.initialize().unwrap();
562
563 library
564 .create_matrix(
565 "A".to_string(),
566 2,
567 2,
568 DataType::Float64,
569 vec![1.0, 2.0, 3.0, 4.0],
570 )
571 .unwrap();
572 library
573 .create_matrix(
574 "B".to_string(),
575 2,
576 2,
577 DataType::Float64,
578 vec![5.0, 6.0, 7.0, 8.0],
579 )
580 .unwrap();
581 library.matrix_multiply("A", "B", "C", 1.0, 0.0).unwrap();
582
583 let summary = library.performance_summary();
584 assert!(summary.contains("Linear Algebra Performance Summary"));
585 assert!(summary.contains("matrix_multiply"));
586 }
587
588 #[test]
589 fn test_cache_hit_rate_accessor() {
590 let mut library = LinearAlgebraLibrary::new();
591 library.initialize().unwrap();
592
593 assert_eq!(library.cache_hit_rate(), 0.0);
595
596 library
597 .create_matrix(
598 "A".to_string(),
599 2,
600 2,
601 DataType::Float64,
602 vec![1.0, 2.0, 3.0, 4.0],
603 )
604 .unwrap();
605 library
606 .create_matrix(
607 "B".to_string(),
608 2,
609 2,
610 DataType::Float64,
611 vec![5.0, 6.0, 7.0, 8.0],
612 )
613 .unwrap();
614 library.matrix_multiply("A", "B", "C", 1.0, 0.0).unwrap();
615
616 assert!(library.cache_size() > 0);
618 }
619
620 #[test]
621 fn test_transpose_records_metrics() {
622 let mut library = LinearAlgebraLibrary::new();
623 library.initialize().unwrap();
624
625 library
626 .create_matrix(
627 "A".to_string(),
628 2,
629 3,
630 DataType::Float64,
631 vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0],
632 )
633 .unwrap();
634
635 library.matrix_transpose("A", "AT").unwrap();
636
637 let op_metrics = library
638 .performance_monitor
639 .get_operation_metrics("matrix_transpose");
640 assert!(op_metrics.is_some());
641 assert!(op_metrics.unwrap().count > 0);
642 }
643
644 #[test]
645 fn test_inverse_records_metrics() {
646 let mut library = LinearAlgebraLibrary::new();
647 library.initialize().unwrap();
648
649 library
650 .create_matrix(
651 "A".to_string(),
652 2,
653 2,
654 DataType::Float64,
655 vec![2.0, 1.0, 1.0, 1.0],
656 )
657 .unwrap();
658
659 library.matrix_inverse("A", "A_inv").unwrap();
660
661 let op_metrics = library
662 .performance_monitor
663 .get_operation_metrics("matrix_inverse");
664 assert!(op_metrics.is_some());
665 assert!(op_metrics.unwrap().count > 0);
666 }
667
668 #[test]
669 fn test_solve_records_metrics() {
670 let mut library = LinearAlgebraLibrary::new();
671 library.initialize().unwrap();
672
673 library
674 .create_matrix(
675 "A".to_string(),
676 2,
677 2,
678 DataType::Float64,
679 vec![2.0, 1.0, 1.0, 1.0],
680 )
681 .unwrap();
682 library
683 .create_matrix("b".to_string(), 2, 1, DataType::Float64, vec![3.0, 2.0])
684 .unwrap();
685
686 library.solve_linear_system("A", "b", "x").unwrap();
687
688 let op_metrics = library
689 .performance_monitor
690 .get_operation_metrics("solve_linear_system");
691 assert!(op_metrics.is_some());
692 assert!(op_metrics.unwrap().count > 0);
693 }
694}
695
696pub struct LinearAlgebraLibrary {
698 pub matrix_storage: MatrixStorage,
699 pub computation_engine: ComputationEngine,
700 pub optimization_engine: OptimizationEngine,
701 pub privacy_engine: PrivacyEngine,
702 pub performance_monitor: LAPerformanceMonitor,
703}
704
705impl LinearAlgebraLibrary {
706 pub fn new() -> Self {
708 Self {
709 matrix_storage: MatrixStorage::new(),
710 computation_engine: ComputationEngine::new(),
711 optimization_engine: OptimizationEngine::new(),
712 privacy_engine: PrivacyEngine::new(),
713 performance_monitor: LAPerformanceMonitor::new(),
714 }
715 }
716
717 pub fn initialize(&mut self) -> Result<(), LinearAlgebraError> {
719 self.matrix_storage.initialize()?;
721
722 self.computation_engine.initialize()?;
724
725 self.optimization_engine.initialize()?;
727
728 self.privacy_engine.initialize()?;
730
731 Ok(())
732 }
733
734 pub fn create_matrix(
736 &mut self,
737 matrix_id: String,
738 rows: usize,
739 cols: usize,
740 data_type: DataType,
741 data: Vec<f64>,
742 ) -> Result<Matrix, LinearAlgebraError> {
743 if data.len() != rows * cols {
745 return Err(LinearAlgebraError::InvalidDimensions(
746 "Data size doesn't match dimensions".to_string(),
747 ));
748 }
749
750 let metadata = MatrixMetadata {
752 matrix_id: matrix_id.clone(),
753 rows,
754 cols,
755 data_type: data_type.clone(),
756 storage_format: StorageFormat::RowMajor,
757 compression: CompressionType::None,
758 created_at: std::time::SystemTime::now()
759 .duration_since(std::time::UNIX_EPOCH)
760 .unwrap()
761 .as_secs(),
762 last_accessed: 0,
763 access_count: 0,
764 };
765
766 let matrix = Matrix {
768 matrix_id: matrix_id.clone(),
769 rows,
770 cols,
771 data_type,
772 data,
773 storage_format: StorageFormat::RowMajor,
774 metadata,
775 };
776
777 self.matrix_storage.store_matrix(matrix.clone())?;
778
779 Ok(matrix)
780 }
781
782 pub fn matrix_multiply(
784 &mut self,
785 left_id: &str,
786 right_id: &str,
787 result_id: &str,
788 alpha: f64,
789 beta: f64,
790 ) -> Result<LinearAlgebraResult<Matrix>, LinearAlgebraError> {
791 let start_time = std::time::Instant::now();
792
793 let cache_key = format!(
795 "mul:{}:{}:{}:{}:{}",
796 left_id, right_id, result_id, alpha, beta
797 );
798 let cache_hit = self.matrix_storage.cache.get(&cache_key).is_some();
799 if cache_hit {
800 if let Some(cached) = self.matrix_storage.cache.get(&cache_key) {
802 let execution_time = start_time.elapsed().as_millis() as u64;
803 self.performance_monitor
804 .record_operation("matrix_multiply", execution_time, 0);
805 self.performance_monitor
806 .record_matrix_access(result_id, "matrix_multiply", true);
807 return Ok(LinearAlgebraResult {
808 result: cached,
809 execution_time,
810 memory_usage: 0,
811 operations_used: vec!["matrix_multiply".to_string(), "cache_hit".to_string()],
812 privacy_preserved: false,
813 });
814 }
815 }
816
817 let left = self.matrix_storage.get_matrix(left_id)?;
819 let right = self.matrix_storage.get_matrix(right_id)?;
820
821 self.performance_monitor
823 .record_matrix_access(left_id, "matrix_multiply", false);
824 self.performance_monitor
825 .record_matrix_access(right_id, "matrix_multiply", false);
826
827 if left.cols != right.rows {
829 return Err(LinearAlgebraError::InvalidDimensions(
830 "Matrix dimensions incompatible for multiplication".to_string(),
831 ));
832 }
833
834 let optimized_operation = self
836 .optimization_engine
837 .optimize_multiplication(&left, &right)?;
838
839 let result_data =
841 self.computation_engine
842 .execute_multiplication(&optimized_operation, alpha, beta)?;
843
844 let result = self.create_matrix(
846 result_id.to_string(),
847 left.rows,
848 right.cols,
849 left.data_type.clone(),
850 result_data,
851 )?;
852
853 self.matrix_storage.cache.put(&result)?;
855
856 let execution_time = start_time.elapsed().as_millis() as u64;
857 let memory_usage = (left.rows * right.cols * 8) as u64;
858
859 self.performance_monitor.record_operation_detailed(
861 "matrix_multiply",
862 execution_time as f64,
863 (left.rows, right.cols),
864 );
865 self.performance_monitor
866 .record_operation("matrix_multiply", execution_time, memory_usage);
867 self.performance_monitor
868 .record_matrix_access(result_id, "matrix_multiply", false);
869
870 Ok(LinearAlgebraResult {
871 result,
872 execution_time,
873 memory_usage,
874 operations_used: vec!["matrix_multiply".to_string()],
875 privacy_preserved: false,
876 })
877 }
878
879 pub fn matrix_add(
881 &mut self,
882 left_id: &str,
883 right_id: &str,
884 result_id: &str,
885 alpha: f64,
886 ) -> Result<LinearAlgebraResult<Matrix>, LinearAlgebraError> {
887 let start_time = std::time::Instant::now();
888
889 let left = self.matrix_storage.get_matrix(left_id)?;
891 let right = self.matrix_storage.get_matrix(right_id)?;
892
893 self.performance_monitor
895 .record_matrix_access(left_id, "matrix_add", false);
896 self.performance_monitor
897 .record_matrix_access(right_id, "matrix_add", false);
898
899 if left.rows != right.rows || left.cols != right.cols {
901 return Err(LinearAlgebraError::InvalidDimensions(
902 "Matrix dimensions incompatible for addition".to_string(),
903 ));
904 }
905
906 let mut result_data = Vec::with_capacity(left.data.len());
908 for i in 0..left.data.len() {
909 result_data.push(alpha * (left.data[i] + right.data[i]));
910 }
911
912 let result = self.create_matrix(
914 result_id.to_string(),
915 left.rows,
916 left.cols,
917 left.data_type.clone(),
918 result_data,
919 )?;
920
921 self.matrix_storage.cache.put(&result)?;
923
924 let execution_time = start_time.elapsed().as_millis() as u64;
925 let memory_usage = (left.rows * left.cols * 8) as u64;
926
927 self.performance_monitor.record_operation_detailed(
929 "matrix_add",
930 execution_time as f64,
931 (left.rows, left.cols),
932 );
933 self.performance_monitor
934 .record_operation("matrix_add", execution_time, memory_usage);
935 self.performance_monitor
936 .record_matrix_access(result_id, "matrix_add", false);
937
938 Ok(LinearAlgebraResult {
939 result,
940 execution_time,
941 memory_usage,
942 operations_used: vec!["matrix_add".to_string()],
943 privacy_preserved: false,
944 })
945 }
946
947 pub fn matrix_transpose(
949 &mut self,
950 input_id: &str,
951 result_id: &str,
952 ) -> Result<LinearAlgebraResult<Matrix>, LinearAlgebraError> {
953 let start_time = std::time::Instant::now();
954
955 let input = self.matrix_storage.get_matrix(input_id)?;
957
958 self.performance_monitor
960 .record_matrix_access(input_id, "matrix_transpose", false);
961
962 let mut result_data = Vec::with_capacity(input.data.len());
964 for j in 0..input.cols {
965 for i in 0..input.rows {
966 result_data.push(input.data[i * input.cols + j]);
967 }
968 }
969
970 let result = self.create_matrix(
972 result_id.to_string(),
973 input.cols,
974 input.rows,
975 input.data_type.clone(),
976 result_data,
977 )?;
978
979 self.matrix_storage.cache.put(&result)?;
981
982 let execution_time = start_time.elapsed().as_millis() as u64;
983 let memory_usage = (input.rows * input.cols * 8) as u64;
984
985 self.performance_monitor.record_operation_detailed(
987 "matrix_transpose",
988 execution_time as f64,
989 (input.rows, input.cols),
990 );
991 self.performance_monitor
992 .record_operation("matrix_transpose", execution_time, memory_usage);
993 self.performance_monitor
994 .record_matrix_access(result_id, "matrix_transpose", false);
995
996 Ok(LinearAlgebraResult {
997 result,
998 execution_time,
999 memory_usage,
1000 operations_used: vec!["matrix_transpose".to_string()],
1001 privacy_preserved: false,
1002 })
1003 }
1004
1005 pub fn matrix_inverse(
1007 &mut self,
1008 input_id: &str,
1009 result_id: &str,
1010 ) -> Result<LinearAlgebraResult<Matrix>, LinearAlgebraError> {
1011 let start_time = std::time::Instant::now();
1012
1013 let input = self.matrix_storage.get_matrix(input_id)?;
1015
1016 self.performance_monitor
1018 .record_matrix_access(input_id, "matrix_inverse", false);
1019
1020 if input.rows != input.cols {
1022 return Err(LinearAlgebraError::InvalidDimensions(
1023 "Matrix must be square for inversion".to_string(),
1024 ));
1025 }
1026
1027 let n = input.rows;
1029 let mut augmented = Vec::with_capacity(n * 2 * n);
1030
1031 for i in 0..n {
1033 for j in 0..n {
1034 augmented.push(input.data[i * n + j]);
1035 }
1036 for j in 0..n {
1037 augmented.push(if i == j { 1.0 } else { 0.0 });
1038 }
1039 }
1040
1041 for i in 0..n {
1043 let mut pivot_row = i;
1045 for k in (i + 1)..n {
1046 if (augmented[k * 2 * n + i]).abs() > (augmented[pivot_row * 2 * n + i]).abs() {
1047 pivot_row = k;
1048 }
1049 }
1050
1051 for j in 0..(2 * n) {
1053 augmented.swap(i * 2 * n + j, pivot_row * 2 * n + j);
1054 }
1055
1056 let pivot = augmented[i * 2 * n + i];
1058 if pivot.abs() < 1e-10 {
1059 return Err(LinearAlgebraError::SingularMatrix(
1060 "Matrix is singular".to_string(),
1061 ));
1062 }
1063
1064 for j in 0..(2 * n) {
1065 augmented[i * 2 * n + j] /= pivot;
1066 }
1067
1068 for k in 0..n {
1069 if k != i {
1070 let factor = augmented[k * 2 * n + i];
1071 for j in 0..(2 * n) {
1072 augmented[k * 2 * n + j] -= factor * augmented[i * 2 * n + j];
1073 }
1074 }
1075 }
1076 }
1077
1078 let mut result_data = Vec::with_capacity(n * n);
1080 for i in 0..n {
1081 for j in 0..n {
1082 result_data.push(augmented[i * 2 * n + n + j]);
1083 }
1084 }
1085
1086 let result = self.create_matrix(
1088 result_id.to_string(),
1089 n,
1090 n,
1091 input.data_type.clone(),
1092 result_data,
1093 )?;
1094
1095 self.matrix_storage.cache.put(&result)?;
1097
1098 let execution_time = start_time.elapsed().as_millis() as u64;
1099 let memory_usage = (n * n * 8) as u64;
1100
1101 self.performance_monitor.record_operation_detailed(
1103 "matrix_inverse",
1104 execution_time as f64,
1105 (n, n),
1106 );
1107 self.performance_monitor
1108 .record_operation("matrix_inverse", execution_time, memory_usage);
1109 self.performance_monitor
1110 .record_matrix_access(result_id, "matrix_inverse", false);
1111
1112 Ok(LinearAlgebraResult {
1113 result,
1114 execution_time,
1115 memory_usage,
1116 operations_used: vec!["matrix_inverse".to_string()],
1117 privacy_preserved: false,
1118 })
1119 }
1120
1121 pub fn solve_linear_system(
1123 &mut self,
1124 matrix_id: &str,
1125 rhs_id: &str,
1126 solution_id: &str,
1127 ) -> Result<LinearAlgebraResult<Matrix>, LinearAlgebraError> {
1128 let start_time = std::time::Instant::now();
1129
1130 let matrix = self.matrix_storage.get_matrix(matrix_id)?;
1132 let rhs = self.matrix_storage.get_matrix(rhs_id)?;
1133
1134 self.performance_monitor
1136 .record_matrix_access(matrix_id, "solve_linear_system", false);
1137 self.performance_monitor
1138 .record_matrix_access(rhs_id, "solve_linear_system", false);
1139
1140 if matrix.rows != matrix.cols {
1142 return Err(LinearAlgebraError::InvalidDimensions(
1143 "Matrix must be square".to_string(),
1144 ));
1145 }
1146 if matrix.rows != rhs.rows {
1147 return Err(LinearAlgebraError::InvalidDimensions(
1148 "Matrix and RHS dimensions incompatible".to_string(),
1149 ));
1150 }
1151
1152 use crate::solvers::linear_algebra::qr;
1157 use crate::solvers::SolversError;
1158 let n = matrix.rows;
1159 let mut a = matrix.data.clone(); let mut tau = vec![0.0; n];
1161 let mut b = rhs.data.clone(); let mut solution_data = vec![0.0; n];
1163 let map_err = |e: SolversError| match e {
1164 SolversError::SingularMatrix => {
1165 LinearAlgebraError::SingularMatrix("System is singular".to_string())
1166 }
1167 _ => LinearAlgebraError::InvalidDimensions(
1168 "matrix/RHS dimensions incompatible".to_string(),
1169 ),
1170 };
1171 qr::qr_factor(n, n, &mut a, &mut tau).map_err(map_err)?;
1172 qr::qr_solve_least_squares(n, n, &a, &tau, &mut b, &mut solution_data).map_err(map_err)?;
1173
1174 let result = self.create_matrix(
1176 solution_id.to_string(),
1177 n,
1178 1,
1179 matrix.data_type.clone(),
1180 solution_data,
1181 )?;
1182
1183 self.matrix_storage.cache.put(&result)?;
1185
1186 let execution_time = start_time.elapsed().as_millis() as u64;
1187 let memory_usage = (n * n * 8) as u64;
1188
1189 self.performance_monitor.record_operation_detailed(
1191 "solve_linear_system",
1192 execution_time as f64,
1193 (n, n),
1194 );
1195 self.performance_monitor.record_operation(
1196 "solve_linear_system",
1197 execution_time,
1198 memory_usage,
1199 );
1200 self.performance_monitor
1201 .record_matrix_access(solution_id, "solve_linear_system", false);
1202
1203 Ok(LinearAlgebraResult {
1204 result,
1205 execution_time,
1206 memory_usage,
1207 operations_used: vec!["solve_linear_system".to_string()],
1208 privacy_preserved: false,
1209 })
1210 }
1211
1212 pub fn private_matrix_multiply(
1227 &mut self,
1228 left_id: &str,
1229 right_id: &str,
1230 result_id: &str,
1231 ) -> Result<LinearAlgebraResult<Matrix>, LinearAlgebraError> {
1232 let start_time = std::time::Instant::now();
1233
1234 let left = self.matrix_storage.get_matrix(left_id)?;
1235 let right = self.matrix_storage.get_matrix(right_id)?;
1236 if left.cols != right.rows {
1237 return Err(LinearAlgebraError::InvalidDimensions(
1238 "Matrix dimensions incompatible for multiplication".to_string(),
1239 ));
1240 }
1241 let (m, k, n) = (left.rows, left.cols, right.cols);
1242
1243 const FIXED_POINT_SCALE: f64 = 1_000_000.0;
1249 let a_int: Vec<i128> = left
1250 .data
1251 .iter()
1252 .map(|v| (v * FIXED_POINT_SCALE).round() as i128)
1253 .collect();
1254 let b_int: Vec<i128> = right
1255 .data
1256 .iter()
1257 .map(|v| (v * FIXED_POINT_SCALE).round() as i128)
1258 .collect();
1259
1260 let (verified, c_int) = self
1262 .privacy_engine
1263 .zk_proofs
1264 .lock()
1265 .unwrap()
1266 .prove_matrix_multiply(m, k, n, &a_int, &b_int)
1267 .map_err(|e| LinearAlgebraError::PrivacyError(format!("{:?}", e)))?;
1268
1269 if !verified {
1270 return Err(LinearAlgebraError::PrivacyError(
1271 "zero-knowledge proof of A·B = C failed to verify".to_string(),
1272 ));
1273 }
1274
1275 let scale_sq = FIXED_POINT_SCALE * FIXED_POINT_SCALE;
1277 let result_data: Vec<f64> = c_int.iter().map(|&v| v as f64 / scale_sq).collect();
1278 let result =
1279 self.create_matrix(result_id.to_string(), m, n, left.data_type, result_data)?;
1280
1281 let execution_time = start_time.elapsed().as_millis() as u64;
1282 self.performance_monitor
1283 .record_operation("private_matrix_multiply", execution_time, 0);
1284
1285 Ok(LinearAlgebraResult {
1286 result,
1287 execution_time,
1288 memory_usage: 0,
1289 operations_used: vec![
1290 "private_matrix_multiply".to_string(),
1291 "groth16_zk_proof".to_string(),
1292 ],
1293 privacy_preserved: true,
1294 })
1295 }
1296
1297 pub fn analyze_matrix(
1302 &mut self,
1303 matrix_id: &str,
1304 ) -> Result<MatrixAnalysis, LinearAlgebraError> {
1305 let matrix = self.matrix_storage.get_matrix(matrix_id)?;
1306 self.optimization_engine.analyzer.analyze_matrix(&matrix)
1307 }
1308
1309 pub fn get_performance_stats(&self) -> SystemMetrics {
1311 self.performance_monitor.get_system_metrics()
1312 }
1313
1314 pub fn performance_summary(&self) -> String {
1316 self.performance_monitor.summary()
1317 }
1318
1319 pub fn cache_hit_rate(&self) -> f64 {
1321 self.matrix_storage.cache.hit_rate()
1322 }
1323
1324 pub fn cache_size(&self) -> usize {
1326 self.matrix_storage.cache.cache_size()
1327 }
1328
1329 pub fn list_matrices(&self) -> Vec<String> {
1331 self.matrix_storage.list_matrices()
1332 }
1333
1334 pub fn get_matrix_info(&self, matrix_id: &str) -> Option<MatrixMetadata> {
1336 self.matrix_storage.get_matrix_metadata(matrix_id)
1337 }
1338}
1339
1340pub use crate::solvers::polynomial::{Complex, QuadraticRoots};
1349
1350pub fn solve_quadratic(a: f64, b: f64, c: f64) -> Result<QuadraticRoots, LinearAlgebraError> {
1353 crate::solvers::polynomial::solve_quadratic(a, b, c).map_err(|_| {
1354 LinearAlgebraError::ComputationError("invalid quadratic coefficients".to_string())
1355 })
1356}
1357
1358pub fn polynomial_roots(coeffs: &[f64]) -> Result<Vec<Complex>, LinearAlgebraError> {
1361 crate::solvers::polynomial::polynomial_roots(coeffs)
1362 .map_err(|_| LinearAlgebraError::ComputationError("invalid polynomial".to_string()))
1363}
1364
1365pub use crate::solvers::linear_algebra::lu::Lu;
1375
1376pub fn lu_decompose(n: usize, data: &[f64]) -> Result<Lu, LinearAlgebraError> {
1379 crate::solvers::linear_algebra::lu::lu_decompose(n, data).map_err(|_| {
1380 LinearAlgebraError::InvalidDimensions(
1381 "lu_decompose expects a non-empty square n×n matrix".to_string(),
1382 )
1383 })
1384}
1385
1386pub fn determinant(n: usize, data: &[f64]) -> Result<f64, LinearAlgebraError> {
1389 crate::solvers::linear_algebra::lu::determinant(n, data).map_err(|_| {
1390 LinearAlgebraError::InvalidDimensions(
1391 "determinant expects a non-empty square n×n matrix".to_string(),
1392 )
1393 })
1394}
1395
1396pub fn eigen_symmetric(n: usize, data: &[f64]) -> Result<(Vec<f64>, Vec<f64>), LinearAlgebraError> {
1401 if n == 0 || data.len() != n * n {
1402 return Err(LinearAlgebraError::InvalidDimensions(
1403 "eigen_symmetric expects a non-empty square n×n matrix".to_string(),
1404 ));
1405 }
1406 let mut a = data.to_vec();
1409 let mut v = vec![0.0_f64; n * n];
1410 crate::solvers::linear_algebra::eigen::symmetric_eigen(n, &mut a, &mut v).map_err(
1411 |e| match e {
1412 crate::solvers::SolversError::InvalidParameters => {
1413 LinearAlgebraError::ComputationError(
1414 "eigen_symmetric requires a symmetric matrix".to_string(),
1415 )
1416 }
1417 _ => LinearAlgebraError::InvalidDimensions(
1418 "eigen_symmetric expects a non-empty square n×n matrix".to_string(),
1419 ),
1420 },
1421 )?;
1422 let eigenvalues: Vec<f64> = (0..n).map(|i| a[i * n + i]).collect();
1424 Ok((eigenvalues, v))
1425}
1426
1427pub fn characteristic_polynomial(n: usize, data: &[f64]) -> Result<Vec<f64>, LinearAlgebraError> {
1430 crate::solvers::linear_algebra::spectral::characteristic_polynomial(n, data).map_err(|_| {
1431 LinearAlgebraError::InvalidDimensions(
1432 "characteristic_polynomial expects a non-empty square n×n matrix".to_string(),
1433 )
1434 })
1435}
1436
1437pub fn eigenvalues_general(n: usize, data: &[f64]) -> Result<Vec<Complex>, LinearAlgebraError> {
1440 crate::solvers::linear_algebra::spectral::eigenvalues_general(n, data)
1441 .map_err(|_| LinearAlgebraError::ComputationError("eigenvalues_general failed".to_string()))
1442}
1443
1444pub use crate::solvers::linear_algebra::svd::Svd;
1447
1448pub fn svd(m: usize, n: usize, data: &[f64]) -> Result<Svd, LinearAlgebraError> {
1452 crate::solvers::linear_algebra::svd::svd(m, n, data).map_err(|_| {
1453 LinearAlgebraError::InvalidDimensions("svd expects a non-empty m×n matrix".to_string())
1454 })
1455}