Belle II Software  release-05-01-25
minimizer.h
1 /**************************************************************************
2  * BASF2 (Belle Analysis Framework 2) *
3  * Copyright(C) 2021 - Belle II Collaboration *
4  * *
5  * Robust 2D minimizer using grid search *
6  * Used for function with steps in derivatives *
7  * *
8  * Author: The Belle II Collaboration *
9  * Contributors: Radek Zlebcik *
10  * *
11  * This software is provided "as is" without any warranty. *
12  **************************************************************************/
13 
14 #pragma once
15 
16 #include <vector>
17 #include <functional>
18 #include <cmath>
19 #include <utility>
20 #include <iostream>
21 
22 
23 
25 inline std::pair<double, double> getMinima(std::vector<std::vector<double>> vals, int i0, int j0)
26 {
27  int N = vals.size();
28  int Nzoom = (N + 1) / 2;
29 
30 
31  double minIn = 1e50;
32  double minOut = 1e50;
33 
34  for (int i = 0; i < N; ++i)
35  for (int j = 0; j < N; ++j) {
36  if ((i0 <= i && i < i0 + Nzoom) &&
37  (j0 <= j && j < j0 + Nzoom))
38  minIn = std::min(minIn, vals[i][j]);
39  else
40  minOut = std::min(minOut, vals[i][j]);
41  }
42  return {minIn, minOut};
43 }
44 
46 inline std::vector<double> getMinimum(std::function<double(double, double)> fun, double xMin, double xMax, double yMin, double yMax)
47 {
48  const int N = 17; //the grid has size N x N
49  const int Nzoom = (N + 1) / 2; // the size of the zoomed rectangle where minimum is
50 
51 
52  const int kMax = 35; //number of iterations
53 
54  std::vector<std::vector<double>> vals(N);
55  for (auto& v : vals) v.resize(N);
56 
57  for (int k = 0; k < kMax; ++k) {
58 
59  // get values of the function
60  for (int i = 0; i < N; ++i)
61  for (int j = 0; j < N; ++j) {
62  double x = xMin + i * (xMax - xMin) / (N - 1.);
63  double y = yMin + j * (yMax - yMin) / (N - 1.);
64  vals[i][j] = fun(x, y);
65  }
66 
67  if (k == kMax - 1) break;
68 
69  double mOutMax = -1e50;
70  int iOpt = -1, jOpt = -1;
71  //find optimal rectangle
72  for (int i = 0; i < N - Nzoom; ++i)
73  for (int j = 0; j < N - Nzoom; ++j) {
74  double mIn, mOut;
75  std::tie(mIn, mOut) = getMinima(vals, i, j);
76 
77  if (mOut > mOutMax) {
78  mOutMax = mOut;
79  iOpt = i;
80  jOpt = j;
81  }
82  }
83 
84  //Zoom to the optimal rectangle
85  // get values of the function
86 
87  double xMinNow = xMin + iOpt * (xMax - xMin) / (N - 1.);
88  double xMaxNow = xMin + (iOpt + Nzoom - 1) * (xMax - xMin) / (N - 1.);
89 
90  double yMinNow = yMin + jOpt * (yMax - yMin) / (N - 1.);
91  double yMaxNow = yMin + (jOpt + Nzoom - 1) * (yMax - yMin) / (N - 1.);
92 
93  xMin = xMinNow;
94  xMax = xMaxNow;
95  yMin = yMinNow;
96  yMax = yMaxNow;
97 
98  }
99 
100 
101  //get the overall minimum
102  double minTot = 1e50;
103  int iOpt = -1, jOpt = -1;
104 
105  for (int i = 0; i < N; ++i)
106  for (int j = 0; j < N; ++j) {
107  if (vals[i][j] < minTot) {
108  minTot = vals[i][j];
109  iOpt = i;
110  jOpt = j;
111  }
112  }
113 
114  double xMinNow = xMin + iOpt * (xMax - xMin) / (N - 1.);
115  double yMinNow = yMin + jOpt * (yMax - yMin) / (N - 1.);
116 
117  return {xMinNow, yMinNow};
118 }
119