Shapeworks Studio  2.1
Shape analysis software suite
List of all members | Public Member Functions | Protected Attributes
Eigen::SVD< MatrixType > Class Template Reference

Standard SVD decomposition of a matrix and associated features. More...

#include <SVD.h>

+ Collaboration diagram for Eigen::SVD< MatrixType >:

Public Member Functions

 SVD (const MatrixType &matrix)
 
template<typename OtherDerived , typename ResultType >
bool solve (const MatrixBase< OtherDerived > &b, ResultType *result) const
 
const MatrixUTypematrixU () const
 
const SingularValuesTypesingularValues () const
 
const MatrixVTypematrixV () const
 
void compute (const MatrixType &matrix)
 
SVDsort ()
 
template<typename UnitaryType , typename PositiveType >
void computeUnitaryPositive (UnitaryType *unitary, PositiveType *positive) const
 
template<typename PositiveType , typename UnitaryType >
void computePositiveUnitary (PositiveType *positive, UnitaryType *unitary) const
 
template<typename RotationType , typename ScalingType >
void computeRotationScaling (RotationType *unitary, ScalingType *positive) const
 
template<typename ScalingType , typename RotationType >
void computeScalingRotation (ScalingType *positive, RotationType *unitary) const
 
template<typename UnitaryType , typename PositiveType >
void computePositiveUnitary (UnitaryType *positive, PositiveType *unitary) const
 

Protected Attributes

MatrixUType m_matU
 
MatrixVType m_matV
 
SingularValuesType m_sigma
 

Detailed Description

template<typename MatrixType>
class Eigen::SVD< MatrixType >

Standard SVD decomposition of a matrix and associated features.

Parameters
MatrixTypethe type of the matrix of which we are computing the SVD decomposition

This class performs a standard SVD decomposition of a real matrix A of size M x N with M >= N.

See also
MatrixBase::SVD()

Definition at line 30 of file SVD.h.

Member Function Documentation

template<typename MatrixType >
void Eigen::SVD< MatrixType >::compute ( const MatrixType &  matrix)

Computes / recomputes the SVD decomposition A = U S V^* of matrix

Note
this code has been adapted from JAMA (public domain)

Definition at line 94 of file SVD.h.

