Chris@49
|
1 // Copyright (C) 2009-2012 NICTA (www.nicta.com.au)
|
Chris@49
|
2 // Copyright (C) 2009-2012 Conrad Sanderson
|
Chris@49
|
3 //
|
Chris@49
|
4 // This Source Code Form is subject to the terms of the Mozilla Public
|
Chris@49
|
5 // License, v. 2.0. If a copy of the MPL was not distributed with this
|
Chris@49
|
6 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
Chris@49
|
7
|
Chris@49
|
8
|
Chris@49
|
9 //! \addtogroup op_var
|
Chris@49
|
10 //! @{
|
Chris@49
|
11
|
Chris@49
|
12
|
Chris@49
|
13 //! \brief
|
Chris@49
|
14 //! For each row or for each column, find the variance.
|
Chris@49
|
15 //! The result is stored in a dense matrix that has either one column or one row.
|
Chris@49
|
16 //! The dimension, for which the variances are found, is set via the var() function.
|
Chris@49
|
17 template<typename T1>
|
Chris@49
|
18 inline
|
Chris@49
|
19 void
|
Chris@49
|
20 op_var::apply(Mat<typename T1::pod_type>& out, const mtOp<typename T1::pod_type, T1, op_var>& in)
|
Chris@49
|
21 {
|
Chris@49
|
22 arma_extra_debug_sigprint();
|
Chris@49
|
23
|
Chris@49
|
24 typedef typename T1::elem_type in_eT;
|
Chris@49
|
25 typedef typename T1::pod_type out_eT;
|
Chris@49
|
26
|
Chris@49
|
27 const unwrap_check_mixed<T1> tmp(in.m, out);
|
Chris@49
|
28 const Mat<in_eT>& X = tmp.M;
|
Chris@49
|
29
|
Chris@49
|
30 const uword norm_type = in.aux_uword_a;
|
Chris@49
|
31 const uword dim = in.aux_uword_b;
|
Chris@49
|
32
|
Chris@49
|
33 arma_debug_check( (norm_type > 1), "var(): incorrect usage. norm_type must be 0 or 1");
|
Chris@49
|
34 arma_debug_check( (dim > 1), "var(): incorrect usage. dim must be 0 or 1" );
|
Chris@49
|
35
|
Chris@49
|
36 const uword X_n_rows = X.n_rows;
|
Chris@49
|
37 const uword X_n_cols = X.n_cols;
|
Chris@49
|
38
|
Chris@49
|
39 if(dim == 0)
|
Chris@49
|
40 {
|
Chris@49
|
41 arma_extra_debug_print("op_var::apply(), dim = 0");
|
Chris@49
|
42
|
Chris@49
|
43 arma_debug_check( (X_n_rows == 0), "var(): given object has zero rows" );
|
Chris@49
|
44
|
Chris@49
|
45 out.set_size(1, X_n_cols);
|
Chris@49
|
46
|
Chris@49
|
47 out_eT* out_mem = out.memptr();
|
Chris@49
|
48
|
Chris@49
|
49 for(uword col=0; col<X_n_cols; ++col)
|
Chris@49
|
50 {
|
Chris@49
|
51 out_mem[col] = op_var::direct_var( X.colptr(col), X_n_rows, norm_type );
|
Chris@49
|
52 }
|
Chris@49
|
53 }
|
Chris@49
|
54 else
|
Chris@49
|
55 if(dim == 1)
|
Chris@49
|
56 {
|
Chris@49
|
57 arma_extra_debug_print("op_var::apply(), dim = 1");
|
Chris@49
|
58
|
Chris@49
|
59 arma_debug_check( (X_n_cols == 0), "var(): given object has zero columns" );
|
Chris@49
|
60
|
Chris@49
|
61 out.set_size(X_n_rows, 1);
|
Chris@49
|
62
|
Chris@49
|
63 podarray<in_eT> dat(X_n_cols);
|
Chris@49
|
64
|
Chris@49
|
65 in_eT* dat_mem = dat.memptr();
|
Chris@49
|
66 out_eT* out_mem = out.memptr();
|
Chris@49
|
67
|
Chris@49
|
68 for(uword row=0; row<X_n_rows; ++row)
|
Chris@49
|
69 {
|
Chris@49
|
70 dat.copy_row(X, row);
|
Chris@49
|
71
|
Chris@49
|
72 out_mem[row] = op_var::direct_var( dat_mem, X_n_cols, norm_type );
|
Chris@49
|
73 }
|
Chris@49
|
74 }
|
Chris@49
|
75 }
|
Chris@49
|
76
|
Chris@49
|
77
|
Chris@49
|
78
|
Chris@49
|
79 template<typename T1>
|
Chris@49
|
80 inline
|
Chris@49
|
81 typename T1::pod_type
|
Chris@49
|
82 op_var::var_vec(const Base<typename T1::elem_type, T1>& X, const uword norm_type)
|
Chris@49
|
83 {
|
Chris@49
|
84 arma_extra_debug_sigprint();
|
Chris@49
|
85
|
Chris@49
|
86 typedef typename T1::elem_type eT;
|
Chris@49
|
87
|
Chris@49
|
88 arma_debug_check( (norm_type > 1), "var(): incorrect usage. norm_type must be 0 or 1");
|
Chris@49
|
89
|
Chris@49
|
90 const Proxy<T1> P(X.get_ref());
|
Chris@49
|
91
|
Chris@49
|
92 const podarray<eT> tmp(P);
|
Chris@49
|
93
|
Chris@49
|
94 return op_var::direct_var(tmp.memptr(), tmp.n_elem, norm_type);
|
Chris@49
|
95 }
|
Chris@49
|
96
|
Chris@49
|
97
|
Chris@49
|
98
|
Chris@49
|
99 template<typename eT>
|
Chris@49
|
100 inline
|
Chris@49
|
101 typename get_pod_type<eT>::result
|
Chris@49
|
102 op_var::var_vec(const subview_col<eT>& X, const uword norm_type)
|
Chris@49
|
103 {
|
Chris@49
|
104 arma_extra_debug_sigprint();
|
Chris@49
|
105
|
Chris@49
|
106 arma_debug_check( (norm_type > 1), "var(): incorrect usage. norm_type must be 0 or 1");
|
Chris@49
|
107
|
Chris@49
|
108 return op_var::direct_var(X.colptr(0), X.n_rows, norm_type);
|
Chris@49
|
109 }
|
Chris@49
|
110
|
Chris@49
|
111
|
Chris@49
|
112
|
Chris@49
|
113
|
Chris@49
|
114 template<typename eT>
|
Chris@49
|
115 inline
|
Chris@49
|
116 typename get_pod_type<eT>::result
|
Chris@49
|
117 op_var::var_vec(const subview_row<eT>& X, const uword norm_type)
|
Chris@49
|
118 {
|
Chris@49
|
119 arma_extra_debug_sigprint();
|
Chris@49
|
120
|
Chris@49
|
121 arma_debug_check( (norm_type > 1), "var(): incorrect usage. norm_type must be 0 or 1");
|
Chris@49
|
122
|
Chris@49
|
123 const Mat<eT>& A = X.m;
|
Chris@49
|
124
|
Chris@49
|
125 const uword start_row = X.aux_row1;
|
Chris@49
|
126 const uword start_col = X.aux_col1;
|
Chris@49
|
127
|
Chris@49
|
128 const uword end_col_p1 = start_col + X.n_cols;
|
Chris@49
|
129
|
Chris@49
|
130 podarray<eT> tmp(X.n_elem);
|
Chris@49
|
131 eT* tmp_mem = tmp.memptr();
|
Chris@49
|
132
|
Chris@49
|
133 for(uword i=0, col=start_col; col < end_col_p1; ++col, ++i)
|
Chris@49
|
134 {
|
Chris@49
|
135 tmp_mem[i] = A.at(start_row, col);
|
Chris@49
|
136 }
|
Chris@49
|
137
|
Chris@49
|
138 return op_var::direct_var(tmp.memptr(), tmp.n_elem, norm_type);
|
Chris@49
|
139 }
|
Chris@49
|
140
|
Chris@49
|
141
|
Chris@49
|
142
|
Chris@49
|
143 //! find the variance of an array
|
Chris@49
|
144 template<typename eT>
|
Chris@49
|
145 inline
|
Chris@49
|
146 eT
|
Chris@49
|
147 op_var::direct_var(const eT* const X, const uword n_elem, const uword norm_type)
|
Chris@49
|
148 {
|
Chris@49
|
149 arma_extra_debug_sigprint();
|
Chris@49
|
150
|
Chris@49
|
151 if(n_elem >= 2)
|
Chris@49
|
152 {
|
Chris@49
|
153 const eT acc1 = op_mean::direct_mean(X, n_elem);
|
Chris@49
|
154
|
Chris@49
|
155 eT acc2 = eT(0);
|
Chris@49
|
156 eT acc3 = eT(0);
|
Chris@49
|
157
|
Chris@49
|
158 uword i,j;
|
Chris@49
|
159
|
Chris@49
|
160 for(i=0, j=1; j<n_elem; i+=2, j+=2)
|
Chris@49
|
161 {
|
Chris@49
|
162 const eT Xi = X[i];
|
Chris@49
|
163 const eT Xj = X[j];
|
Chris@49
|
164
|
Chris@49
|
165 const eT tmpi = acc1 - Xi;
|
Chris@49
|
166 const eT tmpj = acc1 - Xj;
|
Chris@49
|
167
|
Chris@49
|
168 acc2 += tmpi*tmpi + tmpj*tmpj;
|
Chris@49
|
169 acc3 += tmpi + tmpj;
|
Chris@49
|
170 }
|
Chris@49
|
171
|
Chris@49
|
172 if(i < n_elem)
|
Chris@49
|
173 {
|
Chris@49
|
174 const eT Xi = X[i];
|
Chris@49
|
175
|
Chris@49
|
176 const eT tmpi = acc1 - Xi;
|
Chris@49
|
177
|
Chris@49
|
178 acc2 += tmpi*tmpi;
|
Chris@49
|
179 acc3 += tmpi;
|
Chris@49
|
180 }
|
Chris@49
|
181
|
Chris@49
|
182 const eT norm_val = (norm_type == 0) ? eT(n_elem-1) : eT(n_elem);
|
Chris@49
|
183 const eT var_val = (acc2 - acc3*acc3/eT(n_elem)) / norm_val;
|
Chris@49
|
184
|
Chris@49
|
185 return arma_isfinite(var_val) ? var_val : op_var::direct_var_robust(X, n_elem, norm_type);
|
Chris@49
|
186 }
|
Chris@49
|
187 else
|
Chris@49
|
188 {
|
Chris@49
|
189 return eT(0);
|
Chris@49
|
190 }
|
Chris@49
|
191 }
|
Chris@49
|
192
|
Chris@49
|
193
|
Chris@49
|
194
|
Chris@49
|
195 //! find the variance of an array (robust but slow)
|
Chris@49
|
196 template<typename eT>
|
Chris@49
|
197 inline
|
Chris@49
|
198 eT
|
Chris@49
|
199 op_var::direct_var_robust(const eT* const X, const uword n_elem, const uword norm_type)
|
Chris@49
|
200 {
|
Chris@49
|
201 arma_extra_debug_sigprint();
|
Chris@49
|
202
|
Chris@49
|
203 if(n_elem > 1)
|
Chris@49
|
204 {
|
Chris@49
|
205 eT r_mean = X[0];
|
Chris@49
|
206 eT r_var = eT(0);
|
Chris@49
|
207
|
Chris@49
|
208 for(uword i=1; i<n_elem; ++i)
|
Chris@49
|
209 {
|
Chris@49
|
210 const eT tmp = X[i] - r_mean;
|
Chris@49
|
211 const eT i_plus_1 = eT(i+1);
|
Chris@49
|
212
|
Chris@49
|
213 r_var = eT(i-1)/eT(i) * r_var + (tmp*tmp)/i_plus_1;
|
Chris@49
|
214
|
Chris@49
|
215 r_mean = r_mean + tmp/i_plus_1;
|
Chris@49
|
216 }
|
Chris@49
|
217
|
Chris@49
|
218 return (norm_type == 0) ? r_var : (eT(n_elem-1)/eT(n_elem)) * r_var;
|
Chris@49
|
219 }
|
Chris@49
|
220 else
|
Chris@49
|
221 {
|
Chris@49
|
222 return eT(0);
|
Chris@49
|
223 }
|
Chris@49
|
224 }
|
Chris@49
|
225
|
Chris@49
|
226
|
Chris@49
|
227
|
Chris@49
|
228 //! find the variance of an array (version for complex numbers)
|
Chris@49
|
229 template<typename T>
|
Chris@49
|
230 inline
|
Chris@49
|
231 T
|
Chris@49
|
232 op_var::direct_var(const std::complex<T>* const X, const uword n_elem, const uword norm_type)
|
Chris@49
|
233 {
|
Chris@49
|
234 arma_extra_debug_sigprint();
|
Chris@49
|
235
|
Chris@49
|
236 typedef typename std::complex<T> eT;
|
Chris@49
|
237
|
Chris@49
|
238 if(n_elem >= 2)
|
Chris@49
|
239 {
|
Chris@49
|
240 const eT acc1 = op_mean::direct_mean(X, n_elem);
|
Chris@49
|
241
|
Chris@49
|
242 T acc2 = T(0);
|
Chris@49
|
243 eT acc3 = eT(0);
|
Chris@49
|
244
|
Chris@49
|
245 for(uword i=0; i<n_elem; ++i)
|
Chris@49
|
246 {
|
Chris@49
|
247 const eT tmp = acc1 - X[i];
|
Chris@49
|
248
|
Chris@49
|
249 acc2 += std::norm(tmp);
|
Chris@49
|
250 acc3 += tmp;
|
Chris@49
|
251 }
|
Chris@49
|
252
|
Chris@49
|
253 const T norm_val = (norm_type == 0) ? T(n_elem-1) : T(n_elem);
|
Chris@49
|
254 const T var_val = (acc2 - std::norm(acc3)/T(n_elem)) / norm_val;
|
Chris@49
|
255
|
Chris@49
|
256 return arma_isfinite(var_val) ? var_val : op_var::direct_var_robust(X, n_elem, norm_type);
|
Chris@49
|
257 }
|
Chris@49
|
258 else
|
Chris@49
|
259 {
|
Chris@49
|
260 return T(0);
|
Chris@49
|
261 }
|
Chris@49
|
262 }
|
Chris@49
|
263
|
Chris@49
|
264
|
Chris@49
|
265
|
Chris@49
|
266 //! find the variance of an array (version for complex numbers) (robust but slow)
|
Chris@49
|
267 template<typename T>
|
Chris@49
|
268 inline
|
Chris@49
|
269 T
|
Chris@49
|
270 op_var::direct_var_robust(const std::complex<T>* const X, const uword n_elem, const uword norm_type)
|
Chris@49
|
271 {
|
Chris@49
|
272 arma_extra_debug_sigprint();
|
Chris@49
|
273
|
Chris@49
|
274 typedef typename std::complex<T> eT;
|
Chris@49
|
275
|
Chris@49
|
276 if(n_elem > 1)
|
Chris@49
|
277 {
|
Chris@49
|
278 eT r_mean = X[0];
|
Chris@49
|
279 T r_var = T(0);
|
Chris@49
|
280
|
Chris@49
|
281 for(uword i=1; i<n_elem; ++i)
|
Chris@49
|
282 {
|
Chris@49
|
283 const eT tmp = X[i] - r_mean;
|
Chris@49
|
284 const T i_plus_1 = T(i+1);
|
Chris@49
|
285
|
Chris@49
|
286 r_var = T(i-1)/T(i) * r_var + std::norm(tmp)/i_plus_1;
|
Chris@49
|
287
|
Chris@49
|
288 r_mean = r_mean + tmp/i_plus_1;
|
Chris@49
|
289 }
|
Chris@49
|
290
|
Chris@49
|
291 return (norm_type == 0) ? r_var : (T(n_elem-1)/T(n_elem)) * r_var;
|
Chris@49
|
292 }
|
Chris@49
|
293 else
|
Chris@49
|
294 {
|
Chris@49
|
295 return T(0);
|
Chris@49
|
296 }
|
Chris@49
|
297 }
|
Chris@49
|
298
|
Chris@49
|
299
|
Chris@49
|
300
|
Chris@49
|
301 //! @}
|
Chris@49
|
302
|