File indexing completed on 2024-04-06 12:31:43
0001 #include "RKAdaptiveSolver.h"
0002 #include <cmath>
0003
0004
0005
0006 namespace RKDetails {
0007
0008
0009 inline double fastPow(double a, double b) {
0010 union {
0011 double d;
0012 int x[2];
0013 } u = {a};
0014 u.x[1] = (int)(b * (u.x[1] - 1072632447) + 1072632447);
0015 u.x[0] = 0;
0016 return u.d;
0017 }
0018
0019 }
0020
0021 template <typename T, template <typename, int> class StepWithPrec, int N>
0022 typename RKAdaptiveSolver<T, StepWithPrec, N>::Vector RKAdaptiveSolver<T, StepWithPrec, N>::operator()(
0023 Scalar startPar,
0024 const Vector& startState,
0025 Scalar step,
0026 const RKDerivative<T, N>& deriv,
0027 const RKDistance<T, N>& dist,
0028 float eps) {
0029 using namespace RKDetails;
0030 constexpr float Safety = 0.9;
0031 double remainigStep = step;
0032 double stepSize = step;
0033 Scalar currentPar = startPar;
0034 Vector currentStart = startState;
0035 #ifdef DEBUG_PRINTS
0036 int nsteps = 0;
0037 #endif
0038 std::pair<Vector, Scalar> tryStep;
0039
0040 StepWithPrec<T, N> stepWithAccuracy;
0041
0042 do {
0043 tryStep = stepWithAccuracy(currentPar, currentStart, deriv, dist, stepSize);
0044 float acc = tryStep.second;
0045
0046
0047 #ifdef DEBUG_PRINTS
0048 nsteps++;
0049 #endif
0050 if (acc < eps || std::abs(stepSize) < std::abs(remainigStep) * 0.1f) {
0051 if (std::abs(remainigStep - stepSize) < 0.5f * eps) {
0052 #ifdef DEBUG_PRINTS
0053 std::cout << "Accuracy reached, and full step taken in " << nsteps << " steps" << std::endl;
0054 #endif
0055 return tryStep.first;
0056 } else {
0057 remainigStep -= stepSize;
0058 currentPar += stepSize;
0059
0060
0061 const float cut = std::pow(4.f / Safety, 5.f);
0062
0063 float factor = (eps < cut * acc) ? Safety * fastPow(eps / acc, 0.2) : 4.f;
0064
0065 double absRemainingStep = std::abs(remainigStep);
0066 double absSize = std::min(std::abs(stepSize * factor), absRemainingStep);
0067 if (absSize < 0.05f * absRemainingStep)
0068 absSize = 0.05f * absRemainingStep;
0069 stepSize = std::copysign(absSize, stepSize);
0070 currentStart = tryStep.first;
0071 #ifdef DEBUG_PRINTS
0072 std::cout << "Accuracy reached, but " << remainigStep << " remain after " << nsteps
0073 << " steps. Step size increased by " << factor << " to " << stepSize << std::endl;
0074 #endif
0075 }
0076 } else {
0077
0078 constexpr float cut = Safety * Safety * Safety * Safety * 100 * 100;
0079 float factor = (cut * eps > acc) ?
0080
0081 Safety * fastPow(eps / acc, 0.25)
0082 : 0.1f;
0083 stepSize *= factor;
0084 if (std::abs(stepSize) < 0.05f * std::abs(remainigStep))
0085 stepSize = 0.05f * remainigStep;
0086 #ifdef DEBUG_PRINTS
0087 std::cout << "Accuracy not yet reached: delta = " << tryStep.second << ", step reduced by " << factor << " to "
0088 << stepSize << std::endl;
0089 #endif
0090 }
0091 } while (std::abs(remainigStep) > eps * 0.5f);
0092
0093 return tryStep.first;
0094 }