95 {
96  const int m = matrix.rows();
97  const int n = matrix.cols();
98  const int nu = (std::min)(m,n);
99  ei_assert(m>=n && "In Eigen 2.0, SVD only works for MxN matrices with M>=N. Sorry!");
100  ei_assert(m>1 && "In Eigen 2.0, SVD doesn't work on 1x1 matrices");
101 
102  m_matU.resize(m, nu);
103  m_matU.setZero();
104  m_sigma.resize((std::min)(m,n));
105  m_matV.resize(n,n);
106 
107  RowVector e(n);
108  ColVector work(m);
109  MatrixType matA(matrix);
110  const bool wantu = true;
111  const bool wantv = true;
112  int i=0, j=0, k=0;
113 
114  // Reduce A to bidiagonal form, storing the diagonal elements
115  // in s and the super-diagonal elements in e.
116  int nct = (std::min)(m-1,n);
117  int nrt = (std::max)(0,(std::min)(n-2,m));
118  for (k = 0; k < (std::max)(nct,nrt); ++k)
119  {
120  if (k < nct)
121  {
122  // Compute the transformation for the k-th column and
123  // place the k-th diagonal in m_sigma[k].
124  m_sigma[k] = matA.col(k).end(m-k).norm();
125  if (m_sigma[k] != 0.0) // FIXME
126  {
127  if (matA(k,k) < 0.0)
128  m_sigma[k] = -m_sigma[k];
129  matA.col(k).end(m-k) /= m_sigma[k];
130  matA(k,k) += 1.0;
131  }
132  m_sigma[k] = -m_sigma[k];
133  }
134 
135  for (j = k+1; j < n; ++j)
136  {
137  if ((k < nct) && (m_sigma[k] != 0.0))
138  {
139  // Apply the transformation.
140  Scalar t = matA.col(k).end(m-k).eigen2_dot(matA.col(j).end(m-k)); // FIXME dot product or cwise prod + .sum() ??
141  t = -t/matA(k,k);
142  matA.col(j).end(m-k) += t * matA.col(k).end(m-k);
143  }
144 
145  // Place the k-th row of A into e for the
146  // subsequent calculation of the row transformation.
147  e[j] = matA(k,j);
148  }
149 
150  // Place the transformation in U for subsequent back multiplication.
151  if (wantu & (k < nct))
152  m_matU.col(k).end(m-k) = matA.col(k).end(m-k);
153 
154  if (k < nrt)
155  {
156  // Compute the k-th row transformation and place the
157  // k-th super-diagonal in e[k].
158  e[k] = e.end(n-k-1).norm();
159  if (e[k] != 0.0)
160  {
161  if (e[k+1] < 0.0)
162  e[k] = -e[k];
163  e.end(n-k-1) /= e[k];
164  e[k+1] += 1.0;
165  }
166  e[k] = -e[k];
167  if ((k+1 < m) & (e[k] != 0.0))
168  {
169  // Apply the transformation.
170  work.end(m-k-1) = matA.corner(BottomRight,m-k-1,n-k-1) * e.end(n-k-1);
171  for (j = k+1; j < n; ++j)
172  matA.col(j).end(m-k-1) += (-e[j]/e[k+1]) * work.end(m-k-1);
173  }
174 
175  // Place the transformation in V for subsequent back multiplication.
176  if (wantv)
177  m_matV.col(k).end(n-k-1) = e.end(n-k-1);
178  }
179  }
180 
181 
182  // Set up the final bidiagonal matrix or order p.
183  int p = (std::min)(n,m+1);
184  if (nct < n)
185  m_sigma[nct] = matA(nct,nct);
186  if (m < p)
187  m_sigma[p-1] = 0.0;
188  if (nrt+1 < p)
189  e[nrt] = matA(nrt,p-1);
190  e[p-1] = 0.0;
191 
192  // If required, generate U.
193  if (wantu)
194  {
195  for (j = nct; j < nu; ++j)
196  {
197  m_matU.col(j).setZero();
198  m_matU(j,j) = 1.0;
199  }
200  for (k = nct-1; k >= 0; k--)
201  {
202  if (m_sigma[k] != 0.0)
203  {
204  for (j = k+1; j < nu; ++j)
205  {
206  Scalar t = m_matU.col(k).end(m-k).eigen2_dot(m_matU.col(j).end(m-k)); // FIXME is it really a dot product we want ?
207  t = -t/m_matU(k,k);
208  m_matU.col(j).end(m-k) += t * m_matU.col(k).end(m-k);
209  }
210  m_matU.col(k).end(m-k) = - m_matU.col(k).end(m-k);
211  m_matU(k,k) = Scalar(1) + m_matU(k,k);
212  if (k-1>0)
213  m_matU.col(k).start(k-1).setZero();
214  }
215  else
216  {
217  m_matU.col(k).setZero();
218  m_matU(k,k) = 1.0;
219  }
220  }
221  }
222 
223  // If required, generate V.
224  if (wantv)
225  {
226  for (k = n-1; k >= 0; k--)
227  {
228  if ((k < nrt) & (e[k] != 0.0))
229  {
230  for (j = k+1; j < nu; ++j)
231  {
232  Scalar t = m_matV.col(k).end(n-k-1).eigen2_dot(m_matV.col(j).end(n-k-1)); // FIXME is it really a dot product we want ?
233  t = -t/m_matV(k+1,k);
234  m_matV.col(j).end(n-k-1) += t * m_matV.col(k).end(n-k-1);
235  }
236  }
237  m_matV.col(k).setZero();
238  m_matV(k,k) = 1.0;
239  }
240  }
241 
242  // Main iteration loop for the singular values.
243  int pp = p-1;
244  int iter = 0;
245  Scalar eps = ei_pow(Scalar(2),ei_is_same_type<Scalar,float>::ret ? Scalar(-23) : Scalar(-52));
246  while (p > 0)
247  {
248  int k=0;
249  int kase=0;
250 
251  // Here is where a test for too many iterations would go.
252 
253  // This section of the program inspects for
254  // negligible elements in the s and e arrays. On
255  // completion the variables kase and k are set as follows.
256 
257  // kase = 1 if s(p) and e[k-1] are negligible and k<p
258  // kase = 2 if s(k) is negligible and k<p
259  // kase = 3 if e[k-1] is negligible, k<p, and
260  // s(k), ..., s(p) are not negligible (qr step).
261  // kase = 4 if e(p-1) is negligible (convergence).
262 
263  for (k = p-2; k >= -1; --k)
264  {
265  if (k == -1)
266  break;
267  if (ei_abs(e[k]) <= eps*(ei_abs(m_sigma[k]) + ei_abs(m_sigma[k+1])))
268  {
269  e[k] = 0.0;
270  break;
271  }
272  }
273  if (k == p-2)
274  {
275  kase = 4;
276  }
277  else
278  {
279  int ks;
280  for (ks = p-1; ks >= k; --ks)
281  {
282  if (ks == k)
283  break;
284  Scalar t = (ks != p ? ei_abs(e[ks]) : Scalar(0)) + (ks != k+1 ? ei_abs(e[ks-1]) : Scalar(0));
285  if (ei_abs(m_sigma[ks]) <= eps*t)
286  {
287  m_sigma[ks] = 0.0;
288  break;
289  }
290  }
291  if (ks == k)
292  {
293  kase = 3;
294  }
295  else if (ks == p-1)
296  {
297  kase = 1;
298  }
299  else
300  {
301  kase = 2;
302  k = ks;
303  }
304  }
305  ++k;
306 
307  // Perform the task indicated by kase.
308  switch (kase)
309  {
310 
311  // Deflate negligible s(p).
312  case 1:
313  {
314  Scalar f(e[p-2]);
315  e[p-2] = 0.0;
316  for (j = p-2; j >= k; --j)
317  {
318  Scalar t(numext::hypot(m_sigma[j],f));
319  Scalar cs(m_sigma[j]/t);
320  Scalar sn(f/t);
321  m_sigma[j] = t;
322  if (j != k)
323  {
324  f = -sn*e[j-1];
325  e[j-1] = cs*e[j-1];
326  }
327  if (wantv)
328  {
329  for (i = 0; i < n; ++i)
330  {
331  t = cs*m_matV(i,j) + sn*m_matV(i,p-1);
332  m_matV(i,p-1) = -sn*m_matV(i,j) + cs*m_matV(i,p-1);
333  m_matV(i,j) = t;
334  }
335  }
336  }
337  }
338  break;
339 
340  // Split at negligible s(k).
341  case 2:
342  {
343  Scalar f(e[k-1]);
344  e[k-1] = 0.0;
345  for (j = k; j < p; ++j)
346  {
347  Scalar t(numext::hypot(m_sigma[j],f));
348  Scalar cs( m_sigma[j]/t);
349  Scalar sn(f/t);
350  m_sigma[j] = t;
351  f = -sn*e[j];
352  e[j] = cs*e[j];
353  if (wantu)
354  {
355  for (i = 0; i < m; ++i)
356  {
357  t = cs*m_matU(i,j) + sn*m_matU(i,k-1);
358  m_matU(i,k-1) = -sn*m_matU(i,j) + cs*m_matU(i,k-1);
359  m_matU(i,j) = t;
360  }
361  }
362  }
363  }
364  break;
365 
366  // Perform one qr step.
367  case 3:
368  {
369  // Calculate the shift.
370  Scalar scale = (std::max)((std::max)((std::max)((std::max)(
371  ei_abs(m_sigma[p-1]),ei_abs(m_sigma[p-2])),ei_abs(e[p-2])),
372  ei_abs(m_sigma[k])),ei_abs(e[k]));
373  Scalar sp = m_sigma[p-1]/scale;
374  Scalar spm1 = m_sigma[p-2]/scale;
375  Scalar epm1 = e[p-2]/scale;
376  Scalar sk = m_sigma[k]/scale;
377  Scalar ek = e[k]/scale;
378  Scalar b = ((spm1 + sp)*(spm1 - sp) + epm1*epm1)/Scalar(2);
379  Scalar c = (sp*epm1)*(sp*epm1);
380  Scalar shift(0);
381  if ((b != 0.0) || (c != 0.0))
382  {
383  shift = ei_sqrt(b*b + c);
384  if (b < 0.0)
385  shift = -shift;
386  shift = c/(b + shift);
387  }
388  Scalar f = (sk + sp)*(sk - sp) + shift;
389  Scalar g = sk*ek;
390 
391  // Chase zeros.
392 
393  for (j = k; j < p-1; ++j)
394  {
395  Scalar t = numext::hypot(f,g);
396  Scalar cs = f/t;
397  Scalar sn = g/t;
398  if (j != k)
399  e[j-1] = t;
400  f = cs*m_sigma[j] + sn*e[j];
401  e[j] = cs*e[j] - sn*m_sigma[j];
402  g = sn*m_sigma[j+1];
403  m_sigma[j+1] = cs*m_sigma[j+1];
404  if (wantv)
405  {
406  for (i = 0; i < n; ++i)
407  {
408  t = cs*m_matV(i,j) + sn*m_matV(i,j+1);
409  m_matV(i,j+1) = -sn*m_matV(i,j) + cs*m_matV(i,j+1);
410  m_matV(i,j) = t;
411  }
412  }
413  t = numext::hypot(f,g);
414  cs = f/t;
415  sn = g/t;
416  m_sigma[j] = t;
417  f = cs*e[j] + sn*m_sigma[j+1];
418  m_sigma[j+1] = -sn*e[j] + cs*m_sigma[j+1];
419  g = sn*e[j+1];
420  e[j+1] = cs*e[j+1];
421  if (wantu && (j < m-1))
422  {
423  for (i = 0; i < m; ++i)
424  {
425  t = cs*m_matU(i,j) + sn*m_matU(i,j+1);
426  m_matU(i,j+1) = -sn*m_matU(i,j) + cs*m_matU(i,j+1);
427  m_matU(i,j) = t;
428  }
429  }
430  }
431  e[p-2] = f;
432  iter = iter + 1;
433  }
434  break;
435 
436  // Convergence.
437  case 4:
438  {
439  // Make the singular values positive.
440  if (m_sigma[k] <= 0.0)
441  {
442  m_sigma[k] = m_sigma[k] < Scalar(0) ? -m_sigma[k] : Scalar(0);
443  if (wantv)
444  m_matV.col(k).start(pp+1) = -m_matV.col(k).start(pp+1);
445  }
446 
447  // Order the singular values.
448  while (k < pp)
449  {
450  if (m_sigma[k] >= m_sigma[k+1])
451  break;
452  Scalar t = m_sigma[k];
453  m_sigma[k] = m_sigma[k+1];
454  m_sigma[k+1] = t;
455  if (wantv && (k < n-1))
456  m_matV.col(k).swap(m_matV.col(k+1));
457  if (wantu && (k < m-1))
458  m_matU.col(k).swap(m_matU.col(k+1));
459  ++k;
460  }
461  iter = 0;
462  p--;
463  }
464  break;
465  } // end big switch
466  } // end iterations
467 }
Definition: math3d.h:219
EIGEN_STRONG_INLINE void resize(Index nbRows, Index nbCols)
Derived & setZero(Index size)
template<typename MatrixType>
template<typename UnitaryType , typename PositiveType >
void Eigen::SVD< MatrixType >::computePositiveUnitary ( UnitaryType *  positive,
PositiveType *  unitary 
) const

