ANIMA  4.0
animaQRDecomposition.hxx
Go to the documentation of this file.
1 #pragma once
2 #include "animaQRDecomposition.h"
4 #include <limits>
5 
6 namespace anima
7 {
8 
9 template <typename ScalarType> void QRGivensDecomposition(vnl_matrix <ScalarType> &aMatrix, vnl_vector <ScalarType> &bVector)
10 {
11  unsigned int m = aMatrix.rows();
12  unsigned int n = aMatrix.cols();
13 
14  if (m < n)
15  return;
16 
17  bool applyQToB = (bVector.size() == m);
18 
19  for (unsigned int j = 0;j < n;++j)
20  {
21  for (unsigned int i = m - 1;i >= j + 1;--i)
22  {
23  double bValue = aMatrix.get(i,j);
24  double aValue = aMatrix.get(j,j);
25  if (std::abs(bValue) <= std::numeric_limits <double>::epsilon())
26  continue;
27 
28  // Compute Givens cos and sine values
29  double cosValue, sinValue;
30  double r = std::hypot(aValue,bValue);
31  cosValue = aValue / r;
32  sinValue = - bValue / r;
33 
34  for (unsigned int k = j;k < n;++k)
35  {
36  double ajkValue = aMatrix.get(j,k);
37  double aikValue = aMatrix.get(i,k);
38  double ajValue = cosValue * ajkValue - sinValue * aikValue;
39  double aiValue = sinValue * ajkValue + cosValue * aikValue;
40 
41  aMatrix.put(j,k,ajValue);
42  aMatrix.put(i,k,aiValue);
43  }
44 
45  if (applyQToB)
46  {
47  double bjValue = cosValue * bVector[j] - sinValue * bVector[i];
48  double biValue = sinValue * bVector[j] + cosValue * bVector[i];
49 
50  bVector[j] = bjValue;
51  bVector[i] = biValue;
52  }
53  }
54  }
55 }
56 
57 template <typename ScalarType> void QRPivotDecomposition(vnl_matrix <ScalarType> &aMatrix, std::vector <unsigned int> &pivotVector,
58  std::vector <ScalarType> &houseBetaValues, unsigned int &rank)
59 {
60  unsigned int m = aMatrix.rows();
61  unsigned int n = aMatrix.cols();
62 
63  if (m < n)
64  return;
65 
66  pivotVector.resize(n);
67  houseBetaValues.resize(n);
68 
69  for (unsigned int i = 0;i < n;++i)
70  {
71  pivotVector[i] = i;
72  houseBetaValues[i] = 0.0;
73  }
74 
75  std::vector <double> cVector(n,0.0);
76  for (unsigned int i = 0;i < n;++i)
77  {
78  for (unsigned int j = 0;j < m;++j)
79  {
80  double tmpVal = aMatrix.get(j,i);
81  cVector[i] += tmpVal * tmpVal;
82  }
83  }
84 
85  rank = 0;
86  double tau = cVector[0];
87  unsigned int k = 0;
88  for (unsigned int i = 1;i < n;++i)
89  {
90  if (tau < cVector[i])
91  {
92  k = i;
93  tau = cVector[i];
94  }
95  }
96 
97  std::vector <double> housedVector;
98  std::vector <double> housedTransposeA(n);
99  double epsilon = std::numeric_limits<double>::epsilon();
100 
101  while (tau > 0.0)
102  {
103  ++rank;
104  unsigned int r = rank - 1;
105  unsigned int tmpIndex = pivotVector[k];
106  pivotVector[k] = pivotVector[r];
107  pivotVector[r] = tmpIndex;
108  double tmp = cVector[k];
109  cVector[k] = cVector[r];
110  cVector[r] = tmp;
111 
112  if (r != k)
113  {
114  for (unsigned int i = 0;i < m;++i)
115  {
116  tmp = aMatrix(i,k);
117  aMatrix.put(i,k,aMatrix.get(i,r));
118  aMatrix.put(i,r,tmp);
119  }
120  }
121 
122  housedVector.resize(m - r);
123  for (unsigned int i = r;i < m;++i)
124  housedVector[i - r] = aMatrix.get(i,r);
125 
126  ComputeHouseholderVector(housedVector,houseBetaValues[r]);
127 
128  double diagonalValueTest = 0.0;
129  for (unsigned int l = r;l < m;++l)
130  {
131  double workMatrixHouseValue = 0.0;
132  unsigned int lIndex = l - r;
133  if (lIndex != 0)
134  workMatrixHouseValue = - houseBetaValues[r] * housedVector[0] * housedVector[lIndex];
135  else
136  workMatrixHouseValue = 1.0 - houseBetaValues[r] * housedVector[0] * housedVector[0];
137 
138  diagonalValueTest += workMatrixHouseValue * aMatrix.get(l,r);
139  }
140 
141  if (r > 0)
142  {
143  if (std::abs(diagonalValueTest) < epsilon)
144  {
145  // cancel modifications so far and exit
146  --rank;
147  houseBetaValues[r] = 0.0;
148  tmpIndex = pivotVector[k];
149  pivotVector[k] = pivotVector[r];
150  pivotVector[r] = tmpIndex;
151  tmp = cVector[k];
152  cVector[k] = cVector[r];
153  cVector[r] = tmp;
154 
155  if (r != k)
156  {
157  for (unsigned int i = 0;i < m;++i)
158  {
159  tmp = aMatrix.get(i,k);
160  aMatrix.put(i,k,aMatrix.get(i,r));
161  aMatrix.put(i,r,tmp);
162  }
163  }
164 
165  tau = 0.0;
166  continue;
167  }
168  }
169  else
170  {
171  // Compute reference value for diagonal value test
172  // taken from GSL rank test
173  double basePower = std::floor(std::log(std::abs(diagonalValueTest)) / std::log(2.0));
174  epsilon *= 20.0 * (m + n) * std::pow(2.0,basePower);
175  }
176 
177  for (unsigned int i = 0;i < n - r;++i)
178  {
179  housedTransposeA[i] = 0.0;
180  for (unsigned int j = 0;j < m - r;++j)
181  housedTransposeA[i] += housedVector[j] * aMatrix.get(j + r, i + r);
182  }
183 
184  for (unsigned int i = r;i < m;++i)
185  {
186  for (unsigned int j = r;j < n;++j)
187  {
188  double tmpValue = aMatrix.get(i,j) - houseBetaValues[r] * housedVector[i - r] * housedTransposeA[j - r];
189  aMatrix.put(i,j,tmpValue);
190  }
191  }
192 
193  for (unsigned int i = rank;i < m;++i)
194  aMatrix.put(i,r,housedVector[i - r]);
195 
196  for (unsigned int i = rank;i < n;++i)
197  {
198  double tmpVal = aMatrix.get(r,i);
199  cVector[i] -= tmpVal * tmpVal;
200  }
201 
202  tau = 0.0;
203 
204  if (rank < n)
205  {
206  k = rank;
207  tau = cVector[rank];
208 
209  for (unsigned int i = rank + 1;i < n;++i)
210  {
211  if (tau < cVector[i])
212  {
213  k = i;
214  tau = cVector[i];
215  }
216  }
217  }
218  }
219 }
220 
221 template <typename ScalarType> void GetQtBFromQRPivotDecomposition(vnl_matrix <ScalarType> &qrMatrix, vnl_vector<ScalarType> &bVector,
222  std::vector <ScalarType> &houseBetaValues, unsigned int rank)
223 {
224  unsigned int m = qrMatrix.rows();
225  unsigned int n = qrMatrix.cols();
226 
227  if (m < n)
228  return;
229 
230  for (unsigned int j = 0;j < rank;++j)
231  {
232  // Compute v^T B
233  double vtB = bVector[j];
234  for (unsigned int i = j + 1;i < m;++i)
235  vtB += qrMatrix.get(i,j) * bVector[i];
236 
237  // bVector -= beta * v * vtB
238  bVector[j] -= houseBetaValues[j] * vtB;
239 
240  for (unsigned int i = j + 1;i < m;++i)
241  bVector[i] -= houseBetaValues[j] * qrMatrix.get(i,j) * vtB;
242  }
243 }
244 
245 template <typename ScalarType> void GetQMatrixQRPivotDecomposition(vnl_matrix <ScalarType> &qrMatrix, std::vector <ScalarType> &houseBetaValues,
246  vnl_matrix <ScalarType> &qMatrix, unsigned int rank)
247 {
248  unsigned int m = qrMatrix.rows();
249  unsigned int n = qrMatrix.cols();
250 
251  if (m < n)
252  return;
253 
254  qMatrix.set_size(m,m);
255  qMatrix.set_identity();
256 
257  for (int j = rank - 1;j >= 0;--j)
258  {
259  unsigned int vecSize = m - j;
260  vnl_vector <double> vtQ(vecSize);
261 
262  // Compute v^T B
263  for (unsigned int i = 0;i < vecSize;++i)
264  {
265  vtQ[i] = qMatrix(j,i + j);
266  for (unsigned int k = j + 1;k < m;++k)
267  vtQ[i] += qrMatrix.get(k,j) * qMatrix.get(k,i + j);
268  }
269 
270  for (unsigned int i = 0;i < vecSize;++i)
271  {
272  double constantValue = houseBetaValues[j];
273  if (i != 0)
274  constantValue *= qrMatrix.get(i + j,j);
275 
276  for (unsigned int k = 0;k < vecSize;++k)
277  {
278  double tmpVal = qMatrix.get(i + j,k + j) - constantValue * vtQ[k];
279  qMatrix.put(i + j,k + j,tmpVal);
280  }
281  }
282  }
283 }
284 
285 } // end namespace anima
void QRPivotDecomposition(vnl_matrix< ScalarType > &aMatrix, std::vector< unsigned int > &pivotVector, std::vector< ScalarType > &houseBetaValues, unsigned int &rank)
void GetQtBFromQRPivotDecomposition(vnl_matrix< ScalarType > &qrMatrix, vnl_vector< ScalarType > &bVector, std::vector< ScalarType > &houseBetaValues, unsigned int rank)
void QRGivensDecomposition(vnl_matrix< ScalarType > &aMatrix, vnl_vector< ScalarType > &bVector)
void GetQMatrixQRPivotDecomposition(vnl_matrix< ScalarType > &qrMatrix, std::vector< ScalarType > &houseBetaValues, vnl_matrix< ScalarType > &qMatrix, unsigned int rank)
void ComputeHouseholderVector(const VectorType &inputVector, VectorType &outputVector, double &beta, unsigned int dimension)