This forum has been archived. All content is frozen. Please use KDE Discuss instead.

Conservative resize of dense matrices?

Tags: None
(comma "," separated)
Seb
Registered Member
Posts
99
Karma
0
Hi,

I have the following usecase:

I have some statistical data. During simulation (or during measuring) this data is generated and must be stored. At the beginning it is not known how many samples I have to store. That is, I would like to use a column-major memory layout and append one column in every step. When using plain C arrays, I would simply increase the memory buffer by 'realloc', which is quite efficient.

With Eigen, however, the 'resize' function will always destroy the stored data, regardless if the data buffer is enlarged or reduced, regardless if the storage order must be changed by the resize or not. In opposite to plain C arrays I have to create a temporary which saves the old data.

Is there any 'efficient' way to handle conservative resizes with Eigen?

Thanks.
Sebastian
Hauke
Registered Member
Posts
109
Karma
3
OS
Hi Seb,

The problem is that AFAIK, there is no portable way of performing an aligned reallocation - thus, when implementing conservativeResize(..), I am allocating a new buffer, copying the components I am interested in and finally destroying the old buffer.

If you want something seriously dirty, you might give this a try (just an example)

Code: Select all
std::vector< Vector2d, aligned_allocator<Vector2d> > data;
data.push_back( Vector2d(1,2) );
data.push_back( Vector2d(3,4) );
data.push_back( Vector2d(5,6) );
data.push_back( Vector2d(7,8) );
// ...

// actually, ColMajor is the default...
Map< Matrix<double, 2, Dynamic, ColMajor>, Aligned > mapped_data(&data[0][0],2,static_cast<int>(data.size()));


This works in theory, since for fixed size types we ensure that sizeof(Vector2d) == 2*sizeof(double).

Did I already mention that it's ugly and dangerous!?

In case somebody has the time to come up with a portable version of aligned reallocation, I will be happy to integrate it into the library.

Regards,
Hauke
User avatar
bjacob
Registered Member
Posts
658
Karma
3
That said, your conservativeResize(), even not optimally efficient, already useful to know the existence of! One can partially compensate for its slowness by calling it not every time. So Seb: in the development branch, use matrix.conservativeResize(rows,cols)

http://eigen.tuxfamily.org/dox-devel/cl ... c6d9e7380c

and instead of calling it everytime, allocate space ahead of time, e.g. 100 new rows at a time...

But, that said, this will never be very efficient. I don't see anything better than what Hauke suggests...


Join us on Eigen's IRC channel: #eigen on irc.freenode.net
Have a serious interest in Eigen? Then join the mailing list!
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
well, for many platforms (all 64bits systems I think), malloc already returns aligned pointer, so using realloc for them should be fine, isn't ?

So I'd still suggest to add a ei_aligned_realloc blabla function, and update conservativeResize to use use it when it detects that's possible.
Seb
Registered Member
Posts
99
Karma
0
Thank you all for your replies.

Gael's suggestion sounds best to me. It implies, however, two conservative resize methods. One which resizes without changing the data ordering (i.e. resizing vectors or appending/deleting columns in matrices) and another method which allows arbitrary resizing (i.e. resizing involving reordering of matrix elements, for example deleting rows in column-major matrices).

To me, the second method is so simple to implement that it is not really a necessity for Eigen (I use this in the meantime in Eigen 2.0), while individually implementing the first method requires detailed knowledge on Eigen's architecture.

Sebastian
Hauke
Registered Member
Posts
109
Karma
3
OS
Seb wrote:Thank you all for your replies.

Gael's suggestion sounds best to me. It implies, however, two conservative resize methods. One which resizes without changing the data ordering (i.e. resizing vectors or appending/deleting columns in matrices) and another method which allows arbitrary resizing (i.e. resizing involving reordering of matrix elements, for example deleting rows in column-major matrices).

To me, the second method is so simple to implement that it is not really a necessity for Eigen (I use this in the meantime in Eigen 2.0), while individually implementing the first method requires detailed knowledge on Eigen's architecture.

Sebastian


Ok, I can use the reallocation methods where they are available - actually no big deal.

I do not think that I will add another function. Resizing means resizing and it does not matter that in some cases this is more expensive than in other cases - function names are not about run-times but about semantics.

I will let you know once that is done...

- Hauke
Hauke
Registered Member
Posts
109
Karma
3
OS
I started looking into it and I have to take back my previous statement that it is "no big deal" ...

Here is how I would start in Memory.h

Code: Select all
inline void ei_aligned_realloc(void *ptr, size_t size)
{
  #if !EIGEN_ALIGN
    realloc(ptr,size);
  #elif EIGEN_MALLOC_ALREADY_ALIGNED
    realloc(ptr,size);
  #elif EIGEN_HAS_POSIX_MEMALIGN
    realloc(ptr,size);
  #elif EIGEN_HAS_MM_MALLOC   
    #if defined(_MSC_VER) && defined(_mm_free)
      _aligned_realloc(ptr,size,16);
    #else
      // what do we do here!?
    #endif
  #elif defined(_MSC_VER)
    _aligned_realloc(ptr,size,16);
  #else
    // and here? puh... i don't really want to write this myself
  #endif
}


You probably do recognize the unimplemented paths. Of course, now I could make a define informing me whether realloc exists or not and then I could go ahead and add specialized paths of the resize methods which will work but is not really clean. So again, in case anybody knows how to fill the gaps, please let me know.

- Hauke
Hauke
Registered Member
Posts
109
Karma
3
OS
Hauke wrote:
Code: Select all
inline void ei_aligned_realloc(void *ptr, size_t size)
{
  // ... snip ...
  #elif EIGEN_HAS_MM_MALLOC   
    #if defined(_MSC_VER) && defined(_mm_free)
      _aligned_realloc(ptr,size,16);
    #else
      // what do we do here!?
    #endif
  // ... snap ...
}


I wrote the ei_handmade_aligned_realloc which was easy - now there is only the reallocation for non-msvc EIGEN_HAS_MM_MALLOC path missing...

User avatar
bjacob
Registered Member
Posts
658
Karma
3
As I replied on the list, you don't necessarily have to write a function with this exact API, you can instead let your function take the old size as a parameter, if that helps...


Join us on Eigen's IRC channel: #eigen on irc.freenode.net
Have a serious interest in Eigen? Then join the mailing list!
Hauke
Registered Member
Posts
109
Karma
3
OS
It's implemented in the default branch. The function .conservativeResize(...) is using realloc based resizing in the following cases:

- for all vector types
- for adding rows to row-major matrices
- for adding cols to col-major matrices

In all other cases, a full reallocation will always happen and the content will be copied. In case vectors and matrices grow the new memory is uninitalized. In case you want to set the new memory to some particular value the method .conservativeResizeLike(...) allows you to do exactly that

Code: Select all
MatrixXd m = MatrixXd::Random(25,25);
m.conservativeResizeLike(MatrixXd::Zeros(50,50));


this will add 25 rows and columns and will fill the new memory with zeros.

I hope that's all you need.

Cheers,
Hauke
Seb
Registered Member
Posts
99
Karma
0
That sounds wonderful, Hauke!

One more reason to look forward for 3.0!


Bookmarks



Who is online

Registered users: abc72656, Bing [Bot], daret, Google [Bot], Sogou [Bot], Yahoo [Bot]