mirror of
https://gitlab.com/libeigen/eigen.git
synced 2025-08-12 11:49:02 +08:00
*patch by Daniel Gomez:
- bugfix in SparseMatrix - add a sparse unit test * renamed Transform::affine => linear
This commit is contained in:
parent
082e309d2a
commit
60804c306d
@ -95,7 +95,6 @@ template<typename ExpressionType> class Cwise
|
|||||||
const EIGEN_CWISE_UNOP_RETURN_TYPE(ei_scalar_sin_op) sin() const;
|
const EIGEN_CWISE_UNOP_RETURN_TYPE(ei_scalar_sin_op) sin() const;
|
||||||
const EIGEN_CWISE_UNOP_RETURN_TYPE(ei_scalar_pow_op) pow(const Scalar& exponent) const;
|
const EIGEN_CWISE_UNOP_RETURN_TYPE(ei_scalar_pow_op) pow(const Scalar& exponent) const;
|
||||||
|
|
||||||
|
|
||||||
const ScalarAddReturnType
|
const ScalarAddReturnType
|
||||||
operator+(const Scalar& scalar) const;
|
operator+(const Scalar& scalar) const;
|
||||||
|
|
||||||
|
@ -65,9 +65,9 @@ public:
|
|||||||
typedef _Scalar Scalar;
|
typedef _Scalar Scalar;
|
||||||
/** type of the matrix used to represent the transformation */
|
/** type of the matrix used to represent the transformation */
|
||||||
typedef Matrix<Scalar,HDim,HDim> MatrixType;
|
typedef Matrix<Scalar,HDim,HDim> MatrixType;
|
||||||
/** type of the matrix used to represent the affine part of the transformation */
|
/** type of the matrix used to represent the linear part of the transformation */
|
||||||
typedef Matrix<Scalar,Dim,Dim> AffineMatrixType;
|
typedef Matrix<Scalar,Dim,Dim> AffineMatrixType;
|
||||||
/** type of read/write reference to the affine part of the transformation */
|
/** type of read/write reference to the linear part of the transformation */
|
||||||
typedef Block<MatrixType,Dim,Dim> AffinePart;
|
typedef Block<MatrixType,Dim,Dim> AffinePart;
|
||||||
/** type of a vector */
|
/** type of a vector */
|
||||||
typedef Matrix<Scalar,Dim,1> VectorType;
|
typedef Matrix<Scalar,Dim,1> VectorType;
|
||||||
@ -110,10 +110,10 @@ public:
|
|||||||
/** \returns a writable expression of the transformation matrix */
|
/** \returns a writable expression of the transformation matrix */
|
||||||
inline MatrixType& matrix() { return m_matrix; }
|
inline MatrixType& matrix() { return m_matrix; }
|
||||||
|
|
||||||
/** \returns a read-only expression of the affine (linear) part of the transformation */
|
/** \returns a read-only expression of the linear (linear) part of the transformation */
|
||||||
inline const AffinePart affine() const { return m_matrix.template block<Dim,Dim>(0,0); }
|
inline const AffinePart linear() const { return m_matrix.template block<Dim,Dim>(0,0); }
|
||||||
/** \returns a writable expression of the affine (linear) part of the transformation */
|
/** \returns a writable expression of the linear (linear) part of the transformation */
|
||||||
inline AffinePart affine() { return m_matrix.template block<Dim,Dim>(0,0); }
|
inline AffinePart linear() { return m_matrix.template block<Dim,Dim>(0,0); }
|
||||||
|
|
||||||
/** \returns a read-only expression of the translation vector of the transformation */
|
/** \returns a read-only expression of the translation vector of the transformation */
|
||||||
inline const TranslationPart translation() const { return m_matrix.template block<Dim,1>(0,Dim); }
|
inline const TranslationPart translation() const { return m_matrix.template block<Dim,1>(0,Dim); }
|
||||||
@ -235,7 +235,7 @@ Transform<Scalar,Dim>&
|
|||||||
Transform<Scalar,Dim>::scale(const MatrixBase<OtherDerived> &other)
|
Transform<Scalar,Dim>::scale(const MatrixBase<OtherDerived> &other)
|
||||||
{
|
{
|
||||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim));
|
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim));
|
||||||
affine() = (affine() * other.asDiagonal()).lazy();
|
linear() = (linear() * other.asDiagonal()).lazy();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,7 +263,7 @@ Transform<Scalar,Dim>&
|
|||||||
Transform<Scalar,Dim>::translate(const MatrixBase<OtherDerived> &other)
|
Transform<Scalar,Dim>::translate(const MatrixBase<OtherDerived> &other)
|
||||||
{
|
{
|
||||||
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim));
|
EIGEN_STATIC_ASSERT_VECTOR_SPECIFIC_SIZE(OtherDerived,int(Dim));
|
||||||
translation() += affine() * other;
|
translation() += linear() * other;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +303,7 @@ template<typename RotationType>
|
|||||||
Transform<Scalar,Dim>&
|
Transform<Scalar,Dim>&
|
||||||
Transform<Scalar,Dim>::rotate(const RotationType& rotation)
|
Transform<Scalar,Dim>::rotate(const RotationType& rotation)
|
||||||
{
|
{
|
||||||
affine() *= ToRotationMatrix<Scalar,Dim,RotationType>::convert(rotation);
|
linear() *= ToRotationMatrix<Scalar,Dim,RotationType>::convert(rotation);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -334,8 +334,8 @@ Transform<Scalar,Dim>&
|
|||||||
Transform<Scalar,Dim>::shear(Scalar sx, Scalar sy)
|
Transform<Scalar,Dim>::shear(Scalar sx, Scalar sy)
|
||||||
{
|
{
|
||||||
EIGEN_STATIC_ASSERT(int(Dim)==2, you_did_a_programming_error);
|
EIGEN_STATIC_ASSERT(int(Dim)==2, you_did_a_programming_error);
|
||||||
VectorType tmp = affine().col(0)*sy + affine().col(1);
|
VectorType tmp = linear().col(0)*sy + linear().col(1);
|
||||||
affine() << affine().col(0) + affine().col(1)*sx, tmp;
|
linear() << linear().col(0) + linear().col(1)*sx, tmp;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,18 +360,18 @@ template<typename Scalar, int Dim>
|
|||||||
typename Transform<Scalar,Dim>::AffineMatrixType
|
typename Transform<Scalar,Dim>::AffineMatrixType
|
||||||
Transform<Scalar,Dim>::extractRotation() const
|
Transform<Scalar,Dim>::extractRotation() const
|
||||||
{
|
{
|
||||||
return affine().qr().matrixQ();
|
return linear().qr().matrixQ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \returns the rotation part of the transformation assuming no shear in
|
/** \returns the rotation part of the transformation assuming no shear in
|
||||||
* the affine part.
|
* the linear part.
|
||||||
* \sa extractRotation()
|
* \sa extractRotation()
|
||||||
*/
|
*/
|
||||||
template<typename Scalar, int Dim>
|
template<typename Scalar, int Dim>
|
||||||
typename Transform<Scalar,Dim>::AffineMatrixType
|
typename Transform<Scalar,Dim>::AffineMatrixType
|
||||||
Transform<Scalar,Dim>::extractRotationNoShear() const
|
Transform<Scalar,Dim>::extractRotationNoShear() const
|
||||||
{
|
{
|
||||||
return affine().cwise().abs2()
|
return linear().cwise().abs2()
|
||||||
.verticalRedux(ei_scalar_sum_op<Scalar>()).cwise().sqrt();
|
.verticalRedux(ei_scalar_sum_op<Scalar>()).cwise().sqrt();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,11 +384,11 @@ Transform<Scalar,Dim>&
|
|||||||
Transform<Scalar,Dim>::fromPositionOrientationScale(const MatrixBase<PositionDerived> &position,
|
Transform<Scalar,Dim>::fromPositionOrientationScale(const MatrixBase<PositionDerived> &position,
|
||||||
const OrientationType& orientation, const MatrixBase<ScaleDerived> &scale)
|
const OrientationType& orientation, const MatrixBase<ScaleDerived> &scale)
|
||||||
{
|
{
|
||||||
affine() = ToRotationMatrix<Scalar,Dim,OrientationType>::convert(orientation);
|
linear() = ToRotationMatrix<Scalar,Dim,OrientationType>::convert(orientation);
|
||||||
translation() = position;
|
translation() = position;
|
||||||
m_matrix(Dim,Dim) = 1.;
|
m_matrix(Dim,Dim) = 1.;
|
||||||
m_matrix.template block<1,Dim>(Dim,0).setZero();
|
m_matrix.template block<1,Dim>(Dim,0).setZero();
|
||||||
affine() *= scale.asDiagonal();
|
linear() *= scale.asDiagonal();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -431,7 +431,7 @@ struct ei_transform_product_impl<Other,Dim,HDim, Dim,1>
|
|||||||
> ResultType;
|
> ResultType;
|
||||||
// FIXME should we offer an optimized version when the last row is known to be 0,0...,0,1 ?
|
// FIXME should we offer an optimized version when the last row is known to be 0,0...,0,1 ?
|
||||||
static ResultType run(const TransformType& tr, const Other& other)
|
static ResultType run(const TransformType& tr, const Other& other)
|
||||||
{ return ((tr.affine().nestByValue() * other).nestByValue() + tr.translation().nestByValue()).nestByValue()
|
{ return ((tr.linear().nestByValue() * other).nestByValue() + tr.translation().nestByValue()).nestByValue()
|
||||||
* (Scalar(1) / ( (tr.matrix().template block<1,Dim>(Dim,0) * other).coeff(0) + tr.matrix().coeff(Dim,Dim))); }
|
* (Scalar(1) / ( (tr.matrix().template block<1,Dim>(Dim,0) * other).coeff(0) + tr.matrix().coeff(Dim,Dim))); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -85,11 +85,15 @@ class SparseMatrix : public SparseMatrixBase<SparseMatrix<_Scalar, _Flags> >
|
|||||||
const int inner = RowMajor ? col : row;
|
const int inner = RowMajor ? col : row;
|
||||||
|
|
||||||
int id = m_outerIndex[outer];
|
int id = m_outerIndex[outer];
|
||||||
int end = m_outerIndex[outer+1]-1;
|
int end = m_outerIndex[outer+1];
|
||||||
if (m_data.index(end)==inner)
|
// optimization: let's first check if it is the last coefficient
|
||||||
return m_data.value(end);
|
// (very common in high level algorithms)
|
||||||
|
if (end>0 && inner==m_data.index(end-1))
|
||||||
|
return m_data.value(end-1);
|
||||||
|
else if (id==end)
|
||||||
|
return Scalar(0);
|
||||||
const int* r = std::lower_bound(&m_data.index(id),&m_data.index(end),inner);
|
const int* r = std::lower_bound(&m_data.index(id),&m_data.index(end),inner);
|
||||||
return (*r==inner) ? m_data.value(*r) : Scalar(0);
|
return (*r==inner) ? m_data.value(r-&m_data.index(0)) : Scalar(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Scalar& coeffRef(int row, int col)
|
inline Scalar& coeffRef(int row, int col)
|
||||||
@ -99,9 +103,11 @@ class SparseMatrix : public SparseMatrixBase<SparseMatrix<_Scalar, _Flags> >
|
|||||||
|
|
||||||
int id = m_outerIndex[outer];
|
int id = m_outerIndex[outer];
|
||||||
int end = m_outerIndex[outer+1];
|
int end = m_outerIndex[outer+1];
|
||||||
|
ei_assert(end>=id && "you probably called coeffRef on a non finalized matrix");
|
||||||
|
ei_assert(end>id && "coeffRef cannot be called on a zero coefficient");
|
||||||
int* r = std::lower_bound(&m_data.index(id),&m_data.index(end),inner);
|
int* r = std::lower_bound(&m_data.index(id),&m_data.index(end),inner);
|
||||||
ei_assert(*r==inner);
|
ei_assert(*r==inner && "coeffRef cannot be called on a zero coefficient");
|
||||||
return m_data.value(*r);
|
return m_data.value(r-&m_data.index(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -111,5 +111,6 @@ EI_ADD_TEST(geometry)
|
|||||||
EI_ADD_TEST(regression)
|
EI_ADD_TEST(regression)
|
||||||
EI_ADD_TEST(svd)
|
EI_ADD_TEST(svd)
|
||||||
EI_ADD_TEST(ioformat)
|
EI_ADD_TEST(ioformat)
|
||||||
|
EI_ADD_TEST(sparse)
|
||||||
|
|
||||||
ENDIF(BUILD_TESTS)
|
ENDIF(BUILD_TESTS)
|
||||||
|
@ -117,9 +117,9 @@ template<typename Scalar> void geometry(void)
|
|||||||
q1 = AngleAxis(a, v0.normalized());
|
q1 = AngleAxis(a, v0.normalized());
|
||||||
Transform3 t0, t1, t2;
|
Transform3 t0, t1, t2;
|
||||||
t0.setIdentity();
|
t0.setIdentity();
|
||||||
t0.affine() = q1.toRotationMatrix();
|
t0.linear() = q1.toRotationMatrix();
|
||||||
t1.setIdentity();
|
t1.setIdentity();
|
||||||
t1.affine() = q1.toRotationMatrix();
|
t1.linear() = q1.toRotationMatrix();
|
||||||
|
|
||||||
v0 << 50, 2, 1;//= Vector3::Random().cwiseProduct(Vector3(10,2,0.5));
|
v0 << 50, 2, 1;//= Vector3::Random().cwiseProduct(Vector3(10,2,0.5));
|
||||||
t0.scale(v0);
|
t0.scale(v0);
|
||||||
@ -131,10 +131,10 @@ template<typename Scalar> void geometry(void)
|
|||||||
t0.setIdentity();
|
t0.setIdentity();
|
||||||
t1.setIdentity();
|
t1.setIdentity();
|
||||||
v1 << 1, 2, 3;
|
v1 << 1, 2, 3;
|
||||||
t0.affine() = q1.toRotationMatrix();
|
t0.linear() = q1.toRotationMatrix();
|
||||||
t0.pretranslate(v0);
|
t0.pretranslate(v0);
|
||||||
t0.scale(v1);
|
t0.scale(v1);
|
||||||
t1.affine() = q1.conjugate().toRotationMatrix();
|
t1.linear() = q1.conjugate().toRotationMatrix();
|
||||||
t1.prescale(v1.cwise().inverse());
|
t1.prescale(v1.cwise().inverse());
|
||||||
t1.translate(-v0);
|
t1.translate(-v0);
|
||||||
|
|
||||||
@ -148,12 +148,12 @@ template<typename Scalar> void geometry(void)
|
|||||||
Vector2 v20 = Vector2::Random();
|
Vector2 v20 = Vector2::Random();
|
||||||
Vector2 v21 = Vector2::Random();
|
Vector2 v21 = Vector2::Random();
|
||||||
t21.setIdentity();
|
t21.setIdentity();
|
||||||
t21.affine() = Rotation2D<Scalar>(a).toRotationMatrix();
|
t21.linear() = Rotation2D<Scalar>(a).toRotationMatrix();
|
||||||
VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(),
|
VERIFY_IS_APPROX(t20.fromPositionOrientationScale(v20,a,v21).matrix(),
|
||||||
t21.pretranslate(v20).scale(v21).matrix());
|
t21.pretranslate(v20).scale(v21).matrix());
|
||||||
|
|
||||||
t21.setIdentity();
|
t21.setIdentity();
|
||||||
t21.affine() = Rotation2D<Scalar>(-a).toRotationMatrix();
|
t21.linear() = Rotation2D<Scalar>(-a).toRotationMatrix();
|
||||||
VERIFY( (t20.fromPositionOrientationScale(v20,a,v21) * (t21.prescale(v21.cwise().inverse()).translate(-v20))).isIdentity() );
|
VERIFY( (t20.fromPositionOrientationScale(v20,a,v21) * (t21.prescale(v21.cwise().inverse()).translate(-v20))).isIdentity() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
65
test/sparse.cpp
Normal file
65
test/sparse.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// This file is part of Eigen, a lightweight C++ template library
|
||||||
|
// for linear algebra. Eigen itself is part of the KDE project.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@gmail.com>
|
||||||
|
//
|
||||||
|
// 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/>.
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
#include <Eigen/Sparse>
|
||||||
|
|
||||||
|
void test_sparse()
|
||||||
|
{
|
||||||
|
int rows = 4, cols = 4;
|
||||||
|
SparseMatrix<double> m(rows, cols);
|
||||||
|
|
||||||
|
m.startFill(rows);
|
||||||
|
m.fill(0, 2) = 2;
|
||||||
|
m.fill(1, 2) = 1;
|
||||||
|
m.fill(0, 3) = 5;
|
||||||
|
m.endFill();
|
||||||
|
|
||||||
|
m.coeffRef(0, 2) = 3;
|
||||||
|
VERIFY_RAISES_ASSERT( m.coeffRef(0, 0) = 5 );
|
||||||
|
VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(0, 0), 0.000001 );
|
||||||
|
VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(0, 1), 0.000001 );
|
||||||
|
VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(2, 1), 0.000001 );
|
||||||
|
VERIFY_IS_APPROX( m.coeff(0, 2), 3.0 );
|
||||||
|
VERIFY_IS_APPROX( m.coeff(1, 2), 1.0 );
|
||||||
|
VERIFY_IS_APPROX( m.coeff(0, 3), 5.0 );
|
||||||
|
|
||||||
|
Matrix4d dm;
|
||||||
|
double r;
|
||||||
|
m.startFill(rows*cols);
|
||||||
|
for(int i=0; i<cols; i++) {
|
||||||
|
for(int j=0; j<rows; j++) {
|
||||||
|
r = rand();
|
||||||
|
m.fill(j, i) = r;
|
||||||
|
dm(j, i) = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.endFill();
|
||||||
|
|
||||||
|
for(int i=0; i<cols; i++) {
|
||||||
|
for(int j=0; j<rows; j++) {
|
||||||
|
VERIFY_IS_APPROX( m.coeff(j, i), dm(j, i) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user