ANIMA  4.0
animaBrentRootFindingAlgorithm.cxx
Go to the documentation of this file.
2 
3 namespace anima
4 {
5 
7 {
8  // Implementation from
9  // https://en.m.wikipedia.org/wiki/Brent's_method
10  bool continueLoop = true;
11  unsigned int nbIterations = 0;
12 
13  unsigned int numParameters = this->GetRootFindingFunction()->GetNumberOfParameters();
14  if (numParameters > 1)
15  throw itk::ExceptionObject(__FILE__, __LINE__, "Brent algorithm does not implement multi-dimensional optimization. Only one parameter allowed.");
16 
17  ParametersType p(1);
18 
19  double internalLowerBound = this->GetLowerBound();
20  double internalUpperBound = this->GetUpperBound();
21 
22  double fValAtLowerBound = this->GetFunctionValueAtInitialLowerBound();
24  {
25  p[0] = internalLowerBound;
26  fValAtLowerBound = this->GetRootFindingFunction()->GetValue(p);
27  }
28 
29  double fValAtUpperBound = this->GetFunctionValueAtInitialUpperBound();
31  {
32  p[0] = internalUpperBound;
33  fValAtUpperBound = this->GetRootFindingFunction()->GetValue(p);
34  }
35 
36  if (std::abs(fValAtLowerBound) < std::abs(fValAtUpperBound))
37  {
38  double workValue = internalLowerBound;
39  internalLowerBound = internalUpperBound;
40  internalUpperBound = workValue;
41  workValue = fValAtLowerBound;
42  fValAtLowerBound = fValAtUpperBound;
43  fValAtUpperBound = workValue;
44  }
45 
46  double cValue = internalLowerBound;
47  double fValAtCValue = fValAtLowerBound;
48  double dValue = 0.0;
49  bool mFlag = true;
50  double deltaValue = this->GetRootRelativeTolerance() * internalUpperBound;
51 
52  while (continueLoop)
53  {
54  ++nbIterations;
55 
56  double fDiffAC = fValAtLowerBound - fValAtCValue;
57  double fDiffBC = fValAtUpperBound - fValAtCValue;
58  double fDiffAB = fValAtLowerBound - fValAtUpperBound;
59  if (fDiffAC == 0.0 || fDiffBC == 0.0)
60  {
61  // secant
62  p[0] = internalUpperBound + fValAtUpperBound * (internalUpperBound - internalLowerBound) / fDiffAB;
63  }
64  else
65  {
66  // inverse quadratic interpolation
67  double firstTerm = internalLowerBound * fValAtUpperBound * fValAtCValue / (fDiffAB * fDiffAC);
68  double secondTerm = internalUpperBound * fValAtLowerBound * fValAtCValue / (-fDiffAB * fDiffBC);
69  double thirdTerm = cValue * fValAtLowerBound * fValAtUpperBound / (fDiffAC * fDiffBC);
70  p[0] = firstTerm + secondTerm + thirdTerm;
71  }
72 
73  bool condition1 = (p[0] < (3.0 * internalLowerBound + internalUpperBound) / 4.0) || (p[0] > internalUpperBound);
74  bool condition2 = (mFlag) && (std::abs(p[0] - internalUpperBound) >= std::abs(internalUpperBound - cValue) / 2.0);
75  bool condition3 = (!mFlag) && (std::abs(p[0] - internalUpperBound) >= std::abs(cValue - dValue) / 2.0);
76  bool condition4 = (mFlag) && (std::abs(internalUpperBound - cValue) < deltaValue);
77  bool condition5 = (!mFlag) && (std::abs(cValue - dValue) < deltaValue);
78 
79  if (condition1 || condition2 || condition3 || condition4 || condition5)
80  {
81  // bisection
82  p[0] = (internalLowerBound + internalUpperBound) / 2.0;
83  mFlag = true;
84  }
85  else
86  mFlag = false;
87 
88  double tentativeCost = this->GetRootFindingFunction()->GetValue(p);
89 
90  continueLoop = (std::abs(tentativeCost) >= this->GetCostFunctionTolerance());
91 
92  dValue = cValue;
93  cValue = internalUpperBound;
94  fValAtCValue = fValAtUpperBound;
95 
96  if (fValAtLowerBound * tentativeCost < 0.0)
97  {
98  internalUpperBound = p[0];
99  fValAtUpperBound = tentativeCost;
100  }
101  else
102  {
103  internalLowerBound = p[0];
104  fValAtLowerBound = tentativeCost;
105  }
106 
107  if (std::abs(fValAtLowerBound) < std::abs(fValAtUpperBound))
108  {
109  double workValue = internalLowerBound;
110  internalLowerBound = internalUpperBound;
111  internalUpperBound = workValue;
112  workValue = fValAtLowerBound;
113  fValAtLowerBound = fValAtUpperBound;
114  fValAtUpperBound = workValue;
115  }
116 
117  deltaValue = this->GetRootRelativeTolerance() * internalUpperBound;
118 
119  if ((nbIterations >= this->GetMaximumNumberOfIterations()) ||
120  (std::abs(internalUpperBound - internalLowerBound) < this->GetRootRelativeTolerance() * (internalLowerBound + internalUpperBound) / 2.0))
121  continueLoop = false;
122  }
123 
124  return p[0];
125 }
126 
127 } // end namespace anima
BaseCostFunctionType::ParametersType ParametersType