matrix_math/utils/
mod.rs

1use crate::enums::MatrixOperation;
2use crate::error::MatrixError;
3use crate::types::{Matrix, MatrixRef};
4
5pub fn nonzero_positive_input<T>(msg: &str, desired_count: Option<T>) -> T
6where
7    T: std::str::FromStr + std::cmp::PartialOrd + std::fmt::Debug,
8    T: num_traits::Unsigned + num_traits::NumCast,
9{
10    use std::io::Write;
11
12    if let Some(count) = desired_count {
13        println!("Count inferred as: {count:?}");
14        return count;
15    }
16
17    let mut input = String::new();
18
19    loop {
20        print!("{}", msg);
21        std::io::stdout().flush().unwrap();
22        std::io::stdin()
23            .read_line(&mut input)
24            .expect("Failed to read line.");
25        println!();
26        match input.trim().parse::<T>() {
27            Ok(result) => {
28                if result < num_traits::cast(1).expect("Infalliable num trait cast.") {
29                    input = String::new();
30                    eprintln!("Error: The Input needs to be greater than 0.");
31                    continue;
32                }
33                return result;
34            }
35            _ => {
36                input = String::new();
37                eprintln!("Error: invalid input");
38                continue;
39            }
40        };
41    }
42}
43
44pub fn numeric_input<T>(msg: &str, predefined: Option<T>) -> T
45where
46    T: std::str::FromStr + std::fmt::Debug + num_traits::Signed,
47{
48    use std::io::Write;
49
50    if let Some(input) = predefined {
51        println!("Input was inferred as: {input:?}");
52        return input;
53    }
54
55    let mut input = String::new();
56
57    loop {
58        print!("{}", msg);
59        std::io::stdout().flush().unwrap();
60        std::io::stdin()
61            .read_line(&mut input)
62            .expect("Failed to read line.");
63        println!();
64        match input.trim().parse::<T>() {
65            Ok(result) => {
66                return result;
67            }
68            _ => {
69                input = String::new();
70                eprintln!("Error: invalid input");
71                continue;
72            }
73        };
74    }
75}
76
77pub fn matrix(n: u32, cols: Option<usize>, rows: Option<usize>) -> Vec<Vec<i32>> {
78    let col_count =
79        nonzero_positive_input::<usize>(&format!("Enter column count for matrix {}: ", n), cols);
80    let row_count =
81        nonzero_positive_input::<usize>(&format!("Enter row count for matrix {}: ", n), rows);
82
83    let mut res: Vec<Vec<i32>> = vec![];
84
85    for col in 1..=col_count {
86        let mut row_content = Vec::with_capacity(col_count);
87        for row in 1..=row_count {
88            row_content.push(numeric_input::<i32>(
89                &format!(
90                    "Enter item at row {} and column {} for matrix {n}: ",
91                    row, col
92                ),
93                None,
94            ));
95        }
96        res.push(row_content);
97    }
98
99    res
100}
101
102/// SAFETY:
103///
104/// This function assumes `m1.len()` == `m2.len()` as well as `m1[0].len()` == `m2[0].len()`.
105/// If you wish to instead handle the errors in the case you're unsure if the lengths are the same
106/// then please use `fn matrix_operation()` and handle the `Result<T, E>` appropriately.
107pub fn matrix_operation_unchecked(
108    op: MatrixOperation,
109    m1: MatrixRef<'_, i32>,
110    m2: MatrixRef<'_, i32>,
111) -> Matrix<i32> {
112    use MatrixOperation as MO;
113
114    let operation: Box<dyn Fn(i32, i32) -> i32> = match op {
115        MO::Addition => Box::new(|a, b| a + b),
116        MO::Subtraction => Box::new(|a, b| a - b),
117        MO::Multiplication => Box::new(|a, b| a * b),
118    };
119
120    m1.iter()
121        .enumerate()
122        .map(|(i, col)| {
123            col.iter()
124                .enumerate()
125                .map(|(j, _)| operation(m1[i][j], m2[i][j]))
126                .collect::<Vec<i32>>()
127        })
128        .collect::<Matrix<i32>>()
129}
130
131#[allow(unused)]
132pub fn matrix_operation<'m>(
133    op: MatrixOperation,
134    m1: MatrixRef<'m, i32>,
135    m2: MatrixRef<'m, i32>,
136) -> Result<Vec<Vec<i32>>, MatrixError<'m, i32>> {
137    use MatrixError as ME;
138
139    if m1.is_empty() {
140        return Err(ME::Empty(m1));
141    }
142    if m2.is_empty() {
143        return Err(ME::Empty(m2));
144    }
145
146    if m1.len() != m2.len() || m1[0].len() != m2[0].len() {
147        return Err(ME::NotEqual(m1, m2));
148    }
149
150    Ok(matrix_operation_unchecked(op, m1, m2))
151}