[eigen] inconsistency in fast eigen decomposition

[ Thread Index | Date Index | More lists.tuxfamily.org/eigen Archives ]


Hi all,

Gael, we've been using the fast eigen decomposition suggested by you in an e-mail back in 09/02/10 (regarding SelfAdjointEigenSolver<Matrix3f> - http://listengine.tuxfamily.org/lists.tuxfamily.org/eigen/2010/08/msg00283.html) without any major issues for the past few months.

We've recently hit a problem, and I was wondering whether there is a fix for it that doesn't involve switching to another SVD/eigendecomposition method in Eigen, as the implementation that we're using (see attached source) is still blazing fast.

Here's the snippet of code that exhibits the problem (not that it's a c&p so please ignore the style/format):

Eigen3::Matrix3f covariance_matrix_f;
covariance_matrix_f << 5.64909, 5.64909, 0.0860435, 5.64909, 5.64909, 0.0860435, 0.0860435, 0.0860435, 2.92133;

Eigen3::SelfAdjointEigenSolver<Eigen3::Matrix3f> ei_symm (covariance_matrix_f);
Eigen3::Vector3f eigen_values = ei_symm.eigenvalues ();
Eigen3::Matrix3f eigen_vectors = ei_symm.eigenvectors ();

cerr << eigen_vectors << endl;
cerr << eigen_values << endl;
cerr << "Normal: " << eigen_vectors (0, 0) << ", " << eigen_vectors (1, 0) << ", " << eigen_vectors (2, 0) << endl;

Eigen3::Vector3f eigen_val;
Eigen3::Matrix3f eigen_vec;
eigen33 (covariance_matrix_f, eigen_vec, eigen_val);

cerr << eigen_vec << endl;
cerr << eigen_val << endl;
cerr << "Normal: " << eigen_vec (0, 0) << ", " << eigen_vec (1, 0) << ", " << eigen_vec (2, 0) << endl;
----

The output is:

  0.707107 -0.0102705   0.707032
 -0.707107 -0.0102656   0.707032
3.48268e-06   0.999894  0.0145212
3.41638e-08
2.91956
11.2999
Normal: 0.707107, -0.707107, 3.48268e-06

-0.00781202 0.0102683  0.707032
-0.00781202 0.0102683  0.707032
 0.999939 -0.999895 0.0145207
-1.01014e-06
2.91956
11.2999
Normal: -0.00781202, -0.00781202, 0.999939
---


Thanks in advance.


Cheers,
Radu.
--
http://pointclouds.org
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@xxxxxxxx>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

// The computeRoots function included in this is based on materials
// covered by the following copyright and license:
// 
// Geometric Tools, LLC
// Copyright (c) 1998-2010
// Distributed under the Boost Software License, Version 1.0.
// 
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
// 
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#ifndef PCL_EIGEN_H_
#define PCL_EIGEN_H_

#include <Eigen3/Core>
#include <Eigen3/Eigenvalues>
#include <Eigen3/Geometry>

template<typename Matrix, typename Roots> inline void
  computeRoots (const Matrix& rkA, Roots& adRoot)
{
  typedef typename Matrix::Scalar Scalar;
  const Scalar msInv3 = 1.0/3.0;
  const Scalar msRoot3 = Eigen3::internal::sqrt (Scalar (3.0));

  Scalar dA00 = rkA (0, 0);
  Scalar dA01 = rkA (0, 1);
  Scalar dA02 = rkA (0, 2);
  Scalar dA11 = rkA (1, 1);
  Scalar dA12 = rkA (1, 2);
  Scalar dA22 = rkA (2, 2);

  // The characteristic equation is x^3 - c2*x^2 + c1*x - c0 = 0.  The
  // eigenvalues are the roots to this equation, all guaranteed to be
  // real-valued, because the matrix is symmetric.
  Scalar dC0 = dA00*dA11*dA22 + Scalar (2)*dA01*dA02*dA12 - dA00*dA12*dA12 - dA11*dA02*dA02 - dA22*dA01*dA01;
  Scalar dC1 = dA00*dA11 - dA01*dA01 + dA00*dA22 - dA02*dA02 + dA11*dA22 - dA12*dA12;
  Scalar dC2 = dA00 + dA11 + dA22;

  // Construct the parameters used in classifying the roots of the equation
  // and in solving the equation for the roots in closed form.
  Scalar dC2Div3 = dC2*msInv3;
  Scalar dADiv3 = (dC1 - dC2*dC2Div3)*msInv3;
  if (dADiv3 > Scalar (0))
    dADiv3 = Scalar (0);

  Scalar dMBDiv2 = Scalar (0.5) * (dC0 + dC2Div3 * (Scalar (2) * dC2Div3*dC2Div3 - dC1));

  Scalar dQ = dMBDiv2*dMBDiv2 + dADiv3*dADiv3*dADiv3;
  if (dQ > Scalar (0))
    dQ = Scalar (0);

  // Compute the eigenvalues by solving for the roots of the polynomial.
  Scalar dMagnitude = Eigen3::internal::sqrt (-dADiv3);
  Scalar dAngle = std::atan2 (Eigen3::internal::sqrt (-dQ), dMBDiv2) * msInv3;
  Scalar dCos = Eigen3::internal::cos (dAngle);
  Scalar dSin = Eigen3::internal::sin (dAngle);
  adRoot (0) = dC2Div3 + 2.f*dMagnitude*dCos;
  adRoot (1) = dC2Div3 - dMagnitude * (dCos + msRoot3*dSin);
  adRoot (2) = dC2Div3 - dMagnitude * (dCos - msRoot3*dSin);

  // Sort in increasing order.
  if (adRoot (0) >= adRoot (1))
    std::swap (adRoot (0), adRoot (1));
  if (adRoot (1) >= adRoot (2))
  {
    std::swap (adRoot (1), adRoot (2));
    if (adRoot (0) >= adRoot (1))
      std::swap (adRoot (0), adRoot (1));
  }
}

template<typename Matrix, typename Vector> inline void
  eigen33 (const Matrix& mat, Matrix& evecs, Vector& evals)
{
  typedef typename Matrix::Scalar Scalar;
  // Scale the matrix so its entries are in [-1,1].  The scaling is applied
  // only when at least one matrix entry has magnitude larger than 1.

  Scalar scale = mat.cwiseAbs ()/*.template triangularView<Lower>()*/.maxCoeff ();
  scale = (std::max) (scale,Scalar (1));
  Matrix scaledMat = mat / scale;

  // Compute the eigenvalues
  pcl::computeRoots (scaledMat, evals);

  // compute the eigen vectors
  // here we assume 3 differents eigenvalues
  Matrix tmp;
  tmp = scaledMat;
  tmp.diagonal ().array () -= evals (0);
  evecs.col (0) = tmp.row (0).cross (tmp.row (1)).normalized ();

  tmp = scaledMat;
  tmp.diagonal ().array () -= evals (1);
  evecs.col (1) = tmp.row (0).cross (tmp.row (1)).normalized ();

  tmp = scaledMat;
  tmp.diagonal ().array () -= evals (2);
  evecs.col (2) = tmp.row (0).cross (tmp.row (1)).normalized ();
   
  // Rescale back to the original size.
  evals *= scale;
}
#endif  //#ifndef PCL_EIGEN_H_


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/