~choreonoid/choreonoid/debian

« back to all changes in this revision

Viewing changes to thirdparty/eigen3/Eigen/src/Eigenvalues/RealSchur.h

  • Committer: Thomas Moulard
  • Date: 2012-10-23 12:43:24 UTC
  • Revision ID: git-v1:351cf736ad49bc7a9a7b9767dee760a013517a5d
Tags: upstream/1.1.0
ImportedĀ UpstreamĀ versionĀ 1.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// This file is part of Eigen, a lightweight C++ template library
 
2
// for linear algebra.
 
3
//
 
4
// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
 
5
// Copyright (C) 2010 Jitse Niesen <jitse@maths.leeds.ac.uk>
 
6
//
 
7
// Eigen is free software; you can redistribute it and/or
 
8
// modify it under the terms of the GNU Lesser General Public
 
9
// License as published by the Free Software Foundation; either
 
10
// version 3 of the License, or (at your option) any later version.
 
11
//
 
12
// Alternatively, you can redistribute it and/or
 
13
// modify it under the terms of the GNU General Public License as
 
14
// published by the Free Software Foundation; either version 2 of
 
15
// the License, or (at your option) any later version.
 
16
//
 
17
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
 
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 
19
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
 
20
// GNU General Public License for more details.
 
21
//
 
22
// You should have received a copy of the GNU Lesser General Public
 
23
// License and a copy of the GNU General Public License along with
 
24
// Eigen. If not, see <http://www.gnu.org/licenses/>.
 
25
 
 
26
#ifndef EIGEN_REAL_SCHUR_H
 
27
#define EIGEN_REAL_SCHUR_H
 
28
 
 
29
#include "./EigenvaluesCommon.h"
 
30
#include "./HessenbergDecomposition.h"
 
31
 
 
32
/** \eigenvalues_module \ingroup Eigenvalues_Module
 
33
  *
 
34
  *
 
35
  * \class RealSchur
 
36
  *
 
37
  * \brief Performs a real Schur decomposition of a square matrix
 
38
  *
 
39
  * \tparam _MatrixType the type of the matrix of which we are computing the
 
40
  * real Schur decomposition; this is expected to be an instantiation of the
 
41
  * Matrix class template.
 
42
  *
 
43
  * Given a real square matrix A, this class computes the real Schur
 
44
  * decomposition: \f$ A = U T U^T \f$ where U is a real orthogonal matrix and
 
45
  * T is a real quasi-triangular matrix. An orthogonal matrix is a matrix whose
 
46
  * inverse is equal to its transpose, \f$ U^{-1} = U^T \f$. A quasi-triangular
 
47
  * matrix is a block-triangular matrix whose diagonal consists of 1-by-1
 
48
  * blocks and 2-by-2 blocks with complex eigenvalues. The eigenvalues of the
 
49
  * blocks on the diagonal of T are the same as the eigenvalues of the matrix
 
50
  * A, and thus the real Schur decomposition is used in EigenSolver to compute
 
51
  * the eigendecomposition of a matrix.
 
52
  *
 
53
  * Call the function compute() to compute the real Schur decomposition of a
 
54
  * given matrix. Alternatively, you can use the RealSchur(const MatrixType&, bool)
 
55
  * constructor which computes the real Schur decomposition at construction
 
56
  * time. Once the decomposition is computed, you can use the matrixU() and
 
57
  * matrixT() functions to retrieve the matrices U and T in the decomposition.
 
58
  *
 
59
  * The documentation of RealSchur(const MatrixType&, bool) contains an example
 
60
  * of the typical use of this class.
 
61
  *
 
62
  * \note The implementation is adapted from
 
63
  * <a href="http://math.nist.gov/javanumerics/jama/">JAMA</a> (public domain).
 
64
  * Their code is based on EISPACK.
 
65
  *
 
66
  * \sa class ComplexSchur, class EigenSolver, class ComplexEigenSolver
 
67
  */
 
68
template<typename _MatrixType> class RealSchur
 
69
{
 
70
  public:
 
71
    typedef _MatrixType MatrixType;
 
72
    enum {
 
73
      RowsAtCompileTime = MatrixType::RowsAtCompileTime,
 
74
      ColsAtCompileTime = MatrixType::ColsAtCompileTime,
 
75
      Options = MatrixType::Options,
 
76
      MaxRowsAtCompileTime = MatrixType::MaxRowsAtCompileTime,
 
77
      MaxColsAtCompileTime = MatrixType::MaxColsAtCompileTime
 
78
    };
 
79
    typedef typename MatrixType::Scalar Scalar;
 
80
    typedef std::complex<typename NumTraits<Scalar>::Real> ComplexScalar;
 
81
    typedef typename MatrixType::Index Index;
 
82
 
 
83
    typedef Matrix<ComplexScalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> EigenvalueType;
 
84
    typedef Matrix<Scalar, ColsAtCompileTime, 1, Options & ~RowMajor, MaxColsAtCompileTime, 1> ColumnVectorType;
 
85
 
 
86
    /** \brief Default constructor.
 
87
      *
 
88
      * \param [in] size  Positive integer, size of the matrix whose Schur decomposition will be computed.
 
89
      *
 
90
      * The default constructor is useful in cases in which the user intends to
 
91
      * perform decompositions via compute().  The \p size parameter is only
 
92
      * used as a hint. It is not an error to give a wrong \p size, but it may
 
93
      * impair performance.
 
94
      *
 
95
      * \sa compute() for an example.
 
96
      */
 
97
    RealSchur(Index size = RowsAtCompileTime==Dynamic ? 1 : RowsAtCompileTime)
 
98
            : m_matT(size, size),
 
99
              m_matU(size, size),
 
100
              m_workspaceVector(size),
 
101
              m_hess(size),
 
102
              m_isInitialized(false),
 
103
              m_matUisUptodate(false)
 
104
    { }
 
105
 
 
106
    /** \brief Constructor; computes real Schur decomposition of given matrix. 
 
107
      * 
 
108
      * \param[in]  matrix    Square matrix whose Schur decomposition is to be computed.
 
109
      * \param[in]  computeU  If true, both T and U are computed; if false, only T is computed.
 
110
      *
 
111
      * This constructor calls compute() to compute the Schur decomposition.
 
112
      *
 
113
      * Example: \include RealSchur_RealSchur_MatrixType.cpp
 
114
      * Output: \verbinclude RealSchur_RealSchur_MatrixType.out
 
115
      */
 
116
    RealSchur(const MatrixType& matrix, bool computeU = true)
 
117
            : m_matT(matrix.rows(),matrix.cols()),
 
118
              m_matU(matrix.rows(),matrix.cols()),
 
119
              m_workspaceVector(matrix.rows()),
 
120
              m_hess(matrix.rows()),
 
121
              m_isInitialized(false),
 
122
              m_matUisUptodate(false)
 
123
    {
 
124
      compute(matrix, computeU);
 
125
    }
 
126
 
 
127
    /** \brief Returns the orthogonal matrix in the Schur decomposition. 
 
128
      *
 
129
      * \returns A const reference to the matrix U.
 
130
      *
 
131
      * \pre Either the constructor RealSchur(const MatrixType&, bool) or the
 
132
      * member function compute(const MatrixType&, bool) has been called before
 
133
      * to compute the Schur decomposition of a matrix, and \p computeU was set
 
134
      * to true (the default value).
 
135
      *
 
136
      * \sa RealSchur(const MatrixType&, bool) for an example
 
137
      */
 
138
    const MatrixType& matrixU() const
 
139
    {
 
140
      eigen_assert(m_isInitialized && "RealSchur is not initialized.");
 
141
      eigen_assert(m_matUisUptodate && "The matrix U has not been computed during the RealSchur decomposition.");
 
142
      return m_matU;
 
143
    }
 
144
 
 
145
    /** \brief Returns the quasi-triangular matrix in the Schur decomposition. 
 
146
      *
 
147
      * \returns A const reference to the matrix T.
 
148
      *
 
149
      * \pre Either the constructor RealSchur(const MatrixType&, bool) or the
 
150
      * member function compute(const MatrixType&, bool) has been called before
 
151
      * to compute the Schur decomposition of a matrix.
 
152
      *
 
153
      * \sa RealSchur(const MatrixType&, bool) for an example
 
154
      */
 
155
    const MatrixType& matrixT() const
 
156
    {
 
157
      eigen_assert(m_isInitialized && "RealSchur is not initialized.");
 
158
      return m_matT;
 
159
    }
 
160
  
 
161
    /** \brief Computes Schur decomposition of given matrix. 
 
162
      * 
 
163
      * \param[in]  matrix    Square matrix whose Schur decomposition is to be computed.
 
164
      * \param[in]  computeU  If true, both T and U are computed; if false, only T is computed.
 
165
      * \returns    Reference to \c *this
 
166
      *
 
167
      * The Schur decomposition is computed by first reducing the matrix to
 
168
      * Hessenberg form using the class HessenbergDecomposition. The Hessenberg
 
169
      * matrix is then reduced to triangular form by performing Francis QR
 
170
      * iterations with implicit double shift. The cost of computing the Schur
 
171
      * decomposition depends on the number of iterations; as a rough guide, it
 
172
      * may be taken to be \f$25n^3\f$ flops if \a computeU is true and
 
173
      * \f$10n^3\f$ flops if \a computeU is false.
 
174
      *
 
175
      * Example: \include RealSchur_compute.cpp
 
176
      * Output: \verbinclude RealSchur_compute.out
 
177
      */
 
178
    RealSchur& compute(const MatrixType& matrix, bool computeU = true);
 
179
 
 
180
    /** \brief Reports whether previous computation was successful.
 
181
      *
 
182
      * \returns \c Success if computation was succesful, \c NoConvergence otherwise.
 
183
      */
 
184
    ComputationInfo info() const
 
185
    {
 
186
      eigen_assert(m_isInitialized && "RealSchur is not initialized.");
 
187
      return m_info;
 
188
    }
 
189
 
 
190
    /** \brief Maximum number of iterations.
 
191
      *
 
192
      * Maximum number of iterations allowed for an eigenvalue to converge. 
 
193
      */
 
194
    static const int m_maxIterations = 40;
 
195
 
 
196
  private:
 
197
    
 
198
    MatrixType m_matT;
 
199
    MatrixType m_matU;
 
200
    ColumnVectorType m_workspaceVector;
 
201
    HessenbergDecomposition<MatrixType> m_hess;
 
202
    ComputationInfo m_info;
 
203
    bool m_isInitialized;
 
204
    bool m_matUisUptodate;
 
205
 
 
206
    typedef Matrix<Scalar,3,1> Vector3s;
 
207
 
 
208
    Scalar computeNormOfT();
 
209
    Index findSmallSubdiagEntry(Index iu, Scalar norm);
 
210
    void splitOffTwoRows(Index iu, bool computeU, Scalar exshift);
 
211
    void computeShift(Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo);
 
212
    void initFrancisQRStep(Index il, Index iu, const Vector3s& shiftInfo, Index& im, Vector3s& firstHouseholderVector);
 
213
    void performFrancisQRStep(Index il, Index im, Index iu, bool computeU, const Vector3s& firstHouseholderVector, Scalar* workspace);
 
214
};
 
