Tomato
OxFitterAmoebaNr2.h
Go to the documentation of this file.
1 
7 #ifndef Tomato_OXFITTERAMOEBANr2_H
8 #define Tomato_OXFITTERAMOEBANr2_H
9 
10 #include "CmakeConfigForTomato.h"
11 #ifdef USE_NR2
12 
13 #include "OxFitter.h"
14 
15 extern "C"{
16 #include "nr_modified.h"
17 #include "nrutil.h"
18 };
19 
20 
21 namespace Ox {
22 
23  namespace Ugly {
24  /*****************/
26  /*****************/
27  // if you want to increase it beyond, you have to add more lines
28  const int NR_MAX_THREADS = 8;
29 
30  // Numerical Recipes Amoeba needs a pointer to a function to be passed with just one argument - minimization
31  // parameters. We need some more
32  // solution taken from https://isocpp.org/wiki/faq/pointers-to-members
33  // it needs declaring globals, so I am using an arrays to have separate global for each thread
34 
35  // static because https://stackoverflow.com/questions/14425262/why-include-guards-do-not-prevent-multiple-function-definitions
36 
37  // global array of pointers to OxFunctorT1adapterNr3
38  static Model<float> *globalFunctonsT1Nr2Array[NR_MAX_THREADS]; // could possibly go up to ITK_MAX_THREADS
39 
40  // global wrapper functions. Exactly as in https://isocpp.org/wiki/faq/pointers-to-members
41  static float f_wrapper0(float *params) { return globalFunctonsT1Nr2Array[0]->calcCostValue(params+1); }
42  static float f_wrapper1(float *params) { return globalFunctonsT1Nr2Array[1]->calcCostValue(params+1); }
43  static float f_wrapper2(float *params) { return globalFunctonsT1Nr2Array[2]->calcCostValue(params+1); }
44  static float f_wrapper3(float *params) { return globalFunctonsT1Nr2Array[3]->calcCostValue(params+1); }
45  static float f_wrapper4(float *params) { return globalFunctonsT1Nr2Array[4]->calcCostValue(params+1); }
46  static float f_wrapper5(float *params) { return globalFunctonsT1Nr2Array[5]->calcCostValue(params+1); }
47  static float f_wrapper6(float *params) { return globalFunctonsT1Nr2Array[6]->calcCostValue(params+1); }
48  static float f_wrapper7(float *params) { return globalFunctonsT1Nr2Array[7]->calcCostValue(params+1); }
49 
50  // for convenience I put the wrapper functions into an array
51  static float (*f_wrapperArray[NR_MAX_THREADS])(float *params) = {
52  f_wrapper0,
53  f_wrapper1,
54  f_wrapper2,
55  f_wrapper3,
56  f_wrapper4,
57  f_wrapper5,
58  f_wrapper6,
59  f_wrapper7,
60  };
61  }
62 
71  template<typename MeasureType>
72  class FitterAmoebaNr2 : public Fitter<MeasureType> {
73 
74  public:
75 
80  virtual Fitter<MeasureType> *newByCloning() { return new FitterAmoebaNr2<MeasureType>(*this); }
81 
82 
83  int performFitting() {
84 
85  // from now on everything depends on the thread we are currently using
86  int threadId = this->_ThreadId;
87  if (threadId < 0 || threadId >= Ugly::NR_MAX_THREADS){
88  throw std::runtime_error("Incorrect threadID");
89  }
90 
91  // use global ugliness
92  Ugly::globalFunctonsT1Nr2Array[threadId] = this->_Model;
93  float(*func)(float*) = Ugly::f_wrapperArray[threadId];
94  int nDims = this->_Model->getNDims();
95 
96  // store start point
97  float *startPoint = new float[nDims];
98  KWUtil::copyArrayToArray(nDims, startPoint, this->getParameters());
99 
100 
101  // modified NR example code
102  int MP = nDims + 1;
103  int NP = nDims;
104  float FTOL = this->getFTolerance();
105 
106  int i, nfunc, j, ndim = NP;
107  float *x, *y, **p;
108 
109  // alloc
110  x = vector(1, NP);
111  y = vector(1, MP);
112  p = matrix(1, MP, 1, NP);
113 
114  // init the simples
115  for (i = 1; i <= MP; i++) {
116  for (j = 1; j <= NP; j++)
117  if (i != j+1)
118  x[j] = p[i][j] = startPoint[j-1];
119  else
120  x[j] = p[i][j] = startPoint[j-1] * 1.4;
121  y[i] = func(x);
122  }
123 
124  // printing
125  if (this->_Verbose) {
126  printf("\n%3s %10s %12s %12s %14s\n\n",
127  "i", "x[i]", "y[i]", "z[i]", "function");
128  for (i = 1; i <= MP; i++) {
129  printf("%3d ", i);
130  for (j = 1; j <= NP; j++) printf("%12.6f ", p[i][j]);
131  printf("%12.6f\n", y[i]);
132  }
133  }
134 
135  // minimise
136  amoeba(p, y, ndim, FTOL, func, &nfunc);
137 
138  // copy results
139  this->copyToParameters(p[1]+1);
140 
141  // printing
142  if (this->_Verbose) {
143  printf("\nNumber of function evaluations: %3d\n", nfunc);
144  printf("Vertices of final 3-d simplex and\n");
145  printf("function values at the vertices:\n\n");
146  printf("%3s %10s %12s %12s %14s\n\n",
147  "i", "x[i]", "y[i]", "z[i]", "function");
148  for (i = 1; i <= MP; i++) {
149  printf("%3d ", i);
150  for (j = 1; j <= NP; j++) printf("%12.6f ", p[i][j]);
151  printf("%12.6f\n", y[i]);
152  }
153  }
154 
155  // dealloc
156  free_matrix(p, 1, MP, 1, NP);
157  free_vector(y, 1, MP);
158  free_vector(x, 1, NP);
159  delete [] startPoint;
160 
161  return 0; // EXIT_SUCCESS
162  }
163  };
164 
165 } // namespace Ox
166 
167 #endif //Tomato_OXFITTERAMOEBANr2_H
168 
169 #endif // USE_NR2
Definition: OxCalculator.h:19