11use crate :: { generate:: * , inner:: * , norm:: Norm , types:: * } ;
22use ndarray:: * ;
3- use num_traits:: Zero ;
43
4+ /// Iterative orthogonalizer using modified Gram-Schmit procedure
55#[ derive( Debug , Clone ) ]
66pub struct MGS < A > {
7- dim : usize ,
7+ /// Dimension of base space
8+ dimension : usize ,
9+ /// Basis of spanned space
810 q : Vec < Array1 < A > > ,
9- r : Vec < Array1 < A > > ,
1011}
1112
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 > ;
1615
1716impl < A : Scalar + Lapack > MGS < A > {
18- pub fn new ( dim : usize ) -> Self {
17+ pub fn new ( dimension : usize ) -> Self {
1918 Self {
20- dim ,
19+ dimension ,
2120 q : Vec :: new ( ) ,
22- r : Vec :: new ( ) ,
2321 }
2422 }
2523
2624 pub fn dim ( & self ) -> usize {
27- self . dim
25+ self . dimension
2826 }
2927
3028 pub fn len ( & self ) -> usize {
3129 self . q . len ( )
3230 }
3331
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 > )
4438 where
45- S : Data < Elem = A > ,
39+ S : DataMut < Elem = A > ,
4640 {
4741 assert_eq ! ( a. len( ) , self . dim( ) ) ;
48- let mut a = a. into_owned ( ) ;
4942 let mut coef = Array1 :: zeros ( self . len ( ) + 1 ) ;
5043 for i in 0 ..self . len ( ) {
5144 let q = & self . q [ i] ;
@@ -54,32 +47,35 @@ impl<A: Scalar + Lapack> MGS<A> {
5447 coef[ i] = c;
5548 }
5649 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 ( ) ;
5766 if nrm < rtol {
67+ // Linearly dependent
5868 return None ;
5969 }
60- coef[ self . len ( ) ] = A :: from_real ( nrm) ;
61- self . r . push ( coef) ;
6270 azip ! ( mut a in { * a = * a / A :: from_real( nrm) } ) ;
6371 self . q . push ( a) ;
64- Some ( nrm )
72+ Some ( coef )
6573 }
6674
6775 /// Get orthogonal basis as Q matrix
6876 pub fn get_q ( & self ) -> Array2 < A > {
6977 hstack ( & self . q ) . unwrap ( )
7078 }
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- }
8379}
8480
8581#[ cfg( test) ]
0 commit comments