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}