Branch data Line data Source code
1 : : /*
2 : : * eqnsys.cpp - equation system solver class implementation
3 : : *
4 : : * Copyright (C) 2004, 2005, 2006, 2007, 2008 Stefan Jahn <stefan@lkcc.org>
5 : : *
6 : : * This is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 2, or (at your option)
9 : : * any later version.
10 : : *
11 : : * This software is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this package; see the file COPYING. If not, write to
18 : : * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19 : : * Boston, MA 02110-1301, USA.
20 : : *
21 : : * $Id$
22 : : *
23 : : */
24 : :
25 : : // the types required for qucs library files are defined
26 : : // in qucs_typedefs.h, created by configure from
27 : : // qucs_typedefs.h.in
28 : : #include "qucs_typedefs.h"
29 : :
30 : : #include <assert.h>
31 : : #include <time.h>
32 : : #include <cmath>
33 : : #include <float.h>
34 : :
35 : : #include <limits>
36 : :
37 : : #include "compat.h"
38 : : #include "logging.h"
39 : : #include "precision.h"
40 : : #include "complex.h"
41 : : #include "tmatrix.h"
42 : : #include "eqnsys.h"
43 : : #include "exception.h"
44 : : #include "exceptionstack.h"
45 : :
46 : : //! Little helper macro.
47 : : #define Swap(type,a,b) { type t; t = a; a = b; b = t; }
48 : :
49 : : namespace qucs {
50 : :
51 : : //! Constructor creates an unnamed instance of the eqnsys class.
52 : : template <class nr_type_t>
53 : 429216 : eqnsys<nr_type_t>::eqnsys () {
54 : 429216 : A = V = NULL;
55 : 429216 : B = X = NULL;
56 : 429216 : S = E = NULL;
57 : 429216 : T = R = NULL;
58 : 429216 : nPvt = NULL;
59 : 429216 : cMap = rMap = NULL;
60 : 429216 : update = 1;
61 : 429216 : pivoting = PIVOT_PARTIAL;
62 : 429216 : N = 0;
63 : 429216 : }
64 : :
65 : : //! Destructor deletes the eqnsys class object.
66 : : template <class nr_type_t>
67 : 429216 : eqnsys<nr_type_t>::~eqnsys () {
68 [ - + ][ # # ]: 429216 : if (R != NULL) delete R;
69 [ - + ][ # # ]: 429216 : if (T != NULL) delete T;
70 [ + + ][ + - ]: 429216 : if (B != NULL) delete B;
71 [ - + ][ # # ]: 429216 : if (S != NULL) delete S;
72 [ - + ][ # # ]: 429216 : if (E != NULL) delete E;
73 [ - + ][ # # ]: 429216 : if (V != NULL) delete V;
74 [ + + ][ + - ]: 429216 : if (rMap != NULL) delete[] rMap;
75 [ + + ][ + - ]: 429216 : if (cMap != NULL) delete[] cMap;
76 [ + + ][ + - ]: 429216 : if (nPvt != NULL) delete[] nPvt;
77 : 429216 : }
78 : :
79 : : /*! The copy constructor creates a new instance of the eqnsys class
80 : : based on the given eqnsys object. */
81 : : template <class nr_type_t>
82 : 0 : eqnsys<nr_type_t>::eqnsys (eqnsys & e) {
83 : 0 : A = e.A;
84 : 0 : V = NULL;
85 : 0 : S = E = NULL;
86 : 0 : T = R = NULL;
87 [ # # ][ # # ]: 0 : B = e.B ? new tvector<nr_type_t> (*(e.B)) : NULL;
88 : 0 : cMap = rMap = NULL;
89 : 0 : nPvt = NULL;
90 : 0 : update = 1;
91 : 0 : X = e.X;
92 : 0 : N = 0;
93 : 0 : }
94 : :
95 : : /*! With this function the describing matrices for the equation system
96 : : is passed to the equation system solver class. Matrix A is the
97 : : left hand side of the equation system and B the right hand side
98 : : vector. The reference pointer to the X vector is going to be the
99 : : solution vector. The B vector will be locally copied. */
100 : : template <class nr_type_t>
101 : 903249 : void eqnsys<nr_type_t>::passEquationSys (tmatrix<nr_type_t> * nA,
102 : : tvector<nr_type_t> * refX,
103 : : tvector<nr_type_t> * nB) {
104 [ + + ]: 903249 : if (nA != NULL) {
105 : 877587 : A = nA;
106 : 877587 : update = 1;
107 [ + + ]: 877587 : if (N != A->getCols ()) {
108 : 216152 : N = A->getCols ();
109 [ + + ][ + - ]: 216152 : if (cMap) delete[] cMap; cMap = new int[N];
110 [ + + ][ + - ]: 216152 : if (rMap) delete[] rMap; rMap = new int[N];
111 [ + + ][ + - ]: 216152 : if (nPvt) delete[] nPvt; nPvt = new nr_double_t[N];
112 : : }
113 : : }
114 : : else {
115 : 25662 : update = 0;
116 : : }
117 [ + + ][ + - ]: 903249 : if (B != NULL) delete B;
118 [ + - ]: 903249 : B = new tvector<nr_type_t> (*nB);
119 : 903249 : X = refX;
120 : 903249 : }
121 : :
122 : : /*! Depending on the algorithm applied to the equation system solver
123 : : the function stores the solution of the system into the matrix
124 : : pointed to by the X matrix reference. */
125 : : template <class nr_type_t>
126 : 903249 : void eqnsys<nr_type_t>::solve (void) {
127 : : #if DEBUG && 0
128 : : time_t t = time (NULL);
129 : : #endif
130 [ - - - + : 903249 : switch (algo) {
- + - + -
- - - - -
- - ]
131 : : case ALGO_INVERSE:
132 : 0 : solve_inverse ();
133 : 0 : break;
134 : : case ALGO_GAUSS:
135 : 0 : solve_gauss ();
136 : 0 : break;
137 : : case ALGO_GAUSS_JORDAN:
138 : 0 : solve_gauss_jordan ();
139 : 0 : break;
140 : : case ALGO_LU_DECOMPOSITION_CROUT:
141 : 874546 : solve_lu_crout ();
142 : 874546 : break;
143 : : case ALGO_LU_DECOMPOSITION_DOOLITTLE:
144 : 0 : solve_lu_doolittle ();
145 : 0 : break;
146 : : case ALGO_LU_FACTORIZATION_CROUT:
147 : 3005 : factorize_lu_crout ();
148 : 3005 : break;
149 : : case ALGO_LU_FACTORIZATION_DOOLITTLE:
150 : 0 : factorize_lu_doolittle ();
151 : 0 : break;
152 : : case ALGO_LU_SUBSTITUTION_CROUT:
153 : 25698 : substitute_lu_crout ();
154 : 25698 : break;
155 : : case ALGO_LU_SUBSTITUTION_DOOLITTLE:
156 : 0 : substitute_lu_doolittle ();
157 : 0 : break;
158 : : case ALGO_JACOBI: case ALGO_GAUSS_SEIDEL:
159 : 0 : solve_iterative ();
160 : 0 : break;
161 : : case ALGO_SOR:
162 : 0 : solve_sor ();
163 : 0 : break;
164 : : case ALGO_QR_DECOMPOSITION:
165 : 0 : solve_qr ();
166 : 0 : break;
167 : : case ALGO_QR_DECOMPOSITION_LS:
168 : 0 : solve_qr_ls ();
169 : 0 : break;
170 : : case ALGO_SV_DECOMPOSITION:
171 : 0 : solve_svd ();
172 : 0 : break;
173 : : case ALGO_QR_DECOMPOSITION_2:
174 : 0 : solve_qrh ();
175 : 0 : break;
176 : : }
177 : : #if DEBUG && 0
178 : : logprint (LOG_STATUS, "NOTIFY: %dx%d eqnsys solved in %ld seconds\n",
179 : : A->getRows (), A->getCols (), time (NULL) - t);
180 : : #endif
181 : 903249 : }
182 : :
183 : : /*! Simple matrix inversion is used to solve the equation system. */
184 : : template <class nr_type_t>
185 : 0 : void eqnsys<nr_type_t>::solve_inverse (void) {
186 [ # # ][ # # ]: 0 : *X = inverse (*A) * *B;
[ # # ][ # # ]
187 : 0 : }
188 : :
189 : : #define A_ (*A)
190 : : #define X_ (*X)
191 : : #define B_ (*B)
192 : :
193 : : /*! The function solves the equation system applying Gaussian
194 : : elimination with full column pivoting only (no row pivoting). */
195 : : template <class nr_type_t>
196 : 0 : void eqnsys<nr_type_t>::solve_gauss (void) {
197 : : nr_double_t MaxPivot;
198 : 0 : nr_type_t f;
199 : : int i, c, r, pivot;
200 : :
201 : : // triangulate the matrix
202 [ # # ]: 0 : for (i = 0; i < N; i++) {
203 : : // find maximum column value for pivoting
204 [ # # ]: 0 : for (MaxPivot = 0, pivot = r = i; r < N; r++) {
205 [ # # ][ # # ]: 0 : if (abs (A_(r, i)) > MaxPivot) {
[ # # ]
206 [ # # ]: 0 : MaxPivot = abs (A_(r, i));
207 : 0 : pivot = r;
208 : : }
209 : : }
210 : : // exchange rows if necessary
211 [ # # ]: 0 : assert (MaxPivot != 0);
212 [ # # ]: 0 : if (i != pivot) {
213 [ # # ]: 0 : A->exchangeRows (i, pivot);
214 [ # # ]: 0 : B->exchangeRows (i, pivot);
215 : : }
216 : : // compute new rows and columns
217 [ # # ]: 0 : for (r = i + 1; r < N; r++) {
218 [ # # ][ # # ]: 0 : f = A_(r, i) / A_(i, i);
[ # # ]
219 [ # # ][ # # ]: 0 : for (c = i + 1; c < N; c++) A_(r, c) -= f * A_(i, c);
[ # # ][ # # ]
[ # # ]
220 [ # # ][ # # ]: 0 : B_(r) -= f * B_(i);
[ # # ]
221 : : }
222 : : }
223 : :
224 : : // backward substitution
225 [ # # ][ # # ]: 0 : for (i = N - 1; i >= 0; i--) {
226 [ # # ]: 0 : f = B_(i);
227 [ # # ][ # # ]: 0 : for (c = i + 1; c < N; c++) f -= A_(i, c) * X_(c);
[ # # ][ # # ]
[ # # ]
228 [ # # ][ # # ]: 0 : X_(i) = f / A_(i, i);
[ # # ]
229 : : }
230 : 0 : }
231 : :
232 : : /*! The function solves the equation system applying a modified
233 : : Gaussian elimination with full column pivoting only (no row
234 : : pivoting). */
235 : : template <class nr_type_t>
236 : 0 : void eqnsys<nr_type_t>::solve_gauss_jordan (void) {
237 : : nr_double_t MaxPivot;
238 : 0 : nr_type_t f;
239 : : int i, c, r, pivot;
240 : :
241 : : // create the eye matrix
242 [ # # ]: 0 : for (i = 0; i < N; i++) {
243 : : // find maximum column value for pivoting
244 [ # # ]: 0 : for (MaxPivot = 0, pivot = r = i; r < N; r++) {
245 [ # # ][ # # ]: 0 : if (abs (A_(r, i)) > MaxPivot) {
[ # # ]
246 [ # # ]: 0 : MaxPivot = abs (A_(r, i));
247 : 0 : pivot = r;
248 : : }
249 : : }
250 : : // exchange rows if necessary
251 [ # # ]: 0 : assert (MaxPivot != 0);
252 [ # # ]: 0 : if (i != pivot) {
253 [ # # ]: 0 : A->exchangeRows (i, pivot);
254 [ # # ]: 0 : B->exchangeRows (i, pivot);
255 : : }
256 : :
257 : : // compute current row
258 [ # # ]: 0 : f = A_(i, i);
259 [ # # ][ # # ]: 0 : for (c = i + 1; c < N; c++) A_(i, c) /= f;
[ # ]
260 [ # # ]: 0 : B_(i) /= f;
261 : :
262 : : // compute new rows and columns
263 [ # # ]: 0 : for (r = 0; r < N; r++) {
264 [ # # ]: 0 : if (r != i) {
265 [ # # ]: 0 : f = A_(r, i);
266 [ # # ][ # # ]: 0 : for (c = i + 1; c < N; c++) A_(r, c) -= f * A_(i, c);
[ # # ][ # # ]
[ # # ]
267 [ # # ][ # # ]: 0 : B_(r) -= f * B_(i);
[ # # ]
268 : : }
269 : : }
270 : : }
271 : :
272 : : // right hand side is now the solution
273 [ # # ]: 0 : *X = *B;
274 : 0 : }
275 : :
276 : : #define LU_FAILURE 0
277 : : #define VIRTUAL_RES(txt,i) { \
278 : : qucs::exception * e = new qucs::exception (EXCEPTION_SINGULAR); \
279 : : e->setText (txt); \
280 : : e->setData (rMap[i]); \
281 : : A_(i, i) = NR_TINY; /* virtual resistance to ground */ \
282 : : throw_exception (e); }
283 : :
284 : : /*! The function uses LU decomposition and the appropriate forward and
285 : : backward substitutions in order to solve the linear equation
286 : : system. It is very useful when dealing with equation systems where
287 : : the left hand side (the A matrix) does not change but the right
288 : : hand side (the B vector) only. */
289 : : template <class nr_type_t>
290 : 874546 : void eqnsys<nr_type_t>::solve_lu_crout (void) {
291 : :
292 : : // skip decomposition if requested
293 [ + - ]: 874546 : if (update) {
294 : : // perform LU composition
295 : 874546 : factorize_lu_crout ();
296 : : }
297 : :
298 : : // finally solve the equation system
299 : 874546 : substitute_lu_crout ();
300 : 874546 : }
301 : :
302 : : /*! The other LU decomposition. */
303 : : template <class nr_type_t>
304 : 0 : void eqnsys<nr_type_t>::solve_lu_doolittle (void) {
305 : :
306 : : // skip decomposition if requested
307 [ # # ]: 0 : if (update) {
308 : : // perform LU composition
309 : 0 : factorize_lu_doolittle ();
310 : : }
311 : :
312 : : // finally solve the equation system
313 : 0 : substitute_lu_doolittle ();
314 : 0 : }
315 : :
316 : : /*! This function decomposes the left hand matrix into an upper U and
317 : : lower L matrix. The algorithm is called LU decomposition (Crout's
318 : : definition). The function performs the actual LU decomposition of
319 : : the matrix A using (implicit) partial row pivoting. */
320 : : template <class nr_type_t>
321 : 877551 : void eqnsys<nr_type_t>::factorize_lu_crout (void) {
322 : : nr_double_t d, MaxPivot;
323 : 9678 : nr_type_t f;
324 : : int k, c, r, pivot;
325 : :
326 : : // initialize pivot exchange table
327 [ + + ]: 6729518 : for (r = 0; r < N; r++) {
328 [ + + ]: 65252782 : for (MaxPivot = 0, c = 0; c < N; c++)
329 [ + - ][ + + ]: 59400815 : if ((d = abs (A_(r, c))) > MaxPivot)
[ + + ]
330 : 8969988 : MaxPivot = d;
331 [ - + ]: 5851967 : if (MaxPivot <= 0) MaxPivot = NR_TINY;
332 : 5851967 : nPvt[r] = 1 / MaxPivot;
333 : 5851967 : rMap[r] = r;
334 : : }
335 : :
336 : : // decompose the matrix into L (lower) and U (upper) matrix
337 [ + + ]: 6729518 : for (c = 0; c < N; c++) {
338 : : // upper matrix entries
339 [ + + ][ + + ]: 32626391 : for (r = 0; r < c; r++) {
340 [ + - ]: 26774424 : f = A_(r, c);
341 [ + - ][ + - ]: 155872495 : for (k = 0; k < r; k++) f -= A_(r, k) * A_(k, c);
[ + - ][ + + ]
[ + + ]
342 [ + - ][ + - ]: 26774424 : A_(r, c) = f / A_(r, r);
[ + - ]
343 : : }
344 : : // lower matrix entries
345 [ + + ]: 38478358 : for (MaxPivot = 0, pivot = r; r < N; r++) {
346 [ + - ]: 32626391 : f = A_(r, c);
347 [ + - ][ + - ]: 188498886 : for (k = 0; k < c; k++) f -= A_(r, k) * A_(k, c);
[ + - ][ + + ]
[ + + ]
348 [ + - ]: 32626391 : A_(r, c) = f;
349 : : // larger pivot ?
350 [ + + ][ + + ]: 32626391 : if ((d = nPvt[r] * abs (f)) > MaxPivot) {
351 : 8205638 : MaxPivot = d;
352 : 8205638 : pivot = r;
353 : : }
354 : : }
355 : :
356 : : // check pivot element and throw appropriate exception
357 [ + + ]: 5851967 : if (MaxPivot <= 0) {
358 : : #if LU_FAILURE
359 : : qucs::exception * e = new qucs::exception (EXCEPTION_PIVOT);
360 : : e->setText ("no pivot != 0 found during Crout LU decomposition");
361 : : e->setData (c);
362 : : throw_exception (e);
363 : : goto fail;
364 : : #else /* insert virtual resistance */
365 [ # + ][ # # ]: 17 : VIRTUAL_RES ("no pivot != 0 found during Crout LU decomposition", c);
[ # # ][ # # ]
[ # # ][ - ]
366 : : #endif
367 : : }
368 : :
369 : : // swap matrix rows if necessary and remember that step in the
370 : : // exchange table
371 [ + + ]: 5851967 : if (c != pivot) {
372 [ + - ]: 2224451 : A->exchangeRows (c, pivot);
373 : 2224451 : Swap (int, rMap[c], rMap[pivot]);
374 : 2224451 : Swap (nr_double_t, nPvt[c], nPvt[pivot]);
375 : : }
376 : : }
377 : : #if LU_FAILURE
378 : : fail:
379 : : #endif
380 : 877551 : }
381 : :
382 : : /*! This function decomposes the left hand matrix into an upper U and
383 : : lower L matrix. The algorithm is called LU decomposition
384 : : (Doolittle's definition). The function performs the actual LU
385 : : decomposition of the matrix A using (implicit) partial row pivoting. */
386 : : template <class nr_type_t>
387 : 0 : void eqnsys<nr_type_t>::factorize_lu_doolittle (void) {
388 : : nr_double_t d, MaxPivot;
389 : 0 : nr_type_t f;
390 : : int k, c, r, pivot;
391 : :
392 : : // initialize pivot exchange table
393 [ # # ]: 0 : for (r = 0; r < N; r++) {
394 [ # # ]: 0 : for (MaxPivot = 0, c = 0; c < N; c++)
395 [ # # ][ # # ]: 0 : if ((d = abs (A_(r, c))) > MaxPivot)
[ # # ]
396 : 0 : MaxPivot = d;
397 [ # # ]: 0 : if (MaxPivot <= 0) MaxPivot = NR_TINY;
398 : 0 : nPvt[r] = 1 / MaxPivot;
399 : 0 : rMap[r] = r;
400 : : }
401 : :
402 : : // decompose the matrix into L (lower) and U (upper) matrix
403 [ # # ]: 0 : for (c = 0; c < N; c++) {
404 : : // upper matrix entries
405 [ # # ][ # # ]: 0 : for (r = 0; r < c; r++) {
406 [ # # ]: 0 : f = A_(r, c);
407 [ # # ][ # # ]: 0 : for (k = 0; k < r; k++) f -= A_(r, k) * A_(k, c);
[ # # ][ # # ]
[ # # ]
408 [ # # ]: 0 : A_(r, c) = f;
409 : : }
410 : : // lower matrix entries
411 [ # # ]: 0 : for (MaxPivot = 0, pivot = r; r < N; r++) {
412 [ # # ]: 0 : f = A_(r, c);
413 [ # # ][ # # ]: 0 : for (k = 0; k < c; k++) f -= A_(r, k) * A_(k, c);
[ # # ][ # # ]
[ # # ]
414 [ # # ]: 0 : A_(r, c) = f;
415 : : // larger pivot ?
416 [ # # ][ # # ]: 0 : if ((d = nPvt[r] * abs (f)) > MaxPivot) {
417 : 0 : MaxPivot = d;
418 : 0 : pivot = r;
419 : : }
420 : : }
421 : :
422 : : // check pivot element and throw appropriate exception
423 [ # # ]: 0 : if (MaxPivot <= 0) {
424 : : #if LU_FAILURE
425 : : qucs::exception * e = new qucs::exception (EXCEPTION_PIVOT);
426 : : e->setText ("no pivot != 0 found during Doolittle LU decomposition");
427 : : e->setData (c);
428 : : throw_exception (e);
429 : : goto fail;
430 : : #else /* insert virtual resistance */
431 [ # # ][ # # ]: 0 : VIRTUAL_RES ("no pivot != 0 found during Doolittle LU decomposition", c);
[ # # ][ # # ]
[ # # ][ # ]
432 : : #endif
433 : : }
434 : :
435 : : // swap matrix rows if necessary and remember that step in the
436 : : // exchange table
437 [ # # ]: 0 : if (c != pivot) {
438 [ # # ]: 0 : A->exchangeRows (c, pivot);
439 : 0 : Swap (int, rMap[c], rMap[pivot]);
440 : 0 : Swap (nr_double_t, nPvt[c], nPvt[pivot]);
441 : : }
442 : :
443 : : // finally divide by the pivot element
444 [ # # ]: 0 : if (c < N - 1) {
445 [ # # ]: 0 : f = 1.0 / A_(c, c);
446 [ # # ][ # # ]: 0 : for (r = c + 1; r < N; r++) A_(r, c) *= f;
[ # # ]
447 : : }
448 : : }
449 : : #if LU_FAILURE
450 : : fail:
451 : : #endif
452 : 0 : }
453 : :
454 : : /*! The function is used in order to run the forward and backward
455 : : substitutions using the LU decomposed matrix (Crout's definition -
456 : : Uii are ones). */
457 : : template <class nr_type_t>
458 : 900244 : void eqnsys<nr_type_t>::substitute_lu_crout (void) {
459 : 32371 : nr_type_t f;
460 : : int i, c;
461 : :
462 : : // forward substitution in order to solve LY = B
463 [ + + ][ + + ]: 6953118 : for (i = 0; i < N; i++) {
464 [ + - ]: 6052874 : f = B_(rMap[i]);
465 [ + - ][ + - ]: 33637883 : for (c = 0; c < i; c++) f -= A_(i, c) * X_(c);
[ + - ][ + + ]
[ + + ]
466 [ + - ][ + - ]: 6052874 : X_(i) = f / A_(i, i);
[ + - ]
467 : : }
468 : :
469 : : // backward substitution in order to solve UX = Y
470 [ + + ][ + + ]: 6953118 : for (i = N - 1; i >= 0; i--) {
471 [ + - ]: 6052874 : f = X_(i);
472 [ + - ][ + - ]: 33637883 : for (c = i + 1; c < N; c++) f -= A_(i, c) * X_(c);
[ + - ][ + + ]
[ + + ]
473 : : // remember that the Uii diagonal are ones only in Crout's definition
474 [ + - ]: 6052874 : X_(i) = f;
475 : : }
476 : 900244 : }
477 : :
478 : : /*! The function is used in order to run the forward and backward
479 : : substitutions using the LU decomposed matrix (Doolittle's
480 : : definition - Lii are ones). This function is here because of
481 : : transposed LU matrices as used in the AC noise analysis. */
482 : : template <class nr_type_t>
483 : 0 : void eqnsys<nr_type_t>::substitute_lu_doolittle (void) {
484 : 0 : nr_type_t f;
485 : : int i, c;
486 : :
487 : : // forward substitution in order to solve LY = B
488 [ # # ][ # # ]: 0 : for (i = 0; i < N; i++) {
489 [ # # ]: 0 : f = B_(rMap[i]);
490 [ # # ][ # # ]: 0 : for (c = 0; c < i; c++) f -= A_(i, c) * X_(c);
[ # # ][ # # ]
[ # # ]
491 : : // remember that the Lii diagonal are ones only in Doolittle's definition
492 [ # # ]: 0 : X_(i) = f;
493 : : }
494 : :
495 : : // backward substitution in order to solve UX = Y
496 [ # # ][ # # ]: 0 : for (i = N - 1; i >= 0; i--) {
497 [ # # ]: 0 : f = X_(i);
498 [ # # ][ # # ]: 0 : for (c = i + 1; c < N; c++) f -= A_(i, c) * X_(c);
[ # # ][ # # ]
[ # # ]
499 [ # # ][ # # ]: 0 : X_(i) = f / A_(i, i);
[ # # ]
500 : : }
501 : 0 : }
502 : :
503 : : /*! The function solves the equation system using a full-step iterative
504 : : method (called Jacobi's method) or a single-step method (called
505 : : Gauss-Seidel) depending on the given algorithm. If the current X
506 : : vector (the solution vector) is the solution within a
507 : : Newton-Raphson iteration it is a good initial guess and the method
508 : : is very likely to converge. On divergence the method falls back to
509 : : LU decomposition. */
510 : : template <class nr_type_t>
511 : 0 : void eqnsys<nr_type_t>::solve_iterative (void) {
512 : 0 : nr_type_t f;
513 : : int error, conv, i, c, r;
514 : 0 : int MaxIter = N; // -> less than N^3 operations
515 : 0 : nr_double_t reltol = 1e-4;
516 : 0 : nr_double_t abstol = NR_TINY;
517 : : nr_double_t diff, crit;
518 : :
519 : : // ensure that all diagonal values are non-zero
520 [ # # ]: 0 : ensure_diagonal ();
521 : :
522 : : // try to raise diagonal dominance
523 [ # # ]: 0 : preconditioner ();
524 : :
525 : : // decide here about possible convergence
526 [ # # ]: 0 : if ((crit = convergence_criteria ()) >= 1) {
527 : : #if DEBUG && 0
528 : : logprint (LOG_STATUS, "NOTIFY: convergence criteria: %g >= 1 (%dx%d)\n",
529 : : crit, N, N);
530 : : #endif
531 : : //solve_lu ();
532 : : //return;
533 : : }
534 : :
535 : : // normalize the equation system to have ones on its diagonal
536 [ # # ][ # # ]: 0 : for (r = 0; r < N; r++) {
537 [ # # ]: 0 : f = A_(r, r);
538 [ # # ][ # # ]: 0 : assert (f != 0); // singular matrix
[ # # ]
539 [ # # ][ # # ]: 0 : for (c = 0; c < N; c++) A_(r, c) /= f;
[ # # ]
540 [ # # ]: 0 : B_(r) /= f;
541 : : }
542 : :
543 : : // the current X vector is a good initial guess for the iteration
544 [ # # ][ # # ]: 0 : tvector<nr_type_t> * Xprev = new tvector<nr_type_t> (*X);
[ # ]
545 : :
546 : : // start iterating here
547 : 0 : i = 0; error = 0;
548 [ # # ][ # # ]: 0 : do {
[ # # ][ # # ]
[ # # ][ # # ]
549 : : // compute new solution vector
550 [ # # ]: 0 : for (r = 0; r < N; r++) {
551 [ # # # ]: 0 : for (f = 0, c = 0; c < N; c++) {
552 [ # # ]: 0 : if (algo == ALGO_GAUSS_SEIDEL) {
553 : : // Gauss-Seidel
554 [ # # ][ # # ]: 0 : if (c < r) f += A_(r, c) * X_(c);
[ # # ][ # # ]
555 [ # # ][ # # ]: 0 : else if (c > r) f += A_(r, c) * Xprev->get (c);
[ # # ][ # # ]
556 : : }
557 : : else {
558 : : // Jacobi
559 [ # # ][ # # ]: 0 : if (c != r) f += A_(r, c) * Xprev->get (c);
[ # # ][ # # ]
560 : : }
561 : : }
562 [ # # ][ # # ]: 0 : X_(r) = B_(r) - f;
563 : : }
564 : : // check for convergence
565 [ # # ]: 0 : for (conv = 1, r = 0; r < N; r++) {
566 [ # # ][ # # ]: 0 : diff = abs (X_(r) - Xprev->get (r));
567 [ # # ][ # # ]: 0 : if (diff >= abstol + reltol * abs (X_(r))) {
[ # # ]
568 : 0 : conv = 0;
569 : 0 : break;
570 : : }
571 [ # # ]: 0 : if (!std::isfinite (diff)) { error++; break; }
572 : : }
573 : : // save last values
574 [ # # ]: 0 : *Xprev = *X;
575 : : }
576 : : while (++i < MaxIter && !conv);
577 : :
578 [ # # ]: 0 : delete Xprev;
579 : :
580 [ # # ][ # # ]: 0 : if (!conv || error) {
581 : : logprint (LOG_ERROR,
582 : : "WARNING: no convergence after %d %s iterations\n",
583 [ # # ][ # # ]: 0 : i, algo == ALGO_JACOBI ? "jacobi" : "gauss-seidel");
584 [ # # ]: 0 : solve_lu_crout ();
585 : : }
586 : : #if DEBUG && 0
587 : : else {
588 : : logprint (LOG_STATUS,
589 : : "NOTIFY: %s convergence after %d iterations\n",
590 : : algo == ALGO_JACOBI ? "jacobi" : "gauss-seidel", i);
591 : : }
592 : : #endif
593 : 0 : }
594 : :
595 : : /*! The function solves the linear equation system using a single-step
596 : : iterative algorithm. It is a modification of the Gauss-Seidel
597 : : method and is called successive over relaxation. The function uses
598 : : an adaptive scheme to adjust the relaxation parameter. */
599 : : template <class nr_type_t>
600 : 0 : void eqnsys<nr_type_t>::solve_sor (void) {
601 : 0 : nr_type_t f;
602 : : int error, conv, i, c, r;
603 : 0 : int MaxIter = N; // -> less than N^3 operations
604 : 0 : nr_double_t reltol = 1e-4;
605 : 0 : nr_double_t abstol = NR_TINY;
606 : 0 : nr_double_t diff, crit, l = 1, d, s;
607 : :
608 : : // ensure that all diagonal values are non-zero
609 [ # # ]: 0 : ensure_diagonal ();
610 : :
611 : : // try to raise diagonal dominance
612 [ # # ]: 0 : preconditioner ();
613 : :
614 : : // decide here about possible convergence
615 [ # # ]: 0 : if ((crit = convergence_criteria ()) >= 1) {
616 : : #if DEBUG && 0
617 : : logprint (LOG_STATUS, "NOTIFY: convergence criteria: %g >= 1 (%dx%d)\n",
618 : : crit, N, N);
619 : : #endif
620 : : //solve_lu ();
621 : : //return;
622 : : }
623 : :
624 : : // normalize the equation system to have ones on its diagonal
625 [ # # ][ # # ]: 0 : for (r = 0; r < N; r++) {
626 [ # # ]: 0 : f = A_(r, r);
627 [ # # ][ # # ]: 0 : assert (f != 0); // singular matrix
[ # # ]
628 [ # # ][ # # ]: 0 : for (c = 0; c < N; c++) A_(r, c) /= f;
[ # # ]
629 [ # # ]: 0 : B_(r) /= f;
630 : : }
631 : :
632 : : // the current X vector is a good initial guess for the iteration
633 [ # # ][ # # ]: 0 : tvector<nr_type_t> * Xprev = new tvector<nr_type_t> (*X);
[ # ]
634 : :
635 : : // start iterating here
636 : 0 : i = 0; error = 0;
637 [ # # ][ # # ]: 0 : do {
[ # # ][ # # ]
[ # # ][ # # ]
638 : : // compute new solution vector
639 [ # # ]: 0 : for (r = 0; r < N; r++) {
640 [ # # # ]: 0 : for (f = 0, c = 0; c < N; c++) {
641 [ # # ][ # # ]: 0 : if (c < r) f += A_(r, c) * X_(c);
[ # # ][ # # ]
642 [ # # ][ # # ]: 0 : else if (c > r) f += A_(r, c) * Xprev->get (c);
[ # # ][ # # ]
643 : : }
644 [ # # ][ # # ]: 0 : X_(r) = (1 - l) * Xprev->get (r) + l * (B_(r) - f);
[ # # ]
645 : : }
646 : : // check for convergence
647 [ # # ]: 0 : for (s = 0, d = 0, conv = 1, r = 0; r < N; r++) {
648 [ # # ][ # # ]: 0 : diff = abs (X_(r) - Xprev->get (r));
649 [ # # ][ # # ]: 0 : if (diff >= abstol + reltol * abs (X_(r))) {
[ # # ]
650 : 0 : conv = 0;
651 : 0 : break;
652 : : }
653 [ # # ]: 0 : d += diff; s += abs (X_(r));
654 [ # # ]: 0 : if (!std::isfinite (diff)) { error++; break; }
655 : : }
656 [ # # ]: 0 : if (!error) {
657 : : // adjust relaxation based on average errors
658 [ # # ][ # # ]: 0 : if ((s == 0 && d == 0) || d >= abstol * N + reltol * s) {
[ # # ]
659 : : // values <= 1 -> non-convergence to convergence
660 [ # # ]: 0 : if (l >= 0.6) l -= 0.1;
661 [ # # ]: 0 : if (l >= 1.0) l = 1.0;
662 : : }
663 : : else {
664 : : // values >= 1 -> faster convergence
665 [ # # ]: 0 : if (l < 1.5) l += 0.01;
666 [ # # ]: 0 : if (l < 1.0) l = 1.0;
667 : : }
668 : : }
669 : : // save last values
670 [ # # ]: 0 : *Xprev = *X;
671 : : }
672 : : while (++i < MaxIter && !conv);
673 : :
674 [ # # ]: 0 : delete Xprev;
675 : :
676 [ # # ][ # # ]: 0 : if (!conv || error) {
677 : : logprint (LOG_ERROR,
678 : : "WARNING: no convergence after %d sor iterations (l = %g)\n",
679 [ # # ]: 0 : i, l);
680 [ # # ]: 0 : solve_lu_crout ();
681 : : }
682 : : #if DEBUG && 0
683 : : else {
684 : : logprint (LOG_STATUS,
685 : : "NOTIFY: sor convergence after %d iterations\n", i);
686 : : }
687 : : #endif
688 : 0 : }
689 : :
690 : : /*! The function computes the convergence criteria for iterative
691 : : methods like Jacobi or Gauss-Seidel as defined by Schmidt and
692 : : v.Mises. */
693 : : template <class nr_type_t>
694 : 0 : nr_double_t eqnsys<nr_type_t>::convergence_criteria (void) {
695 : 0 : nr_double_t f = 0;
696 [ # # ]: 0 : for (int r = 0; r < A->getCols (); r++) {
697 [ # # ]: 0 : for (int c = 0; c < A->getCols (); c++) {
698 [ # # ]: 0 : if (r != c) f += norm (A_(r, c) / A_(r, r));
699 : : }
700 : : }
701 : 0 : return sqrt (f);
702 : : }
703 : :
704 : : /*! The function tries to ensure that there are non-zero diagonal
705 : : elements in the equation system matrix A. This is required for
706 : : iterative solution methods. */
707 : : template <class nr_type_t>
708 : 0 : void eqnsys<nr_type_t>::ensure_diagonal (void) {
709 : 0 : ensure_diagonal_MNA ();
710 : 0 : }
711 : :
712 : : /*! The function ensures that there are non-zero diagonal elements in
713 : : the equation system matrix A. It achieves this condition for
714 : : non-singular matrices which have been produced by the modified
715 : : nodal analysis. It takes advantage of the fact that the zero
716 : : diagonal elements have pairs of 1 and -1 on the same column and
717 : : row. */
718 : : template <class nr_type_t>
719 : 0 : void eqnsys<nr_type_t>::ensure_diagonal_MNA (void) {
720 : 0 : int restart, exchanged, begin = 0, pairs;
721 : : int pivot1, pivot2, i;
722 [ # # ]: 0 : do {
723 : 0 : restart = exchanged = 0;
724 : : /* search for zero diagonals with lone pairs */
725 [ # # ]: 0 : for (i = begin; i < N; i++) {
726 [ # # ][ # # ]: 0 : if (A_(i, i) == 0) {
[ # # ][ # ]
[ # ]
727 [ # # ]: 0 : pairs = countPairs (i, pivot1, pivot2);
728 [ # # ]: 0 : if (pairs == 1) { /* lone pair found, substitute rows */
729 [ # # ]: 0 : A->exchangeRows (i, pivot1);
730 [ # # ]: 0 : B->exchangeRows (i, pivot1);
731 : 0 : exchanged = 1;
732 : : }
733 [ # # ][ # # ]: 0 : else if ((pairs > 1) && !restart) {
734 : 0 : restart = 1;
735 : 0 : begin = i;
736 : : }
737 : : }
738 : : }
739 : :
740 : : /* all lone pairs are gone, look for zero diagonals with multiple pairs */
741 [ # # ]: 0 : if (restart) {
742 [ # # ][ # # ]: 0 : for (i = begin; !exchanged && i < N; i++) {
[ # # ]
743 [ # # ][ # # ]: 0 : if (A_(i, i) == 0) {
[ # # ][ # ]
[ # ]
744 [ # # ]: 0 : pairs = countPairs (i, pivot1, pivot2);
745 [ # # ]: 0 : A->exchangeRows (i, pivot1);
746 [ # # ]: 0 : B->exchangeRows (i, pivot1);
747 : 0 : exchanged = 1;
748 : : }
749 : : }
750 : : }
751 : : }
752 : : while (restart);
753 : 0 : }
754 : :
755 : : /*! Helper function for the above ensure_diagonal_MNA() function. It
756 : : looks for the pairs of 1 and -1 on the given row and column index. */
757 : : template <class nr_type_t>
758 : 0 : int eqnsys<nr_type_t>::countPairs (int i, int& r1, int& r2) {
759 : 0 : int pairs = 0;
760 [ # # ]: 0 : for (int r = 0; r < N; r++) {
761 [ # # ]: 0 : if (fabs (real (A_(r, i))) == 1.0) {
762 : 0 : r1 = r;
763 : 0 : pairs++;
764 [ # # ]: 0 : for (r++; r < N; r++) {
765 [ # # ]: 0 : if (fabs (real (A_(r, i))) == 1.0) {
766 : 0 : r2 = r;
767 [ # # ]: 0 : if (++pairs >= 2) return pairs;
768 : : }
769 : : }
770 : : }
771 : : }
772 : 0 : return pairs;
773 : : }
774 : :
775 : : /*! The function tries to raise the absolute value of diagonal elements
776 : : by swapping rows and thereby make the A matrix diagonally
777 : : dominant. */
778 : : template <class nr_type_t>
779 : 0 : void eqnsys<nr_type_t>::preconditioner (void) {
780 : : int pivot, r;
781 : : nr_double_t MaxPivot;
782 [ # # ]: 0 : for (int i = 0; i < N; i++) {
783 : : // find maximum column value for pivoting
784 [ # # ]: 0 : for (MaxPivot = 0, pivot = i, r = 0; r < N; r++) {
785 [ # # ][ # # ]: 0 : if (abs (A_(r, i)) > MaxPivot &&
[ # # ]
786 : : abs (A_(i, r)) >= abs (A_(r, r))) {
787 : 0 : MaxPivot = abs (A_(r, i));
788 : 0 : pivot = r;
789 : : }
790 : : }
791 : : // swap matrix rows if possible
792 [ # # ]: 0 : if (i != pivot) {
793 : 0 : A->exchangeRows (i, pivot);
794 : 0 : B->exchangeRows (i, pivot);
795 : : }
796 : : }
797 : 0 : }
798 : :
799 : : #define R_ (*R)
800 : : #define T_ (*T)
801 : :
802 : : /*! This function uses the QR decomposition using householder
803 : : transformations in order to solve the given equation system. */
804 : : template <class nr_type_t>
805 : 0 : void eqnsys<nr_type_t>::solve_qrh (void) {
806 : 0 : factorize_qrh ();
807 : 0 : substitute_qrh ();
808 : 0 : }
809 : :
810 : : /*! This function uses the QR decomposition using householder
811 : : transformations in order to solve the given equation system. */
812 : : template <class nr_type_t>
813 : 0 : void eqnsys<nr_type_t>::solve_qr (void) {
814 : 0 : factorize_qr_householder ();
815 : 0 : substitute_qr_householder ();
816 : 0 : }
817 : :
818 : : /*! The function uses the QR decomposition using householder
819 : : transformations in order to solve the given under-determined
820 : : equation system in its minimum norm (least square) sense. */
821 : : template <class nr_type_t>
822 : 0 : void eqnsys<nr_type_t>::solve_qr_ls (void) {
823 : 0 : A->transpose ();
824 : 0 : factorize_qr_householder ();
825 : 0 : substitute_qr_householder_ls ();
826 : 0 : }
827 : :
828 : : /*! Helper function for the euclidian norm calculators. */
829 : : static void
830 : 0 : euclidian_update (nr_double_t a, nr_double_t& n, nr_double_t& scale) {
831 : : nr_double_t x, ax;
832 [ # # ]: 0 : if ((x = a) != 0) {
833 : 0 : ax = fabs (x);
834 [ # # ]: 0 : if (scale < ax) {
835 : 0 : x = scale / ax;
836 : 0 : n = 1 + n * x * x;
837 : 0 : scale = ax;
838 : : }
839 : : else {
840 : 0 : x = ax / scale;
841 : 0 : n += x * x;
842 : : }
843 : : }
844 : 0 : }
845 : :
846 : : /*! The following function computes the euclidian norm of the given
847 : : column vector of the matrix A starting from the given row. */
848 : : template <class nr_type_t>
849 : 0 : nr_double_t eqnsys<nr_type_t>::euclidian_c (int c, int r) {
850 : 0 : nr_double_t scale = 0, n = 1;
851 [ # # ]: 0 : for (int i = r; i < N; i++) {
852 [ # # ][ # # ]: 0 : euclidian_update (real (A_(i, c)), n, scale);
853 [ # # ][ # # ]: 0 : euclidian_update (imag (A_(i, c)), n, scale);
854 : : }
855 [ # # ]: 0 : return scale * sqrt (n);
856 : : }
857 : :
858 : : /*! The following function computes the euclidian norm of the given
859 : : row vector of the matrix A starting from the given column. */
860 : : template <class nr_type_t>
861 : 0 : nr_double_t eqnsys<nr_type_t>::euclidian_r (int r, int c) {
862 : 0 : nr_double_t scale = 0, n = 1;
863 [ # # ]: 0 : for (int i = c; i < N; i++) {
864 [ # # ][ # # ]: 0 : euclidian_update (real (A_(r, i)), n, scale);
865 [ # # ][ # # ]: 0 : euclidian_update (imag (A_(r, i)), n, scale);
866 : : }
867 [ # # ]: 0 : return scale * sqrt (n);
868 : : }
869 : :
870 : : template <typename nr_type_t>
871 : 0 : inline nr_type_t cond_conj (nr_type_t t) {
872 : 0 : return std::conj(t);
873 : : }
874 : :
875 : : template <>
876 : 0 : inline double cond_conj (double t) {
877 : 0 : return t;
878 : : }
879 : :
880 : : /*! The function decomposes the matrix A into two matrices, the
881 : : orthonormal matrix Q and the upper triangular matrix R. The
882 : : original matrix is replaced by the householder vectors in the lower
883 : : triangular (including the diagonal) and the upper triangular R
884 : : matrix with its diagonal elements stored in the R vector. */
885 : : template <class nr_type_t>
886 : 0 : void eqnsys<nr_type_t>::factorize_qrh (void) {
887 : : int c, r, k, pivot;
888 : 0 : nr_type_t f, t;
889 : : nr_double_t s, MaxPivot;
890 : :
891 [ # # ][ # # ]: 0 : if (R) delete R; R = new tvector<nr_type_t> (N);
[ # # ][ # # ]
[ # ]
892 : :
893 [ # # ][ # # ]: 0 : for (c = 0; c < N; c++) {
894 : : // compute column norms and save in work array
895 [ # # ]: 0 : nPvt[c] = euclidian_c (c);
896 : 0 : cMap[c] = c; // initialize permutation vector
897 : : }
898 : :
899 [ # # ]: 0 : for (c = 0; c < N; c++) {
900 : :
901 : : // put column with largest norm into pivot position
902 : 0 : MaxPivot = nPvt[c]; pivot = c;
903 [ # # ]: 0 : for (r = c + 1; r < N; r++) {
904 [ # # ]: 0 : if ((s = nPvt[r]) > MaxPivot) {
905 : 0 : pivot = r;
906 : 0 : MaxPivot = s;
907 : : }
908 : : }
909 [ # # ]: 0 : if (pivot != c) {
910 [ # # ]: 0 : A->exchangeCols (pivot, c);
911 : 0 : Swap (int, cMap[pivot], cMap[c]);
912 : 0 : Swap (nr_double_t, nPvt[pivot], nPvt[c]);
913 : : }
914 : :
915 : : // compute householder vector
916 [ # # ]: 0 : if (c < N) {
917 : 0 : nr_type_t a, b;
918 [ # # ]: 0 : s = euclidian_c (c, c + 1);
919 [ # # ]: 0 : a = A_(c, c);
920 [ # # ][ # # ]: 0 : b = -sign (a) * xhypot (a, s); // Wj
921 [ # # ]: 0 : t = xhypot (s, a - b); // || Vi - Wi ||
922 [ # # ]: 0 : R_(c) = b;
923 : : // householder vector entries Ui
924 [ # # ][ # # ]: 0 : A_(c, c) = (a - b) / t;
925 [ # # ][ # # ]: 0 : for (r = c + 1; r < N; r++) A_(r, c) /= t;
[ # ]
926 : : }
927 : : else {
928 [ # # ][ # # ]: 0 : R_(c) = A_(c, c);
929 : : }
930 : :
931 : : // apply householder transformation to remaining columns
932 [ # # ]: 0 : for (r = c + 1; r < N; r++) {
933 [ # # ][ # # ]: 0 : for (f = 0, k = c; k < N; k++) f += cond_conj (A_(k, c)) * A_(k, r);
[ # # ][ # # ]
[ # ]
934 [ # # ][ # # ]: 0 : for (k = c; k < N; k++) A_(k, r) -= 2.0 * f * A_(k, c);
[ # # ][ # # ]
[ # # ]
935 : : }
936 : :
937 : : // update norms of remaining columns too
938 [ # # ][ # # ]: 0 : for (r = c + 1; r < N; r++) {
939 [ # # ]: 0 : nPvt[r] = euclidian_c (r, c + 1);
940 : : }
941 : : }
942 : 0 : }
943 : :
944 : : /*! The function decomposes the matrix A into two matrices, the
945 : : orthonormal matrix Q and the upper triangular matrix R. The
946 : : original matrix is replaced by the householder vectors in the lower
947 : : triangular and the upper triangular R matrix (including the
948 : : diagonal). The householder vectors are normalized to have one in
949 : : their first position. */
950 : : template <class nr_type_t>
951 : 0 : void eqnsys<nr_type_t>::factorize_qr_householder (void) {
952 : : int c, r, pivot;
953 : : nr_double_t s, MaxPivot;
954 : :
955 [ # # ][ # # ]: 0 : if (T) delete T; T = new tvector<nr_type_t> (N);
[ # # ][ # # ]
[ # ]
956 : :
957 [ # # ][ # # ]: 0 : for (c = 0; c < N; c++) {
958 : : // compute column norms and save in work array
959 [ # # ]: 0 : nPvt[c] = euclidian_c (c);
960 : 0 : cMap[c] = c; // initialize permutation vector
961 : : }
962 : :
963 [ # # ]: 0 : for (c = 0; c < N; c++) {
964 : :
965 : : // put column with largest norm into pivot position
966 : 0 : MaxPivot = nPvt[c]; pivot = c;
967 [ # # ]: 0 : for (r = c + 1; r < N; r++)
968 [ # # ]: 0 : if ((s = nPvt[r]) > MaxPivot) {
969 : 0 : pivot = r;
970 : 0 : MaxPivot = s;
971 : : }
972 [ # # ]: 0 : if (pivot != c) {
973 [ # # ]: 0 : A->exchangeCols (pivot, c);
974 : 0 : Swap (int, cMap[pivot], cMap[c]);
975 : 0 : Swap (nr_double_t, nPvt[pivot], nPvt[c]);
976 : : }
977 : :
978 : : // compute and apply householder vector
979 [ # # ][ # # ]: 0 : T_(c) = householder_left (c);
980 : :
981 : : // update norms of remaining columns too
982 [ # # ][ # # ]: 0 : for (r = c + 1; r < N; r++) {
983 [ # # ]: 0 : if ((s = nPvt[r]) > 0) {
984 : 0 : nr_double_t y = 0;
985 [ # # ][ # # ]: 0 : nr_double_t t = norm (A_(c, r) / s);
986 [ # # ][ # # ]: 0 : if (t < 1)
987 [ # # ]: 0 : y = s * sqrt (1 - t);
988 [ # # ]: 0 : if (fabs (y / s) < NR_TINY)
989 [ # # ]: 0 : nPvt[r] = euclidian_c (r, c + 1);
990 : : else
991 : 0 : nPvt[r] = y;
992 : : }
993 : : }
994 : : }
995 : 0 : }
996 : :
997 : : /*! The function uses the householder vectors in order to compute Q'B,
998 : : then the equation system RX = B is solved by backward substitution. */
999 : : template <class nr_type_t>
1000 : 0 : void eqnsys<nr_type_t>::substitute_qrh (void) {
1001 : : int c, r;
1002 : 0 : nr_type_t f;
1003 : :
1004 : : // form the new right hand side Q'B
1005 [ # # ]: 0 : for (c = 0; c < N - 1; c++) {
1006 : : // scalar product u_k^T * B
1007 [ # # ][ # # ]: 0 : for (f = 0, r = c; r < N; r++) f += cond_conj (A_(r, c)) * B_(r);
[ # # ][ # # ]
[ # ]
1008 : : // z - 2 * f * u_k
1009 [ # # ][ # # ]: 0 : for (r = c; r < N; r++) B_(r) -= 2.0 * f * A_(r, c);
[ # # ][ # # ]
[ # # ]
1010 : : }
1011 : :
1012 : : // backward substitution in order to solve RX = Q'B
1013 [ # # ]: 0 : for (r = N - 1; r >= 0; r--) {
1014 [ # # ]: 0 : f = B_(r);
1015 [ # # ][ # # ]: 0 : for (c = r + 1; c < N; c++) f -= A_(r, c) * X_(cMap[c]);
[ # # ][ # # ]
[ # # ]
1016 [ # # ][ # # ]: 0 : if (abs (R_(r)) > std::numeric_limits<nr_double_t>::epsilon())
[ # # ]
1017 [ # # ][ # # ]: 0 : X_(cMap[r]) = f / R_(r);
[ # # ]
1018 : : else
1019 [ # # ]: 0 : X_(cMap[r]) = 0;
1020 : : }
1021 : 0 : }
1022 : :
1023 : : /*! The function uses the householder vectors in order to compute Q'B,
1024 : : then the equation system RX = B is solved by backward substitution. */
1025 : : template <class nr_type_t>
1026 : 0 : void eqnsys<nr_type_t>::substitute_qr_householder (void) {
1027 : : int c, r;
1028 : 0 : nr_type_t f;
1029 : :
1030 : : // form the new right hand side Q'B
1031 [ # # ]: 0 : for (c = 0; c < N; c++) {
1032 [ # # ][ # # ]: 0 : if (T_(c) != 0) {
[ # # ]
1033 : : // scalar product u' * B
1034 [ # # ][ # # ]: 0 : for (f = B_(c), r = c + 1; r < N; r++) f += cond_conj (A_(r, c)) * B_(r);
[ # # ][ # # ]
[ # # ][ # ]
1035 : : // z - T * f * u
1036 [ # # ][ # # ]: 0 : f *= cond_conj (T_(c)); B_(c) -= f;
1037 [ # # ][ # # ]: 0 : for (r = c + 1; r < N; r++) B_(r) -= f * A_(r, c);
[ # # ][ # # ]
[ # ]
1038 : : }
1039 : : }
1040 : :
1041 : : // backward substitution in order to solve RX = Q'B
1042 [ # # ]: 0 : for (r = N - 1; r >= 0; r--) {
1043 [ # # ][ # # ]: 0 : for (f = B_(r), c = r + 1; c < N; c++) f -= A_(r, c) * X_(cMap[c]);
[ # # ][ # # ]
[ # # ]
1044 [ # # ][ # # ]: 0 : if (abs (A_(r, r)) > std::numeric_limits<nr_double_t>::epsilon())
[ # # ]
1045 [ # # ][ # # ]: 0 : X_(cMap[r]) = f / A_(r, r);
[ # # ]
1046 : : else
1047 [ # # ]: 0 : X_(cMap[r]) = 0;
1048 : : }
1049 : 0 : }
1050 : :
1051 : : /*! The function uses the householder vectors in order to the solve the
1052 : : equation system R'X = B by forward substitution, then QX is computed
1053 : : to obtain the least square solution of the under-determined equation
1054 : : system AX = B. */
1055 : : template <class nr_type_t>
1056 : 0 : void eqnsys<nr_type_t>::substitute_qr_householder_ls (void) {
1057 : : int c, r;
1058 : 0 : nr_type_t f;
1059 : :
1060 : : // forward substitution in order to solve R'X = B
1061 [ # # ]: 0 : for (r = 0; r < N; r++) {
1062 [ # # ][ # # ]: 0 : for (f = B_(r), c = 0; c < r; c++) f -= A_(c, r) * B_(c);
[ # # ][ # # ]
[ # # ]
1063 [ # # ][ # # ]: 0 : if (abs (A_(r, r)) > std::numeric_limits<nr_double_t>::epsilon())
[ # # ]
1064 [ # # ][ # # ]: 0 : B_(r) = f / A_(r, r);
[ # # ]
1065 : : else
1066 [ # # ]: 0 : B_(r) = 0;
1067 : : }
1068 : :
1069 : : // compute the least square solution QX
1070 [ # # ]: 0 : for (c = N - 1; c >= 0; c--) {
1071 [ # # ][ # # ]: 0 : if (T_(c) != 0) {
[ # # ]
1072 : : // scalar product u' * B
1073 [ # # ][ # # ]: 0 : for (f = B_(c), r = c + 1; r < N; r++) f += cond_conj (A_(r, c)) * B_(r);
[ # # ][ # # ]
[ # # ][ # ]
1074 : : // z - T * f * u_k
1075 [ # # ][ # # ]: 0 : f *= T_(c); B_(c) -= f;
1076 [ # # ][ # # ]: 0 : for (r = c + 1; r < N; r++) B_(r) -= f * A_(r, c);
[ # # ][ # # ]
[ # ]
1077 : : }
1078 : : }
1079 : :
1080 : : // permute solution vector
1081 [ # # ][ # # ]: 0 : for (r = 0; r < N; r++) X_(cMap[r]) = B_(r);
[ # # ][ # ]
1082 : 0 : }
1083 : :
1084 : : #define sign_(a) (real (a) < 0 ? -1 : 1)
1085 : :
1086 : : /*! The function creates the left-hand householder vector for a given
1087 : : column which eliminates the column except the first element. The
1088 : : householder vector is normalized to have one in the first position.
1089 : : The diagonal element is replaced by the applied householder vector
1090 : : and the vector itself is located in the free matrix positions. The
1091 : : function returns the normalization factor. */
1092 : : template <class nr_type_t>
1093 : 0 : nr_type_t eqnsys<nr_type_t>::householder_create_left (int c) {
1094 : 0 : nr_type_t a, b, t;
1095 : : nr_double_t s, g;
1096 [ # # ]: 0 : s = euclidian_c (c, c + 1);
1097 [ # # ][ # # ]: 0 : if (s == 0 && imag (A_(c, c)) == 0) {
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1098 : : // no reflection necessary
1099 : 0 : t = 0;
1100 : : }
1101 : : else {
1102 : : // calculate householder reflection
1103 [ # # ]: 0 : a = A_(c, c);
1104 [ # # ][ # # ]: 0 : g = sign_(a) * xhypot (a, s);
[ # # ]
1105 : 0 : b = a + g;
1106 : 0 : t = b / g;
1107 : : // store householder vector
1108 [ # # ][ # # ]: 0 : for (int r = c + 1; r < N; r++) A_(r, c) /= b;
[ # # ]
1109 [ # # ]: 0 : A_(c, c) = -g;
1110 : : }
1111 : 0 : return t;
1112 : : }
1113 : :
1114 : : /*! The function computes a Householder vector to zero-out the matrix
1115 : : entries in the given column, stores it in the annihilated vector
1116 : : space (in a packed form) and applies the transformation to the
1117 : : remaining right-hand columns. */
1118 : : template <class nr_type_t>
1119 : 0 : nr_type_t eqnsys<nr_type_t>::householder_left (int c) {
1120 : : // compute householder vector
1121 [ # # ]: 0 : nr_type_t t = householder_create_left (c);
1122 : : // apply householder transformation to remaining columns if necessary
1123 [ # # ][ # # ]: 0 : if (t != 0) {
[ # # ]
1124 [ # # ]: 0 : householder_apply_left (c, t);
1125 : : }
1126 : 0 : return t;
1127 : : }
1128 : :
1129 : : /*! The function computes a Householder vector to zero-out the matrix
1130 : : entries in the given row, stores it in the annihilated vector space
1131 : : (in a packed form) and applies the transformation to the remaining
1132 : : downward rows. */
1133 : : template <class nr_type_t>
1134 : 0 : nr_type_t eqnsys<nr_type_t>::householder_right (int r) {
1135 : : // compute householder vector
1136 [ # # ]: 0 : nr_type_t t = householder_create_right (r);
1137 : : // apply householder transformation to remaining rows if necessary
1138 [ # # ][ # # ]: 0 : if (t != 0) {
[ # # ]
1139 [ # # ]: 0 : householder_apply_right (r, t);
1140 : : }
1141 : 0 : return t;
1142 : : }
1143 : :
1144 : : /*! The function creates the right-hand householder vector for a given
1145 : : row which eliminates the row except the first element. The
1146 : : householder vector is normalized to have one in the first position.
1147 : : The super-diagonal element is replaced by the applied householder
1148 : : vector and the vector itself is located in the free matrix
1149 : : positions. The function returns the normalization factor. */
1150 : : template <class nr_type_t>
1151 : 0 : nr_type_t eqnsys<nr_type_t>::householder_create_right (int r) {
1152 : 0 : nr_type_t a, b, t;
1153 : : nr_double_t s, g;
1154 [ # # ]: 0 : s = euclidian_r (r, r + 2);
1155 [ # # ][ # # ]: 0 : if (s == 0 && imag (A_(r, r + 1)) == 0) {
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1156 : : // no reflection necessary
1157 : 0 : t = 0;
1158 : : }
1159 : : else {
1160 : : // calculate householder reflection
1161 [ # # ]: 0 : a = A_(r, r + 1);
1162 [ # # ][ # # ]: 0 : g = sign_(a) * xhypot (a, s);
[ # # ]
1163 : 0 : b = a + g;
1164 : 0 : t = b / g;
1165 : : // store householder vector
1166 [ # # ][ # # ]: 0 : for (int c = r + 2; c < N; c++) A_(r, c) /= b;
[ # # ]
1167 [ # # ]: 0 : A_(r, r + 1) = -g;
1168 : : }
1169 : 0 : return t;
1170 : : }
1171 : :
1172 : : /*! Applies the householder vector stored in the given column to the
1173 : : right-hand columns using the given normalization factor. */
1174 : : template <class nr_type_t>
1175 : 0 : void eqnsys<nr_type_t>::householder_apply_left (int c, nr_type_t t) {
1176 : 0 : nr_type_t f;
1177 : : int k, r;
1178 : : // apply the householder vector to each right-hand column
1179 [ # # ]: 0 : for (r = c + 1; r < N; r++) {
1180 : : // calculate f = u' * A (a scalar product)
1181 [ # # ]: 0 : f = A_(c, r);
1182 [ # # ][ # # ]: 0 : for (k = c + 1; k < N; k++) f += cond_conj (A_(k, c)) * A_(k, r);
[ # # ][ # # ]
[ # # ]
1183 : : // calculate A -= T * f * u
1184 [ # # ]: 0 : f *= cond_conj (t); A_(c, r) -= f;
1185 [ # # ][ # # ]: 0 : for (k = c + 1; k < N; k++) A_(k, r) -= f * A_(k, c);
[ # # ][ # # ]
[ # ]
1186 : : }
1187 : 0 : }
1188 : :
1189 : : /*! Applies the householder vector stored in the given row to the
1190 : : downward rows using the given normalization factor. */
1191 : : template <class nr_type_t>
1192 : 0 : void eqnsys<nr_type_t>::householder_apply_right (int r, nr_type_t t) {
1193 : 0 : nr_type_t f;
1194 : : int k, c;
1195 : : // apply the householder vector to each downward row
1196 [ # # ]: 0 : for (c = r + 1; c < N; c++) {
1197 : : // calculate f = u' * A (a scalar product)
1198 [ # # ]: 0 : f = A_(c, r + 1);
1199 [ # # ][ # # ]: 0 : for (k = r + 2; k < N; k++) f += cond_conj (A_(r, k)) * A_(c, k);
[ # # ][ # # ]
[ # # ]
1200 : : // calculate A -= T * f * u
1201 [ # # ]: 0 : f *= cond_conj (t); A_(c, r + 1) -= f;
1202 [ # # ][ # # ]: 0 : for (k = r + 2; k < N; k++) A_(c, k) -= f * A_(r, k);
[ # # ][ # # ]
[ # ]
1203 : : }
1204 : 0 : }
1205 : :
1206 : : // Some helper defines for SVD.
1207 : : #define V_ (*V)
1208 : : #define S_ (*S)
1209 : : #define E_ (*E)
1210 : : #define U_ (*A)
1211 : :
1212 : : /*! The function does exactly the same as householder_apply_right()
1213 : : except that it applies the householder transformations to another
1214 : : matrix. */
1215 : : template <class nr_type_t>
1216 : 0 : void eqnsys<nr_type_t>::householder_apply_right_extern (int r, nr_type_t t) {
1217 : 0 : nr_type_t f;
1218 : : int k, c;
1219 : : // apply the householder vector to each downward row
1220 [ # # ]: 0 : for (c = r + 1; c < N; c++) {
1221 : : // calculate f = u' * A (a scalar product)
1222 [ # # ]: 0 : f = V_(c, r + 1);
1223 [ # # ][ # # ]: 0 : for (k = r + 2; k < N; k++) f += cond_conj (A_(r, k)) * V_(c, k);
[ # # ][ # # ]
[ # # ]
1224 : : // calculate A -= T * f * u
1225 [ # # ]: 0 : f *= cond_conj (t); V_(c, r + 1) -= f;
1226 [ # # ][ # # ]: 0 : for (k = r + 2; k < N; k++) V_(c, k) -= f * A_(r, k);
[ # # ][ # # ]
[ # ]
1227 : : }
1228 : 0 : }
1229 : :
1230 : : /*! This function solves the equation system AX = B using the singular
1231 : : value decomposition (Golub-Reinsch-SVD). */
1232 : : template <class nr_type_t>
1233 : 0 : void eqnsys<nr_type_t>::solve_svd (void) {
1234 : 0 : factorize_svd ();
1235 : 0 : chop_svd ();
1236 : 0 : substitute_svd ();
1237 : 0 : }
1238 : :
1239 : : //! Annihilates near-zero singular values.
1240 : : template <class nr_type_t>
1241 : 0 : void eqnsys<nr_type_t>::chop_svd (void) {
1242 : : int c;
1243 : : nr_double_t Max, Min;
1244 : 0 : Max = 0.0;
1245 [ # # ][ # # ]: 0 : for (c = 0; c < N; c++) if (fabs (S_(c)) > Max) Max = fabs (S_(c));
1246 : 0 : Min = Max * std::numeric_limits<nr_double_t>::max();
1247 [ # # ][ # # ]: 0 : for (c = 0; c < N; c++) if (fabs (S_(c)) < Min) S_(c) = 0.0;
1248 : 0 : }
1249 : :
1250 : : /*! The function uses the singular value decomposition A = USV' to
1251 : : solve the equation system AX = B by simple matrix multiplications.
1252 : : Remember that the factorization actually computed U, S and V'. */
1253 : : template <class nr_type_t>
1254 : 0 : void eqnsys<nr_type_t>::substitute_svd (void) {
1255 : : int c, r;
1256 : 0 : nr_type_t f;
1257 : : // calculate U'B
1258 [ # # ][ # # ]: 0 : for (c = 0; c < N; c++) {
1259 : 0 : f = 0.0;
1260 : : // non-zero result only if S is non-zero
1261 [ # # ]: 0 : if (S_(c) != 0.0) {
[ # # # # ]
1262 [ # # ][ # # ]: 0 : for (r = 0; r < N; r++) f += cond_conj (U_(r, c)) * B_(r);
[ # # ][ # # ]
1263 : : // this is the divide by S
1264 [ # # ]: 0 : f /= S_(c);
1265 : : }
1266 [ # # ]: 0 : R_(c) = f;
1267 : : }
1268 : : // matrix multiply by V to get the final solution
1269 [ # # ][ # # ]: 0 : for (r = 0; r < N; r++) {
1270 [ # # ][ # # ]: 0 : for (f = 0.0, c = 0; c < N; c++) f += cond_conj (V_(c, r)) * R_(c);
[ # # ][ # # ]
[ # ]
1271 [ # # ]: 0 : X_(r) = f;
1272 : : }
1273 : 0 : }
1274 : :
1275 : : /*! The function decomposes the matrix A into three other matrices U, S
1276 : : and V'. The matrix A is overwritten by the U matrix, S is stored
1277 : : in a separate vector and V in a separate matrix. */
1278 : :
1279 : : template <class nr_type_t>
1280 : 0 : void eqnsys<nr_type_t>::factorize_svd (void) {
1281 : : int i, j, l;
1282 : 0 : nr_type_t t;
1283 : :
1284 : : // allocate space for vectors and matrices
1285 [ # # ][ # # ]: 0 : if (R) delete R; R = new tvector<nr_type_t> (N);
[ # # ][ # # ]
[ # ]
1286 [ # # ][ # # ]: 0 : if (T) delete T; T = new tvector<nr_type_t> (N);
[ # # ][ # # ]
[ # ]
1287 [ # # ][ # # ]: 0 : if (V) delete V; V = new tmatrix<nr_type_t> (N);
[ # # ][ # # ]
[ # ]
1288 [ # # ][ # # ]: 0 : if (S) delete S; S = new tvector<nr_double_t> (N);
[ # # ][ # # ]
[ # ]
1289 [ # # ][ # # ]: 0 : if (E) delete E; E = new tvector<nr_double_t> (N);
[ # # ][ # # ]
[ # ]
1290 : :
1291 : : // bidiagonalization through householder transformations
1292 [ # # ]: 0 : for (i = 0; i < N; i++) {
1293 [ # # ][ # # ]: 0 : T_(i) = householder_left (i);
1294 [ # # ][ # # ]: 0 : if (i < N - 1) R_(i) = householder_right (i);
[ # # ][ # # ]
1295 : : }
1296 : :
1297 : : // copy over the real valued bidiagonal values
1298 [ # # ][ # # ]: 0 : for (i = 0; i < N; i++) S_(i) = real (A_(i, i));
[ # # ]
1299 [ # # ][ # # ]: 0 : for (E_(0) = 0, i = 1; i < N; i++) E_(i) = real (A_(i - 1, i));
[ # # ][ # # ]
[ # ]
1300 : :
1301 : : // backward accumulation of right-hand householder transformations
1302 : : // yields the V' matrix
1303 [ # # ]: 0 : for (l = N, i = N - 1; i >= 0; l = i--) {
1304 [ # # ]: 0 : if (i < N - 1) {
1305 [ # # ][ # # ]: 0 : if ((t = R_(i)) != 0.0) {
[ # ]
1306 [ # # ]: 0 : householder_apply_right_extern (i, cond_conj (t));
1307 : : }
1308 [ # # ]: 0 : else for (j = l; j < N; j++) // cleanup this row
1309 [ # # ][ # # ]: 0 : V_(i, j) = V_(j, i) = 0.0;
1310 : : }
1311 [ # # ]: 0 : V_(i, i) = 1.0;
1312 : : }
1313 : :
1314 : : // backward accumulation of left-hand householder transformations
1315 : : // yields the U matrix in place of the A matrix
1316 [ # # ]: 0 : for (l = N, i = N - 1; i >= 0; l = i--) {
1317 [ # # ]: 0 : for (j = l; j < N; j++) // cleanup upper row
1318 [ # # ]: 0 : A_(i, j) = 0.0;
1319 [ # # ][ # # ]: 0 : if ((t = T_(i)) != 0.0) {
[ # ]
1320 [ # # ]: 0 : householder_apply_left (i, cond_conj (t));
1321 [ # # ][ # # ]: 0 : for (j = l; j < N; j++) A_(j, i) *= -t;
1322 : : }
1323 [ # # ]: 0 : else for (j = l; j < N; j++) // cleanup this column
1324 [ # # ]: 0 : A_(j, i) = 0.0;
1325 [ # # ]: 0 : A_(i, i) = 1.0 - t;
1326 : : }
1327 : :
1328 : : // S and E contain diagonal and super-diagonal, A contains U, V'
1329 : : // calculated; now diagonalization can begin
1330 [ # # ]: 0 : diagonalize_svd ();
1331 : 0 : }
1332 : :
1333 : : #ifndef MAX
1334 : : # define MAX(x,y) (((x) > (y)) ? (x) : (y))
1335 : : #endif
1336 : :
1337 : : //! Helper function computes Givens rotation.
1338 : : static nr_double_t
1339 : 0 : givens (nr_double_t a, nr_double_t b, nr_double_t& c, nr_double_t& s) {
1340 : 0 : nr_double_t z = xhypot (a, b);
1341 : 0 : c = a / z;
1342 : 0 : s = b / z;
1343 : 0 : return z;
1344 : : }
1345 : :
1346 : : template <class nr_type_t>
1347 : 0 : void eqnsys<nr_type_t>::givens_apply_u (int c1, int c2,
1348 : : nr_double_t c, nr_double_t s) {
1349 [ # # ]: 0 : for (int i = 0; i < N; i++) {
1350 [ # # ]: 0 : nr_type_t y = U_(i, c1);
1351 [ # # ]: 0 : nr_type_t z = U_(i, c2);
1352 [ # # ]: 0 : U_(i, c1) = y * c + z * s;
1353 [ # # ]: 0 : U_(i, c2) = z * c - y * s;
1354 : : }
1355 : 0 : }
1356 : :
1357 : : template <class nr_type_t>
1358 : 0 : void eqnsys<nr_type_t>::givens_apply_v (int r1, int r2,
1359 : : nr_double_t c, nr_double_t s) {
1360 [ # # ]: 0 : for (int i = 0; i < N; i++) {
1361 [ # # ]: 0 : nr_type_t y = V_(r1, i);
1362 [ # # ]: 0 : nr_type_t z = V_(r2, i);
1363 [ # # ]: 0 : V_(r1, i) = y * c + z * s;
1364 [ # # ]: 0 : V_(r2, i) = z * c - y * s;
1365 : : }
1366 : 0 : }
1367 : :
1368 : : /*! This function diagonalizes the upper bidiagonal matrix fromed by
1369 : : the diagonal S and the super-diagonal vector E. Both vectors are
1370 : : real valued. Thus real valued calculations even when solving a
1371 : : complex valued equation systems is possible except for the matrix
1372 : : updates of U and V'. */
1373 : : template <class nr_type_t>
1374 : 0 : void eqnsys<nr_type_t>::diagonalize_svd (void) {
1375 : : bool split;
1376 : 0 : int i, l, j, its, k, n, MaxIters = 30;
1377 : : nr_double_t an, f, g, h, d, c, s, b, a;
1378 : :
1379 : : // find largest bidiagonal value
1380 [ # # ]: 0 : for (an = 0, i = 0; i < N; i++)
1381 [ # # ][ # # ]: 0 : an = MAX (an, fabs (S_(i)) + fabs (E_(i)));
[ # # ][ # # ]
[ # # ]
1382 : :
1383 : : // diagonalize the bidiagonal matrix (stored as super-diagonal
1384 : : // vector E and diagonal vector S)
1385 [ # # ]: 0 : for (k = N - 1; k >= 0; k--) {
1386 : : // loop over singular values
1387 [ # # ]: 0 : for (its = 0; its <= MaxIters; its++) {
1388 : 0 : split = true;
1389 : : // check for a zero entry along the super-diagonal E, if there
1390 : : // is one, it is possible to QR iterate on two separate matrices
1391 : : // above and below it
1392 [ # # ]: 0 : for (n = 0, l = k; l >= 1; l--) {
1393 : : // note that E_(0) is always zero
1394 : 0 : n = l - 1;
1395 [ # # ][ # # ]: 0 : if (fabs (E_(l)) + an == an) { split = false; break; }
1396 [ # # ][ # # ]: 0 : if (fabs (S_(n)) + an == an) break;
1397 : : }
1398 : : // if there is a zero on the diagonal S, it is possible to zero
1399 : : // out the corresponding super-diagonal E entry to its right
1400 [ # # ]: 0 : if (split) {
1401 : : // cancellation of E_(l), if l > 0
1402 : 0 : c = 0.0;
1403 : 0 : s = 1.0;
1404 [ # # ]: 0 : for (i = l; i <= k; i++) {
1405 [ # # ]: 0 : f = -s * E_(i);
1406 [ # # ]: 0 : E_(i) *= c;
1407 [ # # ]: 0 : if (fabs (f) + an == an) break;
1408 [ # # ]: 0 : g = S_(i);
1409 [ # # ][ # # ]: 0 : S_(i) = givens (f, g, c, s);
1410 : : // apply inverse rotation to U
1411 [ # # ]: 0 : givens_apply_u (n, i, c, s);
1412 : : }
1413 : : }
1414 : :
1415 [ # # ]: 0 : d = S_(k);
1416 : : // convergence
1417 [ # # ]: 0 : if (l == k) {
1418 : : // singular value is made non-negative
1419 [ # # ]: 0 : if (d < 0.0) {
1420 [ # # ]: 0 : S_(k) = -d;
1421 [ # # ][ # # ]: 0 : for (j = 0; j < N; j++) V_(k, j) = -V_(k, j);
[ # # # ]
1422 : : }
1423 : 0 : break;
1424 : : }
1425 [ # # ]: 0 : if (its == MaxIters) {
1426 : : logprint (LOG_ERROR, "WARNING: no convergence in %d SVD iterations\n",
1427 [ # # ]: 0 : MaxIters);
1428 : : }
1429 : :
1430 : : // shift from bottom 2-by-2 minor
1431 [ # # ]: 0 : a = S_(l);
1432 : 0 : n = k - 1;
1433 [ # # ]: 0 : b = S_(n);
1434 [ # # ]: 0 : g = E_(n);
1435 [ # # ]: 0 : h = E_(k);
1436 : :
1437 : : // compute QR shift value (as close as possible to the largest
1438 : : // eigenvalue of the 2-by-2 minor matrix)
1439 : 0 : f = (b - d) * (b + d) + (g - h) * (g + h);
1440 : 0 : f /= 2.0 * h * b;
1441 [ # # ][ # # ]: 0 : f += sign_(f) * xhypot (f, 1.0);
[ # # ]
1442 : 0 : f = ((a - d) * (a + d) + h * (b / f - h)) / a;
1443 : : // f => (B_{ll}^2 - u) / B_{ll}
1444 : : // u => eigenvalue of T = B' * B nearer T_{22} (Wilkinson shift)
1445 : :
1446 : : // next QR transformation
1447 : 0 : c = s = 1.0;
1448 [ # # ]: 0 : for (j = l; j <= n; j++) {
1449 : 0 : i = j + 1;
1450 [ # # ]: 0 : g = E_(i);
1451 [ # # ]: 0 : b = S_(i);
1452 : 0 : h = s * g; // h => right-hand non-zero to annihilate
1453 : 0 : g *= c;
1454 [ # # ][ # # ]: 0 : E_(j) = givens (f, h, c, s);
1455 : : // perform the rotation
1456 : 0 : f = a * c + g * s;
1457 : 0 : g = g * c - a * s;
1458 : 0 : h = b * s;
1459 : 0 : b *= c;
1460 : : // here: +- -+
1461 : : // | f g | = B * V'_j (also first V'_1)
1462 : : // | h b |
1463 : : // +- -+
1464 : :
1465 : : // accumulate the rotation in V'
1466 [ # # ]: 0 : givens_apply_v (j, i, c, s);
1467 [ # # ][ # # ]: 0 : d = S_(j) = xhypot (f, h);
1468 : : // rotation can be arbitrary if d = 0
1469 [ # # ]: 0 : if (d != 0.0) {
1470 : : // d => non-zero result on diagonal
1471 : 0 : d = 1.0 / d;
1472 : : // rotation coefficients to annihilate the lower non-zero
1473 : 0 : c = f * d;
1474 : 0 : s = h * d;
1475 : : }
1476 : 0 : f = c * g + s * b;
1477 : 0 : a = c * b - s * g;
1478 : : // here: +- -+
1479 : : // | d f | => U_j * B
1480 : : // | 0 a |
1481 : : // +- -+
1482 : :
1483 : : // accumulate rotation into U
1484 [ # # ]: 0 : givens_apply_u (j, i, c, s);
1485 : : }
1486 [ # # ]: 0 : E_(l) = 0;
1487 [ # # ]: 0 : E_(k) = f;
1488 [ # # ]: 0 : S_(k) = a;
1489 : : }
1490 : : }
1491 : 0 : }
1492 : :
1493 : : } // namespace qucs
1494 : :
1495 : : #undef V_
|