File indexing completed on 2025-09-15 08:59:24
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #include <cfloat>
0032 #include <iostream>
0033 #include <numeric>
0034
0035 template <class T>
0036 void G4SimplexDownhill<T>::init()
0037 {
0038 alpha = 2.0;
0039 beta = 0.5;
0040 gamma = 2.0;
0041
0042 maximum_no_trial = 10000;
0043 max_se = FLT_MIN;
0044
0045 max_ratio = DBL_EPSILON / 1;
0046 minimized = false;
0047 }
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 template <class T>
0062 G4double G4SimplexDownhill<T>::GetMinimum()
0063 {
0064 initialize();
0065
0066
0067
0068
0069 doDownhill();
0070
0071
0072 auto it_minh = std::min_element(currentHeights.cbegin(), currentHeights.cend());
0073 G4int imin = 0;
0074 G4int i = 0;
0075 for(auto it = currentHeights.cbegin(); it != currentHeights.cend(); ++it)
0076 {
0077 if(it == it_minh)
0078 {
0079 imin = i;
0080 }
0081 ++i;
0082 }
0083 minimumPoint = currentSimplex[imin];
0084
0085
0086
0087
0088 initialize();
0089
0090 currentSimplex[numberOfVariable] = minimumPoint;
0091
0092
0093 doDownhill();
0094
0095
0096 G4double sum =
0097 std::accumulate(currentHeights.begin(), currentHeights.end(), 0.0);
0098 G4double average = sum / (numberOfVariable + 1);
0099 G4double minimum = average;
0100
0101 minimized = true;
0102
0103 return minimum;
0104 }
0105
0106 template <class T>
0107 void G4SimplexDownhill<T>::initialize()
0108 {
0109 currentSimplex.resize(numberOfVariable + 1);
0110 currentHeights.resize(numberOfVariable + 1);
0111
0112 for(G4int i = 0; i < numberOfVariable; ++i)
0113 {
0114 std::vector<G4double> avec(numberOfVariable, 0.0);
0115 avec[i] = 1.0;
0116 currentSimplex[i] = std::move(avec);
0117 }
0118
0119
0120 std::vector<G4double> avec(numberOfVariable, 1);
0121 currentSimplex[numberOfVariable] = std::move(avec);
0122 }
0123
0124 template <class T>
0125 void G4SimplexDownhill<T>::calHeights()
0126 {
0127 for(G4int i = 0; i <= numberOfVariable; ++i)
0128 {
0129 currentHeights[i] = getValue(currentSimplex[i]);
0130 }
0131 }
0132
0133 template <class T>
0134 std::vector<G4double> G4SimplexDownhill<T>::calCentroid(G4int ih)
0135 {
0136 std::vector<G4double> centroid(numberOfVariable, 0.0);
0137
0138 G4int i = 0;
0139 for(const auto & it : currentSimplex)
0140 {
0141 if(i != ih)
0142 {
0143 for(G4int j = 0; j < numberOfVariable; ++j)
0144 {
0145 centroid[j] += it[j] / numberOfVariable;
0146 }
0147 }
0148 ++i;
0149 }
0150
0151 return centroid;
0152 }
0153
0154 template <class T>
0155 std::vector<G4double> G4SimplexDownhill<T>::getReflectionPoint(
0156 std::vector<G4double> p, std::vector<G4double> centroid)
0157 {
0158
0159
0160 std::vector<G4double> reflectionP(numberOfVariable, 0.0);
0161
0162 for(G4int i = 0; i < numberOfVariable; ++i)
0163 {
0164 reflectionP[i] = (1 + alpha) * centroid[i] - alpha * p[i];
0165 }
0166
0167 return reflectionP;
0168 }
0169
0170 template <class T>
0171 std::vector<G4double> G4SimplexDownhill<T>::getExpansionPoint(
0172 std::vector<G4double> p, std::vector<G4double> centroid)
0173 {
0174
0175
0176 std::vector<G4double> expansionP(numberOfVariable, 0.0);
0177
0178 for(G4int i = 0; i < numberOfVariable; ++i)
0179 {
0180 expansionP[i] = (1 - gamma) * centroid[i] + gamma * p[i];
0181 }
0182
0183 return expansionP;
0184 }
0185
0186 template <class T>
0187 std::vector<G4double> G4SimplexDownhill<T>::getContractionPoint(
0188 std::vector<G4double> p, std::vector<G4double> centroid)
0189 {
0190 std::vector<G4double> contractionP(numberOfVariable, 0.0);
0191
0192 for(G4int i = 0; i < numberOfVariable; ++i)
0193 {
0194 contractionP[i] = (1 - beta) * centroid[i] + beta * p[i];
0195 }
0196
0197 return contractionP;
0198 }
0199
0200 template <class T>
0201 G4bool G4SimplexDownhill<T>::isItGoodEnough()
0202 {
0203 G4double sum =
0204 std::accumulate(currentHeights.begin(), currentHeights.end(), 0.0);
0205 G4double average = sum / (numberOfVariable + 1);
0206
0207 G4double delta = 0.0;
0208 for(G4int i = 0; i <= numberOfVariable; ++i)
0209 {
0210 delta += std::abs(currentHeights[i] - average);
0211 }
0212
0213 G4bool result = false;
0214 if (average > 0.0)
0215 {
0216 result = ((delta / (numberOfVariable + 1) / average) < max_ratio);
0217 }
0218 return result;
0219 }
0220
0221 template <class T>
0222 void G4SimplexDownhill<T>::doDownhill()
0223 {
0224 G4int nth_trial = 0;
0225
0226 while(nth_trial < maximum_no_trial)
0227 {
0228 calHeights();
0229
0230 if(isItGoodEnough())
0231 {
0232 break;
0233 }
0234
0235 auto it_maxh = std::max_element(currentHeights.cbegin(), currentHeights.cend());
0236 auto it_minh = std::min_element(currentHeights.cbegin(), currentHeights.cend());
0237
0238 G4double h_H = *it_maxh;
0239 G4double h_L = *it_minh;
0240
0241 G4int ih = 0;
0242 G4int il = 0;
0243 G4double h_H2 = 0.0;
0244 G4int i = 0;
0245 for(auto it = currentHeights.cbegin(); it != currentHeights.cend(); ++it)
0246 {
0247 if(it == it_maxh)
0248 {
0249 ih = i;
0250 }
0251 else
0252 {
0253 h_H2 = std::max(h_H2, *it);
0254 }
0255
0256 if(it == it_minh)
0257 {
0258 il = i;
0259 }
0260 ++i;
0261 }
0262
0263 std::vector<G4double> centroidPoint = calCentroid(ih);
0264
0265
0266 std::vector<G4double> reflectionPoint =
0267 getReflectionPoint(currentSimplex[ih], centroidPoint);
0268
0269 G4double h = getValue(reflectionPoint);
0270
0271 if(h <= h_L)
0272 {
0273
0274 std::vector<G4double> expansionPoint =
0275 getExpansionPoint(reflectionPoint, std::move(centroidPoint));
0276 G4double hh = getValue(expansionPoint);
0277
0278 if(hh <= h_L)
0279 {
0280
0281 currentSimplex[ih] = std::move(expansionPoint);
0282
0283 }
0284 else
0285 {
0286
0287 currentSimplex[ih] = std::move(reflectionPoint);
0288
0289 }
0290 }
0291 else
0292 {
0293 if(h <= h_H2)
0294 {
0295
0296 currentSimplex[ih] = std::move(reflectionPoint);
0297
0298 }
0299 else
0300 {
0301 if(h <= h_H)
0302 {
0303
0304 currentSimplex[ih] = std::move(reflectionPoint);
0305
0306 }
0307
0308 std::vector<G4double> contractionPoint =
0309 getContractionPoint(currentSimplex[ih], std::move(centroidPoint));
0310 G4double hh = getValue(contractionPoint);
0311 if(hh <= h_H)
0312 {
0313
0314 currentSimplex[ih] = std::move(contractionPoint);
0315
0316 }
0317 else
0318 {
0319
0320 for(G4int j = 0; j <= numberOfVariable; ++j)
0321 {
0322 std::vector<G4double> vec(numberOfVariable, 0.0);
0323 for(G4int k = 0; k < numberOfVariable; ++k)
0324 {
0325 vec[k] = (currentSimplex[j][k] + currentSimplex[il][k]) / 2.0;
0326 }
0327 currentSimplex[j] = std::move(vec);
0328 }
0329 }
0330 }
0331 }
0332
0333 ++nth_trial;
0334 }
0335 }
0336
0337 template <class T>
0338 std::vector<G4double> G4SimplexDownhill<T>::GetMinimumPoint()
0339 {
0340 if(!minimized)
0341 {
0342 GetMinimum();
0343 }
0344
0345 auto it_minh = std::min_element(currentHeights.cbegin(), currentHeights.cend());
0346
0347 G4int imin = 0;
0348 G4int i = 0;
0349 for(auto it = currentHeights.cbegin(); it != currentHeights.cend(); ++it)
0350 {
0351 if(it == it_minh)
0352 {
0353 imin = i;
0354 }
0355 ++i;
0356 }
0357 minimumPoint = currentSimplex[imin];
0358
0359 return minimumPoint;
0360 }