215
 
 
216
 
 
217
template<typename MatrixType>
 
218
RealSchur<MatrixType>& RealSchur<MatrixType>::compute(const MatrixType& matrix, bool computeU)
 
219
{
 
220
  assert(matrix.cols() == matrix.rows());
 
221
 
 
222
  // Step 1. Reduce to Hessenberg form
 
223
  m_hess.compute(matrix);
 
224
  m_matT = m_hess.matrixH();
 
225
  if (computeU)
 
226
    m_matU = m_hess.matrixQ();
 
227
 
 
228
  // Step 2. Reduce to real Schur form  
 
229
  m_workspaceVector.resize(m_matT.cols());
 
230
  Scalar* workspace = &m_workspaceVector.coeffRef(0);
 
231
 
 
232
  // The matrix m_matT is divided in three parts. 
 
233
  // Rows 0,...,il-1 are decoupled from the rest because m_matT(il,il-1) is zero. 
 
234
  // Rows il,...,iu is the part we are working on (the active window).
 
235
  // Rows iu+1,...,end are already brought in triangular form.
 
236
  Index iu = m_matT.cols() - 1;
 
237
  Index iter = 0; // iteration count
 
238
  Scalar exshift = 0.0; // sum of exceptional shifts
 
239
  Scalar norm = computeNormOfT();
 
240
 
 
241
  while (iu >= 0)
 
242
  {
 
243
    Index il = findSmallSubdiagEntry(iu, norm);
 
244
 
 
245
    // Check for convergence
 
246
    if (il == iu) // One root found
 
247
    {
 
248
      m_matT.coeffRef(iu,iu) = m_matT.coeff(iu,iu) + exshift;
 
249
      if (iu > 0) 
 
250
        m_matT.coeffRef(iu, iu-1) = Scalar(0);
 
251
      iu--;
 
252
      iter = 0;
 
253
    }
 
254
    else if (il == iu-1) // Two roots found
 
255
    {
 
256
      splitOffTwoRows(iu, computeU, exshift);
 
257
      iu -= 2;
 
258
      iter = 0;
 
259
    }
 
260
    else // No convergence yet
 
261
    {
 
262
      // The firstHouseholderVector vector has to be initialized to something to get rid of a silly GCC warning (-O1 -Wall -DNDEBUG )
 
263
      Vector3s firstHouseholderVector(0,0,0), shiftInfo;
 
264
      computeShift(iu, iter, exshift, shiftInfo);
 
265
      iter = iter + 1; 
 
266
      if (iter > m_maxIterations) break;
 
267
      Index im;
 
268
      initFrancisQRStep(il, iu, shiftInfo, im, firstHouseholderVector);
 
269
      performFrancisQRStep(il, im, iu, computeU, firstHouseholderVector, workspace);
 
270
    }
 
271
  } 
 
272
 
 
273
  if(iter <= m_maxIterations) 
 
274
    m_info = Success;
 
275
  else
 
276
    m_info = NoConvergence;
 
277
 
 
278
  m_isInitialized = true;
 
279
  m_matUisUptodate = computeU;
 
280
  return *this;
 
281
}
 
