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
130
131
132
133
use cblas;
use ndarray::{
Data,
ShapeBuilder,
};
use ndarray::prelude::*;
use std::slice;
use crate::{
Error,
GramSchmidt,
Result,
utils::get_layout,
};
#[derive(Clone, Debug)]
pub struct Modified {
q: Array2<f64>,
r: Array2<f64>,
memory_layout: cblas::Layout,
}
impl GramSchmidt for Modified {
fn from_shape<T>(shape: T) -> Result<Self>
where T: ShapeBuilder<Dim = Ix2>,
{
let shape = shape.into_shape();
let q = Array2::zeros(shape);
let memory_layout = match get_layout(&q) {
Some(layout) => layout,
None => Err(Error::NonContiguous)?,
};
let r = q.clone();
Ok(Self {
q,
r,
memory_layout,
})
}
fn compute<S>(&mut self, a: &ArrayBase<S, Ix2>) -> Result<()>
where S: Data<Elem = f64>,
{
let (n_rows, n_cols) = a.dim();
for i in 0..n_cols {
{
let (q_done, mut q_todo) = self.q.view_mut().split_at(Axis(1), i);
let mut q_todo_column = q_todo.column_mut(0);
q_todo_column.assign(&a.column(i));
for (j, q_done_column) in q_done.gencolumns().into_iter().enumerate() {
let projection_factor = q_done_column.dot(&q_todo_column);
self.r[(j, i)] = projection_factor;
q_todo_column.scaled_add(-projection_factor, &q_done_column);
}
}
let norm = {
let len = self.q.len();
let q_ptr = self.q.as_mut_ptr();
unsafe {
let (q_column, q_inc) = match self.memory_layout {
cblas::Layout::RowMajor => {
let offset = i as isize;
let q_column = slice::from_raw_parts_mut(q_ptr.offset(offset), len - i);
(q_column, n_cols as i32)
},
cblas::Layout::ColumnMajor => {
let offset = n_rows * i;
let q_column = slice::from_raw_parts_mut(q_ptr.offset(offset as isize), len - offset);
(q_column, 1)
},
};
cblas::dnrm2(n_rows as i32, q_column, q_inc)
}
};
self.r[(i,i)] = norm;
let mut q_column = self.q.column_mut(i);
q_column /= norm;
}
Ok(())
}
fn q(&self) -> &Array2<f64> {
&self.q
}
fn r(&self) -> &Array2<f64> {
&self.r
}
}
pub fn mgs<S>(a: &ArrayBase<S, Ix2>) -> Result<(Array<f64, Ix2>, Array<f64, Ix2>)>
where S: Data<Elem=f64>
{
let mut mgs = Modified::from_matrix(a)?;
mgs.compute(a)?;
Ok((mgs.q().clone(), mgs.r().clone()))
}
#[cfg(test)]
generate_tests!(Modified, 1e-13);