1use crate::error::{Result, UmicpError};
8use crate::types::MatrixResult;
9
10#[derive(Debug)]
12pub struct Matrix {
13 }
15
16impl Matrix {
17 pub fn new() -> Self {
19 Matrix {}
20 }
21
22 pub fn add(&self, a: &[f32], b: &[f32], result: &mut [f32], rows: usize, cols: usize) -> Result<MatrixResult> {
25 self.validate_dimensions(a.len(), b.len(), result.len(), rows, cols)?;
26
27 if rows * cols > 1000 {
29 self.add_parallel(a, b, result, rows, cols);
30 } else {
31 self.add_sequential(a, b, result);
32 }
33
34 Ok(MatrixResult {
35 success: true,
36 error: None,
37 result: None,
38 similarity: None,
39 data: None,
40 })
41 }
42
43 pub fn multiply(&self, a: &[f32], b: &[f32], result: &mut [f32], m: usize, n: usize, p: usize) -> Result<MatrixResult> {
45 let a_len = m * n;
46 let b_len = n * p;
47 let result_len = m * p;
48
49 if a.len() != a_len || b.len() != b_len || result.len() != result_len {
50 return Err(UmicpError::matrix(format!(
51 "Invalid matrix dimensions: a({}) != {}x{}, b({}) != {}x{}, result({}) != {}x{}",
52 a.len(), m, n, b.len(), n, p, result.len(), m, p
53 )));
54 }
55
56 result.fill(0.0);
58
59 if m * n * p > 10000 {
61 self.multiply_parallel(a, b, result, m, n, p);
62 } else {
63 self.multiply_sequential(a, b, result, m, n, p);
64 }
65
66 Ok(MatrixResult {
67 success: true,
68 error: None,
69 result: None,
70 similarity: None,
71 data: None,
72 })
73 }
74
75 pub fn transpose(&self, input: &[f32], output: &mut [f32], rows: usize, cols: usize) -> Result<MatrixResult> {
77 let input_len = rows * cols;
78 let output_len = cols * rows;
79
80 if input.len() != input_len || output.len() != output_len {
81 return Err(UmicpError::matrix(format!(
82 "Invalid transpose dimensions: input({}) != {}x{}, output({}) != {}x{}",
83 input.len(), rows, cols, output.len(), cols, rows
84 )));
85 }
86
87 for i in 0..rows {
89 for j in 0..cols {
90 output[j * rows + i] = input[i * cols + j];
91 }
92 }
93
94 Ok(MatrixResult {
95 success: true,
96 error: None,
97 result: None,
98 similarity: None,
99 data: None,
100 })
101 }
102
103 pub fn dot_product(&self, a: &[f32], b: &[f32]) -> Result<MatrixResult> {
105 if a.len() != b.len() {
106 return Err(UmicpError::matrix(format!(
107 "Vector length mismatch: a({}) != b({})",
108 a.len(), b.len()
109 )));
110 }
111
112 let result = if a.len() >= 8 {
114 self.dot_product_simd(a, b)
115 } else {
116 a.iter().zip(b.iter()).map(|(x, y)| x * y).sum()
117 };
118
119 Ok(MatrixResult {
120 success: true,
121 error: None,
122 result: Some(result as f64),
123 similarity: None,
124 data: None,
125 })
126 }
127
128 pub fn normalize(&self, matrix: &mut [f32], rows: usize, cols: usize) -> Result<MatrixResult> {
130 let matrix_len = rows * cols;
131 if matrix.len() != matrix_len {
132 return Err(UmicpError::matrix(format!(
133 "Invalid matrix dimensions: matrix({}) != {}x{}",
134 matrix.len(), rows, cols
135 )));
136 }
137
138 for row in 0..rows {
139 let start = row * cols;
140 let end = start + cols;
141 let row_slice = &mut matrix[start..end];
142
143 let norm: f32 = row_slice.iter().map(|x| x * x).sum::<f32>().sqrt();
145
146 if norm > 0.0 {
147 for val in row_slice.iter_mut() {
149 *val /= norm;
150 }
151 }
152 }
153
154 Ok(MatrixResult {
155 success: true,
156 error: None,
157 result: None,
158 similarity: None,
159 data: Some(matrix.to_vec()),
160 })
161 }
162
163 pub fn cosine_similarity(&self, a: &[f32], b: &[f32]) -> Result<MatrixResult> {
165 if a.len() != b.len() {
166 return Err(UmicpError::matrix(format!(
167 "Vector length mismatch: a({}) != b({})",
168 a.len(), b.len()
169 )));
170 }
171
172 let dot_result = self.dot_product(a, b)?;
174 let dot_product = dot_result.result.unwrap() as f32;
175
176 let a_magnitude: f32 = a.iter().map(|x| x * x).sum::<f32>().sqrt();
178 let b_magnitude: f32 = b.iter().map(|x| x * x).sum::<f32>().sqrt();
179
180 if a_magnitude == 0.0 || b_magnitude == 0.0 {
181 return Ok(MatrixResult {
182 success: true,
183 error: None,
184 result: None,
185 similarity: Some(0.0),
186 data: None,
187 });
188 }
189
190 let similarity = dot_product / (a_magnitude * b_magnitude);
191
192 Ok(MatrixResult {
193 success: true,
194 error: None,
195 result: None,
196 similarity: Some(similarity as f64),
197 data: None,
198 })
199 }
200
201 pub fn vector_add(&self, a: &[f32], b: &[f32], result: &mut [f32]) -> Result<MatrixResult> {
203 if a.len() != b.len() || a.len() != result.len() {
204 return Err(UmicpError::matrix(format!(
205 "Vector length mismatch: a({}), b({}), result({})",
206 a.len(), b.len(), result.len()
207 )));
208 }
209
210 for i in 0..a.len() {
211 result[i] = a[i] + b[i];
212 }
213
214 Ok(MatrixResult {
215 success: true,
216 error: None,
217 result: None,
218 similarity: None,
219 data: None,
220 })
221 }
222
223 pub fn vector_subtract(&self, a: &[f32], b: &[f32], result: &mut [f32]) -> Result<MatrixResult> {
225 if a.len() != b.len() || a.len() != result.len() {
226 return Err(UmicpError::matrix(format!(
227 "Vector length mismatch: a({}), b({}), result({})",
228 a.len(), b.len(), result.len()
229 )));
230 }
231
232 for i in 0..a.len() {
233 result[i] = a[i] - b[i];
234 }
235
236 Ok(MatrixResult {
237 success: true,
238 error: None,
239 result: None,
240 similarity: None,
241 data: None,
242 })
243 }
244
245 pub fn vector_multiply(&self, a: &[f32], b: &[f32], result: &mut [f32]) -> Result<MatrixResult> {
247 if a.len() != b.len() || a.len() != result.len() {
248 return Err(UmicpError::matrix(format!(
249 "Vector length mismatch: a({}), b({}), result({})",
250 a.len(), b.len(), result.len()
251 )));
252 }
253
254 for i in 0..a.len() {
255 result[i] = a[i] * b[i];
256 }
257
258 Ok(MatrixResult {
259 success: true,
260 error: None,
261 result: None,
262 similarity: None,
263 data: None,
264 })
265 }
266
267 pub fn vector_scale(&self, vector: &[f32], scalar: f32, result: &mut [f32]) -> Result<MatrixResult> {
269 if vector.len() != result.len() {
270 return Err(UmicpError::matrix(format!(
271 "Vector length mismatch: vector({}), result({})",
272 vector.len(), result.len()
273 )));
274 }
275
276 for i in 0..vector.len() {
277 result[i] = vector[i] * scalar;
278 }
279
280 Ok(MatrixResult {
281 success: true,
282 error: None,
283 result: None,
284 similarity: None,
285 data: None,
286 })
287 }
288
289 pub fn determinant(&self, matrix: &[f32], size: usize) -> Result<MatrixResult> {
291 let matrix_len = size * size;
292 if matrix.len() != matrix_len {
293 return Err(UmicpError::matrix(format!(
294 "Invalid matrix dimensions for determinant: matrix({}) != {}x{}",
295 matrix.len(), size, size
296 )));
297 }
298
299 if size == 1 {
300 return Ok(MatrixResult {
301 success: true,
302 error: None,
303 result: Some(matrix[0] as f64),
304 similarity: None,
305 data: None,
306 });
307 }
308
309 if size == 2 {
310 let det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
311 return Ok(MatrixResult {
312 success: true,
313 error: None,
314 result: Some(det as f64),
315 similarity: None,
316 data: None,
317 });
318 }
319
320 Err(UmicpError::matrix("Determinant calculation for matrices larger than 2x2 not yet implemented"))
322 }
323
324 pub fn inverse(&self, matrix: &[f32], result: &mut [f32], size: usize) -> Result<MatrixResult> {
326 let matrix_len = size * size;
327 if matrix.len() != matrix_len || result.len() != matrix_len {
328 return Err(UmicpError::matrix(format!(
329 "Invalid matrix dimensions for inverse: matrix({}) != {}x{}, result({}) != {}x{}",
330 matrix.len(), size, size, result.len(), size, size
331 )));
332 }
333
334 if size == 2 {
336 let det = matrix[0] * matrix[3] - matrix[1] * matrix[2];
337 if det == 0.0 {
338 return Err(UmicpError::matrix("Matrix is singular, cannot compute inverse"));
339 }
340
341 result[0] = matrix[3] / det;
342 result[1] = -matrix[1] / det;
343 result[2] = -matrix[2] / det;
344 result[3] = matrix[0] / det;
345
346 return Ok(MatrixResult {
347 success: true,
348 error: None,
349 result: None,
350 similarity: None,
351 data: Some(result.to_vec()),
352 });
353 }
354
355 Err(UmicpError::matrix("Matrix inverse for matrices larger than 2x2 not yet implemented"))
357 }
358
359 fn validate_dimensions(&self, a_len: usize, b_len: usize, result_len: usize, rows: usize, cols: usize) -> Result<()> {
362 let expected_len = rows * cols;
363 if a_len != expected_len || b_len != expected_len || result_len != expected_len {
364 return Err(UmicpError::matrix(format!(
365 "Invalid matrix dimensions: expected {}x{} ({} elements), got a({}), b({}), result({})",
366 rows, cols, expected_len, a_len, b_len, result_len
367 )));
368 }
369 Ok(())
370 }
371
372 fn add_sequential(&self, a: &[f32], b: &[f32], result: &mut [f32]) {
373 for i in 0..a.len() {
374 result[i] = a[i] + b[i];
375 }
376 }
377
378 fn add_parallel(&self, a: &[f32], b: &[f32], result: &mut [f32], _rows: usize, _cols: usize) {
379 for i in 0..a.len() {
381 result[i] = a[i] + b[i];
382 }
383 }
384
385 fn multiply_sequential(&self, a: &[f32], b: &[f32], result: &mut [f32], m: usize, n: usize, p: usize) {
386 for i in 0..m {
387 for j in 0..p {
388 for k in 0..n {
389 result[i * p + j] += a[i * n + k] * b[k * p + j];
390 }
391 }
392 }
393 }
394
395 fn multiply_parallel(&self, a: &[f32], b: &[f32], result: &mut [f32], m: usize, n: usize, p: usize) {
396 for i in 0..m {
398 for j in 0..p {
399 let mut sum = 0.0;
400 for k in 0..n {
401 sum += a[i * n + k] * b[k * p + j];
402 }
403 result[i * p + j] = sum;
404 }
405 }
406 }
407
408 fn dot_product_simd(&self, a: &[f32], b: &[f32]) -> f32 {
409 a.iter().zip(b.iter()).map(|(x, y)| x * y).sum()
412 }
413}
414
415impl Default for Matrix {
416 fn default() -> Self {
417 Self::new()
418 }
419}
420
421#[cfg(test)]
422mod tests {
423 use super::*;
424
425 #[test]
426 fn test_matrix_creation() {
427 let _matrix = Matrix::new();
428 assert!(true);
430 }
431
432 #[test]
433 fn test_vector_add() {
434 let matrix = Matrix::new();
435 let a = vec![1.0, 2.0, 3.0];
436 let b = vec![4.0, 5.0, 6.0];
437 let mut result = vec![0.0; 3];
438
439 let matrix_result = matrix.vector_add(&a, &b, &mut result).unwrap();
440 assert!(matrix_result.success);
441 assert_eq!(result, vec![5.0, 7.0, 9.0]);
442 }
443
444 #[test]
445 fn test_dot_product() {
446 let matrix = Matrix::new();
447 let a = vec![1.0, 2.0, 3.0];
448 let b = vec![4.0, 5.0, 6.0];
449
450 let result = matrix.dot_product(&a, &b).unwrap();
451 assert!(result.success);
452 assert_eq!(result.result.unwrap(), 32.0); }
454
455 #[test]
456 fn test_cosine_similarity() {
457 let matrix = Matrix::new();
458 let a = vec![1.0, 2.0, 3.0];
459 let b = vec![1.0, 2.0, 3.0]; let result = matrix.cosine_similarity(&a, &b).unwrap();
462 assert!(result.success);
463 assert!((result.similarity.unwrap() - 1.0).abs() < 1e-6); }
465
466 #[test]
467 fn test_matrix_multiply() {
468 let matrix = Matrix::new();
469 let a = vec![1.0, 2.0, 3.0, 4.0];
471 let b = vec![5.0, 6.0, 7.0, 8.0];
472 let mut result = vec![0.0; 4];
473
474 let matrix_result = matrix.multiply(&a, &b, &mut result, 2, 2, 2).unwrap();
475 assert!(matrix_result.success);
476 assert_eq!(result[0], 19.0);
478 assert_eq!(result[1], 22.0);
479 assert_eq!(result[2], 43.0);
480 assert_eq!(result[3], 50.0);
481 }
482
483 #[test]
484 fn test_matrix_transpose() {
485 let matrix = Matrix::new();
486 let input = vec![1.0, 2.0, 3.0, 4.0]; let mut output = vec![0.0; 4];
488
489 let result = matrix.transpose(&input, &mut output, 2, 2).unwrap();
490 assert!(result.success);
491 assert_eq!(output, vec![1.0, 3.0, 2.0, 4.0]);
492 }
493
494 #[test]
495 fn test_determinant_2x2() {
496 let matrix = Matrix::new();
497 let mat = vec![1.0, 2.0, 3.0, 4.0]; let result = matrix.determinant(&mat, 2).unwrap();
500 assert!(result.success);
501 assert_eq!(result.result.unwrap(), -2.0);
502 }
503
504 #[test]
505 fn test_validation_errors() {
506 let matrix = Matrix::new();
507
508 let a = vec![1.0, 2.0];
510 let b = vec![1.0, 2.0, 3.0];
511 let mut result = vec![0.0; 2];
512
513 let matrix_result = matrix.vector_add(&a, &b, &mut result);
514 assert!(matrix_result.is_err());
515 }
516}