1
1
use crate :: { generate:: * , inner:: * , norm:: Norm , types:: * } ;
2
2
use ndarray:: * ;
3
- use num_traits:: Zero ;
4
3
4
+ /// Iterative orthogonalizer using modified Gram-Schmit procedure
5
5
#[ derive( Debug , Clone ) ]
6
6
pub struct MGS < A > {
7
- dim : usize ,
7
+ /// Dimension of base space
8
+ dimension : usize ,
9
+ /// Basis of spanned space
8
10
q : Vec < Array1 < A > > ,
9
- r : Vec < Array1 < A > > ,
10
11
}
11
12
12
- pub enum Dependence < A : Scalar > {
13
- Orthogonal ( A :: Real ) ,
14
- Coefficient ( Array1 < A > ) ,
15
- }
13
+ pub type Residual < S > = ArrayBase < S , Ix1 > ;
14
+ pub type Coefficient < A > = Array1 < A > ;
16
15
17
16
impl < A : Scalar + Lapack > MGS < A > {
18
- pub fn new ( dim : usize ) -> Self {
17
+ pub fn new ( dimension : usize ) -> Self {
19
18
Self {
20
- dim ,
19
+ dimension ,
21
20
q : Vec :: new ( ) ,
22
- r : Vec :: new ( ) ,
23
21
}
24
22
}
25
23
26
24
pub fn dim ( & self ) -> usize {
27
- self . dim
25
+ self . dimension
28
26
}
29
27
30
28
pub fn len ( & self ) -> usize {
31
29
self . q . len ( )
32
30
}
33
31
34
- /// Add new vector, return residual norm
35
- pub fn append < S > ( & mut self , a : ArrayBase < S , Ix1 > ) -> A :: Real
36
- where
37
- S : Data < Elem = A > ,
38
- {
39
- self . append_if ( a, A :: Real :: zero ( ) ) . unwrap ( )
40
- }
41
-
42
- /// Add new vector if the residual is larger than relative tolerance
43
- pub fn append_if < S > ( & mut self , a : ArrayBase < S , Ix1 > , rtol : A :: Real ) -> Option < A :: Real >
32
+ /// Orthogonalize given vector using current basis
33
+ ///
34
+ /// Panic
35
+ /// -------
36
+ /// - if the size of the input array mismaches to the dimension
37
+ pub fn orthogonalize < S > ( & self , mut a : ArrayBase < S , Ix1 > ) -> ( Residual < S > , Coefficient < A > )
44
38
where
45
- S : Data < Elem = A > ,
39
+ S : DataMut < Elem = A > ,
46
40
{
47
41
assert_eq ! ( a. len( ) , self . dim( ) ) ;
48
- let mut a = a. into_owned ( ) ;
49
42
let mut coef = Array1 :: zeros ( self . len ( ) + 1 ) ;
50
43
for i in 0 ..self . len ( ) {
51
44
let q = & self . q [ i] ;
@@ -54,32 +47,35 @@ impl<A: Scalar + Lapack> MGS<A> {
54
47
coef[ i] = c;
55
48
}
56
49
let nrm = a. norm_l2 ( ) ;
50
+ coef[ self . len ( ) ] = A :: from_real ( nrm) ;
51
+ ( a, coef)
52
+ }
53
+
54
+ /// Add new vector if the residual is larger than relative tolerance
55
+ ///
56
+ /// Panic
57
+ /// -------
58
+ /// - if the size of the input array mismaches to the dimension
59
+ pub fn append_if_independent < S > ( & mut self , a : ArrayBase < S , Ix1 > , rtol : A :: Real ) -> Option < Coefficient < A > >
60
+ where
61
+ S : Data < Elem = A > ,
62
+ {
63
+ let a = a. into_owned ( ) ;
64
+ let ( mut a, coef) = self . orthogonalize ( a) ;
65
+ let nrm = coef[ coef. len ( ) ] . re ( ) ;
57
66
if nrm < rtol {
67
+ // Linearly dependent
58
68
return None ;
59
69
}
60
- coef[ self . len ( ) ] = A :: from_real ( nrm) ;
61
- self . r . push ( coef) ;
62
70
azip ! ( mut a in { * a = * a / A :: from_real( nrm) } ) ;
63
71
self . q . push ( a) ;
64
- Some ( nrm )
72
+ Some ( coef )
65
73
}
66
74
67
75
/// Get orthogonal basis as Q matrix
68
76
pub fn get_q ( & self ) -> Array2 < A > {
69
77
hstack ( & self . q ) . unwrap ( )
70
78
}
71
-
72
- /// Get each vector norm and coefficients as R matrix
73
- pub fn get_r ( & self ) -> Array2 < A > {
74
- let len = self . len ( ) ;
75
- let mut r = Array2 :: zeros ( ( len, len) ) ;
76
- for i in 0 ..len {
77
- for j in 0 ..=i {
78
- r[ ( j, i) ] = self . r [ i] [ j] ;
79
- }
80
- }
81
- r
82
- }
83
79
}
84
80
85
81
#[ cfg( test) ]
0 commit comments