1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
27 #include "scalarList.H"
28 #include "scalarMatrices.H"
31 // * * * * * * * * * * * * * * * * Constructor * * * * * * * * * * * * * * //
33 Foam::SVD::SVD(const scalarRectangularMatrix& A, const scalar minCondition)
38 VSinvUt_(A.m(), A.n()),
41 // SVDcomp to find U_, V_ and S_ - the singular values
43 const label Um = U_.m();
44 const label Un = U_.n();
53 for (label i = 0; i < Um; i++)
61 for (label k = i; k < Un; k++)
63 scale += mag(U_[k][i]);
68 for (label k = i; k < Un; k++)
71 s += U_[k][i]*U_[k][i];
75 g = -sign(Foam::sqrt(s), f);
79 for (label j = l-1; j < Um; j++)
82 for (label k = i; k < Un; k++)
84 s += U_[k][i]*U_[k][j];
88 for (label k = i; k < A.n(); k++)
90 U_[k][j] += f*U_[k][i];
94 for (label k = i; k < Un; k++)
105 if (i+1 <= Un && i != Um)
107 for (label k = l-1; k < Um; k++)
109 scale += mag(U_[i][k]);
114 for (label k=l-1; k < Um; k++)
117 s += U_[i][k]*U_[i][k];
120 scalar f = U_[i][l-1];
121 g = -sign(Foam::sqrt(s),f);
125 for (label k = l-1; k < Um; k++)
130 for (label j = l-1; j < Un; j++)
133 for (label k = l-1; k < Um; k++)
135 s += U_[j][k]*U_[i][k];
138 for (label k = l-1; k < Um; k++)
140 U_[j][k] += s*rv1[k];
143 for (label k = l-1; k < Um; k++)
150 anorm = max(anorm, mag(S_[i]) + mag(rv1[i]));
153 for (label i = Um-1; i >= 0; i--)
159 for (label j = l; j < Um; j++)
161 V_[j][i] = (U_[i][j]/U_[i][l])/g;
164 for (label j=l; j < Um; j++)
167 for (label k = l; k < Um; k++)
169 s += U_[i][k]*V_[k][j];
172 for (label k = l; k < Um; k++)
174 V_[k][j] += s*V_[k][i];
179 for (label j = l; j < Um;j++)
181 V_[i][j] = V_[j][i] = 0.0;
190 for (label i = min(Um, Un) - 1; i >= 0; i--)
195 for (label j = l; j < Um; j++)
204 for (label j = l; j < Um; j++)
207 for (label k = l; k < Un; k++)
209 s += U_[k][i]*U_[k][j];
212 scalar f = (s/U_[i][i])*g;
214 for (label k = i; k < Un; k++)
216 U_[k][j] += f*U_[k][i];
220 for (label j = i; j < Un; j++)
227 for (label j = i; j < Un; j++)
236 for (label k = Um-1; k >= 0; k--)
238 for (label its = 0; its < 35; its++)
243 for (l = k; l >= 0; l--)
246 if (mag(rv1[l]) + anorm == anorm)
251 if (mag(S_[nm]) + anorm == anorm) break;
258 for (label i = l-1; i < k+1; i++)
263 if (mag(f) + anorm == anorm) break;
266 scalar h = sqrtSumSqr(f, g);
272 for (label j = 0; j < Un; j++)
274 scalar y = U_[j][nm];
276 U_[j][nm] = y*c + z*s;
277 U_[j][i] = z*c - y*s;
290 for (label j = 0; j < Um; j++) V_[j][k] = -V_[j][k];
299 "(scalarRectangularMatrix& A, const scalar minCondition)"
300 ) << "no convergence in 35 SVD iterations"
309 scalar f = ((y - z)*(y + z) + (g - h)*(g + h))/(2.0*h*y);
310 g = sqrtSumSqr(f, scalar(1));
311 f = ((x - z)*(x + z) + h*((y/(f + sign(g, f))) - h))/x;
315 for (label j = l; j <= nm; j++)
322 scalar z = sqrtSumSqr(f, h);
331 for (label jj = 0; jj < Um; jj++)
335 V_[jj][j] = x*c + z*s;
336 V_[jj][i] = z*c - x*s;
339 z = sqrtSumSqr(f, h);
350 for (label jj=0; jj < Un; jj++)
354 U_[jj][j] = y*c + z*s;
355 U_[jj][i] = z*c - y*s;
364 // zero singular values that are less than minCondition*maxS
365 const scalar minS = minCondition*S_[findMax(S_)];
370 //Info<< "Removing " << S_[i] << " < " << minS << endl;
376 // now multiply out to find the pseudo inverse of A, VSinvUt_
377 multiply(VSinvUt_, V_, inv(S_), U_.T());
380 /*scalarRectangularMatrix SVDA(A.n(), A.m());
381 multiply(SVDA, U_, S_, transpose(V_));
384 for (label i = 0; i < A.n(); i++)
386 for (label j = 0; j < A.m(); j++)
388 diff = mag(A[i][j] - SVDA[i][j]);
389 if (diff > maxDiff) maxDiff = diff;
392 Info<< "Maximum discrepancy between A and svd(A) = " << maxDiff << endl;
396 Info<< "singular values " << S_ << endl;
402 // ************************************************************************* //