ANIMA  4.0
animaBVLSOptimizer.cxx
Go to the documentation of this file.
1 #include <animaBVLSOptimizer.h>
2 #include <vnl/algo/vnl_qr.h>
3 
4 namespace anima
5 {
6 
8 {
9  unsigned int parametersSize = m_DataMatrix.cols();
10  unsigned int numEquations = m_DataMatrix.rows();
11 
12  if ((numEquations != m_Points.size())||(numEquations == 0)||(parametersSize == 0))
13  itkExceptionMacro("Wrongly sized inputs to BVLS, aborting");
14 
15  m_bPrimeVector.set_size(numEquations);
16  m_CurrentPosition.SetSize(parametersSize);
17  m_ParametersAtBoundsVector.resize(parametersSize);
18 
19  this->InitializeSolutionByProjection();
20 
21  bool continueLoop = true;
22  bool wRequired = true;
23 
24  while (continueLoop)
25  {
26  if (wRequired)
27  this->ComputeWVector();
28  continueLoop = this->TestKuhnTuckerConvergence();
29  if (!continueLoop)
30  break;
31 
32  // Find t*
33  double maxVal = 0.0;
34  unsigned int maxIndex = 0;
35  for (unsigned int i = 0;i < parametersSize;++i)
36  {
37  double testVal = m_WVector[i] * m_ParametersAtBoundsVector[i];
38  if (testVal > maxVal)
39  {
40  maxVal = testVal;
41  maxIndex = i;
42  }
43  }
44 
45  // Set it to F
46  m_ParametersAtBoundsVector[maxIndex] = 0;
47 
48  bool continueInternalLoop = true;
49  while (continueInternalLoop)
50  {
51  // Compute b' and A'
52  unsigned int numReducedParameters = 0;
53  for (unsigned int i = 0;i < parametersSize;++i)
54  numReducedParameters += (m_ParametersAtBoundsVector[i] == 0);
55 
56  if (numReducedParameters == 0)
57  break;
58 
59  m_ReducedDataMatrix.set_size(numEquations,numReducedParameters);
60  for (unsigned int j = 0;j < numEquations;++j)
61  {
62  m_bPrimeVector[j] = m_Points[j];
63  unsigned int pos = 0;
64  for (unsigned int k = 0;k < parametersSize;++k)
65  {
66  if (m_ParametersAtBoundsVector[k] != 0)
67  m_bPrimeVector[j] -= m_DataMatrix(j,k) * m_CurrentPosition[k];
68  else
69  {
70  m_ReducedDataMatrix[j][pos] = m_DataMatrix[j][k];
71  ++pos;
72  }
73  }
74  }
75 
76  // Compute reduced solution
77  m_ReducedSolution = vnl_qr <double> (m_ReducedDataMatrix).solve(m_bPrimeVector);
78 
79  // Test reduced solution
80  bool reducedOk = true;
81  unsigned int pos = 0;
82  for (unsigned int i = 0;i < parametersSize;++i)
83  {
84  if (m_ParametersAtBoundsVector[i] != 0)
85  continue;
86 
87  if ((m_ReducedSolution[pos] <= m_LowerBounds[i])||
88  (m_ReducedSolution[pos] >= m_UpperBounds[i]))
89  {
90  reducedOk = false;
91  break;
92  }
93 
94  ++pos;
95  }
96 
97  if (reducedOk)
98  {
99  continueInternalLoop = false;
100  pos = 0;
101  for (unsigned int i = 0;i < parametersSize;++i)
102  {
103  if (m_ParametersAtBoundsVector[i] != 0)
104  continue;
105 
106  m_CurrentPosition[i] = m_ReducedSolution[pos];
107  ++pos;
108  }
109  }
110  else
111  {
112  // If not ok, compute alphas and update sets
113  // Init minAlpha to 2.0, will be replaced at first out bound
114  // since it should be between 0.0 and 1.0
115  double minAlpha = 2.0;
116  unsigned int minIndex = 0;
117 
118  pos = 0;
119  for (unsigned int i = 0;i < parametersSize;++i)
120  {
121  if (m_ParametersAtBoundsVector[i] != 0)
122  continue;
123 
124  if ((m_ReducedSolution[pos] <= m_LowerBounds[i])||
125  (m_ReducedSolution[pos] >= m_UpperBounds[i]))
126  {
127  double denom = m_ReducedSolution[pos] - m_CurrentPosition[i];
128  double alpha = 0.0;
129  if (m_ReducedSolution[pos] >= m_UpperBounds[i])
130  alpha = m_UpperBounds[i] - m_CurrentPosition[i];
131  else
132  alpha = m_LowerBounds[i] - m_CurrentPosition[i];
133 
134  alpha /= denom;
135  alpha = std::max(0.0,alpha);
136 
137  if (alpha < minAlpha)
138  {
139  minAlpha = alpha;
140  minIndex = i;
141  }
142  }
143 
144  ++pos;
145  }
146 
147  if ((minAlpha == 0.0) && (minIndex == maxIndex))
148  {
149  m_WVector[maxIndex] = 0.0;
150  wRequired = false;
151  continueInternalLoop = false;
152 
153  if (m_CurrentPosition[maxIndex] == m_LowerBounds[maxIndex])
154  m_ParametersAtBoundsVector[maxIndex] = 1;
155  else if (m_CurrentPosition[maxIndex] == m_UpperBounds[maxIndex])
156  m_ParametersAtBoundsVector[maxIndex] = -1;
157 
158  continue;
159  }
160 
161  pos = 0;
162  for (unsigned int i = 0;i < parametersSize;++i)
163  {
164  if (m_ParametersAtBoundsVector[i] != 0)
165  continue;
166 
167  if (i != minIndex)
168  {
169  double addonValue = minAlpha * (m_ReducedSolution[pos] - m_CurrentPosition[i]);
170  m_CurrentPosition[i] += addonValue;
171  }
172  else
173  {
174  if (m_ReducedSolution[pos] <= m_LowerBounds[i])
175  m_CurrentPosition[i] = m_LowerBounds[i];
176  else
177  m_CurrentPosition[i] = m_UpperBounds[i];
178  }
179 
180  if (m_CurrentPosition[i] <= m_LowerBounds[i])
181  {
182  m_ParametersAtBoundsVector[i] = 1;
183  m_CurrentPosition[i] = m_LowerBounds[i];
184  }
185  else if (m_CurrentPosition[i] >= m_UpperBounds[i])
186  {
187  m_ParametersAtBoundsVector[i] = -1;
188  m_CurrentPosition[i] = m_UpperBounds[i];
189  }
190 
191  ++pos;
192  }
193  }
194 
195  wRequired = true;
196  }
197  }
198 }
199 
200 void BVLSOptimizer::InitializeSolutionByProjection()
201 {
202  unsigned int parametersSize = m_DataMatrix.cols();
203  m_CurrentPosition.SetSize(parametersSize);
204  m_ParametersAtBoundsVector.resize(parametersSize);
205  std::fill(m_ParametersAtBoundsVector.begin(), m_ParametersAtBoundsVector.end(),0);
206 
207  unsigned int countBounded = 0;
208  unsigned int diffCountBounded = 1;
209  unsigned int numEquations = m_DataMatrix.rows();
210 
211  while ((diffCountBounded != 0) && (countBounded < parametersSize))
212  {
213  unsigned int numParameters = parametersSize - countBounded;
214 
215  m_ReducedDataMatrix.set_size(numEquations,numParameters);
216  for (unsigned int j = 0;j < numEquations;++j)
217  {
218  m_bPrimeVector[j] = m_Points[j];
219  unsigned int pos = 0;
220  for (unsigned int k = 0;k < parametersSize;++k)
221  {
222  if (m_ParametersAtBoundsVector[k] != 0)
223  m_bPrimeVector[j] -= m_DataMatrix[j][k] * m_CurrentPosition[k];
224  else
225  {
226  m_ReducedDataMatrix[j][pos] = m_DataMatrix[j][k];
227  ++pos;
228  }
229  }
230  }
231 
232  m_ReducedSolution = vnl_qr <double> (m_ReducedDataMatrix).solve(m_bPrimeVector);
233  diffCountBounded = 0;
234  unsigned int pos = 0;
235  for (unsigned int i = 0;i < parametersSize;++i)
236  {
237  if (m_ParametersAtBoundsVector[i] != 0)
238  continue;
239 
240  if (m_ReducedSolution[pos] <= m_LowerBounds[i])
241  {
242  m_CurrentPosition[i] = m_LowerBounds[i];
243  m_ParametersAtBoundsVector[i] = 1;
244  ++diffCountBounded;
245  }
246  else if (m_ReducedSolution[pos] >= m_UpperBounds[i])
247  {
248  m_CurrentPosition[i] = m_UpperBounds[i];
249  m_ParametersAtBoundsVector[i] = -1;
250  ++diffCountBounded;
251  }
252  else
253  m_CurrentPosition[i] = m_ReducedSolution[pos];
254 
255  ++pos;
256  }
257 
258  countBounded += diffCountBounded;
259  }
260 }
261 
262 void BVLSOptimizer::ComputeWVector()
263 {
264  unsigned int numEqs = m_Points.size();
265  unsigned int numParameters = m_DataMatrix.cols();
266  m_TmpVector.resize(numEqs);
267  m_WVector.resize(numParameters);
268 
269  for (unsigned int i = 0;i < numEqs;++i)
270  {
271  m_TmpVector[i] = m_Points[i];
272  for (unsigned int j = 0;j < numParameters;++j)
273  m_TmpVector[i] -= m_DataMatrix[i][j] * m_CurrentPosition[j];
274  }
275 
276  for (unsigned int i = 0;i < numParameters;++i)
277  {
278  m_WVector[i] = 0.0;
279 
280  for (unsigned int j = 0;j < numEqs;++j)
281  m_WVector[i] += m_DataMatrix[j][i] * m_TmpVector[j];
282  }
283 }
284 
285 bool BVLSOptimizer::TestKuhnTuckerConvergence()
286 {
287  bool freeSetFull = true;
288  bool allNegativeWsForL = true;
289  bool allPositiveWsForU = true;
290  bool encounteredL = false;
291  bool encounteredU = false;
292 
293  unsigned int parametersSize = m_DataMatrix.cols();
294  for (unsigned int i = 0;i < parametersSize;++i)
295  {
296  if (m_ParametersAtBoundsVector[i] == 0)
297  continue;
298 
299  freeSetFull = false;
300  if (m_ParametersAtBoundsVector[i] == 1)
301  {
302  encounteredL = true;
303  if (m_WVector[i] > 0.0)
304  allNegativeWsForL = false;
305  }
306  else
307  {
308  encounteredU = true;
309  if (m_WVector[i] < 0.0)
310  allPositiveWsForU = false;
311  }
312  }
313 
314  bool returnValue = !freeSetFull;
315  if (returnValue)
316  {
317  if (encounteredL && encounteredU)
318  returnValue = !(allNegativeWsForL && allPositiveWsForU);
319  else if (encounteredL)
320  returnValue = !allNegativeWsForL;
321  else if (encounteredU)
322  returnValue = !allPositiveWsForU;
323  }
324 
325  return returnValue;
326 }
327 
329 {
330  double residualValue = 0;
331 
332  for (unsigned int i = 0;i < m_DataMatrix.rows();++i)
333  {
334  double tmpVal = 0;
335  for (unsigned int j = 0;j < m_DataMatrix.cols();++j)
336  tmpVal += m_DataMatrix[i][j] * m_CurrentPosition[j];
337 
338  residualValue += (tmpVal - m_Points[i]) * (tmpVal - m_Points[i]);
339  }
340 
341  return residualValue;
342 }
343 
344 }
void StartOptimization() ITK_OVERRIDE