Computes the polar decomposition of the matrix, as a product positive x unitary.

If either pointer is zero, the corresponding computation is skipped.

Only for square matrices.

See also
computeUnitaryPositive(), computeRotationScaling()

Definition at line 565 of file SVD.h.

567 {
568  ei_assert(m_matU.rows() == m_matV.rows() && "Polar decomposition is only for square matrices");
569  if(unitary) *unitary = m_matU * m_matV.adjoint();
570  if(positive) *positive = m_matU * m_sigma.asDiagonal() * m_matU.adjoint();
571 }
template<typename MatrixType >
template<typename RotationType , typename ScalingType >
void Eigen::SVD< MatrixType >::computeRotationScaling ( RotationType *  rotation,
ScalingType *  scaling 
) const

decomposes the matrix as a product rotation x scaling, the scaling being not necessarily positive.

If either pointer is zero, the corresponding computation is skipped.

This method requires the Geometry module.

See also
computeScalingRotation(), computeUnitaryPositive()

Definition at line 584 of file SVD.h.

585 {
586  ei_assert(m_matU.rows() == m_matV.rows() && "Polar decomposition is only for square matrices");
587  Scalar x = (m_matU * m_matV.adjoint()).determinant(); // so x has absolute value 1
588  Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> sv(m_sigma);
589  sv.coeffRef(0) *= x;
590  if(scaling) scaling->lazyAssign(m_matV * sv.asDiagonal() * m_matV.adjoint());
591  if(rotation)
592  {
593  MatrixType m(m_matU);
594  m.col(0) /= x;
595  rotation->lazyAssign(m * m_matV.adjoint());
596  }
597 }
template<typename MatrixType >
template<typename ScalingType , typename RotationType >
void Eigen::SVD< MatrixType >::computeScalingRotation ( ScalingType *  scaling,
RotationType *  rotation 
) const

