-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmatrix.rs
129 lines (110 loc) · 3.97 KB
/
matrix.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/// A column-major heap-allocated matrix.
pub struct Matrix<T> { content: Vec<T>, rowc: usize }
impl<T> Matrix<T> where T: Clone {
/// Allocates a matrix with `rowc` rows and `colc` columns, cloning `default`
/// into each cell.
pub fn new_uniform(rowc: usize, colc: usize, default: T) -> Self {
Matrix {
content: vec![default; rowc * colc],
rowc
}
}
pub fn literal<const M: usize, const N: usize>(v: [[T; N]; M]) -> Self {
let mut content: Vec<T> = Vec::with_capacity(M * N);
for n in 0..N {
for m in 0..M {
content.push(v[m][n].clone());
}
}
Self { content, rowc: M }
}
}
impl<T> Matrix<T> where T: Clone + Default {
pub fn new(rowc: usize, colc: usize) -> Self {
Self::new_uniform(rowc, colc, T::default())
}
}
impl<T> Matrix<T> {
pub fn rowc(&self) -> usize { self.rowc }
pub fn colc(&self) -> usize { self.content.len() / self.rowc }
/// Transposes this matrix by allocating a new matrix,
/// moving all values from this matrix into the new matrix,
/// and discarding this matrix.
pub fn transpose(mut self) -> Self {
let (src_rowc, src_colc) = (self.rowc(), self.colc());
let (dst_rowc, dst_colc) = (src_colc, src_rowc);
let size = self.content.len();
let mut content = Vec::with_capacity(size);
let spare = content.spare_capacity_mut();
for (i, value) in self.content.drain(..).enumerate() {
let (src_row, src_col) = (i % src_rowc, i / src_rowc);
let (dst_row, dst_col) = (src_col, src_row);
let dst_i = (dst_col * dst_rowc) + dst_row;
let dst_p = &mut spare[dst_i];
dst_p.write(value);
}
unsafe { content.set_len(size); }
Self { content, rowc: dst_rowc }
}
pub fn get_col(&self, i: usize) -> &[T] {
assert!(i < self.colc());
let begin = self.rowc() * i;
let end = begin + self.rowc();
&self.content[begin..end]
}
pub fn get_col_mut(&mut self, i: usize) -> &mut [T] {
assert!(i < self.colc());
let begin = self.rowc() * i;
let end = begin + self.rowc();
&mut self.content[begin..end]
}
pub fn map<U>(&self, f: impl Fn(&T) -> U) -> Matrix<U>
{
let content: Vec<U> = self.content.iter().map(f).collect();
Matrix { content, rowc: self.rowc }
}
}
impl<T> Clone for Matrix<T> where T: Clone {
fn clone(&self) -> Self {
let size = self.rowc() * self.colc();
let mut content: Vec<T> = Vec::with_capacity(size);
for i in 0..size {
content.push(self.content[i].clone());
}
Matrix { content, rowc: self.rowc() }
}
}
/// A type for which the dot product of two equal-length vectors is defined.
pub trait DotProduct = std::ops::Add<Output = Self> + std::ops::Mul<Output = Self> + Default + Copy;
/// Computes the dot product of two equal-length vectors `a` and `b` and
/// returns the result.
pub fn dot<T>(a: &[T], b: &[T]) -> T where T: DotProduct {
assert!(a.len() == b.len());
let mut dp = T::default();
for i in 0..a.len() {
dp = dp + a[i] * b[i]
}
return dp;
}
pub fn matmul<T>(left: &Matrix<T>, right: &Matrix<T>, output: &mut Matrix<T>)
where T: DotProduct
{
assert!(left.colc() == right.rowc());
assert!(output.rowc() == left.rowc());
assert!(output.colc() == right.colc());
let left_t = left.clone().transpose();
for i in 0..left.rowc() {
for j in 0..right.colc() {
let dp = dot(left_t.get_col(i), right.get_col(j));
output.get_col_mut(j)[i] = dp;
}
}
}
pub fn matmul_replace<T>(left: &Matrix<T>, right: &mut Matrix<T>)
where T: DotProduct + Default
{
assert!(left.rowc() == right.rowc());
let mut intermediate: Matrix<T> = Matrix::new(left.rowc(), right.colc());
matmul(left, right, &mut intermediate);
*right = intermediate;
}