1use std::fmt::Display;
2use std::ops::{Add, AddAssign, Mul, MulAssign, Sub};
3use num_traits::{Num, Signed};
4use rand::distributions::uniform::SampleUniform;
5use crate::util::{ErrorKind, NmlError};
6use rand::Rng;
7use crate::util::ErrorKind::{CreateMatrix, InvalidCols, InvalidRows};
8
9
10#[derive(Debug)]
13pub struct NmlMatrix<T> {
14 pub num_rows: u32,
15 pub num_cols: u32,
16 pub data: Box<[T]>,
17 pub is_square: bool,
18}
19
20impl<T> NmlMatrix<T> where T: Num + Copy + Default + Signed + PartialOrd + MulAssign + AddAssign + Display + SampleUniform {
21 pub fn new(num_rows: u32, num_cols: u32) -> NmlMatrix<T> {
23 let data: Box<[T]> = vec![T::default(); (num_rows * num_cols) as usize].into_boxed_slice();
24 Self {
25 num_rows,
26 num_cols,
27 data,
28 is_square: num_rows == num_cols,
29 }
30 }
31 pub fn new_with_2d_vec(num_rows: u32, num_cols: u32, data_2d: &mut Vec<Vec<T>>) -> Result<Self, NmlError> {
33 let rows: u32 = data_2d.len() as u32;
34 let mut cols_match = true;
35 let mut vec_data: Vec<T> = Vec::with_capacity((num_rows*num_cols) as usize);
36 for element in data_2d {
37 if element.len() as u32 != num_cols {
38 cols_match = false;
39 break;
40 }
41 vec_data.append(element);
42 }
43 let data: Box<[T]> = vec_data.into_boxed_slice();
44 match cols_match && rows == num_rows{
45 true => {Ok(Self{
46 num_cols,
47 num_rows,
48 data,
49 is_square: num_rows == num_rows
50 })},
51 false => {Err(NmlError::new(ErrorKind::CreateMatrix))}
52 }
53 }
54
55 pub fn new_with_data(num_rows: u32, num_cols: u32, data: Box<[T]>) -> Result<Self, NmlError> {
57 match (num_rows * num_cols) as usize == data.len() {
58 false => Err(NmlError::new(ErrorKind::CreateMatrix)),
59 true => {
60 let is_square = num_rows == num_cols;
61 Ok(NmlMatrix {
62 num_rows,
63 num_cols,
64 data,
65 is_square,
66 })
67 },
68 }
69 }
70
71 pub fn nml_mat_rnd(num_rows: u32, num_cols: u32, minimum: T, maximum: T) -> Self {
73 let mut rng = rand::thread_rng();
74 let random_numbers: Vec<T> = (0..100).map(|_| (rng.gen_range(minimum..maximum))).collect();
75 Self {
76 num_rows,
77 num_cols,
78 data: random_numbers.into_boxed_slice(),
79 is_square: num_rows == num_cols,
80 }
81 }
82
83 pub fn nml_mat_sqr(size: u32) -> Self {
85 Self {
86 num_rows: size,
87 num_cols: size,
88 data: vec![T::default(); (size * size) as usize].into_boxed_slice(),
89 is_square: true,
90 }
91 }
92
93 pub fn nml_mat_eye(size: u32) -> Self {
95 let mut data: Vec<T> = vec![T::default(); (size * size) as usize];
96 for i in 0..size {
97 data[(i * size + i) as usize] = T::one();
98 }
99 Self {
100 num_rows: size,
101 num_cols: size,
102 data: data.into_boxed_slice(),
103 is_square: true,
104 }
105 }
106 pub fn nml_mat_cp(matrix: &NmlMatrix<T>) -> Self {
108 Self {
109 num_rows: matrix.num_rows,
110 num_cols: matrix.num_cols,
111 data: matrix.data.clone(),
112 is_square: matrix.is_square,
113 }
114 }
115
116 pub fn equality(self: &Self, matrix: &NmlMatrix<T>) -> bool {
118 if self.num_rows != matrix.num_rows || self.num_cols != matrix.num_cols {
119 return false;
120 }
121 for i in 0..self.num_rows {
122 for j in 0..self.num_cols {
123 if self.data[(i * self.num_cols + j) as usize] != matrix.data[(i * matrix.num_cols + j) as usize] {
124 return false;
125 }
126 }
127 }
128 true
129 }
130 pub fn equality_in_tolerance(self: &Self, matrix: NmlMatrix<T>, tolerance: T) -> bool {
132 if self.num_rows != matrix.num_rows || self.num_cols != matrix.num_cols {
133 return false;
134 }
135 for i in 0..self.num_rows {
136 for j in 0..self.num_cols {
137 if (self.data[(i * self.num_cols + j) as usize] - matrix.data[(i * matrix.num_cols + j) as usize]).abs() > tolerance {
138 return false;
139 }
140 }
141 }
142 true
143 }
144
145 pub fn at(self: &Self, row: u32, col: u32) -> Result<T, NmlError> {
147 match row < self.num_rows as u32 && col < self.num_cols as u32 {
148 false => Err(NmlError::new(InvalidRows)),
149 true => Ok(self.data[(row * self.num_cols + col) as usize]),
150 }
151 }
152
153 pub fn get_column(self: &Self, column: u32) -> Result<Self, NmlError> {
155 match column < self.num_cols {
156 false => Err(NmlError::new(InvalidCols)),
157 true => {
158 let mut data: Vec<T> = Vec::with_capacity(self.num_rows as usize);
159 for i in 0..self.num_rows {
160 data.push(self.data[(i * self.num_rows + column) as usize]);
161 }
162 Ok(Self {
163 num_cols: 1,
164 num_rows: self.num_rows,
165 data: data.into_boxed_slice(),
166 is_square: false
167 })
168 },
169 }
170 }
171
172 pub fn get_row(self: &Self, row: u32) -> Result<Self, NmlError> {
174 match row < self.num_rows {
175 true => {
176 let data: Vec<T> = self.data[(row * self.num_cols) as usize..(row * self.num_cols + self.num_cols) as usize].to_vec().clone();
177 Ok(Self {
178 num_cols: self.num_cols,
179 num_rows: 1,
180 data: data.into_boxed_slice(),
181 is_square: false
182 })
183 },
184 false => Err(NmlError::new(InvalidRows)),
185 }
186 }
187 pub fn set_value(self: &mut Self, row: u32, col: u32, data: T) -> Result<(), NmlError> {
189 let valid_tuple: (bool, bool) = (row < self.num_rows, col < self.num_cols);
190 match valid_tuple {
191 (false, _) => Err(NmlError::new(InvalidRows)),
192 (_, false) => Err(NmlError::new(InvalidCols)),
193 (true, true) => {
194 self.data[(row * self.num_cols + col) as usize] = data;
195 Ok(())
196 },
197 }
198 }
199 pub fn set_all_values(self: &mut Self, value: T) {
201 for i in 0..self.num_rows {
202 for j in 0..self.num_cols {
203 self.data[(i * self.num_cols + j) as usize] = value;
204 }
205 }
206 }
207 pub fn set_dig_values(self: &mut Self, value: T) -> Result<(), NmlError> {
209 if self.is_square == true {
210 for i in 0..self.num_rows {
211 self.data[(i * self.num_cols + i) as usize] = value;
212 }
213 }
214 match self.is_square {
215 true => Ok(()),
216 false => Err(NmlError::new(ErrorKind::MatrixNotSquare)),
217 }
218 }
219 pub fn multiply_row_scalar(self: &mut Self, row: u32, scalar: T) -> Result<(), NmlError> {
221 match row < self.num_rows {
222 false => Err(NmlError::new(InvalidRows)),
223 true => {
224 for i in 0..self.num_cols {
225 self.data[(row * self.num_cols + i) as usize] *= scalar;
226 }
227 Ok(())
228 },
229 }
230 }
231 pub fn multiply_col_scalar(self: &mut Self, col: u32, scalar: T) -> Result<(), NmlError> {
233 match col < self.num_cols {
234 false => Err(NmlError::new(InvalidCols)),
235 true => {
236 for i in 0..self.num_rows {
237 self.data[(i * self.num_cols + col) as usize] *= scalar;
238 }
239 Ok(())
240 }
241 }
242 }
243 pub fn multiply_matrix_scalar(self: &mut Self, scalar: T) {
245 for i in 0..self.data.len() {
246 self.data[i] *= scalar;
247 }
248 }
249
250 pub fn add_rows(self: &mut Self, row_1: u32, scalar_1: T, row_2: u32, scalar_2: T) -> Result<(), NmlError> {
252 match row_1 < self.num_rows && row_2 < self.num_rows {
253 false => Err(NmlError::new(InvalidRows)),
254 true => {
255 for i in 0..self.num_cols {
256 let value = self.data[(row_1 * self.num_cols + i) as usize];
257 self.data[(row_1 * self.num_cols + i) as usize] = value * scalar_1 + self.data[(row_2 * self.num_cols + i) as usize] * scalar_2;
258 }
259 Ok(())
260 }
261 }
262 }
263 pub fn swap_rows(self: &mut Self, row_1: u32, row_2: u32) -> Result<(), NmlError> {
265 match row_1 < self.num_rows && row_2 < self.num_rows {
266 false => Err(NmlError::new(InvalidRows)),
267 true => {
268 for i in 0..self.num_cols {
269 let temp = self.data[(row_1 * self.num_cols + i) as usize];
270 self.data[(row_1 * self.num_cols + i) as usize] = self.data[(row_2 * self.num_cols + i) as usize];
271 self.data[(row_2 * self.num_cols + i) as usize] = temp;
272 }
273 Ok(())
274 }
275 }
276 }
277 pub fn swap_columns(self: &mut Self, col_1: u32, col_2: u32) -> Result<(), NmlError> {
279 match col_1 < self.num_cols && col_2 < self.num_cols {
280 false => Err(NmlError::new(InvalidCols)),
281 true => {
282 for i in 0..self.num_rows {
283 let temp = self.data[(i * self.num_cols + col_1) as usize];
284 self.data[(i * self.num_cols + col_1) as usize] = self.data[(i * self.num_cols + col_2) as usize];
285 self.data[(i * self.num_cols + col_2) as usize] = temp;
286 }
287 Ok(())
288 }
289 }
290 }
291 pub fn remove_column(self: &Self, col: u32) -> Result<Self, NmlError> {
294 match col < self.num_cols {
295 false => Err(NmlError::new(InvalidCols)),
296 true => {
297 let mut data: Vec<T> = Vec::with_capacity(self.data.len());
298 let indexes: Vec<usize> = (col as usize..self.data.len()).step_by(self.num_cols as usize).collect();
299 for i in 0..self.data.len() {
300 if !indexes.contains(&i) {
301 data.push(self.data[i]);
302 }
303 }
304 Ok(
305 Self {
306 num_cols: 1,
307 num_rows: self.num_rows,
308 data: data.into_boxed_slice(),
309 is_square: false
310 }
311 )
312 }
313 }
314 }
315 pub fn remove_row(self: &Self, row: u32) -> Result<Self, NmlError> {
318 match row < self.num_rows {
319 false => Err(NmlError::new(InvalidRows)),
320 true => {
321 let data: Vec<T> = self.data[((row + 1) * self.num_cols) as usize..self.data.len()].to_vec();
322 Ok(Self {
323 num_cols: self.num_cols,
324 num_rows: 1,
325 data: data.into_boxed_slice(),
326 is_square: false,
327 })
328 }
329 }
330 }
331
332 pub fn get_sub_mtr(self: &Self, row_start: u32, row_end: u32, col_start: u32, col_end: u32) -> Result<Self, NmlError> {
333 match row_start < self.num_rows && row_end < self.num_rows && col_start < self.num_cols && col_end < self.num_cols {
334 false => Err(NmlError::new(InvalidRows)),
335 true => {
336 let mut data: Vec<T> = Vec::new();
337 for i in row_start - 1..row_end {
338 for j in col_start - 1..col_end {
339 data.push(self.data[(i * self.num_cols + j) as usize]);
340 }
341 }
342 Ok(Self {
343 num_rows: row_end - row_start,
344 num_cols: col_end - col_start,
345 data: data.into_boxed_slice(),
346 is_square: false,
347 })
348 }
349 }
350 }
351
352 pub fn transpose(self: &Self) -> Self{
354 let mut data: Vec<T> = Vec::with_capacity(self.data.len());
355 for i in 0..self.num_cols {
356 for j in 0..self.num_rows {
357 data.push(self.data[(i + j*self.num_cols) as usize]);
358 }
359 }
360 Self {
361 num_rows: self.num_cols,
362 num_cols: self.num_rows,
363 data: data.into_boxed_slice(),
364 is_square: self.is_square,
365 }
366 }
367 pub fn mul_transpose(self: &Self, other: &Self) -> Result<Self, NmlError> {
369 match self.num_cols == other.num_rows {
370 false => Err(NmlError::new(InvalidCols)),
371 true => {
372 let m: u32 = self.num_rows;
373 let n: u32 = self.num_cols;
374 let p: u32 = other.num_cols;
375 let transpose: NmlMatrix<T> = other.transpose();
376 let mut data: Vec<T> = Vec::new();
377 for i in 0..m {
378 for j in 0..p {
379 data.insert((i * p + j) as usize, T::default());
380 for k in 0..n {
381 data[(i*p+j) as usize] += self.data[(i * n + k) as usize] * transpose.data[(p * k + j) as usize];
382 }
383 }
384 }
385 Ok(Self{
386 num_rows: self.num_rows,
387 num_cols: other.num_cols,
388 data: data.into_boxed_slice(),
389 is_square: self.num_rows == other.num_cols
390 })
391 }
392 }
393 }
394 pub fn mul_naive(self: &Self, other: &Self) -> Result<Self,NmlError> {
396 let m = self.num_rows;
397 let n_1 = self.num_cols;
398 let n_2 = other.num_rows;
399 let p = other.num_cols;
400 match n_1 == n_2 {
401 false => {Err(NmlError::new(CreateMatrix))},
402 true => {
403 let mut data: Vec<T> = Vec::with_capacity((m*p) as usize);
404 for i in 0..m {
405 for j in 0..p {
406 data.insert((i * p + j) as usize, T::default());
407 for k in 0..n_1 {
408 data[(i*p+j) as usize] += self.data[(i * n_1 + k) as usize] * other.data[(p * k + j) as usize];
409 }
410 }
411 }
412 Ok(Self{
413 num_rows: m,
414 num_cols: p,
415 data: data.into_boxed_slice(),
416 is_square: m == p,
417 })
418 }
419 }
420 }
421
422 pub fn evcxr_display(&self) {
423 let mut html = String::new();
424 html.push_str("<table>");
425 for i in 0..self.num_rows {
426 html.push_str("<tr>");
427 for j in 0..self.num_cols {
428 html.push_str("<td>");
429 html.push_str(&self.data[(i * self.num_cols + j) as usize].to_string());
430 html.push_str("</td>");
431 }
432 html.push_str("</tr>");
433 }
434 html.push_str("</table>");
435 println!("EVCXR_BEGIN_CONTENT text/html\n{}\nEVCXR_END_CONTENT", html);
436 }
437
438}
439impl<T> Sub for NmlMatrix<T> where T: Num + Copy + Default + Signed + PartialOrd + MulAssign + AddAssign {
440 type Output = Result<Self, NmlError>;
441
442 fn sub(self, rhs: Self) -> Self::Output {
443 match self.num_rows == rhs.num_rows && self.num_cols == rhs.num_cols {
444 false => Err(NmlError::new(CreateMatrix)),
445 true => {
446 let mut data: Vec<T> = Vec::new();
447 for i in 0..self.data.len() -1 {
448 data.push(self.data[i] - rhs.data[i]);
449 }
450 Ok(Self{
451 num_rows: self.num_rows,
452 num_cols: self.num_cols,
453 data: data.into_boxed_slice(),
454 is_square: self.is_square
455 })
456 }
457 }
458 }
459}
460
461impl<T> Sub for &NmlMatrix<T> where T: Num + Copy + Default + Signed + PartialOrd + MulAssign + AddAssign {
462 type Output = Result<NmlMatrix<T>, NmlError>;
463
464 fn sub(self, rhs: Self) -> Self::Output {
465 match self.num_rows == rhs.num_rows && self.num_cols == rhs.num_cols {
466 false => Err(NmlError::new(CreateMatrix)),
467 true => {
468 let mut data: Vec<T> = Vec::new();
469 for i in 0..self.data.len() -1 {
470 data.push(self.data[i] - rhs.data[i]);
471 }
472 Ok(NmlMatrix{
473 num_rows: self.num_rows,
474 num_cols: self.num_cols,
475 data: data.into_boxed_slice(),
476 is_square: self.is_square
477 })
478 }
479 }
480 }
481}
482
483impl<T> Display for NmlMatrix<T> where T: Num + Copy + Default + Signed + PartialOrd + MulAssign + AddAssign + Display{
484 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
485 let mut output = String::new();
486 for i in 0..self.num_rows {
487 for j in 0..self.num_cols {
488 output.push_str(&self.data[(i * self.num_cols + j) as usize].to_string());
489 output.push_str(" ");
490 }
491 output.push_str("\n");
492 }
493 write!(f, "{}", output)
494 }
495}
496
497impl<T> Eq for NmlMatrix<T> where T: Num + Copy + Default + Signed + PartialOrd + MulAssign + AddAssign + SampleUniform + Display{}
498impl<T> PartialEq for NmlMatrix<T> where T: Num + Copy + Default + Signed + PartialOrd + MulAssign + AddAssign + SampleUniform + Display{
499 fn eq(&self, other: &Self) -> bool {
500 self.equality(other)
501 }
502}
503
504impl<T> Add for NmlMatrix<T> where T: Num + Copy + Default + Signed + PartialOrd + MulAssign + AddAssign{
505 type Output = Result<Self, NmlError>;
506
507 fn add(self, rhs: Self) -> Self::Output {
508 match self.num_rows == rhs.num_rows && self.num_cols == rhs.num_cols{
509 false => Err(NmlError::new(CreateMatrix)),
510 true => {
511 let mut data: Vec<T> = Vec::new();
512 for i in 0..self.data.len() {
513 data.push(self.data[i] + rhs.data[i]);
514 }
515 Ok(Self{
516 num_cols: self.num_cols,
517 num_rows: self.num_rows,
518 data: data.into_boxed_slice(),
519 is_square: self.is_square
520 })
521 }
522 }
523 }
524}
525
526impl<T> Add for &NmlMatrix<T> where T: Num + Copy + Default + Signed + PartialOrd + MulAssign + AddAssign{
527 type Output = Result<NmlMatrix<T>, NmlError>;
528
529 fn add(self, rhs: Self) -> Self::Output {
530 match self.num_rows == rhs.num_rows && self.num_cols == rhs.num_cols{
531 false => Err(NmlError::new(CreateMatrix)),
532 true => {
533 let mut data: Vec<T> = Vec::new();
534 for i in 0..self.data.len() {
535 data.push(self.data[i] + rhs.data[i]);
536 }
537 Ok(NmlMatrix{
538 num_cols: self.num_cols,
539 num_rows: self.num_rows,
540 data: data.into_boxed_slice(),
541 is_square: self.is_square
542 })
543 }
544 }
545 }
546}
547
548impl<T> Mul for NmlMatrix<T> where T: Num + Copy + Default + Signed + PartialOrd + MulAssign + AddAssign + SampleUniform + Display{
549 type Output = Result<Self<>, NmlError>;
550
551 fn mul(self, rhs: Self) -> Self::Output {
552 return self.mul_naive(&rhs);
553 }
554}
555