SVD: VSinvUt is not always needed and is now calculated and returned by the 'VSinvUt()' function

rather than being calculated on construction and stored as member data.

The convergence warning has be replaced with the 'convergence()' member
function which returns 'true' if the SVD iteration converged, otherwise 'false'.
This commit is contained in:
Henry Weller
2016-07-18 13:15:25 +01:00
parent af6b67c719
commit 3b7de01705
6 changed files with 47 additions and 33 deletions

View File

@ -35,7 +35,7 @@ Foam::SVD::SVD(const scalarRectangularMatrix& A, const scalar minCondition)
U_(A), U_(A),
V_(A.n(), A.n()), V_(A.n(), A.n()),
S_(A.n()), S_(A.n()),
VSinvUt_(A.n(), A.m()), converged_(true),
nZeros_(0) nZeros_(0)
{ {
// SVDcomp to find U_, V_ and S_ - the singular values // SVDcomp to find U_, V_ and S_ - the singular values
@ -117,10 +117,10 @@ Foam::SVD::SVD(const scalarRectangularMatrix& A, const scalar minCondition)
s += U_(i, k)*U_(i, k); s += U_(i, k)*U_(i, k);
} }
scalar f = U_[i][l-1]; scalar f = U_(i, l-1);
g = -sign(sqrt(s), f); g = -sign(sqrt(s), f);
scalar h = f*g - s; scalar h = f*g - s;
U_[i][l-1] = f - g; U_(i, l-1) = f - g;
for (label k=l-1; k<Un; k++) for (label k=l-1; k<Un; k++)
{ {
@ -281,9 +281,9 @@ Foam::SVD::SVD(const scalarRectangularMatrix& A, const scalar minCondition)
for (label j=0; j<Um; j++) for (label j=0; j<Um; j++)
{ {
scalar y = U_[j][mn]; scalar y = U_(j, mn);
scalar z = U_(j, i); scalar z = U_(j, i);
U_[j][mn] = y*c + z*s; U_(j, mn) = y*c + z*s;
U_(j, i) = z*c - y*s; U_(j, i) = z*c - y*s;
} }
} }
@ -303,11 +303,10 @@ Foam::SVD::SVD(const scalarRectangularMatrix& A, const scalar minCondition)
} }
break; break;
} }
if (its == 29) if (its == 29)
{ {
WarningInFunction converged_ = false;
<< "No convergence in 30 SVD iterations"
<< endl;
} }
scalar x = S_[l]; scalar x = S_[l];
@ -339,10 +338,10 @@ Foam::SVD::SVD(const scalarRectangularMatrix& A, const scalar minCondition)
for (label jj = 0; jj < Un; jj++) for (label jj = 0; jj < Un; jj++)
{ {
x = V_[jj][j]; x = V_(jj, j);
z = V_[jj][i]; z = V_(jj, i);
V_[jj][j] = x*c + z*s; V_(jj, j) = x*c + z*s;
V_[jj][i] = z*c - x*s; V_(jj, i) = z*c - x*s;
} }
z = sqrtSumSqr(f, h); z = sqrtSumSqr(f, h);
@ -358,10 +357,10 @@ Foam::SVD::SVD(const scalarRectangularMatrix& A, const scalar minCondition)
for (label jj=0; jj < Um; jj++) for (label jj=0; jj < Um; jj++)
{ {
y = U_[jj][j]; y = U_(jj, j);
z = U_[jj][i]; z = U_(jj, i);
U_[jj][j] = y*c + z*s; U_(jj, j) = y*c + z*s;
U_[jj][i] = z*c - y*s; U_(jj, i) = z*c - y*s;
} }
} }
rv1[l] = 0; rv1[l] = 0;
@ -380,9 +379,14 @@ Foam::SVD::SVD(const scalarRectangularMatrix& A, const scalar minCondition)
nZeros_++; nZeros_++;
} }
} }
}
// Now multiply out to find the pseudo inverse of A, VSinvUt_
multiply(VSinvUt_, V_, inv(S_), U_.T()); Foam::scalarRectangularMatrix Foam::SVD::VSinvUt() const
{
scalarRectangularMatrix VSinvUt;
multiply(VSinvUt, V_, inv(S_), U_.T());
return VSinvUt;
} }

View File

@ -62,8 +62,8 @@ class SVD
//- The singular values //- The singular values
DiagonalMatrix<scalar> S_; DiagonalMatrix<scalar> S_;
//- The matrix product V S^(-1) U^T //- Convergence flag
scalarRectangularMatrix VSinvUt_; bool converged_;
//- The number of zero singular values //- The number of zero singular values
label nZeros_; label nZeros_;
@ -100,14 +100,17 @@ public:
//- Return the singular values //- Return the singular values
inline const scalarDiagonalMatrix& S() const; inline const scalarDiagonalMatrix& S() const;
//- Return VSinvUt (the pseudo inverse) //- Return the minimum non-zero singular value
inline const scalarRectangularMatrix& VSinvUt() const; inline bool converged() const;
//- Return the number of zero singular values //- Return the number of zero singular values
inline label nZeros() const; inline label nZeros() const;
//- Return the minimum non-zero singular value //- Return the minimum non-zero singular value
inline scalar minNonZeroS() const; inline scalar minNonZeroS() const;
//- Return the matrix product V S^(-1) U^T (the pseudo inverse)
scalarRectangularMatrix VSinvUt() const;
}; };

