My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
tridiag.cpp
Go to the documentation of this file.
1 /*
2  * tridiag.cpp - tridiagonal matrix template class implementation
3  *
4  * Copyright (C) 2005, 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: tridiag.cpp 1825 2011-03-11 20:42:14Z ela $
22  *
23  */
24 
25 #if HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 #include <assert.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <math.h>
34 
35 #include "compat.h"
36 #include "complex.h"
37 #include "tvector.h"
38 
39 // Constructor creates an instance of the tridiag class.
40 template <class nr_type_t>
42  abov = belo = diag = offdiag = rhs = NULL;
43  type = TRIDIAG_UNKNOWN;
44 }
45 
46 /* The copy constructor creates a new instance based on the given
47  tridiag object. */
48 template <class nr_type_t>
50  abov = t.abov;
51  belo = t.belo;
52  diag = t.diag;
53  offdiag = t.offdiag;
54  rhs = t.rhs;
55  type = t.type;
56 }
57 
58 /* The assignment copy constructor creates a new instance based on the
59  given tridiag object. */
60 template <class nr_type_t>
61 const tridiag<nr_type_t>&
63  if (&t != this) {
64  abov = t.abov;
65  belo = t.belo;
66  diag = t.diag;
67  offdiag = t.offdiag;
68  rhs = t.rhs;
69  type = t.type;
70  }
71  return *this;
72 }
73 
74 // Destructor deletes a tridiag object.
75 template <class nr_type_t>
77 }
78 
79 // Set the diagonal vector of the tridiagonal matrix.
80 template <class nr_type_t>
82  diag = v;
83 }
84 
85 // Set the off-diagonal vector of the tridiagonal matrix.
86 template <class nr_type_t>
88  abov = belo = offdiag = v;
89 }
90 
91 // Set the above off-diagonal vector of the tridiagonal matrix.
92 template <class nr_type_t>
94  abov = v;
95 }
96 
97 // Set the below off-diagonal vector of the tridiagonal matrix.
98 template <class nr_type_t>
100  belo = v;
101 }
102 
103 // Set the right hand side vector of the equation system.
104 template <class nr_type_t>
106  rhs = v;
107 }
108 
109 /* Depending on the type of tridiagonal matrix the function runs one
110  of the solvers specialized on this type. The solvers are in-place
111  algorithms meaning the right hand side is replaced by the solution
112  and the original matrix entries are destroyed during solving the
113  system. */
114 template <class nr_type_t>
116  switch (type) {
117  case TRIDIAG_NONSYM:
118  solve_ns (); break;
119  case TRIDIAG_SYM:
120  solve_s (); break;
122  solve_ns_cyc (); break;
123  case TRIDIAG_SYM_CYCLIC:
124  solve_s_cyc (); break;
125  }
126 }
127 
128 /* This function solves a tridiagonal equation system given
129  by
130  diag[0] abov[0] 0 ..... 0
131  belo[1] diag[1] abov[1] ..... 0
132  0 belo[2] diag[2]
133  0 0 belo[3] ..... abov[n-2]
134  ... ...
135  0 ... belo[n-1] diag[n-1]
136 */
137 template <class nr_type_t>
139  d = al = diag->getData ();
140  f = ga = abov->getData ();
141  e = belo->getData ();
142  b = c = x = rhs->getData ();
143  int i, n = diag->getSize ();
144 
145  // factorize A = LU
146  al[0] = d[0];
147  ga[0] = f[0] / al[0];
148  for (i = 1; i < n - 1; i++) {
149  al[i] = d[i] - e[i] * ga[i-1];
150  ga[i] = f[i] / al[i];
151  }
152  al[n-1] = d[n-1] - e[n-1] * ga[n-2];
153 
154  // update b = Lc
155  c[0] = b[0] / d[0];
156  for (i = 1; i < n; i++) {
157  c[i] = (b[i] - e[i] * c[i-1]) / al[i];
158  }
159 
160  // back substitution Rx = c
161  x[n-1] = c[n-1];
162  for (i = n - 2; i >= 0; i--) {
163  x[i] = c[i] - ga[i] * x[i+1];
164  }
165 }
166 
167 /* This function solves a cyclically tridiagonal equation system given
168  by
169  diag[0] abov[0] 0 ..... belo[0]
170  belo[1] diag[1] abov[1] ..... 0
171  0 belo[2] diag[2]
172  0 0 belo[3] ..... abov[n-2]
173  ... ...
174  abov[n-1] ... belo[n-1] diag[n-1]
175 */
176 template <class nr_type_t>
178  d = al = diag->getData ();
179  f = ga = abov->getData ();
180  e = be = belo->getData ();
181  b = x = c = rhs->getData ();
182  int i, n = diag->getSize ();
183  de = new nr_type_t[n];
184  ep = new nr_type_t[n];
185 
186  // factorize A = LU
187  al[0] = d[0];
188  ga[0] = f[0] / al[0];
189  de[0] = e[0] / al[0];
190  for (i = 1; i < n - 2; i++) {
191  al[i] = d[i] - e[i] * ga[i-1];
192  ga[i] = f[i] / al[i];
193  be[i] = e[i];
194  de[i] = -be[i] * de[i-1] / al[i];
195  }
196  al[n-2] = d[n-2] - e[n-2] * ga[n-3];
197  be[n-2] = e[n-2];
198  ep[2] = f[n-1];
199  for (i = 3; i < n; i++) {
200  ep[i] = -ep[i-1] * ga[i-3];
201  }
202  ga[n-2] = (f[n-2] - be[n-2] * de[n-3]) / al[n-2];
203  be[n-1] = e[n-1] - ep[n-1] * ga[n-3];
204  al[n-1] = d[n-1] - be[n-1] * ga[n-2];
205  for (i = 2; i < n; i++) {
206  al[n-1] -= ep[i] * de[i-2];
207  }
208 
209  // update Lc = b
210  c[0] = b[0] / al[0];
211  for (i = 1; i < n - 1; i++) {
212  c[i] = (b[i] - c[i-1] * be[i]) / al[i];
213  }
214  c[n-1] = b[n-1] - be[n-1] * c[n-2];
215  for (i = 2; i < n; i++) {
216  c[n-1] -= ep[i] * c[i-2];
217  }
218  c[n-1] /= al[n-1];
219 
220  // back substitution Rx = c
221  x[n-1] = c[n-1];
222  x[n-2] = c[n-2] - ga[n-2] * x[n-1];
223  for (i = n - 3; i >= 0; i--) {
224  x[i] = c[i] - ga[i] * x[i+1] - de[i] * x[n-1];
225  }
226 
227  delete[] de;
228  delete[] ep;
229 }
230 
231 /* This function solves a symmetric tridiagonal strongly nonsingular
232  equation system given by
233  diag[0] offdiag[0] 0 ..... 0
234  offdiag[0] diag[1] offdiag[1] ..... 0
235  0 offdiag[1] diag[2]
236  0 0 offdiag[2] ..... offdiag[n-2]
237  ... ...
238  0 ... offdiag[n-2] diag[n-1]
239 */
240 template <class nr_type_t>
242  d = al = diag->getData ();
243  f = ga = offdiag->getData ();
244  b = z = x = b = rhs->getData ();
245  nr_type_t t;
246  int i, n = diag->getSize ();
247  de = new nr_type_t[n];
248 
249  // factorize A = LDL'
250  al[0] = d[0];
251  t = f[0];
252  ga[0] = t / al[0];
253  for (i = 1; i < n - 1; i++) {
254  al[i] = d[i] - t * ga[i-1];
255  t = f[i];
256  ga[i] = t / al[i];
257  }
258  al[n-1] = d[n-1] - t * ga[n-2];
259 
260  // update L'z = b and Dc = z
261  z[0] = b[0];
262  for (i = 1; i < n; i++) {
263  z[i] = b[i] - ga[i-1] * z[i-1];
264  }
265  for (i = 0; i < n; i++) {
266  c[i] = z[i] / al[i];
267  }
268 
269  // back substitution L'x = c
270  x[n-1] = c[n-1];
271  for (i = n-2; i >= 0; i--) {
272  x[i] = c[i] - ga[i] * x[i+1];
273  }
274 
275  delete[] de;
276 }
277 
278 /* This function solves a symmetric cyclically tridiagonal strongly
279  nonsingular equation system given by
280  diag[0] offdiag[0] 0 ..... offdiag[n-1]
281  offdiag[0] diag[1] offdiag[1] ..... 0
282  0 offdiag[1] diag[2]
283  0 0 offdiag[2] ..... offdiag[n-2]
284  ... ...
285  offdiag[n-1] ... offdiag[n-2] diag[n-1]
286 */
287 template <class nr_type_t>
289  d = al = diag->getData ();
290  f = ga = offdiag->getData ();
291  b = c = z = x = rhs->getData ();
292  nr_type_t t;
293  int i, n = diag->getSize ();
294  de = new nr_type_t[n];
295 
296  // factorize A = LDL'
297  al[0] = d[0];
298  t = f[0];
299  ga[0] = t / al[0];
300  de[0] = f[n-1] / al[0];
301  for (i = 1; i < n - 2; i++) {
302  al[i] = d[i] - t * ga[i-1];
303  de[i] = -de[i-1] * t / al[i];
304  t = f[i];
305  ga[i] = t / al[i];
306  }
307  al[n-2] = d[n-2] - t * ga[n-3];
308  ga[n-2] = (f[n-2] - t * de[n-3]) / al[n-2];
309  al[n-1] = d[n-1] - al[n-2] * ga[n-2] * ga[n-2];
310  for (i = 0; i < n - 2; i++) {
311  al[n-1] -= al[i] * de[i] * de[i];
312  }
313 
314  // update Lz = b and Dc = z
315  z[0] = b[0];
316  for (i = 1; i < n - 1; i++) {
317  z[i] = b[i] - ga[i-1] * z[i-1];
318  }
319  z[n-1] = b[n-1] - ga[n-2] * z[n-2];
320  for (i = 0; i < n - 2; i++) {
321  z[n-1] -= de[i] * z[i];
322  }
323  for (i = 0; i < n; i++) {
324  c[i] = z[i] / al[i];
325  }
326 
327  // back substitution L'x = c
328  x[n-1] = c[n-1];
329  x[n-2] = c[n-2] - ga[n-2] * x[n-1];
330  for (i = n - 3; i >= 0; i--) {
331  x[i] = c[i] - ga[i] * x[i+1] - de[i] * x[n-1];
332  }
333 
334  delete[] de;
335 }