decomposes the matrix as a product scaling x rotation, the scaling being not necessarily positive.

If either pointer is zero, the corresponding computation is skipped.

This method requires the Geometry module.

See also
computeRotationScaling(), computeUnitaryPositive()

Definition at line 610 of file SVD.h.

611 {
612  ei_assert(m_matU.rows() == m_matV.rows() && "Polar decomposition is only for square matrices");
613  Scalar x = (m_matU * m_matV.adjoint()).determinant(); // so x has absolute value 1
614  Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> sv(m_sigma);
615  sv.coeffRef(0) *= x;
616  if(scaling) scaling->lazyAssign(m_matU * sv.asDiagonal() * m_matU.adjoint());
617  if(rotation)
618  {
619  MatrixType m(m_matU);
620  m.col(0) /= x;
621  rotation->lazyAssign(m * m_matV.adjoint());
622  }
623 }
template<typename MatrixType >
template<typename UnitaryType , typename PositiveType >
void Eigen::SVD< MatrixType >::computeUnitaryPositive ( UnitaryType *  unitary,
PositiveType *  positive 
) const

Computes the polar decomposition of the matrix, as a product unitary x positive.

If either pointer is zero, the corresponding computation is skipped.

Only for square matrices.

See also
computePositiveUnitary(), computeRotationScaling()

