comparison liboctave/numeric/gsvd.cc @ 22236:065a44375723

gsvd: reduce code duplication with templates. * CmplxGSVD.cc, CmplxGSVD.h, dbleGSVD.cc, dbleGSVD.h: Remove files for no longer existing classes. Replaced by gsvd template class. This classes never existed in an Octave release, this was freshly imported from Octave Forge so backwards compatibility is not an issue. * liboctave/numeric/gsvd.h, liboctave/numeric/gsvd.cc: New files for gsvd class template generated from CmplxGSVD.cc, CmplxGSVD.h, dbleGSVD.cc, and dbleGSVD.h and converted to template. Removed unused << operator, unused constructor with &info, and commented code. Only instantiated for Matrix and ComplexMatrix, providing interface to DGGSVD and ZGGSVD. * liboctave/numeric/module.mk: Update. * mx-defs.h, mx-ext.h: Use new classes.
author Barbara Locsi <locsi.barbara@gmail.com>
date Tue, 09 Aug 2016 18:02:11 +0200
parents
children da201af35c97
comparison
equal deleted inserted replaced
22235:63b41167ef1e 22236:065a44375723
1 // Copyright (C) 1996, 1997 John W. Eaton
2 // Copyright (C) 2006 Pascal Dupuis <Pascal.Dupuis@uclouvain.be>
3 // Copyright (C) 2016 Barbara Lócsi
4 //
5 // This program is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free Software
7 // Foundation; either version 3 of the License, or (at your option) any later
8 // version.
9 //
10 // This program is distributed in the hope that it will be useful, but WITHOUT
11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU General Public License along with
16 // this program; if not, see <http://www.gnu.org/licenses/>.
17
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include "gsvd.h"
23 #include "f77-fcn.h"
24 #include "lo-error.h"
25 #include "CMatrix.h"
26 #include "dDiagMatrix.h"
27 #include "dMatrix.h"
28
29 extern "C"
30 {
31 F77_RET_T
32 F77_FUNC (dggsvd, DGGSVD)
33 (
34 F77_CONST_CHAR_ARG_DECL, // JOBU (input) CHARACTER*1
35 F77_CONST_CHAR_ARG_DECL, // JOBV (input) CHARACTER*1
36 F77_CONST_CHAR_ARG_DECL, // JOBQ (input) CHARACTER*1
37 const F77_INT&, // M (input) INTEGER
38 const F77_INT&, // N (input) INTEGER
39 const F77_INT&, // P (input) INTEGER
40 F77_INT &, // K (output) INTEGER
41 F77_INT &, // L (output) INTEGER
42 F77_DBLE*, // A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
43 const F77_INT&, // LDA (input) INTEGER
44 F77_DBLE*, // B (input/output) DOUBLE PRECISION array, dimension (LDB,N)
45 const F77_INT&, // LDB (input) INTEGER
46 F77_DBLE*, // ALPHA (output) DOUBLE PRECISION array, dimension (N)
47 F77_DBLE*, // BETA (output) DOUBLE PRECISION array, dimension (N)
48 F77_DBLE*, // U (output) DOUBLE PRECISION array, dimension (LDU,M)
49 const F77_INT&, // LDU (input) INTEGER
50 F77_DBLE*, // V (output) DOUBLE PRECISION array, dimension (LDV,P)
51 const F77_INT&, // LDV (input) INTEGER
52 F77_DBLE*, // Q (output) DOUBLE PRECISION array, dimension (LDQ,N)
53 const F77_INT&, // LDQ (input) INTEGER
54 F77_DBLE*, // WORK (workspace) DOUBLE PRECISION array
55 int*, // IWORK (workspace/output) INTEGER array, dimension (N)
56 F77_INT& // INFO (output)INTEGER
57 F77_CHAR_ARG_LEN_DECL
58 F77_CHAR_ARG_LEN_DECL
59 F77_CHAR_ARG_LEN_DECL
60 );
61
62 F77_RET_T
63 F77_FUNC (zggsvd, ZGGSVD)
64 (
65 F77_CONST_CHAR_ARG_DECL, // JOBU (input) CHARACTER*1
66 F77_CONST_CHAR_ARG_DECL, // JOBV (input) CHARACTER*1
67 F77_CONST_CHAR_ARG_DECL, // JOBQ (input) CHARACTER*1
68 const F77_INT&, // M (input) INTEGER
69 const F77_INT&, // N (input) INTEGER
70 const F77_INT&, // P (input) INTEGER
71 F77_INT &, // K (output) INTEGER
72 F77_INT &, // L (output) INTEGER
73 F77_DBLE_CMPLX*, // A (input/output) COMPLEX*16 array, dimension (LDA,N)
74 const F77_INT&, // LDA (input) INTEGER
75 F77_DBLE_CMPLX*, // B (input/output) COMPLEX*16 array, dimension (LDB,N)
76 const F77_INT&, // LDB (input) INTEGER
77 F77_DBLE*, // ALPHA (output) DOUBLE PRECISION array, dimension (N)
78 F77_DBLE*, // BETA (output) DOUBLE PRECISION array, dimension (N)
79 F77_DBLE_CMPLX*, // U (output) COMPLEX*16 array, dimension (LDU,M)
80 const F77_INT&, // LDU (input) INTEGER
81 F77_DBLE_CMPLX*, // V (output) COMPLEX*16 array, dimension (LDV,P)
82 const F77_INT&, // LDV (input) INTEGER
83 F77_DBLE_CMPLX*, // Q (output) COMPLEX*16 array, dimension (LDQ,N)
84 const F77_INT&, // LDQ (input) INTEGER
85 F77_DBLE_CMPLX*, // WORK (workspace) COMPLEX*16 array
86 F77_DBLE*, // RWORK (workspace) DOUBLE PRECISION array
87 int*, // IWORK (workspace/output) INTEGER array, dimension (N)
88 F77_INT& // INFO (output)INTEGER
89 F77_CHAR_ARG_LEN_DECL
90 F77_CHAR_ARG_LEN_DECL
91 F77_CHAR_ARG_LEN_DECL
92 );
93 }
94
95 template <>
96 void
97 gsvd<Matrix>::ggsvd (char& jobu, char& jobv, char& jobq, octave_idx_type m,
98 octave_idx_type n, octave_idx_type p, octave_idx_type& k,
99 octave_idx_type& l, double *tmp_dataA, octave_idx_type m1,
100 double *tmp_dataB, octave_idx_type p1, Matrix& alpha,
101 Matrix& beta, double *u, octave_idx_type nrow_u, double *v,
102 octave_idx_type nrow_v, double *q, octave_idx_type nrow_q,
103 Matrix& work, octave_idx_type* iwork, octave_idx_type& info)
104 {
105 F77_XFCN (dggsvd, DGGSVD, (F77_CONST_CHAR_ARG2 (&jobu, 1),
106 F77_CONST_CHAR_ARG2 (&jobv, 1),
107 F77_CONST_CHAR_ARG2 (&jobq, 1),
108 m, n, p, k, l, tmp_dataA, m1,
109 tmp_dataB, p1, alpha.fortran_vec (),
110 beta.fortran_vec (), u, nrow_u,
111 v, nrow_v, q, nrow_q, work.fortran_vec (),
112 iwork, info
113 F77_CHAR_ARG_LEN (1)
114 F77_CHAR_ARG_LEN (1)
115 F77_CHAR_ARG_LEN (1)));
116 }
117
118
119 template <>
120 void
121 gsvd<ComplexMatrix>::ggsvd (char& jobu, char& jobv, char& jobq,
122 octave_idx_type m, octave_idx_type n,
123 octave_idx_type p, octave_idx_type& k,
124 octave_idx_type& l, Complex *tmp_dataA,
125 octave_idx_type m1, Complex *tmp_dataB,
126 octave_idx_type p1, Matrix& alpha,
127 Matrix& beta, Complex *u, octave_idx_type nrow_u,
128 Complex *v, octave_idx_type nrow_v, Complex *q,
129 octave_idx_type nrow_q, ComplexMatrix& work,
130 octave_idx_type* iwork, octave_idx_type& info)
131 {
132 Matrix rwork(2*n, 1);
133 F77_XFCN (zggsvd, ZGGSVD, (F77_CONST_CHAR_ARG2 (&jobu, 1),
134 F77_CONST_CHAR_ARG2 (&jobv, 1),
135 F77_CONST_CHAR_ARG2 (&jobq, 1),
136 m, n, p, k, l, F77_DBLE_CMPLX_ARG (tmp_dataA), m1,
137 F77_DBLE_CMPLX_ARG (tmp_dataB), p1,
138 alpha.fortran_vec (), beta.fortran_vec (),
139 F77_DBLE_CMPLX_ARG (u), nrow_u,
140 F77_DBLE_CMPLX_ARG (v), nrow_v,
141 F77_DBLE_CMPLX_ARG (q), nrow_q,
142 F77_DBLE_CMPLX_ARG (work.fortran_vec ()),
143 rwork.fortran_vec (), iwork, info
144 F77_CHAR_ARG_LEN (1)
145 F77_CHAR_ARG_LEN (1)
146 F77_CHAR_ARG_LEN (1)));
147 }
148
149 template <typename T>
150 T
151 gsvd<T>::left_singular_matrix_A (void) const
152 {
153 if (type == gsvd::Type::sigma_only)
154 {
155 (*current_liboctave_error_handler)
156 ("gsvd: U not computed because type == gsvd::sigma_only");
157 return T ();
158 }
159 else
160 return left_smA;
161 }
162
163 template <typename T>
164 T
165 gsvd<T>::left_singular_matrix_B (void) const
166 {
167 if (type == gsvd::Type::sigma_only)
168 {
169 (*current_liboctave_error_handler)
170 ("gsvd: V not computed because type == gsvd::sigma_only");
171 return T ();
172 }
173 else
174 return left_smB;
175 }
176
177 template <typename T>
178 T
179 gsvd<T>::right_singular_matrix (void) const
180 {
181 if (type == gsvd::Type::sigma_only)
182 {
183 (*current_liboctave_error_handler)
184 ("gsvd: X not computed because type == gsvd::sigma_only");
185 return T ();
186 }
187 else
188 return right_sm;
189 }
190
191 template <typename T>
192 T
193 gsvd<T>::R_matrix (void) const
194 {
195 if (type != gsvd::Type::std)
196 {
197 (*current_liboctave_error_handler)
198 ("gsvd: R not computed because type != gsvd::std");
199 return T ();
200 }
201 else
202 return R;
203 }
204
205 template <typename T>
206 gsvd<T>::gsvd (const T& a, const T& b, gsvd::Type gsvd_type)
207 {
208 octave_idx_type info;
209
210 octave_idx_type m = a.rows ();
211 octave_idx_type n = a.cols ();
212 octave_idx_type p = b.rows ();
213
214 T atmp = a;
215 P *tmp_dataA = atmp.fortran_vec ();
216
217 T btmp = b;
218 P *tmp_dataB = btmp.fortran_vec ();
219
220 char jobu = 'U';
221 char jobv = 'V';
222 char jobq = 'Q';
223
224 octave_idx_type nrow_u = m;
225 octave_idx_type nrow_v = p;
226 octave_idx_type nrow_q = n;
227
228 octave_idx_type k, l;
229
230 switch (gsvd_type)
231 {
232 case gsvd<T>::Type::sigma_only:
233
234 // Note: for this case, both jobu and jobv should be 'N', but
235 // there seems to be a bug in dgesvd from Lapack V2.0. To
236 // demonstrate the bug, set both jobu and jobv to 'N' and find
237 // the singular values of [eye(3), eye(3)]. The result is
238 // [-sqrt(2), -sqrt(2), -sqrt(2)].
239 //
240 // For Lapack 3.0, this problem seems to be fixed.
241
242 jobu = 'N';
243 jobv = 'N';
244 jobq = 'N';
245 nrow_u = nrow_v = nrow_q = 1;
246 break;
247
248 default:
249 break;
250 }
251
252 type = gsvd_type;
253
254 if (! (jobu == 'N' || jobu == 'O'))
255 left_smA.resize (nrow_u, m);
256
257 P *u = left_smA.fortran_vec ();
258
259 if (! (jobv == 'N' || jobv == 'O'))
260 left_smB.resize (nrow_v, p);
261
262 P *v = left_smB.fortran_vec ();
263
264 if (! (jobq == 'N' || jobq == 'O'))
265 right_sm.resize (nrow_q, n);
266
267 P *q = right_sm.fortran_vec ();
268
269 octave_idx_type lwork = 3*n;
270 lwork = lwork > m ? lwork : m;
271 lwork = (lwork > p ? lwork : p) + n;
272
273 T work (lwork, 1);
274 Matrix alpha (n, 1);
275 Matrix beta (n, 1);
276
277 std::vector<octave_idx_type> iwork (n);
278
279 gsvd<T>::ggsvd (jobu, jobv, jobq, m, n, p, k, l,
280 tmp_dataA, m, tmp_dataB, p, alpha, beta, u,
281 nrow_u, v, nrow_v, q, nrow_q, work, iwork.data (), info);
282
283 if (f77_exception_encountered)
284 (*current_liboctave_error_handler) ("unrecoverable error in *ggsvd");
285
286 if (info < 0)
287 (*current_liboctave_error_handler) ("*ggsvd.f: argument %d illegal", -info);
288 else
289 {
290 if (info > 0)
291 (*current_liboctave_error_handler)
292 ("*ggsvd.f: Jacobi-type procedure failed to converge.");
293 else
294 {
295 octave_idx_type i, j;
296
297 if (gsvd<T>::Type::std == gsvd_type)
298 {
299 R.resize(k+l, k+l);
300 int astart = n-k-l;
301 if (m - k - l >= 0)
302 {
303 astart = n-k-l;
304 // R is stored in A(1:K+L,N-K-L+1:N)
305 for (i = 0; i < k+l; i++)
306 for (j = 0; j < k+l; j++)
307 R.xelem (i, j) = atmp.xelem (i, astart + j);
308 }
309 else
310 {
311 // (R11 R12 R13 ) is stored in A(1:M, N-K-L+1:N),
312 // ( 0 R22 R23 )
313
314 for (i = 0; i < m; i++)
315 for (j = 0; j < k+l; j++)
316 R.xelem (i, j) = atmp.xelem (i, astart + j);
317 // and R33 is stored in B(M-K+1:L,N+M-K-L+1:N)
318 for (i = k+l-1; i >=m; i--) {
319 for (j = 0; j < m; j++)
320 R.xelem(i, j) = 0.0;
321 for (j = m; j < k+l; j++)
322 R.xelem (i, j) = btmp.xelem (i - k, astart + j);
323 }
324 }
325 }
326
327 if (m-k-l >= 0)
328 {
329 // Fills in C and S
330 sigmaA.resize (l, l);
331 sigmaB.resize (l, l);
332 for (i = 0; i < l; i++)
333 {
334 sigmaA.dgxelem(i) = alpha.elem(k+i);
335 sigmaB.dgxelem(i) = beta.elem(k+i);
336 }
337 }
338 else
339 {
340 // Fills in C and S
341 sigmaA.resize (m-k, m-k);
342 sigmaB.resize (m-k, m-k);
343 for (i = 0; i < m-k; i++)
344 {
345 sigmaA.dgxelem(i) = alpha.elem(k+i);
346 sigmaB.dgxelem(i) = beta.elem(k+i);
347 }
348 }
349 }
350 }
351 }
352
353 // Instantiations we need.
354
355 template class gsvd<Matrix>;
356
357 template class gsvd<ComplexMatrix>;