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_Crout_HeaderFile
0015 #define _MathLin_Crout_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
0023 #include <cmath>
0024
0025 namespace MathLin
0026 {
0027 using namespace MathUtils;
0028
0029
0030
0031 struct CroutResult
0032 {
0033 MathUtils::Status Status = MathUtils::Status::NotConverged;
0034 std::optional<math_Matrix> L;
0035 std::optional<math_Vector> D;
0036 std::optional<math_Matrix> Inverse;
0037 std::optional<double> Determinant;
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
0052
0053
0054
0055
0056
0057
0058
0059 inline CroutResult Crout(const math_Matrix& theA, double theMinPivot = 1.0e-20)
0060 {
0061 CroutResult 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 aN = aRowUpper - aRowLower + 1;
0068
0069
0070 if (aN != aColUpper - aColLower + 1)
0071 {
0072 aResult.Status = Status::InvalidInput;
0073 return aResult;
0074 }
0075
0076
0077 math_Matrix aL(1, aN, 1, aN, 0.0);
0078 math_Vector aDiag(1, aN);
0079
0080 double aDet = 1.0;
0081
0082
0083 for (int i = 1; i <= aN; ++i)
0084 {
0085
0086 for (int j = 1; j <= i - 1; ++j)
0087 {
0088 double aScale = 0.0;
0089 for (int k = 1; k <= j - 1; ++k)
0090 {
0091 aScale += aL(i, k) * aL(j, k) * aDiag(k);
0092 }
0093 aL(i, j) = (theA(i + aRowLower - 1, j + aColLower - 1) - aScale) / aDiag(j);
0094 }
0095
0096
0097 double aScale = 0.0;
0098 for (int k = 1; k <= i - 1; ++k)
0099 {
0100 aScale += aL(i, k) * aL(i, k) * aDiag(k);
0101 }
0102 aDiag(i) = theA(i + aRowLower - 1, i + aColLower - 1) - aScale;
0103 aDet *= aDiag(i);
0104
0105
0106 if (std::abs(aDiag(i)) <= theMinPivot)
0107 {
0108 aResult.Status = Status::Singular;
0109 return aResult;
0110 }
0111
0112 aL(i, i) = 1.0;
0113 }
0114
0115
0116 aL(1, 1) = 1.0 / aL(1, 1);
0117 for (int i = 2; i <= aN; ++i)
0118 {
0119 for (int k = 1; k <= i - 1; ++k)
0120 {
0121 double aScale = 0.0;
0122 for (int j = k; j <= i - 1; ++j)
0123 {
0124 aScale += aL(i, j) * aL(j, k);
0125 }
0126 aL(i, k) = -aScale / aL(i, i);
0127 }
0128 aL(i, i) = 1.0 / aL(i, i);
0129 }
0130
0131
0132 math_Matrix aInv(1, aN, 1, aN, 0.0);
0133 for (int j = 1; j <= aN; ++j)
0134 {
0135 double aScale = aL(j, j) * aL(j, j) / aDiag(j);
0136 for (int k = j + 1; k <= aN; ++k)
0137 {
0138 aScale += aL(k, j) * aL(k, j) / aDiag(k);
0139 }
0140 aInv(j, j) = aScale;
0141
0142 for (int i = j + 1; i <= aN; ++i)
0143 {
0144 aScale = aL(i, j) * aL(i, i) / aDiag(i);
0145 for (int k = i + 1; k <= aN; ++k)
0146 {
0147 aScale += aL(k, j) * aL(k, i) / aDiag(k);
0148 }
0149 aInv(i, j) = aScale;
0150 }
0151 }
0152
0153
0154 aResult.L = math_Matrix(aRowLower, aRowUpper, aColLower, aColUpper, 0.0);
0155 for (int i = 1; i <= aN; ++i)
0156 {
0157 for (int j = 1; j <= i; ++j)
0158 {
0159 (*aResult.L)(i + aRowLower - 1, j + aColLower - 1) = aL(i, j);
0160 }
0161 }
0162
0163 aResult.D = math_Vector(aRowLower, aRowUpper);
0164 for (int i = 1; i <= aN; ++i)
0165 {
0166 (*aResult.D)(i + aRowLower - 1) = aDiag(i);
0167 }
0168
0169 aResult.Inverse = math_Matrix(aRowLower, aRowUpper, aColLower, aColUpper, 0.0);
0170 for (int i = 1; i <= aN; ++i)
0171 {
0172 for (int j = 1; j <= i; ++j)
0173 {
0174 (*aResult.Inverse)(i + aRowLower - 1, j + aColLower - 1) = aInv(i, j);
0175 }
0176
0177 for (int j = i + 1; j <= aN; ++j)
0178 {
0179 (*aResult.Inverse)(i + aRowLower - 1, j + aColLower - 1) = aInv(j, i);
0180 }
0181 }
0182
0183 aResult.Determinant = aDet;
0184 aResult.Status = Status::OK;
0185 return aResult;
0186 }
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197 inline LinearResult SolveCrout(const math_Matrix& theA,
0198 const math_Vector& theB,
0199 double theMinPivot = 1.0e-20)
0200 {
0201 LinearResult aResult;
0202
0203
0204 CroutResult aCrout = Crout(theA, theMinPivot);
0205 if (!aCrout.IsDone())
0206 {
0207 aResult.Status = aCrout.Status;
0208 return aResult;
0209 }
0210
0211 const int aRowLower = theA.LowerRow();
0212 const int aRowUpper = theA.UpperRow();
0213 const int aN = aRowUpper - aRowLower + 1;
0214
0215
0216 if (theB.Length() != aN)
0217 {
0218 aResult.Status = Status::InvalidInput;
0219 return aResult;
0220 }
0221
0222 const math_Matrix& aInv = *aCrout.Inverse;
0223 const int aBLower = theB.Lower();
0224
0225
0226 aResult.Solution = math_Vector(aRowLower, aRowUpper, 0.0);
0227 for (int i = 1; i <= aN; ++i)
0228 {
0229 double aSum = aInv(i + aRowLower - 1, 1 + aRowLower - 1) * theB(1 + aBLower - 1);
0230 for (int j = 2; j <= i; ++j)
0231 {
0232 aSum += aInv(i + aRowLower - 1, j + aRowLower - 1) * theB(j + aBLower - 1);
0233 }
0234 for (int j = i + 1; j <= aN; ++j)
0235 {
0236 aSum += aInv(j + aRowLower - 1, i + aRowLower - 1) * theB(j + aBLower - 1);
0237 }
0238 (*aResult.Solution)(i + aRowLower - 1) = aSum;
0239 }
0240
0241 aResult.Determinant = aCrout.Determinant;
0242 aResult.Status = Status::OK;
0243 return aResult;
0244 }
0245
0246
0247
0248
0249
0250
0251 inline InverseResult InvertCrout(const math_Matrix& theA, double theMinPivot = 1.0e-20)
0252 {
0253 InverseResult aResult;
0254
0255 CroutResult aCrout = Crout(theA, theMinPivot);
0256 if (!aCrout.IsDone())
0257 {
0258 aResult.Status = aCrout.Status;
0259 return aResult;
0260 }
0261
0262 aResult.Status = Status::OK;
0263 aResult.Inverse = aCrout.Inverse;
0264 aResult.Determinant = aCrout.Determinant;
0265 return aResult;
0266 }
0267
0268 }
0269
0270 #endif