282
 
 
283
/** \internal Computes and returns vector L1 norm of T */
 
284
template<typename MatrixType>
 
285
inline typename MatrixType::Scalar RealSchur<MatrixType>::computeNormOfT()
 
286
{
 
287
  const Index size = m_matT.cols();
 
288
  // FIXME to be efficient the following would requires a triangular reduxion code
 
289
  // Scalar norm = m_matT.upper().cwiseAbs().sum() 
 
290
  //               + m_matT.bottomLeftCorner(size-1,size-1).diagonal().cwiseAbs().sum();
 
291
  Scalar norm = 0.0;
 
292
  for (Index j = 0; j < size; ++j)
 
293
    norm += m_matT.row(j).segment(std::max(j-1,Index(0)), size-std::max(j-1,Index(0))).cwiseAbs().sum();
 
294
  return norm;
 
295
}
 
296
 
 
297
/** \internal Look for single small sub-diagonal element and returns its index */
 
298
template<typename MatrixType>
 
299
inline typename MatrixType::Index RealSchur<MatrixType>::findSmallSubdiagEntry(Index iu, Scalar norm)
 
300
{
 
301
  Index res = iu;
 
302
  while (res > 0)
 
303
  {
 
304
    Scalar s = internal::abs(m_matT.coeff(res-1,res-1)) + internal::abs(m_matT.coeff(res,res));
 
305
    if (s == 0.0)
 
306
      s = norm;
 
307
    if (internal::abs(m_matT.coeff(res,res-1)) < NumTraits<Scalar>::epsilon() * s)
 
308
      break;
 
309
    res--;
 
310
  }
 
311
  return res;
 
312
}
 
313
 
 
314
/** \internal Update T given that rows iu-1 and iu decouple from the rest. */
 
315
template<typename MatrixType>
 
316
inline void RealSchur<MatrixType>::splitOffTwoRows(Index iu, bool computeU, Scalar exshift)
 
317
{
 
318
  const Index size = m_matT.cols();
 
319
 
 
320
  // The eigenvalues of the 2x2 matrix [a b; c d] are 
 
321
  // trace +/- sqrt(discr/4) where discr = tr^2 - 4*det, tr = a + d, det = ad - bc
 
322
  Scalar p = Scalar(0.5) * (m_matT.coeff(iu-1,iu-1) - m_matT.coeff(iu,iu));
 
323
  Scalar q = p * p + m_matT.coeff(iu,iu-1) * m_matT.coeff(iu-1,iu);   // q = tr^2 / 4 - det = discr/4
 
324
  m_matT.coeffRef(iu,iu) += exshift;
 
325
  m_matT.coeffRef(iu-1,iu-1) += exshift;
 
326
 
 
327
  if (q >= Scalar(0)) // Two real eigenvalues
 
328
  {
 
329
    Scalar z = internal::sqrt(internal::abs(q));
 
330
    JacobiRotation<Scalar> rot;
 
331
    if (p >= Scalar(0))
 
332
      rot.makeGivens(p + z, m_matT.coeff(iu, iu-1));
 
333
    else
 
334
      rot.makeGivens(p - z, m_matT.coeff(iu, iu-1));
 
335
 
 
336
    m_matT.rightCols(size-iu+1).applyOnTheLeft(iu-1, iu, rot.adjoint());
 
337
    m_matT.topRows(iu+1).applyOnTheRight(iu-1, iu, rot);
 
338
    m_matT.coeffRef(iu, iu-1) = Scalar(0); 
 
339
    if (computeU)
 
340
      m_matU.applyOnTheRight(iu-1, iu, rot);
 
341
  }
 
342
 
 
343
  if (iu > 1) 
 
344
    m_matT.coeffRef(iu-1, iu-2) = Scalar(0);
 
345
}
 
346
 
 
347
/** \internal Form shift in shiftInfo, and update exshift if an exceptional shift is performed. */
 
348
template<typename MatrixType>
 
349
inline void RealSchur<MatrixType>::computeShift(Index iu, Index iter, Scalar& exshift, Vector3s& shiftInfo)
 
350
{
 
351
  shiftInfo.coeffRef(0) = m_matT.coeff(iu,iu);
 
352
  shiftInfo.coeffRef(1) = m_matT.coeff(iu-1,iu-1);
 
353
  shiftInfo.coeffRef(2) = m_matT.coeff(iu,iu-1) * m_matT.coeff(iu-1,iu);
 
354
 
 
355
  // Wilkinson's original ad hoc shift
 
356
  if (iter == 10)
 
357
  {
 
358
    exshift += shiftInfo.coeff(0);
 
359
    for (Index i = 0; i <= iu; ++i)
 
360
      m_matT.coeffRef(i,i) -= shiftInfo.coeff(0);
 
361
    Scalar s = internal::abs(m_matT.coeff(iu,iu-1)) + internal::abs(m_matT.coeff(iu-1,iu-2));
 
362
    shiftInfo.coeffRef(0) = Scalar(0.75) * s;
 
363
    shiftInfo.coeffRef(1) = Scalar(0.75) * s;
 
364
    shiftInfo.coeffRef(2) = Scalar(-0.4375) * s * s;
 
365
  }
 
366
 
 
367
  // MATLAB's new ad hoc shift
 
368
  if (iter == 30)
 
369
  {
 
370
    Scalar s = (shiftInfo.coeff(1) - shiftInfo.coeff(0)) / Scalar(2.0);
 
371
    s = s * s + shiftInfo.coeff(2);
 
372
    if (s > Scalar(0))
 
373
    {
 
374
      s = internal::sqrt(s);
 
375
      if (shiftInfo.coeff(1) < shiftInfo.coeff(0))
 
376
        s = -s;
 
377
      s = s + (shiftInfo.coeff(1) - shiftInfo.coeff(0)) / Scalar(2.0);
 
378
      s = shiftInfo.coeff(0) - shiftInfo.coeff(2) / s;
 
379
      exshift += s;
 
380
      for (Index i = 0; i <= iu; ++i)
 
381
        m_matT.coeffRef(i,i) -= s;
 
382
      shiftInfo.setConstant(Scalar(0.964));
 
383
    }
 
384
  }
 
385
}
 
386
 
 
387
/** \internal Compute index im at which Francis QR step starts and the first Householder vector. */
 
388
template<typename MatrixType>
 
389
inline void RealSchur<MatrixType>::initFrancisQRStep(Index il, Index iu, const Vector3s& shiftInfo, Index& im, Vector3s& firstHouseholderVector)
 
