I.e.: the algorithm depends on the data structure
A x = b | write: A = M - N => (M - N) x = b <=> Mx - Nx = b <=> Mx = Nx + b <=> x = M-1Nx + M-1b <=> x = Px + Qb |
Jacobi Iteration: xn+1 = Pxn + Qb |
There are two operations in the Jacobi iteration:
|
The algorithm will be different when the matrix and the vector are stored differently
class Vector { public: double x[3]; Vector operator+(Vector &v) { Vector z; int i; for (i = 0; i < 3; i = i + 1) z.x[i] = x[i] + v.x[i]; return(z); } } |
class DenseMatrix { public: double A[3][3]; Vector operator*(Vector &v) { Vector z; int i, j; for (i = 0; i < 3; i=i+1) z.x[i] = 0; for (i = 0; i < 3; i=i+1) for (j = 0; j < 3; j=j+1) z.x[i] = z.x[i] + A[i][j]*v.x[j]; return z; } }; |
double distance(Vector a, Vector b) { double sum = 0; int i; for (i = 0; i < 3; i = i + 1) sum = sum + fabs(a.x[i] - b.x[i]); return(sum); } Vector Jacobi(DenseMatrix & P, DenseMatrix & Q, Vector b) { Vector v1, v2; int i; double d; for (i = 0; i < 3; i = i + 1) { v1.x[i] = 0; v2.x[i] = 1; } d = 0.1; while ( d > 0.0001 ) { v2 = P*v1 + Q*b; d = distance(v1, v2); v1 = v2; } return(v2); } |
Notice that
v2 = P*v1 + Q*b; |
will invoke the Matrix-vector multiply function defined in the class DenseMatrix
[ 11 12 14 ] [ 22 23 25 ] [ 31 33 34 ] [ 42 45 46 ] [ 55 ] [ 65 66 67 ] [ 75 77 78 ] [ 87 88 ] |
Representation using Coordinate-wise method:
Index 0 1 2 3 4 5 6 7 8 9 10 ----------------------------------------------------------- Val 11 12 14 22 23 25 31 33 34 42 45 Row 0 0 0 1 1 1 2 2 2 3 3 Col 0 1 3 1 2 4 0 2 3 1 4 Index 11 12 13 14 15 16 17 18 19 20 21 ------------------------------------------------------------ Val 46 55 65 66 67 75 77 78 87 88 - Row 3 4 5 5 5 6 6 6 7 7 - Col 5 4 4 5 6 4 6 7 6 7 - |
for (k = 0; k < N; k = k + 1) result[i] = 0; for (k = 0; k < nnz; k = k + 1) result[Row[k]] = result[Row[k]] + Val[k]*d[Col[k]]; |
class Vector { public: double x[3]; Vector operator+(Vector &v) { Vector z; int i; for (i = 0; i < 3; i = i + 1) z.x[i] = x[i] + v.x[i]; return(z); } } |
class SparseMatrix { public: int nnz; double val[6]; int row[6]; int col[6]; Vector operator*(Vector &v) { Vector z; int k; for (k = 0; k < 3; k = k + 1) z.x[k] = 0; for (k = 0; k < nnz; k = k + 1) z.x[row[k]] = z.x[row[k]] + val[k]*v.x[col[k]]; return z; } }; |
Vector Jacobi(SparseMatrix & P, SparseMatrix & Q, Vector b) { Vector v1, v2; int i; double d; for (i = 0; i < 3; i = i + 1) { v1.x[i] = 0; v2.x[i] = 1; } d = 0.1; while ( d > 0.0001 ) { v2 = P*v1 + Q*b; d = distance(v1, v2); v1 = v2; } return(v2); } |
Notice that
v2 = P*v1 + Q*b; |
will invoke the Matrix-vector multiply function defined in the class SparseMatrix
We CANNOT the first Jacobi function:
Vector Jacobi(DenseMatrix & P, DenseMatrix & Q, Vector b) { ... } |
because the input parameters are of different type and therefore, different functions are invoked.
Vector Jacobi(Matrix P, Matrix Q, Vector b) { Vector v1, v2; int i; double d; for (i = 0; i < 3; i = i + 1) { v1.x[i] = 0; v2.x[i] = 1; } d = 0.1; while ( d > 0.0001 ) { v2 = P*v1 + Q*b; d = distance(v1, v2); v1 = v2; } return(v2); } |
This function that implements the Jacobi algorithm using a generic matrix-vector multiplication (and vector-vector addition) operations.
DenseMatrix P1, Q1; Vector sol, b; sol = Jacobi( P1, Q1, b); |
SparseMatrix P1, Q1; Vector sol, b; sol = Jacobi( P1, Q1, b); |
Nothing else need to be changed !!!
But before we can explain the technique, we need some background knowledge on derived classes and polymorphism.