Advertisement
MrFrAnTA

Simplex

Dec 23rd, 2015
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.45 KB | None | 0 0
  1. #ifndef DBL_MAX
  2.   /*!
  3.    * \brief A macro (constant) for maximal positive double value.
  4.    */
  5.   #define DBL_MAX 1.7976931348623157E+308
  6. #endif
  7.  
  8. #ifndef DBL_NMIN
  9.   /*!
  10.    * \brief A macro (constant) for minimal negative double value.
  11.    */
  12.   #define DBL_NMIN -DBL_MAX
  13. #endif
  14.  
  15.  
  16. struct SegmentData {
  17.   int unixTime; /*!< Time of data measurement (in unix form). */
  18.   double time; /*!< Time of data measurement (in rational form). */
  19.   double blood; /*!< Measured glucose in blood. */
  20.   double ist; /*!< Measured ist - glucose measured under the skin. */
  21. };
  22.  
  23. struct Segment {
  24.   unsigned int id; /*!< Identifier of measured segment. */
  25.   std::vector<SegmentData> data; /*!< Measured segment data. */
  26.   double timeFrom; /*!< Time of segment beginning (in rational form). */
  27.   double timeTo; /*!< Time of segment end (in rational form). */
  28. };
  29.  
  30. struct FilteredSegment : Segment {
  31.   std::vector<SegmentData> filteredData; /*!< Filtered data which contain only data with measured blood and ist. */
  32. };
  33.  
  34.  
  35. static double evaluateFi(Segment& segment, unsigned int dataId, double *params) {
  36.   double t = segment.data[dataId].time;
  37.   double h = params[PARAM_H_INDEX];
  38.  
  39.   // prevent divining by 0
  40.   if (h == 0.0) {
  41.     return DBL_NMIN;
  42.   }
  43.  
  44.   double ist = getIstValueAt(segment, t - h);
  45.   if (ist == DBL_NMIN) {
  46.     return ist; // returns DBL_NMIN
  47.   }
  48.  
  49.   return t + params[PARAM_DT_INDEX] + params[PARAM_K_INDEX] * ((segment.data[dataId].ist - ist) / h);
  50. }
  51.  
  52. static double evaluateBeta(double ist, double *params) {
  53.   return params[PARAM_P_INDEX] - params[PARAM_CG_INDEX] * ist;
  54. }
  55.  
  56. static double evaluateGama(Segment& segment, unsigned int dataId, double *params) {
  57.   double fi = evaluateFi(segment, dataId, params);
  58.   if (fi == DBL_NMIN) {
  59.     return fi; // returns DBL_NMIN
  60.   }
  61.  
  62.   double ist = getIstValueAt(segment, fi);
  63.   if (ist == DBL_NMIN) {
  64.     return ist; // returns DBL_NMIN
  65.   }
  66.  
  67.   return params[PARAM_C_INDEX] - ist;
  68. }
  69.  
  70. static double evaluateD(Segment& segment, unsigned int dataId, double *params) {
  71.   double alpha = params[PARAM_CG_INDEX];
  72.   double beta = evaluateBeta(segment.data[dataId].ist, params);
  73.   double gama = evaluateGama(segment, dataId, params);
  74.   if (gama == DBL_NMIN) {
  75.     return gama; // returns DBL_NMIN
  76.   }
  77.  
  78.   return pow(beta, 2) - 4 * alpha * gama;
  79. }
  80.  
  81. double evaluateTheoreticalBlood(Segment& segment, unsigned int dataId, double *params) {
  82.   double alpha = params[PARAM_CG_INDEX];
  83.   // prevent divining by 0
  84.   if (alpha == 0.0) {
  85.     return DBL_NMIN;
  86.   }
  87.  
  88.   double d = evaluateD(segment, dataId, params);
  89.   if (d < 0) {
  90.     return DBL_NMIN; // minimal double value = unknown value, there is no sense to continue
  91.   }
  92.   if (d == DBL_NMIN) {
  93.     return d; // returns DBL_NMIN
  94.   }
  95.  
  96.   double beta = evaluateBeta(segment.data[dataId].ist, params);
  97.  
  98.   return (-1 * beta + sqrt(d)) / (2 * alpha);
  99. }
  100.  
  101. const Fitness fitness(FilteredSegment& segment, vector<double>& params) {
  102.   Fitness f; // result of fitness function
  103.   f.dataCount = segment.filteredData.size();
  104.  
  105.   double epsilon = 0.0; // summary of relative mistakes e(t) for computed b(t)
  106.   double epsilonSqr = 0.0; // summary of squared e(t) [e(t)^2]
  107.  
  108.   vector<SegmentData> data = segment.filteredData;
  109.   for (size_t i = 0; i < data.size(); i++) {
  110.     double blood = data[i].blood;
  111.     double theoretical = evaluateTheoreticalBlood(segment, i, &params[0]);
  112.     if (theoretical == DBL_NMIN) {
  113.       continue;
  114.     }
  115.  
  116.     //printf("b(t) = %0.5f, blood = %0.5f\n", theoretical, blood);
  117.  
  118.     double e = abs((blood - theoretical) / blood); // e = (x - x0) / x0
  119.     epsilon += e;
  120.     epsilonSqr += pow(e, 2);
  121.     f.calcCount++;
  122.   }
  123.  
  124.   f.epsilon = epsilon / (double)f.calcCount; // average of e(t): x = 1/N * sum(x_i)
  125.   double averageSqr = epsilonSqr / (double)f.calcCount; // average of squared e(t): 1/N * sum(x_i^2)
  126.   f.deviation = sqrt(averageSqr - pow(f.epsilon, 2)); // o = sqrt((1/N * sum(x_i^2)) - x^2)
  127.  
  128.   unsigned int minData = (unsigned int)(getAppConfig().minDataCoef * f.dataCount);
  129.   if (f.calcCount >= minData && f.calcCount > 0) {
  130.     f.fitness = f.epsilon + f.deviation;
  131.   }
  132.   else {
  133.     f.fitness = DBL_MAX;
  134.   }
  135.  
  136.   return f;
  137. }
  138.  
  139. const SimplexResult simplex(Segment& segment, Bounds& bounds) {
  140.   printf("Starting simplex optimalization for segment %d\n", segment.id);
  141.   high_resolution_clock::time_point start = high_resolution_clock::now(); // start timer
  142.  
  143.   const Config appConfig = getAppConfig(); // configuration of application
  144.  
  145.   const double epsilon = appConfig.epsilon * numeric_limits<double>::epsilon(); // termination criteria
  146.   const int iterations = appConfig.iterations;
  147.  
  148.   const int N = PARAMS_COUNT; // N: space dimension
  149.  
  150.   // filters segment
  151.   FilteredSegment fSegment = filterSegment(segment);
  152.  
  153.   // initializes the simplex
  154.   vector<vector<double>> x = vector<vector<double>>(N + 1); // x: the Simplex
  155.   for (size_t i = 0; i < x.size(); i++) {
  156.     for (int j = 0; j < appConfig.initIterations; j++) {
  157.       vector<double> xi = generateParameters(bounds);
  158.       Fitness fi = fitness(fSegment, xi);
  159.       if (fi.fitness != DBL_MAX) {
  160.         x[i] = xi;
  161.         break;
  162.       }
  163.     }
  164.   }
  165.  
  166.   vector<double> xcentroidOld(N, 0); // simplex center * (N+1)
  167.   vector<double> xcentroidNew(N, 0); // simplex center * (N+1)
  168.  
  169.   vector<Fitness> vf(N + 1); // fitness evaluated at simplex vertexes  
  170.  
  171.   size_t x1 = 0;   // x1:   f(x1) = min { f(x1), f(x2)...f(x_{n+1} }
  172.   size_t xn = 0;   // xnp1: f(xnp1) = max { f(x1), f(x2)...f(x_{n+1} }
  173.   size_t xnp1 = 0; // xn:   f(xn)<f(xnp1) && f(xn)> all other f(x_i)        
  174.  
  175.   int it = 0; // iteration step number
  176.   // optimization begins
  177.   for (it = 0; it < iterations; it++) {
  178.     for (int i = 0; i < N + 1; i++) {
  179.       vf[i] = fitness(fSegment, x[i]);
  180.     }
  181.  
  182.     // find index of max, second max, min of vf.
  183.     x1 = 0; xn = 0; xnp1 = 0;
  184.  
  185.     for (size_t i = 0; i < vf.size(); i++) {
  186.       if (vf[i] < vf[x1]) {
  187.         x1 = i;
  188.       }
  189.       if (vf[i] > vf[xnp1]) {
  190.         xnp1 = i;
  191.       }
  192.     }
  193.  
  194.     xn = x1;
  195.  
  196.     for (size_t i = 0; i < vf.size(); i++) {
  197.       if (vf[i]<vf[xnp1] && vf[i]>vf[xn]) {
  198.         xn = i;
  199.       }
  200.     }
  201.  
  202.     // x1, xn, xnp1 are found
  203.  
  204.     vector<double> xg(N, 0); // xg: centroid of the N best vertexes
  205.     for (size_t i = 0; i < x.size(); i++) {
  206.       if (i != xnp1) {
  207.         transform(xg.begin(), xg.end(), x[i].begin(), xg.begin(), plus<double>());
  208.       }
  209.     }
  210.  
  211.     transform(xg.begin(), xg.end(), x[xnp1].begin(), xcentroidNew.begin(), plus<double>());
  212.     transform(xg.begin(), xg.end(), xg.begin(), bind2nd(divides<double>(), N));
  213.     // xg found, xcentroid_new updated
  214.  
  215.     // termination condition
  216.     if (appConfig.epsilonEnabled) {
  217.       double diff = 0; //calculate the difference of the simplex centers see if the difference is less than the termination criteria
  218.       for (int i = 0; i < N; i++) {
  219.         diff += fabs(xcentroidOld[i] - xcentroidNew[i]);
  220.       }
  221.  
  222.       // the final solution cannot have this fitness
  223.       if ((diff / N < epsilon) && vf[x1].fitness != DBL_MAX) {
  224.         break; //terminate the optimizer
  225.       }
  226.     }
  227.  
  228.     xcentroidOld.swap(xcentroidNew); //update simplex center
  229.  
  230.     // reflection:
  231.     vector<double> xr(N, 0);
  232.     for (int i = 0; i < N; i++) {
  233.       xr[i] = xg[i] + A * (xg[i] - x[xnp1][i]);
  234.     }
  235.     // reflection, xr found
  236.  
  237.     parametersCorrection(bounds, xr); // correct parameters
  238.     Fitness fxr = fitness(fSegment, xr); // record function at xr
  239.     if (vf[x1] <= fxr && fxr <= vf[xn]) {
  240.       copy(xr.begin(), xr.end(), x[xnp1].begin());
  241.     }
  242.  
  243.     //expansion:
  244.     else if (fxr < vf[x1]) {
  245.       vector<double> xe(N, 0);
  246.       for (int i = 0; i < N; i++) {
  247.         xe[i] = xr[i] + B * (xr[i] - xg[i]);
  248.       }
  249.  
  250.       parametersCorrection(bounds, xe); // correct parameters
  251.       if (fitness(fSegment, xe) < fxr) {
  252.         copy(xe.begin(), xe.end(), x[xnp1].begin());
  253.       }
  254.       else {
  255.         copy(xr.begin(), xr.end(), x[xnp1].begin());
  256.       }
  257.     }
  258.     // expansion finished, xe is not used outside the scope
  259.  
  260.     // contraction:
  261.     else if (fxr > vf[xn]) {
  262.       vector<double> xc(N, 0);
  263.       for (int i = 0; i < N; i++) {
  264.         xc[i] = xg[i] + G * (x[xnp1][i] - xg[i]);
  265.       }
  266.  
  267.       parametersCorrection(bounds, xc); // correct parameters
  268.       if (fitness(fSegment, xc) < vf[xnp1]) {
  269.         copy(xc.begin(), xc.end(), x[xnp1].begin());
  270.       }
  271.       else {
  272.         for (size_t i = 0; i < x.size(); i++) {
  273.           if (i != x1) {
  274.             for (int j = 0; j < N; j++) {
  275.               x[i][j] = x[x1][j] + H * (x[i][j] - x[x1][j]);
  276.             }
  277.             parametersCorrection(bounds, x[i]); // correct parameters
  278.           }
  279.         }
  280.       }
  281.     } // contraction finished, xc is not used outside the scope
  282.   } // optimization is finished
  283.  
  284.   high_resolution_clock::time_point end = high_resolution_clock::now(); // stop timer
  285.   long long duration = duration_cast<milliseconds>(end - start).count();
  286.  
  287.   if (it == iterations && appConfig.epsilonEnabled) { //max number of iteration achieves before tol is satisfied
  288.     printf("Warning: Iteration limit achieves, result may not be optimal\n");
  289.   }
  290.  
  291.   printf("Found parameters for segment %d in %d iterations [%lld ms]\n", segment.id, it, duration);
  292.   printParametersWithFitness(x[x1], vf[x1], false);
  293.  
  294.   // preparation of result
  295.   SimplexResult result;
  296.   result.segmentId = segment.id;
  297.   result.params = x[x1];
  298.   result.fitness = vf[x1].fitness;
  299.   result.duration = duration;
  300.  
  301.   return result;
  302. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement