SDPSL
Semidefinite Programming Specification Library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Pages
qrdec.h
Go to the documentation of this file.
1 
7 #ifndef __QRDEC_H__
8 #define __QRDEC_H__
9 
10 #include <vector>
11 #include <iostream>
12 
13 #ifdef __MPF_BUILD__
14 namespace mpf_sdp {
15 #else
16 namespace sdp {
17 #endif
18 
30 template <class T>
32  int _m, _n; // Number of rows and columns
33  T sfactor; // Scaling factor
34  std::vector<T> QR; // Matrix containing Q and R
35  std::vector<T> sigma; // Reflector parameters & diagonal of R
36  std::vector<T> msigma; // The opposites of the sigma numbers
37  std::vector<int> p; // Pivot vector
38 
39 public:
52  QRDecomposition(const std::vector<T>& A, int m, int n, double sing_eps = 1e-10)
53  : _m(m), _n(n), QR(A), p(n)
54  {
55  if (m < n)
56  throw ValueError(ERROR_MSG("Number of rows smaller than of columns"));
57 
58  /* Finds the scaling factor and scales the matrix */
59  sfactor = 0;
60  for (int i = 0; i < QR.size(); i++)
61  if (NumberOperations::abs(QR[i]) > sfactor)
62  sfactor = NumberOperations::abs(QR[i]);
63 
64  for (int i = 0; i < QR.size(); i++) QR[i] /= sfactor;
65 
66  /* Computes column squared norms */
67  std::vector<T> cnorms(n, 0);
68 
69  for (int j = 0; j < n; j++)
70  for (int i = 0; i < m; i++)
71  cnorms[j] += QR[i + j * m] * QR[i + j * m];
72 
73  /* Does the QR decomposition with column pivoting */
74  sigma.reserve(n);
75  for (int j = 0; j < n; j++) p[j] = j;
76 
77  for (int k = 0; k < n; k++) {
78  /* Pivoting step */
79  int pivot = k;
80  for (int j = k + 1; j < n; j++)
81  if (cnorms[p[j]] > cnorms[p[pivot]])
82  pivot = j;
83 
84  if (cnorms[p[pivot]] <= sing_eps) break; // We are finished
85 
86  { int tmp = p[k];
87  p[k] = p[pivot];
88  p[pivot] = tmp;
89  }
90 
91  /* Computes the reflector */
92  T s = NumberOperations::sqrt(cnorms[p[k]]);
93 
94  if (QR[k + p[k] * m] < 0) s *= -1;
95  QR[k + p[k] * m] += s;
96 
97  T gamma_inv = s * QR[k + p[k] * m];
98  sigma.push_back(s);
99 
100  /* Applies reflector to other columns */
101  for (int j = k + 1; j < n; j++) {
102  T tau = 0;
103  for (int i = k; i < m; i++)
104  tau += QR[i + p[k] * m] * QR[i + p[j] * m];
105 
106  tau /= gamma_inv;
107  for (int i = k; i < m; i++)
108  QR[i + p[j] * m] -= tau * QR[i + p[k] * m];
109  }
110 
111  /* Updates column norms */
112  for (int j = k + 1; j < n; j++)
113  cnorms[p[j]] -= QR[k + p[j] * m] * QR[k + p[j] * m];
114  }
115 
116  /* And we fill msigma */
117  msigma = sigma;
118  for (int i = 0; i < msigma.size(); i++)
119  msigma[i] *= -1;
120  }
121 
137  int rank() const { return sigma.size(); }
138 
150  int perm(int j) const { return p[j]; }
151 
158  const T& scaling_factor() const { return sfactor; }
159 
164  const T& R(int i, int j) const
165  {
166  if (i == j) return msigma[i];
167 
168  return QR[i + p[j] * _m];
169  }
170 
172  void Q_mul(std::vector<T>& x) const
173  {
174  for (int k = sigma.size() - 1; k >= 0; k--) {
175  T tau = 0;
176 
177  for (int i = k; i < _m; i++)
178  tau += QR[i + p[k] * _m] * x[i];
179 
180  tau /= sigma[k] * QR[k + p[k] * _m];
181 
182  for (int i = k; i < _m; i++)
183  x[i] -= tau * QR[i + p[k] * _m];
184  }
185  }
186 
188  void Q_transpose_mul(std::vector<T>& x) const
189  {
190  for (int k = 0; k < sigma.size(); k++) {
191  T tau = 0;
192 
193  for (int i = k; i < _m; i++)
194  tau += QR[i + p[k] * _m] * x[i];
195 
196  tau /= sigma[k] * QR[k + p[k] * _m];
197 
198  for (int i = k; i < _m; i++)
199  x[i] -= tau * QR[i + p[k] * _m];
200  }
201  }
202 };
203 
204 } // namespace
205 
206 #endif
207 
208 // Local variables:
209 // mode: c++
210 // End: