File indexing completed on 2026-09-28 09:20:51
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef _MathOpt_Uzawa_HeaderFile
0015 #define _MathOpt_Uzawa_HeaderFile
0016
0017 #include <MathUtils_Types.hxx>
0018 #include <MathUtils_Config.hxx>
0019 #include <math_Vector.hxx>
0020 #include <math_Matrix.hxx>
0021 #include <MathLin_Crout.hxx>
0022
0023 #include <cmath>
0024
0025 namespace MathOpt
0026 {
0027 using namespace MathUtils;
0028
0029
0030 struct UzawaResult
0031 {
0032 MathUtils::Status Status = MathUtils::Status::NotConverged;
0033 std::optional<math_Vector> Solution;
0034 std::optional<math_Vector> Dual;
0035 std::optional<math_Vector> Error;
0036 std::optional<math_Vector> InitialError;
0037 std::optional<math_Matrix> InverseCTC;
0038 int NbIterations = 0;
0039
0040 bool IsDone() const { return Status == MathUtils::Status::OK; }
0041
0042 explicit operator bool() const { return IsDone(); }
0043 };
0044
0045
0046 struct UzawaConfig
0047 {
0048 double EpsLix = 1.0e-6;
0049 double EpsLic = 1.0e-6;
0050 int MaxIterations = 500;
0051 };
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071 inline UzawaResult Uzawa(const math_Matrix& theCont,
0072 const math_Vector& theSecont,
0073 const math_Vector& theStartingPoint,
0074 int theNce,
0075 int theNci,
0076 const UzawaConfig& theConfig = UzawaConfig())
0077 {
0078 UzawaResult aResult;
0079
0080 const int aNlig = theCont.RowNumber();
0081 const int aNcol = theCont.ColNumber();
0082
0083
0084 if (theSecont.Length() != aNlig || (theNce + theNci) != aNlig
0085 || theStartingPoint.Length() != aNcol)
0086 {
0087 aResult.Status = Status::InvalidInput;
0088 return aResult;
0089 }
0090
0091 const int aRowLower = theCont.LowerRow();
0092 const int aColLower = theCont.LowerCol();
0093 const int aSecLower = theSecont.Lower();
0094 const int aXLower = theStartingPoint.Lower();
0095
0096
0097 math_Vector aErrinit(1, aNlig);
0098 for (int i = 1; i <= aNlig; ++i)
0099 {
0100 double aSum = 0.0;
0101 for (int j = 1; j <= aNcol; ++j)
0102 {
0103 aSum += theCont(i + aRowLower - 1, j + aColLower - 1) * theStartingPoint(j + aXLower - 1);
0104 }
0105 aErrinit(i) = aSum - theSecont(i + aSecLower - 1);
0106 }
0107
0108 aResult.InitialError = aErrinit;
0109
0110
0111 math_Vector aVardua(1, aNlig);
0112 math_Vector aErruza(1, aNcol, 0.0);
0113 math_Matrix aCTCinv(1, aNlig, 1, aNlig, 0.0);
0114
0115 if (theNci == 0)
0116 {
0117
0118 aResult.NbIterations = 1;
0119
0120
0121 for (int i = 1; i <= aNlig; ++i)
0122 {
0123 for (int j = 1; j <= i; ++j)
0124 {
0125 double aSum = 0.0;
0126 for (int k = 1; k <= aNcol; ++k)
0127 {
0128 aSum += theCont(i + aRowLower - 1, k + aColLower - 1)
0129 * theCont(j + aRowLower - 1, k + aColLower - 1);
0130 }
0131 aCTCinv(i, j) = aSum;
0132 if (i != j)
0133 {
0134 aCTCinv(j, i) = aSum;
0135 }
0136 }
0137 }
0138
0139
0140 MathLin::InverseResult aInvResult = MathLin::InvertCrout(aCTCinv);
0141 if (!aInvResult.IsDone())
0142 {
0143 aResult.Status = Status::Singular;
0144 return aResult;
0145 }
0146 aCTCinv = *aInvResult.Inverse;
0147
0148
0149 for (int i = 1; i <= aNlig; ++i)
0150 {
0151 double aSum = 0.0;
0152 for (int j = 1; j <= aNlig; ++j)
0153 {
0154 aSum += aCTCinv(i, j) * aErrinit(j);
0155 }
0156 aVardua(i) = aSum;
0157 }
0158
0159
0160 for (int i = 1; i <= aNcol; ++i)
0161 {
0162 double aSum = 0.0;
0163 for (int j = 1; j <= aNlig; ++j)
0164 {
0165 aSum -= theCont(j + aRowLower - 1, i + aColLower - 1) * aVardua(j);
0166 }
0167 aErruza(i) = aSum;
0168 }
0169
0170
0171 math_Vector aResul(1, aNcol);
0172 for (int i = 1; i <= aNcol; ++i)
0173 {
0174 aResul(i) = theStartingPoint(i + aXLower - 1) + aErruza(i);
0175 }
0176
0177 aResult.Solution = aResul;
0178 aResult.Dual = aVardua;
0179 aResult.Error = aErruza;
0180 aResult.InverseCTC = aCTCinv;
0181 aResult.Status = Status::OK;
0182 return aResult;
0183 }
0184
0185
0186
0187 for (int i = 1; i <= aNlig; ++i)
0188 {
0189 aVardua(i) = (i <= theNce) ? 0.0 : 1.0;
0190 }
0191
0192
0193 double aNormat = 0.0;
0194 for (int i = 1; i <= aNlig; ++i)
0195 {
0196 double aNormli = 0.0;
0197 for (int j = 1; j <= aNcol; ++j)
0198 {
0199 double aVal = theCont(i + aRowLower - 1, j + aColLower - 1);
0200 aNormli += aVal * aVal;
0201 }
0202 aNormat += aNormli;
0203 }
0204 const double aRho = 1.0 / (std::sqrt(2.0) * aNormat);
0205
0206
0207 for (int anIter = 1; anIter <= theConfig.MaxIterations; ++anIter)
0208 {
0209 aResult.NbIterations = anIter;
0210
0211 double aXmax = 0.0;
0212
0213
0214 for (int i = 1; i <= aNcol; ++i)
0215 {
0216 double aXprev = aErruza(i);
0217 double aSum = 0.0;
0218 for (int j = 1; j <= aNlig; ++j)
0219 {
0220 aSum -= theCont(j + aRowLower - 1, i + aColLower - 1) * aVardua(j);
0221 }
0222 aErruza(i) = aSum;
0223
0224 if (anIter > 1)
0225 {
0226 aXmax = std::max(aXmax, std::abs(aErruza(i) - aXprev));
0227 }
0228 }
0229
0230
0231 double aErrMax = 0.0;
0232 for (int i = 1; i <= aNlig; ++i)
0233 {
0234
0235 double aErr = aErrinit(i);
0236 for (int j = 1; j <= aNcol; ++j)
0237 {
0238 aErr += theCont(i + aRowLower - 1, j + aColLower - 1) * aErruza(j);
0239 }
0240
0241 double aErr1;
0242 if (i <= theNce)
0243 {
0244
0245 aVardua(i) += aRho * aErr;
0246 aErr1 = std::abs(aRho * aErr);
0247 }
0248 else
0249 {
0250
0251 double aXmuPrev = aVardua(i);
0252 aVardua(i) = std::max(0.0, aVardua(i) + aRho * aErr);
0253 aErr1 = std::abs(aVardua(i) - aXmuPrev);
0254 }
0255 aErrMax = std::max(aErrMax, aErr1);
0256 }
0257
0258
0259 if (anIter > 1)
0260 {
0261 if (aXmax <= theConfig.EpsLix)
0262 {
0263 if (aErrMax <= theConfig.EpsLic)
0264 {
0265
0266 math_Vector aResul(1, aNcol);
0267 for (int i = 1; i <= aNcol; ++i)
0268 {
0269 aResul(i) = theStartingPoint(i + aXLower - 1) + aErruza(i);
0270 }
0271
0272 aResult.Solution = aResul;
0273 aResult.Dual = aVardua;
0274 aResult.Error = aErruza;
0275 aResult.Status = Status::OK;
0276 return aResult;
0277 }
0278 else
0279 {
0280
0281 aResult.Status = Status::NotConverged;
0282 return aResult;
0283 }
0284 }
0285 }
0286 }
0287
0288 aResult.Status = Status::MaxIterations;
0289 return aResult;
0290 }
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301 inline UzawaResult UzawaEquality(const math_Matrix& theCont,
0302 const math_Vector& theSecont,
0303 const math_Vector& theStartingPoint,
0304 const UzawaConfig& theConfig = UzawaConfig())
0305 {
0306 return Uzawa(theCont, theSecont, theStartingPoint, theCont.RowNumber(), 0, theConfig);
0307 }
0308
0309 }
0310
0311 #endif