Fix sparse insert
Reference issue
What does this implement/fix?
The sparse product test revealed a subtle unintended behavior. First, I thought the issue was limited to StorageIndex overflowing, which is always a potential issue. However, the actual issue is that uncompressed matrices may have unused capacity in a) the buffer to the right of data().size() and b) the inactive nonzeros to the left of data().size(). Previously, I was only checking for a). Now, I also check for b) by searching to the left as well. This simplifies the reserve strategy, as now insert exhausts all options before reserving nonzeros.
Added check for fast push back to coeffRef and insert, which helps in certain access patterns.
makeCompressed() now attempts to make fewer, larger copies of contiguous data, though I haven't been able to design a test that demonstrates any difference in performance.
I also addressed a very irritating issue where every empty sparse matrix held allocated memory for the outer indices (which is completely worthless and has to be reallocated for any resize).
SparseMatrix<float> A; // constructor calls resize(0,0), which allocates memory for m_outerIndex (m_outerSize + 1 == 1)
A.resize(1,1); // must reallocate the memory at m_outerIndex
Diagonal assignment with coeffRef (mostly to prove there was no regression for push-to-back access pattern)
int diagSize = 500'000'000;
SparseMatrix<double> A(diagSize, diagSize);
for (int j = 0; j < diagSize; j++)
A.coeffRef(j, j) = j;
Before: 5797 ms After: 4948 ms
Random insertion with coeffRef:
int size = 50'000;
SparseMatrix<double> A(size, size);
for (int nz = 0; nz < size ; nz++)
{
int i = internal::random(0, size - 1);
int j = internal::random(0, size - 1);
A.coeffRef(i, j) = i*j;
}
Before: 2056 ms After: 25 ms
insert/coeffRef now appears to scale well with the size of the matrix.
int size = 500'000;
Before: 244,838 ms After: 488 ms
Random insertion into a denser matrix using coeffRef:
int size = 10'000;
SparseMatrix<double> A(size, size);
for (int nz = 0; nz < size ; nz++)
{
for (int nz2 = 0; nz2 < size/100; nz2++)
{
int i = internal::random(0, size - 1);
int j = internal::random(0, size - 1);
A.coeffRef(i, j) = i*j;
}
}
Before: 21,239 ms After: 1764 ms