3 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002, 2004, 2007 Gerard Jungman, Brian Gough, David Necas
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 /* Author: G. Jungman */
25 #include <gsl/gsl_errno.h>
27 #include <gsl/gsl_linalg.h>
29 /* for description of method see [Engeln-Mullges + Uhlig, p. 92]
31 * diag[0] offdiag[0] 0 .....
32 * offdiag[0] diag[1] offdiag[1] .....
33 * 0 offdiag[1] diag[2]
34 * 0 0 offdiag[2] .....
39 const double diag[], size_t d_stride,
40 const double offdiag[], size_t o_stride,
41 const double b[], size_t b_stride,
42 double x[], size_t x_stride,
45 int status = GSL_SUCCESS;
46 double *gamma = (double *) malloc (N * sizeof (double));
47 double *alpha = (double *) malloc (N * sizeof (double));
48 double *c = (double *) malloc (N * sizeof (double));
49 double *z = (double *) malloc (N * sizeof (double));
51 if (gamma == 0 || alpha == 0 || c == 0 || z == 0)
53 GSL_ERROR("failed to allocate working space", GSL_ENOMEM);
59 /* Cholesky decomposition
65 gamma[0] = offdiag[0] / alpha[0];
68 status = GSL_EZERODIV;
71 for (i = 1; i < N - 1; i++)
73 alpha[i] = diag[d_stride * i] - offdiag[o_stride*(i - 1)] * gamma[i - 1];
74 gamma[i] = offdiag[o_stride * i] / alpha[i];
76 status = GSL_EZERODIV;
82 alpha[N - 1] = diag[d_stride * (N - 1)] - offdiag[o_stride*(N - 2)] * gamma[N - 2];
87 for (i = 1; i < N; i++)
89 z[i] = b[b_stride * i] - gamma[i - 1] * z[i - 1];
91 for (i = 0; i < N; i++)
93 c[i] = z[i] / alpha[i];
96 /* backsubstitution */
97 x[x_stride * (N - 1)] = c[N - 1];
100 for (i = N - 2, j = 0; j <= N - 2; j++, i--)
102 x[x_stride * i] = c[i] - gamma[i] * x[x_stride * (i + 1)];
116 if (status == GSL_EZERODIV) {
117 GSL_ERROR ("matrix must be positive definite", status);
123 /* plain gauss elimination, only not bothering with the zeroes
125 * diag[0] abovediag[0] 0 .....
126 * belowdiag[0] diag[1] abovediag[1] .....
127 * 0 belowdiag[1] diag[2]
128 * 0 0 belowdiag[2] .....
132 solve_tridiag_nonsym(
133 const double diag[], size_t d_stride,
134 const double abovediag[], size_t a_stride,
135 const double belowdiag[], size_t b_stride,
136 const double rhs[], size_t r_stride,
137 double x[], size_t x_stride,
140 int status = GSL_SUCCESS;
141 double *alpha = (double *) malloc (N * sizeof (double));
142 double *z = (double *) malloc (N * sizeof (double));
144 if (alpha == 0 || z == 0)
146 GSL_ERROR("failed to allocate working space", GSL_ENOMEM);
152 /* Bidiagonalization (eliminating belowdiag)
161 status = GSL_EZERODIV;
164 for (i = 1; i < N; i++)
166 const double t = belowdiag[b_stride*(i - 1)]/alpha[i-1];
167 alpha[i] = diag[d_stride*i] - t*abovediag[a_stride*(i - 1)];
168 z[i] = rhs[r_stride*i] - t*z[i-1];
170 status = GSL_EZERODIV;
174 /* backsubstitution */
175 x[x_stride * (N - 1)] = z[N - 1]/alpha[N - 1];
178 for (i = N - 2, j = 0; j <= N - 2; j++, i--)
180 x[x_stride * i] = (z[i] - abovediag[a_stride*i] * x[x_stride * (i + 1)])/alpha[i];
190 if (status == GSL_EZERODIV) {
191 GSL_ERROR ("matrix must be positive definite", status);
197 /* for description of method see [Engeln-Mullges + Uhlig, p. 96]
199 * diag[0] offdiag[0] 0 ..... offdiag[N-1]
200 * offdiag[0] diag[1] offdiag[1] .....
201 * 0 offdiag[1] diag[2]
202 * 0 0 offdiag[2] .....
210 const double diag[], size_t d_stride,
211 const double offdiag[], size_t o_stride,
212 const double b[], size_t b_stride,
213 double x[], size_t x_stride,
216 int status = GSL_SUCCESS;
217 double * delta = (double *) malloc (N * sizeof (double));
218 double * gamma = (double *) malloc (N * sizeof (double));
219 double * alpha = (double *) malloc (N * sizeof (double));
220 double * c = (double *) malloc (N * sizeof (double));
221 double * z = (double *) malloc (N * sizeof (double));
223 if (delta == 0 || gamma == 0 || alpha == 0 || c == 0 || z == 0)
225 GSL_ERROR("failed to allocate working space", GSL_ENOMEM);
236 x[0] = b[0] / diag[0];
241 gamma[0] = offdiag[0] / alpha[0];
242 delta[0] = offdiag[o_stride * (N-1)] / alpha[0];
245 status = GSL_EZERODIV;
248 for (i = 1; i < N - 2; i++)
250 alpha[i] = diag[d_stride * i] - offdiag[o_stride * (i-1)] * gamma[i - 1];
251 gamma[i] = offdiag[o_stride * i] / alpha[i];
252 delta[i] = -delta[i - 1] * offdiag[o_stride * (i-1)] / alpha[i];
254 status = GSL_EZERODIV;
258 for (i = 0; i < N - 2; i++)
260 sum += alpha[i] * delta[i] * delta[i];
263 alpha[N - 2] = diag[d_stride * (N - 2)] - offdiag[o_stride * (N - 3)] * gamma[N - 3];
265 gamma[N - 2] = (offdiag[o_stride * (N - 2)] - offdiag[o_stride * (N - 3)] * delta[N - 3]) / alpha[N - 2];
267 alpha[N - 1] = diag[d_stride * (N - 1)] - sum - alpha[(N - 2)] * gamma[N - 2] * gamma[N - 2];
271 for (i = 1; i < N - 1; i++)
273 z[i] = b[b_stride * i] - z[i - 1] * gamma[i - 1];
276 for (i = 0; i < N - 2; i++)
278 sum += delta[i] * z[i];
280 z[N - 1] = b[b_stride * (N - 1)] - sum - gamma[N - 2] * z[N - 2];
281 for (i = 0; i < N; i++)
283 c[i] = z[i] / alpha[i];
286 /* backsubstitution */
287 x[x_stride * (N - 1)] = c[N - 1];
288 x[x_stride * (N - 2)] = c[N - 2] - gamma[N - 2] * x[x_stride * (N - 1)];
291 for (i = N - 3, j = 0; j <= N - 3; j++, i--)
293 x[x_stride * i] = c[i] - gamma[i] * x[x_stride * (i + 1)] - delta[i] * x[x_stride * (N - 1)];
309 if (status == GSL_EZERODIV) {
310 GSL_ERROR ("matrix must be positive definite", status);
316 /* solve following system w/o the corner elements and then use
317 * Sherman-Morrison formula to compensate for them
319 * diag[0] abovediag[0] 0 ..... belowdiag[N-1]
320 * belowdiag[0] diag[1] abovediag[1] .....
321 * 0 belowdiag[1] diag[2]
322 * 0 0 belowdiag[2] .....
327 int solve_cyc_tridiag_nonsym(
328 const double diag[], size_t d_stride,
329 const double abovediag[], size_t a_stride,
330 const double belowdiag[], size_t b_stride,
331 const double rhs[], size_t r_stride,
332 double x[], size_t x_stride,
335 int status = GSL_SUCCESS;
336 double *alpha = (double *) malloc (N * sizeof (double));
337 double *zb = (double *) malloc (N * sizeof (double));
338 double *zu = (double *) malloc (N * sizeof (double));
339 double *w = (double *) malloc (N * sizeof (double));
341 if (alpha == 0 || zb == 0 || zu == 0 || w == 0)
343 GSL_ERROR("failed to allocate working space", GSL_ENOMEM);
349 /* Bidiagonalization (eliminating belowdiag)
356 if (diag[0] != 0) beta = -diag[0]; else beta = 1;
358 const double q = 1 - abovediag[0]*belowdiag[0]/(diag[0]*diag[d_stride]);
359 if (fabs(q/beta) > 0.5 && fabs(q/beta) < 2) {
360 beta *= (fabs(q/beta) < 1) ? 0.5 : 2;
364 alpha[0] = diag[0] - beta;
367 status = GSL_EZERODIV;
372 for (i = 1; i+1 < N; i++)
374 const double t = belowdiag[b_stride*(i - 1)]/alpha[i-1];
375 alpha[i] = diag[d_stride*i] - t*abovediag[a_stride*(i - 1)];
376 zb[i] = rhs[r_stride*i] - t*zb[i-1];
380 status = GSL_EZERODIV;
386 const size_t i = N-1;
387 const double t = belowdiag[b_stride*(i - 1)]/alpha[i-1];
388 alpha[i] = diag[d_stride*i]
389 - abovediag[a_stride*i]*belowdiag[b_stride*i]/beta
390 - t*abovediag[a_stride*(i - 1)];
391 zb[i] = rhs[r_stride*i] - t*zb[i-1];
392 zu[i] = abovediag[a_stride*i] - t*zu[i-1];
395 status = GSL_EZERODIV;
399 /* backsubstitution */
402 w[N-1] = zu[N-1]/alpha[N-1];
403 x[N-1] = zb[N-1]/alpha[N-1];
404 for (i = N - 2, j = 0; j <= N - 2; j++, i--)
406 w[i] = (zu[i] - abovediag[a_stride*i] * w[i+1])/alpha[i];
407 x[i*x_stride] = (zb[i] - abovediag[a_stride*i] * x[x_stride*(i + 1)])/alpha[i];
411 /* Sherman-Morrison */
413 const double vw = w[0] + belowdiag[b_stride*(N - 1)]/beta * w[N-1];
414 const double vx = x[0] + belowdiag[b_stride*(N - 1)]/beta * x[x_stride*(N - 1)];
417 status = GSL_EZERODIV;
422 for (i = 0; i < N; i++)
423 x[i] -= vx/(1 + vw)*w[i];
437 if (status == GSL_EZERODIV) {
438 GSL_ERROR ("matrix must be positive definite", status);
445 gsl_linalg_solve_symm_tridiag(
446 const gsl_vector * diag,
447 const gsl_vector * offdiag,
448 const gsl_vector * rhs,
449 gsl_vector * solution)
451 if(diag->size != rhs->size)
453 GSL_ERROR ("size of diag must match rhs", GSL_EBADLEN);
455 else if (offdiag->size != rhs->size-1)
457 GSL_ERROR ("size of offdiag must match rhs-1", GSL_EBADLEN);
459 else if (solution->size != rhs->size)
461 GSL_ERROR ("size of solution must match rhs", GSL_EBADLEN);
465 return solve_tridiag(diag->data, diag->stride,
466 offdiag->data, offdiag->stride,
467 rhs->data, rhs->stride,
468 solution->data, solution->stride,
475 gsl_linalg_solve_tridiag(
476 const gsl_vector * diag,
477 const gsl_vector * abovediag,
478 const gsl_vector * belowdiag,
479 const gsl_vector * rhs,
480 gsl_vector * solution)
482 if(diag->size != rhs->size)
484 GSL_ERROR ("size of diag must match rhs", GSL_EBADLEN);
486 else if (abovediag->size != rhs->size-1)
488 GSL_ERROR ("size of abovediag must match rhs-1", GSL_EBADLEN);
490 else if (belowdiag->size != rhs->size-1)
492 GSL_ERROR ("size of belowdiag must match rhs-1", GSL_EBADLEN);
494 else if (solution->size != rhs->size)
496 GSL_ERROR ("size of solution must match rhs", GSL_EBADLEN);
500 return solve_tridiag_nonsym(diag->data, diag->stride,
501 abovediag->data, abovediag->stride,
502 belowdiag->data, belowdiag->stride,
503 rhs->data, rhs->stride,
504 solution->data, solution->stride,
511 gsl_linalg_solve_symm_cyc_tridiag(
512 const gsl_vector * diag,
513 const gsl_vector * offdiag,
514 const gsl_vector * rhs,
515 gsl_vector * solution)
517 if(diag->size != rhs->size)
519 GSL_ERROR ("size of diag must match rhs", GSL_EBADLEN);
521 else if (offdiag->size != rhs->size)
523 GSL_ERROR ("size of offdiag must match rhs", GSL_EBADLEN);
525 else if (solution->size != rhs->size)
527 GSL_ERROR ("size of solution must match rhs", GSL_EBADLEN);
529 else if (diag->size < 3)
531 GSL_ERROR ("size of cyclic system must be 3 or more", GSL_EBADLEN);
535 return solve_cyc_tridiag(diag->data, diag->stride,
536 offdiag->data, offdiag->stride,
537 rhs->data, rhs->stride,
538 solution->data, solution->stride,
544 gsl_linalg_solve_cyc_tridiag(
545 const gsl_vector * diag,
546 const gsl_vector * abovediag,
547 const gsl_vector * belowdiag,
548 const gsl_vector * rhs,
549 gsl_vector * solution)
551 if(diag->size != rhs->size)
553 GSL_ERROR ("size of diag must match rhs", GSL_EBADLEN);
555 else if (abovediag->size != rhs->size)
557 GSL_ERROR ("size of abovediag must match rhs", GSL_EBADLEN);
559 else if (belowdiag->size != rhs->size)
561 GSL_ERROR ("size of belowdiag must match rhs", GSL_EBADLEN);
563 else if (solution->size != rhs->size)
565 GSL_ERROR ("size of solution must match rhs", GSL_EBADLEN);
567 else if (diag->size < 3)
569 GSL_ERROR ("size of cyclic system must be 3 or more", GSL_EBADLEN);
573 return solve_cyc_tridiag_nonsym(diag->data, diag->stride,
574 abovediag->data, abovediag->stride,
575 belowdiag->data, belowdiag->stride,
576 rhs->data, rhs->stride,
577 solution->data, solution->stride,