File indexing completed on 2025-01-18 09:59:05
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] = avec;
0117 }
0118
0119
0120 std::vector<G4double> avec(numberOfVariable, 1);
0121 currentSimplex[numberOfVariable] = 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 G4bool result = false;
0204
0205 G4double sum =
0206 std::accumulate(currentHeights.begin(), currentHeights.end(), 0.0);
0207 G4double average = sum / (numberOfVariable + 1);
0208
0209 G4double delta = 0.0;
0210 for(G4int i = 0; i <= numberOfVariable; ++i)
0211 {
0212 delta += std::abs(currentHeights[i] - average);
0213 }
0214
0215 if(delta / (numberOfVariable + 1) / average < max_ratio)
0216 {
0217 result = true;
0218 }
0219
0220 return result;
0221 }
0222
0223 template <class T>
0224 void G4SimplexDownhill<T>::doDownhill()
0225 {
0226 G4int nth_trial = 0;
0227
0228 while(nth_trial < maximum_no_trial)
0229 {
0230 calHeights();
0231
0232 if(isItGoodEnough())
0233 {
0234 break;
0235 }
0236
0237 auto it_maxh = std::max_element(currentHeights.cbegin(), currentHeights.cend());
0238 auto it_minh = std::min_element(currentHeights.cbegin(), currentHeights.cend());
0239
0240 G4double h_H = *it_maxh;
0241 G4double h_L = *it_minh;
0242
0243 G4int ih = 0;
0244 G4int il = 0;
0245 G4double h_H2 = 0.0;
0246 G4int i = 0;
0247 for(auto it = currentHeights.cbegin(); it != currentHeights.cend(); ++it)
0248 {
0249 if(it == it_maxh)
0250 {
0251 ih = i;
0252 }
0253 else
0254 {
0255 h_H2 = std::max(h_H2, *it);
0256 }
0257
0258 if(it == it_minh)
0259 {
0260 il = i;
0261 }
0262 ++i;
0263 }
0264
0265 std::vector<G4double> centroidPoint = calCentroid(ih);
0266
0267
0268 std::vector<G4double> reflectionPoint =
0269 getReflectionPoint(currentSimplex[ih], centroidPoint);
0270
0271 G4double h = getValue(reflectionPoint);
0272
0273 if(h <= h_L)
0274 {
0275
0276 std::vector<G4double> expansionPoint =
0277 getExpansionPoint(reflectionPoint, centroidPoint);
0278 G4double hh = getValue(expansionPoint);
0279
0280 if(hh <= h_L)
0281 {
0282
0283 currentSimplex[ih] = expansionPoint;
0284
0285 }
0286 else
0287 {
0288
0289 currentSimplex[ih] = reflectionPoint;
0290
0291 }
0292 }
0293 else
0294 {
0295 if(h <= h_H2)
0296 {
0297
0298 currentSimplex[ih] = reflectionPoint;
0299
0300 }
0301 else
0302 {
0303 if(h <= h_H)
0304 {
0305
0306 currentSimplex[ih] = reflectionPoint;
0307
0308 }
0309
0310 std::vector<G4double> contractionPoint =
0311 getContractionPoint(currentSimplex[ih], centroidPoint);
0312 G4double hh = getValue(contractionPoint);
0313 if(hh <= h_H)
0314 {
0315
0316 currentSimplex[ih] = contractionPoint;
0317
0318 }
0319 else
0320 {
0321
0322 for(G4int j = 0; j <= numberOfVariable; ++j)
0323 {
0324 std::vector<G4double> vec(numberOfVariable, 0.0);
0325 for(G4int k = 0; k < numberOfVariable; ++k)
0326 {
0327 vec[k] = (currentSimplex[j][k] + currentSimplex[il][k]) / 2.0;
0328 }
0329 currentSimplex[j] = vec;
0330 }
0331 }
0332 }
0333 }
0334
0335 ++nth_trial;
0336 }
0337 }
0338
0339 template <class T>
0340 std::vector<G4double> G4SimplexDownhill<T>::GetMinimumPoint()
0341 {
0342 if(!minimized)
0343 {
0344 GetMinimum();
0345 }
0346
0347 auto it_minh = std::min_element(currentHeights.cbegin(), currentHeights.cend());
0348
0349 G4int imin = 0;
0350 G4int i = 0;
0351 for(auto it = currentHeights.cbegin(); it != currentHeights.cend(); ++it)
0352 {
0353 if(it == it_minh)
0354 {
0355 imin = i;
0356 }
0357 ++i;
0358 }
0359 minimumPoint = currentSimplex[imin];
0360
0361 return minimumPoint;
0362 }