preconditioned conjugate gradient solver

Hello everyone.
I wrote a simple diagonal preconditioned conjugate gradient solver and I followed the steps provided below.

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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <algorithm>
#include <numeric>
#include <cmath>
#include <cassert>
using namespace std;

const double SMALL = 1.0E-30;          // used to stop divide-by-zero
const double NEARZERO = 1.0E-10;       // interpretation of "zero" for printing purposes

using vec    = vector<double>;         // vector
using matrix = vector<vec>;            // matrix (=collection of (row) vectors)

//======================================================================

void print( const string &title, const matrix &A )
{
   if ( title != "" ) cout << title << '\n';

   for ( auto &row : A )
   {
      for ( auto x : row ) cout << setw( 15 ) << ( abs( x ) < NEARZERO ? 0.0 : x );
      cout << '\n';
   }
}

//======================================================================

void print( const string &title, const vec &A )
{
   if ( title != "" ) cout << title << '\n';

   for ( auto x : A ) cout << setw( 15 ) << ( abs( x ) < NEARZERO ? 0.0 : x );
   cout << '\n';
}

//======================================================================

matrix matmul( const matrix &A, const matrix &B )          // Matrix times matrix
{
   int rowsA = A.size(),   colsA = A[0].size();
   int rowsB = B.size(),   colsB = B[0].size();
   assert( colsA == rowsB );

   matrix C( rowsA, vec( colsB, 0.0 ) );
   for ( int i = 0; i < rowsA; i++ )
   {
      for ( int j = 0; j < colsB; j++ )
      {
         // scalar product of ith row of A and jth column of B
         for ( int k = 0; k < colsA; k++ ) C[i][j] += A[i][k] * B[k][j];
      }
   }
   return C;
}

//======================================================================

vec matmul( const matrix &A, const vec &V )                // Matrix times vector
{
   int rowsA = A.size(),   colsA = A[0].size();
   int rowsV = V.size();
   assert( colsA == rowsV );

   vec C( rowsA, 0.0 );
   for ( int i = 0; i < rowsA; i++ )
   {
      for ( int k = 0; k < colsA; k++ ) C[i] += A[i][k] * V[k];
   }
   return C;
}

//======================================================================

double innerProduct( const vec &U, const vec &V )          // Inner product of U and V
{
   return inner_product( U.begin(), U.end(), V.begin(), 0.0 );
}

//======================================================================

double norm( const vec &V )                                // L2 norm of V
{
   return sqrt( innerProduct( V, V ) );
}

//======================================================================

bool conjugateGradient( const matrix &A, const vec &B, vec &X )
{
   double TOLERANCE = 1.0e-10;
   int n = A.size();
   X = vec( n, 0.0 );
   vec R = B, P = B;

   for ( int k = 0; k < n; k++ )
   {
      vec Rold = R;                                         // Store previous residual
      vec AP = matmul( A, P );

      double alpha = innerProduct( R, R ) / max( innerProduct( P, AP ), SMALL );
      for ( int i = 0; i < n; i++ ) 
      {
         X[i] += alpha * P[i];                              // Next estimate of solution
         R[i] -= alpha * AP[i];                             // Residual
      }
      if ( norm( R ) < TOLERANCE ) break;                   // Convergence test

      double beta = innerProduct( R, R ) / max( innerProduct( Rold, Rold ), SMALL );
      for ( int i = 0; i < n; i++ ) P[i] = R[i] + beta * P[i];       // Next gradient     
   }

   return true;
}

//======================================================================

int main()
{
   matrix A = { { 7, 3, 1  },
                { 3, 7, 0  },
                { 1, 0, 10 } };
   vec B = { 1, -5, 2 };

   vec X;
   if ( conjugateGradient( A, B, X ) )
   {
      print( "X:" , X );
      cout << "\n\nCheck:\n";
      print( "B:" , B );
      print( "AX:", matmul( A, X ) );
   }
   else
   {
      cout << "Unable to solve\n";
   }
}
Last edited on
Change line 31
double err=0.0;
to
double err=10.0;

Otherwise, you will never loop, since the test condition isn't met with your initial value of err.
Last edited on
Thanks for your answer
Last edited on
https://cplusplus.com/forum/general/278081/#msg1200345

Get it working without preconditioning first.
Last edited on
@lastchance
I fixed the code. I modified the code in this thread. Thanks
Last edited on
Topic archived. No new replies allowed.