00001 /*
00002 File: Solve.cc
00003
00004 Function: Implements Solve.h
00005
00006 Author(s): Andrew Willmott
00007
00008 Copyright: (c) 1995-2000, Andrew Willmott
00009
00010 Notes:
00011
00012 */
00013
00014
00015 #include "vl/Solve.h"
00016
00035 TMReal SolveOverRelax(
00036 const TMat &A,
00037 TVec &x,
00038 const TVec &b,
00039 TMReal epsilon,
00040 TMReal omega,
00041 Int *steps
00042 )
00043 {
00044 Int i, j, jMax;
00045 TMReal sum;
00046 TMReal diagonal, xOld, error;
00047
00048 Assert(A.IsSquare(), "(SolveOverRelax) Matrix not square");
00049 j = 0;
00050 if (steps)
00051 jMax = *steps;
00052 else
00053 jMax = VL_MAX_STEPS;
00054
00055 do
00056 {
00057 error = 0.0;
00058 for (i = 0; i < A.Rows(); i++)
00059 {
00060 sum = b[i] - dot(A[i], x);
00061 diagonal = A[i][i];
00062 sum += diagonal * x[i];
00063 // I.e., sum = b[i] - (A[i] * x - A[i,i])
00064 xOld = x[i];
00065
00066 if (diagonal == 0)
00067 _Warning("(SolveOverRelax) diagonal element = 0");
00068 else if (omega == 1.0) // Gauss-Seidel
00069 x[i] = sum / diagonal;
00070 else // Overrelax
00071 x[i] = Mix(xOld, sum / diagonal, (Real) omega);
00072
00073 sum -= diagonal * xOld;
00074 error += sqr(sum);
00075 }
00076 j++;
00077 }
00078 while (error > epsilon && j < jMax);
00079
00080 if (steps)
00081 *steps = j;
00082
00083 return(error);
00084 }
00085
00091 TMReal SolveOverRelax(
00092 const TSparseMat &A,
00093 TVec &x,
00094 const TVec &b,
00095 TMReal epsilon,
00096 TMReal omega,
00097 Int *steps
00098 )
00099 {
00100 Int i, j, jMax;
00101 TMReal sum;
00102 TMReal diagonal, xOld, error;
00103
00104 Assert(A.IsSquare(), "(SolveOverRelax) Matrix not square");
00105 j = 0;
00106 if (steps)
00107 jMax = *steps;
00108 else
00109 jMax = VL_MAX_STEPS;
00110
00111 do
00112 {
00113 error = 0.0;
00114 for (i = 0; i < A.Rows(); i++)
00115 {
00116 // sum = b[i] - (A[i] dot x - A[i,i])
00117
00118 sum = b[i] - dot(A[i], x);
00119 diagonal = A[i].Get(i);
00120 sum += diagonal * x[i];
00121
00122 xOld = x[i];
00123
00124 if (diagonal == 0)
00125 _Warning("(SolveOverRelax) diagonal element = 0");
00126 else if (omega == 1)
00127 x[i] = sum / diagonal; // Gauss-Seidel
00128 else
00129 x[i] = Mix(xOld, sum / diagonal, (Real) omega);
00130
00131 sum -= diagonal * xOld;
00132 error += sqr(sum);
00133 }
00134 j++;
00135 }
00136 while (error > epsilon && j < jMax);
00137
00138 if (steps)
00139 *steps = j;
00140
00141 return(error);
00142 }
00143
00144
00159 TMReal SolveConjGrad(
00160 const TMat &A, // Solve Ax = b.
00161 TVec &x,
00162 const TVec &b,
00163 TMReal epsilon, // how low should we go?
00164 Int *steps // iterations to converge.
00165 )
00166 {
00167 Int i, iMax;
00168 TMReal alpha, beta, rSqrLen, rSqrLenOld, u;
00169 TVec r(A.Rows()); // Residual vector, b - Ax
00170 TVec d(A.Rows()); // Direction to move x at each step
00171 TVec t(A.Rows()); // temp!
00172
00173 Assert(A.IsSquare(), "(SolveConjGrad) Matrix not square");
00174
00175 r = b;
00176 r -= A * x;
00177 rSqrLen = sqrlen(r);
00178 d = r;
00179 i = 0;
00180 if (steps)
00181 iMax = *steps;
00182 else
00183 iMax = VL_MAX_STEPS;
00184
00185 if (rSqrLen < epsilon)
00186 while (i < iMax)
00187 {
00188 i++;
00189 t = A * d;
00190 u = dot(d, t);
00191
00192 if (u == 0)
00193 {
00194 _Warning("(SolveConjGrad) d'Ad = 0");
00195 break;
00196 }
00197
00198 alpha = rSqrLen / u; // How far should we go?
00199 x += alpha * d; // Take a step along direction d
00200 if (i & 0x3F)
00201 r -= alpha * t;
00202 else
00203 {
00204 r = b; // For stability, correct r every 64th iteration
00205 r -= A * x;
00206 }
00207
00208 rSqrLenOld = rSqrLen;
00209 rSqrLen = sqrlen(r);
00210
00211 if (rSqrLen <= epsilon)
00212 break; // Converged! Let's get out of here
00213
00214 beta = rSqrLen/rSqrLenOld;
00215 d *= beta; // Change direction: d = r + beta * d
00216 d += r;
00217 }
00218
00219 if (steps)
00220 *steps = i;
00221
00222 return(rSqrLen);
00223 }
00224
00230 TMReal SolveConjGrad(
00231 const TSparseMat &A,
00232 TVec &x,
00233 const TVec &b,
00234 TMReal epsilon,
00235 Int *steps
00236 )
00237 {
00238 Int i, iMax;
00239 TMReal alpha, beta, rSqrLen, rSqrLenOld, u;
00240 TVec r(b.Elts()); // Residual vector, b - Ax
00241 TVec d(b.Elts()); // Direction to move x at each step
00242 TVec t(b.Elts());
00243
00244 Assert(A.IsSquare(), "(SolveConjGrad) Matrix not square");
00245 r = b;
00246 r -= A * x;
00247 rSqrLen = sqrlen(r);
00248 d = r;
00249 i = 0;
00250 if (steps)
00251 iMax = *steps;
00252 else
00253 iMax = VL_MAX_STEPS;
00254
00255 if (rSqrLen > epsilon) // If we haven't already converged...
00256 while (i < iMax)
00257 {
00258 i++;
00259 t = A * d;
00260 u = dot(d, t);
00261
00262 if (u == 0.0)
00263 {
00264 _Warning("(SolveConjGrad) d'Ad = 0");
00265 break;
00266 }
00267
00268 alpha = rSqrLen / u; // How far should we go?
00269 x += alpha * d; // Take a step along direction d
00270 r -= alpha * t;
00271 rSqrLenOld = rSqrLen;
00272 rSqrLen = sqrlen(r);
00273
00274 if (rSqrLen <= epsilon)
00275 break; // Converged! Let's get out of here
00276
00277 beta = rSqrLen / rSqrLenOld;
00278 d = r + beta * d; // Change direction
00279 }
00280
00281 if (steps)
00282 *steps = i;
00283
00284 return(rSqrLen);
00285 }
00286