1use std::collections::HashMap;
2
3use super::computation::*;
4use super::core_types::*;
5use super::storage::*;
6
7pub struct OptimizationEngine {
9 pub optimizer: MatrixOptimizer,
10 pub analyzer: MatrixAnalyzer,
11 pub transformer: MatrixTransformer,
12}
13
14pub struct MatrixOptimizer {
16 pub optimization_strategies: Vec<OptimizationStrategy>,
17 pub optimization_history: Vec<OptimizationRecord>,
18}
19
20#[derive(Debug, Clone, PartialEq)]
22pub enum OptimizationStrategy {
23 CacheOptimization,
24 MemoryLayoutOptimization,
25 AlgorithmSelection,
26 Parallelization,
27 Vectorization,
28 Fusion,
29}
30
31#[derive(Debug, Clone)]
33pub struct OptimizationRecord {
34 pub timestamp: u64,
35 pub matrix_id: String,
36 pub strategy: OptimizationStrategy,
37 pub performance_improvement: f64,
38 pub memory_reduction: f64,
39}
40
41pub struct MatrixAnalyzer {
43 pub analysis_algorithms: Vec<AnalysisAlgorithm>,
44 pub pattern_recognition: PatternRecognition,
45}
46
47#[derive(Debug, Clone, PartialEq)]
49pub enum AnalysisAlgorithm {
50 SparsityAnalysis,
51 StructureAnalysis,
52 AccessPatternAnalysis,
53 PerformanceAnalysis,
54}
55
56pub struct PatternRecognition {
58 pub recognized_patterns: Vec<MatrixPattern>,
59 pub pattern_library: PatternLibrary,
60}
61
62#[derive(Debug, Clone, PartialEq, Eq, Hash)]
64pub enum MatrixPattern {
65 Diagonal,
66 Triangular,
67 Banded,
68 Symmetric,
69 PositiveDefinite,
70 Orthogonal,
71 Sparse,
72 Dense,
73 BlockDiagonal,
74 Toeplitz,
75 Hankel,
76 Circulant,
77}
78
79pub struct PatternLibrary {
81 pub patterns: HashMap<String, MatrixPattern>,
82 pub optimization_hints: HashMap<MatrixPattern, OptimizationHint>,
83}
84
85#[derive(Debug, Clone)]
87pub struct OptimizationHint {
88 pub preferred_algorithm: String,
89 pub memory_layout: StorageFormat,
90 pub parallelization_strategy: String,
91 pub vectorization_hints: Vec<String>,
92 pub estimated_speedup: f64,
94}
95
96pub struct MatrixTransformer {
98 pub transformation_rules: Vec<TransformationRule>,
99 pub transformation_history: Vec<TransformationRecord>,
100}
101
102#[derive(Debug, Clone, PartialEq)]
104pub enum TransformationRule {
105 RowColumnSwap,
106 BlockReordering,
107 DataTypeConversion,
108 CompressionDecompression,
109 LayoutConversion,
110}
111
112#[derive(Debug, Clone)]
114pub struct TransformationRecord {
115 pub timestamp: u64,
116 pub matrix_id: String,
117 pub transformation: TransformationRule,
118 pub performance_impact: f64,
119}
120
121#[derive(Debug, Clone, PartialEq)]
128pub enum MatrixLayout {
129 RowMajor,
133 ColMajor,
136 Blocked(Box<MatrixLayout>, usize),
144 Packed,
149}
150
151const SIMD_WIDTH: usize = 4;
155
156impl OptimizationEngine {
157 pub fn new() -> Self {
158 Self {
159 optimizer: MatrixOptimizer::new(),
160 analyzer: MatrixAnalyzer::new(),
161 transformer: MatrixTransformer::new(),
162 }
163 }
164
165 pub fn initialize(&mut self) -> Result<(), LinearAlgebraError> {
166 self.optimizer.initialize()?;
167 self.analyzer.initialize()?;
168 self.transformer.initialize()?;
169 Ok(())
170 }
171
172 pub fn optimize_multiplication(
173 &mut self,
174 left: &Matrix,
175 right: &Matrix,
176 ) -> Result<OptimizedMultiplication, LinearAlgebraError> {
177 let _left_analysis = self.analyzer.analyze_matrix(left)?;
179 let _right_analysis = self.analyzer.analyze_matrix(right)?;
180
181 let optimized = OptimizedMultiplication {
183 left: left.clone(),
184 right: right.clone(),
185 optimization_strategy: OptimizationStrategy::Vectorization,
186 expected_performance_gain: 2.0,
187 };
188
189 Ok(optimized)
190 }
191}
192
193impl MatrixOptimizer {
194 pub fn new() -> Self {
195 Self {
196 optimization_strategies: vec![
197 OptimizationStrategy::Vectorization,
198 OptimizationStrategy::CacheOptimization,
199 OptimizationStrategy::Parallelization,
200 ],
201 optimization_history: Vec::new(),
202 }
203 }
204
205 pub fn initialize(&mut self) -> Result<(), LinearAlgebraError> {
206 Ok(())
207 }
208}
209
210impl MatrixAnalyzer {
211 pub fn new() -> Self {
212 Self {
213 analysis_algorithms: vec![
214 AnalysisAlgorithm::StructureAnalysis,
215 AnalysisAlgorithm::SparsityAnalysis,
216 ],
217 pattern_recognition: PatternRecognition::new(),
218 }
219 }
220
221 pub fn initialize(&mut self) -> Result<(), LinearAlgebraError> {
222 self.pattern_recognition.initialize()?;
223 Ok(())
224 }
225
226 pub fn analyze_matrix(
229 &mut self,
230 matrix: &Matrix,
231 ) -> Result<MatrixAnalysis, LinearAlgebraError> {
232 let detected = self.detect_structure(matrix);
233 let sparsity = self.calculate_sparsity(matrix);
234
235 let mut recommended_algorithms = Vec::new();
237 let mut hint_strings = Vec::new();
238 for pattern in &detected {
239 if let Some(hint) = self
240 .pattern_recognition
241 .pattern_library
242 .get_optimization_hint(pattern)
243 {
244 recommended_algorithms.push(hint.preferred_algorithm.clone());
245 hint_strings.push(format!(
246 "{:?}: {} (speedup ~{:.1}x)",
247 pattern, hint.preferred_algorithm, hint.estimated_speedup
248 ));
249 }
250 }
251
252 let structure = detected.first().cloned().unwrap_or(MatrixPattern::Dense);
254
255 Ok(MatrixAnalysis {
256 matrix_id: matrix.matrix_id.clone(),
257 sparsity,
258 structure,
259 detected_patterns: detected,
260 access_pattern: AccessPattern::Sequential,
261 optimization_hints: hint_strings,
262 recommended_algorithms,
263 })
264 }
265
266 fn calculate_sparsity(&self, matrix: &Matrix) -> f64 {
267 let non_zero = matrix.data.iter().filter(|&&x| x.abs() > 1e-10).count();
268 1.0 - (non_zero as f64 / matrix.data.len().max(1) as f64)
269 }
270
271 pub fn detect_structure(&self, matrix: &Matrix) -> Vec<MatrixPattern> {
274 const TOL: f64 = 1e-10;
275 let rows = matrix.rows;
276 let cols = matrix.cols;
277 let data = &matrix.data;
278 let mut patterns = Vec::new();
279
280 let at = |i: usize, j: usize| -> f64 { data[i * cols + j] };
282
283 let non_zero_count = data.iter().filter(|&&x| x.abs() > TOL).count();
285 let total = data.len();
286 let non_zero_frac = if total > 0 {
287 non_zero_count as f64 / total as f64
288 } else {
289 0.0
290 };
291 let is_sparse = non_zero_frac < 0.3;
292 if is_sparse {
293 patterns.push(MatrixPattern::Sparse);
294 }
295
296 let is_square = rows == cols && rows > 0;
298
299 if is_square {
301 let mut is_diagonal = true;
302 for i in 0..rows {
303 for j in 0..cols {
304 if i != j && at(i, j).abs() > TOL {
305 is_diagonal = false;
306 break;
307 }
308 }
309 if !is_diagonal {
310 break;
311 }
312 }
313 if is_diagonal {
314 patterns.push(MatrixPattern::Diagonal);
315 }
316 }
317
318 if is_square {
320 let mut is_upper = true;
322 for i in 1..rows {
323 for j in 0..i {
324 if at(i, j).abs() > TOL {
325 is_upper = false;
326 break;
327 }
328 }
329 if !is_upper {
330 break;
331 }
332 }
333 let mut is_lower = true;
335 for i in 0..rows {
336 for j in (i + 1)..cols {
337 if at(i, j).abs() > TOL {
338 is_lower = false;
339 break;
340 }
341 }
342 if !is_lower {
343 break;
344 }
345 }
346 if is_upper || is_lower {
347 patterns.push(MatrixPattern::Triangular);
348 }
349 }
350
351 if is_square {
353 let mut is_symmetric = true;
354 for i in 0..rows {
355 for j in (i + 1)..cols {
356 if (at(i, j) - at(j, i)).abs() > TOL {
357 is_symmetric = false;
358 break;
359 }
360 }
361 if !is_symmetric {
362 break;
363 }
364 }
365 if is_symmetric {
366 patterns.push(MatrixPattern::Symmetric);
367
368 if Self::is_positive_definite(rows, data, TOL) {
371 patterns.push(MatrixPattern::PositiveDefinite);
372 }
373 }
374 }
375
376 if rows > 0 && cols > 0 {
378 let max_dim = rows.max(cols);
379 let mut bandwidth = 0usize;
381 for i in 0..rows {
382 for j in 0..cols {
383 if at(i, j).abs() > TOL {
384 let dist = if i >= j { i - j } else { j - i };
385 if dist > bandwidth {
386 bandwidth = dist;
387 }
388 }
389 }
390 }
391 if bandwidth > 0 && (bandwidth as f64) < (max_dim as f64) / 3.0 {
394 patterns.push(MatrixPattern::Banded);
395 }
396 }
397
398 if is_square && rows >= 4 {
400 if Self::is_block_diagonal(rows, data, TOL) {
401 patterns.push(MatrixPattern::BlockDiagonal);
402 }
403 }
404
405 if rows > 1 && cols > 1 {
407 let mut is_toeplitz = true;
408 for d in -(rows as isize - 1)..(cols as isize) {
410 let first = if d >= 0 {
412 at(0, d as usize)
413 } else {
414 at((-d) as usize, 0)
415 };
416 let start_i = if d >= 0 { 0 } else { (-d) as usize };
418 let start_j = if d >= 0 { d as usize } else { 0 };
419 let mut i = start_i;
420 let mut j = start_j;
421 while i < rows && j < cols {
422 if (at(i, j) - first).abs() > TOL {
423 is_toeplitz = false;
424 break;
425 }
426 i += 1;
427 j += 1;
428 }
429 if !is_toeplitz {
430 break;
431 }
432 }
433 if is_toeplitz {
434 patterns.push(MatrixPattern::Toeplitz);
435 }
436 }
437
438 if is_square && rows > 0 {
440 if Self::is_orthogonal(rows, data, TOL) {
441 patterns.push(MatrixPattern::Orthogonal);
442 }
443 }
444
445 if is_square && rows > 1 {
447 let mut is_circulant = true;
448 for i in 1..rows {
449 for j in 0..cols {
451 let expected = at(i - 1, if j == 0 { cols - 1 } else { j - 1 });
452 if (at(i, j) - expected).abs() > TOL {
453 is_circulant = false;
454 break;
455 }
456 }
457 if !is_circulant {
458 break;
459 }
460 }
461 if is_circulant {
462 patterns.push(MatrixPattern::Circulant);
463 }
464 }
465
466 if rows > 1 && cols > 1 {
468 let mut is_hankel = true;
469 for d in 0..(rows + cols - 1) {
472 let mut first_val: Option<f64> = None;
474 for i in 0..rows {
475 let j = d as isize - i as isize;
476 if j >= 0 && (j as usize) < cols {
477 let v = at(i, j as usize);
478 if first_val.is_none() {
479 first_val = Some(v);
480 } else if (v - first_val.unwrap()).abs() > TOL {
481 is_hankel = false;
482 break;
483 }
484 }
485 }
486 if !is_hankel {
487 break;
488 }
489 }
490 if is_hankel {
491 patterns.push(MatrixPattern::Hankel);
492 }
493 }
494
495 if patterns.is_empty() {
497 patterns.push(MatrixPattern::Dense);
498 }
499
500 patterns
501 }
502
503 fn is_positive_definite(n: usize, data: &[f64], tol: f64) -> bool {
506 for k in 1..=n {
507 let mut sub = vec![0.0; k * k];
509 for i in 0..k {
510 for j in 0..k {
511 sub[i * k + j] = data[i * n + j];
512 }
513 }
514 let det = Self::determinant(k, &sub);
516 if det <= tol {
517 return false;
518 }
519 }
520 true
521 }
522
523 fn determinant(n: usize, data: &[f64]) -> f64 {
525 if n == 0 {
526 return 1.0;
527 }
528 if n == 1 {
529 return data[0];
530 }
531 let mut a = data.to_vec();
533 let mut sign = 1.0_f64;
534 for i in 0..n {
535 let mut max_row = i;
537 let mut max_val = a[i * n + i].abs();
538 for k in (i + 1)..n {
539 if a[k * n + i].abs() > max_val {
540 max_val = a[k * n + i].abs();
541 max_row = k;
542 }
543 }
544 if max_val < 1e-15 {
545 return 0.0; }
547 if max_row != i {
548 for j in 0..n {
549 let tmp = a[i * n + j];
550 a[i * n + j] = a[max_row * n + j];
551 a[max_row * n + j] = tmp;
552 }
553 sign = -sign;
554 }
555 for k in (i + 1)..n {
557 let factor = a[k * n + i] / a[i * n + i];
558 for j in i..n {
559 a[k * n + j] -= factor * a[i * n + j];
560 }
561 }
562 }
563 let mut det = sign;
564 for i in 0..n {
565 det *= a[i * n + i];
566 }
567 det
568 }
569
570 fn is_block_diagonal(n: usize, data: &[f64], tol: f64) -> bool {
572 let at = |i: usize, j: usize| -> f64 { data[i * n + j] };
575 for block_size in [2, 4, 8].iter() {
576 if *block_size >= n {
577 continue;
578 }
579 if n % block_size != 0 {
580 continue;
581 }
582 let mut is_block_diag = true;
583 'outer: for bi in 0..(n / block_size) {
584 for bj in 0..(n / block_size) {
585 if bi == bj {
586 continue; }
588 for i in 0..*block_size {
590 for j in 0..*block_size {
591 if at(bi * block_size + i, bj * block_size + j).abs() > tol {
592 is_block_diag = false;
593 break 'outer;
594 }
595 }
596 }
597 }
598 }
599 if is_block_diag {
600 return true;
601 }
602 }
603 false
604 }
605
606 fn is_orthogonal(n: usize, data: &[f64], tol: f64) -> bool {
608 let at = |i: usize, j: usize| -> f64 { data[i * n + j] };
609 for i in 0..n {
611 for j in 0..n {
612 let mut dot = 0.0;
613 for k in 0..n {
614 dot += at(i, k) * at(j, k);
615 }
616 let expected = if i == j { 1.0 } else { 0.0 };
617 if (dot - expected).abs() > tol * 10.0 {
618 return false;
619 }
620 }
621 }
622 true
623 }
624}
625
626impl PatternRecognition {
627 pub fn new() -> Self {
628 Self {
629 recognized_patterns: Vec::new(),
630 pattern_library: PatternLibrary::new(),
631 }
632 }
633
634 pub fn initialize(&mut self) -> Result<(), LinearAlgebraError> {
635 self.pattern_library.initialize()?;
636 Ok(())
637 }
638}
639
640impl PatternLibrary {
641 pub fn new() -> Self {
642 Self {
643 patterns: HashMap::new(),
644 optimization_hints: HashMap::new(),
645 }
646 }
647
648 pub fn initialize(&mut self) -> Result<(), LinearAlgebraError> {
649 self.patterns
651 .insert("diagonal".to_string(), MatrixPattern::Diagonal);
652 self.patterns
653 .insert("triangular".to_string(), MatrixPattern::Triangular);
654 self.patterns
655 .insert("banded".to_string(), MatrixPattern::Banded);
656 self.patterns
657 .insert("symmetric".to_string(), MatrixPattern::Symmetric);
658 self.patterns.insert(
659 "positive_definite".to_string(),
660 MatrixPattern::PositiveDefinite,
661 );
662 self.patterns
663 .insert("orthogonal".to_string(), MatrixPattern::Orthogonal);
664 self.patterns
665 .insert("sparse".to_string(), MatrixPattern::Sparse);
666 self.patterns
667 .insert("dense".to_string(), MatrixPattern::Dense);
668 self.patterns
669 .insert("block_diagonal".to_string(), MatrixPattern::BlockDiagonal);
670 self.patterns
671 .insert("toeplitz".to_string(), MatrixPattern::Toeplitz);
672 self.patterns
673 .insert("hankel".to_string(), MatrixPattern::Hankel);
674 self.patterns
675 .insert("circulant".to_string(), MatrixPattern::Circulant);
676
677 self.optimization_hints.insert(
679 MatrixPattern::Diagonal,
680 OptimizationHint {
681 preferred_algorithm: "diagonal_scale".to_string(),
682 memory_layout: StorageFormat::CompressedSparseRow,
683 parallelization_strategy: "element_wise".to_string(),
684 vectorization_hints: vec!["scalar_multiply".to_string()],
685 estimated_speedup: 10.0,
686 },
687 );
688 self.optimization_hints.insert(
689 MatrixPattern::Triangular,
690 OptimizationHint {
691 preferred_algorithm: "triangular_solve".to_string(),
692 memory_layout: StorageFormat::RowMajor,
693 parallelization_strategy: "row_parallel".to_string(),
694 vectorization_hints: vec!["forward_substitution".to_string()],
695 estimated_speedup: 3.0,
696 },
697 );
698 self.optimization_hints.insert(
699 MatrixPattern::Banded,
700 OptimizationHint {
701 preferred_algorithm: "banded_gemm".to_string(),
702 memory_layout: StorageFormat::Blocked,
703 parallelization_strategy: "band_parallel".to_string(),
704 vectorization_hints: vec!["band_vectorization".to_string()],
705 estimated_speedup: 5.0,
706 },
707 );
708 self.optimization_hints.insert(
709 MatrixPattern::Symmetric,
710 OptimizationHint {
711 preferred_algorithm: "symmetric_gemm".to_string(),
712 memory_layout: StorageFormat::RowMajor,
713 parallelization_strategy: "block_parallel".to_string(),
714 vectorization_hints: vec!["symmetric_pack".to_string()],
715 estimated_speedup: 2.0,
716 },
717 );
718 self.optimization_hints.insert(
719 MatrixPattern::PositiveDefinite,
720 OptimizationHint {
721 preferred_algorithm: "cholesky_decomposition".to_string(),
722 memory_layout: StorageFormat::RowMajor,
723 parallelization_strategy: "block_parallel".to_string(),
724 vectorization_hints: vec!["cholesky_vectorized".to_string()],
725 estimated_speedup: 4.0,
726 },
727 );
728 self.optimization_hints.insert(
729 MatrixPattern::Orthogonal,
730 OptimizationHint {
731 preferred_algorithm: "orthogonal_transform".to_string(),
732 memory_layout: StorageFormat::RowMajor,
733 parallelization_strategy: "column_parallel".to_string(),
734 vectorization_hints: vec!["transpose_free".to_string()],
735 estimated_speedup: 3.0,
736 },
737 );
738 self.optimization_hints.insert(
739 MatrixPattern::Sparse,
740 OptimizationHint {
741 preferred_algorithm: "sparse_gemm".to_string(),
742 memory_layout: StorageFormat::CompressedSparseRow,
743 parallelization_strategy: "row_parallel".to_string(),
744 vectorization_hints: vec!["sparse_vectorization".to_string()],
745 estimated_speedup: 8.0,
746 },
747 );
748 self.optimization_hints.insert(
749 MatrixPattern::Dense,
750 OptimizationHint {
751 preferred_algorithm: "blocked_gemm".to_string(),
752 memory_layout: StorageFormat::Blocked,
753 parallelization_strategy: "block_parallel".to_string(),
754 vectorization_hints: vec!["avx2_vectorization".to_string()],
755 estimated_speedup: 1.0,
756 },
757 );
758 self.optimization_hints.insert(
759 MatrixPattern::BlockDiagonal,
760 OptimizationHint {
761 preferred_algorithm: "block_diagonal_gemm".to_string(),
762 memory_layout: StorageFormat::Blocked,
763 parallelization_strategy: "block_parallel".to_string(),
764 vectorization_hints: vec!["block_vectorization".to_string()],
765 estimated_speedup: 6.0,
766 },
767 );
768 self.optimization_hints.insert(
769 MatrixPattern::Toeplitz,
770 OptimizationHint {
771 preferred_algorithm: "toeplitz_fft".to_string(),
772 memory_layout: StorageFormat::RowMajor,
773 parallelization_strategy: "diagonal_parallel".to_string(),
774 vectorization_hints: vec!["fft_convolution".to_string()],
775 estimated_speedup: 7.0,
776 },
777 );
778 self.optimization_hints.insert(
779 MatrixPattern::Hankel,
780 OptimizationHint {
781 preferred_algorithm: "hankel_fft".to_string(),
782 memory_layout: StorageFormat::RowMajor,
783 parallelization_strategy: "anti_diagonal_parallel".to_string(),
784 vectorization_hints: vec!["fft_convolution".to_string()],
785 estimated_speedup: 7.0,
786 },
787 );
788 self.optimization_hints.insert(
789 MatrixPattern::Circulant,
790 OptimizationHint {
791 preferred_algorithm: "circulant_fft".to_string(),
792 memory_layout: StorageFormat::RowMajor,
793 parallelization_strategy: "row_parallel".to_string(),
794 vectorization_hints: vec!["fft_convolution".to_string()],
795 estimated_speedup: 8.0,
796 },
797 );
798
799 Ok(())
800 }
801
802 pub fn get_optimization_hint(&self, pattern: &MatrixPattern) -> Option<&OptimizationHint> {
804 self.optimization_hints.get(pattern)
805 }
806}
807
808impl MatrixTransformer {
809 pub fn new() -> Self {
810 Self {
811 transformation_rules: vec![
812 TransformationRule::LayoutConversion,
813 TransformationRule::RowColumnSwap,
814 TransformationRule::BlockReordering,
815 TransformationRule::DataTypeConversion,
816 ],
817 transformation_history: Vec::new(),
818 }
819 }
820
821 pub fn initialize(&mut self) -> Result<(), LinearAlgebraError> {
822 Ok(())
823 }
824
825 pub fn transform_matrix(
842 &self,
843 matrix: &Matrix,
844 target_layout: MatrixLayout,
845 ) -> Result<Matrix, LinearAlgebraError> {
846 let rows = matrix.rows;
847 let cols = matrix.cols;
848
849 validate_source_buffer(matrix)?;
851
852 let src =
855 |i: usize, j: usize| -> Result<f64, LinearAlgebraError> { read_element(matrix, i, j) };
856
857 let (data, storage_format) = match target_layout {
858 MatrixLayout::RowMajor => {
859 let mut data = Vec::with_capacity(rows * cols);
860 for i in 0..rows {
861 for j in 0..cols {
862 data.push(src(i, j)?);
863 }
864 }
865 (data, StorageFormat::RowMajor)
866 }
867 MatrixLayout::ColMajor => {
868 let mut data = Vec::with_capacity(rows * cols);
869 for j in 0..cols {
871 for i in 0..rows {
872 data.push(src(i, j)?);
873 }
874 }
875 (data, StorageFormat::ColumnMajor)
876 }
877 MatrixLayout::Blocked(inner, block_size) => {
878 if block_size == 0 {
879 return Err(LinearAlgebraError::OptimizationError(
880 "Blocked layout requires block_size > 0".to_string(),
881 ));
882 }
883 let mut data = Vec::with_capacity(rows * cols);
884 let block_rows = (rows + block_size - 1) / block_size;
885 let block_cols = (cols + block_size - 1) / block_size;
886 let col_major_inner = *inner == MatrixLayout::ColMajor;
889 for bi in 0..block_rows {
890 for bj in 0..block_cols {
891 let i_start = bi * block_size;
892 let i_end = rows.min((bi + 1) * block_size);
893 let j_start = bj * block_size;
894 let j_end = cols.min((bj + 1) * block_size);
895 if col_major_inner {
896 for j in j_start..j_end {
897 for i in i_start..i_end {
898 data.push(src(i, j)?);
899 }
900 }
901 } else {
902 for i in i_start..i_end {
903 for j in j_start..j_end {
904 data.push(src(i, j)?);
905 }
906 }
907 }
908 }
909 }
910 (data, StorageFormat::Blocked)
911 }
912 MatrixLayout::Packed => {
913 let stride = padded_stride(cols);
914 let mut data = vec![0.0; rows * stride];
915 for i in 0..rows {
916 for j in 0..cols {
917 data[i * stride + j] = src(i, j)?;
918 }
919 }
920 (data, StorageFormat::Packed)
921 }
922 };
923
924 let mut result = matrix.clone();
925 result.data = data;
926 result.storage_format = storage_format.clone();
927 result.metadata.storage_format = storage_format;
928 Ok(result)
929 }
930
931 pub fn optimize_layout(
944 &self,
945 matrix: &Matrix,
946 access_pattern: &AccessPattern,
947 ) -> Result<Matrix, LinearAlgebraError> {
948 let target = match access_pattern {
949 AccessPattern::Sequential => MatrixLayout::RowMajor,
950 AccessPattern::Strided => MatrixLayout::ColMajor,
951 AccessPattern::Blocked => {
952 let block_size = matrix.rows.min(matrix.cols).max(1).min(16);
955 MatrixLayout::Blocked(Box::new(MatrixLayout::RowMajor), block_size)
956 }
957 AccessPattern::Random => MatrixLayout::RowMajor,
958 AccessPattern::Adaptive => {
959 if matrix.rows > matrix.cols {
960 MatrixLayout::ColMajor
961 } else {
962 MatrixLayout::RowMajor
963 }
964 }
965 };
966 self.transform_matrix(matrix, target)
967 }
968}
969
970fn padded_stride(cols: usize) -> usize {
973 ((cols + SIMD_WIDTH - 1) / SIMD_WIDTH) * SIMD_WIDTH
974}
975
976fn read_element(matrix: &Matrix, i: usize, j: usize) -> Result<f64, LinearAlgebraError> {
980 let rows = matrix.rows;
981 let cols = matrix.cols;
982 if i >= rows || j >= cols {
983 return Err(LinearAlgebraError::OptimizationError(format!(
984 "element index ({}, {}) out of bounds for matrix of shape {}x{}",
985 i, j, rows, cols
986 )));
987 }
988 let idx = match matrix.storage_format {
989 StorageFormat::RowMajor => i * cols + j,
990 StorageFormat::ColumnMajor => j * rows + i,
991 StorageFormat::Packed => {
992 let stride = padded_stride(cols);
993 i * stride + j
994 }
995 StorageFormat::Blocked => {
996 return Err(LinearAlgebraError::OptimizationError(
997 "cannot read from Blocked source: block size is not stored in Matrix metadata"
998 .to_string(),
999 ));
1000 }
1001 StorageFormat::CompressedSparseRow | StorageFormat::CompressedSparseColumn => {
1002 return Err(LinearAlgebraError::OptimizationError(
1003 "sparse source layouts are not supported by the layout transformer".to_string(),
1004 ));
1005 }
1006 };
1007 if idx >= matrix.data.len() {
1008 return Err(LinearAlgebraError::OptimizationError(format!(
1009 "linear index {} out of bounds for data buffer of length {} (layout {:?})",
1010 idx,
1011 matrix.data.len(),
1012 matrix.storage_format
1013 )));
1014 }
1015 Ok(matrix.data[idx])
1016}
1017
1018fn validate_source_buffer(matrix: &Matrix) -> Result<(), LinearAlgebraError> {
1021 let expected = match matrix.storage_format {
1022 StorageFormat::RowMajor | StorageFormat::ColumnMajor | StorageFormat::Blocked => {
1023 matrix.rows * matrix.cols
1024 }
1025 StorageFormat::Packed => matrix.rows * padded_stride(matrix.cols),
1026 StorageFormat::CompressedSparseRow | StorageFormat::CompressedSparseColumn => {
1027 return Ok(());
1030 }
1031 };
1032 if matrix.data.len() != expected {
1033 return Err(LinearAlgebraError::OptimizationError(format!(
1034 "source data length {} does not match expected {} for {:?} layout ({}x{})",
1035 matrix.data.len(),
1036 expected,
1037 matrix.storage_format,
1038 matrix.rows,
1039 matrix.cols
1040 )));
1041 }
1042 Ok(())
1043}
1044
1045#[derive(Debug, Clone)]
1046pub struct MatrixAnalysis {
1047 pub matrix_id: String,
1048 pub sparsity: f64,
1049 pub structure: MatrixPattern,
1050 pub detected_patterns: Vec<MatrixPattern>,
1052 pub access_pattern: AccessPattern,
1053 pub optimization_hints: Vec<String>,
1054 pub recommended_algorithms: Vec<String>,
1056}
1057
1058pub type MatrixAnalysisResult = MatrixAnalysis;
1060
1061#[cfg(test)]
1062mod tests {
1063 use super::*;
1064
1065 fn make_matrix(id: &str, rows: usize, cols: usize, data: Vec<f64>) -> Matrix {
1066 let metadata = MatrixMetadata {
1067 matrix_id: id.to_string(),
1068 rows,
1069 cols,
1070 data_type: DataType::Float64,
1071 storage_format: StorageFormat::RowMajor,
1072 compression: CompressionType::None,
1073 created_at: 0,
1074 last_accessed: 0,
1075 access_count: 0,
1076 };
1077 Matrix {
1078 matrix_id: id.to_string(),
1079 rows,
1080 cols,
1081 data_type: DataType::Float64,
1082 data,
1083 storage_format: StorageFormat::RowMajor,
1084 metadata,
1085 }
1086 }
1087
1088 fn make_analyzer() -> MatrixAnalyzer {
1089 let mut analyzer = MatrixAnalyzer::new();
1090 analyzer.initialize().unwrap();
1091 analyzer
1092 }
1093
1094 #[test]
1095 fn test_detect_diagonal() {
1096 let analyzer = make_analyzer();
1097 let m = make_matrix("d", 3, 3, vec![1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0]);
1099 let patterns = analyzer.detect_structure(&m);
1100 assert!(patterns.contains(&MatrixPattern::Diagonal));
1101 }
1102
1103 #[test]
1104 fn test_detect_upper_triangular() {
1105 let analyzer = make_analyzer();
1106 let m = make_matrix("u", 3, 3, vec![1.0, 2.0, 3.0, 0.0, 4.0, 5.0, 0.0, 0.0, 6.0]);
1107 let patterns = analyzer.detect_structure(&m);
1108 assert!(patterns.contains(&MatrixPattern::Triangular));
1109 }
1110
1111 #[test]
1112 fn test_detect_lower_triangular() {
1113 let analyzer = make_analyzer();
1114 let m = make_matrix("l", 3, 3, vec![1.0, 0.0, 0.0, 2.0, 3.0, 0.0, 4.0, 5.0, 6.0]);
1115 let patterns = analyzer.detect_structure(&m);
1116 assert!(patterns.contains(&MatrixPattern::Triangular));
1117 }
1118
1119 #[test]
1120 fn test_detect_symmetric() {
1121 let analyzer = make_analyzer();
1122 let m = make_matrix("s", 3, 3, vec![1.0, 2.0, 3.0, 2.0, 4.0, 5.0, 3.0, 5.0, 6.0]);
1123 let patterns = analyzer.detect_structure(&m);
1124 assert!(patterns.contains(&MatrixPattern::Symmetric));
1125 }
1126
1127 #[test]
1128 fn test_detect_not_symmetric() {
1129 let analyzer = make_analyzer();
1130 let m = make_matrix("ns", 2, 2, vec![1.0, 2.0, 3.0, 4.0]);
1131 let patterns = analyzer.detect_structure(&m);
1132 assert!(!patterns.contains(&MatrixPattern::Symmetric));
1133 }
1134
1135 #[test]
1136 fn test_detect_positive_definite() {
1137 let analyzer = make_analyzer();
1138 let m = make_matrix("pd", 2, 2, vec![2.0, 1.0, 1.0, 2.0]);
1140 let patterns = analyzer.detect_structure(&m);
1141 assert!(patterns.contains(&MatrixPattern::PositiveDefinite));
1142 }
1143
1144 #[test]
1145 fn test_detect_not_positive_definite() {
1146 let analyzer = make_analyzer();
1147 let m = make_matrix("npd", 2, 2, vec![1.0, 2.0, 2.0, 1.0]);
1149 let patterns = analyzer.detect_structure(&m);
1150 assert!(!patterns.contains(&MatrixPattern::PositiveDefinite));
1151 }
1152
1153 #[test]
1154 fn test_detect_sparse() {
1155 let analyzer = make_analyzer();
1156 let m = make_matrix(
1158 "sp",
1159 4,
1160 4,
1161 vec![
1162 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0,
1163 ],
1164 );
1165 let patterns = analyzer.detect_structure(&m);
1166 assert!(patterns.contains(&MatrixPattern::Sparse));
1167 }
1168
1169 #[test]
1170 fn test_detect_dense() {
1171 let analyzer = make_analyzer();
1172 let m = make_matrix("d", 2, 2, vec![1.0, 2.0, 3.0, 4.0]);
1173 let patterns = analyzer.detect_structure(&m);
1174 assert!(patterns.contains(&MatrixPattern::Dense));
1175 }
1176
1177 #[test]
1178 fn test_detect_banded() {
1179 let analyzer = make_analyzer();
1180 let m = make_matrix(
1182 "b",
1183 5,
1184 5,
1185 vec![
1186 1.0, 2.0, 0.0, 0.0, 0.0, 3.0, 4.0, 5.0, 0.0, 0.0, 0.0, 6.0, 7.0, 8.0, 0.0, 0.0,
1187 0.0, 9.0, 10.0, 11.0, 0.0, 0.0, 0.0, 12.0, 13.0,
1188 ],
1189 );
1190 let patterns = analyzer.detect_structure(&m);
1191 assert!(patterns.contains(&MatrixPattern::Banded));
1192 }
1193
1194 #[test]
1195 fn test_detect_toeplitz() {
1196 let analyzer = make_analyzer();
1197 let m = make_matrix("t", 3, 3, vec![1.0, 2.0, 3.0, 4.0, 1.0, 2.0, 5.0, 4.0, 1.0]);
1200 let patterns = analyzer.detect_structure(&m);
1201 assert!(patterns.contains(&MatrixPattern::Toeplitz));
1202 }
1203
1204 #[test]
1205 fn test_detect_orthogonal() {
1206 let analyzer = make_analyzer();
1207 let m = make_matrix("o", 2, 2, vec![0.0, -1.0, 1.0, 0.0]);
1210 let patterns = analyzer.detect_structure(&m);
1211 assert!(patterns.contains(&MatrixPattern::Orthogonal));
1212 }
1213
1214 #[test]
1215 fn test_detect_circulant() {
1216 let analyzer = make_analyzer();
1217 let m = make_matrix("c", 3, 3, vec![1.0, 2.0, 3.0, 3.0, 1.0, 2.0, 2.0, 3.0, 1.0]);
1220 let patterns = analyzer.detect_structure(&m);
1221 assert!(patterns.contains(&MatrixPattern::Circulant));
1222 }
1223
1224 #[test]
1225 fn test_detect_hankel() {
1226 let analyzer = make_analyzer();
1227 let m = make_matrix("h", 3, 3, vec![1.0, 2.0, 3.0, 2.0, 3.0, 4.0, 3.0, 4.0, 5.0]);
1230 let patterns = analyzer.detect_structure(&m);
1231 assert!(patterns.contains(&MatrixPattern::Hankel));
1232 }
1233
1234 #[test]
1235 fn test_detect_block_diagonal() {
1236 let analyzer = make_analyzer();
1237 let m = make_matrix(
1239 "bd",
1240 4,
1241 4,
1242 vec![
1243 1.0, 2.0, 0.0, 0.0, 3.0, 4.0, 0.0, 0.0, 0.0, 0.0, 5.0, 6.0, 0.0, 0.0, 7.0, 8.0,
1244 ],
1245 );
1246 let patterns = analyzer.detect_structure(&m);
1247 assert!(patterns.contains(&MatrixPattern::BlockDiagonal));
1248 }
1249
1250 #[test]
1251 fn test_pattern_library_initialize() {
1252 let mut lib = PatternLibrary::new();
1253 lib.initialize().unwrap();
1254
1255 assert_eq!(lib.patterns.len(), 12);
1257 assert_eq!(lib.optimization_hints.len(), 12);
1258 }
1259
1260 #[test]
1261 fn test_get_optimization_hint() {
1262 let mut lib = PatternLibrary::new();
1263 lib.initialize().unwrap();
1264
1265 let hint = lib.get_optimization_hint(&MatrixPattern::Diagonal);
1266 assert!(hint.is_some());
1267 let h = hint.unwrap();
1268 assert_eq!(h.preferred_algorithm, "diagonal_scale");
1269 assert!(h.estimated_speedup > 0.0);
1270
1271 let hint2 = lib.get_optimization_hint(&MatrixPattern::Sparse);
1272 assert!(hint2.is_some());
1273 assert_eq!(hint2.unwrap().preferred_algorithm, "sparse_gemm");
1274 }
1275
1276 #[test]
1277 fn test_analyze_matrix() {
1278 let mut analyzer = make_analyzer();
1279 let m = make_matrix("s", 2, 2, vec![2.0, 1.0, 1.0, 2.0]);
1280 let result = analyzer.analyze_matrix(&m).unwrap();
1281
1282 assert_eq!(result.matrix_id, "s");
1283 assert!(result.detected_patterns.contains(&MatrixPattern::Symmetric));
1284 assert!(result
1285 .detected_patterns
1286 .contains(&MatrixPattern::PositiveDefinite));
1287 assert!(!result.recommended_algorithms.is_empty());
1288 }
1289
1290 #[test]
1291 fn test_analyze_matrix_sparsity() {
1292 let mut analyzer = make_analyzer();
1293 let m = make_matrix(
1295 "sp",
1296 3,
1297 3,
1298 vec![1.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 3.0],
1299 );
1300 let result = analyzer.analyze_matrix(&m).unwrap();
1301 assert!((result.sparsity - 6.0 / 9.0).abs() < 1e-10); }
1303
1304 fn make_transformer() -> MatrixTransformer {
1307 let mut t = MatrixTransformer::new();
1308 t.initialize().unwrap();
1309 t
1310 }
1311
1312 fn make_col_matrix(id: &str, rows: usize, cols: usize, row_major_data: Vec<f64>) -> Matrix {
1316 let mut col_major = Vec::with_capacity(rows * cols);
1318 for j in 0..cols {
1319 for i in 0..rows {
1320 col_major.push(row_major_data[i * cols + j]);
1321 }
1322 }
1323 let metadata = MatrixMetadata {
1324 matrix_id: id.to_string(),
1325 rows,
1326 cols,
1327 data_type: DataType::Float64,
1328 storage_format: StorageFormat::ColumnMajor,
1329 compression: CompressionType::None,
1330 created_at: 0,
1331 last_accessed: 0,
1332 access_count: 0,
1333 };
1334 Matrix {
1335 matrix_id: id.to_string(),
1336 rows,
1337 cols,
1338 data_type: DataType::Float64,
1339 data: col_major,
1340 storage_format: StorageFormat::ColumnMajor,
1341 metadata,
1342 }
1343 }
1344
1345 fn read_blocked(m: &Matrix, block_size: usize, i: usize, j: usize) -> f64 {
1349 let rows = m.rows;
1350 let cols = m.cols;
1351 let block_rows = (rows + block_size - 1) / block_size;
1352 let block_cols = (cols + block_size - 1) / block_size;
1353 let bi = i / block_size;
1354 let bj = j / block_size;
1355 let li = i % block_size; let lj = j % block_size; let mut offset = 0usize;
1359 'outer: for bbi in 0..block_rows {
1360 for bbj in 0..block_cols {
1361 if bbi == bi && bbj == bj {
1362 break 'outer;
1363 }
1364 let i_end = rows.min((bbi + 1) * block_size);
1365 let j_end = cols.min((bbj + 1) * block_size);
1366 offset += (i_end - bbi * block_size) * (j_end - bbj * block_size);
1367 }
1368 }
1369 let i_start = bi * block_size;
1371 let j_start = bj * block_size;
1372 let _local_rows = rows.min((bi + 1) * block_size) - i_start;
1373 let local_cols = cols.min((bj + 1) * block_size) - j_start;
1374 offset += li * local_cols + lj;
1376 m.data[offset]
1377 }
1378
1379 #[test]
1380 fn test_row_to_col_major() {
1381 let transformer = make_transformer();
1382 let m = make_matrix("rm", 2, 3, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1386 assert_eq!(m.storage_format, StorageFormat::RowMajor);
1387
1388 let result = transformer
1389 .transform_matrix(&m, MatrixLayout::ColMajor)
1390 .unwrap();
1391
1392 assert_eq!(result.storage_format, StorageFormat::ColumnMajor);
1393 assert_eq!(result.metadata.storage_format, StorageFormat::ColumnMajor);
1394 assert_eq!(result.rows, 2);
1395 assert_eq!(result.cols, 3);
1396 assert_eq!(result.data, vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
1398 for i in 0..2 {
1400 for j in 0..3 {
1401 let expected = m.data[i * 3 + j];
1402 let got = result.data[j * 2 + i];
1403 assert_eq!(got, expected, "element ({},{}) mismatch", i, j);
1404 }
1405 }
1406 }
1407
1408 #[test]
1409 fn test_col_to_row_major() {
1410 let transformer = make_transformer();
1411 let m = make_col_matrix("cm", 2, 3, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1413 assert_eq!(m.storage_format, StorageFormat::ColumnMajor);
1414 assert_eq!(m.data, vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
1415
1416 let result = transformer
1417 .transform_matrix(&m, MatrixLayout::RowMajor)
1418 .unwrap();
1419
1420 assert_eq!(result.storage_format, StorageFormat::RowMajor);
1421 assert_eq!(result.rows, 2);
1422 assert_eq!(result.cols, 3);
1423 assert_eq!(result.data, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1425 for i in 0..2 {
1427 for j in 0..3 {
1428 let expected = m.data[j * 2 + i]; let got = result.data[i * 3 + j]; assert_eq!(got, expected, "element ({},{}) mismatch", i, j);
1431 }
1432 }
1433 }
1434
1435 #[test]
1436 fn test_blocked_layout() {
1437 let transformer = make_transformer();
1438 let m = make_matrix(
1444 "blk",
1445 4,
1446 4,
1447 vec![
1448 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0,
1449 16.0,
1450 ],
1451 );
1452
1453 let result = transformer
1454 .transform_matrix(
1455 &m,
1456 MatrixLayout::Blocked(Box::new(MatrixLayout::RowMajor), 2),
1457 )
1458 .unwrap();
1459
1460 assert_eq!(result.storage_format, StorageFormat::Blocked);
1461 assert_eq!(result.rows, 4);
1462 assert_eq!(result.cols, 4);
1463 assert_eq!(result.data.len(), 16);
1464 assert_eq!(
1470 result.data,
1471 vec![
1472 1.0, 2.0, 5.0, 6.0, 3.0, 4.0, 7.0, 8.0, 9.0, 10.0, 13.0, 14.0, 11.0, 12.0, 15.0,
1473 16.0,
1474 ]
1475 );
1476 for i in 0..4 {
1478 for j in 0..4 {
1479 let expected = m.data[i * 4 + j];
1480 let got = read_blocked(&result, 2, i, j);
1481 assert_eq!(got, expected, "blocked element ({},{}) mismatch", i, j);
1482 }
1483 }
1484 }
1485
1486 #[test]
1487 fn test_optimize_layout_row_access() {
1488 let transformer = make_transformer();
1489 let m = make_matrix("r", 2, 3, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1490 let result = transformer
1492 .optimize_layout(&m, &AccessPattern::Sequential)
1493 .unwrap();
1494 assert_eq!(result.storage_format, StorageFormat::RowMajor);
1495 assert_eq!(result.data, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1497 }
1498
1499 #[test]
1500 fn test_optimize_layout_col_access() {
1501 let transformer = make_transformer();
1502 let m = make_matrix("c", 2, 3, vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]);
1503 let result = transformer
1505 .optimize_layout(&m, &AccessPattern::Strided)
1506 .unwrap();
1507 assert_eq!(result.storage_format, StorageFormat::ColumnMajor);
1508 assert_eq!(result.data, vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
1510 }
1511}