fix realloc when initial size was 0 (bug reported by Jens Mueller)

This commit is contained in:
Gael Guennebaud 2009-05-07 13:13:42 +00:00
parent 4f0af00e51
commit 6dffdca123

View File

@ -138,7 +138,7 @@ class SparseMatrix
setZero(); setZero();
m_data.reserve(reserveSize); m_data.reserve(reserveSize);
} }
/** Preallocates \a reserveSize non zeros */ /** Preallocates \a reserveSize non zeros */
inline void reserve(int reserveSize) inline void reserve(int reserveSize)
{ {
@ -175,9 +175,9 @@ class SparseMatrix
m_data.append(0, inner); m_data.append(0, inner);
return m_data.value(id); return m_data.value(id);
} }
//--- low level purely coherent filling --- //--- low level purely coherent filling ---
inline Scalar& insertBack(int outer, int inner) inline Scalar& insertBack(int outer, int inner)
{ {
ei_assert(size_t(m_outerIndex[outer+1]) == m_data.size() && "wrong sorted insertion"); ei_assert(size_t(m_outerIndex[outer+1]) == m_data.size() && "wrong sorted insertion");
@ -187,14 +187,14 @@ class SparseMatrix
m_data.append(0, inner); m_data.append(0, inner);
return m_data.value(id); return m_data.value(id);
} }
inline void startVec(int outer) inline void startVec(int outer)
{ {
ei_assert(m_outerIndex[outer]==int(m_data.size()) && "you must call startVec on each inner vec"); ei_assert(m_outerIndex[outer]==int(m_data.size()) && "you must call startVec on each inner vec");
ei_assert(m_outerIndex[outer+1]==0 && "you must call startVec on each inner vec"); ei_assert(m_outerIndex[outer+1]==0 && "you must call startVec on each inner vec");
m_outerIndex[outer+1] = m_outerIndex[outer]; m_outerIndex[outer+1] = m_outerIndex[outer];
} }
//--- //---
/** \deprecated use insert() /** \deprecated use insert()
@ -204,20 +204,20 @@ class SparseMatrix
{ {
return insert(row,col); return insert(row,col);
} }
/** \returns a reference to a novel non zero coefficient with coordinates \a row x \a col. /** \returns a reference to a novel non zero coefficient with coordinates \a row x \a col.
* The non zero coefficient must \b not already exist. * The non zero coefficient must \b not already exist.
* *
* \warning This function can be extremely slow if the non zero coefficients * \warning This function can be extremely slow if the non zero coefficients
* are not inserted in a coherent order. * are not inserted in a coherent order.
* *
* After an insertion session, you should call the finalize() function. * After an insertion session, you should call the finalize() function.
*/ */
EIGEN_DONT_INLINE Scalar& insert(int row, int col) EIGEN_DONT_INLINE Scalar& insert(int row, int col)
{ {
const int outer = IsRowMajor ? row : col; const int outer = IsRowMajor ? row : col;
const int inner = IsRowMajor ? col : row; const int inner = IsRowMajor ? col : row;
int previousOuter = outer; int previousOuter = outer;
if (m_outerIndex[outer+1]==0) if (m_outerIndex[outer+1]==0)
{ {
@ -229,13 +229,13 @@ class SparseMatrix
} }
m_outerIndex[outer+1] = m_outerIndex[outer]; m_outerIndex[outer+1] = m_outerIndex[outer];
} }
// here we have to handle the tricky case where the outerIndex array // here we have to handle the tricky case where the outerIndex array
// starts with: [ 0 0 0 0 0 1 ...] and we are inserting in, e.g., // starts with: [ 0 0 0 0 0 1 ...] and we are inserting in, e.g.,
// the 2nd inner vector... // the 2nd inner vector...
bool isLastVec = (!(previousOuter==-1 && m_data.size()!=0)) bool isLastVec = (!(previousOuter==-1 && m_data.size()!=0))
&& (size_t(m_outerIndex[outer+1]) == m_data.size()); && (size_t(m_outerIndex[outer+1]) == m_data.size());
size_t startId = m_outerIndex[outer]; size_t startId = m_outerIndex[outer];
// FIXME let's make sure sizeof(long int) == sizeof(size_t) // FIXME let's make sure sizeof(long int) == sizeof(size_t)
size_t id = m_outerIndex[outer+1]; size_t id = m_outerIndex[outer+1];
@ -244,18 +244,26 @@ class SparseMatrix
float reallocRatio = 1; float reallocRatio = 1;
if (m_data.allocatedSize()<=m_data.size()) if (m_data.allocatedSize()<=m_data.size())
{ {
// we need to reallocate the data, to reduce multiple reallocations // if there is no preallocated memory, let's reserve a minimum of 32 elements
// we use a smart resize algorithm based on the current filling ratio if (m_data.size()==0)
// in addition, we use float to avoid integers overflows {
float nnzEstimate = float(m_outerIndex[outer])*float(m_outerSize)/float(outer+1); m_data.reserve(32);
reallocRatio = (nnzEstimate-float(m_data.size()))/float(m_data.size()); }
// furthermore we bound the realloc ratio to: else
// 1) reduce multiple minor realloc when the matrix is almost filled {
// 2) avoid to allocate too much memory when the matrix is almost empty // we need to reallocate the data, to reduce multiple reallocations
reallocRatio = std::min(std::max(reallocRatio,1.5f),8.f); // we use a smart resize algorithm based on the current filling ratio
// in addition, we use float to avoid integers overflows
float nnzEstimate = float(m_outerIndex[outer])*float(m_outerSize)/float(outer+1);
reallocRatio = (nnzEstimate-float(m_data.size()))/float(m_data.size());
// furthermore we bound the realloc ratio to:
// 1) reduce multiple minor realloc when the matrix is almost filled
// 2) avoid to allocate too much memory when the matrix is almost empty
reallocRatio = std::min(std::max(reallocRatio,1.5f),8.f);
}
} }
m_data.resize(m_data.size()+1,reallocRatio); m_data.resize(m_data.size()+1,reallocRatio);
if (!isLastVec) if (!isLastVec)
{ {
if (previousOuter==-1) if (previousOuter==-1)
@ -310,7 +318,7 @@ class SparseMatrix
} }
EIGEN_DEPRECATED void endFill() { finalize(); } EIGEN_DEPRECATED void endFill() { finalize(); }
/** Must be called after inserting a set of non zero entries. /** Must be called after inserting a set of non zero entries.
*/ */
inline void finalize() inline void finalize()