390
{
 
391
  Vector3s& v = firstHouseholderVector; // alias to save typing
 
392
 
 
393
  for (im = iu-2; im >= il; --im)
 
394
  {
 
395
    const Scalar Tmm = m_matT.coeff(im,im);
 
396
    const Scalar r = shiftInfo.coeff(0) - Tmm;
 
397
    const Scalar s = shiftInfo.coeff(1) - Tmm;
 
398
    v.coeffRef(0) = (r * s - shiftInfo.coeff(2)) / m_matT.coeff(im+1,im) + m_matT.coeff(im,im+1);
 
399
    v.coeffRef(1) = m_matT.coeff(im+1,im+1) - Tmm - r - s;
 
400
    v.coeffRef(2) = m_matT.coeff(im+2,im+1);
 
401
    if (im == il) {
 
402
      break;
 
403
    }
 
404
    const Scalar lhs = m_matT.coeff(im,im-1) * (internal::abs(v.coeff(1)) + internal::abs(v.coeff(2)));
 
405
    const Scalar rhs = v.coeff(0) * (internal::abs(m_matT.coeff(im-1,im-1)) + internal::abs(Tmm) + internal::abs(m_matT.coeff(im+1,im+1)));
 
406
    if (internal::abs(lhs) < NumTraits<Scalar>::epsilon() * rhs)
 
407
    {
 
408
      break;
 
409
    }
 
410
  }
 
411
}
 
412
 
 
413
/** \internal Perform a Francis QR step involving rows il:iu and columns im:iu. */
 
414
template<typename MatrixType>
 
415
inline void RealSchur<MatrixType>::performFrancisQRStep(Index il, Index im, Index iu, bool computeU, const Vector3s& firstHouseholderVector, Scalar* workspace)
 
416
{
 
417
  assert(im >= il);
 
418
  assert(im <= iu-2);
 
419
 
 
420
  const Index size = m_matT.cols();
 
421
 
 
422
  for (Index k = im; k <= iu-2; ++k)
 
423
  {
 
424
    bool firstIteration = (k == im);
 
425
 
 
426
    Vector3s v;
 
427
    if (firstIteration)
 
428
      v = firstHouseholderVector;
 
429
    else
 
430
      v = m_matT.template block<3,1>(k,k-1);
 
431
 
 
432
    Scalar tau, beta;
 
433
    Matrix<Scalar, 2, 1> ess;
 
434
    v.makeHouseholder(ess, tau, beta);
 
435
    
 
436
    if (beta != Scalar(0)) // if v is not zero
 
437
    {
 
438
      if (firstIteration && k > il)
 
439
        m_matT.coeffRef(k,k-1) = -m_matT.coeff(k,k-1);
 
440
      else if (!firstIteration)
 
441
        m_matT.coeffRef(k,k-1) = beta;
 
442
 
 
443
      // These Householder transformations form the O(n^3) part of the algorithm
 
444
      m_matT.block(k, k, 3, size-k).applyHouseholderOnTheLeft(ess, tau, workspace);
 
445
      m_matT.block(0, k, std::min(iu,k+3) + 1, 3).applyHouseholderOnTheRight(ess, tau, workspace);
 
446
      if (computeU)
 
447
        m_matU.block(0, k, size, 3).applyHouseholderOnTheRight(ess, tau, workspace);
 
448
    }
 
449
  }
 
450
 
 
451
  Matrix<Scalar, 2, 1> v = m_matT.template block<2,1>(iu-1, iu-2);
 
452
  Scalar tau, beta;
 
453
  Matrix<Scalar, 1, 1> ess;
 
454
  v.makeHouseholder(ess, tau, beta);
 
455
 
 
456
  if (beta != Scalar(0)) // if v is not zero
 
457
  {
 
458
    m_matT.coeffRef(iu-1, iu-2) = beta;
 
459
    m_matT.block(iu-1, iu-1, 2, size-iu+1).applyHouseholderOnTheLeft(ess, tau, workspace);
 
460
    m_matT.block(0, iu-1, iu+1, 2).applyHouseholderOnTheRight(ess, tau, workspace);
 
461
    if (computeU)
 
462
      m_matU.block(0, iu-1, size, 2).applyHouseholderOnTheRight(ess, tau, workspace);
 
463
  }
 
464
 
 
465
  // clean up pollution due to round-off errors
 
466
  for (Index i = im+2; i <= iu; ++i)
 
467
  {
 
468
    m_matT.coeffRef(i,i-2) = Scalar(0);
 
469
    if (i > im+2)
 
470
      m_matT.coeffRef(i,i-3) = Scalar(0);
 
471
  }
 
472
}
 
473
 
 
474
#endif // EIGEN_REAL_SCHUR_H