@@ -8,17 +8,17 @@ use crate::{inner::*, norm::*};
8
8
use num_traits:: One ;
9
9
10
10
/// Calc a reflactor `w` from a vector `x`
11
- pub fn calc_reflector < A , S > ( x : & mut ArrayBase < S , Ix1 > ) -> A
11
+ pub fn calc_reflector < A , S > ( x : & mut ArrayBase < S , Ix1 > )
12
12
where
13
13
A : Scalar + Lapack ,
14
14
S : DataMut < Elem = A > ,
15
15
{
16
+ assert ! ( x. len( ) > 0 ) ;
16
17
let norm = x. norm_l2 ( ) ;
17
18
let alpha = -x[ 0 ] . mul_real ( norm / x[ 0 ] . abs ( ) ) ;
18
19
x[ 0 ] -= alpha;
19
20
let inv_rev_norm = A :: Real :: one ( ) / x. norm_l2 ( ) ;
20
21
azip ! ( mut a( x) in { * a = a. mul_real( inv_rev_norm) } ) ;
21
- alpha
22
22
}
23
23
24
24
/// Take a reflection `P = I - 2ww^T`
@@ -50,12 +50,19 @@ pub struct Householder<A: Scalar> {
50
50
///
51
51
/// The coefficient is copied into another array, and this does not contain
52
52
v : Vec < Array1 < A > > ,
53
+
54
+ /// Tolerance
55
+ tol : A :: Real ,
53
56
}
54
57
55
58
impl < A : Scalar + Lapack > Householder < A > {
56
59
/// Create a new orthogonalizer
57
- pub fn new ( dim : usize ) -> Self {
58
- Householder { dim, v : Vec :: new ( ) }
60
+ pub fn new ( dim : usize , tol : A :: Real ) -> Self {
61
+ Householder {
62
+ dim,
63
+ v : Vec :: new ( ) ,
64
+ tol,
65
+ }
59
66
}
60
67
61
68
/// Take a Reflection `P = I - 2ww^T`
@@ -92,12 +99,32 @@ impl<A: Scalar + Lapack> Householder<A> {
92
99
}
93
100
}
94
101
95
- fn eval_residual < S > ( & self , a : & ArrayBase < S , Ix1 > ) -> A :: Real
102
+ /// Compose coefficients array using reflected vector
103
+ fn compose_coefficients < S > ( & self , a : & ArrayBase < S , Ix1 > ) -> Coefficients < A >
96
104
where
97
105
S : Data < Elem = A > ,
98
106
{
99
- let l = self . v . len ( ) ;
100
- a. slice ( s ! [ l..] ) . norm_l2 ( )
107
+ let k = self . len ( ) ;
108
+ let res = a. slice ( s ! [ k..] ) . norm_l2 ( ) ;
109
+ let mut c = Array1 :: zeros ( k + 1 ) ;
110
+ azip ! ( mut c( c. slice_mut( s![ ..k] ) ) , a( a. slice( s![ ..k] ) ) in { * c = a } ) ;
111
+ if k < a. len ( ) {
112
+ let ak = a[ k] ;
113
+ c[ k] = -ak. mul_real ( res / ak. abs ( ) ) ;
114
+ } else {
115
+ c[ k] = A :: from_real ( res) ;
116
+ }
117
+ c
118
+ }
119
+
120
+ /// Construct the residual vector from reflected vector
121
+ fn construct_residual < S > ( & self , a : & mut ArrayBase < S , Ix1 > )
122
+ where
123
+ S : DataMut < Elem = A > ,
124
+ {
125
+ let k = self . len ( ) ;
126
+ azip ! ( mut a( a. slice_mut( s![ ..k] ) ) in { * a = A :: zero( ) } ) ;
127
+ self . backward_reflection ( a) ;
101
128
}
102
129
}
103
130
@@ -112,45 +139,61 @@ impl<A: Scalar + Lapack> Orthogonalizer for Householder<A> {
112
139
self . v . len ( )
113
140
}
114
141
142
+ fn tolerance ( & self ) -> A :: Real {
143
+ self . tol
144
+ }
145
+
146
+ fn decompose < S > ( & self , a : & mut ArrayBase < S , Ix1 > ) -> Array1 < A >
147
+ where
148
+ S : DataMut < Elem = A > ,
149
+ {
150
+ self . forward_reflection ( a) ;
151
+ let coef = self . compose_coefficients ( a) ;
152
+ self . construct_residual ( a) ;
153
+ coef
154
+ }
155
+
115
156
fn coeff < S > ( & self , a : ArrayBase < S , Ix1 > ) -> Array1 < A >
116
157
where
117
158
S : Data < Elem = A > ,
118
159
{
119
160
let mut a = a. into_owned ( ) ;
120
161
self . forward_reflection ( & mut a) ;
121
- let res = self . eval_residual ( & a) ;
122
- let k = self . len ( ) ;
123
- let mut c = Array1 :: zeros ( k + 1 ) ;
124
- azip ! ( mut c( c. slice_mut( s![ ..k] ) ) , a( a. slice( s![ ..k] ) ) in { * c = a } ) ;
125
- c[ k] = A :: from_real ( res) ;
126
- c
162
+ self . compose_coefficients ( & a)
127
163
}
128
164
129
- fn append < S > ( & mut self , mut a : ArrayBase < S , Ix1 > , rtol : A :: Real ) -> Result < Array1 < A > , Array1 < A > >
165
+ fn div_append < S > ( & mut self , a : & mut ArrayBase < S , Ix1 > ) -> AppendResult < A >
130
166
where
131
167
S : DataMut < Elem = A > ,
132
168
{
133
169
assert_eq ! ( a. len( ) , self . dim) ;
134
170
let k = self . len ( ) ;
135
-
136
- self . forward_reflection ( & mut a) ;
137
- let mut coef = Array :: zeros ( k + 1 ) ;
138
- for i in 0 ..k {
139
- coef[ i] = a[ i] ;
140
- }
141
- if self . is_full ( ) {
142
- return Err ( coef) ; // coef[k] must be zero in this case
171
+ self . forward_reflection ( a) ;
172
+ let coef = self . compose_coefficients ( a) ;
173
+ if coef[ k] . abs ( ) < self . tol {
174
+ return AppendResult :: Dependent ( coef) ;
143
175
}
176
+ calc_reflector ( & mut a. slice_mut ( s ! [ k..] ) ) ;
177
+ self . v . push ( a. to_owned ( ) ) ;
178
+ self . construct_residual ( a) ;
179
+ AppendResult :: Added ( coef)
180
+ }
144
181
145
- let alpha = calc_reflector ( & mut a. slice_mut ( s ! [ k..] ) ) ;
146
- coef[ k] = alpha;
147
-
148
- if alpha. abs ( ) < rtol {
149
- // linearly dependent
150
- return Err ( coef) ;
182
+ fn append < S > ( & mut self , a : ArrayBase < S , Ix1 > ) -> AppendResult < A >
183
+ where
184
+ S : Data < Elem = A > ,
185
+ {
186
+ assert_eq ! ( a. len( ) , self . dim) ;
187
+ let mut a = a. into_owned ( ) ;
188
+ let k = self . len ( ) ;
189
+ self . forward_reflection ( & mut a) ;
190
+ let coef = self . compose_coefficients ( & a) ;
191
+ if coef[ k] . abs ( ) < self . tol {
192
+ return AppendResult :: Dependent ( coef) ;
151
193
}
152
- self . v . push ( a. into_owned ( ) ) ;
153
- Ok ( coef)
194
+ calc_reflector ( & mut a. slice_mut ( s ! [ k..] ) ) ;
195
+ self . v . push ( a. to_owned ( ) ) ;
196
+ AppendResult :: Added ( coef)
154
197
}
155
198
156
199
fn get_q ( & self ) -> Q < A > {
@@ -175,8 +218,8 @@ where
175
218
A : Scalar + Lapack ,
176
219
S : Data < Elem = A > ,
177
220
{
178
- let h = Householder :: new ( dim) ;
179
- qr ( iter, h, rtol , strategy)
221
+ let h = Householder :: new ( dim, rtol ) ;
222
+ qr ( iter, h, strategy)
180
223
}
181
224
182
225
#[ cfg( test) ]
0 commit comments