-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalgorithm.cpp
125 lines (112 loc) · 3.97 KB
/
algorithm.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#include "dragoncello.h"
void DRAGONCELLO::solveTridiagonalSystem(vector<double>& a, vector<double>& b, vector<double>& c, vector<double>& r, vector<double>& u, int n) {
int j = 0;
double bet = 0.0;
vector<double> gam(n,0.); //double gam[n];
// One vector of workspace, gam, is needed.
if (b[0] == 0.0) cerr << "Error 1 in tridag: the first diagonal term is 0!! " << endl;
//If this happens, then you should rewrite your equations as a set of order N-1, with u1 trivially eliminated.
bet = b[0];
u[0] = r[0] / bet;
for (j = 1; j < n; j++) { //Decomposition and forward substitution.
//double* gm = gam+j;
//(*gm) = c[j-1]/bet;
gam[j] = c[j-1]/bet;
//bet = b[j] - a[j]*(*gm);
bet = b[j] - a[j]*gam[j];
if (bet == 0.0){
cout << "j = 0 " << " --> diagonal term b[0] = " << b[0] << " off diagonal term a[0] = " << a[0] << " c[0] = " << c[0] << " u[0] = " << u[0] << " bet = b[0] " << endl;
cout << "j = " << j << " --> diagonal term b[j] = " << b[j] << " off diagonal term a[j] = " << a[j] << " gam[j] = " << gam[j] << " bet = b[j] - a[j]*c[j-1]/bet " << bet << endl;
cerr << "Error 2 in tridag: bet = 0!" << endl;
}
u[j] = (r[j] - a[j]*u[j-1])/bet;
}
for (j = (n-2); j >= 0; j--)
u[j] -= gam[j+1]*u[j+1]; //Backsubstitution.
return ;
}
int DRAGONCELLO::gsl_linalg_solve_tridiag(const vector<double> & diag,
const vector<double> & abovediag,
const vector<double> & belowdiag,
const vector<double> & rhs,
vector<double> & solution)
{
if(diag.size() != rhs.size())
{
cout << "size of diag must match rhs" << endl;
exit(GSL_EBADLEN);
}
else if (abovediag.size() != rhs.size()-1)
{
cout << "size of abovediag must match rhs-1" << endl;
exit(GSL_EBADLEN);
}
else if (belowdiag.size() != rhs.size()-1)
{
cout << "size of belowdiag must match rhs-1" << endl;
exit(GSL_EBADLEN);
}
else if (solution.size() != rhs.size())
{
cout << "size of solution must match rhs" << endl;
exit(GSL_EBADLEN);
}
else
{
return solve_tridiag_nonsym(diag, abovediag, belowdiag, rhs, solution, diag.size());
}
return 0;
}
/* plain gauss elimination, only not bothering with the zeroes
*
* diag[0] abovediag[0] 0 .....
* belowdiag[0] diag[1] abovediag[1] .....
* 0 belowdiag[1] diag[2]
* 0 0 belowdiag[2] .....
*/
int DRAGONCELLO::solve_tridiag_nonsym(const vector<double> & diag,
const vector<double> & abovediag,
const vector<double> & belowdiag,
const vector<double> & rhs,
vector<double> & x,
size_t N)
{
int status = GSL_SUCCESS;
vector<double> alpha(N);
vector<double> z(N);
size_t i, j;
/* Bidiagonalization (eliminating belowdiag)
& rhs update
diag' = alpha
rhs' = z
*/
alpha[0] = diag.at(0);
z[0] = rhs.at(0);
if (alpha[0] == 0) {
status = GSL_EZERODIV;
}
for (i = 1; i < N; i++)
{
const double t = belowdiag.at(i - 1) / alpha[i-1];
alpha[i] = diag.at(i) - t * abovediag.at(i - 1);
z[i] = rhs.at(i) - t * z[i-1];
if (alpha[i] == 0) {
status = GSL_EZERODIV;
}
}
/* backsubstitution */
x.at(N - 1) = z[N - 1] / alpha[N - 1];
if (N >= 2)
{
for (i = N - 2, j = 0; j <= N - 2; j++, i--)
{
x.at(i) = (z[i] - abovediag.at(i) * x.at(i + 1)) / alpha[i];
}
}
if (status == GSL_EZERODIV) {
cout << "Error : matrix must be positive definite!" << "\n";
}
//delete alpha;
//delete z;
return status;
}