From 9f14d7292799b5e73c64602a92744af76a0a5aec Mon Sep 17 00:00:00 2001 From: Jitse Niesen Date: Thu, 10 Sep 2009 09:22:06 +0100 Subject: [PATCH 01/83] Remove no-op statement in AlignedVector3. --- unsupported/Eigen/AlignedVector3 | 1 - 1 file changed, 1 deletion(-) diff --git a/unsupported/Eigen/AlignedVector3 b/unsupported/Eigen/AlignedVector3 index 854f0601f..aaec5f98a 100644 --- a/unsupported/Eigen/AlignedVector3 +++ b/unsupported/Eigen/AlignedVector3 @@ -152,7 +152,6 @@ template class AlignedVector3 { ei_assert(m_coeffs.w()==Scalar(0)); ei_assert(other.m_coeffs.w()==Scalar(0)); - Scalar r = m_coeffs.dot(other.m_coeffs); return m_coeffs.dot(other.m_coeffs); } From d5319f4ba8709d093cebfdf3030e26d5f4b9de4e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 15 Sep 2009 11:16:58 +0200 Subject: [PATCH 02/83] fix warning in stable norm --- Eigen/src/Core/StableNorm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/StableNorm.h b/Eigen/src/Core/StableNorm.h index 77fe79782..facab9dbd 100644 --- a/Eigen/src/Core/StableNorm.h +++ b/Eigen/src/Core/StableNorm.h @@ -56,7 +56,7 @@ MatrixBase::stableNorm() const { const int blockSize = 4096; RealScalar scale = 0; - RealScalar invScale; + RealScalar invScale = 1; RealScalar ssq = 0; // sum of square enum { Alignment = (int(Flags)&DirectAccessBit) || (int(Flags)&AlignedBit) ? ForceAligned : AsRequested From 432fcefcb1ddffd8293ec2443234232eb64f199c Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 15 Sep 2009 11:27:31 +0200 Subject: [PATCH 03/83] fix warning with gcc 4.2 --- unsupported/Eigen/AlignedVector3 | 60 ++++++++++++++++---------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/unsupported/Eigen/AlignedVector3 b/unsupported/Eigen/AlignedVector3 index aaec5f98a..f20fad6d1 100644 --- a/unsupported/Eigen/AlignedVector3 +++ b/unsupported/Eigen/AlignedVector3 @@ -63,37 +63,37 @@ template class AlignedVector3 typedef Matrix<_Scalar,4,1> CoeffType; CoeffType m_coeffs; public: - + EIGEN_GENERIC_PUBLIC_INTERFACE(AlignedVector3) using Base::operator*; - + inline int rows() const { return 3; } inline int cols() const { return 1; } - + inline const Scalar& coeff(int row, int col) const { return m_coeffs.coeff(row, col); } - + inline Scalar& coeffRef(int row, int col) { return m_coeffs.coeffRef(row, col); } - + inline const Scalar& coeff(int index) const { return m_coeffs.coeff(index); } inline Scalar& coeffRef(int index) { return m_coeffs.coeffRef(index);} - - + + inline AlignedVector3(const Scalar& x, const Scalar& y, const Scalar& z) : m_coeffs(x, y, z, Scalar(0)) {} - + inline AlignedVector3(const AlignedVector3& other) - : m_coeffs(other.m_coeffs) + : Base(), m_coeffs(other.m_coeffs) {} - + template struct generic_assign_selector {}; - + template struct generic_assign_selector { inline static void run(AlignedVector3& dest, const XprType& src) @@ -101,7 +101,7 @@ template class AlignedVector3 dest.m_coeffs = src; } }; - + template struct generic_assign_selector { inline static void run(AlignedVector3& dest, const XprType& src) @@ -110,44 +110,44 @@ template class AlignedVector3 dest.m_coeffs.w() = Scalar(0); } }; - + template inline explicit AlignedVector3(const MatrixBase& other) { generic_assign_selector::run(*this,other.derived()); } - + inline AlignedVector3& operator=(const AlignedVector3& other) { m_coeffs = other.m_coeffs; return *this; } - - + + inline AlignedVector3 operator+(const AlignedVector3& other) const { return AlignedVector3(m_coeffs + other.m_coeffs); } - + inline AlignedVector3& operator+=(const AlignedVector3& other) { m_coeffs += other.m_coeffs; return *this; } - + inline AlignedVector3 operator-(const AlignedVector3& other) const { return AlignedVector3(m_coeffs - other.m_coeffs); } - + inline AlignedVector3 operator-=(const AlignedVector3& other) { m_coeffs -= other.m_coeffs; return *this; } - + inline AlignedVector3 operator*(const Scalar& s) const { return AlignedVector3(m_coeffs * s); } - + inline friend AlignedVector3 operator*(const Scalar& s,const AlignedVector3& vec) { return AlignedVector3(s * vec.m_coeffs); } - + inline AlignedVector3& operator*=(const Scalar& s) { m_coeffs *= s; return *this; } - + inline AlignedVector3 operator/(const Scalar& s) const { return AlignedVector3(m_coeffs / s); } - + inline AlignedVector3& operator/=(const Scalar& s) { m_coeffs /= s; return *this; } - + inline Scalar dot(const AlignedVector3& other) const { ei_assert(m_coeffs.w()==Scalar(0)); @@ -164,29 +164,29 @@ template class AlignedVector3 { return AlignedVector3(m_coeffs / norm()); } - + inline Scalar sum() const { ei_assert(m_coeffs.w()==Scalar(0)); return m_coeffs.sum(); } - + inline Scalar squaredNorm() const { ei_assert(m_coeffs.w()==Scalar(0)); return m_coeffs.squaredNorm(); } - + inline Scalar norm() const { return ei_sqrt(squaredNorm()); } - + inline AlignedVector3 cross(const AlignedVector3& other) const { return AlignedVector3(m_coeffs.cross3(other.m_coeffs)); } - + template inline bool isApprox(const MatrixBase& other, RealScalar eps=precision()) const { From 9e9abab2b90f7ed006687dc5e3f1671f57e61015 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 15 Sep 2009 11:53:24 +0200 Subject: [PATCH 04/83] bugfixes for ICC (compilation and runtime) --- Eigen/src/SVD/JacobiSVD.h | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index 2801ee077..4b69e67c4 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -25,6 +25,22 @@ #ifndef EIGEN_JACOBISVD_H #define EIGEN_JACOBISVD_H +// forward declarations (needed by ICC) +template::IsComplex> +struct ei_svd_precondition_2x2_block_to_be_real; + +templateMatrixType::ColsAtCompileTime))> +struct ei_svd_precondition_if_more_rows_than_cols; + +templateMatrixType::RowsAtCompileTime))> +struct ei_svd_precondition_if_more_cols_than_rows; + /** \ingroup SVD_Module * \nonstableyet * @@ -118,8 +134,8 @@ template class JacobiSVD friend struct ei_svd_precondition_if_more_cols_than_rows; }; -template::IsComplex> -struct ei_svd_precondition_2x2_block_to_be_real +template +struct ei_svd_precondition_2x2_block_to_be_real { typedef JacobiSVD SVD; static void run(typename SVD::WorkMatrixType&, JacobiSVD&, int, int) {} @@ -195,10 +211,7 @@ void ei_real_2x2_jacobi_svd(const MatrixType& matrix, int p, int q, *j_left = rot1 * j_right->transpose(); } -templateMatrixType::ColsAtCompileTime)> +template struct ei_svd_precondition_if_more_rows_than_cols { typedef JacobiSVD SVD; @@ -231,10 +244,7 @@ struct ei_svd_precondition_if_more_rows_than_cols } }; -templateMatrixType::RowsAtCompileTime)> +template struct ei_svd_precondition_if_more_cols_than_rows { typedef JacobiSVD SVD; @@ -256,7 +266,7 @@ struct ei_svd_precondition_if_more_cols_than_rows MaxColsAtCompileTime = SVD::MaxColsAtCompileTime, MatrixOptions = SVD::MatrixOptions }; - + static bool run(const MatrixType& matrix, typename SVD::WorkMatrixType& work_matrix, SVD& svd) { int rows = matrix.rows(); From 4a6e5694d60ef0dab6ed17e563372c94a2744a31 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Tue, 15 Sep 2009 13:03:24 +0200 Subject: [PATCH 05/83] disable warning 279: controlling expression is constant for ICC --- test/main.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/main.h b/test/main.h index 619fc9e06..8c93e856c 100644 --- a/test/main.h +++ b/test/main.h @@ -40,6 +40,11 @@ #define DEFAULT_REPEAT 10 +#ifdef __ICC +// disable warning #279: controlling expression is constant +#pragma warning disable 279 +#endif + namespace Eigen { static std::vector g_test_stack; From 46be9c9ac14fc951599ecd5dc7cd3c1a44f8b9d5 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 16 Sep 2009 14:18:30 -0400 Subject: [PATCH 06/83] * fix super nasty bug: vector.maxCoeff(&index) didn't work when 'vector' was a row-vector. Fixed by splitting the vector version from the matrix version. * add unit test, the visitors weren't covered by any test!! --- Eigen/src/Core/MatrixBase.h | 7 +- Eigen/src/Core/Visitor.h | 33 ++++++++- test/CMakeLists.txt | 1 + test/redux.cpp | 2 +- test/visitor.cpp | 131 ++++++++++++++++++++++++++++++++++++ 5 files changed, 170 insertions(+), 4 deletions(-) create mode 100644 test/visitor.cpp diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 25a0545c6..f267aa34d 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -675,8 +675,11 @@ template class MatrixBase typename ei_traits::Scalar minCoeff() const; typename ei_traits::Scalar maxCoeff() const; - typename ei_traits::Scalar minCoeff(int* row, int* col = 0) const; - typename ei_traits::Scalar maxCoeff(int* row, int* col = 0) const; + typename ei_traits::Scalar minCoeff(int* row, int* col) const; + typename ei_traits::Scalar maxCoeff(int* row, int* col) const; + + typename ei_traits::Scalar minCoeff(int* index) const; + typename ei_traits::Scalar maxCoeff(int* index) const; template typename ei_result_of::Scalar)>::type diff --git a/Eigen/src/Core/Visitor.h b/Eigen/src/Core/Visitor.h index 598c2db8d..590efc766 100644 --- a/Eigen/src/Core/Visitor.h +++ b/Eigen/src/Core/Visitor.h @@ -164,7 +164,7 @@ struct ei_functor_traits > { /** \returns the minimum of all coefficients of *this * and puts in *row and *col its location. * - * \sa MatrixBase::maxCoeff(int*,int*), MatrixBase::visitor(), MatrixBase::minCoeff() + * \sa MatrixBase::minCoeff(int*), MatrixBase::maxCoeff(int*,int*), MatrixBase::visitor(), MatrixBase::minCoeff() */ template typename ei_traits::Scalar @@ -177,6 +177,22 @@ MatrixBase::minCoeff(int* row, int* col) const return minVisitor.res; } +/** \returns the minimum of all coefficients of *this + * and puts in *index its location. + * + * \sa MatrixBase::minCoeff(int*,int*), MatrixBase::maxCoeff(int*,int*), MatrixBase::visitor(), MatrixBase::minCoeff() + */ +template +typename ei_traits::Scalar +MatrixBase::minCoeff(int* index) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + ei_min_coeff_visitor minVisitor; + this->visit(minVisitor); + *index = (RowsAtCompileTime==1) ? minVisitor.col : minVisitor.row; + return minVisitor.res; +} + /** \returns the maximum of all coefficients of *this * and puts in *row and *col its location. * @@ -193,5 +209,20 @@ MatrixBase::maxCoeff(int* row, int* col) const return maxVisitor.res; } +/** \returns the maximum of all coefficients of *this + * and puts in *index its location. + * + * \sa MatrixBase::maxCoeff(int*,int*), MatrixBase::minCoeff(int*,int*), MatrixBase::visitor(), MatrixBase::maxCoeff() + */ +template +typename ei_traits::Scalar +MatrixBase::maxCoeff(int* index) const +{ + EIGEN_STATIC_ASSERT_VECTOR_ONLY(Derived) + ei_max_coeff_visitor maxVisitor; + this->visit(maxVisitor); + *index = (RowsAtCompileTime==1) ? maxVisitor.col : maxVisitor.row; + return maxVisitor.res; +} #endif // EIGEN_VISITOR_H diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4e279ea47..f3c15612f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -94,6 +94,7 @@ ei_add_test(basicstuff) ei_add_test(linearstructure) ei_add_test(cwiseop) ei_add_test(redux) +ei_add_test(visitor) ei_add_test(product_small) ei_add_test(product_large ${EI_OFLAG}) ei_add_test(product_extra ${EI_OFLAG}) diff --git a/test/redux.cpp b/test/redux.cpp index 2a0dc97f1..b929fdc0e 100644 --- a/test/redux.cpp +++ b/test/redux.cpp @@ -120,7 +120,7 @@ void test_redux() CALL_SUBTEST( matrixRedux(MatrixXi(8, 12)) ); } for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( vectorRedux(VectorXf(5)) ); + CALL_SUBTEST( vectorRedux(VectorX4f()) ); CALL_SUBTEST( vectorRedux(VectorXd(10)) ); CALL_SUBTEST( vectorRedux(VectorXf(33)) ); } diff --git a/test/visitor.cpp b/test/visitor.cpp new file mode 100644 index 000000000..b78782b78 --- /dev/null +++ b/test/visitor.cpp @@ -0,0 +1,131 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2008 Benoit Jacob +// +// 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 . + +#include "main.h" + +template void matrixVisitor(const MatrixType& p) +{ + typedef typename MatrixType::Scalar Scalar; + + int rows = p.rows(); + int cols = p.cols(); + + // construct a random matrix where all coefficients are different + MatrixType m; + m = MatrixType::Random(rows, cols); + for(int i = 0; i < m.size(); i++) + for(int i2 = 0; i2 < i; i2++) + while(m(i) == m(i2)) // yes, == + m(i) = ei_random(); + + Scalar minc = Scalar(1000), maxc = Scalar(-1000); + int minrow,mincol,maxrow,maxcol; + for(int j = 0; j < cols; j++) + for(int i = 0; i < rows; i++) + { + if(m(i,j) < minc) + { + minc = m(i,j); + minrow = i; + mincol = j; + } + if(m(i,j) > maxc) + { + maxc = m(i,j); + maxrow = i; + maxcol = j; + } + } + int eigen_minrow, eigen_mincol, eigen_maxrow, eigen_maxcol; + Scalar eigen_minc, eigen_maxc; + eigen_minc = m.minCoeff(&eigen_minrow,&eigen_mincol); + eigen_maxc = m.maxCoeff(&eigen_maxrow,&eigen_maxcol); + VERIFY(minrow == eigen_minrow); + VERIFY(maxrow == eigen_maxrow); + VERIFY(mincol == eigen_mincol); + VERIFY(maxcol == eigen_maxcol); + VERIFY_IS_APPROX(minc, eigen_minc); + VERIFY_IS_APPROX(maxc, eigen_maxc); + VERIFY_IS_APPROX(minc, m.minCoeff()); + VERIFY_IS_APPROX(maxc, m.maxCoeff()); +} + +template void vectorVisitor(const VectorType& w) +{ + typedef typename VectorType::Scalar Scalar; + + int size = w.size(); + + // construct a random vector where all coefficients are different + VectorType v; + v = VectorType::Random(size); + for(int i = 0; i < size; i++) + for(int i2 = 0; i2 < i; i2++) + while(v(i) == v(i2)) // yes, == + v(i) = ei_random(); + + Scalar minc = Scalar(1000), maxc = Scalar(-1000); + int minidx,maxidx; + for(int i = 0; i < size; i++) + { + if(v(i) < minc) + { + minc = v(i); + minidx = i; + } + if(v(i) > maxc) + { + maxc = v(i); + maxidx = i; + } + } + int eigen_minidx, eigen_maxidx; + Scalar eigen_minc, eigen_maxc; + eigen_minc = v.minCoeff(&eigen_minidx); + eigen_maxc = v.maxCoeff(&eigen_maxidx); + VERIFY(minidx == eigen_minidx); + VERIFY(maxidx == eigen_maxidx); + VERIFY_IS_APPROX(minc, eigen_minc); + VERIFY_IS_APPROX(maxc, eigen_maxc); + VERIFY_IS_APPROX(minc, v.minCoeff()); + VERIFY_IS_APPROX(maxc, v.maxCoeff()); +} + +void test_visitor() +{ + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST( matrixVisitor(Matrix()) ); + CALL_SUBTEST( matrixVisitor(Matrix2f()) ); + CALL_SUBTEST( matrixVisitor(Matrix4d()) ); + CALL_SUBTEST( matrixVisitor(MatrixXd(8, 12)) ); + CALL_SUBTEST( matrixVisitor(Matrix(20, 20)) ); + CALL_SUBTEST( matrixVisitor(MatrixXi(8, 12)) ); + } + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST( vectorVisitor(Vector4f()) ); + CALL_SUBTEST( vectorVisitor(VectorXd(10)) ); + CALL_SUBTEST( vectorVisitor(RowVectorXd(10)) ); + CALL_SUBTEST( vectorVisitor(VectorXf(33)) ); + } +} From a4fd0aa25b1de432976ab9dc371abf9073db0fab Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 16 Sep 2009 14:19:59 -0400 Subject: [PATCH 07/83] * fix bug in col-pivoting qr, forgot to swap the colNorms when swapping cols * add Gael a copyright line --- Eigen/src/LU/PartialLU.h | 1 + Eigen/src/QR/ColPivotingHouseholderQR.h | 1 + test/qr_colpivoting.cpp | 4 +--- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Eigen/src/LU/PartialLU.h b/Eigen/src/LU/PartialLU.h index 0ef59bac7..20ebd9d6a 100644 --- a/Eigen/src/LU/PartialLU.h +++ b/Eigen/src/LU/PartialLU.h @@ -2,6 +2,7 @@ // for linear algebra. // // Copyright (C) 2006-2009 Benoit Jacob +// Copyright (C) 2009 Gael Guennebaud // // Eigen is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff --git a/Eigen/src/QR/ColPivotingHouseholderQR.h b/Eigen/src/QR/ColPivotingHouseholderQR.h index 8024e3b9d..883e3449f 100644 --- a/Eigen/src/QR/ColPivotingHouseholderQR.h +++ b/Eigen/src/QR/ColPivotingHouseholderQR.h @@ -306,6 +306,7 @@ ColPivotingHouseholderQR& ColPivotingHouseholderQR::comp cols_transpositions.coeffRef(k) = biggest_col_in_corner; if(k != biggest_col_in_corner) { m_qr.col(k).swap(m_qr.col(biggest_col_in_corner)); + std::swap(colSqNorms.coeffRef(k), colSqNorms.coeffRef(biggest_col_in_corner)); ++number_of_transpositions; } diff --git a/test/qr_colpivoting.cpp b/test/qr_colpivoting.cpp index 283855451..9c387005a 100644 --- a/test/qr_colpivoting.cpp +++ b/test/qr_colpivoting.cpp @@ -116,9 +116,7 @@ template void qr_verify_assert() void test_qr_colpivoting() { - for(int i = 0; i < 1; i++) { - // FIXME : very weird bug here -// CALL_SUBTEST( qr(Matrix2f()) ); + for(int i = 0; i < 1; i++) { CALL_SUBTEST( qr() ); CALL_SUBTEST( qr() ); CALL_SUBTEST( qr() ); From 77f858f6abf0e80eddf33b01d8dd3598be3fd7a3 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 16 Sep 2009 14:34:08 +0200 Subject: [PATCH 08/83] improve ComplexShur api and doc --- Eigen/src/Eigenvalues/ComplexSchur.h | 54 ++++++++++++++----- .../src/Eigenvalues/HessenbergDecomposition.h | 6 +-- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/Eigen/src/Eigenvalues/ComplexSchur.h b/Eigen/src/Eigenvalues/ComplexSchur.h index 58e2ea440..0534715c4 100644 --- a/Eigen/src/Eigenvalues/ComplexSchur.h +++ b/Eigen/src/Eigenvalues/ComplexSchur.h @@ -31,8 +31,15 @@ * * \class ComplexShur * - * \brief Performs a complex Shur decomposition of a real or complex square matrix + * \brief Performs a complex Schur decomposition of a real or complex square matrix * + * Given a real or complex square matrix A, this class computes the Schur decomposition: + * \f$ A = U T U^*\f$ where U is a unitary complex matrix, and T is a complex upper + * triangular matrix. + * + * The diagonal of the matrix T corresponds to the eigenvalues of the matrix A. + * + * \sa class RealSchur, class EigenSolver */ template class ComplexSchur { @@ -42,41 +49,56 @@ template class ComplexSchur typedef typename NumTraits::Real RealScalar; typedef std::complex Complex; typedef Matrix ComplexMatrixType; + enum { + Size = MatrixType::RowsAtCompileTime + }; - /** - * \brief Default Constructor. + /** \brief Default Constructor. * * The default constructor is useful in cases in which the user intends to - * perform decompositions via ComplexSchur::compute(const MatrixType&). + * perform decompositions via ComplexSchur::compute(). */ - ComplexSchur() : m_matT(), m_matU(), m_isInitialized(false) + ComplexSchur(int size = Size==Dynamic ? 0 : Size) + : m_matT(size,size), m_matU(size,size), m_isInitialized(false), m_matUisUptodate(false) {} - ComplexSchur(const MatrixType& matrix) + /** Constructor computing the Schur decomposition of the matrix \a matrix. + * If \a skipU is true, then the matrix U is not computed. */ + ComplexSchur(const MatrixType& matrix, bool skipU = false) : m_matT(matrix.rows(),matrix.cols()), m_matU(matrix.rows(),matrix.cols()), - m_isInitialized(false) + m_isInitialized(false), + m_matUisUptodate(false) { - compute(matrix); + compute(matrix, skipU); } - ComplexMatrixType matrixU() const + /** \returns a const reference to the matrix U of the respective Schur decomposition. */ + const ComplexMatrixType& matrixU() const { ei_assert(m_isInitialized && "ComplexSchur is not initialized."); + ei_assert(m_matUisUptodate && "The matrix U has not been computed during the ComplexSchur decomposition."); return m_matU; } - ComplexMatrixType matrixT() const + /** \returns a const reference to the matrix T of the respective Schur decomposition. + * Note that this function returns a plain square matrix. If you want to reference + * only the upper triangular part, use: + * \code schur.matrixT().triangularView() \endcode. */ + const ComplexMatrixType& matrixT() const { ei_assert(m_isInitialized && "ComplexShur is not initialized."); return m_matT; } - void compute(const MatrixType& matrix); + /** Computes the Schur decomposition of the matrix \a matrix. + * If \a skipU is true, then the matrix U is not computed. */ + void compute(const MatrixType& matrix, bool skipU = false); protected: ComplexMatrixType m_matT, m_matU; bool m_isInitialized; + bool m_matUisUptodate; }; /** Computes the principal value of the square root of the complex \a z. */ @@ -117,17 +139,20 @@ std::complex ei_sqrt(const std::complex &z) } template -void ComplexSchur::compute(const MatrixType& matrix) +void ComplexSchur::compute(const MatrixType& matrix, bool skipU) { // this code is inspired from Jampack + + m_matUisUptodate = false; assert(matrix.cols() == matrix.rows()); int n = matrix.cols(); // Reduce to Hessenberg form + // TODO skip Q if skipU = true HessenbergDecomposition hess(matrix); m_matT = hess.matrixH(); - m_matU = hess.matrixQ(); + if(!skipU) m_matU = hess.matrixQ(); int iu = m_matT.cols() - 1; int il; @@ -206,7 +231,7 @@ void ComplexSchur::compute(const MatrixType& matrix) { m_matT.block(0,i,n,n-i).applyOnTheLeft(i, i+1, rot.adjoint()); m_matT.block(0,0,std::min(i+2,iu)+1,n).applyOnTheRight(i, i+1, rot); - m_matU.applyOnTheRight(i, i+1, rot); + if(!skipU) m_matU.applyOnTheRight(i, i+1, rot); if(i != iu-1) { @@ -232,6 +257,7 @@ void ComplexSchur::compute(const MatrixType& matrix) */ m_isInitialized = true; + m_matUisUptodate = !skipU; } #endif // EIGEN_COMPLEX_SCHUR_H diff --git a/Eigen/src/Eigenvalues/HessenbergDecomposition.h b/Eigen/src/Eigenvalues/HessenbergDecomposition.h index b1e21d4ee..bb7e3fcfc 100644 --- a/Eigen/src/Eigenvalues/HessenbergDecomposition.h +++ b/Eigen/src/Eigenvalues/HessenbergDecomposition.h @@ -88,14 +88,14 @@ template class HessenbergDecomposition _compute(m_matrix, m_hCoeffs); } - /** \returns the householder coefficients allowing to + /** \returns a const reference to the householder coefficients allowing to * reconstruct the matrix Q from the packed data. * * \sa packedMatrix() */ - CoeffVectorType householderCoefficients() const { return m_hCoeffs; } + const CoeffVectorType& householderCoefficients() const { return m_hCoeffs; } - /** \returns the internal result of the decomposition. + /** \returns a const reference to the internal representation of the decomposition. * * The returned matrix contains the following information: * - the upper part and lower sub-diagonal represent the Hessenberg matrix H From 49dd5d7847e4439f30de37de8372c9483b63b425 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 16 Sep 2009 14:35:42 +0200 Subject: [PATCH 09/83] * add a HouseholderSequence class (not good enough yet for Triadiagonalization and HessenbergDecomposition) * rework a bit AnyMatrixBase, and mobe it to a separate file --- Eigen/Core | 1 + Eigen/Householder | 1 + Eigen/src/Core/AnyMatrixBase.h | 153 ++++++++++++++++++++ Eigen/src/Core/MatrixBase.h | 58 ++------ Eigen/src/Core/Product.h | 14 -- Eigen/src/Core/TriangularMatrix.h | 12 +- Eigen/src/Core/util/ForwardDeclarations.h | 1 + Eigen/src/Householder/HouseholderSequence.h | 146 +++++++++++++++++++ Eigen/src/QR/HouseholderQR.h | 37 ++--- test/householder.cpp | 9 +- test/jacobisvd.cpp | 8 +- test/qr.cpp | 2 +- 12 files changed, 339 insertions(+), 103 deletions(-) create mode 100644 Eigen/src/Core/AnyMatrixBase.h create mode 100644 Eigen/src/Householder/HouseholderSequence.h diff --git a/Eigen/Core b/Eigen/Core index 854f737d6..42eb363a9 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -143,6 +143,7 @@ namespace Eigen { #include "src/Core/Functors.h" #include "src/Core/MatrixBase.h" +#include "src/Core/AnyMatrixBase.h" #include "src/Core/Coeffs.h" #ifndef EIGEN_PARSED_BY_DOXYGEN // work around Doxygen bug triggered by Assign.h r814874 diff --git a/Eigen/Householder b/Eigen/Householder index ba06bd8fb..ef3e61373 100644 --- a/Eigen/Householder +++ b/Eigen/Householder @@ -16,6 +16,7 @@ namespace Eigen { */ #include "src/Householder/Householder.h" +#include "src/Householder/HouseholderSequence.h" } // namespace Eigen diff --git a/Eigen/src/Core/AnyMatrixBase.h b/Eigen/src/Core/AnyMatrixBase.h new file mode 100644 index 000000000..cd354d7b1 --- /dev/null +++ b/Eigen/src/Core/AnyMatrixBase.h @@ -0,0 +1,153 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Benoit Jacob +// Copyright (C) 2009 Gael Guennebaud +// +// 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 . + +#ifndef EIGEN_ANYMATRIXBASE_H +#define EIGEN_ANYMATRIXBASE_H + + +/** Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). + * + * In other words, an AnyMatrixBase object is an object that can be copied into a MatrixBase. + * + * Besides MatrixBase-derived classes, this also includes special matrix classes such as diagonal matrices, etc. + * + * Notice that this class is trivial, it is only used to disambiguate overloaded functions. + */ +template struct AnyMatrixBase +{ + typedef typename ei_plain_matrix_type::type PlainMatrixType; + + Derived& derived() { return *static_cast(this); } + const Derived& derived() const { return *static_cast(this); } + + /** \returns the number of rows. \sa cols(), RowsAtCompileTime */ + inline int rows() const { return derived().rows(); } + /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/ + inline int cols() const { return derived().cols(); } + + /** \internal Don't use it, but do the equivalent: \code dst = *this; \endcode */ + template inline void evalTo(Dest& dst) const + { derived().evalTo(dst); } + + /** \internal Don't use it, but do the equivalent: \code dst += *this; \endcode */ + template inline void addToDense(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + typename Dest::PlainMatrixType res(rows(),cols()); + evalTo(res); + dst += res; + } + + /** \internal Don't use it, but do the equivalent: \code dst -= *this; \endcode */ + template inline void subToDense(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + typename Dest::PlainMatrixType res(rows(),cols()); + evalTo(res); + dst -= res; + } + + /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheRight(*this); \endcode */ + template inline void applyThisOnTheRight(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + dst = dst * this->derived(); + } + + /** \internal Don't use it, but do the equivalent: \code dst.applyOnTheLeft(*this); \endcode */ + template inline void applyThisOnTheLeft(Dest& dst) const + { + // This is the default implementation, + // derived class can reimplement it in a more optimized way. + dst = this->derived() * dst; + } + +}; + +/*************************************************************************** +* Implementation of matrix base methods +***************************************************************************/ + +/** Copies the generic expression \a other into *this. \returns a reference to *this. + * The expression must provide a (templated) evalToDense(Derived& dst) const function + * which does the actual job. In practice, this allows any user to write its own + * special matrix without having to modify MatrixBase */ +template +template +Derived& MatrixBase::operator=(const AnyMatrixBase &other) +{ + other.derived().evalTo(derived()); + return derived(); +} + +template +template +Derived& MatrixBase::operator+=(const AnyMatrixBase &other) +{ + other.derived().addToDense(derived()); + return derived(); +} + +template +template +Derived& MatrixBase::operator-=(const AnyMatrixBase &other) +{ + other.derived().subToDense(derived()); + return derived(); +} + +/** replaces \c *this by \c *this * \a other. + * + * \returns a reference to \c *this + */ +template +template +inline Derived& +MatrixBase::operator*=(const AnyMatrixBase &other) +{ + other.derived().applyThisOnTheRight(derived()); + return derived(); +} + +/** replaces \c *this by \c *this * \a other. It is equivalent to MatrixBase::operator*=() */ +template +template +inline void MatrixBase::applyOnTheRight(const AnyMatrixBase &other) +{ + other.derived().applyThisOnTheRight(derived()); +} + +/** replaces \c *this by \c *this * \a other. */ +template +template +inline void MatrixBase::applyOnTheLeft(const AnyMatrixBase &other) +{ + other.derived().applyThisOnTheLeft(derived()); +} + +#endif // EIGEN_ANYMATRIXBASE_H diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index f267aa34d..4835f167c 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -26,44 +26,6 @@ #ifndef EIGEN_MATRIXBASE_H #define EIGEN_MATRIXBASE_H - -/** Common base class for all classes T such that MatrixBase has an operator=(T) and a constructor MatrixBase(T). - * - * In other words, an AnyMatrixBase object is an object that can be copied into a MatrixBase. - * - * Besides MatrixBase-derived classes, this also includes special matrix classes such as diagonal matrices, etc. - * - * Notice that this class is trivial, it is only used to disambiguate overloaded functions. - */ -template struct AnyMatrixBase -{ - typedef typename ei_plain_matrix_type::type PlainMatrixType; - - Derived& derived() { return *static_cast(this); } - const Derived& derived() const { return *static_cast(this); } - /** \returns the number of rows. \sa cols(), RowsAtCompileTime */ - inline int rows() const { return derived().rows(); } - /** \returns the number of columns. \sa rows(), ColsAtCompileTime*/ - inline int cols() const { return derived().cols(); } - - template inline void evalTo(Dest& dst) const - { derived().evalTo(dst); } - - template inline void addToDense(Dest& dst) const - { - typename Dest::PlainMatrixType res(rows(),cols()); - evalToDense(res); - dst += res; - } - - template inline void subToDense(Dest& dst) const - { - typename Dest::PlainMatrixType res(rows(),cols()); - evalToDense(res); - dst -= res; - } -}; - /** \class MatrixBase * * \brief Base class for all matrices, vectors, and expressions @@ -96,7 +58,6 @@ template class MatrixBase #endif // not EIGEN_PARSED_BY_DOXYGEN { public: - #ifndef EIGEN_PARSED_BY_DOXYGEN using ei_special_scalar_op_base::Scalar, typename NumTraits::Scalar>::Real>::operator*; @@ -301,21 +262,14 @@ template class MatrixBase */ Derived& operator=(const MatrixBase& other); - /** Copies the generic expression \a other into *this. \returns a reference to *this. - * The expression must provide a (templated) evalToDense(Derived& dst) const function - * which does the actual job. In practice, this allows any user to write its own - * special matrix without having to modify MatrixBase */ template - Derived& operator=(const AnyMatrixBase &other) - { other.derived().evalToDense(derived()); return derived(); } + Derived& operator=(const AnyMatrixBase &other); template - Derived& operator+=(const AnyMatrixBase &other) - { other.derived().addToDense(derived()); return derived(); } + Derived& operator+=(const AnyMatrixBase &other); template - Derived& operator-=(const AnyMatrixBase &other) - { other.derived().subToDense(derived()); return derived(); } + Derived& operator-=(const AnyMatrixBase &other); template Derived& operator=(const ReturnByValue& func); @@ -436,6 +390,12 @@ template class MatrixBase template Derived& operator*=(const AnyMatrixBase& other); + template + void applyOnTheLeft(const AnyMatrixBase& other); + + template + void applyOnTheRight(const AnyMatrixBase& other); + template const DiagonalProduct operator*(const DiagonalBase &diagonal) const; diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index e7227d4f6..7f0c2df6e 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -434,18 +434,4 @@ MatrixBase::operator*(const MatrixBase &other) const return typename ProductReturnType::Type(derived(), other.derived()); } - - -/** replaces \c *this by \c *this * \a other. - * - * \returns a reference to \c *this - */ -template -template -inline Derived & -MatrixBase::operator*=(const AnyMatrixBase &other) -{ - return derived() = derived() * other.derived(); -} - #endif // EIGEN_PRODUCT_H diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index b0362f20c..17726bca3 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -91,9 +91,9 @@ template class TriangularBase : public AnyMatrixBase #endif // not EIGEN_PARSED_BY_DOXYGEN template - void evalToDense(MatrixBase &other) const; + void evalTo(MatrixBase &other) const; template - void evalToDenseLazy(MatrixBase &other) const; + void evalToLazy(MatrixBase &other) const; protected: @@ -546,23 +546,23 @@ void TriangularView::lazyAssign(const TriangularBase template -void TriangularBase::evalToDense(MatrixBase &other) const +void TriangularBase::evalTo(MatrixBase &other) const { if(ei_traits::Flags & EvalBeforeAssigningBit) { typename Derived::PlainMatrixType other_evaluated(rows(), cols()); - evalToDenseLazy(other_evaluated); + evalToLazy(other_evaluated); other.derived().swap(other_evaluated); } else - evalToDenseLazy(other.derived()); + evalToLazy(other.derived()); } /** Assigns a triangular or selfadjoint matrix to a dense matrix. * If the matrix is triangular, the opposite part is set to zero. */ template template -void TriangularBase::evalToDenseLazy(MatrixBase &other) const +void TriangularBase::evalToLazy(MatrixBase &other) const { const bool unroll = DenseDerived::SizeAtCompileTime * Derived::CoeffReadCost / 2 <= EIGEN_UNROLLING_LIMIT; diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index c5f27d80b..3f66738f0 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -123,6 +123,7 @@ template class SVD; template class JacobiSVD; template class LLT; template class LDLT; +template class HouseholderSequence; template class PlanarRotation; // Geometry module: diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h new file mode 100644 index 000000000..86395213b --- /dev/null +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -0,0 +1,146 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// 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 . + +#ifndef EIGEN_HOUSEHOLDER_SEQUENCE_H +#define EIGEN_HOUSEHOLDER_SEQUENCE_H + +/** \ingroup Householder_Module + * \householder_module + * \class HouseholderSequence + * \brief Represents a sequence of householder reflections with decreasing size + * + * This class represents a product sequence of householder reflections \f$ H = \Pi_0^{n-1} H_i \f$ + * where \f$ H_i \f$ is the i-th householder transformation \f$ I - h_i v_i v_i^* \f$, + * \f$ v_i \f$ is the i-th householder vector \f$ [ 1, m_vectors(i+1,i), m_vectors(i+2,i), ...] \f$ + * and \f$ h_i \f$ is the i-th householder coefficient \c m_coeffs[i]. + * + * Typical usages are listed below, where H is a HouseholderSequence: + * \code + * A.applyOnTheRight(H); // A = A * H + * A.applyOnTheLeft(H); // A = H * A + * A.applyOnTheRight(H.adjoint()); // A = A * H^* + * A.applyOnTheLeft(H.adjoint()); // A = H^* * A + * MatrixXd Q = H; // conversion to a dense matrix + * \endcode + * In addition to the adjoint, you can also apply the inverse (=adjoint), the transpose, and the conjugate. + * + * \sa MatrixBase::applyOnTheLeft(), MatrixBase::applyOnTheRight() + */ + +template +struct ei_traits > +{ + typedef typename VectorsType::Scalar Scalar; + enum { + RowsAtCompileTime = ei_traits::RowsAtCompileTime, + ColsAtCompileTime = ei_traits::RowsAtCompileTime, + MaxRowsAtCompileTime = ei_traits::MaxRowsAtCompileTime, + MaxColsAtCompileTime = ei_traits::MaxRowsAtCompileTime, + Flags = 0 + }; +}; + +template class HouseholderSequence + : public AnyMatrixBase > +{ + typedef typename VectorsType::Scalar Scalar; + public: + + typedef HouseholderSequence::IsComplex, + NestByValue::type >, + CoeffsType>::ret> ConjugateReturnType; + + HouseholderSequence(const VectorsType& v, const CoeffsType& h, bool trans = false) + : m_vectors(v), m_coeffs(h), m_trans(trans) + {} + + int rows() const { return m_vectors.rows(); } + int cols() const { return m_vectors.rows(); } + + HouseholderSequence transpose() const + { return HouseholderSequence(m_vectors, m_coeffs, !m_trans); } + + ConjugateReturnType conjugate() const + { return ConjugateReturnType(m_vectors, m_coeffs.conjugate(), m_trans); } + + ConjugateReturnType adjoint() const + { return ConjugateReturnType(m_vectors, m_coeffs.conjugate(), !m_trans); } + + ConjugateReturnType inverse() const { return adjoint(); } + + /** \internal */ + template void evalTo(DestType& dst) const + { + int vecs = std::min(m_vectors.cols(),m_vectors.rows()); + int length = m_vectors.rows(); + dst.setIdentity(); + Matrix temp(dst.rows()); + for(int k = vecs-1; k >= 0; --k) + { + if(m_trans) + dst.corner(BottomRight, length-k, length-k) + .applyHouseholderOnTheRight(m_vectors.col(k).end(length-k-1), m_coeffs.coeff(k), &temp.coeffRef(0)); + else + dst.corner(BottomRight, length-k, length-k) + .applyHouseholderOnTheLeft(m_vectors.col(k).end(length-k-1), m_coeffs.coeff(k), &temp.coeffRef(k)); + } + } + + /** \internal */ + template inline void applyThisOnTheRight(Dest& dst) const + { + int vecs = std::min(m_vectors.cols(),m_vectors.rows()); // number of householder vectors + int length = m_vectors.rows(); // size of the largest householder vector + Matrix temp(dst.rows()); + for(int k = 0; k < vecs; ++k) + { + int actual_k = m_trans ? vecs-k-1 : k; + dst.corner(BottomRight, dst.rows(), length-k) + .applyHouseholderOnTheRight(m_vectors.col(k).end(length-k-1), m_coeffs.coeff(k), &temp.coeffRef(0)); + } + } + + /** \internal */ + template inline void applyThisOnTheLeft(Dest& dst) const + { + int vecs = std::min(m_vectors.cols(),m_vectors.rows()); // number of householder vectors + int length = m_vectors.rows(); // size of the largest householder vector + Matrix temp(dst.cols()); + for(int k = 0; k < vecs; ++k) + { + int actual_k = m_trans ? k : vecs-k-1; + dst.corner(BottomRight, length-actual_k, dst.cols()) + .applyHouseholderOnTheLeft(m_vectors.col(actual_k).end(length-actual_k-1), m_coeffs.coeff(actual_k), &temp.coeffRef(0)); + } + } + + protected: + + typename VectorsType::Nested m_vectors; + typename CoeffsType::Nested m_coeffs; + bool m_trans; +}; + +#endif // EIGEN_HOUSEHOLDER_SEQUENCE_H diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h index a89305869..39edda80c 100644 --- a/Eigen/src/QR/HouseholderQR.h +++ b/Eigen/src/QR/HouseholderQR.h @@ -56,12 +56,13 @@ template class HouseholderQR Options = MatrixType::Options, DiagSizeAtCompileTime = EIGEN_ENUM_MIN(ColsAtCompileTime,RowsAtCompileTime) }; - + typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef Matrix MatrixQType; typedef Matrix HCoeffsType; typedef Matrix RowVectorType; + typedef typename HouseholderSequence::ConjugateReturnType HouseholderSequenceType; /** * \brief Default Constructor. @@ -97,7 +98,12 @@ template class HouseholderQR template void solve(const MatrixBase& b, ResultType *result) const; - MatrixQType matrixQ(void) const; + MatrixQType matrixQ() const; + + HouseholderSequenceType matrixQAsHouseholderSequence() const + { + return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()); + } /** \returns a reference to the matrix where the Householder QR decomposition is stored * in a LAPACK-compatible way. @@ -169,7 +175,7 @@ HouseholderQR& HouseholderQR::compute(const MatrixType& int rows = matrix.rows(); int cols = matrix.cols(); int size = std::min(rows,cols); - + m_qr = matrix; m_hCoeffs.resize(size); @@ -206,15 +212,7 @@ void HouseholderQR::solve( result->resize(rows, cols); *result = b; - - Matrix temp(cols); - for (int k = 0; k < cols; ++k) - { - int remainingSize = rows-k; - - result->corner(BottomRight, remainingSize, cols) - .applyHouseholderOnTheLeft(m_qr.col(k).end(remainingSize-1), m_hCoeffs.coeff(k), &temp.coeffRef(0)); - } + result->applyOnTheLeft(matrixQAsHouseholderSequence().inverse()); const int rank = std::min(result->rows(), result->cols()); m_qr.corner(TopLeft, rank, rank) @@ -227,20 +225,7 @@ template typename HouseholderQR::MatrixQType HouseholderQR::matrixQ() const { ei_assert(m_isInitialized && "HouseholderQR is not initialized."); - // compute the product H'_0 H'_1 ... H'_n-1, - // where H_k is the k-th Householder transformation I - h_k v_k v_k' - // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...] - int rows = m_qr.rows(); - int cols = m_qr.cols(); - int size = std::min(rows,cols); - MatrixQType res = MatrixQType::Identity(rows, rows); - Matrix temp(rows); - for (int k = size-1; k >= 0; k--) - { - res.block(k, k, rows-k, rows-k) - .applyHouseholderOnTheLeft(m_qr.col(k).end(rows-k-1), ei_conj(m_hCoeffs.coeff(k)), &temp.coeffRef(k)); - } - return res; + return matrixQAsHouseholderSequence(); } #endif // EIGEN_HIDE_HEAVY_CODE diff --git a/test/householder.cpp b/test/householder.cpp index 7d300899f..b27279479 100644 --- a/test/householder.cpp +++ b/test/householder.cpp @@ -43,7 +43,7 @@ template void householder(const MatrixType& m) Matrix _tmp(std::max(rows,cols)); Scalar* tmp = &_tmp.coeffRef(0,0); - + Scalar beta; RealScalar alpha; EssentialVectorType essential; @@ -58,7 +58,7 @@ template void householder(const MatrixType& m) v2 = v1; v1.applyHouseholderOnTheLeft(essential,beta,tmp); VERIFY_IS_APPROX(v1.norm(), v2.norm()); - + MatrixType m1(rows, cols), m2(rows, cols); @@ -72,7 +72,7 @@ template void householder(const MatrixType& m) VERIFY_IS_MUCH_SMALLER_THAN(m1.block(1,0,rows-1,cols).norm(), m1.norm()); VERIFY_IS_MUCH_SMALLER_THAN(ei_imag(m1(0,0)), ei_real(m1(0,0))); VERIFY_IS_APPROX(ei_real(m1(0,0)), alpha); - + v1 = VectorType::Random(rows); if(even) v1.end(rows-1).setZero(); SquareMatrixType m3(rows,rows), m4(rows,rows); @@ -84,6 +84,9 @@ template void householder(const MatrixType& m) VERIFY_IS_MUCH_SMALLER_THAN(m3.block(0,1,rows,rows-1).norm(), m3.norm()); VERIFY_IS_MUCH_SMALLER_THAN(ei_imag(m3(0,0)), ei_real(m3(0,0))); VERIFY_IS_APPROX(ei_real(m3(0,0)), alpha); + + // test householder sequence + // TODO test HouseholderSequence } void test_householder() diff --git a/test/jacobisvd.cpp b/test/jacobisvd.cpp index 5940b8497..2e3f089a0 100644 --- a/test/jacobisvd.cpp +++ b/test/jacobisvd.cpp @@ -36,14 +36,14 @@ template void svd(const MatrixType& m RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime }; - + typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; typedef Matrix MatrixUType; typedef Matrix MatrixVType; typedef Matrix ColVectorType; typedef Matrix InputVectorType; - + MatrixType a; if(pickrandom) a = MatrixType::Random(rows,cols); else a = m; @@ -53,7 +53,7 @@ template void svd(const MatrixType& m sigma.diagonal() = svd.singularValues().template cast(); MatrixUType u = svd.matrixU(); MatrixVType v = svd.matrixV(); - + VERIFY_IS_APPROX(a, u * sigma * v.adjoint()); VERIFY_IS_UNITARY(u); VERIFY_IS_UNITARY(v); @@ -98,7 +98,7 @@ void test_jacobisvd() } CALL_SUBTEST(( svd(MatrixXf(300,200)) )); CALL_SUBTEST(( svd(MatrixXcd(100,150)) )); - + CALL_SUBTEST(( svd_verify_assert() )); CALL_SUBTEST(( svd_verify_assert() )); CALL_SUBTEST(( svd_verify_assert() )); diff --git a/test/qr.cpp b/test/qr.cpp index f2e2eda61..f185ac86e 100644 --- a/test/qr.cpp +++ b/test/qr.cpp @@ -78,7 +78,7 @@ template void qr_invertible() m3 = MatrixType::Random(size,size); qr.solve(m3, &m2); VERIFY_IS_APPROX(m3, m1*m2); - + // now construct a matrix with prescribed determinant m1.setZero(); for(int i = 0; i < size; i++) m1(i,i) = ei_random(); From 24950bdfcb60830bc615220f993c12082dd42059 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 16 Sep 2009 15:56:20 +0200 Subject: [PATCH 10/83] make ColPivotingQR use HouseholderSequence --- Eigen/src/Core/VectorBlock.h | 3 +- Eigen/src/Householder/HouseholderSequence.h | 26 ++++++++- Eigen/src/QR/ColPivotingHouseholderQR.h | 59 ++++++++------------- Eigen/src/QR/FullPivotingHouseholderQR.h | 26 ++++----- test/qr_colpivoting.cpp | 8 +-- test/qr_fullpivoting.cpp | 8 +-- 6 files changed, 68 insertions(+), 62 deletions(-) diff --git a/Eigen/src/Core/VectorBlock.h b/Eigen/src/Core/VectorBlock.h index b291f7b1a..65268b626 100644 --- a/Eigen/src/Core/VectorBlock.h +++ b/Eigen/src/Core/VectorBlock.h @@ -77,11 +77,12 @@ template class VectorBlock typedef Block::RowsAtCompileTime==1 ? 1 : Size, ei_traits::ColsAtCompileTime==1 ? 1 : Size, - PacketAccess> Base; + PacketAccess> _Base; enum { IsColVector = ei_traits::ColsAtCompileTime==1 }; public: + _EIGEN_GENERIC_PUBLIC_INTERFACE(VectorBlock, _Base) using Base::operator=; using Base::operator+=; diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index 86395213b..16e362814 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -80,10 +80,10 @@ template class HouseholderSequence int cols() const { return m_vectors.rows(); } HouseholderSequence transpose() const - { return HouseholderSequence(m_vectors, m_coeffs, !m_trans); } + { return HouseholderSequence(m_vectors, m_coeffs, !m_trans); } ConjugateReturnType conjugate() const - { return ConjugateReturnType(m_vectors, m_coeffs.conjugate(), m_trans); } + { return ConjugateReturnType(m_vectors, m_coeffs.conjugate(), m_trans); } ConjugateReturnType adjoint() const { return ConjugateReturnType(m_vectors, m_coeffs.conjugate(), !m_trans); } @@ -136,6 +136,22 @@ template class HouseholderSequence } } + template + typename OtherDerived::PlainMatrixType operator*(const MatrixBase& other) const + { + typename OtherDerived::PlainMatrixType res(other); + applyThisOnTheLeft(res); + return res; + } + + template friend + typename OtherDerived::PlainMatrixType operator*(const MatrixBase& other, const HouseholderSequence& h) + { + typename OtherDerived::PlainMatrixType res(other); + h.applyThisOnTheRight(res); + return res; + } + protected: typename VectorsType::Nested m_vectors; @@ -143,4 +159,10 @@ template class HouseholderSequence bool m_trans; }; +template +HouseholderSequence makeHouseholderSequence(const VectorsType& v, const CoeffsType& h, bool trans=false) +{ + return HouseholderSequence(v, h, trans); +} + #endif // EIGEN_HOUSEHOLDER_SEQUENCE_H diff --git a/Eigen/src/QR/ColPivotingHouseholderQR.h b/Eigen/src/QR/ColPivotingHouseholderQR.h index 883e3449f..c4c7d2d55 100644 --- a/Eigen/src/QR/ColPivotingHouseholderQR.h +++ b/Eigen/src/QR/ColPivotingHouseholderQR.h @@ -45,14 +45,14 @@ template class ColPivotingHouseholderQR { public: - + enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, Options = MatrixType::Options, DiagSizeAtCompileTime = EIGEN_ENUM_MIN(ColsAtCompileTime,RowsAtCompileTime) }; - + typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef Matrix MatrixQType; @@ -62,6 +62,7 @@ template class ColPivotingHouseholderQR typedef Matrix RowVectorType; typedef Matrix ColVectorType; typedef Matrix RealRowVectorType; + typedef typename HouseholderSequence::ConjugateReturnType HouseholderSequenceType; /** * \brief Default Constructor. @@ -99,7 +100,7 @@ template class ColPivotingHouseholderQR template bool solve(const MatrixBase& b, ResultType *result) const; - MatrixQType matrixQ(void) const; + HouseholderSequenceType matrixQ(void) const; /** \returns a reference to the matrix where the Householder QR decomposition is stored */ @@ -110,13 +111,13 @@ template class ColPivotingHouseholderQR } ColPivotingHouseholderQR& compute(const MatrixType& matrix); - + const IntRowVectorType& colsPermutation() const { ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); return m_cols_permutation; } - + /** \returns the absolute value of the determinant of the matrix of which * *this is the QR decomposition. It has only linear complexity * (that is, O(n) where n is the dimension of the square matrix) @@ -145,7 +146,7 @@ template class ColPivotingHouseholderQR * \sa absDeterminant(), MatrixBase::determinant() */ typename MatrixType::RealScalar logAbsDeterminant() const; - + /** \returns the rank of the matrix of which *this is the QR decomposition. * * \note This is computed at the time of the construction of the QR decomposition. This @@ -268,7 +269,7 @@ ColPivotingHouseholderQR& ColPivotingHouseholderQR::comp int cols = matrix.cols(); int size = std::min(rows,cols); m_rank = size; - + m_qr = matrix; m_hCoeffs.resize(size); @@ -279,18 +280,18 @@ ColPivotingHouseholderQR& ColPivotingHouseholderQR::comp IntRowVectorType cols_transpositions(matrix.cols()); m_cols_permutation.resize(matrix.cols()); int number_of_transpositions = 0; - + RealRowVectorType colSqNorms(cols); for(int k = 0; k < cols; ++k) colSqNorms.coeffRef(k) = m_qr.col(k).squaredNorm(); RealScalar biggestColSqNorm = colSqNorms.maxCoeff(); - + for (int k = 0; k < size; ++k) { int biggest_col_in_corner; RealScalar biggestColSqNormInCorner = colSqNorms.end(cols-k).maxCoeff(&biggest_col_in_corner); biggest_col_in_corner += k; - + // if the corner is negligible, then we have less than full rank, and we can finish early if(ei_isMuchSmallerThan(biggestColSqNormInCorner, biggestColSqNorm, m_precision)) { @@ -302,7 +303,7 @@ ColPivotingHouseholderQR& ColPivotingHouseholderQR::comp } break; } - + cols_transpositions.coeffRef(k) = biggest_col_in_corner; if(k != biggest_col_in_corner) { m_qr.col(k).swap(m_qr.col(biggest_col_in_corner)); @@ -316,7 +317,7 @@ ColPivotingHouseholderQR& ColPivotingHouseholderQR::comp m_qr.corner(BottomRight, rows-k, cols-k-1) .applyHouseholderOnTheLeft(m_qr.col(k).end(rows-k-1), m_hCoeffs.coeffRef(k), &temp.coeffRef(k+1)); - + colSqNorms.end(cols-k-1) -= m_qr.row(k).end(cols-k-1).cwise().abs2(); } @@ -326,7 +327,7 @@ ColPivotingHouseholderQR& ColPivotingHouseholderQR::comp m_det_pq = (number_of_transpositions%2) ? -1 : 1; m_isInitialized = true; - + return *this; } @@ -352,16 +353,11 @@ bool ColPivotingHouseholderQR::solve( const int rows = m_qr.rows(); const int cols = b.cols(); ei_assert(b.rows() == rows); - + typename OtherDerived::PlainMatrixType c(b); - - Matrix temp(cols); - for (int k = 0; k < m_rank; ++k) - { - int remainingSize = rows-k; - c.corner(BottomRight, remainingSize, cols) - .applyHouseholderOnTheLeft(m_qr.col(k).end(remainingSize-1), m_hCoeffs.coeff(k), &temp.coeffRef(0)); - } + + // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T + c.applyOnTheLeft(makeHouseholderSequence(m_qr.corner(TopLeft,rows,m_rank), m_hCoeffs.start(m_rank)).transpose()); if(!isSurjective()) { @@ -381,25 +377,12 @@ bool ColPivotingHouseholderQR::solve( return true; } -/** \returns the matrix Q */ +/** \returns the matrix Q as a sequence of householder transformations */ template -typename ColPivotingHouseholderQR::MatrixQType ColPivotingHouseholderQR::matrixQ() const +typename ColPivotingHouseholderQR::HouseholderSequenceType ColPivotingHouseholderQR::matrixQ() const { ei_assert(m_isInitialized && "ColPivotingHouseholderQR is not initialized."); - // compute the product H'_0 H'_1 ... H'_n-1, - // where H_k is the k-th Householder transformation I - h_k v_k v_k' - // and v_k is the k-th Householder vector [1,m_qr(k+1,k), m_qr(k+2,k), ...] - int rows = m_qr.rows(); - int cols = m_qr.cols(); - int size = std::min(rows,cols); - MatrixQType res = MatrixQType::Identity(rows, rows); - Matrix temp(rows); - for (int k = size-1; k >= 0; k--) - { - res.block(k, k, rows-k, rows-k) - .applyHouseholderOnTheLeft(m_qr.col(k).end(rows-k-1), ei_conj(m_hCoeffs.coeff(k)), &temp.coeffRef(k)); - } - return res; + return HouseholderSequenceType(m_qr, m_hCoeffs.conjugate()); } #endif // EIGEN_HIDE_HEAVY_CODE diff --git a/Eigen/src/QR/FullPivotingHouseholderQR.h b/Eigen/src/QR/FullPivotingHouseholderQR.h index 0d542cf7a..9fee77803 100644 --- a/Eigen/src/QR/FullPivotingHouseholderQR.h +++ b/Eigen/src/QR/FullPivotingHouseholderQR.h @@ -45,14 +45,14 @@ template class FullPivotingHouseholderQR { public: - + enum { RowsAtCompileTime = MatrixType::RowsAtCompileTime, ColsAtCompileTime = MatrixType::ColsAtCompileTime, Options = MatrixType::Options, DiagSizeAtCompileTime = EIGEN_ENUM_MIN(ColsAtCompileTime,RowsAtCompileTime) }; - + typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; typedef Matrix MatrixQType; @@ -106,13 +106,13 @@ template class FullPivotingHouseholderQR } FullPivotingHouseholderQR& compute(const MatrixType& matrix); - + const IntRowVectorType& colsPermutation() const { ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); return m_cols_permutation; } - + const IntColVectorType& rowsTranspositions() const { ei_assert(m_isInitialized && "FullPivotingHouseholderQR is not initialized."); @@ -147,7 +147,7 @@ template class FullPivotingHouseholderQR * \sa absDeterminant(), MatrixBase::determinant() */ typename MatrixType::RealScalar logAbsDeterminant() const; - + /** \returns the rank of the matrix of which *this is the QR decomposition. * * \note This is computed at the time of the construction of the QR decomposition. This @@ -271,7 +271,7 @@ FullPivotingHouseholderQR& FullPivotingHouseholderQR::co int cols = matrix.cols(); int size = std::min(rows,cols); m_rank = size; - + m_qr = matrix; m_hCoeffs.resize(size); @@ -283,9 +283,9 @@ FullPivotingHouseholderQR& FullPivotingHouseholderQR::co IntRowVectorType cols_transpositions(matrix.cols()); m_cols_permutation.resize(matrix.cols()); int number_of_transpositions = 0; - + RealScalar biggest(0); - + for (int k = 0; k < size; ++k) { int row_of_biggest_in_corner, col_of_biggest_in_corner; @@ -297,7 +297,7 @@ FullPivotingHouseholderQR& FullPivotingHouseholderQR::co row_of_biggest_in_corner += k; col_of_biggest_in_corner += k; if(k==0) biggest = biggest_in_corner; - + // if the corner is negligible, then we have less than full rank, and we can finish early if(ei_isMuchSmallerThan(biggest_in_corner, biggest, m_precision)) { @@ -336,7 +336,7 @@ FullPivotingHouseholderQR& FullPivotingHouseholderQR::co m_det_pq = (number_of_transpositions%2) ? -1 : 1; m_isInitialized = true; - + return *this; } @@ -358,13 +358,13 @@ bool FullPivotingHouseholderQR::solve( } else return false; } - + const int rows = m_qr.rows(); const int cols = b.cols(); ei_assert(b.rows() == rows); - + typename OtherDerived::PlainMatrixType c(b); - + Matrix temp(cols); for (int k = 0; k < m_rank; ++k) { diff --git a/test/qr_colpivoting.cpp b/test/qr_colpivoting.cpp index 9c387005a..588a41e56 100644 --- a/test/qr_colpivoting.cpp +++ b/test/qr_colpivoting.cpp @@ -42,18 +42,18 @@ template void qr() VERIFY(!qr.isInjective()); VERIFY(!qr.isInvertible()); VERIFY(!qr.isSurjective()); - + MatrixType r = qr.matrixQR(); // FIXME need better way to construct trapezoid for(int i = 0; i < rows; i++) for(int j = 0; j < cols; j++) if(i>j) r(i,j) = Scalar(0); - + MatrixType b = qr.matrixQ() * r; MatrixType c = MatrixType::Zero(rows,cols); - + for(int i = 0; i < cols; ++i) c.col(qr.colsPermutation().coeff(i)) = b.col(i); VERIFY_IS_APPROX(m1, c); - + MatrixType m2 = MatrixType::Random(cols,cols2); MatrixType m3 = m1*m2; m2 = MatrixType::Random(cols,cols2); diff --git a/test/qr_fullpivoting.cpp b/test/qr_fullpivoting.cpp index 525c669a5..3a37bcb46 100644 --- a/test/qr_fullpivoting.cpp +++ b/test/qr_fullpivoting.cpp @@ -46,14 +46,14 @@ template void qr() MatrixType r = qr.matrixQR(); // FIXME need better way to construct trapezoid for(int i = 0; i < rows; i++) for(int j = 0; j < cols; j++) if(i>j) r(i,j) = Scalar(0); - + MatrixType b = qr.matrixQ() * r; MatrixType c = MatrixType::Zero(rows,cols); - + for(int i = 0; i < cols; ++i) c.col(qr.colsPermutation().coeff(i)) = b.col(i); VERIFY_IS_APPROX(m1, c); - + MatrixType m2 = MatrixType::Random(cols,cols2); MatrixType m3 = m1*m2; m2 = MatrixType::Random(cols,cols2); @@ -88,7 +88,7 @@ template void qr_invertible() m3 = MatrixType::Random(size,size); VERIFY(qr.solve(m3, &m2)); VERIFY_IS_APPROX(m3, m1*m2); - + // now construct a matrix with prescribed determinant m1.setZero(); for(int i = 0; i < size; i++) m1(i,i) = ei_random(); From fcae32cc3fde7e0a4928c1f896f3eac82b48891d Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 17 Sep 2009 15:11:13 +0200 Subject: [PATCH 11/83] compilation fixes --- Eigen/src/LU/PartialLU.h | 10 +++++----- test/redux.cpp | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Eigen/src/LU/PartialLU.h b/Eigen/src/LU/PartialLU.h index 20ebd9d6a..e467c62f0 100644 --- a/Eigen/src/LU/PartialLU.h +++ b/Eigen/src/LU/PartialLU.h @@ -216,10 +216,10 @@ struct ei_partial_lu_impl typedef Map > MapLU; typedef Block MatrixType; typedef Block BlockType; - + /** \internal performs the LU decomposition in-place of the matrix \a lu * using an unblocked algorithm. - * + * * In addition, this function returns the row transpositions in the * vector \a row_transpositions which must have a size equal to the number * of columns of the matrix \a lu, and an integer \a nb_transpositions @@ -233,7 +233,7 @@ struct ei_partial_lu_impl for(int k = 0; k < size; ++k) { int row_of_biggest_in_col; - lu.block(k,k,rows-k,1).cwise().abs().maxCoeff(&row_of_biggest_in_col); + lu.col(k).end(rows-k).cwise().abs().maxCoeff(&row_of_biggest_in_col); row_of_biggest_in_col += k; row_transpositions[k] = row_of_biggest_in_col; @@ -296,7 +296,7 @@ struct ei_partial_lu_impl int bs = std::min(size-k,blockSize); // actual size of the block int trows = rows - k - bs; // trailing rows int tsize = size - k - bs; // trailing size - + // partition the matrix: // A00 | A01 | A02 // lu = A10 | A11 | A12 @@ -344,7 +344,7 @@ void ei_partial_lu_inplace(MatrixType& lu, IntVector& row_transpositions, int& n { ei_assert(lu.cols() == row_transpositions.size()); ei_assert((&row_transpositions.coeffRef(1)-&row_transpositions.coeffRef(0)) == 1); - + ei_partial_lu_impl ::blocked_lu(lu.rows(), lu.cols(), &lu.coeffRef(0,0), lu.stride(), &row_transpositions.coeffRef(0), nb_transpositions); diff --git a/test/redux.cpp b/test/redux.cpp index b929fdc0e..951b34bca 100644 --- a/test/redux.cpp +++ b/test/redux.cpp @@ -120,7 +120,7 @@ void test_redux() CALL_SUBTEST( matrixRedux(MatrixXi(8, 12)) ); } for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST( vectorRedux(VectorX4f()) ); + CALL_SUBTEST( vectorRedux(Vector4f()) ); CALL_SUBTEST( vectorRedux(VectorXd(10)) ); CALL_SUBTEST( vectorRedux(VectorXf(33)) ); } From 9395326e4491b52d8fe0e6431e8843c9629acc79 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 17 Sep 2009 23:18:21 +0200 Subject: [PATCH 12/83] fix #53: performance regression, hopefully I did not resurected another perf. issue... --- Eigen/src/Core/arch/SSE/PacketMath.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/arch/SSE/PacketMath.h b/Eigen/src/Core/arch/SSE/PacketMath.h index 52e666d2f..5d9af130d 100644 --- a/Eigen/src/Core/arch/SSE/PacketMath.h +++ b/Eigen/src/Core/arch/SSE/PacketMath.h @@ -77,15 +77,16 @@ template<> struct ei_unpacket_traits { typedef int type; enum {size #ifdef __GNUC__ // Sometimes GCC implements _mm_set1_p* using multiple moves, // that is inefficient :( +// TODO make sure the new solution using the shuffle/unpacklo is ok template<> EIGEN_STRONG_INLINE Packet4f ei_pset1(const float& from) { Packet4f res = _mm_set_ss(from); - asm("shufps $0, %[x], %[x]" : [x] "+x" (res) : ); - return res; + return _mm_shuffle_ps(res,res,0); + //asm("shufps $0, %[x], %[x]" : [x] "+x" (res) : ); } template<> EIGEN_STRONG_INLINE Packet2d ei_pset1(const double& from) { Packet2d res = _mm_set_sd(from); - asm("unpcklpd %[x], %[x]" : [x] "+x" (res) : ); - return res; + return _mm_unpacklo_pd(res,res); +// asm("unpcklpd %[x], %[x]" : [x] "+x" (res) : ); } #else template<> EIGEN_STRONG_INLINE Packet4f ei_pset1(const float& from) { return _mm_set1_ps(from); } From 760636a237d875aa6f0e108e432fd98974ab25ea Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Fri, 18 Sep 2009 18:45:45 -0400 Subject: [PATCH 13/83] fix bug #52: Transform::inverse() should return a Transform --- Eigen/src/Geometry/Transform.h | 22 +++++++++++----------- test/geo_transformations.cpp | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index 9eb8ed535..dcb41435b 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -395,7 +395,7 @@ public: Transform& fromPositionOrientationScale(const MatrixBase &position, const OrientationType& orientation, const MatrixBase &scale); - inline const MatrixType inverse(TransformTraits traits = (TransformTraits)Mode) const; + inline Transform inverse(TransformTraits traits = (TransformTraits)Mode) const; /** \returns a const pointer to the column major internal matrix */ const Scalar* data() const { return m_matrix.data(); } @@ -874,7 +874,7 @@ Transform::fromPositionOrientationScale(const MatrixBase::fromPositionOrientationScale(const MatrixBase -const typename Transform::MatrixType +Transform Transform::inverse(TransformTraits hint) const { + Transform res; if (hint == Projective) { - return m_matrix.inverse(); + res.matrix() = m_matrix.inverse(); } else { - MatrixType res; if (hint == Isometry) { - res.template corner(TopLeft) = linear().transpose(); + res.matrix().template corner(TopLeft) = linear().transpose(); } else if(hint&Affine) { - res.template corner(TopLeft) = linear().inverse(); + res.matrix().template corner(TopLeft) = linear().inverse(); } else { ei_assert(false && "Invalid transform traits in Transform::Inverse"); } // translation and remaining parts - res.template corner(TopRight) = - res.template corner(TopLeft) * translation(); + res.matrix().template corner(TopRight) = - res.matrix().template corner(TopLeft) * translation(); if(int(Mode)!=int(AffineCompact)) { - res.template block<1,Dim>(Dim,0).setZero(); - res.coeffRef(Dim,Dim) = 1; + res.matrix().template block<1,Dim>(Dim,0).setZero(); + res.matrix().coeffRef(Dim,Dim) = 1; } - return res; } + return res; } /***************************************************** diff --git a/test/geo_transformations.cpp b/test/geo_transformations.cpp index 914dbaf74..2b05f2457 100644 --- a/test/geo_transformations.cpp +++ b/test/geo_transformations.cpp @@ -296,10 +296,10 @@ template void transformations(void) t0.setIdentity(); t0.translate(v0); t0.linear().setRandom(); - VERIFY_IS_APPROX(t0.inverse(Affine), t0.matrix().inverse()); + VERIFY_IS_APPROX(t0.inverse(Affine).matrix(), t0.matrix().inverse()); t0.setIdentity(); t0.translate(v0).rotate(q1); - VERIFY_IS_APPROX(t0.inverse(Isometry), t0.matrix().inverse()); + VERIFY_IS_APPROX(t0.inverse(Isometry).matrix(), t0.matrix().inverse()); } // test extract rotation and aligned scaling From 5ba7fe3bee57000a7554b57d981e045586b70831 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 17 Sep 2009 23:34:00 +0200 Subject: [PATCH 14/83] clean the commented asm instructions because now I'm sure the previous fix is ok --- Eigen/src/Core/arch/SSE/PacketMath.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Eigen/src/Core/arch/SSE/PacketMath.h b/Eigen/src/Core/arch/SSE/PacketMath.h index 5d9af130d..ddc7b4aaf 100644 --- a/Eigen/src/Core/arch/SSE/PacketMath.h +++ b/Eigen/src/Core/arch/SSE/PacketMath.h @@ -76,17 +76,14 @@ template<> struct ei_unpacket_traits { typedef int type; enum {size #ifdef __GNUC__ // Sometimes GCC implements _mm_set1_p* using multiple moves, -// that is inefficient :( -// TODO make sure the new solution using the shuffle/unpacklo is ok +// that is inefficient :( (e.g., see ei_gemm_pack_rhs) template<> EIGEN_STRONG_INLINE Packet4f ei_pset1(const float& from) { Packet4f res = _mm_set_ss(from); return _mm_shuffle_ps(res,res,0); - //asm("shufps $0, %[x], %[x]" : [x] "+x" (res) : ); } template<> EIGEN_STRONG_INLINE Packet2d ei_pset1(const double& from) { Packet2d res = _mm_set_sd(from); return _mm_unpacklo_pd(res,res); -// asm("unpcklpd %[x], %[x]" : [x] "+x" (res) : ); } #else template<> EIGEN_STRONG_INLINE Packet4f ei_pset1(const float& from) { return _mm_set1_ps(from); } From add5381be7cb1d32ee1e3603a0b999f74abaf612 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Thu, 17 Sep 2009 23:51:16 +0200 Subject: [PATCH 15/83] finish my evalToDense => evalTo change --- Eigen/src/Core/AnyMatrixBase.h | 2 +- Eigen/src/Core/DiagonalMatrix.h | 4 ++-- Eigen/src/Sparse/SparseMatrixBase.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Core/AnyMatrixBase.h b/Eigen/src/Core/AnyMatrixBase.h index cd354d7b1..58b425740 100644 --- a/Eigen/src/Core/AnyMatrixBase.h +++ b/Eigen/src/Core/AnyMatrixBase.h @@ -94,7 +94,7 @@ template struct AnyMatrixBase ***************************************************************************/ /** Copies the generic expression \a other into *this. \returns a reference to *this. - * The expression must provide a (templated) evalToDense(Derived& dst) const function + * The expression must provide a (templated) evalTo(Derived& dst) const function * which does the actual job. In practice, this allows any user to write its own * special matrix without having to modify MatrixBase */ template diff --git a/Eigen/src/Core/DiagonalMatrix.h b/Eigen/src/Core/DiagonalMatrix.h index a74695921..4665fe0ca 100644 --- a/Eigen/src/Core/DiagonalMatrix.h +++ b/Eigen/src/Core/DiagonalMatrix.h @@ -51,7 +51,7 @@ class DiagonalBase : public AnyMatrixBase DenseMatrixType toDenseMatrix() const { return derived(); } template - void evalToDense(MatrixBase &other) const; + void evalTo(MatrixBase &other) const; template void addToDense(MatrixBase &other) const { other.diagonal() += diagonal(); } @@ -72,7 +72,7 @@ class DiagonalBase : public AnyMatrixBase template template -void DiagonalBase::evalToDense(MatrixBase &other) const +void DiagonalBase::evalTo(MatrixBase &other) const { other.setZero(); other.diagonal() = diagonal(); diff --git a/Eigen/src/Sparse/SparseMatrixBase.h b/Eigen/src/Sparse/SparseMatrixBase.h index d0b7c98c8..b2b010565 100644 --- a/Eigen/src/Sparse/SparseMatrixBase.h +++ b/Eigen/src/Sparse/SparseMatrixBase.h @@ -452,7 +452,7 @@ template class SparseMatrixBase : public AnyMatrixBase - void evalToDense(MatrixBase& dst) const + void evalTo(MatrixBase& dst) const { dst.setZero(); for (int j=0; j Date: Fri, 18 Sep 2009 22:01:49 -0400 Subject: [PATCH 16/83] update page to explain how to get rid of it --- doc/D11_UnalignedArrayAssert.dox | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/doc/D11_UnalignedArrayAssert.dox b/doc/D11_UnalignedArrayAssert.dox index e95c767b4..226b20452 100644 --- a/doc/D11_UnalignedArrayAssert.dox +++ b/doc/D11_UnalignedArrayAssert.dox @@ -21,6 +21,7 @@ There are 4 known causes for this issue. Please read on to understand them and l - \ref c3 - \ref c4 - \ref explanation + - \ref getrid \section where Where in my own code is the cause of the problem? @@ -101,6 +102,16 @@ Eigen normally takes care of these alignment issues for you, by setting an align However there are a few corner cases where these alignment settings get overridden: they are the possible causes for this assertion. +\section getrid I don't care about vectorization, how do I get rid of that stuff? + +Two possibilities: +
    +
  • Define EIGEN_DONT_ALIGN. That disables all 128-bit alignment code, and in particular everything vectorization-related. But do note that this in particular breaks ABI compatibility with vectorized code.
  • +
  • Or define both EIGEN_DONT_VECTORIZE and EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT. This keeps the 128-bit alignment code and thus preserves ABI compatibility.
  • +
+ +For more information, see this FAQ. + */ } From 3b5a9acba8ee5e08b801371122a7a544c8f26031 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 18 Sep 2009 11:41:38 +0200 Subject: [PATCH 17/83] fix stable_norm unit test --- Eigen/src/Householder/Householder.h | 8 ++++---- test/stable_norm.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Eigen/src/Householder/Householder.h b/Eigen/src/Householder/Householder.h index 36f02d7ce..775b2f872 100644 --- a/Eigen/src/Householder/Householder.h +++ b/Eigen/src/Householder/Householder.h @@ -55,12 +55,12 @@ void MatrixBase::makeHouseholderInPlace(Scalar *tau, RealScalar *beta) * \f$ H = I - tau v v^*\f$ * and the vector v is: * \f$ v^T = [1 essential^T] \f$ - * + * * On output: * \param essential the essential part of the vector \c v * \param tau the scaling factor of the householder transformation * \param beta the result of H * \c *this - * + * * \sa MatrixBase::makeHouseholderInPlace(), MatrixBase::applyHouseholderOnTheLeft(), * MatrixBase::applyHouseholderOnTheRight() */ @@ -73,10 +73,10 @@ void MatrixBase::makeHouseholder( { EIGEN_STATIC_ASSERT_VECTOR_ONLY(EssentialPart) VectorBlock tail(derived(), 1, size()-1); - + RealScalar tailSqNorm = size()==1 ? 0 : tail.squaredNorm(); Scalar c0 = coeff(0); - + if(tailSqNorm == RealScalar(0) && ei_imag(c0)==RealScalar(0)) { *tau = 0; diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index b8fbf5271..726512ec0 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -36,7 +36,7 @@ template void stable_norm(const MatrixType& m) int rows = m.rows(); int cols = m.cols(); - Scalar big = ei_random() * std::numeric_limits::max() * RealScalar(1e-4); + Scalar big = ei_abs(ei_random()) * (std::numeric_limits::max() * RealScalar(1e-4)); Scalar small = static_cast(1)/big; MatrixType vzero = MatrixType::Zero(rows, cols), From 6b5f96cb030a0fc65d772c91d66fc27f9cf57af3 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sat, 19 Sep 2009 19:14:28 -0400 Subject: [PATCH 18/83] undef B0 --- Eigen/Core | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Eigen/Core b/Eigen/Core index 42eb363a9..c8fcb1c09 100644 --- a/Eigen/Core +++ b/Eigen/Core @@ -106,6 +106,9 @@ #error The preprocessor symbols 'min' or 'max' are defined. If you are compiling on Windows, do #define NOMINMAX to prevent windows.h from defining these symbols. #endif +// defined in bits/termios.h +#undef B0 + namespace Eigen { /** \defgroup Core_Module Core module From 0b60027f3c952163608a2d9b75b5da4ed7275210 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 18 Sep 2009 15:36:05 +0200 Subject: [PATCH 19/83] implement __gnuc_forget_about_setZero_its_over_now --- Eigen/src/Sparse/SparseProduct.h | 58 +++++++++++++++----------------- bench/sparse_dense_product.cpp | 28 ++++++--------- 2 files changed, 37 insertions(+), 49 deletions(-) diff --git a/Eigen/src/Sparse/SparseProduct.h b/Eigen/src/Sparse/SparseProduct.h index a9ad8aad4..cb1196bc9 100644 --- a/Eigen/src/Sparse/SparseProduct.h +++ b/Eigen/src/Sparse/SparseProduct.h @@ -305,23 +305,9 @@ inline Derived& SparseMatrixBase::operator=(const SparseProduct -// template -// Derived& MatrixBase::lazyAssign(const SparseProduct& product) -// { -// typedef typename ei_cleantype::type _Lhs; -// typedef typename _Lhs::InnerIterator LhsInnerIterator; -// enum { LhsIsRowMajor = (_Lhs::Flags&RowMajorBit)==RowMajorBit }; -// derived().setZero(); -// for (int j=0; j -template -Derived& MatrixBase::lazyAssign(const SparseProduct& product) +// Note that here we force no inlining and separate the setZero() because GCC messes up otherwise +template +EIGEN_DONT_INLINE void ei_sparse_time_dense_product(const Lhs& lhs, const Rhs& rhs, Dest& dst) { typedef typename ei_cleantype::type _Lhs; typedef typename ei_cleantype::type _Rhs; @@ -335,34 +321,44 @@ Derived& MatrixBase::lazyAssign(const SparseProduct res(derived().row(LhsIsRowMajor ? j : 0)); - for (; (ProcessFirstHalf ? i && i.index() < j : i) ; ++i) + typename Rhs::Scalar rhs_j = rhs.coeff(j,0); + Block dst_j(dst.row(LhsIsRowMajor ? j : 0)); + for(; (ProcessFirstHalf ? i && i.index() < j : i) ; ++i) { - if (LhsIsSelfAdjoint) + if(LhsIsSelfAdjoint) { int a = LhsIsRowMajor ? j : i.index(); int b = LhsIsRowMajor ? i.index() : j; - Scalar v = i.value(); - derived().row(a) += (v) * product.rhs().row(b); - derived().row(b) += ei_conj(v) * product.rhs().row(a); + typename Lhs::Scalar v = i.value(); + dst.row(a) += (v) * rhs.row(b); + dst.row(b) += ei_conj(v) * rhs.row(a); } - else if (LhsIsRowMajor) - res += i.value() * product.rhs().row(i.index()); + else if(LhsIsRowMajor) + dst_j += i.value() * rhs.row(i.index()); + else if(Rhs::ColsAtCompileTime==1) + dst.coeffRef(i.index()) += i.value() * rhs_j; else - derived().row(i.index()) += i.value() * product.rhs().row(j); + dst.row(i.index()) += i.value() * rhs.row(j); } if (ProcessFirstHalf && i && (i.index()==j)) - derived().row(j) += i.value() * product.rhs().row(j); + dst.row(j) += i.value() * rhs.row(j); } +} + +template +template +Derived& MatrixBase::lazyAssign(const SparseProduct& product) +{ + derived().setZero(); + ei_sparse_time_dense_product(product.lhs(), product.rhs(), derived()); return derived(); } diff --git a/bench/sparse_dense_product.cpp b/bench/sparse_dense_product.cpp index 9b9af8819..bfe46122d 100644 --- a/bench/sparse_dense_product.cpp +++ b/bench/sparse_dense_product.cpp @@ -91,22 +91,22 @@ int main(int argc, char *argv[]) { std::cout << "Eigen sparse\t" << sm1.nonZeros()/float(sm1.rows()*sm1.cols())*100 << "%\n"; - BENCH(for (int k=0; k m1(sm1); // std::cout << "Eigen dyn-sparse\t" << m1.nonZeros()/float(m1.rows()*m1.cols())*100 << "%\n"; -// +// // BENCH(for (int k=0; k gmmV1(cols), gmmV2(cols); Map >(&gmmV1[0], cols) = v1; Map >(&gmmV2[0], cols) = v2; - timer.reset(); - timer.start(); - for (int k=0; k Date: Sun, 20 Sep 2009 05:49:17 -0400 Subject: [PATCH 20/83] add demo of how to mix eigen with C code --- demos/mix_eigen_and_c/README | 7 + demos/mix_eigen_and_c/binary_library.cpp | 176 +++++++++++++++++++++++ demos/mix_eigen_and_c/binary_library.h | 62 ++++++++ demos/mix_eigen_and_c/example.c | 56 ++++++++ 4 files changed, 301 insertions(+) create mode 100644 demos/mix_eigen_and_c/README create mode 100644 demos/mix_eigen_and_c/binary_library.cpp create mode 100644 demos/mix_eigen_and_c/binary_library.h create mode 100644 demos/mix_eigen_and_c/example.c diff --git a/demos/mix_eigen_and_c/README b/demos/mix_eigen_and_c/README new file mode 100644 index 000000000..d543f8d99 --- /dev/null +++ b/demos/mix_eigen_and_c/README @@ -0,0 +1,7 @@ +To try this with GCC, do: + + g++ -c binary_library.cpp -O2 -msse2 -I ../.. + gcc example.c binary_library.o -o example -lstdc++ + ./example + +This is an example of how one can wrap some of Eigen into a C library. diff --git a/demos/mix_eigen_and_c/binary_library.cpp b/demos/mix_eigen_and_c/binary_library.cpp new file mode 100644 index 000000000..2a63c0863 --- /dev/null +++ b/demos/mix_eigen_and_c/binary_library.cpp @@ -0,0 +1,176 @@ +// This C++ file compiles to binary code that can be linked to by your C program, +// thanks to the extern "C" syntax used in the declarations in binary_library.h. + +#include "binary_library.h" + +#include + +using namespace Eigen; + +/************************* pointer conversion methods **********************************************/ + +////// class MatrixXd ////// + +inline MatrixXd& c_to_eigen(C_MatrixXd* ptr) +{ + return *reinterpret_cast(ptr); +} + +inline const MatrixXd& c_to_eigen(const C_MatrixXd* ptr) +{ + return *reinterpret_cast(ptr); +} + +inline C_MatrixXd* eigen_to_c(MatrixXd& ref) +{ + return reinterpret_cast(&ref); +} + +inline const C_MatrixXd* eigen_to_c(const MatrixXd& ref) +{ + return reinterpret_cast(&ref); +} + +////// class Map ////// + +inline Map& c_to_eigen(C_Map_MatrixXd* ptr) +{ + return *reinterpret_cast*>(ptr); +} + +inline const Map& c_to_eigen(const C_Map_MatrixXd* ptr) +{ + return *reinterpret_cast*>(ptr); +} + +inline C_Map_MatrixXd* eigen_to_c(Map& ref) +{ + return reinterpret_cast(&ref); +} + +inline const C_Map_MatrixXd* eigen_to_c(const Map& ref) +{ + return reinterpret_cast(&ref); +} + + +/************************* implementation of classes **********************************************/ + + +////// class MatrixXd ////// + + +C_MatrixXd* MatrixXd_new(int rows, int cols) +{ + return eigen_to_c(*new MatrixXd(rows,cols)); +} + +void MatrixXd_delete(C_MatrixXd *m) +{ + delete &c_to_eigen(m); +} + +double* MatrixXd_data(C_MatrixXd *m) +{ + return c_to_eigen(m).data(); +} + +void MatrixXd_set_zero(C_MatrixXd *m) +{ + c_to_eigen(m).setZero(); +} + +void MatrixXd_resize(C_MatrixXd *m, int rows, int cols) +{ + c_to_eigen(m).resize(rows,cols); +} + +void MatrixXd_copy(C_MatrixXd *dst, const C_MatrixXd *src) +{ + c_to_eigen(dst) = c_to_eigen(src); +} + +void MatrixXd_copy_map(C_MatrixXd *dst, const C_Map_MatrixXd *src) +{ + c_to_eigen(dst) = c_to_eigen(src); +} + +void MatrixXd_set_coeff(C_MatrixXd *m, int i, int j, double coeff) +{ + c_to_eigen(m)(i,j) = coeff; +} + +double MatrixXd_get_coeff(const C_MatrixXd *m, int i, int j) +{ + return c_to_eigen(m)(i,j); +} + +void MatrixXd_print(const C_MatrixXd *m) +{ + std::cout << c_to_eigen(m) << std::endl; +} + +void MatrixXd_multiply(const C_MatrixXd *m1, const C_MatrixXd *m2, C_MatrixXd *result) +{ + c_to_eigen(result) = c_to_eigen(m1) * c_to_eigen(m2); +} + +void MatrixXd_add(const C_MatrixXd *m1, const C_MatrixXd *m2, C_MatrixXd *result) +{ + c_to_eigen(result) = c_to_eigen(m1) + c_to_eigen(m2); +} + + + +////// class Map_MatrixXd ////// + + +C_Map_MatrixXd* Map_MatrixXd_new(double *array, int rows, int cols) +{ + return eigen_to_c(*new Map(array,rows,cols)); +} + +void Map_MatrixXd_delete(C_Map_MatrixXd *m) +{ + delete &c_to_eigen(m); +} + +void Map_MatrixXd_set_zero(C_Map_MatrixXd *m) +{ + c_to_eigen(m).setZero(); +} + +void Map_MatrixXd_copy(C_Map_MatrixXd *dst, const C_Map_MatrixXd *src) +{ + c_to_eigen(dst) = c_to_eigen(src); +} + +void Map_MatrixXd_copy_matrix(C_Map_MatrixXd *dst, const C_MatrixXd *src) +{ + c_to_eigen(dst) = c_to_eigen(src); +} + +void Map_MatrixXd_set_coeff(C_Map_MatrixXd *m, int i, int j, double coeff) +{ + c_to_eigen(m)(i,j) = coeff; +} + +double Map_MatrixXd_get_coeff(const C_Map_MatrixXd *m, int i, int j) +{ + return c_to_eigen(m)(i,j); +} + +void Map_MatrixXd_print(const C_Map_MatrixXd *m) +{ + std::cout << c_to_eigen(m) << std::endl; +} + +void Map_MatrixXd_multiply(const C_Map_MatrixXd *m1, const C_Map_MatrixXd *m2, C_Map_MatrixXd *result) +{ + c_to_eigen(result) = c_to_eigen(m1) * c_to_eigen(m2); +} + +void Map_MatrixXd_add(const C_Map_MatrixXd *m1, const C_Map_MatrixXd *m2, C_Map_MatrixXd *result) +{ + c_to_eigen(result) = c_to_eigen(m1) + c_to_eigen(m2); +} diff --git a/demos/mix_eigen_and_c/binary_library.h b/demos/mix_eigen_and_c/binary_library.h new file mode 100644 index 000000000..c41e7da10 --- /dev/null +++ b/demos/mix_eigen_and_c/binary_library.h @@ -0,0 +1,62 @@ +// This is a pure C header, no C++ here. +// The functions declared here will be implemented in C++ but +// we don't have to know, because thanks to the extern "C" syntax, +// they will be compiled to C object code. + +#ifdef __cplusplus +extern "C" +{ +#endif + + // just dummy empty structs to give different pointer types, + // instead of using void* which would be type unsafe + struct C_MatrixXd {}; + struct C_Map_MatrixXd {}; + + // the C_MatrixXd class, wraps some of the functionality + // of Eigen::MatrixXd. + struct C_MatrixXd* MatrixXd_new(int rows, int cols); + void MatrixXd_delete (struct C_MatrixXd *m); + double* MatrixXd_data (struct C_MatrixXd *m); + void MatrixXd_set_zero (struct C_MatrixXd *m); + void MatrixXd_resize (struct C_MatrixXd *m, int rows, int cols); + void MatrixXd_copy (struct C_MatrixXd *dst, + const struct C_MatrixXd *src); + void MatrixXd_copy_map (struct C_MatrixXd *dst, + const struct C_Map_MatrixXd *src); + void MatrixXd_set_coeff (struct C_MatrixXd *m, + int i, int j, double coeff); + double MatrixXd_get_coeff (const struct C_MatrixXd *m, + int i, int j); + void MatrixXd_print (const struct C_MatrixXd *m); + void MatrixXd_add (const struct C_MatrixXd *m1, + const struct C_MatrixXd *m2, + struct C_MatrixXd *result); + void MatrixXd_multiply (const struct C_MatrixXd *m1, + const struct C_MatrixXd *m2, + struct C_MatrixXd *result); + + // the C_Map_MatrixXd class, wraps some of the functionality + // of Eigen::Map + struct C_Map_MatrixXd* Map_MatrixXd_new(double *array, int rows, int cols); + void Map_MatrixXd_delete (struct C_Map_MatrixXd *m); + void Map_MatrixXd_set_zero (struct C_Map_MatrixXd *m); + void Map_MatrixXd_copy (struct C_Map_MatrixXd *dst, + const struct C_Map_MatrixXd *src); + void Map_MatrixXd_copy_matrix(struct C_Map_MatrixXd *dst, + const struct C_MatrixXd *src); + void Map_MatrixXd_set_coeff (struct C_Map_MatrixXd *m, + int i, int j, double coeff); + double Map_MatrixXd_get_coeff (const struct C_Map_MatrixXd *m, + int i, int j); + void Map_MatrixXd_print (const struct C_Map_MatrixXd *m); + void Map_MatrixXd_add (const struct C_Map_MatrixXd *m1, + const struct C_Map_MatrixXd *m2, + struct C_Map_MatrixXd *result); + void Map_MatrixXd_multiply (const struct C_Map_MatrixXd *m1, + const struct C_Map_MatrixXd *m2, + struct C_Map_MatrixXd *result); + +#ifdef __cplusplus +} // end extern "C" +#endif \ No newline at end of file diff --git a/demos/mix_eigen_and_c/example.c b/demos/mix_eigen_and_c/example.c new file mode 100644 index 000000000..431808c81 --- /dev/null +++ b/demos/mix_eigen_and_c/example.c @@ -0,0 +1,56 @@ +#include "binary_library.h" +#include "stdio.h" + +void demo_MatrixXd() +{ + struct C_MatrixXd *matrix1, *matrix2, *result; + printf("*** demo_MatrixXd ***\n"); + + matrix1 = MatrixXd_new(3, 3); + MatrixXd_set_zero(matrix1); + MatrixXd_set_coeff(matrix1, 0, 1, 2.5); + MatrixXd_set_coeff(matrix1, 1, 0, 1.4); + printf("Here is matrix1:\n"); + MatrixXd_print(matrix1); + + matrix2 = MatrixXd_new(3, 3); + MatrixXd_multiply(matrix1, matrix1, matrix2); + printf("Here is matrix1*matrix1:\n"); + MatrixXd_print(matrix2); + + MatrixXd_delete(matrix1); + MatrixXd_delete(matrix2); +} + +// this helper function takes a plain C array and prints it in one line +void print_array(double *array, int n) +{ + struct C_Map_MatrixXd *m = Map_MatrixXd_new(array, 1, n); + Map_MatrixXd_print(m); + Map_MatrixXd_delete(m); +} + +void demo_Map_MatrixXd() +{ + struct C_Map_MatrixXd *map; + double array[5]; + int i; + printf("*** demo_Map_MatrixXd ***\n"); + + for(i = 0; i < 5; ++i) array[i] = i; + printf("Initially, the array is:\n"); + print_array(array, 5); + + map = Map_MatrixXd_new(array, 5, 1); + Map_MatrixXd_add(map, map, map); + Map_MatrixXd_delete(map); + + printf("Now the array is:\n"); + print_array(array, 5); +} + +int main() +{ + demo_MatrixXd(); + demo_Map_MatrixXd(); +} From 3c780fd4729cad99363d28c4c62c73471bdc7e2b Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sun, 20 Sep 2009 06:00:39 -0400 Subject: [PATCH 21/83] add legalese --- demos/mix_eigen_and_c/binary_library.cpp | 24 ++++++++++++++++++++++++ demos/mix_eigen_and_c/binary_library.h | 24 ++++++++++++++++++++++++ demos/mix_eigen_and_c/example.c | 24 ++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/demos/mix_eigen_and_c/binary_library.cpp b/demos/mix_eigen_and_c/binary_library.cpp index 2a63c0863..efbf28ff0 100644 --- a/demos/mix_eigen_and_c/binary_library.cpp +++ b/demos/mix_eigen_and_c/binary_library.cpp @@ -1,3 +1,27 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Benoit Jacob +// +// 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 . + // This C++ file compiles to binary code that can be linked to by your C program, // thanks to the extern "C" syntax used in the declarations in binary_library.h. diff --git a/demos/mix_eigen_and_c/binary_library.h b/demos/mix_eigen_and_c/binary_library.h index c41e7da10..3a4dc5b77 100644 --- a/demos/mix_eigen_and_c/binary_library.h +++ b/demos/mix_eigen_and_c/binary_library.h @@ -1,3 +1,27 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Benoit Jacob +// +// 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 . + // This is a pure C header, no C++ here. // The functions declared here will be implemented in C++ but // we don't have to know, because thanks to the extern "C" syntax, diff --git a/demos/mix_eigen_and_c/example.c b/demos/mix_eigen_and_c/example.c index 431808c81..4391a6d78 100644 --- a/demos/mix_eigen_and_c/example.c +++ b/demos/mix_eigen_and_c/example.c @@ -1,3 +1,27 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Benoit Jacob +// +// 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 . + #include "binary_library.h" #include "stdio.h" From 828a79ac783001f7c4d56bd06ef221f31f32f2ba Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sat, 19 Sep 2009 19:45:58 -0400 Subject: [PATCH 22/83] allow to override EIGEN_RESTRICT, to satisfy a smart ass blogger who claims that eigen2 owes all its performance to nonstandard restrict keyword. well, this can also improve portability in case some compiler doesn't have __restrict. --- Eigen/src/Core/util/Macros.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index ec8337e33..4b62891d9 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -221,7 +221,12 @@ using Eigen::ei_cos; #error Please tell me what is the equivalent of __attribute__((aligned(16))) for your compiler #endif -#define EIGEN_RESTRICT __restrict +#ifdef EIGEN_DONT_USE_RESTRICT_KEYWORD + #define EIGEN_RESTRICT +#endif +#ifndef EIGEN_RESTRICT + #define EIGEN_RESTRICT __restrict +#endif #ifndef EIGEN_STACK_ALLOCATION_LIMIT #define EIGEN_STACK_ALLOCATION_LIMIT 1000000 From 1df54e3ac23780cd67c91c50f27052199902f81f Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sat, 19 Sep 2009 19:59:49 -0400 Subject: [PATCH 23/83] fix bug #42, add missing Transform::Identity() --- Eigen/src/Geometry/Transform.h | 4 ++++ test/geo_transformations.cpp | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index dcb41435b..e89581e21 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -345,6 +345,10 @@ public: /** \sa MatrixBase::setIdentity() */ void setIdentity() { m_matrix.setIdentity(); } + static const typename MatrixType::IdentityReturnType Identity() + { + return MatrixType::Identity(); + } template inline Transform& scale(const MatrixBase &other); diff --git a/test/geo_transformations.cpp b/test/geo_transformations.cpp index 2b05f2457..23b297314 100644 --- a/test/geo_transformations.cpp +++ b/test/geo_transformations.cpp @@ -102,7 +102,14 @@ template void transformations(void) a = ei_random(-Scalar(0.4)*Scalar(M_PI), Scalar(0.4)*Scalar(M_PI)); q1 = AngleAxisx(a, v0.normalized()); Transform3 t0, t1, t2; + + // first test setIdentity() and Identity() t0.setIdentity(); + VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity()); + t0.matrix().setZero(); + t0 = Transform3::Identity(); + VERIFY_IS_APPROX(t0.matrix(), Transform3::MatrixType::Identity()); + t0.linear() = q1.toRotationMatrix(); t1.setIdentity(); t1.linear() = q1.toRotationMatrix(); From c1c780a94f148c618a74cfcccf40037442ae2d7c Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Tue, 22 Sep 2009 12:20:45 -0400 Subject: [PATCH 24/83] * ReturnByValue: -- simpplify by removing the 2nd template parameter -- rename Functor to Derived, as now it's a usual CRTP * Homogeneous: -- in products, honor the Max sizes etc. --- Eigen/src/Core/Matrix.h | 8 ++--- Eigen/src/Core/MatrixBase.h | 4 +-- Eigen/src/Core/ReturnByValue.h | 38 +++++++++-------------- Eigen/src/Core/util/ForwardDeclarations.h | 2 +- Eigen/src/Geometry/Homogeneous.h | 30 ++++++++++++++---- Eigen/src/Geometry/Transform.h | 8 ++--- test/geo_homogeneous.cpp | 2 +- 7 files changed, 51 insertions(+), 41 deletions(-) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index c08f12491..aea0f15c8 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -399,8 +399,8 @@ class Matrix return Base::lazyAssign(other.derived()); } - template - EIGEN_STRONG_INLINE Matrix& operator=(const ReturnByValue& func) + template + EIGEN_STRONG_INLINE Matrix& operator=(const ReturnByValue& func) { resize(func.rows(), func.cols()); return Base::operator=(func); @@ -504,8 +504,8 @@ class Matrix _set_noalias(other); } /** Copy constructor with in-place evaluation */ - template - EIGEN_STRONG_INLINE Matrix(const ReturnByValue& other) + template + EIGEN_STRONG_INLINE Matrix(const ReturnByValue& other) { _check_template_params(); resize(other.rows(), other.cols()); diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 4835f167c..a1659e2a7 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -271,8 +271,8 @@ template class MatrixBase template Derived& operator-=(const AnyMatrixBase &other); - template - Derived& operator=(const ReturnByValue& func); + template + Derived& operator=(const ReturnByValue& func); #ifndef EIGEN_PARSED_BY_DOXYGEN /** Copies \a other into *this without evaluating other. \returns a reference to *this. */ diff --git a/Eigen/src/Core/ReturnByValue.h b/Eigen/src/Core/ReturnByValue.h index 3f2b478ff..4a5d5c105 100644 --- a/Eigen/src/Core/ReturnByValue.h +++ b/Eigen/src/Core/ReturnByValue.h @@ -28,45 +28,37 @@ /** \class ReturnByValue * */ -template -struct ei_traits > > - : public ei_traits > +template +struct ei_traits > + : public ei_traits::ReturnMatrixType> { enum { - Flags = ei_traits >::Flags | EvalBeforeNestingBit + Flags = ei_traits::ReturnMatrixType>::Flags | EvalBeforeNestingBit }; }; -template -struct ei_nested >, n, EvalTypeDerived> +template +struct ei_nested, n, PlainMatrixType> { - typedef EvalTypeDerived type; + typedef typename ei_traits::ReturnMatrixType type; }; -template class ReturnByValue +template + class ReturnByValue : public MatrixBase > { - public: - template inline void evalTo(Dest& dst) const - { static_cast(this)->evalTo(dst); } -}; - -template - class ReturnByValue > - : public MatrixBase > > -{ - typedef Matrix<_Scalar,_Rows,_Cols,_Options,_MaxRows,_MaxCols> EvalType; + typedef typename ei_traits::ReturnMatrixType ReturnMatrixType; public: EIGEN_GENERIC_PUBLIC_INTERFACE(ReturnByValue) template inline void evalTo(Dest& dst) const - { static_cast(this)->evalTo(dst); } - inline int rows() const { return static_cast(this)->rows(); } - inline int cols() const { return static_cast(this)->cols(); } + { static_cast(this)->evalTo(dst); } + inline int rows() const { return static_cast(this)->rows(); } + inline int cols() const { return static_cast(this)->cols(); } }; template -template -Derived& MatrixBase::operator=(const ReturnByValue& other) +template +Derived& MatrixBase::operator=(const ReturnByValue& other) { other.evalTo(derived()); return derived(); diff --git a/Eigen/src/Core/util/ForwardDeclarations.h b/Eigen/src/Core/util/ForwardDeclarations.h index 3f66738f0..65e5ce687 100644 --- a/Eigen/src/Core/util/ForwardDeclarations.h +++ b/Eigen/src/Core/util/ForwardDeclarations.h @@ -64,7 +64,7 @@ template class SelfAdjointView; template class Cwise; template class WithFormat; template struct CommaInitializer; -template class ReturnByValue; +template class ReturnByValue; template class BandMatrix; diff --git a/Eigen/src/Geometry/Homogeneous.h b/Eigen/src/Geometry/Homogeneous.h index 2de99b5de..035d213b7 100644 --- a/Eigen/src/Geometry/Homogeneous.h +++ b/Eigen/src/Geometry/Homogeneous.h @@ -206,11 +206,20 @@ VectorwiseOp::hnormalized() const Direction==Horizontal ? _expression().cols()-1 : 1).nestByValue(); } +template +struct ei_traits,Lhs> > +{ + typedef Matrix::Scalar, + Lhs::RowsAtCompileTime, + MatrixType::ColsAtCompileTime, + MatrixType::PlainMatrixType::Options, + Lhs::MaxRowsAtCompileTime, + MatrixType::MaxColsAtCompileTime> ReturnMatrixType; +}; + template struct ei_homogeneous_left_product_impl,Lhs> - : public ReturnByValue,Lhs>, - Matrix::Scalar, - Lhs::RowsAtCompileTime,MatrixType::ColsAtCompileTime> > + : public ReturnByValue,Lhs> > { typedef typename ei_cleantype::type LhsNested; ei_homogeneous_left_product_impl(const Lhs& lhs, const MatrixType& rhs) @@ -235,11 +244,20 @@ struct ei_homogeneous_left_product_impl,Lhs> const typename MatrixType::Nested m_rhs; }; +template +struct ei_traits,Rhs> > +{ + typedef Matrix::Scalar, + MatrixType::RowsAtCompileTime, + Rhs::ColsAtCompileTime, + MatrixType::PlainMatrixType::Options, + MatrixType::MaxRowsAtCompileTime, + Rhs::MaxColsAtCompileTime> ReturnMatrixType; +}; + template struct ei_homogeneous_right_product_impl,Rhs> - : public ReturnByValue,Rhs>, - Matrix::Scalar, - MatrixType::RowsAtCompileTime, Rhs::ColsAtCompileTime> > + : public ReturnByValue,Rhs> > { typedef typename ei_cleantype::type RhsNested; ei_homogeneous_right_product_impl(const MatrixType& lhs, const Rhs& rhs) diff --git a/Eigen/src/Geometry/Transform.h b/Eigen/src/Geometry/Transform.h index e89581e21..d03fd52fd 100644 --- a/Eigen/src/Geometry/Transform.h +++ b/Eigen/src/Geometry/Transform.h @@ -247,14 +247,14 @@ public: ei_transform_construct_from_matrix::run(this, other.matrix()); } - template - Transform(const ReturnByValue& other) + template + Transform(const ReturnByValue& other) { other.evalTo(*this); } - template - Transform& operator=(const ReturnByValue& other) + template + Transform& operator=(const ReturnByValue& other) { other.evalTo(*this); return *this; diff --git a/test/geo_homogeneous.cpp b/test/geo_homogeneous.cpp index c4db32f9c..4b66e488c 100644 --- a/test/geo_homogeneous.cpp +++ b/test/geo_homogeneous.cpp @@ -97,7 +97,7 @@ template void homogeneous(void) pts.setRandom(Size,5); Rt_pts1 = Rt * pts.colwise().homogeneous(); - std::cerr << (Rt_pts1 - pts).sum() << "\n"; + // std::cerr << (Rt_pts1 - pts).sum() << "\n"; VERIFY_IS_MUCH_SMALLER_THAN( (Rt_pts1 - pts).sum(), Scalar(1)); } From c6822d6723ec34c052ca35393aa7e83146bee8c6 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Mon, 21 Sep 2009 19:59:58 +0200 Subject: [PATCH 25/83] Added EIGEN_REF_TO_TEMPORARY define for rvalue support. Allowed VC10 to make use of static_assert. --- CMakeLists.txt | 4 ++++ Eigen/src/Core/Matrix.h | 4 ++-- Eigen/src/Core/MatrixBase.h | 2 +- Eigen/src/Core/Swap.h | 8 +------- Eigen/src/Core/TriangularMatrix.h | 4 ++-- Eigen/src/Core/util/Macros.h | 7 +++++++ Eigen/src/Core/util/StaticAssert.h | 2 +- Eigen/src/Sparse/SparseMatrixBase.h | 2 +- cmake/EigenTesting.cmake | 3 +++ 9 files changed, 22 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c229a2858..166dbe621 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -108,6 +108,10 @@ if(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION) message("Disabling vectorization in tests/examples") endif(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION) +option(EIGEN_TEST_C++0x "Enables all C++0x features." OFF) + +option(EIGEN_TEST_RVALUE_REF_SUPPORT "Enable rvalue references for unit tests." OFF) + include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) set(INCLUDE_INSTALL_DIR diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index aea0f15c8..2e2826205 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -538,7 +538,7 @@ class Matrix * data pointers. */ template - void swap(const MatrixBase& other); + void swap(MatrixBase EIGEN_REF_TO_TEMPORARY other); /** \name Map * These are convenience functions returning Map objects. The Map() static functions return unaligned Map objects, @@ -756,7 +756,7 @@ struct ei_matrix_swap_impl template template -inline void Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::swap(const MatrixBase& other) +inline void Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::swap(MatrixBase EIGEN_REF_TO_TEMPORARY other) { enum { SwapPointers = ei_is_same_type::ret && Base::SizeAtCompileTime==Dynamic }; ei_matrix_swap_impl::run(*this, *const_cast*>(&other)); diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index a1659e2a7..5ae2b0002 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -592,7 +592,7 @@ template class MatrixBase { return typename ei_eval::type(derived()); } template - void swap(const MatrixBase& other); + void swap(MatrixBase EIGEN_REF_TO_TEMPORARY other); template const Flagged marked() const; diff --git a/Eigen/src/Core/Swap.h b/Eigen/src/Core/Swap.h index 44e1f07e0..a7cf219f7 100644 --- a/Eigen/src/Core/Swap.h +++ b/Eigen/src/Core/Swap.h @@ -128,15 +128,9 @@ template class SwapWrapper */ template template -void MatrixBase::swap(const MatrixBase& other) +void MatrixBase::swap(MatrixBase EIGEN_REF_TO_TEMPORARY other) { (SwapWrapper(derived())).lazyAssign(other); } #endif // EIGEN_SWAP_H - - - - - - diff --git a/Eigen/src/Core/TriangularMatrix.h b/Eigen/src/Core/TriangularMatrix.h index 17726bca3..e60d57e70 100644 --- a/Eigen/src/Core/TriangularMatrix.h +++ b/Eigen/src/Core/TriangularMatrix.h @@ -300,13 +300,13 @@ template class TriangularView } template - void swap(const TriangularBase& other) + void swap(TriangularBase EIGEN_REF_TO_TEMPORARY other) { TriangularView,Mode>(const_cast(m_matrix)).lazyAssign(other.derived()); } template - void swap(const MatrixBase& other) + void swap(MatrixBase EIGEN_REF_TO_TEMPORARY other) { TriangularView,Mode>(const_cast(m_matrix)).lazyAssign(other.derived()); } diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 4b62891d9..530306643 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -251,6 +251,13 @@ using Eigen::ei_cos; // needed to define it here as escaping characters in CMake add_definition's argument seems very problematic. #define EIGEN_DOCS_IO_FORMAT IOFormat(3, 0, " ", "\n", "", "") +// C++0x features +#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined(_MSC_VER) && (_MSC_VER >= 1600)) + #define EIGEN_REF_TO_TEMPORARY && +#else + #define EIGEN_REF_TO_TEMPORARY const & +#endif + #ifdef _MSC_VER #define EIGEN_INHERIT_ASSIGNMENT_OPERATORS(Derived) \ using Base::operator =; \ diff --git a/Eigen/src/Core/util/StaticAssert.h b/Eigen/src/Core/util/StaticAssert.h index 73d302fda..7116e4d0f 100644 --- a/Eigen/src/Core/util/StaticAssert.h +++ b/Eigen/src/Core/util/StaticAssert.h @@ -41,7 +41,7 @@ #ifndef EIGEN_NO_STATIC_ASSERT - #ifdef __GXX_EXPERIMENTAL_CXX0X__ + #if defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined(_MSC_VER) && (_MSC_VER >= 1600)) // if native static_assert is enabled, let's use it #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG); diff --git a/Eigen/src/Sparse/SparseMatrixBase.h b/Eigen/src/Sparse/SparseMatrixBase.h index b2b010565..61e8adea3 100644 --- a/Eigen/src/Sparse/SparseMatrixBase.h +++ b/Eigen/src/Sparse/SparseMatrixBase.h @@ -515,7 +515,7 @@ template class SparseMatrixBase : public AnyMatrixBase::type(derived()); } // template -// void swap(const MatrixBase& other); +// void swap(MatrixBase EIGEN_REF_TO_TEMPORARY other); template const SparseFlagged marked() const; diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index faa75c6f4..b252e90e2 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -159,6 +159,9 @@ if(CMAKE_COMPILER_IS_GNUCXX) else(EIGEN_COVERAGE_TESTING) set(COVERAGE_FLAGS "") endif(EIGEN_COVERAGE_TESTING) + if((EIGEN_TEST_RVALUE_REF_SUPPORT OR EIGEN_TEST_C++0x) AND NOT MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + endif((EIGEN_TEST_RVALUE_REF_SUPPORT OR EIGEN_TEST_C++0x) AND NOT MSVC) if(CMAKE_SYSTEM_NAME MATCHES Linux) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_FLAGS} -g2") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COVERAGE_FLAGS} -O2 -g2") From b347075936236a74417fe7cb4739399ffb2f7eca Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Tue, 22 Sep 2009 10:03:40 +0200 Subject: [PATCH 26/83] Removed unnecessary MSVC check. --- cmake/EigenTesting.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index b252e90e2..96049aa93 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -159,9 +159,9 @@ if(CMAKE_COMPILER_IS_GNUCXX) else(EIGEN_COVERAGE_TESTING) set(COVERAGE_FLAGS "") endif(EIGEN_COVERAGE_TESTING) - if((EIGEN_TEST_RVALUE_REF_SUPPORT OR EIGEN_TEST_C++0x) AND NOT MSVC) + if(EIGEN_TEST_RVALUE_REF_SUPPORT OR EIGEN_TEST_C++0x) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") - endif((EIGEN_TEST_RVALUE_REF_SUPPORT OR EIGEN_TEST_C++0x) AND NOT MSVC) + endif(EIGEN_TEST_RVALUE_REF_SUPPORT OR EIGEN_TEST_C++0x) if(CMAKE_SYSTEM_NAME MATCHES Linux) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_FLAGS} -g2") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${COVERAGE_FLAGS} -O2 -g2") From 51db7ab0dfcf9120589241db6183456971ba89c4 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 23 Sep 2009 20:58:20 -0400 Subject: [PATCH 27/83] add eigen_gen_credits script --- scripts/eigen_gen_credits | 21 ++++ scripts/eigen_gen_credits.cpp | 209 ++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100755 scripts/eigen_gen_credits create mode 100644 scripts/eigen_gen_credits.cpp diff --git a/scripts/eigen_gen_credits b/scripts/eigen_gen_credits new file mode 100755 index 000000000..ec31da33c --- /dev/null +++ b/scripts/eigen_gen_credits @@ -0,0 +1,21 @@ +#!/bin/sh + +# this script must be run from the eigen2/ directory. +# when running hg churn from the scripts/ subdir, i hit a divide-by-zero error in hg churn. +# +# like this: +# cd eigen2 +# scripts/eigen_gen_credits + +# configuration +USER='bjacob' + +wget http://eigen.tuxfamily.org/index.php?title=ContributorsInfo -O online-info.out -o wget.log +hg churn -r 37: --changesets -t {author} > churn-changesets.out +hg churn -r 37: -t {author} > churn-changedlines.out + +g++ scripts/eigen_gen_credits.cpp -o e + +./e > credits.out + +rsync credits.out $USER@ssh.tuxfamily.org:eigen/eigen.tuxfamily.org-web/htdocs/credits.out || (echo "upload failed"; exit 1) diff --git a/scripts/eigen_gen_credits.cpp b/scripts/eigen_gen_credits.cpp new file mode 100644 index 000000000..4f86c7c9d --- /dev/null +++ b/scripts/eigen_gen_credits.cpp @@ -0,0 +1,209 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +// this function takes a line that may contain a name and/or email address, +// and returns just the name, while fixing the "bad cases". +std::string contributor_name(const std::string& line) +{ + string result; + size_t position_of_email_address = line.find_first_of('<'); + if(position_of_email_address != string::npos) + { + // there is an e-mail address. + + // Hauke once committed as "John Smith", fix that. + if(line.find("hauke.heibel") != string::npos) + result = "Hauke Heibel"; + else + { + // just remove the e-mail address + result = line.substr(0, position_of_email_address); + } + } + else + { + // there is no e-mail address. + + if(line.find("convert-repo") != string::npos) + result = ""; + else + result = line; + } + + // remove trailing spaces + size_t length = result.length(); + while(length >= 1 && result[length-1] == ' ') result.erase(--length); + + return result; +} + +// parses hg churn output to generate a contributors map. +map contributors_map_from_churn_output(const char *filename) +{ + map contributors_map; + + string line; + ifstream churn_out; + churn_out.open(filename, ios::in); + while(!getline(churn_out,line).eof()) + { + // remove the histograms "******" that hg churn may draw at the end of some lines + size_t first_star = line.find_first_of('*'); + if(first_star != string::npos) line.erase(first_star); + + // remove trailing spaces + size_t length = line.length(); + while(length >= 1 && line[length-1] == ' ') line.erase(--length); + + // now the last space indicates where the number starts + size_t last_space = line.find_last_of(' '); + + // get the number (of changesets or of modified lines for each contributor) + int number; + istringstream(line.substr(last_space+1)) >> number; + + // get the name of the contributor + line.erase(last_space); + string name = contributor_name(line); + + map::iterator it = contributors_map.find(name); + // if new contributor, insert + if(it == contributors_map.end()) + contributors_map.insert(pair(name, number)); + // if duplicate, just add the number + else + it->second += number; + } + churn_out.close(); + + return contributors_map; +} + +struct contributor +{ + string name; + int changedlines; + int changesets; + string url; + string misc; + + contributor() : changedlines(0), changesets(0) {} + + bool operator < (const contributor& other) + { + return changedlines > other.changedlines; + } +}; + +void add_online_info_into_contributors_list(list& contributors_list, const char *filename) +{ + string line; + ifstream churn_out; + churn_out.open(filename, ios::in); + while(!getline(churn_out,line).eof()) + { + string hgname, realname, url, misc; + + size_t last_bar = line.find_last_of('|'); + if(last_bar == string::npos) continue; + if(last_bar < line.length()) + misc = line.substr(last_bar+1); + line.erase(last_bar); + + last_bar = line.find_last_of('|'); + if(last_bar == string::npos) continue; + if(last_bar < line.length()) + url = line.substr(last_bar+1); + line.erase(last_bar); + + last_bar = line.find_last_of('|'); + if(last_bar == string::npos) continue; + if(last_bar < line.length()) + realname = line.substr(last_bar+1); + line.erase(last_bar); + + hgname = line; + + // remove the example line + if(hgname.find("MercurialName") != string::npos) continue; + + list::iterator it; + for(it=contributors_list.begin(); it != contributors_list.end() && it->name != hgname; ++it) + {} + + if(it == contributors_list.end()) + { + contributor c; + c.name = realname; + c.url = url; + c.misc = misc; + contributors_list.push_back(c); + } + else + { + it->name = realname; + it->url = url; + it->misc = misc; + } + } +} + +ostream& operator<<(ostream& stream, const contributor& c) +{ + stream << c.name << "|" << c.changedlines << "|" << c.changesets << "|" << c.url << "|" << c.misc; +} + +int main() +{ + // parse the hg churn output files + map contributors_map_for_changedlines = contributors_map_from_churn_output("churn-changedlines.out"); + map contributors_map_for_changesets = contributors_map_from_churn_output("churn-changesets.out"); + + // merge into the contributors list + list contributors_list; + map::iterator it; + for(it=contributors_map_for_changedlines.begin(); it != contributors_map_for_changedlines.end(); ++it) + { + contributor c; + c.name = it->first; + c.changedlines = it->second; + c.changesets = contributors_map_for_changesets.find(it->first)->second; + contributors_list.push_back(c); + } + + add_online_info_into_contributors_list(contributors_list, "online-info.out"); + + contributors_list.sort(); + + cout << "{| cellpadding=\"5\"\n"; + cout << "!\n"; + cout << "! Lines changed\n(changesets)\n"; + cout << "! Misc\n"; + + list::iterator itc; + int i = 0; + for(itc=contributors_list.begin(); itc != contributors_list.end(); ++itc) + { + if(itc->name.length() == 0) continue; + if(i%2) cout << "|-\n"; + else cout << "|- style=\"background:#FFFFD0\"\n"; + if(itc->url.length()) + cout << "| [" << itc->url << " " << itc->name << "]\n"; + else + cout << "| " << itc->name << "\n"; + if(itc->changedlines) + cout << "| " << itc->changedlines << " (" << itc->changesets << ")\n"; + else + cout << "| (no own changesets) \n"; + cout << "| " << itc->misc << "\n"; + i++; + } + cout << "|}" << endl; +} From a279a277e32fad9cce8b39b506bbcdb0ba421948 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 23 Sep 2009 21:01:14 -0400 Subject: [PATCH 28/83] fix typo --- scripts/eigen_gen_credits.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/eigen_gen_credits.cpp b/scripts/eigen_gen_credits.cpp index 4f86c7c9d..7c1330ac6 100644 --- a/scripts/eigen_gen_credits.cpp +++ b/scripts/eigen_gen_credits.cpp @@ -105,9 +105,9 @@ struct contributor void add_online_info_into_contributors_list(list& contributors_list, const char *filename) { string line; - ifstream churn_out; - churn_out.open(filename, ios::in); - while(!getline(churn_out,line).eof()) + ifstream online_info; + online_info.open(filename, ios::in); + while(!getline(online_info,line).eof()) { string hgname, realname, url, misc; From 64648b4b355af5f021d29ae476f6308b4a0ac8ea Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Thu, 24 Sep 2009 07:04:55 -0400 Subject: [PATCH 29/83] improvements, especially: automatically flush the server side cache --- .hgignore | 3 ++- scripts/eigen_gen_credits | 14 +++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.hgignore b/.hgignore index 412e037a8..9432702ba 100644 --- a/.hgignore +++ b/.hgignore @@ -20,4 +20,5 @@ CMakeCache.txt tags .*.swp activity.png -gmon.out +*.out +*.php* \ No newline at end of file diff --git a/scripts/eigen_gen_credits b/scripts/eigen_gen_credits index ec31da33c..a7adce1cc 100755 --- a/scripts/eigen_gen_credits +++ b/scripts/eigen_gen_credits @@ -10,12 +10,20 @@ # configuration USER='bjacob' -wget http://eigen.tuxfamily.org/index.php?title=ContributorsInfo -O online-info.out -o wget.log -hg churn -r 37: --changesets -t {author} > churn-changesets.out -hg churn -r 37: -t {author} > churn-changedlines.out +rm eigen_gen_credits.log + +hg pull >> eigen_gen_credits.log + +wget http://eigen.tuxfamily.org/index.php?title=ContributorsInfo -O online-info.out -a eigen_gen_credits.log +hg churn -r 37: --changesets -t {author} >> churn-changesets.out +hg churn -r 37: -t {author} >> churn-changedlines.out g++ scripts/eigen_gen_credits.cpp -o e ./e > credits.out rsync credits.out $USER@ssh.tuxfamily.org:eigen/eigen.tuxfamily.org-web/htdocs/credits.out || (echo "upload failed"; exit 1) + +# clear the server-side cache for Main Page +wget "http://eigen.tuxfamily.org/index.php?title=Main_Page&action=purge" -O main-page.out -a eigen_gen_credits.log +rm main-page.out From 905b3b9379858a9d2f804503c10750949f52b6dd Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Thu, 24 Sep 2009 07:18:31 -0400 Subject: [PATCH 30/83] oops, don't append, overwrite --- scripts/eigen_gen_credits | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/eigen_gen_credits b/scripts/eigen_gen_credits index a7adce1cc..654743256 100755 --- a/scripts/eigen_gen_credits +++ b/scripts/eigen_gen_credits @@ -15,8 +15,8 @@ rm eigen_gen_credits.log hg pull >> eigen_gen_credits.log wget http://eigen.tuxfamily.org/index.php?title=ContributorsInfo -O online-info.out -a eigen_gen_credits.log -hg churn -r 37: --changesets -t {author} >> churn-changesets.out -hg churn -r 37: -t {author} >> churn-changedlines.out +hg churn -r 37: --changesets -t {author} > churn-changesets.out +hg churn -r 37: -t {author} > churn-changedlines.out g++ scripts/eigen_gen_credits.cpp -o e From 68988e4ad0eb1d0428a208633d4d0dea9e2c5db3 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Thu, 24 Sep 2009 13:26:23 +0200 Subject: [PATCH 31/83] use -f so that the script is happy even if the log file is not there --- scripts/eigen_gen_credits | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/eigen_gen_credits b/scripts/eigen_gen_credits index 654743256..f597b1b6a 100755 --- a/scripts/eigen_gen_credits +++ b/scripts/eigen_gen_credits @@ -8,9 +8,9 @@ # scripts/eigen_gen_credits # configuration -USER='bjacob' +USER='orzel' -rm eigen_gen_credits.log +rm -f eigen_gen_credits.log hg pull >> eigen_gen_credits.log From ddfd23a13ef444218bd1842b202743e321377de7 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Thu, 24 Sep 2009 13:56:33 -0400 Subject: [PATCH 32/83] * sort by last name alphabetically * replace (no own changesets) by (no information) --- scripts/eigen_gen_credits.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/scripts/eigen_gen_credits.cpp b/scripts/eigen_gen_credits.cpp index 7c1330ac6..7ffba8414 100644 --- a/scripts/eigen_gen_credits.cpp +++ b/scripts/eigen_gen_credits.cpp @@ -86,6 +86,15 @@ map contributors_map_from_churn_output(const char *filename) return contributors_map; } +// find the last name, i.e. the last word. +// for "van den Schbling" types of last names, that's not a problem, that's actually what we want. +string lastname(const string& name) +{ + size_t last_space = name.find_last_of(' '); + if(last_space >= name.length()-1) return name; + else return name.substr(last_space+1); +} + struct contributor { string name; @@ -98,7 +107,7 @@ struct contributor bool operator < (const contributor& other) { - return changedlines > other.changedlines; + return lastname(name).compare(lastname(other.name)) < 0; } }; @@ -155,11 +164,6 @@ void add_online_info_into_contributors_list(list& contributors_list } } -ostream& operator<<(ostream& stream, const contributor& c) -{ - stream << c.name << "|" << c.changedlines << "|" << c.changesets << "|" << c.url << "|" << c.misc; -} - int main() { // parse the hg churn output files @@ -185,7 +189,7 @@ int main() cout << "{| cellpadding=\"5\"\n"; cout << "!\n"; cout << "! Lines changed\n(changesets)\n"; - cout << "! Misc\n"; + cout << "!\n"; list::iterator itc; int i = 0; @@ -201,7 +205,7 @@ int main() if(itc->changedlines) cout << "| " << itc->changedlines << " (" << itc->changesets << ")\n"; else - cout << "| (no own changesets) \n"; + cout << "| (no information)\n"; cout << "| " << itc->misc << "\n"; i++; } From e58e9c842e72222d0f7fd3a60311e6ae1ea0c2cd Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Thu, 24 Sep 2009 15:14:45 -0400 Subject: [PATCH 33/83] remove (changesets), it's enough numbers like this --- scripts/eigen_gen_credits.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/eigen_gen_credits.cpp b/scripts/eigen_gen_credits.cpp index 7ffba8414..086548e26 100644 --- a/scripts/eigen_gen_credits.cpp +++ b/scripts/eigen_gen_credits.cpp @@ -168,7 +168,7 @@ int main() { // parse the hg churn output files map contributors_map_for_changedlines = contributors_map_from_churn_output("churn-changedlines.out"); - map contributors_map_for_changesets = contributors_map_from_churn_output("churn-changesets.out"); + //map contributors_map_for_changesets = contributors_map_from_churn_output("churn-changesets.out"); // merge into the contributors list list contributors_list; @@ -178,7 +178,7 @@ int main() contributor c; c.name = it->first; c.changedlines = it->second; - c.changesets = contributors_map_for_changesets.find(it->first)->second; + c.changesets = 0; //contributors_map_for_changesets.find(it->first)->second; contributors_list.push_back(c); } @@ -188,7 +188,7 @@ int main() cout << "{| cellpadding=\"5\"\n"; cout << "!\n"; - cout << "! Lines changed\n(changesets)\n"; + cout << "! Lines changed\n"; cout << "!\n"; list::iterator itc; @@ -203,7 +203,7 @@ int main() else cout << "| " << itc->name << "\n"; if(itc->changedlines) - cout << "| " << itc->changedlines << " (" << itc->changesets << ")\n"; + cout << "| " << itc->changedlines << "\n"; else cout << "| (no information)\n"; cout << "| " << itc->misc << "\n"; From 2fbf5ce7df432b3187418e3ac7ae437174346a56 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 25 Sep 2009 10:12:09 +0200 Subject: [PATCH 34/83] Fixed issue #57. --- Eigen/src/Core/CommaInitializer.h | 3 +++ Eigen/src/QR/HouseholderQR.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/CommaInitializer.h b/Eigen/src/Core/CommaInitializer.h index e86f47ad0..328c5580c 100644 --- a/Eigen/src/Core/CommaInitializer.h +++ b/Eigen/src/Core/CommaInitializer.h @@ -116,6 +116,9 @@ struct CommaInitializer int m_row; // current row id int m_col; // current col id int m_currentBlockRows; // current block height + +private: + CommaInitializer& operator=(const CommaInitializer&); }; /** \anchor MatrixBaseCommaInitRef diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h index 39edda80c..39502a30f 100644 --- a/Eigen/src/QR/HouseholderQR.h +++ b/Eigen/src/QR/HouseholderQR.h @@ -59,7 +59,7 @@ template class HouseholderQR typedef typename MatrixType::Scalar Scalar; typedef typename MatrixType::RealScalar RealScalar; - typedef Matrix MatrixQType; + typedef Matrix::Flags&RowMajorBit ? RowMajor : ColMajor)> MatrixQType; typedef Matrix HCoeffsType; typedef Matrix RowVectorType; typedef typename HouseholderSequence::ConjugateReturnType HouseholderSequenceType; From 3d6e4ab879d7ebb9b6927954f75ffd98d659eaf2 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 25 Sep 2009 10:14:16 +0200 Subject: [PATCH 35/83] Uuups that was not yet intended for a commit. --- Eigen/src/Core/CommaInitializer.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/Eigen/src/Core/CommaInitializer.h b/Eigen/src/Core/CommaInitializer.h index 328c5580c..e86f47ad0 100644 --- a/Eigen/src/Core/CommaInitializer.h +++ b/Eigen/src/Core/CommaInitializer.h @@ -116,9 +116,6 @@ struct CommaInitializer int m_row; // current row id int m_col; // current col id int m_currentBlockRows; // current block height - -private: - CommaInitializer& operator=(const CommaInitializer&); }; /** \anchor MatrixBaseCommaInitRef From e12bd2e8d209d7f92fa77adb3c4791a48c9fa0b7 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 25 Sep 2009 12:58:04 +0200 Subject: [PATCH 36/83] extend the support for bool --- Eigen/src/Core/MathFunctions.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 40edf4a3c..8c86d1dd4 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -317,4 +317,34 @@ inline bool ei_isApproxOrLessThan(long double a, long double b, long double prec return a <= b || ei_isApprox(a, b, prec); } +/************** +*** bool *** +**************/ + +template<> inline bool precision() { return 0; } +inline bool ei_real(bool x) { return x; } +inline bool& ei_real_ref(bool& x) { return x; } +inline bool ei_imag(bool) { return 0; } +inline bool ei_conj(bool x) { return x; } +inline bool ei_abs(bool x) { return x; } +inline bool ei_abs2(bool x) { return x; } +inline bool ei_sqrt(bool x) { return x; } + +template<> inline bool ei_random() +{ + return ei_random(0,1); +} +inline bool ei_isMuchSmallerThan(bool a, bool, bool = precision()) +{ + return !a; +} +inline bool ei_isApprox(bool a, bool b, bool = precision()) +{ + return a == b; +} +inline bool ei_isApproxOrLessThan(bool a, bool b, bool = precision()) +{ + return int(a) <= int(b); +} + #endif // EIGEN_MATHFUNCTIONS_H From bdf603caecc72f8250f212c497d6cf2b42e1c054 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 25 Sep 2009 12:58:41 +0200 Subject: [PATCH 37/83] remove some dirty lines --- Eigen/src/Core/products/SelfadjointRank2Update.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/Eigen/src/Core/products/SelfadjointRank2Update.h b/Eigen/src/Core/products/SelfadjointRank2Update.h index 64fcf8660..69cf1896c 100644 --- a/Eigen/src/Core/products/SelfadjointRank2Update.h +++ b/Eigen/src/Core/products/SelfadjointRank2Update.h @@ -38,10 +38,8 @@ struct ei_selfadjoint_rank2_update_selector static void run(Scalar* mat, int stride, const UType& u, const VType& v, Scalar alpha) { const int size = u.size(); -// std::cerr << "lower \n" << u.transpose() << "\n" << v.transpose() << "\n\n"; for (int i=0; i >(mat+stride*i+i, size-i) += (alpha * ei_conj(u.coeff(i))) * v.end(size-i) + (alpha * ei_conj(v.coeff(i))) * u.end(size-i); From 04dc63776a63e5d0ec0237706cb440152d57769e Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 25 Sep 2009 13:08:39 +0200 Subject: [PATCH 38/83] add a wip blas library built on top of Eigen. TODO: - write extentive unit tests (maybe this already exist in other projects) - the level2 functions still have to be implemented --- CMakeLists.txt | 6 +- blas/CMakeLists.txt | 10 ++ blas/README.txt | 7 + blas/common.h | 115 +++++++++++++ blas/complex_double.cpp | 31 ++++ blas/complex_single.cpp | 31 ++++ blas/double.cpp | 31 ++++ blas/level1_impl.h | 225 +++++++++++++++++++++++++ blas/level2_impl.h | 214 +++++++++++++++++++++++ blas/level3_impl.h | 365 ++++++++++++++++++++++++++++++++++++++++ blas/single.cpp | 31 ++++ 11 files changed, 1065 insertions(+), 1 deletion(-) create mode 100644 blas/CMakeLists.txt create mode 100644 blas/README.txt create mode 100644 blas/common.h create mode 100644 blas/complex_double.cpp create mode 100644 blas/complex_single.cpp create mode 100644 blas/double.cpp create mode 100644 blas/level1_impl.h create mode 100644 blas/level2_impl.h create mode 100644 blas/level3_impl.h create mode 100644 blas/single.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 166dbe621..94b2e99d0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,7 +95,7 @@ if(MSVC) option(EIGEN_TEST_SSE2 "Enable/Disable SSE2 in tests/examples" OFF) if(EIGEN_TEST_SSE2) if(NOT CMAKE_CL_64) - # arch is not supported on 64 bit systems, SSE is enabled automatically. + # arch is not supported on 64 bit systems, SSE is enabled automatically. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /arch:SSE2") endif(NOT CMAKE_CL_64) message("Enabling SSE2 in tests/examples") @@ -142,6 +142,10 @@ if(EIGEN_BUILD_DEMOS) add_subdirectory(demos) endif(EIGEN_BUILD_DEMOS) +if(EIGEN_BUILD_BLAS) + add_subdirectory(blas) +endif(EIGEN_BUILD_BLAS) + if(EIGEN_BUILD_BTL) add_subdirectory(bench/btl) endif(EIGEN_BUILD_BTL) diff --git a/blas/CMakeLists.txt b/blas/CMakeLists.txt new file mode 100644 index 000000000..477693bad --- /dev/null +++ b/blas/CMakeLists.txt @@ -0,0 +1,10 @@ + +set(EigenBlas_SRCS single.cpp double.cpp complex_single.cpp complex_double.cpp) + +add_library(eigen_blas SHARED ${EigenBlas_SRCS}) + +install(TARGETS eigen_blas + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib) + diff --git a/blas/README.txt b/blas/README.txt new file mode 100644 index 000000000..466a6751c --- /dev/null +++ b/blas/README.txt @@ -0,0 +1,7 @@ + +This directory contains a BLAS library built on top of Eigen. + +This is currently a work in progress which is far to be ready for use, +but feel free to contribute to it if you wish. + +If you want to compile it, set the cmake variable EIGEN_BUILD_BLAS to "on". diff --git a/blas/common.h b/blas/common.h new file mode 100644 index 000000000..74c3c9f11 --- /dev/null +++ b/blas/common.h @@ -0,0 +1,115 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// 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 . + +#ifndef EIGEN_BLAS_COMMON_H +#define EIGEN_BLAS_COMMON_H + +#ifndef SCALAR +#error the token SCALAR must be defined to compile this file +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + +#ifdef __cplusplus +} +#endif + + +#define NOTR 0 +#define TR 1 +#define ADJ 2 + +#define LEFT 0 +#define RIGHT 1 + +#define UP 0 +#define LO 1 + +#define NUNIT 0 +#define UNIT 1 + +#define OP(X) ( ((X)=='N' || (X)=='n') ? NOTR \ + : ((X)=='T' || (X)=='t') ? TR \ + : ((X)=='C' || (X)=='c') ? ADJ \ + : 0xff) + +#define SIDE(X) ( ((X)=='L' || (X)=='l') ? LEFT \ + : ((X)=='R' || (X)=='r') ? RIGHT \ + : 0xff) + +#define UPLO(X) ( ((X)=='U' || (X)=='u') ? UP \ + : ((X)=='L' || (X)=='l') ? LO \ + : 0xff) + +#define DIAG(X) ( ((X)=='N' || (X)=='N') ? NUNIT \ + : ((X)=='U' || (X)=='u') ? UNIT \ + : 0xff) + +#include +#include +using namespace Eigen; + +template +Block > >, Dynamic, Dynamic> +matrix(T* data, int rows, int cols, int stride) +{ + return Map >(data, stride, cols).nestByValue().block(0,0,rows,cols); +} + +template +Block > >, Dynamic, 1> +vector(T* data, int size, int incr) +{ + return Map >(data, size, incr).nestByValue().col(0); +} + +template +Map > +vector(T* data, int size) +{ + return Map >(data, size); +} + +typedef SCALAR Scalar; +typedef NumTraits::Real RealScalar; +typedef std::complex Complex; + +enum +{ + IsComplex = Eigen::NumTraits::IsComplex, + Conj = IsComplex +}; + +typedef Block > >, Dynamic, Dynamic> MatrixType; +typedef Block > >, Dynamic, 1> StridedVectorType; +typedef Map > CompactVectorType; + +#define EIGEN_BLAS_FUNC(X) EIGEN_CAT(SCALAR_SUFFIX,X##_) + +#endif // EIGEN_BLAS_COMMON_H diff --git a/blas/complex_double.cpp b/blas/complex_double.cpp new file mode 100644 index 000000000..f51ccb25b --- /dev/null +++ b/blas/complex_double.cpp @@ -0,0 +1,31 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// 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 . + +#define SCALAR std::complex +#define SCALAR_SUFFIX c +#define ISCOMPLEX 1 + +#include "level1_impl.h" +#include "level2_impl.h" +#include "level3_impl.h" diff --git a/blas/complex_single.cpp b/blas/complex_single.cpp new file mode 100644 index 000000000..b6617e7b9 --- /dev/null +++ b/blas/complex_single.cpp @@ -0,0 +1,31 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// 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 . + +#define SCALAR std::complex +#define SCALAR_SUFFIX z +#define ISCOMPLEX 1 + +#include "level1_impl.h" +#include "level2_impl.h" +#include "level3_impl.h" diff --git a/blas/double.cpp b/blas/double.cpp new file mode 100644 index 000000000..8145696b3 --- /dev/null +++ b/blas/double.cpp @@ -0,0 +1,31 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// 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 . + +#define SCALAR double +#define SCALAR_SUFFIX d +#define ISCOMPLEX 0 + +#include "level1_impl.h" +#include "level2_impl.h" +#include "level3_impl.h" diff --git a/blas/level1_impl.h b/blas/level1_impl.h new file mode 100644 index 000000000..c508626db --- /dev/null +++ b/blas/level1_impl.h @@ -0,0 +1,225 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// 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 . + +#include "common.h" + +int EIGEN_BLAS_FUNC(axpy)(int *n, RealScalar *palpha, RealScalar *px, int *incx, RealScalar *py, int *incy) +{ + Scalar* x = reinterpret_cast(px); + Scalar* y = reinterpret_cast(py); + Scalar alpha = *reinterpret_cast(palpha); + + if(*incx==1 && *incy==1) + vector(y,*n) += alpha * vector(x,*n); + else + vector(y,*n,*incy) += alpha * vector(x,*n,*incx); + + return 1; +} + +// computes the sum of magnitudes of all vector elements or, for a complex vector x, the sum +// res = |Rex1| + |Imx1| + |Rex2| + |Imx2| + ... + |Rexn| + |Imxn|, where x is a vector of order n +RealScalar EIGEN_BLAS_FUNC(asum)(int *n, RealScalar *px, int *incx) +{ + int size = IsComplex ? 2* *n : *n; + + if(*incx==1) + return vector(px,size).cwise().abs().sum(); + else + return vector(px,size,*incx).cwise().abs().sum(); + + return 1; +} + +int EIGEN_BLAS_FUNC(copy)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy) +{ + int size = IsComplex ? 2* *n : *n; + + if(*incx==1 && *incy==1) + vector(py,size) = vector(px,size); + else + vector(py,size,*incy) = vector(px,size,*incx); + + return 1; +} + +// computes a vector-vector dot product. +Scalar EIGEN_BLAS_FUNC(dot)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy) +{ + Scalar* x = reinterpret_cast(px); + Scalar* y = reinterpret_cast(py); + + if(*incx==1 && *incy==1) + return (vector(x,*n).cwise()*vector(y,*n)).sum(); + + return (vector(x,*n,*incx).cwise()*vector(y,*n,*incy)).sum(); +} + +/* + +// computes a vector-vector dot product with extended precision. +Scalar EIGEN_BLAS_FUNC(sdot)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy) +{ + // TODO + Scalar* x = reinterpret_cast(px); + Scalar* y = reinterpret_cast(py); + + if(*incx==1 && *incy==1) + return vector(x,*n).dot(vector(y,*n)); + + return vector(x,*n,*incx).dot(vector(y,*n,*incy)); +} + +*/ + +#if ISCOMPLEX + +// computes a dot product of a conjugated vector with another vector. +Scalar EIGEN_BLAS_FUNC(dotc)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy) +{ + Scalar* x = reinterpret_cast(px); + Scalar* y = reinterpret_cast(py); + + if(*incx==1 && *incy==1) + return vector(x,*n).dot(vector(y,*n)); + + return vector(x,*n,*incx).dot(vector(y,*n,*incy)); +} + +// computes a vector-vector dot product without complex conjugation. +Scalar EIGEN_BLAS_FUNC(dotu)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy) +{ + Scalar* x = reinterpret_cast(px); + Scalar* y = reinterpret_cast(py); + + if(*incx==1 && *incy==1) + return (vector(x,*n).cwise()*vector(y,*n)).sum(); + + return (vector(x,*n,*incx).cwise()*vector(y,*n,*incy)).sum(); +} + +#endif // ISCOMPLEX + +// computes the Euclidean norm of a vector. +Scalar EIGEN_BLAS_FUNC(nrm2)(int *n, RealScalar *px, int *incx) +{ + Scalar* x = reinterpret_cast(px); + + if(*incx==1) + return vector(x,*n).norm(); + + return vector(x,*n,*incx).norm(); +} + +int EIGEN_BLAS_FUNC(rot)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *pc, RealScalar *ps) +{ + Scalar* x = reinterpret_cast(px); + Scalar* y = reinterpret_cast(py); + Scalar c = *reinterpret_cast(pc); + Scalar s = *reinterpret_cast(ps); + + StridedVectorType vx(vector(x,*n,*incx)); + StridedVectorType vy(vector(y,*n,*incy)); + ei_apply_rotation_in_the_plane(vx, vy, PlanarRotation(c,s)); + return 1; +} + +int EIGEN_BLAS_FUNC(rotg)(RealScalar *pa, RealScalar *pb, RealScalar *pc, RealScalar *ps) +{ + Scalar a = *reinterpret_cast(pa); + Scalar b = *reinterpret_cast(pb); + Scalar* c = reinterpret_cast(pc); + Scalar* s = reinterpret_cast(ps); + + PlanarRotation r; + r.makeGivens(a,b); + *c = r.c(); + *s = r.s(); + + return 1; +} + +#if !ISCOMPLEX +/* +// performs rotation of points in the modified plane. +int EIGEN_BLAS_FUNC(rotm)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy, RealScalar *param) +{ + Scalar* x = reinterpret_cast(px); + Scalar* y = reinterpret_cast(py); + + // TODO + + return 0; +} + +// computes the modified parameters for a Givens rotation. +int EIGEN_BLAS_FUNC(rotmg)(RealScalar *d1, RealScalar *d2, RealScalar *x1, RealScalar *x2, RealScalar *param) +{ + // TODO + + return 0; +} +*/ +#endif // !ISCOMPLEX + +int EIGEN_BLAS_FUNC(scal)(int *n, RealScalar *px, int *incx, RealScalar *palpha) +{ + Scalar* x = reinterpret_cast(px); + Scalar alpha = *reinterpret_cast(palpha); + + if(*incx==1) + vector(x,*n) *= alpha; + + vector(x,*n,*incx) *= alpha; + + return 1; +} + +int EIGEN_BLAS_FUNC(swap)(int *n, RealScalar *px, int *incx, RealScalar *py, int *incy) +{ + int size = IsComplex ? 2* *n : *n; + + if(*incx==1 && *incy==1) + vector(py,size).swap(vector(px,size)); + else + vector(py,size,*incy).swap(vector(px,size,*incx)); + + return 1; +} + +#if !ISCOMPLEX + +RealScalar EIGEN_BLAS_FUNC(casum)(int *n, RealScalar *px, int *incx) +{ + Complex* x = reinterpret_cast(px); + + if(*incx==1) + return vector(x,*n).cwise().abs().sum(); + else + return vector(x,*n,*incx).cwise().abs().sum(); + + return 1; +} + +#endif // ISCOMPLEX diff --git a/blas/level2_impl.h b/blas/level2_impl.h new file mode 100644 index 000000000..5691e8a7f --- /dev/null +++ b/blas/level2_impl.h @@ -0,0 +1,214 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// 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 . + +#include "common.h" + +int EIGEN_BLAS_FUNC(gemv)(char *opa, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *incb, RealScalar *pbeta, RealScalar *pc, int *incc) +{ + Scalar* a = reinterpret_cast(pa); + Scalar* b = reinterpret_cast(pb); + Scalar* c = reinterpret_cast(pc); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); + + if(beta!=Scalar(1)) + vector(c, *m, *incc) *= beta; + + if(OP(*opa)==NOTR) + if(*incc==1) + vector(c,*m) += alpha * matrix(a,*m,*n,*lda) * vector(b,*n,*incb); + else + vector(c,*m,*incc) += alpha * matrix(a,*m,*n,*lda) * vector(b,*n,*incb); + else if(OP(*opa)==TR) + if(*incb==1) + vector(c,*m,*incc) += alpha * matrix(a,*n,*m,*lda).transpose() * vector(b,*n); + else + vector(c,*m,*incc) += alpha * matrix(a,*n,*m,*lda).transpose() * vector(b,*n,*incb); + else if(OP(*opa)==TR) + if(*incb==1) + vector(c,*m,*incc) += alpha * matrix(a,*n,*m,*lda).adjoint() * vector(b,*n); + else + vector(c,*m,*incc) += alpha * matrix(a,*n,*m,*lda).adjoint() * vector(b,*n,*incb); + else + return 0; + + return 1; +} + +/* +int EIGEN_BLAS_FUNC(trsv)(char *uplo, char *opa, char *diag, int *n, RealScalar *pa, int *lda, RealScalar *pb, int *incb) +{ + typedef void (*functype)(int, const Scalar *, int, Scalar *, int); + functype func[16]; + + static bool init = false; + if(!init) + { + for(int k=0; k<16; ++k) + func[k] = 0; + +// func[NOTR | (UP << 2) | (NUNIT << 3)] = (ei_triangular_solve_vector::run); +// func[TR | (UP << 2) | (NUNIT << 3)] = (ei_triangular_solve_vector::run); +// func[ADJ | (UP << 2) | (NUNIT << 3)] = (ei_triangular_solve_vector::run); +// +// func[NOTR | (LO << 2) | (NUNIT << 3)] = (ei_triangular_solve_vector::run); +// func[TR | (LO << 2) | (NUNIT << 3)] = (ei_triangular_solve_vector::run); +// func[ADJ | (LO << 2) | (NUNIT << 3)] = (ei_triangular_solve_vector::run); +// +// func[NOTR | (UP << 3) | (UNIT << 3)] = (ei_triangular_solve_vector::run); +// func[TR | (UP << 2) | (UNIT << 3)] = (ei_triangular_solve_vector::run); +// func[ADJ | (UP << 2) | (UNIT << 3)] = (ei_triangular_solve_vector::run); +// +// func[NOTR | (LO << 2) | (UNIT << 3)] = (ei_triangular_solve_vector::run); +// func[TR | (LO << 2) | (UNIT << 3)] = (ei_triangular_solve_vector::run); +// func[ADJ | (LO << 2) | (UNIT << 3)] = (ei_triangular_solve_vector::run); + + init = true; + } + + Scalar* a = reinterpret_cast(pa); + Scalar* b = reinterpret_cast(pb); + + int code = OP(*opa) | (UPLO(*uplo) << 2) | (DIAG(*diag) << 3); + if(code>=16 || func[code]==0) + return 0; + + func[code](*n, a, *lda, b, *incb); + return 1; +} +*/ + +/* +int EIGEN_BLAS_FUNC(trmv)(char *uplo, char *opa, char *diag, int *n, RealScalar *pa, int *lda, RealScalar *pb, int *incb) +{ + // TODO + + typedef void (*functype)(int, const Scalar *, int, const Scalar *, int, Scalar *, int); + functype func[16]; + + static bool init = false; + if(!init) + { + for(int k=0; k<16; ++k) + func[k] = 0; + +// func[NOTR | (UP << 2) | (NUNIT << 3)] = (ei_product_triangular_matrix_vector::run); +// func[TR | (UP << 2) | (NUNIT << 3)] = (ei_product_triangular_matrix_vector::run); +// func[ADJ | (UP << 2) | (NUNIT << 3)] = (ei_product_triangular_matrix_vector::run); +// +// func[NOTR | (LO << 2) | (NUNIT << 3)] = (ei_product_triangular_matrix_vector::run); +// func[TR | (LO << 2) | (NUNIT << 3)] = (ei_product_triangular_matrix_vector::run); +// func[ADJ | (LO << 2) | (NUNIT << 3)] = (ei_product_triangular_matrix_vector::run); +// +// func[NOTR | (UP << 2) | (UNIT << 3)] = (ei_product_triangular_matrix_vector::run); +// func[TR | (UP << 2) | (UNIT << 3)] = (ei_product_triangular_matrix_vector::run); +// func[ADJ | (UP << 2) | (UNIT << 3)] = (ei_product_triangular_matrix_vector::run); +// +// func[NOTR | (LO << 2) | (UNIT << 3)] = (ei_product_triangular_matrix_vector::run); +// func[TR | (LO << 2) | (UNIT << 3)] = (ei_product_triangular_matrix_vector::run); +// func[ADJ | (LO << 2) | (UNIT << 3)] = (ei_product_triangular_matrix_vector::run); + + init = true; + } + + Scalar* a = reinterpret_cast(pa); + Scalar* b = reinterpret_cast(pb); + + int code = OP(*opa) | (UPLO(*uplo) << 2) | (DIAG(*diag) << 3); + if(code>=16 || func[code]==0) + return 0; + + func[code](*n, a, *lda, b, *incb, b, *incb); + return 1; +} +*/ + +/* +int EIGEN_BLAS_FUNC(syr)(char *uplo, int *n, RealScalar *palpha, RealScalar *pa, int *inca, RealScalar *pc, int *ldc) +{ + // TODO + typedef void (*functype)(int, const Scalar *, int, Scalar *, int, Scalar); + functype func[2]; + + static bool init = false; + if(!init) + { + for(int k=0; k<2; ++k) + func[k] = 0; + +// func[UP] = (ei_selfadjoint_product::run); +// func[LO] = (ei_selfadjoint_product::run); + + init = true; + } + + Scalar* a = reinterpret_cast(pa); + Scalar* c = reinterpret_cast(pc); + Scalar alpha = *reinterpret_cast(palpha); + + int code = UPLO(*uplo); + if(code>=2 || func[code]==0) + return 0; + + func[code](*n, a, *inca, c, *ldc, alpha); + return 1; +} +*/ + +/* +int EIGEN_BLAS_FUNC(syr2)(char *uplo, int *n, RealScalar *palpha, RealScalar *pa, int *inca, RealScalar *pb, int *incb, RealScalar *pc, int *ldc) +{ + // TODO + typedef void (*functype)(int, const Scalar *, int, const Scalar *, int, Scalar *, int, Scalar); + functype func[2]; + + static bool init = false; + if(!init) + { + for(int k=0; k<2; ++k) + func[k] = 0; + +// func[UP] = (ei_selfadjoint_product::run); +// func[LO] = (ei_selfadjoint_product::run); + + init = true; + } + + Scalar* a = reinterpret_cast(pa); + Scalar* b = reinterpret_cast(pb); + Scalar* c = reinterpret_cast(pc); + Scalar alpha = *reinterpret_cast(palpha); + + int code = UPLO(*uplo); + if(code>=2 || func[code]==0) + return 0; + + func[code](*n, a, *inca, b, *incb, c, *ldc, alpha); + return 1; +} +*/ + +#if ISCOMPLEX + +#endif // ISCOMPLEX diff --git a/blas/level3_impl.h b/blas/level3_impl.h new file mode 100644 index 000000000..d44de1b5d --- /dev/null +++ b/blas/level3_impl.h @@ -0,0 +1,365 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// 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 . + +#include "common.h" + +int EIGEN_BLAS_FUNC(gemm)(char *opa, char *opb, int *m, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc) +{ + typedef void (*functype)(int, int, int, const Scalar *, int, const Scalar *, int, Scalar *, int, Scalar); + functype func[12]; + + static bool init = false; + if(!init) + { + for(int k=0; k<12; ++k) + func[k] = 0; + func[NOTR | (NOTR << 2)] = (ei_general_matrix_matrix_product::run); + func[TR | (NOTR << 2)] = (ei_general_matrix_matrix_product::run); + func[ADJ | (NOTR << 2)] = (ei_general_matrix_matrix_product::run); + func[NOTR | (TR << 2)] = (ei_general_matrix_matrix_product::run); + func[TR | (TR << 2)] = (ei_general_matrix_matrix_product::run); + func[ADJ | (TR << 2)] = (ei_general_matrix_matrix_product::run); + func[NOTR | (ADJ << 2)] = (ei_general_matrix_matrix_product::run); + func[TR | (ADJ << 2)] = (ei_general_matrix_matrix_product::run); + func[ADJ | (ADJ << 2)] = (ei_general_matrix_matrix_product::run); + init = true; + } + + Scalar* a = reinterpret_cast(pa); + Scalar* b = reinterpret_cast(pb); + Scalar* c = reinterpret_cast(pc); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); + + if(beta!=Scalar(1)) + matrix(c, *m, *n, *ldc) *= beta; + + int code = OP(*opa) | (OP(*opb) << 2); + if(code>=12 || func[code]==0) + return 0; + + func[code](*m, *n, *k, a, *lda, b, *ldb, c, *ldc, alpha); + return 1; +} + +int EIGEN_BLAS_FUNC(trsm)(char *side, char *uplo, char *opa, char *diag, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb) +{ + typedef void (*functype)(int, int, const Scalar *, int, Scalar *, int); + functype func[32]; + + static bool init = false; + if(!init) + { + for(int k=0; k<32; ++k) + func[k] = 0; + + func[NOTR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + func[TR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + func[ADJ | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + + func[NOTR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + func[TR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + func[ADJ | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + + func[NOTR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + func[TR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + func[ADJ | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + + func[NOTR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + func[TR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + func[ADJ | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_triangular_solve_matrix::run); + + + func[NOTR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + func[TR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + func[ADJ | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + + func[NOTR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + func[TR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + func[ADJ | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + + func[NOTR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + func[TR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + func[ADJ | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + + func[NOTR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + func[TR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + func[ADJ | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (ei_triangular_solve_matrix::run); + + init = true; + } + + Scalar* a = reinterpret_cast(pa); + Scalar* b = reinterpret_cast(pb); + Scalar alpha = *reinterpret_cast(palpha); + + // TODO handle alpha + + int code = OP(*opa) | (SIDE(*side) << 2) | (UPLO(*uplo) << 3) | (DIAG(*diag) << 4); + if(code>=32 || func[code]==0) + return 0; + + func[code](*m, *n, a, *lda, b, *ldb); + return 1; +} + + +// b = alpha*op(a)*b for side = 'L'or'l' +// b = alpha*b*op(a) for side = 'R'or'r' +int EIGEN_BLAS_FUNC(trmm)(char *side, char *uplo, char *opa, char *diag, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb) +{ + typedef void (*functype)(int, int, const Scalar *, int, const Scalar *, int, Scalar *, int, Scalar); + functype func[32]; + + static bool init = false; + if(!init) + { + for(int k=0; k<32; ++k) + func[k] = 0; + + func[NOTR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[TR | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[ADJ | (LEFT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + + func[NOTR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[TR | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[ADJ | (RIGHT << 2) | (UP << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + + func[NOTR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[TR | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[ADJ | (LEFT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + + func[NOTR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[TR | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[ADJ | (RIGHT << 2) | (LO << 3) | (NUNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + + func[NOTR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[TR | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[ADJ | (LEFT << 2) | (UP << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + + func[NOTR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[TR | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[ADJ | (RIGHT << 2) | (UP << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + + func[NOTR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[TR | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[ADJ | (LEFT << 2) | (LO << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + + func[NOTR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[TR | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + func[ADJ | (RIGHT << 2) | (LO << 3) | (UNIT << 4)] = (ei_product_triangular_matrix_matrix::run); + + init = true; + } + + Scalar* a = reinterpret_cast(pa); + Scalar* b = reinterpret_cast(pb); + Scalar alpha = *reinterpret_cast(palpha); + + int code = OP(*opa) | (SIDE(*side) << 2) | (UPLO(*uplo) << 3) | (DIAG(*diag) << 4); + if(code>=32 || func[code]==0) + return 0; + + func[code](*m, *n, a, *lda, b, *ldb, b, *ldb, alpha); + return 1; +} + +// c = alpha*a*b + beta*c for side = 'L'or'l' +// c = alpha*b*a + beta*c for side = 'R'or'r +int EIGEN_BLAS_FUNC(symm)(char *side, char *uplo, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc) +{ + Scalar* a = reinterpret_cast(pa); + Scalar* b = reinterpret_cast(pb); + Scalar* c = reinterpret_cast(pc); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); + + if(beta!=Scalar(1)) + matrix(c, *m, *n, *ldc) *= beta; + + if(SIDE(*side)==LEFT) + if(UPLO(*uplo)==UP) + ei_product_selfadjoint_matrix::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha); + else if(UPLO(*uplo)==LO) + ei_product_selfadjoint_matrix::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha); + else + return 0; + else if(SIDE(*side)==RIGHT) + if(UPLO(*uplo)==UP) + ei_product_selfadjoint_matrix::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha); + else if(UPLO(*uplo)==LO) + ei_product_selfadjoint_matrix::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha); + else + return 0; + else + return 0; + + return 1; +} + +// c = alpha*a*a' + beta*c for op = 'N'or'n' +// c = alpha*a'*a + beta*c for op = 'T'or't','C'or'c' +int EIGEN_BLAS_FUNC(syrk)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pbeta, RealScalar *pc, int *ldc) +{ + typedef void (*functype)(int, int, const Scalar *, int, Scalar *, int, Scalar); + functype func[8]; + + static bool init = false; + if(!init) + { + for(int k=0; k<8; ++k) + func[k] = 0; + + func[NOTR | (UP << 2)] = (ei_selfadjoint_product::run); + func[TR | (UP << 2)] = (ei_selfadjoint_product::run); + func[ADJ | (UP << 2)] = (ei_selfadjoint_product::run); + + func[NOTR | (LO << 2)] = (ei_selfadjoint_product::run); + func[TR | (LO << 2)] = (ei_selfadjoint_product::run); + func[ADJ | (LO << 2)] = (ei_selfadjoint_product::run); + + init = true; + } + + Scalar* a = reinterpret_cast(pa); + Scalar* c = reinterpret_cast(pc); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); + + int code = OP(*op) | (UPLO(*uplo) << 2); + if(code>=8 || func[code]==0) + return 0; + + if(beta!=Scalar(1)) + matrix(c, *n, *n, *ldc) *= beta; + + func[code](*n, *k, a, *lda, c, *ldc, alpha); + return 1; +} + +// c = alpha*a*b' + alpha*b*a' + beta*c for op = 'N'or'n' +// c = alpha*a'*b + alpha*b'*a + beta*c for op = 'T'or't' +int EIGEN_BLAS_FUNC(syr2k)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc) +{ + Scalar* a = reinterpret_cast(pa); + Scalar* b = reinterpret_cast(pb); + Scalar* c = reinterpret_cast(pc); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); + + // TODO + + return 0; +} + + +#if ISCOMPLEX + +// c = alpha*a*b + beta*c for side = 'L'or'l' +// c = alpha*b*a + beta*c for side = 'R'or'r +int EIGEN_BLAS_FUNC(hemm)(char *side, char *uplo, int *m, int *n, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc) +{ + Scalar* a = reinterpret_cast(pa); + Scalar* b = reinterpret_cast(pb); + Scalar* c = reinterpret_cast(pc); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); + + if(beta!=Scalar(1)) + matrix(c, *m, *n, *ldc) *= beta; + + if(SIDE(*side)==LEFT) + if(UPLO(*uplo)==UP) + ei_product_selfadjoint_matrix::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha); + else if(UPLO(*uplo)==LO) + ei_product_selfadjoint_matrix::run(*m, *n, a, *lda, b, *ldb, c, *ldc, alpha); + else + return 0; + else if(SIDE(*side)==RIGHT) + if(UPLO(*uplo)==UP) + ei_product_selfadjoint_matrix::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha); + else if(UPLO(*uplo)==LO) + ei_product_selfadjoint_matrix::run(*m, *n, b, *ldb, a, *lda, c, *ldc, alpha); + else + return 0; + else + return 0; + + return 1; +} + +// c = alpha*a*conj(a') + beta*c for op = 'N'or'n' +// c = alpha*conj(a')*a + beta*c for op = 'C'or'c' +int EIGEN_BLAS_FUNC(herk)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pbeta, RealScalar *pc, int *ldc) +{ + typedef void (*functype)(int, int, const Scalar *, int, Scalar *, int, Scalar); + functype func[8]; + + static bool init = false; + if(!init) + { + for(int k=0; k<8; ++k) + func[k] = 0; + + func[NOTR | (UP << 2)] = (ei_selfadjoint_product::run); + func[ADJ | (UP << 2)] = (ei_selfadjoint_product::run); + + func[NOTR | (LO << 2)] = (ei_selfadjoint_product::run); + func[ADJ | (LO << 2)] = (ei_selfadjoint_product::run); + + init = true; + } + + Scalar* a = reinterpret_cast(pa); + Scalar* c = reinterpret_cast(pc); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); + + int code = OP(*op) | (UPLO(*uplo) << 2); + if(code>=8 || func[code]==0) + return 0; + + if(beta!=Scalar(1)) + matrix(c, *n, *n, *ldc) *= beta; + + func[code](*n, *k, a, *lda, c, *ldc, alpha); + return 1; +} + +// c = alpha*a*conj(b') + conj(alpha)*b*conj(a') + beta*c, for op = 'N'or'n' +// c = alpha*conj(b')*a + conj(alpha)*conj(a')*b + beta*c, for op = 'C'or'c' +int EIGEN_BLAS_FUNC(her2k)(char *uplo, char *op, int *n, int *k, RealScalar *palpha, RealScalar *pa, int *lda, RealScalar *pb, int *ldb, RealScalar *pbeta, RealScalar *pc, int *ldc) +{ + Scalar* a = reinterpret_cast(pa); + Scalar* b = reinterpret_cast(pb); + Scalar* c = reinterpret_cast(pc); + Scalar alpha = *reinterpret_cast(palpha); + Scalar beta = *reinterpret_cast(pbeta); + + // TODO + + return 0; +} + +#endif // ISCOMPLEX diff --git a/blas/single.cpp b/blas/single.cpp new file mode 100644 index 000000000..842e104b8 --- /dev/null +++ b/blas/single.cpp @@ -0,0 +1,31 @@ +// This file is part of Eigen, a lightweight C++ template library +// for linear algebra. +// +// Copyright (C) 2009 Gael Guennebaud +// +// 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 . + +#define SCALAR float +#define SCALAR_SUFFIX s +#define ISCOMPLEX 0 + +#include "level1_impl.h" +#include "level2_impl.h" +#include "level3_impl.h" From 21d2533723ae31bb7b979239dd45af8489e65397 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 25 Sep 2009 14:44:48 +0200 Subject: [PATCH 39/83] Matrix::conservativeResize, resize only when necessary. --- Eigen/src/Core/Matrix.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Eigen/src/Core/Matrix.h b/Eigen/src/Core/Matrix.h index 2e2826205..027e6bb70 100644 --- a/Eigen/src/Core/Matrix.h +++ b/Eigen/src/Core/Matrix.h @@ -707,6 +707,8 @@ struct ei_conservative_resize_like_impl { static void run(MatrixBase& _this, const MatrixBase& other) { + if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; + // Note: Here is space for improvement. Basically, for conservativeResize(int,int), // neither RowsAtCompileTime or ColsAtCompileTime must be Dynamic. If only one of the // dimensions is dynamic, one could use either conservativeResize(int rows, NoChange_t) or @@ -728,6 +730,8 @@ struct ei_conservative_resize_like_impl { static void run(MatrixBase& _this, const MatrixBase& other) { + if (_this.rows() == other.rows() && _this.cols() == other.cols()) return; + // segment(...) will check whether Derived/OtherDerived are vectors! typename MatrixBase::PlainMatrixType tmp(other); const int common_size = std::min(_this.size(),tmp.size()); From 104f9954e1ebf7421b99e6906b5d1700869748d7 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 25 Sep 2009 14:58:20 +0200 Subject: [PATCH 40/83] Removed implicit type conversion (VC warning fix). --- Eigen/src/Core/MathFunctions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Eigen/src/Core/MathFunctions.h b/Eigen/src/Core/MathFunctions.h index 8c86d1dd4..05469b340 100644 --- a/Eigen/src/Core/MathFunctions.h +++ b/Eigen/src/Core/MathFunctions.h @@ -332,7 +332,7 @@ inline bool ei_sqrt(bool x) { return x; } template<> inline bool ei_random() { - return ei_random(0,1); + return (ei_random(0,1) == 1); } inline bool ei_isMuchSmallerThan(bool a, bool, bool = precision()) { From c532f42a0e6b2587e3dfe4ba00cc9c64bc8d1130 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Fri, 25 Sep 2009 16:30:44 +0200 Subject: [PATCH 41/83] update the sparse tutorial wrt not so recent changes about the filling API --- doc/C07_TutorialSparse.dox | 67 +++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 37 deletions(-) diff --git a/doc/C07_TutorialSparse.dox b/doc/C07_TutorialSparse.dox index 3a7182883..ae96d77c4 100644 --- a/doc/C07_TutorialSparse.dox +++ b/doc/C07_TutorialSparse.dox @@ -129,7 +129,7 @@ SparseVector vec(size); for (SparseVector::InnerIterator it(vec); it; ++it) { it.value(); // == vec[ it.index() ] - it.index(); + it.index(); } \endcode @@ -138,58 +138,51 @@ for (SparseVector::InnerIterator it(vec); it; ++it) \section TutorialSparseFilling Filling a sparse matrix -A DynamicSparseMatrix object can be set and updated just like any dense matrix using the coeffRef(row,col) method. If the coefficient is not stored yet, then it will be inserted in the matrix. Here is an example: +Owing to the special storage scheme of a SparseMatrix, it is obvious that for performance reasons a sparse matrix cannot be filled as easily as a dense matrix. For instance the cost of a purely random insertion into a SparseMatrix is in O(nnz) where nnz is the current number of non zeros. In order to cover all uses cases with best efficiency, Eigen provides various mechanisms, from the easiest but slowest, to the fastest but restrictive one. + +If you don't have any prior knowledge about the order your matrix will be filled, then the best choice is to use a DynamicSparseMatrix. With a DynamicSparseMatrix, you can add or modify any coefficients at any time using the coeffRef(row,col) method. Here is an example: \code DynamicSparseMatrix aux(1000,1000); +aux.reserve(estimated_number_of_non_zero); // optional for (...) - for each i - for each j interacting with i - aux.coeffRef(i,j) += foo(o1,o2); -SparseMatrix mat(aux); // convert the DynamicSparseMatrix to a SparseMatrix + for each j // the j can be random + for each i interacting with j // the i can be random + aux.coeffRef(i,j) += foo(i,j); +\endcode +Then the DynamicSparseMatrix object can be converted to a compact SparseMatrix to be used, e.g., by one of our supported solver: +\code +SparseMatrix mat(aux); \endcode -Sometimes, however, we simply want to set all the coefficients of a matrix before using it through standard matrix operations (addition, product, etc.). In that case it faster to use the low-level startFill()/fill()/fillrand()/endFill() interface. Even though this interface is availabe for both sparse matrix types, their respective restrictions slightly differ from one representation to the other. In all case, a call to startFill() set the matrix to zero, and the fill*() functions will fail if the coefficient already exist. +In order to optimize this process, instead of the generic coeffRef(i,j) method one can also use: + - \code m.insert(i,j) = value; \endcode which assumes the coefficient of coordinate (row,col) does not already exist (otherwise this is a programming error and your program will stop). + - \code m.insertBack(i,j) = value; \endcode which, in addition to the requirements of insert(), also assumes that the coefficient of coordinate (row,col) will be inserted at the end of the target inner-vector. More precisely, if the matrix m is column major, then the row index of the last non zero coefficient of the j-th column must be smaller than i. -As a first difference, for SparseMatrix, the fill*() functions can only be called inside a startFill()/endFill() pair, and no other member functions are allowed during the filling process, i.e., until endFill() has been called. On the other hand, a DynamicSparseMatrix is always in a stable state, and the startFill()/endFill() functions are only for compatibility purpose. -Another difference is that the fill*() functions must be called with increasing outer indices for a SparseMatrix, while they can be random for a DynamicSparseMatrix. +Actually, the SparseMatrix class also supports random insertion via the insert() method. However, its uses should be reserved in cases where the inserted non zero is nearly the last one of the compact storage array. In practice, this means it should be used only to perform random (or sorted) insertion into the current inner-vector while filling the inner-vectors in an increasing order. Moreover, with a SparseMatrix an insertion session must be closed by a call to finalize() before any use of the matrix. Here is an example for a column major matrix: -Finally, the fill() function assumes the coefficient are inserted in a sorted order per inner vector, while the fillrand() variante allows random insertions (the outer indices must still be sorted for SparseMatrix). - -Some examples: - -1 - If you can set the coefficients in exactly the same order that the storage order, then the matrix can be filled directly and very efficiently. Here is an example initializing a random, row-major sparse matrix: \code -SparseMatrix m(rows,cols); -m.startFill(rows*cols*percent_of_non_zero); // estimate of the number of nonzeros (optional) -for (int i=0; i\ mat(1000,1000); +mat.reserve(estimated_number_of_non_zero); // optional +for each j // should be in increasing order for performance reasons + for each i interacting with j // the i can be random + mat.insert(i,j) = foo(i,j); // optional for a DynamicSparseMatrix +mat.finalize(); \endcode -2 - If you can set each outer vector in a consistent order, but do not have sorted data for each inner vector, then you can use fillrand() instead of fill(): -\code -SparseMatrix m(rows,cols); -m.startFill(rows*cols*percent_of_non_zero); // estimate of the number of nonzeros (optional) -for (int i=0; i\ m(rows,cols); +SparseMatrix mat(1000,1000); +mat.reserve(estimated_number_of_non_zero); // optional +for(int j=0; j<1000; ++j) { - RandomSetter > setter(m); - for (int k=0; k\ Date: Sun, 27 Sep 2009 01:56:50 +0200 Subject: [PATCH 42/83] update URL for adol-c --- doc/I00_CustomizingEigen.dox | 2 +- unsupported/Eigen/AdolcForward | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/I00_CustomizingEigen.dox b/doc/I00_CustomizingEigen.dox index 8182a86ef..7c8ba9b75 100644 --- a/doc/I00_CustomizingEigen.dox +++ b/doc/I00_CustomizingEigen.dox @@ -125,7 +125,7 @@ In order to add support for a custom type \c T you need: 3 - define a couple of math functions for your type such as: ei_sqrt, ei_abs, etc... (see the file Eigen/src/Core/MathFunctions.h) -Here is a concrete example adding support for the Adolc's \c adouble type. Adolc is an automatic differentiation library. The type \c adouble is basically a real value tracking the values of any number of partial derivatives. +Here is a concrete example adding support for the Adolc's \c adouble type. Adolc is an automatic differentiation library. The type \c adouble is basically a real value tracking the values of any number of partial derivatives. \code #ifndef ADLOCSUPPORT_H diff --git a/unsupported/Eigen/AdolcForward b/unsupported/Eigen/AdolcForward index 9a54a3aaa..70aa47815 100644 --- a/unsupported/Eigen/AdolcForward +++ b/unsupported/Eigen/AdolcForward @@ -29,7 +29,7 @@ // // This file provides support for adolc's adouble type in forward mode. // ADOL-C is a C++ automatic differentiation library, -// see http://www.math.tu-dresden.de/~adol-c/ for more information. +// see https://projects.coin-or.org/ADOL-C for more information. // // Note that the maximal number of directions is controlled by // the preprocessor token NUMBER_DIRECTIONS. The default is 2. @@ -63,7 +63,7 @@ namespace Eigen { * \defgroup AdolcForward_Module Adolc forward module * This module provides support for adolc's adouble type in forward mode. * ADOL-C is a C++ automatic differentiation library, - * see http://www.math.tu-dresden.de/~adol-c/ for more information. + * see https://projects.coin-or.org/ADOL-C for more information. * It mainly consists in: * - a struct Eigen::NumTraits specialization * - overloads of ei_* math function for adtl::adouble type. From 13545eab9b20cc4b66f67afd068b36521536bf64 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Sun, 27 Sep 2009 17:00:10 +0200 Subject: [PATCH 43/83] Fixed VC compilation error on the JacobiSVD module. --- Eigen/src/SVD/JacobiSVD.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index 4b69e67c4..d6b4561cf 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -26,20 +26,21 @@ #define EIGEN_JACOBISVD_H // forward declarations (needed by ICC) +// the empty bodies are required by VC template::IsComplex> -struct ei_svd_precondition_2x2_block_to_be_real; +struct ei_svd_precondition_2x2_block_to_be_real {}; templateMatrixType::ColsAtCompileTime))> -struct ei_svd_precondition_if_more_rows_than_cols; +struct ei_svd_precondition_if_more_rows_than_cols {}; templateMatrixType::RowsAtCompileTime))> -struct ei_svd_precondition_if_more_cols_than_rows; +struct ei_svd_precondition_if_more_cols_than_rows {}; /** \ingroup SVD_Module * \nonstableyet From 3c74d6b7d4598196d9356510a686fb7f929cf04d Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Sun, 27 Sep 2009 17:03:02 +0200 Subject: [PATCH 44/83] Added private, non-implemented assignment operators to functions that don't need them (fixes VC warning on /W4). --- Eigen/src/Core/CommaInitializer.h | 3 +++ Eigen/src/Core/Cwise.h | 3 +++ Eigen/src/Core/Functors.h | 6 ++++++ Eigen/src/Core/NestByValue.h | 3 +++ Eigen/src/Core/NoAlias.h | 3 +++ Eigen/src/Core/Product.h | 6 ++++++ Eigen/src/Core/ProductBase.h | 2 ++ Eigen/src/Householder/HouseholderSequence.h | 4 +++- 8 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Eigen/src/Core/CommaInitializer.h b/Eigen/src/Core/CommaInitializer.h index e86f47ad0..328c5580c 100644 --- a/Eigen/src/Core/CommaInitializer.h +++ b/Eigen/src/Core/CommaInitializer.h @@ -116,6 +116,9 @@ struct CommaInitializer int m_row; // current row id int m_col; // current col id int m_currentBlockRows; // current block height + +private: + CommaInitializer& operator=(const CommaInitializer&); }; /** \anchor MatrixBaseCommaInitRef diff --git a/Eigen/src/Core/Cwise.h b/Eigen/src/Core/Cwise.h index fbf206d9c..4b143325e 100644 --- a/Eigen/src/Core/Cwise.h +++ b/Eigen/src/Core/Cwise.h @@ -178,6 +178,9 @@ template class Cwise protected: ExpressionTypeNested m_matrix; + + private: + Cwise& operator=(const Cwise&); }; /** \returns a Cwise wrapper of *this providing additional coefficient-wise operations diff --git a/Eigen/src/Core/Functors.h b/Eigen/src/Core/Functors.h index 0c68d7434..cbaeb83e2 100644 --- a/Eigen/src/Core/Functors.h +++ b/Eigen/src/Core/Functors.h @@ -351,6 +351,8 @@ struct ei_scalar_multiple_op { EIGEN_STRONG_INLINE const PacketScalar packetOp(const PacketScalar& a) const { return ei_pmul(a, ei_pset1(m_other)); } const Scalar m_other; +private: + ei_scalar_multiple_op& operator=(const ei_scalar_multiple_op&); }; template struct ei_functor_traits > @@ -378,6 +380,8 @@ struct ei_scalar_quotient1_impl { EIGEN_STRONG_INLINE const PacketScalar packetOp(const PacketScalar& a) const { return ei_pmul(a, ei_pset1(m_other)); } const Scalar m_other; +private: + ei_scalar_quotient1_impl& operator=(const ei_scalar_quotient1_impl&); }; template struct ei_functor_traits > @@ -423,6 +427,8 @@ struct ei_scalar_constant_op { EIGEN_STRONG_INLINE const Scalar operator() (int, int = 0) const { return m_other; } EIGEN_STRONG_INLINE const PacketScalar packetOp() const { return ei_pset1(m_other); } const Scalar m_other; +private: + ei_scalar_constant_op& operator=(const ei_scalar_constant_op&); }; template struct ei_functor_traits > diff --git a/Eigen/src/Core/NestByValue.h b/Eigen/src/Core/NestByValue.h index 85a672779..94a8f8078 100644 --- a/Eigen/src/Core/NestByValue.h +++ b/Eigen/src/Core/NestByValue.h @@ -102,6 +102,9 @@ template class NestByValue protected: const ExpressionType m_expression; + + private: + NestByValue& operator=(const NestByValue&); }; /** \returns an expression of the temporary version of *this. diff --git a/Eigen/src/Core/NoAlias.h b/Eigen/src/Core/NoAlias.h index 66d8d834d..dc32c2f7b 100644 --- a/Eigen/src/Core/NoAlias.h +++ b/Eigen/src/Core/NoAlias.h @@ -73,6 +73,9 @@ class NoAlias protected: ExpressionType& m_expression; + + private: + NoAlias& operator=(const NoAlias&); }; /** \returns a pseudo expression of \c *this with an operator= assuming diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 7f0c2df6e..287fc9c5b 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -211,6 +211,9 @@ class GeneralProduct { ei_outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha); } + + private: + GeneralProduct& operator=(const GeneralProduct&); }; template<> struct ei_outer_product_selector { @@ -276,6 +279,9 @@ class GeneralProduct ei_gemv_selector::ActualAccess)>::run(*this, dst, alpha); } + +private: + GeneralProduct& operator=(const GeneralProduct&); }; // The vector is on the left => transposition diff --git a/Eigen/src/Core/ProductBase.h b/Eigen/src/Core/ProductBase.h index 764dc4d8e..57183ac52 100644 --- a/Eigen/src/Core/ProductBase.h +++ b/Eigen/src/Core/ProductBase.h @@ -137,6 +137,8 @@ class ProductBase : public MatrixBase void coeffRef(int,int); void coeff(int) const; void coeffRef(int); + + ProductBase& operator=(const ProductBase&); }; template diff --git a/Eigen/src/Householder/HouseholderSequence.h b/Eigen/src/Householder/HouseholderSequence.h index 16e362814..f5a8dd742 100644 --- a/Eigen/src/Householder/HouseholderSequence.h +++ b/Eigen/src/Householder/HouseholderSequence.h @@ -153,10 +153,12 @@ template class HouseholderSequence } protected: - typename VectorsType::Nested m_vectors; typename CoeffsType::Nested m_coeffs; bool m_trans; + +private: + HouseholderSequence& operator=(const HouseholderSequence&); }; template From e115fa3cead89763d4c07a5de834220f6fd73e4a Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Sun, 27 Sep 2009 17:18:19 +0200 Subject: [PATCH 45/83] Ok, too many class bodies - it was only required for ei_svd_precondition_2x2_block_to_be_real. --- Eigen/src/SVD/JacobiSVD.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Eigen/src/SVD/JacobiSVD.h b/Eigen/src/SVD/JacobiSVD.h index d6b4561cf..6a0597893 100644 --- a/Eigen/src/SVD/JacobiSVD.h +++ b/Eigen/src/SVD/JacobiSVD.h @@ -34,13 +34,13 @@ templateMatrixType::ColsAtCompileTime))> -struct ei_svd_precondition_if_more_rows_than_cols {}; +struct ei_svd_precondition_if_more_rows_than_cols; templateMatrixType::RowsAtCompileTime))> -struct ei_svd_precondition_if_more_cols_than_rows {}; +struct ei_svd_precondition_if_more_cols_than_rows; /** \ingroup SVD_Module * \nonstableyet From 6b23cb210144683351f94d43c99106b71ce8393d Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sun, 27 Sep 2009 11:39:51 -0400 Subject: [PATCH 46/83] remove the hack we made to allow api.kde.org to generate the dox. Update the error help page. --- Doxyfile | 2 +- Mainpage.dox | 118 +++------------------------------------------------ 2 files changed, 6 insertions(+), 114 deletions(-) diff --git a/Doxyfile b/Doxyfile index f31cf5b35..6065beb0c 100644 --- a/Doxyfile +++ b/Doxyfile @@ -5,7 +5,7 @@ #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = Eigen -PROJECT_NUMBER = 2.0 +PROJECT_NUMBER = you-got-it-wrong OUTPUT_DIRECTORY = ./ CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English diff --git a/Mainpage.dox b/Mainpage.dox index b5b7f30fa..7e8950170 100644 --- a/Mainpage.dox +++ b/Mainpage.dox @@ -1,127 +1,19 @@ - -// Please don't remove the following lines: -// this is the only way to specify doxygen options -// to api.kde.org's scripts - -// DOXYGEN_SET_PROJECT_NAME = Eigen2 -// DOXYGEN_SET_PROJECT_NUMBER = "2.0 - trunk" - -// DOXYGEN_SET_CREATE_SUBDIRS = NO -// DOXYGEN_SET_BRIEF_MEMBER_DESC = YES -// DOXYGEN_SET_REPEAT_BRIEF = YES -// DOXYGEN_SET_ALWAYS_DETAILED_SEC = NO -// DOXYGEN_SET_INLINE_INHERITED_MEMB = NO -// DOXYGEN_SET_FULL_PATH_NAMES = NO -// DOXYGEN_SET_SHORT_NAMES = NO -// DOXYGEN_SET_JAVADOC_AUTOBRIEF = NO -// DOXYGEN_SET_QT_AUTOBRIEF = NO -// DOXYGEN_SET_MULTILINE_CPP_IS_BRIEF = NO -// DOXYGEN_SET_DETAILS_AT_TOP = YES -// DOXYGEN_SET_INHERIT_DOCS = YES -// DOXYGEN_SET_ALIASES = "only_for_vectors=This is only for vectors (either row-vectors or column-vectors), i.e. matrices which are known at compile-time to have either one row or one column." "array_module=This is defined in the %Array module. \code #include \endcode" "lu_module=This is defined in the %LU module. \code #include \endcode" "cholesky_module=This is defined in the %Cholesky module. \code #include \endcode" "qr_module=This is defined in the %QR module. \code #include \endcode" "svd_module=This is defined in the %SVD module. \code #include \endcode" "geometry_module=This is defined in the %Geometry module. \code #include \endcode" "leastsquares_module=This is defined in the %LeastSquares module. \code #include \endcode" "addexample=\anchor" "label=\bug" "redstar=*" "nonstableyet=\warning This is not considered to be part of the stable public API yet. Changes may happen in future releases. See \ref Experimental \"Experimental parts of Eigen\"" -// DOXYGEN_SET_DISTRIBUTE_GROUP_DOC = NO -// DOXYGEN_SET_SUBGROUPING = YES -// DOXYGEN_SET_TYPEDEF_HIDES_STRUCT = NO - -// DOXYGEN_SET_EXTRACT_ALL = NO -// DOXYGEN_SET_EXTRACT_PRIVATE = NO -// DOXYGEN_SET_EXTRACT_STATIC = NO -// DOXYGEN_SET_EXTRACT_LOCAL_CLASSES = NO -// DOXYGEN_SET_EXTRACT_LOCAL_METHODS = NO -// DOXYGEN_SET_EXTRACT_ANON_NSPACES = NO -// DOXYGEN_SET_HIDE_UNDOC_MEMBERS = NO -// DOXYGEN_SET_HIDE_UNDOC_CLASSES = YES -// DOXYGEN_SET_HIDE_FRIEND_COMPOUNDS = YES -// DOXYGEN_SET_HIDE_IN_BODY_DOCS = NO -// DOXYGEN_SET_INTERNAL_DOCS = NO -// DOXYGEN_SET_CASE_SENSE_NAMES = YES -// DOXYGEN_SET_HIDE_SCOPE_NAMES = YES -// DOXYGEN_SET_SHOW_INCLUDE_FILES = YES -// DOXYGEN_SET_INLINE_INFO = YES -// DOXYGEN_SET_SORT_MEMBER_DOCS = YES -// DOXYGEN_SET_SORT_BRIEF_DOCS = YES -// DOXYGEN_SET_SORT_GROUP_NAMES = NO -// DOXYGEN_SET_SORT_BY_SCOPE_NAME = NO -// DOXYGEN_SET_GENERATE_TODOLIST = NO -// DOXYGEN_SET_GENERATE_TESTLIST = NO -// DOXYGEN_SET_GENERATE_BUGLIST = NO -// DOXYGEN_SET_GENERATE_DEPRECATEDLIST= NO -// DOXYGEN_SET_SHOW_USED_FILES = YES -// DOXYGEN_SET_SHOW_DIRECTORIES = NO -// DOXYGEN_SET_SHOW_FILES = YES -// DOXYGEN_SET_SHOW_NAMESPACES = NO - -// DOXYGEN_SET_WARN_IF_UNDOCUMENTED = NO -// DOXYGEN_SET_WARN_NO_PARAMDOC = NO - -// DOXYGEN_SET_INPUT = @topdir@/eigen2/Eigen @topdir@/eigen2/doc @topdir@/eigen2/build/doc @topdir@/eigen2/unsupported/Eigen -// DOXYGEN_SET_EXCLUDE = *.sh *.in - -// DOXYGEN_SET_EXAMPLE_PATH = @topdir@/eigen2/doc/snippets/ @topdir@/eigen2/doc/examples/ @topdir@/eigen2/build/doc/examples/ @topdir@/eigen2/build/doc/snippets/ - -// DOXYGEN_SET_FILE_PATTERNS = * -// DOXYGEN_SET_RECURSIVE = NO -// DOXYGEN_SET_FILTER_SOURCE_FILES = YES - -// DOXYGEN_EXCLUDE_SYMBOLS = MatrixBase<* MapBase<* RotationBase<* Matrix<* - -// DOXYGEN_SET_SOURCE_BROWSER = NO -// DOXYGEN_SET_INLINE_SOURCES = NO -// DOXYGEN_SET_STRIP_CODE_COMMENTS = YES -// DOXYGEN_SET_REFERENCED_BY_RELATION = YES -// DOXYGEN_SET_REFERENCES_RELATION = YES -// DOXYGEN_SET_REFERENCES_LINK_SOURCE = YES -// DOXYGEN_SET_VERBATIM_HEADERS = YES - -// DOXYGEN_SET_ALPHABETICAL_INDEX = NO - -// DOXYGEN_SET_HTML_ALIGN_MEMBERS = YES -// DOXYGEN_SET_GENERATE_TREEVIEW = NO -// DOXYGEN_SET_FORMULA_FONTSIZE = 12 - -// DOXYGEN_SET_GENERATE_LATEX = NO -// DOXYGEN_SET_EXTRA_PACKAGES = amssymb - -// DOXYGEN_SET_ENABLE_PREPROCESSING = YES -// DOXYGEN_SET_MACRO_EXPANSION = YES -// DOXYGEN_SET_EXPAND_ONLY_PREDEF = YES -// DOXYGEN_SET_SEARCH_INCLUDES = YES -// DOXYGEN_SET_PREDEFINED = EIGEN_EMPTY_STRUCT EIGEN_PARSED_BY_DOXYGEN EIGEN_VECTORIZE EIGEN_QT_SUPPORT EIGEN_STRONG_INLINE=inline -// DOXYGEN_SET_EXPAND_AS_DEFINED = EIGEN_MAKE_SCALAR_OPS EIGEN_MAKE_TYPEDEFS EIGEN_MAKE_TYPEDEFS_ALL_SIZES EIGEN_CWISE_UNOP_RETURN_TYPE EIGEN_CWISE_BINOP_RETURN_TYPE -// DOXYGEN_SET_SKIP_FUNCTION_MACROS = YES - -// DOXYGEN_SET_CLASS_DIAGRAMS = NO -// DOXYGEN_SET_HIDE_UNDOC_RELATIONS = NO -// DOXYGEN_SET_HAVE_DOT = NO -// DOXYGEN_SET_CLASS_GRAPH = NO -// DOXYGEN_SET_COLLABORATION_GRAPH = NO -// DOXYGEN_SET_GROUP_GRAPHS = NO -// DOXYGEN_SET_UML_LOOK = NO -// DOXYGEN_SET_TEMPLATE_RELATIONS = NO -// DOXYGEN_SET_INCLUDE_GRAPH = NO -// DOXYGEN_SET_INCLUDED_BY_GRAPH = NO -// DOXYGEN_SET_CALL_GRAPH = NO -// DOXYGEN_SET_CALLER_GRAPH = NO -// DOXYGEN_SET_GRAPHICAL_HIERARCHY = NO -// DOXYGEN_SET_DIRECTORY_GRAPH = NO - - o /** \mainpage Eigen

If you see this page, then you have not properly generated the documentation. Namely, you have run doxygen from the source directory, which is not appropriate for generating the documentation of Eigen.

In order to generate the documentation of Eigen, please follow these steps:
    -
  • make sure you have the required software installed: cmake, doxygen, and a C++ compiler. +
  • make sure you have the required software installed: CMake, Doxygen, LaTeX, and a C++ compiler.
  • create a new directory, which we will call the "build directory", outside of the Eigen source directory.
  • enter the build directory
  • configure the project:
    cmake /path/to/source/directory
  • -
  • now generate the documentaion:
    make doc
    or, if you have two CPUs,
    make doc -j2
    Note that this will compile the examples, run them, and integrate their output into the documentation, which can take some time.
  • +
  • now generate the documentaion:
    make doc
    or, if you have two CPUs,
    make doc -j3
    Note that this will compile the examples, run them, and integrate their output into the documentation, which can take some time.
After doing that, you will find the HTML documentation in the doc/html/ subdirectory of the build directory. -

Note however that the documentation is available online here: -http://eigen.tuxfamily.org/dox

- +

Note however that the documentation is available online here:

+http://eigen.tuxfamily.org/dox for the stable version and +http://eigen.tuxfamily.org/dox-devel for the development branch version. */ From 92480ffd265475a25070b8ea9dfbc8536d038378 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sun, 27 Sep 2009 17:48:53 -0400 Subject: [PATCH 47/83] * Introduce make targets btest (build tests), blas (build blas lib), demos (build demos). * remove EIGEN_BUILD_TESTS and siblings * add summary at the end of cmake run, hopefully not too verbose * fix build of quaternion demo * kill remnants of old binary library option --- CMakeLists.txt | 44 ++++++++--------- Eigen/src/Cholesky/CholeskyInstantiations.cpp | 35 -------------- Eigen/src/Core/CMakeLists.txt | 9 +--- Eigen/src/Core/CoreInstantiations.cpp | 47 ------------------- Eigen/src/QR/QrInstantiations.cpp | 38 --------------- blas/CMakeLists.txt | 2 + cmake/EigenTesting.cmake | 13 ++--- demos/CMakeLists.txt | 10 +++- demos/mandelbrot/CMakeLists.txt | 1 + demos/mix_eigen_and_c/README | 4 +- demos/opengl/CMakeLists.txt | 2 +- demos/opengl/camera.cpp | 2 +- test/CMakeLists.txt | 3 +- unsupported/CMakeLists.txt | 10 +--- 14 files changed, 47 insertions(+), 173 deletions(-) delete mode 100644 Eigen/src/Cholesky/CholeskyInstantiations.cpp delete mode 100644 Eigen/src/Core/CoreInstantiations.cpp delete mode 100644 Eigen/src/QR/QrInstantiations.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 94b2e99d0..be76903e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,20 +33,11 @@ include(CheckCXXCompilerFlag) set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) -option(EIGEN_BUILD_TESTS "Build tests" OFF) -option(EIGEN_BUILD_DEMOS "Build demos" OFF) -if(NOT WIN32) - option(EIGEN_BUILD_LIB "Build the binary shared library" OFF) -endif(NOT WIN32) option(EIGEN_BUILD_BTL "Build benchmark suite" OFF) if(NOT WIN32) option(EIGEN_BUILD_PKGCONFIG "Build pkg-config .pc file for Eigen" ON) endif(NOT WIN32) -if(EIGEN_BUILD_LIB) - option(EIGEN_TEST_LIB "Build the unit tests using the library (disable -pedantic)" OFF) -endif(EIGEN_BUILD_LIB) - set(CMAKE_INCLUDE_CURRENT_DIR ON) if(CMAKE_COMPILER_IS_GNUCXX) @@ -129,27 +120,32 @@ endif(EIGEN_BUILD_PKGCONFIG) add_subdirectory(Eigen) -add_subdirectory(doc) +add_subdirectory(doc EXCLUDE_FROM_ALL) -if(EIGEN_BUILD_TESTS) - include(CTest) - add_subdirectory(test) -endif(EIGEN_BUILD_TESTS) +include(CTest) +enable_testing() # must be called from the root CMakeLists, see man page +add_subdirectory(test EXCLUDE_FROM_ALL) add_subdirectory(unsupported) -if(EIGEN_BUILD_DEMOS) - add_subdirectory(demos) -endif(EIGEN_BUILD_DEMOS) +add_subdirectory(demos EXCLUDE_FROM_ALL) -if(EIGEN_BUILD_BLAS) - add_subdirectory(blas) -endif(EIGEN_BUILD_BLAS) +add_subdirectory(blas EXCLUDE_FROM_ALL) +# TODO: consider also replacing EIGEN_BUILD_BTL by a custom target "make btl"? if(EIGEN_BUILD_BTL) - add_subdirectory(bench/btl) + add_subdirectory(bench/btl EXCLUDE_FROM_ALL) endif(EIGEN_BUILD_BTL) -if(EIGEN_BUILD_TESTS) - ei_testing_print_summary() -endif(EIGEN_BUILD_TESTS) +ei_testing_print_summary() +message("You can now do the following:") +message("Command | Description") +message("-------------+------------------------------------------------------------------") +message("make install | Install Eigen to ${CMAKE_INSTALL_PREFIX}") +message(" | Do: cmake -DCMAKE_INSTALL_PREFIX=yourprefix . to change that") +message("make test | Build and run the unit tests (using CTest)") +message(" | Note: this takes lots of time & memory! Easy on the -j option!") +message("make btest | Only build tests, don't run them") +message("make doc | Generate the API documentation, requires Doxygen & LaTeX") +message("make blas | Build BLAS library") +message("-------------+------------------------------------------------------------------") diff --git a/Eigen/src/Cholesky/CholeskyInstantiations.cpp b/Eigen/src/Cholesky/CholeskyInstantiations.cpp deleted file mode 100644 index 92902f19b..000000000 --- a/Eigen/src/Cholesky/CholeskyInstantiations.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// 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 . - -#ifndef EIGEN_EXTERN_INSTANTIATIONS -#define EIGEN_EXTERN_INSTANTIATIONS -#endif -#include "../../Core" -#undef EIGEN_EXTERN_INSTANTIATIONS - -#include "../../Cholesky" - -namespace Eigen { - EIGEN_CHOLESKY_MODULE_INSTANTIATE(); -} diff --git a/Eigen/src/Core/CMakeLists.txt b/Eigen/src/Core/CMakeLists.txt index a555be756..2346fc2bb 100644 --- a/Eigen/src/Core/CMakeLists.txt +++ b/Eigen/src/Core/CMakeLists.txt @@ -5,13 +5,6 @@ INSTALL(FILES DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core COMPONENT Devel ) -FILE(GLOB Eigen_Core_Product_SRCS "products/*.h") - -INSTALL(FILES - ${Eigen_Core_Product_SRCS} - DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/products COMPONENT Devel - ) - - +ADD_SUBDIRECTORY(products) ADD_SUBDIRECTORY(util) ADD_SUBDIRECTORY(arch) diff --git a/Eigen/src/Core/CoreInstantiations.cpp b/Eigen/src/Core/CoreInstantiations.cpp deleted file mode 100644 index 3c021a8db..000000000 --- a/Eigen/src/Core/CoreInstantiations.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// 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 . - -#ifdef EIGEN_EXTERN_INSTANTIATIONS -#undef EIGEN_EXTERN_INSTANTIATIONS -#endif - -#include "../../Core" - -namespace Eigen -{ - -#define EIGEN_INSTANTIATE_PRODUCT(TYPE) \ -template static void ei_cache_friendly_product( \ - int _rows, int _cols, int depth, \ - bool _lhsRowMajor, const TYPE* _lhs, int _lhsStride, \ - bool _rhsRowMajor, const TYPE* _rhs, int _rhsStride, \ - bool resRowMajor, TYPE* res, int resStride) - -EIGEN_INSTANTIATE_PRODUCT(float); -EIGEN_INSTANTIATE_PRODUCT(double); -EIGEN_INSTANTIATE_PRODUCT(int); -EIGEN_INSTANTIATE_PRODUCT(std::complex); -EIGEN_INSTANTIATE_PRODUCT(std::complex); - -} diff --git a/Eigen/src/QR/QrInstantiations.cpp b/Eigen/src/QR/QrInstantiations.cpp deleted file mode 100644 index 695377d69..000000000 --- a/Eigen/src/QR/QrInstantiations.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2008 Gael Guennebaud -// -// 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 . - -#ifndef EIGEN_EXTERN_INSTANTIATIONS -#define EIGEN_EXTERN_INSTANTIATIONS -#endif -#include "../../Core" -#undef EIGEN_EXTERN_INSTANTIATIONS - -#include "../../QR" - -namespace Eigen -{ - -EIGEN_QR_MODULE_INSTANTIATE(); - -} diff --git a/blas/CMakeLists.txt b/blas/CMakeLists.txt index 477693bad..65ef77c90 100644 --- a/blas/CMakeLists.txt +++ b/blas/CMakeLists.txt @@ -1,7 +1,9 @@ +add_custom_target(blas) set(EigenBlas_SRCS single.cpp double.cpp complex_single.cpp complex_double.cpp) add_library(eigen_blas SHARED ${EigenBlas_SRCS}) +add_dependencies(blas eigen_blas) install(TARGETS eigen_blas RUNTIME DESTINATION bin diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 96049aa93..d4e0678f9 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -39,6 +39,7 @@ macro(ei_add_test testname) set(filename ${testname}.cpp) add_executable(${targetname} ${filename}) + add_dependencies(btest ${targetname}) if(NOT EIGEN_NO_ASSERTION_CHECKING) @@ -102,31 +103,31 @@ macro(ei_testing_print_summary) if(EIGEN_TEST_SSE2) message("SSE2: ON") else(EIGEN_TEST_SSE2) - message("SSE2: AUTO") + message("SSE2: Using architecture defaults") endif(EIGEN_TEST_SSE2) if(EIGEN_TEST_SSE3) message("SSE3: ON") else(EIGEN_TEST_SSE3) - message("SSE3: AUTO") + message("SSE3: Using architecture defaults") endif(EIGEN_TEST_SSE3) if(EIGEN_TEST_SSSE3) message("SSSE3: ON") else(EIGEN_TEST_SSSE3) - message("SSSE3: AUTO") + message("SSSE3: Using architecture defaults") endif(EIGEN_TEST_SSSE3) if(EIGEN_TEST_ALTIVEC) - message("Altivec: ON") + message("Altivec: Using architecture defaults") else(EIGEN_TEST_ALTIVEC) - message("Altivec: AUTO") + message("Altivec: Using architecture defaults") endif(EIGEN_TEST_ALTIVEC) if(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION) message("Explicit vec: OFF") else(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION) - message("Explicit vec: AUTO") + message("Explicit vec: Using architecture defaults") endif(EIGEN_TEST_NO_EXPLICIT_VECTORIZATION) message("\n${EIGEN_TESTING_SUMMARY}") diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 4e8f5164f..1ec49d13e 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -1,3 +1,9 @@ +add_custom_target(demos) -add_subdirectory(mandelbrot) -add_subdirectory(opengl) +find_package(Qt4) +if(QT4_FOUND) + add_subdirectory(mandelbrot) + add_subdirectory(opengl) +else(QT4_FOUND) + message(STATUS "Qt4 not found, so disabling the mandelbrot and opengl demos") +endif(QT4_FOUND) diff --git a/demos/mandelbrot/CMakeLists.txt b/demos/mandelbrot/CMakeLists.txt index d34b60a54..5c500e064 100644 --- a/demos/mandelbrot/CMakeLists.txt +++ b/demos/mandelbrot/CMakeLists.txt @@ -16,5 +16,6 @@ set(mandelbrot_SRCS qt4_automoc(${mandelbrot_SRCS}) add_executable(mandelbrot ${mandelbrot_SRCS}) +add_dependencies(demos mandelbrot) target_link_libraries(mandelbrot ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY}) diff --git a/demos/mix_eigen_and_c/README b/demos/mix_eigen_and_c/README index d543f8d99..21dba8679 100644 --- a/demos/mix_eigen_and_c/README +++ b/demos/mix_eigen_and_c/README @@ -1,7 +1,9 @@ +This is an example of how one can wrap some of Eigen into a C library. + To try this with GCC, do: g++ -c binary_library.cpp -O2 -msse2 -I ../.. gcc example.c binary_library.o -o example -lstdc++ ./example -This is an example of how one can wrap some of Eigen into a C library. +TODO: add CMakeLists, add more explanations here \ No newline at end of file diff --git a/demos/opengl/CMakeLists.txt b/demos/opengl/CMakeLists.txt index 968ed6cb4..b98a30c01 100644 --- a/demos/opengl/CMakeLists.txt +++ b/demos/opengl/CMakeLists.txt @@ -1,4 +1,3 @@ - find_package(Qt4 REQUIRED) find_package(OpenGL REQUIRED) @@ -14,6 +13,7 @@ set(quaternion_demo_SRCS gpuhelper.cpp icosphere.cpp camera.cpp trackball.cpp q qt4_automoc(${quaternion_demo_SRCS}) add_executable(quaternion_demo ${quaternion_demo_SRCS}) +add_dependencies(demos quaternion_demo) target_link_libraries(quaternion_demo ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} diff --git a/demos/opengl/camera.cpp b/demos/opengl/camera.cpp index a785caf78..26598522e 100644 --- a/demos/opengl/camera.cpp +++ b/demos/opengl/camera.cpp @@ -260,7 +260,7 @@ void Camera::activateGL(void) Vector3f Camera::unProject(const Vector2f& uv, float depth) const { - Matrix4f inv = mViewMatrix.inverse(); + Matrix4f inv = mViewMatrix.inverse().matrix(); return unProject(uv, depth, inv); } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f3c15612f..19b832873 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,5 @@ - +add_custom_target(btest) include(EigenTesting) -enable_testing() ei_init_testing() find_package(GSL) diff --git a/unsupported/CMakeLists.txt b/unsupported/CMakeLists.txt index 895fcdbed..7104085a3 100644 --- a/unsupported/CMakeLists.txt +++ b/unsupported/CMakeLists.txt @@ -1,9 +1,3 @@ - add_subdirectory(Eigen) - -add_subdirectory(doc) - -if(EIGEN_BUILD_TESTS) - add_subdirectory(test) -endif(EIGEN_BUILD_TESTS) - +add_subdirectory(doc EXCLUDE_FROM_ALL) +add_subdirectory(test EXCLUDE_FROM_ALL) From 251c0f45ac275d6635a9453d6df65c9d749ef245 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Sun, 27 Sep 2009 23:54:06 +0200 Subject: [PATCH 48/83] remove references to adolc and split tests functions for clarity --- unsupported/test/autodiff.cpp | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/unsupported/test/autodiff.cpp b/unsupported/test/autodiff.cpp index 43ef1a308..b1164897c 100644 --- a/unsupported/test/autodiff.cpp +++ b/unsupported/test/autodiff.cpp @@ -111,7 +111,7 @@ struct TestFunc1 } }; -template void adolc_forward_jacobian(const Func& f) +template void forward_jacobian(const Func& f) { typename Func::InputType x = Func::InputType::Random(f.inputs()); typename Func::ValueType y(f.values()), yref(f.values()); @@ -134,21 +134,29 @@ template void adolc_forward_jacobian(const Func& f) VERIFY_IS_APPROX(j, jref); } -void test_autodiff() +void test_autodiff_scalar() { std::cerr << foo(1,2) << "\n"; AutoDiffScalar ax(1,Vector2f::UnitX()); AutoDiffScalar ay(2,Vector2f::UnitY()); std::cerr << foo >(ax,ay).value() << " <> " << foo >(ax,ay).derivatives().transpose() << "\n\n"; - - for(int i = 0; i < g_repeat; i++) { - CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1()) )); - CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1()) )); - CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1()) )); - CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1()) )); - CALL_SUBTEST(( adolc_forward_jacobian(TestFunc1(3,3)) )); - } - -// exit(1); } + +void test_autodiff_jacobian() +{ + for(int i = 0; i < g_repeat; i++) { + CALL_SUBTEST(( forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1()) )); + CALL_SUBTEST(( forward_jacobian(TestFunc1(3,3)) )); + } +} + +void test_autodiff() +{ + test_autodiff_scalar(); + test_autodiff_jacobian(); +} + From 2e4be5a75ce079028a21c5f864464dda0d0cd09d Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sun, 27 Sep 2009 17:55:58 -0400 Subject: [PATCH 49/83] improve message --- CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index be76903e6..913c094fd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,13 +139,14 @@ endif(EIGEN_BUILD_BTL) ei_testing_print_summary() message("You can now do the following:") +message("-------------+-----------------------------------------------------------------") message("Command | Description") -message("-------------+------------------------------------------------------------------") +message("-------------+-----------------------------------------------------------------") message("make install | Install Eigen to ${CMAKE_INSTALL_PREFIX}") -message(" | Do: cmake -DCMAKE_INSTALL_PREFIX=yourprefix . to change that") +message(" | Do: cmake . -DCMAKE_INSTALL_PREFIX=yourprefix to change that") message("make test | Build and run the unit tests (using CTest)") message(" | Note: this takes lots of time & memory! Easy on the -j option!") message("make btest | Only build tests, don't run them") message("make doc | Generate the API documentation, requires Doxygen & LaTeX") message("make blas | Build BLAS library") -message("-------------+------------------------------------------------------------------") +message("-------------+-----------------------------------------------------------------") From 765600458bb82422a3f720b6080a3d22e65a2a5e Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sun, 27 Sep 2009 18:05:54 -0400 Subject: [PATCH 50/83] * bump to 2.90.0 now that it's agreed that we're doing eigen3 ---> question: do we change the prefix eigen2/ to eigen3/ now? no, better wait until we've also changed the repository name * more message improvements: "Install Eigen" was unclear as it left out other things like the BLAS library --- CMakeLists.txt | 4 +++- Eigen/src/Core/util/Macros.h | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 913c094fd..1edc1eb12 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -138,11 +138,13 @@ if(EIGEN_BUILD_BTL) endif(EIGEN_BUILD_BTL) ei_testing_print_summary() +message("") +message("Configured Eigen ${EIGEN_VERSION_NUMBER}") message("You can now do the following:") message("-------------+-----------------------------------------------------------------") message("Command | Description") message("-------------+-----------------------------------------------------------------") -message("make install | Install Eigen to ${CMAKE_INSTALL_PREFIX}") +message("make install | Install to ${CMAKE_INSTALL_PREFIX}") message(" | Do: cmake . -DCMAKE_INSTALL_PREFIX=yourprefix to change that") message("make test | Build and run the unit tests (using CTest)") message(" | Note: this takes lots of time & memory! Easy on the -j option!") diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 530306643..71962bcae 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -29,8 +29,8 @@ #undef minor #define EIGEN_WORLD_VERSION 2 -#define EIGEN_MAJOR_VERSION 0 -#define EIGEN_MINOR_VERSION 52 +#define EIGEN_MAJOR_VERSION 90 +#define EIGEN_MINOR_VERSION 0 #define EIGEN_VERSION_AT_LEAST(x,y,z) (EIGEN_WORLD_VERSION>x || (EIGEN_WORLD_VERSION>=x && \ (EIGEN_MAJOR_VERSION>y || (EIGEN_MAJOR_VERSION>=y && \ From de942a44c2459a19a12b0b6309cbc226867ea691 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Mon, 28 Sep 2009 01:28:48 +0200 Subject: [PATCH 51/83] default argument for _jac in functor operator() : this way, we can use AutoDiffJacobian::operator()(x,value) exactly as the original functor --- unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h b/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h index 0feb577df..d42197345 100644 --- a/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h +++ b/unsupported/Eigen/src/AutoDiff/AutoDiffJacobian.h @@ -56,7 +56,7 @@ public: typedef Matrix ActiveInput; typedef Matrix ActiveValue; - void operator() (const InputType& x, ValueType* v, JacobianType* _jac) const + void operator() (const InputType& x, ValueType* v, JacobianType* _jac=0) const { ei_assert(v!=0); if (!_jac) From 67bf7c90c5c41d8b62411c298d657908537118ea Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 28 Sep 2009 09:40:18 -0400 Subject: [PATCH 52/83] * update test to expose bug #57 * update createRandomMatrixOfRank to support fixed size --- Eigen/src/QR/ColPivotingHouseholderQR.h | 1 - test/main.h | 14 ++++++---- test/qr_colpivoting.cpp | 37 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 6 deletions(-) diff --git a/Eigen/src/QR/ColPivotingHouseholderQR.h b/Eigen/src/QR/ColPivotingHouseholderQR.h index c4c7d2d55..0898b5d1f 100644 --- a/Eigen/src/QR/ColPivotingHouseholderQR.h +++ b/Eigen/src/QR/ColPivotingHouseholderQR.h @@ -351,7 +351,6 @@ bool ColPivotingHouseholderQR::solve( } const int rows = m_qr.rows(); - const int cols = b.cols(); ei_assert(b.rows() == rows); typename OtherDerived::PlainMatrixType c(b); diff --git a/test/main.h b/test/main.h index 8c93e856c..51b719814 100644 --- a/test/main.h +++ b/test/main.h @@ -248,18 +248,22 @@ template void createRandomMatrixOfRank(int desired_rank, int rows, int cols, MatrixType& m) { typedef typename ei_traits::Scalar Scalar; - typedef Matrix VectorType; + enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime }; - MatrixType a = MatrixType::Random(rows,rows); + typedef Matrix VectorType; + typedef Matrix MatrixAType; + typedef Matrix MatrixBType; + + MatrixAType a = MatrixAType::Random(rows,rows); MatrixType d = MatrixType::Identity(rows,cols); - MatrixType b = MatrixType::Random(cols,cols); + MatrixBType b = MatrixBType::Random(cols,cols); // set the diagonal such that only desired_rank non-zero entries reamain const int diag_size = std::min(d.rows(),d.cols()); d.diagonal().segment(desired_rank, diag_size-desired_rank) = VectorType::Zero(diag_size-desired_rank); - HouseholderQR qra(a); - HouseholderQR qrb(b); + HouseholderQR qra(a); + HouseholderQR qrb(b); m = qra.matrixQ() * d * qrb.matrixQ(); } diff --git a/test/qr_colpivoting.cpp b/test/qr_colpivoting.cpp index 588a41e56..e0edad842 100644 --- a/test/qr_colpivoting.cpp +++ b/test/qr_colpivoting.cpp @@ -63,6 +63,40 @@ template void qr() VERIFY(!qr.solve(m3, &m2)); } +template void qr_fixedsize() +{ + enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime }; + typedef typename MatrixType::Scalar Scalar; + int rank = ei_random(1, std::min(int(Rows), int(Cols))-1); + Matrix m1; + createRandomMatrixOfRank(rank,Rows,Cols,m1); + ColPivotingHouseholderQR > qr(m1); + VERIFY_IS_APPROX(rank, qr.rank()); + VERIFY(Cols - qr.rank() == qr.dimensionOfKernel()); + VERIFY(!qr.isInjective()); + VERIFY(!qr.isInvertible()); + VERIFY(!qr.isSurjective()); + + Matrix r = qr.matrixQR(); + // FIXME need better way to construct trapezoid + for(int i = 0; i < Rows; i++) for(int j = 0; j < Cols; j++) if(i>j) r(i,j) = Scalar(0); + + Matrix b = qr.matrixQ() * r; + + Matrix c = MatrixType::Zero(Rows,Cols); + + for(int i = 0; i < Cols; ++i) c.col(qr.colsPermutation().coeff(i)) = b.col(i); + VERIFY_IS_APPROX(m1, c); + + Matrix m2 = Matrix::Random(Cols,Cols2); + Matrix m3 = m1*m2; + m2 = Matrix::Random(Cols,Cols2); + VERIFY(qr.solve(m3, &m2)); + VERIFY_IS_APPROX(m3, m1*m2); + m3 = Matrix::Random(Rows,Cols2); + VERIFY(!qr.solve(m3, &m2)); +} + template void qr_invertible() { typedef typename NumTraits::Real RealScalar; @@ -121,6 +155,9 @@ void test_qr_colpivoting() CALL_SUBTEST( qr() ); CALL_SUBTEST( qr() ); } + + CALL_SUBTEST(( qr_fixedsize, 4 >() )); + CALL_SUBTEST(( qr_fixedsize, 3 >() )); for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST( qr_invertible() ); From eeabd18afc5fca290612aada629a294f85d9d353 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 28 Sep 2009 10:49:55 -0400 Subject: [PATCH 53/83] Fix compilation of HouseholderQR and ColPivotingHouseholderQR for non-square fixed-size matrices. For Colpiv that was just changing MatrixQType to MatrixType in the instantiation of HouseholderSequence. For HouseholderQR I also re-ported the solve method from Colpiv as there were multiple issues. --- Eigen/src/QR/ColPivotingHouseholderQR.h | 2 +- Eigen/src/QR/HouseholderQR.h | 18 +++++++----- test/qr.cpp | 38 ++++++++++++++----------- test/qr_colpivoting.cpp | 5 ++-- 4 files changed, 36 insertions(+), 27 deletions(-) diff --git a/Eigen/src/QR/ColPivotingHouseholderQR.h b/Eigen/src/QR/ColPivotingHouseholderQR.h index 0898b5d1f..b141da0aa 100644 --- a/Eigen/src/QR/ColPivotingHouseholderQR.h +++ b/Eigen/src/QR/ColPivotingHouseholderQR.h @@ -62,7 +62,7 @@ template class ColPivotingHouseholderQR typedef Matrix RowVectorType; typedef Matrix ColVectorType; typedef Matrix RealRowVectorType; - typedef typename HouseholderSequence::ConjugateReturnType HouseholderSequenceType; + typedef typename HouseholderSequence::ConjugateReturnType HouseholderSequenceType; /** * \brief Default Constructor. diff --git a/Eigen/src/QR/HouseholderQR.h b/Eigen/src/QR/HouseholderQR.h index 39502a30f..4cc553926 100644 --- a/Eigen/src/QR/HouseholderQR.h +++ b/Eigen/src/QR/HouseholderQR.h @@ -62,7 +62,7 @@ template class HouseholderQR typedef Matrix::Flags&RowMajorBit ? RowMajor : ColMajor)> MatrixQType; typedef Matrix HCoeffsType; typedef Matrix RowVectorType; - typedef typename HouseholderSequence::ConjugateReturnType HouseholderSequenceType; + typedef typename HouseholderSequence::ConjugateReturnType HouseholderSequenceType; /** * \brief Default Constructor. @@ -206,18 +206,22 @@ void HouseholderQR::solve( ) const { ei_assert(m_isInitialized && "HouseholderQR is not initialized."); + result->resize(m_qr.cols(), b.cols()); const int rows = m_qr.rows(); - const int cols = b.cols(); + const int rank = std::min(m_qr.rows(), m_qr.cols()); ei_assert(b.rows() == rows); - result->resize(rows, cols); - *result = b; - result->applyOnTheLeft(matrixQAsHouseholderSequence().inverse()); + typename OtherDerived::PlainMatrixType c(b); + + // Note that the matrix Q = H_0^* H_1^*... so its inverse is Q^* = (H_0 H_1 ...)^T + c.applyOnTheLeft(makeHouseholderSequence(m_qr.corner(TopLeft,rows,rank), m_hCoeffs.start(rank)).transpose()); - const int rank = std::min(result->rows(), result->cols()); m_qr.corner(TopLeft, rank, rank) .template triangularView() - .solveInPlace(result->corner(TopLeft, rank, result->cols())); + .solveInPlace(c.corner(TopLeft, rank, c.cols())); + + result->corner(TopLeft, rank, c.cols()) = c.corner(TopLeft,rank, c.cols()); + result->corner(BottomLeft, result->rows()-rank, c.cols()).setZero(); } /** \returns the matrix Q */ diff --git a/test/qr.cpp b/test/qr.cpp index f185ac86e..036a3c9f2 100644 --- a/test/qr.cpp +++ b/test/qr.cpp @@ -41,20 +41,26 @@ template void qr(const MatrixType& m) for(int i = 0; i < rows; i++) for(int j = 0; j < cols; j++) if(i>j) r(i,j) = Scalar(0); VERIFY_IS_APPROX(a, qrOfA.matrixQ() * r); +} - SquareMatrixType b = a.adjoint() * a; +template void qr_fixedsize() +{ + enum { Rows = MatrixType::RowsAtCompileTime, Cols = MatrixType::ColsAtCompileTime }; + typedef typename MatrixType::Scalar Scalar; + Matrix m1 = Matrix::Random(); + HouseholderQR > qr(m1); - // check tridiagonalization - Tridiagonalization tridiag(b); - VERIFY_IS_APPROX(b, tridiag.matrixQ() * tridiag.matrixT() * tridiag.matrixQ().adjoint()); + Matrix r = qr.matrixQR(); + // FIXME need better way to construct trapezoid + for(int i = 0; i < Rows; i++) for(int j = 0; j < Cols; j++) if(i>j) r(i,j) = Scalar(0); - // check hessenberg decomposition - HessenbergDecomposition hess(b); - VERIFY_IS_APPROX(b, hess.matrixQ() * hess.matrixH() * hess.matrixQ().adjoint()); - VERIFY_IS_APPROX(tridiag.matrixT(), hess.matrixH()); - b = SquareMatrixType::Random(cols,cols); - hess.compute(b); - VERIFY_IS_APPROX(b, hess.matrixQ() * hess.matrixH() * hess.matrixQ().adjoint()); + VERIFY_IS_APPROX(m1, qr.matrixQ() * r); + + Matrix m2 = Matrix::Random(Cols,Cols2); + Matrix m3 = m1*m2; + m2 = Matrix::Random(Cols,Cols2); + qr.solve(m3, &m2); + VERIFY_IS_APPROX(m3, m1*m2); } template void qr_invertible() @@ -105,11 +111,11 @@ template void qr_verify_assert() void test_qr() { for(int i = 0; i < 1; i++) { - // FIXME : very weird bug here -// CALL_SUBTEST( qr(Matrix2f()) ); - CALL_SUBTEST( qr(Matrix4d()) ); - CALL_SUBTEST( qr(MatrixXf(47,40)) ); - CALL_SUBTEST( qr(MatrixXcd(17,7)) ); + CALL_SUBTEST( qr(MatrixXf(47,40)) ); + CALL_SUBTEST( qr(MatrixXcd(17,7)) ); + CALL_SUBTEST(( qr_fixedsize, 2 >() )); + CALL_SUBTEST(( qr_fixedsize, 4 >() )); + CALL_SUBTEST(( qr_fixedsize, 7 >() )); } for(int i = 0; i < g_repeat; i++) { diff --git a/test/qr_colpivoting.cpp b/test/qr_colpivoting.cpp index e0edad842..4b6f7dd6b 100644 --- a/test/qr_colpivoting.cpp +++ b/test/qr_colpivoting.cpp @@ -154,10 +154,9 @@ void test_qr_colpivoting() CALL_SUBTEST( qr() ); CALL_SUBTEST( qr() ); CALL_SUBTEST( qr() ); + CALL_SUBTEST(( qr_fixedsize, 4 >() )); + CALL_SUBTEST(( qr_fixedsize, 3 >() )); } - - CALL_SUBTEST(( qr_fixedsize, 4 >() )); - CALL_SUBTEST(( qr_fixedsize, 3 >() )); for(int i = 0; i < g_repeat; i++) { CALL_SUBTEST( qr_invertible() ); From 457b7cba96517328b086d23b9ee47a50176c5982 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 28 Sep 2009 11:08:31 -0400 Subject: [PATCH 54/83] more message improvements, tell the user about building a specific test --- CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1edc1eb12..c1c9ee546 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -145,10 +145,11 @@ message("-------------+--------------------------------------------------------- message("Command | Description") message("-------------+-----------------------------------------------------------------") message("make install | Install to ${CMAKE_INSTALL_PREFIX}") -message(" | Do: cmake . -DCMAKE_INSTALL_PREFIX=yourprefix to change that") -message("make test | Build and run the unit tests (using CTest)") -message(" | Note: this takes lots of time & memory! Easy on the -j option!") -message("make btest | Only build tests, don't run them") +message(" | To change that, do: cmake . -DCMAKE_INSTALL_PREFIX=yourpath") message("make doc | Generate the API documentation, requires Doxygen & LaTeX") +message("make btest | Build the unit tests (doesn't run them)") +message(" | Note: this takes lots of time & memory! Easy on the -j option!") +message("make test | Build and run the unit tests (using CTest)") +message("make test_qr | Build a specific test, here test_qr. To run it: test/test_qr") message("make blas | Build BLAS library") message("-------------+-----------------------------------------------------------------") From fa65b0966133d7feeea5ba6e6671e6a5f6a19a6a Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Tue, 29 Sep 2009 20:30:28 -0400 Subject: [PATCH 55/83] add outerproduct coeff(int,int) method. This is needed to make this expression work: (vec1*vec2.transpose())*vec3 Gael, no objection? Seems to make sense as that's fast. --- Eigen/src/Core/Product.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 287fc9c5b..3c5c56f1c 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -212,6 +212,11 @@ class GeneralProduct ei_outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha); } + Scalar coeff(int row, int col) const + { + return this->lhs().coeff(row) * this->rhs().coeff(col); + } + private: GeneralProduct& operator=(const GeneralProduct&); }; From 4b04a9bcfa1e55a00053588b6a50bb000af2d044 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Tue, 29 Sep 2009 21:00:13 -0400 Subject: [PATCH 56/83] *add test to prevent future regression --- test/product_extra.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/product_extra.cpp b/test/product_extra.cpp index 3ad99fc7a..a67e755d2 100644 --- a/test/product_extra.cpp +++ b/test/product_extra.cpp @@ -115,6 +115,10 @@ template void product_extra(const MatrixType& m) VERIFY_IS_APPROX(m1.col(j2).adjoint() * m1.block(0,j,m1.rows(),c), m1.col(j2).adjoint().eval() * m1.block(0,j,m1.rows(),c).eval()); VERIFY_IS_APPROX(m1.block(i,0,r,m1.cols()) * m1.row(i2).adjoint(), m1.block(i,0,r,m1.cols()).eval() * m1.row(i2).adjoint().eval()); + // test (outer_product) * vector with and without temporary + ColVectorType vc3 = ColVectorType::Random(cols), vc4 = ColVectorType::Random(cols); + vcres = (vc2 * vc3.transpose()) * vc4; // without temporary + VERIFY_IS_APPROX(vcres, (vc2 * vc3.transpose()).eval() * vc4); } void test_product_extra() From d7a2a37a4c1728dbddbfae9d577e2e49f5edda65 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 30 Sep 2009 16:48:02 +0200 Subject: [PATCH 57/83] bugfix in the eigenvalue solvers (forgot to resize the eigen vectors) --- Eigen/src/Eigenvalues/ComplexEigenSolver.h | 1 + Eigen/src/Eigenvalues/EigenSolver.h | 1 + Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h | 1 + 3 files changed, 3 insertions(+) diff --git a/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h index 666381949..224918795 100644 --- a/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -92,6 +92,7 @@ void ComplexEigenSolver::compute(const MatrixType& matrix) assert(matrix.cols() == matrix.rows()); int n = matrix.cols(); m_eivalues.resize(n,1); + m_eivec.resize(n,n); RealScalar eps = epsilon(); diff --git a/Eigen/src/Eigenvalues/EigenSolver.h b/Eigen/src/Eigenvalues/EigenSolver.h index 3fc36c080..73d240de0 100644 --- a/Eigen/src/Eigenvalues/EigenSolver.h +++ b/Eigen/src/Eigenvalues/EigenSolver.h @@ -194,6 +194,7 @@ EigenSolver& EigenSolver::compute(const MatrixType& matr assert(matrix.cols() == matrix.rows()); int n = matrix.cols(); m_eivalues.resize(n,1); + m_eivec.resize(n,n); MatrixType matH = matrix; RealVectorType ort(n); diff --git a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h index 84856aa66..9e155de8f 100644 --- a/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h +++ b/Eigen/src/Eigenvalues/SelfAdjointEigenSolver.h @@ -168,6 +168,7 @@ SelfAdjointEigenSolver& SelfAdjointEigenSolver::compute( assert(matrix.cols() == matrix.rows()); int n = matrix.cols(); m_eivalues.resize(n,1); + m_eivec.resize(n,n); if(n==1) { From 3a315fdc9ad7dddc746af537ecafce9d25c52fbc Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Wed, 30 Sep 2009 15:47:11 -0400 Subject: [PATCH 58/83] make Replicate ctor require the exact expected type --- Eigen/src/Array/Replicate.h | 13 ++++++++++--- Eigen/src/Core/util/StaticAssert.h | 3 ++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Eigen/src/Array/Replicate.h b/Eigen/src/Array/Replicate.h index 02f9c0601..b20bcd49a 100644 --- a/Eigen/src/Array/Replicate.h +++ b/Eigen/src/Array/Replicate.h @@ -69,15 +69,22 @@ template class Replicate EIGEN_GENERIC_PUBLIC_INTERFACE(Replicate) - inline Replicate(const MatrixType& matrix) + template + inline Replicate(const OriginalMatrixType& matrix) : m_matrix(matrix), m_rowFactor(RowFactor), m_colFactor(ColFactor) { + EIGEN_STATIC_ASSERT((ei_is_same_type::ret), + THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) ei_assert(RowFactor!=Dynamic && ColFactor!=Dynamic); } - inline Replicate(const MatrixType& matrix, int rowFactor, int colFactor) + template + inline Replicate(const OriginalMatrixType& matrix, int rowFactor, int colFactor) : m_matrix(matrix), m_rowFactor(rowFactor), m_colFactor(colFactor) - {} + { + EIGEN_STATIC_ASSERT((ei_is_same_type::ret), + THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE) + } inline int rows() const { return m_matrix.rows() * m_rowFactor.value(); } inline int cols() const { return m_matrix.cols() * m_colFactor.value(); } diff --git a/Eigen/src/Core/util/StaticAssert.h b/Eigen/src/Core/util/StaticAssert.h index 7116e4d0f..883f2d95e 100644 --- a/Eigen/src/Core/util/StaticAssert.h +++ b/Eigen/src/Core/util/StaticAssert.h @@ -77,7 +77,8 @@ THIS_METHOD_IS_ONLY_FOR_ROW_MAJOR_MATRICES, INVALID_MATRIX_TEMPLATE_PARAMETERS, BOTH_MATRICES_MUST_HAVE_THE_SAME_STORAGE_ORDER, - THIS_METHOD_IS_ONLY_FOR_DIAGONAL_MATRIX + THIS_METHOD_IS_ONLY_FOR_DIAGONAL_MATRIX, + THE_MATRIX_OR_EXPRESSION_THAT_YOU_PASSED_DOES_NOT_HAVE_THE_EXPECTED_TYPE }; }; From 5409ce1625431f9f8149e66028db17e8515ab166 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Thu, 1 Oct 2009 07:20:09 +0200 Subject: [PATCH 59/83] Fixed wrong line endings. --- Eigen/src/Eigenvalues/ComplexEigenSolver.h | 298 ++++++++++----------- 1 file changed, 149 insertions(+), 149 deletions(-) diff --git a/Eigen/src/Eigenvalues/ComplexEigenSolver.h b/Eigen/src/Eigenvalues/ComplexEigenSolver.h index 224918795..86206ce79 100644 --- a/Eigen/src/Eigenvalues/ComplexEigenSolver.h +++ b/Eigen/src/Eigenvalues/ComplexEigenSolver.h @@ -1,149 +1,149 @@ -// This file is part of Eigen, a lightweight C++ template library -// for linear algebra. -// -// Copyright (C) 2009 Claire Maurice -// Copyright (C) 2009 Gael Guennebaud -// -// 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 . - -#ifndef EIGEN_COMPLEX_EIGEN_SOLVER_H -#define EIGEN_COMPLEX_EIGEN_SOLVER_H - -/** \eigenvalues_module \ingroup Eigenvalues_Module - * \nonstableyet - * - * \class ComplexEigenSolver - * - * \brief Eigen values/vectors solver for general complex matrices - * - * \param MatrixType the type of the matrix of which we are computing the eigen decomposition - * - * \sa class EigenSolver, class SelfAdjointEigenSolver - */ -template class ComplexEigenSolver -{ - public: - typedef _MatrixType MatrixType; - typedef typename MatrixType::Scalar Scalar; - typedef typename NumTraits::Real RealScalar; - typedef std::complex Complex; - typedef Matrix EigenvalueType; - typedef Matrix EigenvectorType; - - /** - * \brief Default Constructor. - * - * The default constructor is useful in cases in which the user intends to - * perform decompositions via ComplexEigenSolver::compute(const MatrixType&). - */ - ComplexEigenSolver() : m_eivec(), m_eivalues(), m_isInitialized(false) - {} - - ComplexEigenSolver(const MatrixType& matrix) - : m_eivec(matrix.rows(),matrix.cols()), - m_eivalues(matrix.cols()), - m_isInitialized(false) - { - compute(matrix); - } - - EigenvectorType eigenvectors(void) const - { - ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); - return m_eivec; - } - - EigenvalueType eigenvalues() const - { - ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); - return m_eivalues; - } - - void compute(const MatrixType& matrix); - - protected: - MatrixType m_eivec; - EigenvalueType m_eivalues; - bool m_isInitialized; -}; - - -template -void ComplexEigenSolver::compute(const MatrixType& matrix) -{ - // this code is inspired from Jampack - assert(matrix.cols() == matrix.rows()); - int n = matrix.cols(); - m_eivalues.resize(n,1); - m_eivec.resize(n,n); - - RealScalar eps = epsilon(); - - // Reduce to complex Schur form - ComplexSchur schur(matrix); - - m_eivalues = schur.matrixT().diagonal(); - - m_eivec.setZero(); - - Scalar d2, z; - RealScalar norm = matrix.norm(); - - // compute the (normalized) eigenvectors - for(int k=n-1 ; k>=0 ; k--) - { - d2 = schur.matrixT().coeff(k,k); - m_eivec.coeffRef(k,k) = Scalar(1.0,0.0); - for(int i=k-1 ; i>=0 ; i--) - { - m_eivec.coeffRef(i,k) = -schur.matrixT().coeff(i,k); - if(k-i-1>0) - m_eivec.coeffRef(i,k) -= (schur.matrixT().row(i).segment(i+1,k-i-1) * m_eivec.col(k).segment(i+1,k-i-1)).value(); - z = schur.matrixT().coeff(i,i) - d2; - if(z==Scalar(0)) - ei_real_ref(z) = eps * norm; - m_eivec.coeffRef(i,k) = m_eivec.coeff(i,k) / z; - - } - m_eivec.col(k).normalize(); - } - - m_eivec = schur.matrixU() * m_eivec; - m_isInitialized = true; - - // sort the eigenvalues - { - for (int i=0; i +// +// 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 . + +#ifndef EIGEN_COMPLEX_EIGEN_SOLVER_H +#define EIGEN_COMPLEX_EIGEN_SOLVER_H + +/** \eigenvalues_module \ingroup Eigenvalues_Module + * \nonstableyet + * + * \class ComplexEigenSolver + * + * \brief Eigen values/vectors solver for general complex matrices + * + * \param MatrixType the type of the matrix of which we are computing the eigen decomposition + * + * \sa class EigenSolver, class SelfAdjointEigenSolver + */ +template class ComplexEigenSolver +{ + public: + typedef _MatrixType MatrixType; + typedef typename MatrixType::Scalar Scalar; + typedef typename NumTraits::Real RealScalar; + typedef std::complex Complex; + typedef Matrix EigenvalueType; + typedef Matrix EigenvectorType; + + /** + * \brief Default Constructor. + * + * The default constructor is useful in cases in which the user intends to + * perform decompositions via ComplexEigenSolver::compute(const MatrixType&). + */ + ComplexEigenSolver() : m_eivec(), m_eivalues(), m_isInitialized(false) + {} + + ComplexEigenSolver(const MatrixType& matrix) + : m_eivec(matrix.rows(),matrix.cols()), + m_eivalues(matrix.cols()), + m_isInitialized(false) + { + compute(matrix); + } + + EigenvectorType eigenvectors(void) const + { + ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); + return m_eivec; + } + + EigenvalueType eigenvalues() const + { + ei_assert(m_isInitialized && "ComplexEigenSolver is not initialized."); + return m_eivalues; + } + + void compute(const MatrixType& matrix); + + protected: + MatrixType m_eivec; + EigenvalueType m_eivalues; + bool m_isInitialized; +}; + + +template +void ComplexEigenSolver::compute(const MatrixType& matrix) +{ + // this code is inspired from Jampack + assert(matrix.cols() == matrix.rows()); + int n = matrix.cols(); + m_eivalues.resize(n,1); + m_eivec.resize(n,n); + + RealScalar eps = epsilon(); + + // Reduce to complex Schur form + ComplexSchur schur(matrix); + + m_eivalues = schur.matrixT().diagonal(); + + m_eivec.setZero(); + + Scalar d2, z; + RealScalar norm = matrix.norm(); + + // compute the (normalized) eigenvectors + for(int k=n-1 ; k>=0 ; k--) + { + d2 = schur.matrixT().coeff(k,k); + m_eivec.coeffRef(k,k) = Scalar(1.0,0.0); + for(int i=k-1 ; i>=0 ; i--) + { + m_eivec.coeffRef(i,k) = -schur.matrixT().coeff(i,k); + if(k-i-1>0) + m_eivec.coeffRef(i,k) -= (schur.matrixT().row(i).segment(i+1,k-i-1) * m_eivec.col(k).segment(i+1,k-i-1)).value(); + z = schur.matrixT().coeff(i,i) - d2; + if(z==Scalar(0)) + ei_real_ref(z) = eps * norm; + m_eivec.coeffRef(i,k) = m_eivec.coeff(i,k) / z; + + } + m_eivec.col(k).normalize(); + } + + m_eivec = schur.matrixU() * m_eivec; + m_isInitialized = true; + + // sort the eigenvalues + { + for (int i=0; i Date: Thu, 1 Oct 2009 13:27:03 +0200 Subject: [PATCH 60/83] better fix for (v * v') * v, we still have to find a way to reorder it --- Eigen/src/Core/Product.h | 7 +------ test/product_extra.cpp | 5 ----- test/product_small.cpp | 6 ++++++ 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Eigen/src/Core/Product.h b/Eigen/src/Core/Product.h index 3c5c56f1c..cc751650d 100644 --- a/Eigen/src/Core/Product.h +++ b/Eigen/src/Core/Product.h @@ -135,7 +135,7 @@ struct ProductReturnType { typedef typename ei_nested::type LhsNested; typedef typename ei_nested::type RhsNested; - typedef GeneralProduct Type; + typedef GeneralProduct Type; }; @@ -212,11 +212,6 @@ class GeneralProduct ei_outer_product_selector<(int(Dest::Flags)&RowMajorBit) ? RowMajor : ColMajor>::run(*this, dest, alpha); } - Scalar coeff(int row, int col) const - { - return this->lhs().coeff(row) * this->rhs().coeff(col); - } - private: GeneralProduct& operator=(const GeneralProduct&); }; diff --git a/test/product_extra.cpp b/test/product_extra.cpp index a67e755d2..8e55c6010 100644 --- a/test/product_extra.cpp +++ b/test/product_extra.cpp @@ -114,11 +114,6 @@ template void product_extra(const MatrixType& m) VERIFY_IS_APPROX(m1.col(j2).adjoint() * m1.block(0,j,m1.rows(),c), m1.col(j2).adjoint().eval() * m1.block(0,j,m1.rows(),c).eval()); VERIFY_IS_APPROX(m1.block(i,0,r,m1.cols()) * m1.row(i2).adjoint(), m1.block(i,0,r,m1.cols()).eval() * m1.row(i2).adjoint().eval()); - - // test (outer_product) * vector with and without temporary - ColVectorType vc3 = ColVectorType::Random(cols), vc4 = ColVectorType::Random(cols); - vcres = (vc2 * vc3.transpose()) * vc4; // without temporary - VERIFY_IS_APPROX(vcres, (vc2 * vc3.transpose()).eval() * vc4); } void test_product_extra() diff --git a/test/product_small.cpp b/test/product_small.cpp index 3aed5cf1b..182af71db 100644 --- a/test/product_small.cpp +++ b/test/product_small.cpp @@ -34,4 +34,10 @@ void test_product_small() CALL_SUBTEST( product(Matrix4d()) ); CALL_SUBTEST( product(Matrix4f()) ); } + + { + // test compilation of (outer_product) * vector + Vector3f v = Vector3f::Random(); + VERIFY_IS_APPROX( (v * v.transpose()) * v, (v * v.transpose()).eval() * v); + } } From 2b810ea81808d205694cacc9ea8f1bacb2b1472b Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Fri, 2 Oct 2009 11:22:47 -0400 Subject: [PATCH 61/83] finally, actually purge the Main Page --- scripts/eigen_gen_credits | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/scripts/eigen_gen_credits b/scripts/eigen_gen_credits index f597b1b6a..026fd34de 100755 --- a/scripts/eigen_gen_credits +++ b/scripts/eigen_gen_credits @@ -7,9 +7,6 @@ # cd eigen2 # scripts/eigen_gen_credits -# configuration -USER='orzel' - rm -f eigen_gen_credits.log hg pull >> eigen_gen_credits.log @@ -23,7 +20,4 @@ g++ scripts/eigen_gen_credits.cpp -o e ./e > credits.out rsync credits.out $USER@ssh.tuxfamily.org:eigen/eigen.tuxfamily.org-web/htdocs/credits.out || (echo "upload failed"; exit 1) - -# clear the server-side cache for Main Page -wget "http://eigen.tuxfamily.org/index.php?title=Main_Page&action=purge" -O main-page.out -a eigen_gen_credits.log -rm main-page.out +ssh $USER@ssh.tuxfamily.org "cd eigen/eigen.tuxfamily.org-web/htdocs; chmod 666 credits.out; echo Main_Page | /usr/bin/php maintenance/purgeList.php" From 57e1c5b0aa71a84926a01668ad096fea2dccae2a Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Fri, 2 Oct 2009 11:32:36 -0400 Subject: [PATCH 62/83] fix permissions 666->660 --- scripts/eigen_gen_credits | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/eigen_gen_credits b/scripts/eigen_gen_credits index 026fd34de..5a0056387 100755 --- a/scripts/eigen_gen_credits +++ b/scripts/eigen_gen_credits @@ -1,11 +1,11 @@ #!/bin/sh # this script must be run from the eigen2/ directory. -# when running hg churn from the scripts/ subdir, i hit a divide-by-zero error in hg churn. +# when running hg churn from the scripts/ subdir, i hit a divide-by-zero error. # # like this: # cd eigen2 -# scripts/eigen_gen_credits +# USER=yourtuxfamilyuser scripts/eigen_gen_credits rm -f eigen_gen_credits.log @@ -20,4 +20,4 @@ g++ scripts/eigen_gen_credits.cpp -o e ./e > credits.out rsync credits.out $USER@ssh.tuxfamily.org:eigen/eigen.tuxfamily.org-web/htdocs/credits.out || (echo "upload failed"; exit 1) -ssh $USER@ssh.tuxfamily.org "cd eigen/eigen.tuxfamily.org-web/htdocs; chmod 666 credits.out; echo Main_Page | /usr/bin/php maintenance/purgeList.php" +ssh $USER@ssh.tuxfamily.org "cd eigen/eigen.tuxfamily.org-web/htdocs; chmod 660 credits.out; echo Main_Page | /usr/bin/php maintenance/purgeList.php" From 71f19d90d0a6a04c1bc79f9f9abee497f03e5299 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Fri, 2 Oct 2009 12:40:19 -0400 Subject: [PATCH 63/83] forgot to hg add this file --- Eigen/src/Core/products/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Eigen/src/Core/products/CMakeLists.txt diff --git a/Eigen/src/Core/products/CMakeLists.txt b/Eigen/src/Core/products/CMakeLists.txt new file mode 100644 index 000000000..21fc94ae3 --- /dev/null +++ b/Eigen/src/Core/products/CMakeLists.txt @@ -0,0 +1,6 @@ +FILE(GLOB Eigen_Core_Product_SRCS "*.h") + +INSTALL(FILES + ${Eigen_Core_Product_SRCS} + DESTINATION ${INCLUDE_INSTALL_DIR}/Eigen/src/Core/products COMPONENT Devel + ) From 7d2ca0e05e4355540abd8c8621d3b11ceb502293 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 2 Oct 2009 18:45:24 +0200 Subject: [PATCH 64/83] Added cmake project definitions. --- blas/CMakeLists.txt | 2 ++ demos/CMakeLists.txt | 2 ++ doc/CMakeLists.txt | 1 + test/CMakeLists.txt | 2 ++ 4 files changed, 7 insertions(+) diff --git a/blas/CMakeLists.txt b/blas/CMakeLists.txt index 65ef77c90..a6c330a5c 100644 --- a/blas/CMakeLists.txt +++ b/blas/CMakeLists.txt @@ -1,3 +1,5 @@ +project(EigenBlas) + add_custom_target(blas) set(EigenBlas_SRCS single.cpp double.cpp complex_single.cpp complex_double.cpp) diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt index 1ec49d13e..ce25125ec 100644 --- a/demos/CMakeLists.txt +++ b/demos/CMakeLists.txt @@ -1,3 +1,5 @@ +project(EigenDemos) + add_custom_target(demos) find_package(Qt4) diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 773866306..1d20a6075 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -1,3 +1,4 @@ +project(EigenDoc) set_directory_properties(PROPERTIES EXCLUDE_FROM_ALL TRUE) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 19b832873..f7f268e48 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,5 @@ +project(EigenTesting) + add_custom_target(btest) include(EigenTesting) ei_init_testing() From 3e4cb080549c39d8af80ce4e9b086a93a55a8f6a Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sat, 3 Oct 2009 15:51:42 -0400 Subject: [PATCH 65/83] fix #59, can't EXCLUDE_FROM_ALL the test directory --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c1c9ee546..3f69c36cf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,7 @@ add_subdirectory(doc EXCLUDE_FROM_ALL) include(CTest) enable_testing() # must be called from the root CMakeLists, see man page -add_subdirectory(test EXCLUDE_FROM_ALL) +add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest add_subdirectory(unsupported) From a1d9b76dd54679bf0e2f6ac2faca27b7417c6bdd Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sat, 3 Oct 2009 16:50:50 -0400 Subject: [PATCH 66/83] add debug targets like debug_qr to build a specific test with debug info remove the btest target, instead just do "make" since anyway we have to let "make" build the tests --- CMakeLists.txt | 7 +++++-- cmake/EigenTesting.cmake | 27 +++++++++++++++++++++------ test/CMakeLists.txt | 1 - 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f69c36cf..af49654d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,10 +146,13 @@ message("Command | Description") message("-------------+-----------------------------------------------------------------") message("make install | Install to ${CMAKE_INSTALL_PREFIX}") message(" | To change that, do: cmake . -DCMAKE_INSTALL_PREFIX=yourpath") -message("make doc | Generate the API documentation, requires Doxygen & LaTeX") -message("make btest | Build the unit tests (doesn't run them)") +message("make | Build the unit tests") +message(" | Note: that's NOT needed if you just want to install Eigen!") message(" | Note: this takes lots of time & memory! Easy on the -j option!") message("make test | Build and run the unit tests (using CTest)") message("make test_qr | Build a specific test, here test_qr. To run it: test/test_qr") +message("make debug_qr| Build a test with full debug info. To run it: test/debug_qr") message("make blas | Build BLAS library") +message("make doc | Generate the API documentation, requires Doxygen & LaTeX") message("-------------+-----------------------------------------------------------------") + diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index d4e0678f9..337e298c0 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -27,7 +27,11 @@ endmacro(ei_add_property) # void test_() { ... } # # this macro add an executable test_ as well as a ctest test -# named +# named . +# +# it also adds another executable debug_ that compiles in full debug mode +# and is not added to the test target. The idea is that when a test fails you want +# a quick way of rebuilding this specific test in full debug mode. # # On platforms with bash simply run: # "ctest -V" or "ctest -V -R " @@ -36,39 +40,50 @@ endmacro(ei_add_property) macro(ei_add_test testname) set(targetname test_${testname}) + set(debug_targetname debug_${testname}) set(filename ${testname}.cpp) add_executable(${targetname} ${filename}) - add_dependencies(btest ${targetname}) + add_executable(${debug_targetname} ${filename}) if(NOT EIGEN_NO_ASSERTION_CHECKING) if(MSVC) set_target_properties(${targetname} PROPERTIES COMPILE_FLAGS "/EHsc") + set_target_properties(${debug_targetname} PROPERTIES COMPILE_FLAGS "/EHsc") else(MSVC) set_target_properties(${targetname} PROPERTIES COMPILE_FLAGS "-fexceptions") + set_target_properties(${debug_targetname} PROPERTIES COMPILE_FLAGS "-fexceptions") endif(MSVC) option(EIGEN_DEBUG_ASSERTS "Enable debuging of assertions" OFF) if(EIGEN_DEBUG_ASSERTS) ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_DEBUG_ASSERTS=1") + ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-DEIGEN_DEBUG_ASSERTS=1") endif(EIGEN_DEBUG_ASSERTS) else(NOT EIGEN_NO_ASSERTION_CHECKING) ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_NO_ASSERTION_CHECKING=1") + ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-DEIGEN_NO_ASSERTION_CHECKING=1") endif(NOT EIGEN_NO_ASSERTION_CHECKING) + # let the user pass e.g. optimization flags, but don't apply them to the debug target if(${ARGC} GREATER 1) ei_add_target_property(${targetname} COMPILE_FLAGS "${ARGV1}") endif(${ARGC} GREATER 1) - ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_TEST_FUNC=${testname}") + # for the debug target, add full debug options + if(CMAKE_COMPILER_IS_GNUCXX) + # O0 is in principle redundant here, but doesn't hurt + ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-O0 -g3") + elseif(MSVC) + ei_add_target_property(${debug_targetname} COMPILE_FLAGS "/Od /Zi") + endif(CMAKE_COMPILER_IS_GNUCXX) - if(TEST_LIB) - target_link_libraries(${targetname} Eigen2) - endif(TEST_LIB) + ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_TEST_FUNC=${testname}") + ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-DEIGEN_TEST_FUNC=${testname}") target_link_libraries(${targetname} ${EXTERNAL_LIBS}) if(${ARGC} GREATER 2) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f7f268e48..f8fb5ad18 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,6 +1,5 @@ project(EigenTesting) -add_custom_target(btest) include(EigenTesting) ei_init_testing() From d040c9fc9e174dfd2b3d2b0171347b03a86f689a Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sat, 3 Oct 2009 17:19:14 -0400 Subject: [PATCH 67/83] add INSTALL and message about no need to do "make" --- CMakeLists.txt | 4 ++++ INSTALL | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 INSTALL diff --git a/CMakeLists.txt b/CMakeLists.txt index af49654d6..ff10f58cb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,4 +155,8 @@ message("make debug_qr| Build a test with full debug info. To run it: test/deb message("make blas | Build BLAS library") message("make doc | Generate the API documentation, requires Doxygen & LaTeX") message("-------------+-----------------------------------------------------------------") +message("") +message("There's no need to do 'make' unless you really want to build the unit tests!") +message("") + diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..5cc57bd1b --- /dev/null +++ b/INSTALL @@ -0,0 +1,37 @@ +Installation instructions for Eigen +*********************************** + +Explanation before starting +*************************** + +It is very important to understand than Eigen consists only of header files, +hence there is nothing to compile before you can use it. Moreover, these +header files do not depend on your platform, they are the same for +everybody. + + +Method 1. Installing without using CMake +**************************************** + +You can use right away the headers in the Eigen/ subdirectory. In order +to install, just copy this Eigen/ subdirectory to your favorite location. +If you also want the unsupported features, also copy the unsupported/ +subdirectory. + +Method 2. Installing using CMake +******************************** + +Let's call this directory 'source_dir'. Before starting, create another +directory which we will call 'build_dir'. + +Do: + + cd build_dir + cmake source_dir + make install + +The "make install" step may require administrator privileges. + +You can adjust the installation destination (the "prefix") +by passing the -DCMAKE_INSTALL_PREFIX=myprefix option to cmake, as is +explained in the message that cmake prints at the end. From 5f320884437b15ad53a3085bd7d5572ea0624694 Mon Sep 17 00:00:00 2001 From: Thomas Capricelli Date: Sun, 4 Oct 2009 03:35:02 +0200 Subject: [PATCH 68/83] use provided $USER if available, let the caller do the update (safer) --- scripts/eigen_gen_docs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/eigen_gen_docs b/scripts/eigen_gen_docs index 3cdacc1a8..17f573673 100644 --- a/scripts/eigen_gen_docs +++ b/scripts/eigen_gen_docs @@ -1,18 +1,17 @@ #!/bin/sh # configuration -USER='orzel' +# You should call this script with USER set as you want, else some default +# will be used +USER=${USER:-'orzel'} -# step 1 : update -hg pull -u || (echo "update failed"; exit 1) - -# step 2 : build +# step 1 : build # todo if 'build is not there, create one: #mkdir build (cd build && cmake .. && make -j3 doc) || (echo "make failed"; exit 1) #todo: n+1 where n = number of cpus -#step 3 : upload +#step 2 : upload BRANCH=`hg branch` if [ $BRANCH == "default" ] then From 7956fc49a0b280b2a506b614eb500d8287748d03 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sat, 3 Oct 2009 22:11:30 -0400 Subject: [PATCH 69/83] dd first-time tip, to warn against doing "make". now i think we're reasonably safe. --- CMakeLists.txt | 42 ++++++++++++++++++++++++------------------ INSTALL | 10 +++++----- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff10f58cb..6fac4fa1f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -141,22 +141,28 @@ ei_testing_print_summary() message("") message("Configured Eigen ${EIGEN_VERSION_NUMBER}") message("You can now do the following:") -message("-------------+-----------------------------------------------------------------") -message("Command | Description") -message("-------------+-----------------------------------------------------------------") -message("make install | Install to ${CMAKE_INSTALL_PREFIX}") -message(" | To change that, do: cmake . -DCMAKE_INSTALL_PREFIX=yourpath") -message("make | Build the unit tests") -message(" | Note: that's NOT needed if you just want to install Eigen!") -message(" | Note: this takes lots of time & memory! Easy on the -j option!") -message("make test | Build and run the unit tests (using CTest)") -message("make test_qr | Build a specific test, here test_qr. To run it: test/test_qr") -message("make debug_qr| Build a test with full debug info. To run it: test/debug_qr") -message("make blas | Build BLAS library") -message("make doc | Generate the API documentation, requires Doxygen & LaTeX") -message("-------------+-----------------------------------------------------------------") -message("") -message("There's no need to do 'make' unless you really want to build the unit tests!") -message("") - +message("--------------+----------------------------------------------------------------") +message("Command | Description") +message("--------------+----------------------------------------------------------------") +message("make install | Install to ${CMAKE_INSTALL_PREFIX}") +message(" | To change that: cmake . -DCMAKE_INSTALL_PREFIX=yourpath") +message("make | Build the unit tests") +message(" | * That's not needed if you just want to install Eigen!") +message(" | * That takes lots of memory! Easy on the -j option!") +message("make test | Build and run the unit tests (using CTest)") +message("make test_qr | Build a specific test, here test_qr. To run it: test/test_qr") +message("make debug_qr | Build a test with full debug info. To run it: test/debug_qr") +message("make blas | Build BLAS library (not the same thing as Eigen)") +message("make doc | Generate the API documentation, requires Doxygen & LaTeX") +message("--------------+----------------------------------------------------------------") +if(NOT EIGEN_CMAKE_ALREADY_RUN) + unset(EIGEN_CMAKE_ALREADY_RUN CACHE) # in case it was manually set to OFF in cache + set(EIGEN_CMAKE_ALREADY_RUN "ON" CACHE BOOL "Set to ON if CMake has already run here.") + message("") + message("First-time tip:") + message("") + message("If you just want to install Eigen, do 'make install' right away.") + message("No need to do 'make' before. See INSTALL file for more details.") + message("") +endif(NOT EIGEN_CMAKE_ALREADY_RUN) diff --git a/INSTALL b/INSTALL index 5cc57bd1b..5face1323 100644 --- a/INSTALL +++ b/INSTALL @@ -4,7 +4,7 @@ Installation instructions for Eigen Explanation before starting *************************** -It is very important to understand than Eigen consists only of header files, +It is very important to understand that Eigen consists only of header files, hence there is nothing to compile before you can use it. Moreover, these header files do not depend on your platform, they are the same for everybody. @@ -15,14 +15,14 @@ Method 1. Installing without using CMake You can use right away the headers in the Eigen/ subdirectory. In order to install, just copy this Eigen/ subdirectory to your favorite location. -If you also want the unsupported features, also copy the unsupported/ -subdirectory. +If you also want the unsupported features, copy the unsupported/ +subdirectory too. Method 2. Installing using CMake ******************************** -Let's call this directory 'source_dir'. Before starting, create another -directory which we will call 'build_dir'. +Let's call this directory 'source_dir' (where this INSTALL file is). +Before starting, create another directory which we will call 'build_dir'. Do: From b78b2ede5f6156c8898c152335176cbd47c34bdb Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Sun, 4 Oct 2009 20:27:44 -0400 Subject: [PATCH 70/83] finally, the right fix: set CTEST_BUILD_TARGET. So this is the come-back of btest target, and the default target is empty again. --- CMakeLists.txt | 20 ++++---------------- CTestConfig.cmake | 1 + INSTALL | 8 +++----- cmake/EigenTesting.cmake | 1 + test/CMakeLists.txt | 2 +- 5 files changed, 10 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6fac4fa1f..c3b63bc55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,7 @@ add_subdirectory(doc EXCLUDE_FROM_ALL) include(CTest) enable_testing() # must be called from the root CMakeLists, see man page -add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest +add_subdirectory(test EXCLUDE_FROM_ALL) # can't do EXCLUDE_FROM_ALL here, breaks CTest add_subdirectory(unsupported) @@ -145,24 +145,12 @@ message("--------------+-------------------------------------------------------- message("Command | Description") message("--------------+----------------------------------------------------------------") message("make install | Install to ${CMAKE_INSTALL_PREFIX}") -message(" | To change that: cmake . -DCMAKE_INSTALL_PREFIX=yourpath") -message("make | Build the unit tests") -message(" | * That's not needed if you just want to install Eigen!") -message(" | * That takes lots of memory! Easy on the -j option!") +message(" | * To change that: cmake . -DCMAKE_INSTALL_PREFIX=yourpath") +message("make btest | Build the unit tests") +message(" | * That takes lots of memory! Easy on the -j option") message("make test | Build and run the unit tests (using CTest)") message("make test_qr | Build a specific test, here test_qr. To run it: test/test_qr") message("make debug_qr | Build a test with full debug info. To run it: test/debug_qr") message("make blas | Build BLAS library (not the same thing as Eigen)") message("make doc | Generate the API documentation, requires Doxygen & LaTeX") message("--------------+----------------------------------------------------------------") - -if(NOT EIGEN_CMAKE_ALREADY_RUN) - unset(EIGEN_CMAKE_ALREADY_RUN CACHE) # in case it was manually set to OFF in cache - set(EIGEN_CMAKE_ALREADY_RUN "ON" CACHE BOOL "Set to ON if CMake has already run here.") - message("") - message("First-time tip:") - message("") - message("If you just want to install Eigen, do 'make install' right away.") - message("No need to do 'make' before. See INSTALL file for more details.") - message("") -endif(NOT EIGEN_CMAKE_ALREADY_RUN) diff --git a/CTestConfig.cmake b/CTestConfig.cmake index 0ccd5a1ad..897a9a854 100644 --- a/CTestConfig.cmake +++ b/CTestConfig.cmake @@ -11,3 +11,4 @@ set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "eigen.tuxfamily.org") set(CTEST_DROP_LOCATION "/CDash/submit.php?project=Eigen") set(CTEST_DROP_SITE_CDASH TRUE) +set(CTEST_BUILD_TARGET "btest") diff --git a/INSTALL b/INSTALL index 5face1323..4f717e9c2 100644 --- a/INSTALL +++ b/INSTALL @@ -4,11 +4,9 @@ Installation instructions for Eigen Explanation before starting *************************** -It is very important to understand that Eigen consists only of header files, -hence there is nothing to compile before you can use it. Moreover, these -header files do not depend on your platform, they are the same for -everybody. - +Eigen consists only of header files, hence there is nothing to compile +before you can use it. Moreover, these header files do not depend on your +platform, they are the same for everybody. Method 1. Installing without using CMake **************************************** diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 337e298c0..0ea6dddb4 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -44,6 +44,7 @@ macro(ei_add_test testname) set(filename ${testname}.cpp) add_executable(${targetname} ${filename}) + add_dependencies(btest ${targetname}) add_executable(${debug_targetname} ${filename}) if(NOT EIGEN_NO_ASSERTION_CHECKING) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f8fb5ad18..b46971493 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,5 +1,5 @@ project(EigenTesting) - +add_custom_target(btest) include(EigenTesting) ei_init_testing() From fa9fc1397ba29806da9aa29776b2b9d3830fbdb9 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 5 Oct 2009 07:42:31 -0400 Subject: [PATCH 71/83] next attempt ... introduce EIGEN_CMAKE_RUN_FROM_CTEST, in that case don't EXCLUDE_FROM_ALL --- CMakeLists.txt | 6 +++++- test/testsuite.cmake | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c3b63bc55..36b2be99f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,11 @@ add_subdirectory(doc EXCLUDE_FROM_ALL) include(CTest) enable_testing() # must be called from the root CMakeLists, see man page -add_subdirectory(test EXCLUDE_FROM_ALL) # can't do EXCLUDE_FROM_ALL here, breaks CTest +if(EIGEN_CMAKE_RUN_FROM_CTEST) +add_subdirectory(test) # can't do EXCLUDE_FROM_ALL here, breaks CTest +else(EIGEN_CMAKE_RUN_FROM_CTEST) +add_subdirectory(test EXCLUDE_FROM_ALL) +endif(EIGEN_CMAKE_RUN_FROM_CTEST) add_subdirectory(unsupported) diff --git a/test/testsuite.cmake b/test/testsuite.cmake index 37ee87565..c6cc07369 100644 --- a/test/testsuite.cmake +++ b/test/testsuite.cmake @@ -148,7 +148,7 @@ endif(NOT EIGEN_NO_UPDATE) # which ctest command to use for running the dashboard SET (CTEST_COMMAND "${EIGEN_CMAKE_DIR}ctest -D ${EIGEN_MODE}") # what cmake command to use for configuring this dashboard -SET (CTEST_CMAKE_COMMAND "${EIGEN_CMAKE_DIR}cmake -DEIGEN_BUILD_TESTS=on ") +SET (CTEST_CMAKE_COMMAND "${EIGEN_CMAKE_DIR}cmake -DEIGEN_CMAKE_RUN_FROM_CTEST=on -DEIGEN_BUILD_TESTS=on ") #################################################################### # The values in this section are optional you can either From a9a9ba8453853db2c5a2212cedb8fbc8dc4cde2e Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 5 Oct 2009 07:58:53 -0400 Subject: [PATCH 72/83] remove unneeded stuff --- CTestConfig.cmake | 1 - test/testsuite.cmake | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CTestConfig.cmake b/CTestConfig.cmake index 897a9a854..0ccd5a1ad 100644 --- a/CTestConfig.cmake +++ b/CTestConfig.cmake @@ -11,4 +11,3 @@ set(CTEST_DROP_METHOD "http") set(CTEST_DROP_SITE "eigen.tuxfamily.org") set(CTEST_DROP_LOCATION "/CDash/submit.php?project=Eigen") set(CTEST_DROP_SITE_CDASH TRUE) -set(CTEST_BUILD_TARGET "btest") diff --git a/test/testsuite.cmake b/test/testsuite.cmake index c6cc07369..147b82d46 100644 --- a/test/testsuite.cmake +++ b/test/testsuite.cmake @@ -148,7 +148,7 @@ endif(NOT EIGEN_NO_UPDATE) # which ctest command to use for running the dashboard SET (CTEST_COMMAND "${EIGEN_CMAKE_DIR}ctest -D ${EIGEN_MODE}") # what cmake command to use for configuring this dashboard -SET (CTEST_CMAKE_COMMAND "${EIGEN_CMAKE_DIR}cmake -DEIGEN_CMAKE_RUN_FROM_CTEST=on -DEIGEN_BUILD_TESTS=on ") +SET (CTEST_CMAKE_COMMAND "${EIGEN_CMAKE_DIR}cmake -DEIGEN_CMAKE_RUN_FROM_CTEST=ON") #################################################################### # The values in this section are optional you can either From a7d51435e12ed40849ce807fc67e87c06b1dbc0c Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Mon, 5 Oct 2009 14:00:32 +0200 Subject: [PATCH 73/83] added cygwin specific stuff --- cmake/EigenTesting.cmake | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 0ea6dddb4..d043f67b8 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -96,7 +96,11 @@ macro(ei_add_test testname) endif(${ARGC} GREATER 2) if(WIN32) - add_test(${testname} "${targetname}") + if(CYGWIN) + add_test(${testname} "${Eigen_SOURCE_DIR}/test/runtest.sh" "${testname}") + else(CYGWIN) + add_test(${testname} "${targetname}") + endif(CYGWIN) else(WIN32) add_test(${testname} "${Eigen_SOURCE_DIR}/test/runtest.sh" "${testname}") endif(WIN32) From d41577819bddb5ca734acc3ba0697646475dc786 Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 5 Oct 2009 10:11:11 -0400 Subject: [PATCH 74/83] we were already aligning to 16 byte boundary fixed-size objects that are multiple of 16 bytes; now we also align to 8byte boundary fixed-size objects that are multiple of 8 bytes. That's only useful for now for double, not e.g. for Vector2f, but that didn't seem to hurt. Am I missing something? Do you prefer that we don't align Vector2f at all? Also, improvements in test_unalignedassert. --- Eigen/src/Core/MatrixStorage.h | 52 ++++++++----- Eigen/src/Core/arch/AltiVec/PacketMath.h | 6 +- Eigen/src/Core/arch/SSE/PacketMath.h | 6 +- Eigen/src/Core/util/Macros.h | 16 ++-- test/packetmath.cpp | 14 ++-- test/unalignedassert.cpp | 94 +++++++++++++----------- 6 files changed, 108 insertions(+), 80 deletions(-) diff --git a/Eigen/src/Core/MatrixStorage.h b/Eigen/src/Core/MatrixStorage.h index f67095d0c..654fdf5e6 100644 --- a/Eigen/src/Core/MatrixStorage.h +++ b/Eigen/src/Core/MatrixStorage.h @@ -29,32 +29,48 @@ struct ei_constructor_without_unaligned_array_assert {}; /** \internal - * Static array automatically aligned if the total byte size is a multiple of 16 and the matrix options require auto alignment + * Static array. If the MatrixOptions require auto-alignment, and the array will be automatically aligned: + * - to 16 bytes boundary, if the total size is a multiple of 16 bytes; + * - or else to 8 bytes boundary, if the total size is a multiple of 8 bytes. */ template struct ei_matrix_array -{ - EIGEN_ALIGN_128 T array[Size]; - - ei_matrix_array() - { - #ifndef EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT - ei_assert((reinterpret_cast(array) & 0xf) == 0 - && "this assertion is explained here: http://eigen.tuxfamily.org/dox/UnalignedArrayAssert.html **** READ THIS WEB PAGE !!! ****"); - #endif - } - - ei_matrix_array(ei_constructor_without_unaligned_array_assert) {} -}; - -template struct ei_matrix_array + int Alignment = (MatrixOptions&DontAlign) ? 0 + : (((Size*sizeof(T))%16)==0) ? 16 + : (((Size*sizeof(T))%8)==0) ? 8 + : 0 > +struct ei_matrix_array { T array[Size]; ei_matrix_array() {} ei_matrix_array(ei_constructor_without_unaligned_array_assert) {} }; +#ifdef EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) +#else + #define EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(sizemask) \ + ei_assert((reinterpret_cast(array) & sizemask) == 0 \ + && "this assertion is explained here: " \ + "http://eigen.tuxfamily.org/dox/UnalignedArrayAssert.html" \ + " **** READ THIS WEB PAGE !!! ****"); +#endif + +template +struct ei_matrix_array +{ + EIGEN_ALIGN16 T array[Size]; + ei_matrix_array() { EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0xf) } + ei_matrix_array(ei_constructor_without_unaligned_array_assert) {} +}; + +template +struct ei_matrix_array +{ + EIGEN_ALIGN8 T array[Size]; + ei_matrix_array() { EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0x7) } + ei_matrix_array(ei_constructor_without_unaligned_array_assert) {} +}; + /** \internal * * \class ei_matrix_storage diff --git a/Eigen/src/Core/arch/AltiVec/PacketMath.h b/Eigen/src/Core/arch/AltiVec/PacketMath.h index a9c16200e..1526a4b97 100644 --- a/Eigen/src/Core/arch/AltiVec/PacketMath.h +++ b/Eigen/src/Core/arch/AltiVec/PacketMath.h @@ -265,14 +265,14 @@ template<> inline void ei_pstoreu(int* to , const v4i& from ) template<> inline float ei_pfirst(const v4f& a) { - float EIGEN_ALIGN_128 af[4]; + float EIGEN_ALIGN16 af[4]; vec_st(a, 0, af); return af[0]; } template<> inline int ei_pfirst(const v4i& a) { - int EIGEN_ALIGN_128 ai[4]; + int EIGEN_ALIGN16 ai[4]; vec_st(a, 0, ai); return ai[0]; } @@ -373,7 +373,7 @@ inline float ei_predux_mul(const v4f& a) inline int ei_predux_mul(const v4i& a) { - EIGEN_ALIGN_128 int aux[4]; + EIGEN_ALIGN16 int aux[4]; ei_pstore(aux, a); return aux[0] * aux[1] * aux[2] * aux[3]; } diff --git a/Eigen/src/Core/arch/SSE/PacketMath.h b/Eigen/src/Core/arch/SSE/PacketMath.h index ddc7b4aaf..eb1c2d311 100644 --- a/Eigen/src/Core/arch/SSE/PacketMath.h +++ b/Eigen/src/Core/arch/SSE/PacketMath.h @@ -359,7 +359,7 @@ template<> EIGEN_STRONG_INLINE int ei_predux_mul(const Packet4i& a) // after some experiments, it is seems this is the fastest way to implement it // for GCC (eg., reusing ei_pmul is very slow !) // TODO try to call _mm_mul_epu32 directly - EIGEN_ALIGN_128 int aux[4]; + EIGEN_ALIGN16 int aux[4]; ei_pstore(aux, a); return (aux[0] * aux[1]) * (aux[2] * aux[3]);; } @@ -378,7 +378,7 @@ template<> EIGEN_STRONG_INLINE int ei_predux_min(const Packet4i& a) { // after some experiments, it is seems this is the fastest way to implement it // for GCC (eg., it does not like using std::min after the ei_pstore !!) - EIGEN_ALIGN_128 int aux[4]; + EIGEN_ALIGN16 int aux[4]; ei_pstore(aux, a); register int aux0 = aux[0] EIGEN_STRONG_INLINE int ei_predux_max(const Packet4i& a) { // after some experiments, it is seems this is the fastest way to implement it // for GCC (eg., it does not like using std::min after the ei_pstore !!) - EIGEN_ALIGN_128 int aux[4]; + EIGEN_ALIGN16 int aux[4]; ei_pstore(aux, a); register int aux0 = aux[0]>aux[1] ? aux[0] : aux[1]; register int aux2 = aux[2]>aux[3] ? aux[2] : aux[3]; diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index 71962bcae..fb149e50a 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -202,25 +202,29 @@ using Eigen::ei_cos; #define EIGEN_ASM_COMMENT(X) #endif -/* EIGEN_ALIGN_128 forces data to be 16-byte aligned, EVEN if vectorization (EIGEN_VECTORIZE) is disabled, +/* EIGEN_ALIGN_TO_BOUNDARY(n) forces data to be n-byte aligned. This is used to satisfy SIMD requirements. + * However, we do that EVEN if vectorization (EIGEN_VECTORIZE) is disabled, * so that vectorization doesn't affect binary compatibility. * * If we made alignment depend on whether or not EIGEN_VECTORIZE is defined, it would be impossible to link * vectorized and non-vectorized code. */ #if !EIGEN_ALIGN - #define EIGEN_ALIGN_128 + #define EIGEN_ALIGN_TO_BOUNDARY(n) #elif (defined __GNUC__) - #define EIGEN_ALIGN_128 __attribute__((aligned(16))) + #define EIGEN_ALIGN_TO_BOUNDARY(n) __attribute__((aligned(n))) #elif (defined _MSC_VER) - #define EIGEN_ALIGN_128 __declspec(align(16)) + #define EIGEN_ALIGN_TO_BOUNDARY(n) __declspec(align(n)) #elif (defined __SUNPRO_CC) // FIXME not sure about this one: - #define EIGEN_ALIGN_128 __attribute__((aligned(16))) + #define EIGEN_ALIGN_TO_BOUNDARY(n) __attribute__((aligned(n))) #else - #error Please tell me what is the equivalent of __attribute__((aligned(16))) for your compiler + #error Please tell me what is the equivalent of __attribute__((aligned(n))) for your compiler #endif +#define EIGEN_ALIGN16 EIGEN_ALIGN_TO_BOUNDARY(16) +#define EIGEN_ALIGN8 EIGEN_ALIGN_TO_BOUNDARY(8) + #ifdef EIGEN_DONT_USE_RESTRICT_KEYWORD #define EIGEN_RESTRICT #endif diff --git a/test/packetmath.cpp b/test/packetmath.cpp index d86d40d68..1745ae5c6 100644 --- a/test/packetmath.cpp +++ b/test/packetmath.cpp @@ -99,10 +99,10 @@ template void packetmath() const int PacketSize = ei_packet_traits::size; const int size = PacketSize*4; - EIGEN_ALIGN_128 Scalar data1[ei_packet_traits::size*4]; - EIGEN_ALIGN_128 Scalar data2[ei_packet_traits::size*4]; - EIGEN_ALIGN_128 Packet packets[PacketSize*2]; - EIGEN_ALIGN_128 Scalar ref[ei_packet_traits::size*4]; + EIGEN_ALIGN16 Scalar data1[ei_packet_traits::size*4]; + EIGEN_ALIGN16 Scalar data2[ei_packet_traits::size*4]; + EIGEN_ALIGN16 Packet packets[PacketSize*2]; + EIGEN_ALIGN16 Scalar ref[ei_packet_traits::size*4]; for (int i=0; i(); @@ -202,9 +202,9 @@ template void packetmath_real() const int PacketSize = ei_packet_traits::size; const int size = PacketSize*4; - EIGEN_ALIGN_128 Scalar data1[ei_packet_traits::size*4]; - EIGEN_ALIGN_128 Scalar data2[ei_packet_traits::size*4]; - EIGEN_ALIGN_128 Scalar ref[ei_packet_traits::size*4]; + EIGEN_ALIGN16 Scalar data1[ei_packet_traits::size*4]; + EIGEN_ALIGN16 Scalar data2[ei_packet_traits::size*4]; + EIGEN_ALIGN16 Scalar ref[ei_packet_traits::size*4]; for (int i=0; i m; // bad: same reason -}; - -struct Bad6 -{ - Matrix m; // bad: same reason -}; - -struct Good7 +struct TestNew4 { EIGEN_MAKE_ALIGNED_OPERATOR_NEW Vector2d m; float f; // make the struct have sizeof%16!=0 to make it a little more tricky when we allow an array of 2 such objects }; -struct Good8 +struct TestNew5 { EIGEN_MAKE_ALIGNED_OPERATOR_NEW - float f; // try the f at first -- the EIGEN_ALIGN_128 attribute of m should make that still work + float f; // try the f at first -- the EIGEN_ALIGN16 attribute of m should make that still work Matrix4f m; }; -struct Good9 +struct TestNew6 { Matrix m; // good: no alignment requested float f; @@ -94,34 +80,56 @@ void check_unalignedassert_good() #if EIGEN_ALIGN template -void check_unalignedassert_bad() +void construct_at_boundary(int boundary) { - float buf[sizeof(T)+16]; - float *unaligned = buf; - while((reinterpret_cast(unaligned)&0xf)==0) ++unaligned; // make sure unaligned is really unaligned - T *x = ::new(static_cast(unaligned)) T; + char buf[sizeof(T)+256]; + size_t _buf = reinterpret_cast(buf); + _buf += (16 - (_buf % 16)); // make 16-byte aligned + _buf += boundary; // make exact boundary-aligned + T *x = ::new(reinterpret_cast(_buf)) T; x->~T(); } #endif void unalignedassert() { - check_unalignedassert_good(); - check_unalignedassert_good(); - check_unalignedassert_good(); -#if EIGEN_ALIGN - VERIFY_RAISES_ASSERT(check_unalignedassert_bad()); - VERIFY_RAISES_ASSERT(check_unalignedassert_bad()); - VERIFY_RAISES_ASSERT(check_unalignedassert_bad()); -#endif + construct_at_boundary(8); + construct_at_boundary(4); + construct_at_boundary(16); + construct_at_boundary(16); + construct_at_boundary(4); + construct_at_boundary(16); + + construct_at_boundary(16); + construct_at_boundary(8); + construct_at_boundary(16); + construct_at_boundary(16); + construct_at_boundary(8); + construct_at_boundary(16); + + check_unalignedassert_good(); + check_unalignedassert_good(); + check_unalignedassert_good(); - check_unalignedassert_good(); - check_unalignedassert_good(); - check_unalignedassert_good(); + check_unalignedassert_good(); + check_unalignedassert_good(); + check_unalignedassert_good(); check_unalignedassert_good >(); - + #if EIGEN_ALIGN - VERIFY_RAISES_ASSERT(check_unalignedassert_bad >()); + VERIFY_RAISES_ASSERT(construct_at_boundary(4)); + VERIFY_RAISES_ASSERT(construct_at_boundary(4)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(4)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(4)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(4)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(4)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); #endif } From bb1cc0d092e118ad2a6119d40349479152cb583d Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Mon, 5 Oct 2009 10:55:42 -0400 Subject: [PATCH 75/83] after all we're not aligning to 8byte boundary keep most of the changes though as they make the code more extensible --- Eigen/src/Core/MatrixStorage.h | 14 ++------------ Eigen/src/Core/util/Macros.h | 1 - test/unalignedassert.cpp | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/Eigen/src/Core/MatrixStorage.h b/Eigen/src/Core/MatrixStorage.h index 654fdf5e6..73b17e63e 100644 --- a/Eigen/src/Core/MatrixStorage.h +++ b/Eigen/src/Core/MatrixStorage.h @@ -29,14 +29,12 @@ struct ei_constructor_without_unaligned_array_assert {}; /** \internal - * Static array. If the MatrixOptions require auto-alignment, and the array will be automatically aligned: - * - to 16 bytes boundary, if the total size is a multiple of 16 bytes; - * - or else to 8 bytes boundary, if the total size is a multiple of 8 bytes. + * Static array. If the MatrixOptions require auto-alignment, the array will be automatically aligned: + * to 16 bytes boundary if the total size is a multiple of 16 bytes. */ template struct ei_matrix_array { @@ -63,14 +61,6 @@ struct ei_matrix_array ei_matrix_array(ei_constructor_without_unaligned_array_assert) {} }; -template -struct ei_matrix_array -{ - EIGEN_ALIGN8 T array[Size]; - ei_matrix_array() { EIGEN_MAKE_UNALIGNED_ARRAY_ASSERT(0x7) } - ei_matrix_array(ei_constructor_without_unaligned_array_assert) {} -}; - /** \internal * * \class ei_matrix_storage diff --git a/Eigen/src/Core/util/Macros.h b/Eigen/src/Core/util/Macros.h index fb149e50a..706b30174 100644 --- a/Eigen/src/Core/util/Macros.h +++ b/Eigen/src/Core/util/Macros.h @@ -223,7 +223,6 @@ using Eigen::ei_cos; #endif #define EIGEN_ALIGN16 EIGEN_ALIGN_TO_BOUNDARY(16) -#define EIGEN_ALIGN8 EIGEN_ALIGN_TO_BOUNDARY(8) #ifdef EIGEN_DONT_USE_RESTRICT_KEYWORD #define EIGEN_RESTRICT diff --git a/test/unalignedassert.cpp b/test/unalignedassert.cpp index 8acc90158..233268d1d 100644 --- a/test/unalignedassert.cpp +++ b/test/unalignedassert.cpp @@ -93,7 +93,7 @@ void construct_at_boundary(int boundary) void unalignedassert() { - construct_at_boundary(8); + construct_at_boundary(4); construct_at_boundary(4); construct_at_boundary(16); construct_at_boundary(16); @@ -101,12 +101,17 @@ void unalignedassert() construct_at_boundary(16); construct_at_boundary(16); - construct_at_boundary(8); + construct_at_boundary(4); construct_at_boundary(16); construct_at_boundary(16); - construct_at_boundary(8); + construct_at_boundary(4); construct_at_boundary(16); + construct_at_boundary(16); + construct_at_boundary(4); + construct_at_boundary(16); + construct_at_boundary(16); + check_unalignedassert_good(); check_unalignedassert_good(); check_unalignedassert_good(); @@ -117,19 +122,14 @@ void unalignedassert() check_unalignedassert_good >(); #if EIGEN_ALIGN - VERIFY_RAISES_ASSERT(construct_at_boundary(4)); - VERIFY_RAISES_ASSERT(construct_at_boundary(4)); VERIFY_RAISES_ASSERT(construct_at_boundary(8)); - VERIFY_RAISES_ASSERT(construct_at_boundary(4)); - VERIFY_RAISES_ASSERT(construct_at_boundary(8)); - VERIFY_RAISES_ASSERT(construct_at_boundary(4)); VERIFY_RAISES_ASSERT(construct_at_boundary(8)); VERIFY_RAISES_ASSERT(construct_at_boundary(8)); - VERIFY_RAISES_ASSERT(construct_at_boundary(4)); VERIFY_RAISES_ASSERT(construct_at_boundary(8)); VERIFY_RAISES_ASSERT(construct_at_boundary(8)); - VERIFY_RAISES_ASSERT(construct_at_boundary(4)); VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); + VERIFY_RAISES_ASSERT(construct_at_boundary(8)); #endif } From 904f35d19497b5442a80a30c42d00fc52c22fe36 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Mon, 5 Oct 2009 17:22:16 +0200 Subject: [PATCH 76/83] discard vectorization in matrix-vector product when data is not even aligned on the scalar type size (e.g., for double on 32 bits system without -malign-double) --- Eigen/src/Core/products/GeneralMatrixVector.h | 35 +++++++++++++------ test/testsuite.cmake | 2 +- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Eigen/src/Core/products/GeneralMatrixVector.h b/Eigen/src/Core/products/GeneralMatrixVector.h index 57875035a..a18e5ef1d 100644 --- a/Eigen/src/Core/products/GeneralMatrixVector.h +++ b/Eigen/src/Core/products/GeneralMatrixVector.h @@ -57,8 +57,7 @@ void ei_cache_friendly_product_colmajor_times_vector( if(ConjugateRhs) alpha = ei_conj(alpha); -// std::cerr << "prod " << size << " " << rhs.size() << "\n"; - + typedef typename NumTraits::Real RealScalar; typedef typename ei_packet_traits::type Packet; const int PacketSize = sizeof(Packet)/sizeof(Scalar); @@ -69,9 +68,9 @@ void ei_cache_friendly_product_colmajor_times_vector( const int PeelAlignedMask = PacketSize*peels-1; // How many coeffs of the result do we have to skip to be aligned. - // Here we assume data are at least aligned on the base scalar type that is mandatory anyway. - const int alignedStart = ei_alignmentOffset(res,size); - const int alignedSize = PacketSize>1 ? alignedStart + ((size-alignedStart) & ~PacketAlignedMask) : 0; + // Here we assume data are at least aligned on the base scalar type. + int alignedStart = ei_alignmentOffset(res,size); + int alignedSize = PacketSize>1 ? alignedStart + ((size-alignedStart) & ~PacketAlignedMask) : 0; const int peeledSize = peels>1 ? alignedStart + ((alignedSize-alignedStart) & ~PeelAlignedMask) : alignedStart; const int alignmentStep = PacketSize>1 ? (PacketSize - lhsStride % PacketSize) & PacketAlignedMask : 0; @@ -84,12 +83,18 @@ void ei_cache_friendly_product_colmajor_times_vector( // find how many columns do we have to skip to be aligned with the result (if possible) int skipColumns = 0; - if (PacketSize>1) + // if the data cannot be aligned (TODO add some compile time tests when possible, e.g. for floats) + if( (size_t(lhs)%sizeof(RealScalar)) || (size_t(res)%sizeof(RealScalar)) ) + { + alignedSize = 0; + alignedStart = 0; + } + else if (PacketSize>1) { ei_internal_assert(size_t(lhs+lhsAlignmentOffset)%sizeof(Packet)==0 || size cj; + typedef typename NumTraits::Real RealScalar; typedef typename ei_packet_traits::type Packet; const int PacketSize = sizeof(Packet)/sizeof(Scalar); @@ -274,9 +280,10 @@ static EIGEN_DONT_INLINE void ei_cache_friendly_product_rowmajor_times_vector( const int size = rhsSize; // How many coeffs of the result do we have to skip to be aligned. - // Here we assume data are at least aligned on the base scalar type that is mandatory anyway. - const int alignedStart = ei_alignmentOffset(rhs, size); - const int alignedSize = PacketSize>1 ? alignedStart + ((size-alignedStart) & ~PacketAlignedMask) : 0; + // Here we assume data are at least aligned on the base scalar type + // if that's not the case then vectorization is discarded, see below. + int alignedStart = ei_alignmentOffset(rhs, size); + int alignedSize = PacketSize>1 ? alignedStart + ((size-alignedStart) & ~PacketAlignedMask) : 0; const int peeledSize = peels>1 ? alignedStart + ((alignedSize-alignedStart) & ~PeelAlignedMask) : alignedStart; const int alignmentStep = PacketSize>1 ? (PacketSize - lhsStride % PacketSize) & PacketAlignedMask : 0; @@ -289,7 +296,13 @@ static EIGEN_DONT_INLINE void ei_cache_friendly_product_rowmajor_times_vector( // find how many rows do we have to skip to be aligned with rhs (if possible) int skipRows = 0; - if (PacketSize>1) + // if the data cannot be aligned (TODO add some compile time tests when possible, e.g. for floats) + if( (size_t(lhs)%sizeof(RealScalar)) || (size_t(rhs)%sizeof(RealScalar)) ) + { + alignedSize = 0; + alignedStart = 0; + } + else if (PacketSize>1) { ei_internal_assert(size_t(lhs+lhsAlignmentOffset)%sizeof(Packet)==0 || size Date: Tue, 6 Oct 2009 10:24:41 +0200 Subject: [PATCH 77/83] fix compilation in stable norm, move a platform check to the unit tests --- Eigen/src/Core/StableNorm.h | 14 ++++---------- test/stable_norm.cpp | 15 +++++++++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Eigen/src/Core/StableNorm.h b/Eigen/src/Core/StableNorm.h index facab9dbd..b4a5d0bfd 100644 --- a/Eigen/src/Core/StableNorm.h +++ b/Eigen/src/Core/StableNorm.h @@ -108,21 +108,15 @@ MatrixBase::blueNorm() const iemax = std::numeric_limits::max_exponent; // maximum exponent rbig = std::numeric_limits::max(); // largest floating-point number - // Check the basic machine-dependent constants. - if(iemin > 1 - 2*it || 1+it>iemax || (it==2 && ibeta<5) - || (it<=4 && ibeta <= 3 ) || it<2) - { - ei_assert(false && "the algorithm cannot be guaranteed on this computer"); - } iexp = -((1-iemin)/2); - b1 = RealScalar(std::pow(double(ibeta),iexp)); // lower boundary of midrange + b1 = RealScalar(std::pow(ibeta,iexp)); // lower boundary of midrange iexp = (iemax + 1 - it)/2; - b2 = RealScalar(std::pow(double(ibeta),iexp)); // upper boundary of midrange + b2 = RealScalar(std::pow(ibeta,iexp)); // upper boundary of midrange iexp = (2-iemin)/2; - s1m = RealScalar(std::pow(double(ibeta),iexp)); // scaling factor for lower range + s1m = RealScalar(std::pow(ibeta,iexp)); // scaling factor for lower range iexp = - ((iemax+it)/2); - s2m = RealScalar(std::pow(double(ibeta),iexp)); // scaling factor for upper range + s2m = RealScalar(std::pow(ibeta,iexp)); // scaling factor for upper range overfl = rbig*s2m; // overfow boundary for abig eps = RealScalar(std::pow(double(ibeta), 1-it)); diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index 726512ec0..6ce99477d 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -33,6 +33,21 @@ template void stable_norm(const MatrixType& m) typedef typename MatrixType::Scalar Scalar; typedef typename NumTraits::Real RealScalar; + // Check the basic machine-dependent constants. + { + int nbig, ibeta, it, iemin, iemax, iexp; + RealScalar abig, eps; + + ibeta = std::numeric_limits::radix; // base for floating-point numbers + it = std::numeric_limits::digits; // number of base-beta digits in mantissa + iemin = std::numeric_limits::min_exponent; // minimum exponent + iemax = std::numeric_limits::max_exponent; // maximum exponent + + VERIFY( (!(iemin > 1 - 2*it || 1+it>iemax || (it==2 && ibeta<5) || (it<=4 && ibeta <= 3 ) || it<2)) + && "the stable norm algorithm cannot be guaranteed on this computer"); + } + + int rows = m.rows(); int cols = m.cols(); From 80ede36b2402e4f3015d8b99843fa6cdc124ca3c Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Tue, 6 Oct 2009 09:26:28 -0400 Subject: [PATCH 78/83] allow arbitrary resulttype, fixes Xuewen's issue, and this stuff is going to get deeply refactored soon anyway. --- Eigen/src/Core/MatrixBase.h | 6 ++- Eigen/src/LU/Inverse.h | 74 +++++++++++++++++++------------------ 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/Eigen/src/Core/MatrixBase.h b/Eigen/src/Core/MatrixBase.h index 5ae2b0002..387c11385 100644 --- a/Eigen/src/Core/MatrixBase.h +++ b/Eigen/src/Core/MatrixBase.h @@ -702,8 +702,10 @@ template class MatrixBase const LU lu() const; const PartialLU partialLu() const; const PlainMatrixType inverse() const; - void computeInverse(PlainMatrixType *result) const; - bool computeInverseWithCheck( PlainMatrixType *result ) const; + template + void computeInverse(ResultType *result) const; + template + bool computeInverseWithCheck(ResultType *result ) const; Scalar determinant() const; /////////// Cholesky module /////////// diff --git a/Eigen/src/LU/Inverse.h b/Eigen/src/LU/Inverse.h index 248b48044..3255c1022 100644 --- a/Eigen/src/LU/Inverse.h +++ b/Eigen/src/LU/Inverse.h @@ -95,8 +95,8 @@ bool ei_compute_inverse_size3(const XprType& matrix, MatrixType* result) return true; } -template -bool ei_compute_inverse_size4_helper(const MatrixType& matrix, MatrixType* result) +template +bool ei_compute_inverse_size4_helper(const MatrixType& matrix, ResultType* result) { /* Let's split M into four 2x2 blocks: * (P Q) @@ -195,47 +195,47 @@ bool ei_compute_inverse_size4_with_check(const XprType& matrix, MatrixType* resu *** Part 2 : selector and MatrixBase methods *** ***********************************************/ -template +template struct ei_compute_inverse { - static inline void run(const MatrixType& matrix, MatrixType* result) + static inline void run(const MatrixType& matrix, ResultType* result) { matrix.partialLu().computeInverse(result); } }; -template -struct ei_compute_inverse +template +struct ei_compute_inverse { - static inline void run(const MatrixType& matrix, MatrixType* result) + static inline void run(const MatrixType& matrix, ResultType* result) { typedef typename MatrixType::Scalar Scalar; result->coeffRef(0,0) = Scalar(1) / matrix.coeff(0,0); } }; -template -struct ei_compute_inverse +template +struct ei_compute_inverse { - static inline void run(const MatrixType& matrix, MatrixType* result) + static inline void run(const MatrixType& matrix, ResultType* result) { ei_compute_inverse_size2(matrix, result); } }; -template -struct ei_compute_inverse +template +struct ei_compute_inverse { - static inline void run(const MatrixType& matrix, MatrixType* result) + static inline void run(const MatrixType& matrix, ResultType* result) { - ei_compute_inverse_size3(matrix, result); + ei_compute_inverse_size3(matrix, result); } }; -template -struct ei_compute_inverse +template +struct ei_compute_inverse { - static inline void run(const MatrixType& matrix, MatrixType* result) + static inline void run(const MatrixType& matrix, ResultType* result) { ei_compute_inverse_size4_with_check(matrix, result); } @@ -256,11 +256,12 @@ struct ei_compute_inverse * \sa inverse(), computeInverseWithCheck() */ template -inline void MatrixBase::computeInverse(PlainMatrixType *result) const +template +inline void MatrixBase::computeInverse(ResultType *result) const { ei_assert(rows() == cols()); EIGEN_STATIC_ASSERT(NumTraits::HasFloatingPoint,NUMERIC_TYPE_MUST_BE_FLOATING_POINT) - ei_compute_inverse::run(eval(), result); + ei_compute_inverse::run(eval(), result); } /** \lu_module @@ -291,10 +292,10 @@ inline const typename MatrixBase::PlainMatrixType MatrixBase:: * Compute inverse with invertibility check * *******************************************/ -template +template struct ei_compute_inverse_with_check { - static inline bool run(const MatrixType& matrix, MatrixType* result) + static inline bool run(const MatrixType& matrix, ResultType* result) { typedef typename MatrixType::Scalar Scalar; LU lu( matrix ); @@ -304,10 +305,10 @@ struct ei_compute_inverse_with_check } }; -template -struct ei_compute_inverse_with_check +template +struct ei_compute_inverse_with_check { - static inline bool run(const MatrixType& matrix, MatrixType* result) + static inline bool run(const MatrixType& matrix, ResultType* result) { typedef typename MatrixType::Scalar Scalar; if( matrix.coeff(0,0) == Scalar(0) ) return false; @@ -316,28 +317,28 @@ struct ei_compute_inverse_with_check } }; -template -struct ei_compute_inverse_with_check +template +struct ei_compute_inverse_with_check { - static inline bool run(const MatrixType& matrix, MatrixType* result) + static inline bool run(const MatrixType& matrix, ResultType* result) { return ei_compute_inverse_size2_with_check(matrix, result); } }; -template -struct ei_compute_inverse_with_check +template +struct ei_compute_inverse_with_check { - static inline bool run(const MatrixType& matrix, MatrixType* result) + static inline bool run(const MatrixType& matrix, ResultType* result) { - return ei_compute_inverse_size3(matrix, result); + return ei_compute_inverse_size3(matrix, result); } }; -template -struct ei_compute_inverse_with_check +template +struct ei_compute_inverse_with_check { - static inline bool run(const MatrixType& matrix, MatrixType* result) + static inline bool run(const MatrixType& matrix, ResultType* result) { return ei_compute_inverse_size4_with_check(matrix, result); } @@ -354,11 +355,12 @@ struct ei_compute_inverse_with_check * \sa inverse(), computeInverse() */ template -inline bool MatrixBase::computeInverseWithCheck(PlainMatrixType *result) const +template +inline bool MatrixBase::computeInverseWithCheck(ResultType *result) const { ei_assert(rows() == cols()); EIGEN_STATIC_ASSERT(NumTraits::HasFloatingPoint,NUMERIC_TYPE_MUST_BE_FLOATING_POINT) - return ei_compute_inverse_with_check::run(eval(), result); + return ei_compute_inverse_with_check::run(eval(), result); } From 9115d33fae9af9899bf3f93949946e625769890f Mon Sep 17 00:00:00 2001 From: Benoit Jacob Date: Tue, 6 Oct 2009 11:44:57 -0400 Subject: [PATCH 79/83] the answer to the ultimate question in life is: 664 --- scripts/eigen_gen_credits | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/eigen_gen_credits b/scripts/eigen_gen_credits index 5a0056387..c67416784 100755 --- a/scripts/eigen_gen_credits +++ b/scripts/eigen_gen_credits @@ -20,4 +20,4 @@ g++ scripts/eigen_gen_credits.cpp -o e ./e > credits.out rsync credits.out $USER@ssh.tuxfamily.org:eigen/eigen.tuxfamily.org-web/htdocs/credits.out || (echo "upload failed"; exit 1) -ssh $USER@ssh.tuxfamily.org "cd eigen/eigen.tuxfamily.org-web/htdocs; chmod 660 credits.out; echo Main_Page | /usr/bin/php maintenance/purgeList.php" +ssh $USER@ssh.tuxfamily.org "cd eigen/eigen.tuxfamily.org-web/htdocs; chmod 664 credits.out; echo Main_Page | /usr/bin/php maintenance/purgeList.php" From 075830ddb0184ff369e95ba0f0f865bb0aaad1c4 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 7 Oct 2009 14:22:44 +0200 Subject: [PATCH 80/83] - remove the debug_test_* targets from "all" (otherwise they are compiled when you simply run make in test/ or when enforcing "test" to be part of "all") - add linking libraries to the debug_test_* targets --- cmake/EigenTesting.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index d043f67b8..8f50b3300 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -45,7 +45,7 @@ macro(ei_add_test testname) set(filename ${testname}.cpp) add_executable(${targetname} ${filename}) add_dependencies(btest ${targetname}) - add_executable(${debug_targetname} ${filename}) + add_executable(${debug_targetname} EXCLUDE_FROM_ALL ${filename}) if(NOT EIGEN_NO_ASSERTION_CHECKING) @@ -92,6 +92,7 @@ macro(ei_add_test testname) string(LENGTH "${ARGV2_stripped}" ARGV2_stripped_length) if(${ARGV2_stripped_length} GREATER 0) target_link_libraries(${targetname} ${ARGV2}) + target_link_libraries(${debug_targetname} ${ARGV2}) endif(${ARGV2_stripped_length} GREATER 0) endif(${ARGC} GREATER 2) From af31345df3707b3b3f33ae0ee2db575683c9d514 Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 7 Oct 2009 14:25:12 +0200 Subject: [PATCH 81/83] really fix stable norm compilation for older gcc --- Eigen/src/Core/StableNorm.h | 8 ++++---- test/stable_norm.cpp | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Eigen/src/Core/StableNorm.h b/Eigen/src/Core/StableNorm.h index b4a5d0bfd..06e69c448 100644 --- a/Eigen/src/Core/StableNorm.h +++ b/Eigen/src/Core/StableNorm.h @@ -109,14 +109,14 @@ MatrixBase::blueNorm() const rbig = std::numeric_limits::max(); // largest floating-point number iexp = -((1-iemin)/2); - b1 = RealScalar(std::pow(ibeta,iexp)); // lower boundary of midrange + b1 = RealScalar(std::pow(RealScalar(ibeta),RealScalar(iexp))); // lower boundary of midrange iexp = (iemax + 1 - it)/2; - b2 = RealScalar(std::pow(ibeta,iexp)); // upper boundary of midrange + b2 = RealScalar(std::pow(RealScalar(ibeta),RealScalar(iexp))); // upper boundary of midrange iexp = (2-iemin)/2; - s1m = RealScalar(std::pow(ibeta,iexp)); // scaling factor for lower range + s1m = RealScalar(std::pow(RealScalar(ibeta),RealScalar(iexp))); // scaling factor for lower range iexp = - ((iemax+it)/2); - s2m = RealScalar(std::pow(ibeta,iexp)); // scaling factor for upper range + s2m = RealScalar(std::pow(RealScalar(ibeta),RealScalar(iexp))); // scaling factor for upper range overfl = rbig*s2m; // overfow boundary for abig eps = RealScalar(std::pow(double(ibeta), 1-it)); diff --git a/test/stable_norm.cpp b/test/stable_norm.cpp index 6ce99477d..ed72bb7a7 100644 --- a/test/stable_norm.cpp +++ b/test/stable_norm.cpp @@ -35,8 +35,7 @@ template void stable_norm(const MatrixType& m) // Check the basic machine-dependent constants. { - int nbig, ibeta, it, iemin, iemax, iexp; - RealScalar abig, eps; + int ibeta, it, iemin, iemax; ibeta = std::numeric_limits::radix; // base for floating-point numbers it = std::numeric_limits::digits; // number of base-beta digits in mantissa From 8f3e33581ecd69eea782d4103985a808ed41dabd Mon Sep 17 00:00:00 2001 From: Gael Guennebaud Date: Wed, 7 Oct 2009 14:25:53 +0200 Subject: [PATCH 82/83] extend the sparse matrix assembly benchmark --- bench/BenchSparseUtil.h | 12 +- bench/sparse_setter.cpp | 320 +++++++++++++++++++++++++++++++--------- 2 files changed, 260 insertions(+), 72 deletions(-) diff --git a/bench/BenchSparseUtil.h b/bench/BenchSparseUtil.h index f4b67cb8d..f8dc8bdf4 100644 --- a/bench/BenchSparseUtil.h +++ b/bench/BenchSparseUtil.h @@ -27,23 +27,23 @@ typedef SparseMatrix EigenSparseMatrix; void fillMatrix(float density, int rows, int cols, EigenSparseMatrix& dst) { - dst.startFill(rows*cols*density); + dst.reserve(rows*cols*density); for(int j = 0; j < cols; j++) { for(int i = 0; i < rows; i++) { Scalar v = (ei_random(0,1) < density) ? ei_random() : 0; if (v!=0) - dst.fillrand(i,j) = v; + dst.insert(i,j) = v; } } - dst.endFill(); + dst.finalize(); } void fillMatrix2(int nnzPerCol, int rows, int cols, EigenSparseMatrix& dst) { std::cout << "alloc " << nnzPerCol*cols << "\n"; - dst.startFill(nnzPerCol*cols); + dst.reserve(nnzPerCol*cols); for(int j = 0; j < cols; j++) { std::set aux; @@ -54,10 +54,10 @@ void fillMatrix2(int nnzPerCol, int rows, int cols, EigenSparseMatrix& dst) k = ei_random(0,rows-1); aux.insert(k); - dst.fillrand(k,j) = ei_random(); + dst.insert(k,j) = ei_random(); } } - dst.endFill(); + dst.finalize(); } void eiToDense(const EigenSparseMatrix& src, DenseMatrix& dst) diff --git a/bench/sparse_setter.cpp b/bench/sparse_setter.cpp index 6f7a19ddf..9c22636d7 100644 --- a/bench/sparse_setter.cpp +++ b/bench/sparse_setter.cpp @@ -12,7 +12,15 @@ #endif #ifndef REPEAT -#define REPEAT 1 +#define REPEAT 2 +#endif + +#ifndef NBTRIES +#define NBTRIES 2 +#endif + +#ifndef KK +#define KK 10 #endif #ifndef NOGOOGLE @@ -22,7 +30,7 @@ #include "BenchSparseUtil.h" -#define CHECK_MEM +#define CHECK_MEM // #define CHECK_MEM std/**/::cout << "check mem\n"; getchar(); #define BENCH(X) \ @@ -37,9 +45,13 @@ typedef std::vector Coordinates; typedef std::vector Values; EIGEN_DONT_INLINE Scalar* setinnerrand_eigen(const Coordinates& coords, const Values& vals); +EIGEN_DONT_INLINE Scalar* setrand_eigen_dynamic(const Coordinates& coords, const Values& vals); +EIGEN_DONT_INLINE Scalar* setrand_eigen_compact(const Coordinates& coords, const Values& vals); +EIGEN_DONT_INLINE Scalar* setrand_eigen_sumeq(const Coordinates& coords, const Values& vals); EIGEN_DONT_INLINE Scalar* setrand_eigen_gnu_hash(const Coordinates& coords, const Values& vals); EIGEN_DONT_INLINE Scalar* setrand_eigen_google_dense(const Coordinates& coords, const Values& vals); EIGEN_DONT_INLINE Scalar* setrand_eigen_google_sparse(const Coordinates& coords, const Values& vals); +EIGEN_DONT_INLINE Scalar* setrand_scipy(const Coordinates& coords, const Values& vals); EIGEN_DONT_INLINE Scalar* setrand_ublas_mapped(const Coordinates& coords, const Values& vals); EIGEN_DONT_INLINE Scalar* setrand_ublas_coord(const Coordinates& coords, const Values& vals); EIGEN_DONT_INLINE Scalar* setrand_ublas_compressed(const Coordinates& coords, const Values& vals); @@ -50,17 +62,36 @@ int main(int argc, char *argv[]) { int rows = SIZE; int cols = SIZE; - bool fullyrand = false; - //float density = float(NBPERROW)/float(SIZE); - + bool fullyrand = true; + BenchTimer timer; Coordinates coords; Values values; if(fullyrand) { - for (int i=0; i(0,rows-1),ei_random(0,cols-1))); +// DynamicSparseMatrix stencil(SIZE,SIZE); + Vector2i ij(ei_random(0,rows-1),ei_random(0,cols-1)); +// if(stencil.coeffRef(ij.x(), ij.y())==0) + { +// stencil.coeffRef(ij.x(), ij.y()) = 1; + pool.push_back(ij); + + } + ++i; + } + std::cerr << "pool ok" << "\n"; + int n = cols*NBPERROW*KK; + coords.reserve(n); + values.reserve(n); + for (int i=0; i(0,pool.size()); + coords.push_back(pool[i]); values.push_back(ei_random()); } } @@ -79,67 +110,55 @@ int main(int argc, char *argv[]) // dense matrices #ifdef DENSEMATRIX { - timer.reset(); - timer.start(); - for (int k=0; k mat(SIZE,SIZE); - mat.startFill(2000000/*coords.size()*/); + //mat.startFill(2000000/*coords.size()*/); for (int i=0; i mat(SIZE,SIZE); + mat.reserve(coords.size()/10); + for (int i=0; i mat(SIZE,SIZE); + for (int j=0; j aux(SIZE,SIZE); + mat.reserve(n); + for (int i=j*n; i<(j+1)*n; ++i) + { + aux.insert(coords[i].x(), coords[i].y()) += vals[i]; + } + aux.finalize(); + mat += aux; + } + return &mat.coeffRef(coords[0].x(), coords[0].y()); +} + +EIGEN_DONT_INLINE Scalar* setrand_eigen_compact(const Coordinates& coords, const Values& vals) +{ + using namespace Eigen; + DynamicSparseMatrix setter(SIZE,SIZE); + setter.reserve(coords.size()/10); + for (int i=0; i mat = setter; + CHECK_MEM; + return &mat.coeffRef(coords[0].x(), coords[0].y()); +} + EIGEN_DONT_INLINE Scalar* setrand_eigen_gnu_hash(const Coordinates& coords, const Values& vals) { using namespace Eigen; @@ -198,11 +260,11 @@ EIGEN_DONT_INLINE Scalar* setrand_eigen_gnu_hash(const Coordinates& coords, cons RandomSetter, StdMapTraits > setter(mat); for (int i=0; i, GoogleDenseHashMapTraits> setter(mat); for (int i=0; i, GoogleSparseHashMapTraits> setter(mat); for (int i=0; i +void coo_tocsr(const int n_row, + const int n_col, + const int nnz, + const Coordinates Aij, + const Values Ax, + int Bp[], + int Bj[], + T Bx[]) +{ + //compute number of non-zero entries per row of A coo_tocsr + std::fill(Bp, Bp + n_row, 0); + + for (int n = 0; n < nnz; n++){ + Bp[Aij[n].x()]++; + } + + //cumsum the nnz per row to get Bp[] + for(int i = 0, cumsum = 0; i < n_row; i++){ + int temp = Bp[i]; + Bp[i] = cumsum; + cumsum += temp; + } + Bp[n_row] = nnz; + + //write Aj,Ax into Bj,Bx + for(int n = 0; n < nnz; n++){ + int row = Aij[n].x(); + int dest = Bp[row]; + + Bj[dest] = Aij[n].y(); + Bx[dest] = Ax[n]; + + Bp[row]++; + } + + for(int i = 0, last = 0; i <= n_row; i++){ + int temp = Bp[i]; + Bp[i] = last; + last = temp; + } + + //now Bp,Bj,Bx form a CSR representation (with possible duplicates) +} + +template< class T1, class T2 > +bool kv_pair_less(const std::pair& x, const std::pair& y){ + return x.first < y.first; +} + + +template +void csr_sort_indices(const I n_row, + const I Ap[], + I Aj[], + T Ax[]) +{ + std::vector< std::pair > temp; + + for(I i = 0; i < n_row; i++){ + I row_start = Ap[i]; + I row_end = Ap[i+1]; + + temp.clear(); + + for(I jj = row_start; jj < row_end; jj++){ + temp.push_back(std::make_pair(Aj[jj],Ax[jj])); + } + + std::sort(temp.begin(),temp.end(),kv_pair_less); + + for(I jj = row_start, n = 0; jj < row_end; jj++, n++){ + Aj[jj] = temp[n].first; + Ax[jj] = temp[n].second; + } + } +} + +template +void csr_sum_duplicates(const I n_row, + const I n_col, + I Ap[], + I Aj[], + T Ax[]) +{ + I nnz = 0; + I row_end = 0; + for(I i = 0; i < n_row; i++){ + I jj = row_end; + row_end = Ap[i+1]; + while( jj < row_end ){ + I j = Aj[jj]; + T x = Ax[jj]; + jj++; + while( jj < row_end && Aj[jj] == j ){ + x += Ax[jj]; + jj++; + } + Aj[nnz] = j; + Ax[nnz] = x; + nnz++; + } + Ap[i+1] = nnz; + } +} + +EIGEN_DONT_INLINE Scalar* setrand_scipy(const Coordinates& coords, const Values& vals) +{ + using namespace Eigen; + SparseMatrix mat(SIZE,SIZE); + mat.resizeNonZeros(coords.size()); +// std::cerr << "setrand_scipy...\n"; + coo_tocsr(SIZE,SIZE, coords.size(), coords, vals, mat._outerIndexPtr(), mat._innerIndexPtr(), mat._valuePtr()); +// std::cerr << "coo_tocsr ok\n"; + + csr_sort_indices(SIZE, mat._outerIndexPtr(), mat._innerIndexPtr(), mat._valuePtr()); + + csr_sum_duplicates(SIZE, SIZE, mat._outerIndexPtr(), mat._innerIndexPtr(), mat._valuePtr()); + + mat.resizeNonZeros(mat._outerIndexPtr()[SIZE]); + + return &mat.coeffRef(coords[0].x(), coords[0].y()); +} + + #ifndef NOUBLAS EIGEN_DONT_INLINE Scalar* setrand_ublas_mapped(const Coordinates& coords, const Values& vals) { @@ -242,7 +430,7 @@ EIGEN_DONT_INLINE Scalar* setrand_ublas_mapped(const Coordinates& coords, const mapped_matrix aux(SIZE,SIZE); for (int i=0; i mat(aux); @@ -278,12 +466,12 @@ EIGEN_DONT_INLINE Scalar* setrand_ublas_genvec(const Coordinates& coords, const using namespace boost; using namespace boost::numeric; using namespace boost::numeric::ublas; - + // ublas::vector > foo; generalized_vector_of_vector > > aux(SIZE,SIZE); for (int i=0; i mat(aux); From e5bf72679c993e302df95aa2947402482aaded71 Mon Sep 17 00:00:00 2001 From: Hauke Heibel Date: Fri, 9 Oct 2009 14:09:25 +0200 Subject: [PATCH 83/83] Fixed nmake parameter. Disabled debug_* targets for MSVC_IDE (they already exist). Removed the make usage message for MSVC_IDE. --- CMakeLists.txt | 2 ++ cmake/EigenTesting.cmake | 32 ++++++++++++++++++++++++-------- test/testsuite.cmake | 2 +- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 36b2be99f..0c068e6f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,7 @@ if(EIGEN_BUILD_BTL) endif(EIGEN_BUILD_BTL) ei_testing_print_summary() +if(NOT MSVC_IDE) message("") message("Configured Eigen ${EIGEN_VERSION_NUMBER}") message("You can now do the following:") @@ -158,3 +159,4 @@ message("make debug_qr | Build a test with full debug info. To run it: test/debu message("make blas | Build BLAS library (not the same thing as Eigen)") message("make doc | Generate the API documentation, requires Doxygen & LaTeX") message("--------------+----------------------------------------------------------------") +endif(NOT MSVC_IDE) diff --git a/cmake/EigenTesting.cmake b/cmake/EigenTesting.cmake index 8f50b3300..b8e159be7 100644 --- a/cmake/EigenTesting.cmake +++ b/cmake/EigenTesting.cmake @@ -40,18 +40,24 @@ endmacro(ei_add_property) macro(ei_add_test testname) set(targetname test_${testname}) - set(debug_targetname debug_${testname}) + if(NOT MSVC_IDE) + set(debug_targetname debug_${testname}) + endif(NOT MSVC_IDE) set(filename ${testname}.cpp) add_executable(${targetname} ${filename}) add_dependencies(btest ${targetname}) - add_executable(${debug_targetname} EXCLUDE_FROM_ALL ${filename}) + if(NOT MSVC_IDE) + add_executable(${debug_targetname} EXCLUDE_FROM_ALL ${filename}) + endif(NOT MSVC_IDE) if(NOT EIGEN_NO_ASSERTION_CHECKING) if(MSVC) set_target_properties(${targetname} PROPERTIES COMPILE_FLAGS "/EHsc") - set_target_properties(${debug_targetname} PROPERTIES COMPILE_FLAGS "/EHsc") + if(NOT MSVC_IDE) + set_target_properties(${debug_targetname} PROPERTIES COMPILE_FLAGS "/EHsc") + endif(NOT MSVC_IDE) else(MSVC) set_target_properties(${targetname} PROPERTIES COMPILE_FLAGS "-fexceptions") set_target_properties(${debug_targetname} PROPERTIES COMPILE_FLAGS "-fexceptions") @@ -60,13 +66,17 @@ macro(ei_add_test testname) option(EIGEN_DEBUG_ASSERTS "Enable debuging of assertions" OFF) if(EIGEN_DEBUG_ASSERTS) ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_DEBUG_ASSERTS=1") - ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-DEIGEN_DEBUG_ASSERTS=1") + if(NOT MSVC_IDE) + ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-DEIGEN_DEBUG_ASSERTS=1") + endif(NOT MSVC_IDE) endif(EIGEN_DEBUG_ASSERTS) else(NOT EIGEN_NO_ASSERTION_CHECKING) ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_NO_ASSERTION_CHECKING=1") - ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-DEIGEN_NO_ASSERTION_CHECKING=1") + if(NOT MSVC_IDE) + ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-DEIGEN_NO_ASSERTION_CHECKING=1") + endif(NOT MSVC_IDE) endif(NOT EIGEN_NO_ASSERTION_CHECKING) @@ -80,11 +90,15 @@ macro(ei_add_test testname) # O0 is in principle redundant here, but doesn't hurt ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-O0 -g3") elseif(MSVC) - ei_add_target_property(${debug_targetname} COMPILE_FLAGS "/Od /Zi") + if(NOT MSVC_IDE) + ei_add_target_property(${debug_targetname} COMPILE_FLAGS "/Od /Zi") + endif(NOT MSVC_IDE) endif(CMAKE_COMPILER_IS_GNUCXX) ei_add_target_property(${targetname} COMPILE_FLAGS "-DEIGEN_TEST_FUNC=${testname}") - ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-DEIGEN_TEST_FUNC=${testname}") + if(NOT MSVC_IDE) + ei_add_target_property(${debug_targetname} COMPILE_FLAGS "-DEIGEN_TEST_FUNC=${testname}") + endif(NOT MSVC_IDE) target_link_libraries(${targetname} ${EXTERNAL_LIBS}) if(${ARGC} GREATER 2) @@ -92,7 +106,9 @@ macro(ei_add_test testname) string(LENGTH "${ARGV2_stripped}" ARGV2_stripped_length) if(${ARGV2_stripped_length} GREATER 0) target_link_libraries(${targetname} ${ARGV2}) - target_link_libraries(${debug_targetname} ${ARGV2}) + if(NOT MSVC_IDE) + target_link_libraries(${debug_targetname} ${ARGV2}) + endif(NOT MSVC_IDE) endif(${ARGV2_stripped_length} GREATER 0) endif(${ARGC} GREATER 2) diff --git a/test/testsuite.cmake b/test/testsuite.cmake index b223345b1..5d0cb6585 100644 --- a/test/testsuite.cmake +++ b/test/testsuite.cmake @@ -175,7 +175,7 @@ if(WIN32 AND NOT UNIX) else(EIGEN_GENERATOR_TYPE) set(CTEST_CMAKE_COMMAND "${CTEST_CMAKE_COMMAND} -G \"NMake Makefiles\" -DCMAKE_MAKE_PROGRAM=nmake") SET (CTEST_INITIAL_CACHE " - MAKECOMMAND:STRING=nmake -i + MAKECOMMAND:STRING=nmake /i CMAKE_MAKE_PROGRAM:FILEPATH=nmake CMAKE_GENERATOR:INTERNAL=NMake Makefiles CMAKE_BUILD_TYPE:STRING=Release