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_Gauss_HeaderFile
0015 #define _MathLin_Gauss_HeaderFile
0016
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Config.hxx>
0019 #include <MathUtils_Core.hxx>
0020 #include <math_Vector.hxx>
0021 #include <math_Matrix.hxx>
0022 #include <math_IntegerVector.hxx>
0023
0024 #include <cmath>
0025
0026 namespace MathLin
0027 {
0028 using namespace MathUtils;
0029
0030
0031 struct LUResult
0032 {
0033 MathUtils::Status Status = MathUtils::Status::NotConverged;
0034 std::optional<math_Matrix> LU;
0035 std::optional<math_IntegerVector> Pivot;
0036 std::optional<double> Determinant;
0037 int Sign = 1;
0038
0039 bool IsDone() const { return Status == MathUtils::Status::OK; }
0040
0041 explicit operator bool() const { return IsDone(); }
0042 };
0043
0044
0045
0046
0047
0048
0049
0050
0051 inline LUResult LU(const math_Matrix& theA, double theMinPivot = 1.0e-20)
0052 {
0053 LUResult aResult;
0054
0055 const int aRowLower = theA.LowerRow();
0056 const int aRowUpper = theA.UpperRow();
0057 const int aColLower = theA.LowerCol();
0058 const int aColUpper = theA.UpperCol();
0059 const int aRowCount = aRowUpper - aRowLower + 1;
0060 const int aColCount = aColUpper - aColLower + 1;
0061
0062
0063 if (aRowCount != aColCount)
0064 {
0065 aResult.Status = Status::InvalidInput;
0066 return aResult;
0067 }
0068
0069
0070 aResult.LU = theA;
0071 aResult.Pivot = math_IntegerVector(aRowLower, aRowUpper);
0072 aResult.Sign = 1;
0073
0074 math_Matrix& aLU = *aResult.LU;
0075 math_IntegerVector& aPivot = *aResult.Pivot;
0076
0077
0078 math_Vector aScale(aRowLower, aRowUpper);
0079 for (int i = aRowLower; i <= aRowUpper; ++i)
0080 {
0081 double aMax = 0.0;
0082 for (int j = aColLower; j <= aColUpper; ++j)
0083 {
0084 const double aAbs = std::abs(aLU(i, j));
0085 if (aAbs > aMax)
0086 {
0087 aMax = aAbs;
0088 }
0089 }
0090 if (aMax < theMinPivot)
0091 {
0092 aResult.Status = Status::NumericalError;
0093 return aResult;
0094 }
0095 aScale(i) = 1.0 / aMax;
0096 }
0097
0098
0099 for (int k = aRowLower; k <= aRowUpper; ++k)
0100 {
0101
0102 double aMaxScaled = 0.0;
0103 int aPivotRow = k;
0104
0105 for (int i = k; i <= aRowUpper; ++i)
0106 {
0107 const double aScaled = aScale(i) * std::abs(aLU(i, k));
0108 if (aScaled > aMaxScaled)
0109 {
0110 aMaxScaled = aScaled;
0111 aPivotRow = i;
0112 }
0113 }
0114
0115
0116 if (aPivotRow != k)
0117 {
0118 for (int j = aColLower; j <= aColUpper; ++j)
0119 {
0120 std::swap(aLU(aPivotRow, j), aLU(k, j));
0121 }
0122 aResult.Sign = -aResult.Sign;
0123 std::swap(aScale(aPivotRow), aScale(k));
0124 }
0125 aPivot(k) = aPivotRow;
0126
0127
0128 if (std::abs(aLU(k, k)) < theMinPivot)
0129 {
0130 aResult.Status = Status::NumericalError;
0131 return aResult;
0132 }
0133
0134
0135 for (int i = k + 1; i <= aRowUpper; ++i)
0136 {
0137 aLU(i, k) /= aLU(k, k);
0138 const double aFactor = aLU(i, k);
0139 for (int j = k + 1; j <= aColUpper; ++j)
0140 {
0141 aLU(i, j) -= aFactor * aLU(k, j);
0142 }
0143 }
0144 }
0145
0146
0147 aResult.Determinant = static_cast<double>(aResult.Sign);
0148 for (int i = aRowLower; i <= aRowUpper; ++i)
0149 {
0150 *aResult.Determinant *= aLU(i, i);
0151 }
0152
0153 aResult.Status = Status::OK;
0154 return aResult;
0155 }
0156
0157
0158
0159
0160
0161
0162
0163 inline LinearResult Solve(const math_Matrix& theA,
0164 const math_Vector& theB,
0165 double theMinPivot = 1.0e-20)
0166 {
0167 LinearResult aResult;
0168
0169
0170 LUResult aLURes = LU(theA, theMinPivot);
0171 if (!aLURes.IsDone())
0172 {
0173 aResult.Status = aLURes.Status;
0174 return aResult;
0175 }
0176
0177 const int aRowLower = theA.LowerRow();
0178 const int aRowUpper = theA.UpperRow();
0179
0180
0181 if (theB.Lower() != aRowLower || theB.Upper() != aRowUpper)
0182 {
0183 aResult.Status = Status::InvalidInput;
0184 return aResult;
0185 }
0186
0187 const math_Matrix& aLU = *aLURes.LU;
0188 const math_IntegerVector& aPivot = *aLURes.Pivot;
0189
0190
0191 math_Vector aX = theB;
0192
0193
0194 int aFirstNonZero = 0;
0195 for (int i = aRowLower; i <= aRowUpper; ++i)
0196 {
0197 const int aPivotIdx = aPivot(i);
0198 double aSum = aX(aPivotIdx);
0199 aX(aPivotIdx) = aX(i);
0200
0201 if (aFirstNonZero != 0)
0202 {
0203 for (int j = aFirstNonZero; j < i; ++j)
0204 {
0205 aSum -= aLU(i, j) * aX(j);
0206 }
0207 }
0208 else if (!MathUtils::IsZero(aSum))
0209 {
0210 aFirstNonZero = i;
0211 }
0212 aX(i) = aSum;
0213 }
0214
0215
0216 for (int i = aRowUpper; i >= aRowLower; --i)
0217 {
0218 double aSum = aX(i);
0219 for (int j = i + 1; j <= aRowUpper; ++j)
0220 {
0221 aSum -= aLU(i, j) * aX(j);
0222 }
0223 aX(i) = aSum / aLU(i, i);
0224 }
0225
0226 aResult.Status = Status::OK;
0227 aResult.Solution = aX;
0228 aResult.Determinant = aLURes.Determinant;
0229 return aResult;
0230 }
0231
0232
0233
0234
0235
0236
0237
0238
0239 inline LinearMultipleResult SolveMultiple(const math_Matrix& theA,
0240 const math_Matrix& theB,
0241 double theMinPivot = 1.0e-20)
0242 {
0243 LinearMultipleResult aResult;
0244
0245
0246 LUResult aLURes = LU(theA, theMinPivot);
0247 if (!aLURes.IsDone())
0248 {
0249 aResult.Status = aLURes.Status;
0250 return aResult;
0251 }
0252
0253 const int aRowLower = theA.LowerRow();
0254 const int aRowUpper = theA.UpperRow();
0255
0256
0257 if (theB.LowerRow() != aRowLower || theB.UpperRow() != aRowUpper)
0258 {
0259 aResult.Status = Status::InvalidInput;
0260 return aResult;
0261 }
0262
0263 const math_Matrix& aLU = *aLURes.LU;
0264 const math_IntegerVector& aPivot = *aLURes.Pivot;
0265
0266
0267 math_Matrix aX(aRowLower, aRowUpper, theB.LowerCol(), theB.UpperCol());
0268
0269 for (int col = theB.LowerCol(); col <= theB.UpperCol(); ++col)
0270 {
0271
0272 math_Vector aWork(aRowLower, aRowUpper);
0273 for (int i = aRowLower; i <= aRowUpper; ++i)
0274 {
0275 aWork(i) = theB(i, col);
0276 }
0277
0278
0279 int aFirstNonZero = 0;
0280 for (int i = aRowLower; i <= aRowUpper; ++i)
0281 {
0282 const int aPivotIdx = aPivot(i);
0283 double aSum = aWork(aPivotIdx);
0284 aWork(aPivotIdx) = aWork(i);
0285
0286 if (aFirstNonZero != 0)
0287 {
0288 for (int j = aFirstNonZero; j < i; ++j)
0289 {
0290 aSum -= aLU(i, j) * aWork(j);
0291 }
0292 }
0293 else if (!MathUtils::IsZero(aSum))
0294 {
0295 aFirstNonZero = i;
0296 }
0297 aWork(i) = aSum;
0298 }
0299
0300
0301 for (int i = aRowUpper; i >= aRowLower; --i)
0302 {
0303 double aSum = aWork(i);
0304 for (int j = i + 1; j <= aRowUpper; ++j)
0305 {
0306 aSum -= aLU(i, j) * aWork(j);
0307 }
0308 aWork(i) = aSum / aLU(i, i);
0309 }
0310
0311
0312 for (int i = aRowLower; i <= aRowUpper; ++i)
0313 {
0314 aX(i, col) = aWork(i);
0315 }
0316 }
0317
0318 aResult.Status = Status::OK;
0319 aResult.Determinant = aLURes.Determinant;
0320 aResult.Solutions = aX;
0321 return aResult;
0322 }
0323
0324
0325
0326
0327
0328
0329 inline LinearResult Determinant(const math_Matrix& theA, double theMinPivot = 1.0e-20)
0330 {
0331 LinearResult aResult;
0332
0333 LUResult aLURes = LU(theA, theMinPivot);
0334 if (!aLURes.IsDone())
0335 {
0336 aResult.Status = aLURes.Status;
0337 aResult.Determinant = 0.0;
0338 return aResult;
0339 }
0340
0341 aResult.Status = Status::OK;
0342 aResult.Determinant = aLURes.Determinant;
0343 return aResult;
0344 }
0345
0346
0347
0348
0349
0350
0351 inline InverseResult Invert(const math_Matrix& theA, double theMinPivot = 1.0e-20)
0352 {
0353 InverseResult aResult;
0354
0355
0356 LUResult aLURes = LU(theA, theMinPivot);
0357 if (!aLURes.IsDone())
0358 {
0359 aResult.Status = aLURes.Status;
0360 return aResult;
0361 }
0362
0363 const int aRowLower = theA.LowerRow();
0364 const int aRowUpper = theA.UpperRow();
0365 const int aColLower = theA.LowerCol();
0366 const int aColUpper = theA.UpperCol();
0367
0368 const math_Matrix& aLU = *aLURes.LU;
0369 const math_IntegerVector& aPivot = *aLURes.Pivot;
0370
0371
0372 math_Matrix aInv(aRowLower, aRowUpper, aColLower, aColUpper, 0.0);
0373 math_Vector aCol(aRowLower, aRowUpper);
0374
0375 for (int col = aColLower; col <= aColUpper; ++col)
0376 {
0377
0378 for (int i = aRowLower; i <= aRowUpper; ++i)
0379 {
0380 aCol(i) = 0.0;
0381 }
0382 aCol(col - aColLower + aRowLower) = 1.0;
0383
0384
0385 int aFirstNonZero = 0;
0386 for (int i = aRowLower; i <= aRowUpper; ++i)
0387 {
0388 const int aPivotIdx = aPivot(i);
0389 double aSum = aCol(aPivotIdx);
0390 aCol(aPivotIdx) = aCol(i);
0391
0392 if (aFirstNonZero != 0)
0393 {
0394 for (int j = aFirstNonZero; j < i; ++j)
0395 {
0396 aSum -= aLU(i, j) * aCol(j);
0397 }
0398 }
0399 else if (!MathUtils::IsZero(aSum))
0400 {
0401 aFirstNonZero = i;
0402 }
0403 aCol(i) = aSum;
0404 }
0405
0406
0407 for (int i = aRowUpper; i >= aRowLower; --i)
0408 {
0409 double aSum = aCol(i);
0410 for (int j = i + 1; j <= aRowUpper; ++j)
0411 {
0412 aSum -= aLU(i, j) * aCol(j);
0413 }
0414 aCol(i) = aSum / aLU(i, i);
0415 }
0416
0417
0418 for (int i = aRowLower; i <= aRowUpper; ++i)
0419 {
0420 aInv(i, col) = aCol(i);
0421 }
0422 }
0423
0424 aResult.Status = Status::OK;
0425 aResult.Inverse = aInv;
0426 aResult.Determinant = aLURes.Determinant;
0427 return aResult;
0428 }
0429
0430 }
0431
0432 #endif