Definition at line 547 of file SVD.h.

549 {
550  ei_assert(m_matU.cols() == m_matV.cols() && "Polar decomposition is only for square matrices");
551  if(unitary) *unitary = m_matU * m_matV.adjoint();
552  if(positive) *positive = m_matV * m_sigma.asDiagonal() * m_matV.adjoint();
553 }
template<typename MatrixType >
template<typename OtherDerived , typename ResultType >
bool Eigen::SVD< MatrixType >::solve ( const MatrixBase< OtherDerived > &  b,
ResultType *  result 
) const
Returns
the solution of $ A x = b $ using the current SVD decomposition of A. The parts of the solution corresponding to zero singular values are ignored.
See also
MatrixBase::svd(), LU::solve(), LLT::solve()

Definition at line 513 of file SVD.h.

514 {
515  const int rows = m_matU.rows();
516  ei_assert(b.rows() == rows);
517 
518  Scalar maxVal = m_sigma.cwise().abs().maxCoeff();
519  for (int j=0; j<b.cols(); ++j)
520  {
521  Matrix<Scalar,MatrixUType::RowsAtCompileTime,1> aux = m_matU.transpose() * b.col(j);
522 
523  for (int i = 0; i <m_matU.cols(); ++i)
524  {
525  Scalar si = m_sigma.coeff(i);
526  if (ei_isMuchSmallerThan(ei_abs(si),maxVal))
527  aux.coeffRef(i) = 0;
528  else
529  aux.coeffRef(i) /= si;
530  }
531 
532  result->col(j) = m_matV * aux;
533  }
534  return true;
535 }

The documentation for this class was generated from the following file: