1use crate::types::*;
4
5#[derive(Debug, Clone, Copy)]
7pub struct MatrixInstance<'a, T> {
8 pub num_rows: u16,
9 pub num_cols: u16,
10 pub data: &'a [T],
11}
12
13impl<'a, T> MatrixInstance<'a, T> {
14 pub fn new(num_rows: u16, num_cols: u16, data: &'a [T]) -> Self {
15 Self {
16 num_rows,
17 num_cols,
18 data,
19 }
20 }
21}
22
23#[derive(Debug)]
25pub struct MatrixInstanceMut<'a, T> {
26 pub num_rows: u16,
27 pub num_cols: u16,
28 pub data: &'a mut [T],
29}
30
31impl<'a, T> MatrixInstanceMut<'a, T> {
32 pub fn new(num_rows: u16, num_cols: u16, data: &'a mut [T]) -> Self {
33 Self {
34 num_rows,
35 num_cols,
36 data,
37 }
38 }
39}
40
41pub fn mat_add_f32(
44 a: &MatrixInstance<f32>,
45 b: &MatrixInstance<f32>,
46 out: &mut MatrixInstanceMut<f32>,
47) -> Status {
48 if a.num_rows != b.num_rows
49 || a.num_cols != b.num_cols
50 || a.num_rows != out.num_rows
51 || a.num_cols != out.num_cols
52 {
53 return Status::SizeMismatch;
54 }
55 let total = (a.num_rows as usize) * (a.num_cols as usize);
56 if a.data.len() < total || b.data.len() < total || out.data.len() < total {
57 return Status::LengthError;
58 }
59 for i in 0..total {
60 out.data[i] = a.data[i] + b.data[i];
61 }
62 Status::Success
63}
64
65pub fn mat_add_q31(
66 a: &MatrixInstance<q31>,
67 b: &MatrixInstance<q31>,
68 out: &mut MatrixInstanceMut<q31>,
69) -> Status {
70 if a.num_rows != b.num_rows
71 || a.num_cols != b.num_cols
72 || a.num_rows != out.num_rows
73 || a.num_cols != out.num_cols
74 {
75 return Status::SizeMismatch;
76 }
77 let total = (a.num_rows as usize) * (a.num_cols as usize);
78 if a.data.len() < total || b.data.len() < total || out.data.len() < total {
79 return Status::LengthError;
80 }
81 for i in 0..total {
82 out.data[i] = a.data[i].saturating_add(b.data[i]);
83 }
84 Status::Success
85}
86
87pub fn mat_add_q15(
88 a: &MatrixInstance<q15>,
89 b: &MatrixInstance<q15>,
90 out: &mut MatrixInstanceMut<q15>,
91) -> Status {
92 if a.num_rows != b.num_rows
93 || a.num_cols != b.num_cols
94 || a.num_rows != out.num_rows
95 || a.num_cols != out.num_cols
96 {
97 return Status::SizeMismatch;
98 }
99 let total = (a.num_rows as usize) * (a.num_cols as usize);
100 if a.data.len() < total || b.data.len() < total || out.data.len() < total {
101 return Status::LengthError;
102 }
103 for i in 0..total {
104 out.data[i] = a.data[i].saturating_add(b.data[i]);
105 }
106 Status::Success
107}
108
109pub fn mat_sub_f32(
112 a: &MatrixInstance<f32>,
113 b: &MatrixInstance<f32>,
114 out: &mut MatrixInstanceMut<f32>,
115) -> Status {
116 if a.num_rows != b.num_rows
117 || a.num_cols != b.num_cols
118 || a.num_rows != out.num_rows
119 || a.num_cols != out.num_cols
120 {
121 return Status::SizeMismatch;
122 }
123 let total = (a.num_rows as usize) * (a.num_cols as usize);
124 if a.data.len() < total || b.data.len() < total || out.data.len() < total {
125 return Status::LengthError;
126 }
127 for i in 0..total {
128 out.data[i] = a.data[i] - b.data[i];
129 }
130 Status::Success
131}
132
133pub fn mat_sub_q31(
134 a: &MatrixInstance<q31>,
135 b: &MatrixInstance<q31>,
136 out: &mut MatrixInstanceMut<q31>,
137) -> Status {
138 if a.num_rows != b.num_rows
139 || a.num_cols != b.num_cols
140 || a.num_rows != out.num_rows
141 || a.num_cols != out.num_cols
142 {
143 return Status::SizeMismatch;
144 }
145 let total = (a.num_rows as usize) * (a.num_cols as usize);
146 if a.data.len() < total || b.data.len() < total || out.data.len() < total {
147 return Status::LengthError;
148 }
149 for i in 0..total {
150 out.data[i] = a.data[i].saturating_sub(b.data[i]);
151 }
152 Status::Success
153}
154
155pub fn mat_sub_q15(
156 a: &MatrixInstance<q15>,
157 b: &MatrixInstance<q15>,
158 out: &mut MatrixInstanceMut<q15>,
159) -> Status {
160 if a.num_rows != b.num_rows
161 || a.num_cols != b.num_cols
162 || a.num_rows != out.num_rows
163 || a.num_cols != out.num_cols
164 {
165 return Status::SizeMismatch;
166 }
167 let total = (a.num_rows as usize) * (a.num_cols as usize);
168 if a.data.len() < total || b.data.len() < total || out.data.len() < total {
169 return Status::LengthError;
170 }
171 for i in 0..total {
172 out.data[i] = a.data[i].saturating_sub(b.data[i]);
173 }
174 Status::Success
175}
176
177pub fn mat_mult_f32(
180 a: &MatrixInstance<f32>,
181 b: &MatrixInstance<f32>,
182 out: &mut MatrixInstanceMut<f32>,
183) -> Status {
184 if a.num_cols != b.num_rows || a.num_rows != out.num_rows || b.num_cols != out.num_cols {
185 return Status::SizeMismatch;
186 }
187 let rows_a = a.num_rows as usize;
188 let cols_a = a.num_cols as usize;
189 let cols_b = b.num_cols as usize;
190
191 for r in 0..rows_a {
192 for c in 0..cols_b {
193 let mut sum = 0.0f32;
194 for k in 0..cols_a {
195 sum += a.data[r * cols_a + k] * b.data[k * cols_b + c];
196 }
197 out.data[r * cols_b + c] = sum;
198 }
199 }
200 Status::Success
201}
202
203pub fn mat_mult_q31(
204 a: &MatrixInstance<q31>,
205 b: &MatrixInstance<q31>,
206 out: &mut MatrixInstanceMut<q31>,
207) -> Status {
208 if a.num_cols != b.num_rows || a.num_rows != out.num_rows || b.num_cols != out.num_cols {
209 return Status::SizeMismatch;
210 }
211 let rows_a = a.num_rows as usize;
212 let cols_a = a.num_cols as usize;
213 let cols_b = b.num_cols as usize;
214
215 for r in 0..rows_a {
216 for c in 0..cols_b {
217 let mut sum: i64 = 0;
218 for k in 0..cols_a {
219 sum +=
220 (a.data[r * cols_a + k].to_bits() as i64
221 * b.data[k * cols_b + c].to_bits() as i64)
222 >> 31;
223 }
224 out.data[r * cols_b + c] =
225 q31::from_bits(sum.clamp(i32::MIN as i64, i32::MAX as i64) as i32);
226 }
227 }
228 Status::Success
229}
230
231pub fn mat_mult_q15(
232 a: &MatrixInstance<q15>,
233 b: &MatrixInstance<q15>,
234 out: &mut MatrixInstanceMut<q15>,
235) -> Status {
236 if a.num_cols != b.num_rows || a.num_rows != out.num_rows || b.num_cols != out.num_cols {
237 return Status::SizeMismatch;
238 }
239 let rows_a = a.num_rows as usize;
240 let cols_a = a.num_cols as usize;
241 let cols_b = b.num_cols as usize;
242
243 for r in 0..rows_a {
244 for c in 0..cols_b {
245 let mut sum: i32 = 0;
246 for k in 0..cols_a {
247 sum += (a.data[r * cols_a + k].to_bits() as i32
248 * b.data[k * cols_b + c].to_bits() as i32)
249 >> 15;
250 }
251 out.data[r * cols_b + c] =
252 q15::from_bits(sum.clamp(i16::MIN as i32, i16::MAX as i32) as i16);
253 }
254 }
255 Status::Success
256}
257
258pub fn mat_scale_f32(
261 src: &MatrixInstance<f32>,
262 scale: f32,
263 out: &mut MatrixInstanceMut<f32>,
264) -> Status {
265 if src.num_rows != out.num_rows || src.num_cols != out.num_cols {
266 return Status::SizeMismatch;
267 }
268 let total = (src.num_rows as usize) * (src.num_cols as usize);
269 for i in 0..total {
270 out.data[i] = src.data[i] * scale;
271 }
272 Status::Success
273}
274
275pub fn mat_scale_q31(
276 src: &MatrixInstance<q31>,
277 scale_fract: q31,
278 shift: i8,
279 out: &mut MatrixInstanceMut<q31>,
280) -> Status {
281 if src.num_rows != out.num_rows || src.num_cols != out.num_cols {
282 return Status::SizeMismatch;
283 }
284 let total = (src.num_rows as usize) * (src.num_cols as usize);
285 crate::basic_math::scale_q31(
286 &src.data[..total],
287 scale_fract,
288 shift,
289 &mut out.data[..total],
290 );
291 Status::Success
292}
293
294pub fn mat_scale_q15(
295 src: &MatrixInstance<q15>,
296 scale_fract: q15,
297 shift: i8,
298 out: &mut MatrixInstanceMut<q15>,
299) -> Status {
300 if src.num_rows != out.num_rows || src.num_cols != out.num_cols {
301 return Status::SizeMismatch;
302 }
303 let total = (src.num_rows as usize) * (src.num_cols as usize);
304 crate::basic_math::scale_q15(
305 &src.data[..total],
306 scale_fract,
307 shift,
308 &mut out.data[..total],
309 );
310 Status::Success
311}
312
313pub fn mat_trans_f32(src: &MatrixInstance<f32>, out: &mut MatrixInstanceMut<f32>) -> Status {
316 if src.num_rows != out.num_cols || src.num_cols != out.num_rows {
317 return Status::SizeMismatch;
318 }
319 let rows = src.num_rows as usize;
320 let cols = src.num_cols as usize;
321
322 for r in 0..rows {
323 for c in 0..cols {
324 out.data[c * rows + r] = src.data[r * cols + c];
325 }
326 }
327 Status::Success
328}
329
330pub fn mat_trans_q31(src: &MatrixInstance<q31>, out: &mut MatrixInstanceMut<q31>) -> Status {
331 if src.num_rows != out.num_cols || src.num_cols != out.num_rows {
332 return Status::SizeMismatch;
333 }
334 let rows = src.num_rows as usize;
335 let cols = src.num_cols as usize;
336
337 for r in 0..rows {
338 for c in 0..cols {
339 out.data[c * rows + r] = src.data[r * cols + c];
340 }
341 }
342 Status::Success
343}
344
345pub fn mat_trans_q15(src: &MatrixInstance<q15>, out: &mut MatrixInstanceMut<q15>) -> Status {
346 if src.num_rows != out.num_cols || src.num_cols != out.num_rows {
347 return Status::SizeMismatch;
348 }
349 let rows = src.num_rows as usize;
350 let cols = src.num_cols as usize;
351
352 for r in 0..rows {
353 for c in 0..cols {
354 out.data[c * rows + r] = src.data[r * cols + c];
355 }
356 }
357 Status::Success
358}
359
360pub fn mat_inverse_f32(src: &MatrixInstance<f32>, out: &mut MatrixInstanceMut<f32>) -> Status {
363 if src.num_rows != src.num_cols || out.num_rows != out.num_cols || src.num_rows != out.num_rows
364 {
365 return Status::SizeMismatch;
366 }
367 let n = src.num_rows as usize;
368 if n == 0 {
369 return Status::SizeMismatch;
370 }
371
372 let mut aug = [0.0f32; 16 * 32];
375 if n > 16 {
376 return Status::ArgumentError; }
378
379 for r in 0..n {
380 for c in 0..n {
381 aug[r * 2 * n + c] = src.data[r * n + c];
382 aug[r * 2 * n + n + c] = if r == c { 1.0 } else { 0.0 };
383 }
384 }
385
386 for i in 0..n {
387 let mut max_row = i;
389 let mut max_val = aug[i * 2 * n + i].abs();
390 for r in (i + 1)..n {
391 let val = aug[r * 2 * n + i].abs();
392 if val > max_val {
393 max_val = val;
394 max_row = r;
395 }
396 }
397
398 if max_val < 1e-12 {
399 return Status::Singular;
400 }
401
402 if max_row != i {
404 for c in 0..(2 * n) {
405 aug.swap(i * 2 * n + c, max_row * 2 * n + c);
406 }
407 }
408
409 let pivot = aug[i * 2 * n + i];
410 for c in 0..(2 * n) {
411 aug[i * 2 * n + c] /= pivot;
412 }
413
414 for r in 0..n {
415 if r != i {
416 let factor = aug[r * 2 * n + i];
417 for c in 0..(2 * n) {
418 let sub = factor * aug[i * 2 * n + c];
419 aug[r * 2 * n + c] -= sub;
420 }
421 }
422 }
423 }
424
425 for r in 0..n {
426 for c in 0..n {
427 out.data[r * n + c] = aug[r * 2 * n + n + c];
428 }
429 }
430
431 Status::Success
432}
433
434pub fn polynomial_least_squares_fit(
444 x: &[f32],
445 y: &[f32],
446 weights: Option<&[f32]>,
447 degree: usize,
448 out_coeffs: &mut [f32],
449) -> Status {
450 let n = x.len();
451 let m = degree + 1; if n == 0 || y.len() != n || out_coeffs.len() < m || n < m {
454 return Status::LengthError;
455 }
456 if let Some(w) = weights {
457 if w.len() != n {
458 return Status::LengthError;
459 }
460 }
461 if degree > 15 {
462 return Status::ArgumentError; }
464
465 let mut aug = [0.0f32; 16 * 17];
468 let cols = m + 1;
469
470 for i in 0..n {
471 let w = if let Some(weights_slice) = weights {
472 weights_slice[i]
473 } else {
474 1.0f32
475 };
476 let xi = x[i];
477 let yi = y[i];
478
479 let mut x_powers = [1.0f32; 32];
481 for p in 1..(2 * m) {
482 x_powers[p] = x_powers[p - 1] * xi;
483 }
484
485 for j in 0..m {
486 let w_xi_j = w * x_powers[j];
487 for k in 0..m {
488 aug[j * cols + k] += w_xi_j * x_powers[k];
489 }
490 aug[j * cols + m] += w_xi_j * yi;
491 }
492 }
493
494 for i in 0..m {
496 let mut max_row = i;
498 let mut max_val = aug[i * cols + i].abs();
499 for r in (i + 1)..m {
500 let val = aug[r * cols + i].abs();
501 if val > max_val {
502 max_val = val;
503 max_row = r;
504 }
505 }
506
507 if max_val < 1e-12 {
508 return Status::Singular;
509 }
510
511 if max_row != i {
512 for c in 0..cols {
513 aug.swap(i * cols + c, max_row * cols + c);
514 }
515 }
516
517 let pivot = aug[i * cols + i];
518 for c in 0..cols {
519 aug[i * cols + c] /= pivot;
520 }
521
522 for r in 0..m {
523 if r != i {
524 let factor = aug[r * cols + i];
525 for c in 0..cols {
526 let sub = factor * aug[i * cols + c];
527 aug[r * cols + c] -= sub;
528 }
529 }
530 }
531 }
532
533 for i in 0..m {
534 out_coeffs[i] = aug[i * cols + m];
535 }
536
537 Status::Success
538}
539
540pub fn polynomial_eval_f32(coeffs: &[f32], x: f32) -> f32 {
542 if coeffs.is_empty() {
543 return 0.0;
544 }
545 let mut result = coeffs[coeffs.len() - 1];
546 for &c in coeffs[..coeffs.len() - 1].iter().rev() {
547 result = result * x + c;
548 }
549 result
550}