matrix_mc/lib.rs
1//! # Matrix-MC
2//!
3//! 'matrix_mc' is a library which provides useful functions for
4//! operating on and analyzing matrices of f64s
5
6/// 2D Vector of f64s
7pub type Matrix = Vec<Vec<f64>>;
8
9/// Returns a square Identity Matrix with length and width
10/// provided by the parameter dim.
11///
12/// # Examples
13///
14/// ```
15/// use matrix_mc::{matrix, identity};
16///
17/// let method1 = matrix![
18/// 1, 0, 0;
19/// 0, 1, 0;
20/// 0, 0, 1
21/// ];
22///
23/// let method2 = identity(3);
24///
25/// assert_eq!(method1, method2);
26/// ```
27pub fn identity(dim: usize) -> Matrix {
28 let mut result = Vec::with_capacity(dim);
29
30 for i in 0..dim {
31 result.push(Vec::with_capacity(dim));
32 for j in 0..dim {
33 let a = if i == j { 1f64 } else { 0f64 };
34 result[i].push(a);
35 }
36 }
37
38 result
39}
40
41/// Row reduces the target matrix a.
42///
43/// # Examples
44///
45/// ```
46/// use matrix_mc::{matrix, rref};
47///
48/// let mut matrix = matrix![
49/// 1, 2, 3;
50/// 4, 5, 6;
51/// 7, 8, 9
52/// ];
53///
54/// let result = matrix![
55/// 1, 0, -1;
56/// 0, 1, 2;
57/// 0, 0, 0
58/// ];
59///
60/// rref(&mut matrix);
61///
62/// assert_eq!(matrix, result);
63/// ```
64pub fn rref(a: &mut Matrix) {
65 let mut i = 0usize;
66 while i < a.len() && i < a[0].len() {
67 let divisor = a[i][i];
68 if divisor != 0f64 {
69 for j in (0..a.len()).filter(|j| *j != i) {
70 let dividend = a[j][i];
71 for k in 0..a[j].len() {
72 a[j][k] -= a[i][k] * (dividend / divisor);
73 }
74 }
75 }
76 i += 1;
77 }
78
79 i = 0;
80 while i < a.len() && i < a[0].len() {
81 let divisor = a[i][i];
82 if divisor != 0f64 {
83 for j in 0..a[i].len() {
84 a[i][j] /= divisor;
85 }
86 }
87 i += 1;
88 }
89}
90
91/// Calculates the Euclidian (square root) norm of the provided matrix a
92///
93/// # Examples
94///
95/// ```
96/// use matrix_mc::{matrix, normalize};
97///
98/// let mut matrix = matrix![
99/// 1, 3, 2;
100/// 0, 0, 1;
101/// 0, 4, 2
102/// ];
103///
104/// let result = matrix![
105/// 1, 3./5., 2./3.;
106/// 0, 0, 1./3.;
107/// 0, 4./5., 2./3.
108/// ];
109///
110/// normalize(&mut matrix);
111///
112/// assert_eq!(matrix, result);
113/// ```
114pub fn normalize(a: &mut Matrix) {
115 for i in 0..a.len() {
116 let mut sum = 0f64;
117
118 for j in 0..a[0].len() {
119 sum += a[j][i] * a[j][i];
120 }
121 let length = f64::sqrt(sum);
122
123 for j in 0..a[0].len() {
124 a[j][i] /= length;
125 }
126 }
127}
128
129/// Applies the provided funtion f to the matrix a,
130/// returning a new matrix with the result of the
131/// computation, leaving the original matrix unchanged
132///
133/// # Examples
134///
135/// ```
136/// use matrix_mc::{rref, identity, dup, matrix, Matrix};
137///
138/// let arg: Matrix = matrix![2, 3, 4;
139/// 5, 6, 7;
140/// 9, 2, 0];
141///
142/// let reduced: Matrix = dup(rref, &arg);
143///
144/// assert_eq!(reduced, identity(3usize));
145/// assert_ne!(arg, reduced);
146/// ```
147pub fn dup<F>(f: F, a: &Matrix) -> Matrix
148where
149 F: FnOnce(&mut Matrix),
150{
151 let mut temp = a.clone();
152 f(&mut temp);
153 temp
154}
155
156/// Provides a concise syntax for creating Matrices of f64s,
157/// Creates a new Matrix, and adds every number seperated by a
158/// comma as a f64, and adds a new row for each semicolon. if
159/// rows are of unequal size, 0s are added to make up for the
160/// difference
161///
162/// # Examples
163///
164/// ```
165/// use matrix_mc::{matrix, Matrix};
166///
167/// let macro_matrix: Matrix = matrix!
168/// [0, 1, 2;
169/// 1, 1;
170/// 2, 3, 4];
171///
172/// let manual_matrix: Matrix = {
173/// let mut temp_matrix: Matrix = Vec::with_capacity(3);
174///
175/// let mut temp_vector: Vec<f64> = Vec::with_capacity(3);
176/// temp_vector.push(0f64);
177/// temp_vector.push(1f64);
178/// temp_vector.push(2f64);
179///
180/// temp_matrix.push(temp_vector);
181///
182/// let mut temp_vector: Vec<f64> = Vec::with_capacity(3);
183/// temp_vector.push(1f64);
184/// temp_vector.push(1f64);
185/// temp_vector.push(0f64);
186///
187/// temp_matrix.push(temp_vector);
188///
189/// let mut temp_vector: Vec<f64> = Vec::with_capacity(3);
190/// temp_vector.push(2f64);
191/// temp_vector.push(3f64);
192/// temp_vector.push(4f64);
193///
194/// temp_matrix.push(temp_vector);
195///
196/// temp_matrix
197/// };
198///
199/// assert_eq!(macro_matrix, manual_matrix);
200/// ```
201#[macro_export(local_inner_macros)]
202macro_rules! matrix {
203 ($( $( $x:expr ),* );* ) => {
204 {
205 let (row_max, col_max) = {
206 let mut temp_vec: Vec<usize> = Vec::with_capacity( count_tts!($( $( $x )* )*) );
207
208 $(
209 let row_max = count_tts!($( $x )* );
210 temp_vec.push(row_max);
211 )*
212
213 (*temp_vec.iter().max().unwrap(), temp_vec.len())
214 };
215
216 let mut temp_matrix = Vec::with_capacity(col_max);
217
218 $(
219 let mut temp_vec = Vec::with_capacity(row_max);
220
221 $(
222 temp_vec.push($x as f64);
223 )*
224
225 while temp_vec.len() < row_max {
226 temp_vec.push(0f64);
227 }
228
229 temp_matrix.push(temp_vec);
230 )*
231
232 temp_matrix
233 }
234 };
235}
236
237#[doc(hidden)]
238#[macro_export]
239macro_rules! replace_expr {
240 ($_t:tt $sub:expr) => {
241 $sub
242 };
243}
244
245#[doc(hidden)]
246#[macro_export]
247macro_rules! count_tts {
248 ($($tts:tt)*) => {
249 0usize $(+ matrix_mc::replace_expr!($tts 1usize))*
250 };
251}