- Added problem size constructor to decompositions that did not have one. It preallocates member data structures.

- Updated unit tests to check above constructor.
- In the compute() method of decompositions: Made temporary matrices/vectors class members to avoid heap allocations during compute() (when dynamic matrices are used, of course).

These  changes can speed up decomposition computation time when a solver instance is used to solve multiple same-sized problems. An added benefit is that the compute() method can now be invoked in contexts were heap allocations are forbidden, such as in real-time control loops.

CAVEAT: Not all of the decompositions in the Eigenvalues module have a heap-allocation-free compute() method. A future patch may address this issue, but some required API changes need to be incorporated first.
This commit is contained in:
Adolfo Rodriguez Tsouroukdissian
2010-04-21 17:15:57 +02:00
parent faf8f7732d
commit 28dde19e40
29 changed files with 396 additions and 121 deletions

View File

@@ -81,6 +81,14 @@ template<typename _MatrixType> class FullPivLU
*/
FullPivLU();
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \a size.
* \sa FullPivLU()
*/
FullPivLU(int rows, int cols);
/** Constructor.
*
* \param matrix the matrix of which to compute the LU decomposition.
@@ -377,6 +385,8 @@ template<typename _MatrixType> class FullPivLU
MatrixType m_lu;
PermutationPType m_p;
PermutationQType m_q;
IntColVectorType m_rowsTranspositions;
IntRowVectorType m_colsTranspositions;
int m_det_pq, m_nonzero_pivots;
RealScalar m_maxpivot, m_prescribedThreshold;
bool m_isInitialized, m_usePrescribedThreshold;
@@ -388,9 +398,27 @@ FullPivLU<MatrixType>::FullPivLU()
{
}
template<typename MatrixType>
FullPivLU<MatrixType>::FullPivLU(int rows, int cols)
: m_lu(rows, cols),
m_p(rows),
m_q(cols),
m_rowsTranspositions(rows),
m_colsTranspositions(cols),
m_isInitialized(false),
m_usePrescribedThreshold(false)
{
}
template<typename MatrixType>
FullPivLU<MatrixType>::FullPivLU(const MatrixType& matrix)
: m_isInitialized(false), m_usePrescribedThreshold(false)
: m_lu(matrix.rows(), matrix.cols()),
m_p(matrix.rows()),
m_q(matrix.cols()),
m_rowsTranspositions(matrix.rows()),
m_colsTranspositions(matrix.cols()),
m_isInitialized(false),
m_usePrescribedThreshold(false)
{
compute(matrix);
}
@@ -407,9 +435,9 @@ FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
// will store the transpositions, before we accumulate them at the end.
// can't accumulate on-the-fly because that will be done in reverse order for the rows.
IntColVectorType rows_transpositions(matrix.rows());
IntRowVectorType cols_transpositions(matrix.cols());
int number_of_transpositions = 0; // number of NONTRIVIAL transpositions, i.e. rows_transpositions[i]!=i
m_rowsTranspositions.resize(matrix.rows());
m_colsTranspositions.resize(matrix.cols());
int number_of_transpositions = 0; // number of NONTRIVIAL transpositions, i.e. m_rowsTranspositions[i]!=i
m_nonzero_pivots = size; // the generic case is that in which all pivots are nonzero (invertible case)
m_maxpivot = RealScalar(0);
@@ -442,8 +470,8 @@ FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
m_nonzero_pivots = k;
for(int i = k; i < size; ++i)
{
rows_transpositions.coeffRef(i) = i;
cols_transpositions.coeffRef(i) = i;
m_rowsTranspositions.coeffRef(i) = i;
m_colsTranspositions.coeffRef(i) = i;
}
break;
}
@@ -453,8 +481,8 @@ FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
// Now that we've found the pivot, we need to apply the row/col swaps to
// bring it to the location (k,k).
rows_transpositions.coeffRef(k) = row_of_biggest_in_corner;
cols_transpositions.coeffRef(k) = col_of_biggest_in_corner;
m_rowsTranspositions.coeffRef(k) = row_of_biggest_in_corner;
m_colsTranspositions.coeffRef(k) = col_of_biggest_in_corner;
if(k != row_of_biggest_in_corner) {
m_lu.row(k).swap(m_lu.row(row_of_biggest_in_corner));
++number_of_transpositions;
@@ -478,11 +506,11 @@ FullPivLU<MatrixType>& FullPivLU<MatrixType>::compute(const MatrixType& matrix)
m_p.setIdentity(rows);
for(int k = size-1; k >= 0; --k)
m_p.applyTranspositionOnTheRight(k, rows_transpositions.coeff(k));
m_p.applyTranspositionOnTheRight(k, m_rowsTranspositions.coeff(k));
m_q.setIdentity(cols);
for(int k = 0; k < size; ++k)
m_q.applyTranspositionOnTheRight(k, cols_transpositions.coeff(k));
m_q.applyTranspositionOnTheRight(k, m_colsTranspositions.coeff(k));
m_det_pq = (number_of_transpositions%2) ? -1 : 1;
return *this;

View File

@@ -83,6 +83,14 @@ template<typename _MatrixType> class PartialPivLU
*/
PartialPivLU();
/** \brief Default Constructor with memory preallocation
*
* Like the default constructor but with preallocation of the internal data
* according to the specified problem \a size.
* \sa PartialPivLU()
*/
PartialPivLU(int size);
/** Constructor.
*
* \param matrix the matrix of which to compute the LU decomposition.
@@ -176,6 +184,7 @@ template<typename _MatrixType> class PartialPivLU
protected:
MatrixType m_lu;
PermutationType m_p;
PermutationVectorType m_rowsTranspositions;
int m_det_p;
bool m_isInitialized;
};
@@ -184,6 +193,17 @@ template<typename MatrixType>
PartialPivLU<MatrixType>::PartialPivLU()
: m_lu(),
m_p(),
m_rowsTranspositions(),
m_det_p(0),
m_isInitialized(false)
{
}
template<typename MatrixType>
PartialPivLU<MatrixType>::PartialPivLU(int size)
: m_lu(size, size),
m_p(size),
m_rowsTranspositions(size),
m_det_p(0),
m_isInitialized(false)
{
@@ -191,8 +211,9 @@ PartialPivLU<MatrixType>::PartialPivLU()
template<typename MatrixType>
PartialPivLU<MatrixType>::PartialPivLU(const MatrixType& matrix)
: m_lu(),
m_p(),
: m_lu(matrix.rows(), matrix.rows()),
m_p(matrix.rows()),
m_rowsTranspositions(matrix.rows()),
m_det_p(0),
m_isInitialized(false)
{
@@ -384,15 +405,15 @@ PartialPivLU<MatrixType>& PartialPivLU<MatrixType>::compute(const MatrixType& ma
ei_assert(matrix.rows() == matrix.cols() && "PartialPivLU is only for square (and moreover invertible) matrices");
const int size = matrix.rows();
PermutationVectorType rows_transpositions(size);
m_rowsTranspositions.resize(size);
int nb_transpositions;
ei_partial_lu_inplace(m_lu, rows_transpositions, nb_transpositions);
ei_partial_lu_inplace(m_lu, m_rowsTranspositions, nb_transpositions);
m_det_p = (nb_transpositions%2) ? -1 : 1;
m_p.setIdentity(size);
for(int k = size-1; k >= 0; --k)
m_p.applyTranspositionOnTheRight(k, rows_transpositions.coeff(k));
m_p.applyTranspositionOnTheRight(k, m_rowsTranspositions.coeff(k));
m_isInitialized = true;
return *this;