View File

@ -40,26 +40,31 @@ inline const Foam::scalarRectangularMatrix& Foam::SVD::U() const
return U_; return U_;
} }
inline const Foam::scalarRectangularMatrix& Foam::SVD::V() const inline const Foam::scalarRectangularMatrix& Foam::SVD::V() const
{ {
return V_; return V_;
} }
inline const Foam::scalarDiagonalMatrix& Foam::SVD::S() const inline const Foam::scalarDiagonalMatrix& Foam::SVD::S() const
{ {
return S_; return S_;
} }
inline const Foam::scalarRectangularMatrix& Foam::SVD::VSinvUt() const
inline bool Foam::SVD::converged() const
{ {
return VSinvUt_; return converged_;
} }
inline Foam::label Foam::SVD::nZeros() const inline Foam::label Foam::SVD::nZeros() const
{ {
return nZeros_; return nZeros_;
} }
inline Foam::scalar Foam::SVD::minNonZeroS() const inline Foam::scalar Foam::SVD::minNonZeroS() const
{ {
scalar minS = S_[0]; scalar minS = S_[0];

View File

@ -321,7 +321,7 @@ void Foam::multiply
} }
Foam::RectangularMatrix<Foam::scalar> Foam::SVDinv Foam::scalarRectangularMatrix Foam::SVDinv
( (
const scalarRectangularMatrix& A, const scalarRectangularMatrix& A,
scalar minCondition scalar minCondition

View File

@ -134,17 +134,18 @@ void Foam::CentredFitSnGradData<Polynomial>::calcFit
for (int iIt = 0; iIt < 8 && !goodFit; iIt++) for (int iIt = 0; iIt < 8 && !goodFit; iIt++)
{ {
SVD svd(B, SMALL); SVD svd(B, SMALL);
scalarRectangularMatrix invB(svd.VSinvUt());
for (label i=0; i<stencilSize; i++) for (label i=0; i<stencilSize; i++)
{ {
coeffsi[i] = wts[1]*wts[i]*svd.VSinvUt()(1, i)/scale; coeffsi[i] = wts[1]*wts[i]*invB(1, i)/scale;
} }
goodFit = goodFit =
( (
mag(wts[0]*wts[0]*svd.VSinvUt()(0, 0) - wLin) mag(wts[0]*wts[0]*invB(0, 0) - wLin)
< this->linearLimitFactor()*wLin) < this->linearLimitFactor()*wLin)
&& (mag(wts[0]*wts[1]*svd.VSinvUt()(0, 1) - (1 - wLin) && (mag(wts[0]*wts[1]*invB(0, 1) - (1 - wLin)
) < this->linearLimitFactor()*(1 - wLin)) ) < this->linearLimitFactor()*(1 - wLin))
&& coeffsi[0] < 0 && coeffsi[1] > 0 && coeffsi[0] < 0 && coeffsi[1] > 0
&& mag(coeffsi[0] + deltaCoeff) < 0.5*deltaCoeff && mag(coeffsi[0] + deltaCoeff) < 0.5*deltaCoeff
@ -163,10 +164,10 @@ void Foam::CentredFitSnGradData<Polynomial>::calcFit
<< " deltaCoeff " << deltaCoeff << nl << " deltaCoeff " << deltaCoeff << nl
<< " sing vals " << svd.S() << nl << " sing vals " << svd.S() << nl
<< "Components of goodFit:\n" << "Components of goodFit:\n"
<< " wts[0]*wts[0]*svd.VSinvUt()(0, 0) = " << " wts[0]*wts[0]*invB(0, 0) = "
<< wts[0]*wts[0]*svd.VSinvUt()(0, 0) << nl << wts[0]*wts[0]*invB(0, 0) << nl
<< " wts[0]*wts[1]*svd.VSinvUt()(0, 1) = " << " wts[0]*wts[1]*invB(0, 1) = "
<< wts[0]*wts[1]*svd.VSinvUt()(0, 1) << wts[0]*wts[1]*invB(0, 1)
<< " dim = " << this->dim() << endl; << " dim = " << this->dim() << endl;
wts[0] *= 10; wts[0] *= 10;

View File

@ -208,13 +208,14 @@ void Foam::FitData<FitDataType, ExtendedStencil, Polynomial>::calcFit
for (int iIt = 0; iIt < 8 && !goodFit; iIt++) for (int iIt = 0; iIt < 8 && !goodFit; iIt++)
{ {
SVD svd(B, SMALL); SVD svd(B, SMALL);
scalarRectangularMatrix invB(svd.VSinvUt());
scalar maxCoeff = 0; scalar maxCoeff = 0;
label maxCoeffi = 0; label maxCoeffi = 0;
for (label i=0; i<stencilSize; i++) for (label i=0; i<stencilSize; i++)
{ {
coeffsi[i] = wts[0]*wts[i]*svd.VSinvUt()(0, i); coeffsi[i] = wts[0]*wts[i]*invB(0, i);
if (mag(coeffsi[i]) > maxCoeff) if (mag(coeffsi[i]) > maxCoeff)
{ {
maxCoeff = mag(coeffsi[i]); maxCoeff = mag(coeffsi[i]);