File indexing completed on 2026-09-28 09:20:50
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef _MathLin_SVD_HeaderFile
0015 #define _MathLin_SVD_HeaderFile
0016
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Config.hxx>
0019 #include <math_Recipes.hxx>
0020 #include <MathUtils_Core.hxx>
0021
0022 #include <cmath>
0023 #include <algorithm>
0024
0025 namespace MathLin
0026 {
0027 using namespace MathUtils;
0028
0029
0030 struct SVDResult
0031 {
0032 MathUtils::Status Status = MathUtils::Status::NotConverged;
0033 std::optional<math_Matrix> U;
0034 std::optional<math_Vector> SingularValues;
0035 std::optional<math_Matrix> V;
0036 int Rank = 0;
0037
0038 bool IsDone() const { return Status == MathUtils::Status::OK; }
0039
0040 explicit operator bool() const { return IsDone(); }
0041 };
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059 inline SVDResult SVD(const math_Matrix& theA, double theTolerance = 1.0e-15)
0060 {
0061 SVDResult aResult;
0062
0063 const int aRowLower = theA.LowerRow();
0064 const int aRowUpper = theA.UpperRow();
0065 const int aColLower = theA.LowerCol();
0066 const int aColUpper = theA.UpperCol();
0067 const int aM = aRowUpper - aRowLower + 1;
0068 const int aN = aColUpper - aColLower + 1;
0069
0070
0071 const int aURows = std::max(aM, aN);
0072
0073
0074 math_Matrix aU(1, aURows, 1, aN, 0.0);
0075 math_Vector aW(1, aN);
0076 math_Matrix aV(1, aN, 1, aN);
0077
0078
0079 for (int i = aRowLower; i <= aRowUpper; ++i)
0080 {
0081 for (int j = aColLower; j <= aColUpper; ++j)
0082 {
0083 aU(i - aRowLower + 1, j - aColLower + 1) = theA(i, j);
0084 }
0085 }
0086
0087
0088 if (SVD_Decompose(aU, aW, aV) != 0)
0089 {
0090 aResult.Status = Status::NumericalError;
0091 return aResult;
0092 }
0093
0094
0095 double aMaxSV = 0.0;
0096 for (int i = 1; i <= aN; ++i)
0097 {
0098 aMaxSV = std::max(aMaxSV, aW(i));
0099 }
0100
0101 double aThreshold = theTolerance * aMaxSV;
0102 aResult.Rank = 0;
0103 for (int i = 1; i <= aN; ++i)
0104 {
0105 if (aW(i) > aThreshold)
0106 {
0107 ++aResult.Rank;
0108 }
0109 }
0110
0111
0112 aResult.U = math_Matrix(aRowLower, aRowLower + aM - 1, aColLower, aColLower + aN - 1);
0113 for (int i = 1; i <= aM; ++i)
0114 {
0115 for (int j = 1; j <= aN; ++j)
0116 {
0117 (*aResult.U)(aRowLower + i - 1, aColLower + j - 1) = aU(i, j);
0118 }
0119 }
0120
0121 aResult.SingularValues = math_Vector(aColLower, aColLower + aN - 1);
0122 for (int i = 1; i <= aN; ++i)
0123 {
0124 (*aResult.SingularValues)(aColLower + i - 1) = aW(i);
0125 }
0126
0127 aResult.V = math_Matrix(aColLower, aColLower + aN - 1, aColLower, aColLower + aN - 1);
0128 for (int i = 1; i <= aN; ++i)
0129 {
0130 for (int j = 1; j <= aN; ++j)
0131 {
0132 (*aResult.V)(aColLower + i - 1, aColLower + j - 1) = aV(i, j);
0133 }
0134 }
0135
0136 aResult.Status = Status::OK;
0137 return aResult;
0138 }
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150 inline LinearResult SolveSVD(const math_Matrix& theA,
0151 const math_Vector& theB,
0152 double theTolerance = 1.0e-6)
0153 {
0154 LinearResult aResult;
0155
0156
0157 SVDResult aSVD = SVD(theA, theTolerance);
0158 if (!aSVD.IsDone())
0159 {
0160 aResult.Status = aSVD.Status;
0161 return aResult;
0162 }
0163
0164 const int aRowLower = theA.LowerRow();
0165 const int aRowUpper = theA.UpperRow();
0166 const int aColLower = theA.LowerCol();
0167 const int aColUpper = theA.UpperCol();
0168 const int aM = aRowUpper - aRowLower + 1;
0169
0170
0171 if (theB.Length() != aM)
0172 {
0173 aResult.Status = Status::InvalidInput;
0174 return aResult;
0175 }
0176
0177 const int aBLower = theB.Lower();
0178
0179 const math_Matrix& aU = *aSVD.U;
0180 const math_Vector& aW = *aSVD.SingularValues;
0181 const math_Matrix& aV = *aSVD.V;
0182
0183
0184 double aMaxSV = 0.0;
0185 for (int i = aColLower; i <= aColUpper; ++i)
0186 {
0187 aMaxSV = std::max(aMaxSV, aW(i));
0188 }
0189 double aWMin = theTolerance * aMaxSV;
0190
0191
0192
0193 math_Vector aTmp(aColLower, aColUpper, 0.0);
0194 for (int j = aColLower; j <= aColUpper; ++j)
0195 {
0196 double aSum = 0.0;
0197 for (int i = aRowLower; i <= aRowUpper; ++i)
0198 {
0199
0200 aSum += aU(i, j) * theB(aBLower + (i - aRowLower));
0201 }
0202
0203 if (aW(j) > aWMin)
0204 {
0205 aTmp(j) = aSum / aW(j);
0206 }
0207
0208 }
0209
0210
0211 aResult.Solution = math_Vector(aColLower, aColUpper, 0.0);
0212 for (int i = aColLower; i <= aColUpper; ++i)
0213 {
0214 double aSum = 0.0;
0215 for (int j = aColLower; j <= aColUpper; ++j)
0216 {
0217 aSum += aV(i, j) * aTmp(j);
0218 }
0219 (*aResult.Solution)(i) = aSum;
0220 }
0221
0222 aResult.Status = Status::OK;
0223 return aResult;
0224 }
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238 inline InverseResult PseudoInverse(const math_Matrix& theA, double theTolerance = 1.0e-6)
0239 {
0240 InverseResult aResult;
0241
0242
0243 SVDResult aSVD = SVD(theA, theTolerance);
0244 if (!aSVD.IsDone())
0245 {
0246 aResult.Status = aSVD.Status;
0247 return aResult;
0248 }
0249
0250 const int aRowLower = theA.LowerRow();
0251 const int aRowUpper = theA.UpperRow();
0252 const int aColLower = theA.LowerCol();
0253 const int aColUpper = theA.UpperCol();
0254
0255 const math_Matrix& aU = *aSVD.U;
0256 const math_Vector& aW = *aSVD.SingularValues;
0257 const math_Matrix& aV = *aSVD.V;
0258
0259
0260 double aMaxSV = 0.0;
0261 for (int i = aColLower; i <= aColUpper; ++i)
0262 {
0263 aMaxSV = std::max(aMaxSV, aW(i));
0264 }
0265 double aWMin = theTolerance * aMaxSV;
0266
0267
0268
0269 aResult.Inverse = math_Matrix(aColLower, aColUpper, aRowLower, aRowUpper, 0.0);
0270
0271 for (int i = aColLower; i <= aColUpper; ++i)
0272 {
0273 for (int j = aRowLower; j <= aRowUpper; ++j)
0274 {
0275 double aSum = 0.0;
0276 for (int k = aColLower; k <= aColUpper; ++k)
0277 {
0278 if (aW(k) > aWMin)
0279 {
0280 aSum += aV(i, k) * aU(j, k) / aW(k);
0281 }
0282 }
0283 (*aResult.Inverse)(i, j) = aSum;
0284 }
0285 }
0286
0287 aResult.Status = Status::OK;
0288 return aResult;
0289 }
0290
0291
0292
0293
0294
0295
0296
0297
0298 inline double ConditionNumber(const math_Matrix& theA)
0299 {
0300 SVDResult aSVD = SVD(theA);
0301 if (!aSVD.IsDone())
0302 {
0303 return std::numeric_limits<double>::infinity();
0304 }
0305
0306 const math_Vector& aW = *aSVD.SingularValues;
0307 const int aLower = aW.Lower();
0308 const int aUpper = aW.Upper();
0309
0310 double aMaxSV = 0.0;
0311 double aMinSV = std::numeric_limits<double>::max();
0312
0313 for (int i = aLower; i <= aUpper; ++i)
0314 {
0315 if (aW(i) > 0.0)
0316 {
0317 aMaxSV = std::max(aMaxSV, aW(i));
0318 aMinSV = std::min(aMinSV, aW(i));
0319 }
0320 }
0321
0322 if (aMinSV <= 0.0 || aMaxSV <= 0.0)
0323 {
0324 return std::numeric_limits<double>::infinity();
0325 }
0326
0327 return aMaxSV / aMinSV;
0328 }
0329
0330
0331
0332
0333
0334
0335
0336 inline int NumericalRank(const math_Matrix& theA, double theTolerance = 1.0e-15)
0337 {
0338 SVDResult aSVD = SVD(theA, theTolerance);
0339 return aSVD.IsDone() ? aSVD.Rank : 0;
0340 }
0341
0342 }
0343
0344 #endif