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_Householder_HeaderFile
0015 #define _MathLin_Householder_HeaderFile
0016
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Config.hxx>
0019 #include <MathUtils_Core.hxx>
0020
0021 #include <cmath>
0022 #include <algorithm>
0023
0024 namespace MathLin
0025 {
0026 using namespace MathUtils;
0027
0028
0029 struct QRResult
0030 {
0031 MathUtils::Status Status = MathUtils::Status::NotConverged;
0032 std::optional<math_Matrix> Q;
0033 std::optional<math_Matrix> R;
0034 int Rank = 0;
0035
0036 bool IsDone() const { return Status == MathUtils::Status::OK; }
0037
0038 explicit operator bool() const { return IsDone(); }
0039 };
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057 inline QRResult QR(const math_Matrix& theA, double theTolerance = 1.0e-20)
0058 {
0059 QRResult aResult;
0060
0061 const int aRowLower = theA.LowerRow();
0062 const int aRowUpper = theA.UpperRow();
0063 const int aColLower = theA.LowerCol();
0064 const int aColUpper = theA.UpperCol();
0065 const int aM = aRowUpper - aRowLower + 1;
0066 const int aN = aColUpper - aColLower + 1;
0067
0068 if (aM < aN)
0069 {
0070 aResult.Status = Status::InvalidInput;
0071 return aResult;
0072 }
0073
0074
0075 math_Matrix aR(aRowLower, aRowUpper, aColLower, aColUpper);
0076 for (int i = aRowLower; i <= aRowUpper; ++i)
0077 {
0078 for (int j = aColLower; j <= aColUpper; ++j)
0079 {
0080 aR(i, j) = theA(i, j);
0081 }
0082 }
0083
0084
0085 math_Matrix aQ(aRowLower, aRowUpper, aRowLower, aRowUpper, 0.0);
0086 for (int i = aRowLower; i <= aRowUpper; ++i)
0087 {
0088 aQ(i, i) = 1.0;
0089 }
0090
0091
0092 math_Vector aV(aRowLower, aRowUpper);
0093
0094 aResult.Rank = 0;
0095
0096
0097 for (int j = aColLower; j <= aColUpper; ++j)
0098 {
0099 const int aJOffset = j - aColLower;
0100
0101
0102 double aNorm = 0.0;
0103 for (int i = aRowLower + aJOffset; i <= aRowUpper; ++i)
0104 {
0105 aNorm += MathUtils::Sqr(aR(i, j));
0106 }
0107 aNorm = std::sqrt(aNorm);
0108
0109 if (aNorm < theTolerance)
0110 {
0111
0112 continue;
0113 }
0114
0115 ++aResult.Rank;
0116
0117
0118 double aAlpha = aR(aRowLower + aJOffset, j);
0119 double aBeta = (aAlpha >= 0.0) ? -aNorm : aNorm;
0120
0121
0122 for (int i = aRowLower; i < aRowLower + aJOffset; ++i)
0123 {
0124 aV(i) = 0.0;
0125 }
0126 aV(aRowLower + aJOffset) = aAlpha - aBeta;
0127 for (int i = aRowLower + aJOffset + 1; i <= aRowUpper; ++i)
0128 {
0129 aV(i) = aR(i, j);
0130 }
0131
0132
0133 double aVNormSq = 0.0;
0134 for (int i = aRowLower + aJOffset; i <= aRowUpper; ++i)
0135 {
0136 aVNormSq += MathUtils::Sqr(aV(i));
0137 }
0138
0139 if (aVNormSq < MathUtils::THE_ZERO_TOL)
0140 {
0141 continue;
0142 }
0143
0144 double aTau = 2.0 / aVNormSq;
0145
0146
0147
0148 for (int k = j; k <= aColUpper; ++k)
0149 {
0150
0151 double aVdotRk = 0.0;
0152 for (int i = aRowLower + aJOffset; i <= aRowUpper; ++i)
0153 {
0154 aVdotRk += aV(i) * aR(i, k);
0155 }
0156
0157
0158 for (int i = aRowLower + aJOffset; i <= aRowUpper; ++i)
0159 {
0160 aR(i, k) -= aTau * aVdotRk * aV(i);
0161 }
0162 }
0163
0164
0165 for (int k = aRowLower; k <= aRowUpper; ++k)
0166 {
0167
0168 double aQkV = 0.0;
0169 for (int i = aRowLower + aJOffset; i <= aRowUpper; ++i)
0170 {
0171 aQkV += aQ(k, i) * aV(i);
0172 }
0173
0174
0175 for (int i = aRowLower + aJOffset; i <= aRowUpper; ++i)
0176 {
0177 aQ(k, i) -= aTau * aQkV * aV(i);
0178 }
0179 }
0180 }
0181
0182
0183 for (int i = aRowLower; i <= aRowUpper; ++i)
0184 {
0185 for (int j = aColLower; j < aColLower + (i - aRowLower) && j <= aColUpper; ++j)
0186 {
0187 aR(i, j) = 0.0;
0188 }
0189 }
0190
0191 aResult.Q = aQ;
0192 aResult.R = aR;
0193 aResult.Status = Status::OK;
0194 return aResult;
0195 }
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210 inline LinearResult SolveQR(const math_Matrix& theA,
0211 const math_Vector& theB,
0212 double theTolerance = 1.0e-20)
0213 {
0214 LinearResult aResult;
0215
0216 const int aRowLower = theA.LowerRow();
0217 const int aRowUpper = theA.UpperRow();
0218 const int aColLower = theA.LowerCol();
0219 const int aColUpper = theA.UpperCol();
0220 const int aM = aRowUpper - aRowLower + 1;
0221
0222
0223 if (theB.Length() != aM)
0224 {
0225 aResult.Status = Status::InvalidInput;
0226 return aResult;
0227 }
0228
0229
0230 QRResult aQR = QR(theA, theTolerance);
0231 if (!aQR.IsDone())
0232 {
0233 aResult.Status = aQR.Status;
0234 return aResult;
0235 }
0236
0237 const math_Matrix& aQ = *aQR.Q;
0238 const math_Matrix& aR = *aQR.R;
0239
0240
0241 math_Vector aC(aRowLower, aRowUpper, 0.0);
0242 for (int i = aRowLower; i <= aRowUpper; ++i)
0243 {
0244 double aSum = 0.0;
0245 for (int k = aRowLower; k <= aRowUpper; ++k)
0246 {
0247 aSum += aQ(k, i) * theB(theB.Lower() + k - aRowLower);
0248 }
0249 aC(i) = aSum;
0250 }
0251
0252
0253 aResult.Solution = math_Vector(aColLower, aColUpper, 0.0);
0254
0255 for (int i = aColUpper; i >= aColLower; --i)
0256 {
0257 const int aIOffset = i - aColLower;
0258 double aDiag = aR(aRowLower + aIOffset, i);
0259
0260 if (std::abs(aDiag) < theTolerance)
0261 {
0262 aResult.Status = Status::Singular;
0263 return aResult;
0264 }
0265
0266 double aSum = aC(aRowLower + aIOffset);
0267 for (int k = i + 1; k <= aColUpper; ++k)
0268 {
0269 aSum -= aR(aRowLower + aIOffset, k) * (*aResult.Solution)(k);
0270 }
0271 (*aResult.Solution)(i) = aSum / aDiag;
0272 }
0273
0274 aResult.Status = Status::OK;
0275 return aResult;
0276 }
0277
0278
0279
0280
0281
0282
0283
0284 inline LinearMultipleResult SolveQRMultiple(const math_Matrix& theA,
0285 const math_Matrix& theB,
0286 double theTolerance = 1.0e-20)
0287 {
0288 LinearMultipleResult aResult;
0289
0290 const int aRowLower = theA.LowerRow();
0291 const int aRowUpper = theA.UpperRow();
0292 const int aColLower = theA.LowerCol();
0293 const int aColUpper = theA.UpperCol();
0294
0295
0296 if (theB.RowNumber() != theA.RowNumber())
0297 {
0298 aResult.Status = Status::InvalidInput;
0299 return aResult;
0300 }
0301
0302
0303 QRResult aQR = QR(theA, theTolerance);
0304 if (!aQR.IsDone())
0305 {
0306 aResult.Status = aQR.Status;
0307 return aResult;
0308 }
0309
0310 const math_Matrix& aQ = *aQR.Q;
0311 const math_Matrix& aR = *aQR.R;
0312
0313
0314 math_Matrix aX(aColLower, aColUpper, theB.LowerCol(), theB.UpperCol(), 0.0);
0315
0316 for (int j = theB.LowerCol(); j <= theB.UpperCol(); ++j)
0317 {
0318
0319 math_Vector aC(aRowLower, aRowUpper, 0.0);
0320 for (int i = aRowLower; i <= aRowUpper; ++i)
0321 {
0322 double aSum = 0.0;
0323 for (int k = aRowLower; k <= aRowUpper; ++k)
0324 {
0325 const int aBRow = theB.LowerRow() + (k - aRowLower);
0326 aSum += aQ(k, i) * theB(aBRow, j);
0327 }
0328 aC(i) = aSum;
0329 }
0330
0331
0332 for (int i = aColUpper; i >= aColLower; --i)
0333 {
0334 const int aIOffset = i - aColLower;
0335 const int aRRow = aRowLower + aIOffset;
0336 double aDiag = aR(aRRow, i);
0337
0338 if (std::abs(aDiag) < theTolerance)
0339 {
0340 aResult.Status = Status::Singular;
0341 return aResult;
0342 }
0343
0344 double aSum = aC(aRRow);
0345 for (int k = i + 1; k <= aColUpper; ++k)
0346 {
0347 aSum -= aR(aRRow, k) * aX(k, j);
0348 }
0349 aX(i, j) = aSum / aDiag;
0350 }
0351 }
0352
0353 aResult.Solutions = aX;
0354 aResult.Status = Status::OK;
0355 return aResult;
0356 }
0357
0358 }
0359
0360 #endif