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

Is Map enough?

Tags: None
(comma "," separated)
martinakos
Registered Member
Posts
53
Karma
0
OS

Is Map enough?

Fri Apr 15, 2011 4:00 pm
Hi there,

I'm still working on replacing our house matrix types with Eigen.
There is one thing I don't know how to do with Eigen yet.

The library I'm refactoring has a double purpose: to be used in standalone applications, and to speedup some Matlab functions.

In this library I have some classes with, for example, a data member of type MatrixXd. When this class is used in the standalone application the MatrixXd data member works fine. On the other hand, when this class is used to speedup Matlab I would like this data member to map to the Matlab matrixes (which could be quite big) memory to be more efficient.

In principle, I should be able to do this using Eigen::Map. I attempted to make the data member of my class in question a Map<MatrixXd> , instead of a MatrixXd, then the idea was to initialise it to the Matlab memory when the class is used for speeding up Matlab, and initialise it to a MatrixXd when the class is used as standalone application. This doesn't work though because Map doesn't have a default constructor, then I don't have a function to reset that Map class member to a new memory anyway.

As a solution, I have been able to wrap the Map<MatrixXd> in a boost::shared_ptr. Example code:

class MatrixUser
{
public:

void setRealData(MatrixXd &m)
{
m_RealData.reset(new Map<MatrixXd>(m.data(), m.rows(), m.cols()));
}

void setRealData(Map<MatrixXd> &m)
{
m_RealData.reset(new Map<MatrixXd>(m.data(), m.rows(), m.cols()));
}

private:
boost::shared_ptr<Map<MatrixXd>> m_RealData;
};

The function expecting a Map<MatrixXd>& is for the Matlab speedup case, where I would pass a Map<MatrixXd> to a Matlab matrix. The function expecting a MatrixXd& is for the standalone application case, where I would pass a MatrixXd loaded from a file, for example.

However, there are two things I don't like in this solution.
First, I don't like to have to have two setRealData functions.
I have tried a single function like:

template<typename T>
void setRealData(MatrixBase<T> &m)
{
m_RealData.reset(new Map<MatrixXr>(m.data(), m.rows(), m.cols()));
}

but this doesn't compile because MatrixBase doesn't have a data() member and polyphormism doesn't seem to work.

The other thing I don't like in this solution is to have the class data member as a shared_ptr to a Map. I think I would prefer a shared_ptr to MatrixBase and then reset the pointer with a heap allocated MatrixXd or Map. But this doesn't compile for various reasons.

Our old house matrixes types allowed to be initialised either from external memory or from copied data, so I could have a class with a HouseMatrix as data member and then use this class for standalone application or matlab speedup efficiently. I want to do the same with Eigen.

Do you have any suggestion about how could a deal with this problem in the most elegant way?

Thanks very much
Martin.
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS

Re: Is Map enough?

Mon Apr 18, 2011 9:01 am
Hi,

perhaps one possibility would be to always declare a Map<MatrixXd> member, and in the case you don't map external memory, you could allocate/delete yourself the mapped memory in your class.

To dynamically change the mapped pointer you can use the placement new syntax:

Code: Select all
new (&m_map) Map<MatrixXd>(new_ptr);


as explained in the doc:

http://eigen.tuxfamily.org/dox-devel/cl ... _1Map.html
martinakos
Registered Member
Posts
53
Karma
0
OS

Re: Is Map enough?

Mon Apr 18, 2011 2:59 pm
Hi ggael,

Thanks for your suggestion. I think I got something closer to the behabiour I wanted but not quite yet.
I have the following code:

class MatrixUser
{
public:
MatrixUser():m_RealData(0,0,0)
{}

void setRealData(MatrixXd &m) //I want a copy of the data
{
new (&m_RealData) MatrixXd(m);
}

void setRealData(Map<MatrixXd> &m) //I'm mapping external memory
{
new (&m_RealData) Map<MatrixXr>(m.derived().data(), m.rows(), m.cols());
}

void printRealData()
{
cout << m_RealData << endl;
}

private:
Map<MatrixXd> m_RealData;
};

void main()
{
MatrixXd m1 = MatrixXr::Random(10,10);
MatrixXd m2 = MatrixXr::Random(10,10); //This would be the equivalent of some matlab matrix
Map<MatrixXd> m2map(m2.data(), m2.rows(), m2.cols());
MatrixUser mu;
mu.setRealData(m1);
mu.printRealData();
mu.setRealData(m2map);
mu.printRealData();
}

The first time I call setRealData with a MatrixXd there is a new allocation and copy constructor.
The second time I call setRealData I just allocate a Map to the Map passed as argument.
The printRealData calls print the correct data, but I see that in the second setRealData call the memory
mapped by m_RealData is not deallocated, so I have a memory leak. How can I call the MatrixXd destructor or dealocate this memory?
I have tried to do m_RealData.resize(0,0) to free memory just before the placement new but
resize only works with Matrix or Array, so I have runtime error.

I always use smart pointers, I wonder if I could use the placement new with smart pointers?

Another thing that puzzels me a bit is that if in the above code I make m_RealData to be a MatrixXd (and remove the Map initialization
in the MatrixUser contructor), the code seems to work exactly the same (including the memory leak).
I would prefer my data member to be MatrixXd rather than a Map<MatrixXd> but I don't fully understand how the line
new (&m_RealData) Map<MatrixXr>(m.derived().data(), m.rows(), m.cols());
can work with m_RealData being a MatrixXd?

Thanks,
Martin.
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS

Re: Is Map enough?

Tue Apr 19, 2011 11:53 am
I think your code is plain wrong because Map can only reference external memory. Here is a variant that should work:

Code: Select all
class MatrixUser
{
public:
MatrixUser():m_RealData(0,0,0)
{}

void setRealData(MatrixXd &m) //I want a copy of the data
{
m_internalData = m;
new (&m_RealData) (m.data(), m.rows(), m.cols());
}

void setRealData(Map<MatrixXd> &m) //I'm mapping external memory
{
new (&m_RealData) Map<MatrixXd>(m.derived().data(), m.rows(), m.cols());
// optionally call m_internalData.resize(0,0); to free internal memory though it will automatically freed in MatrixUser destructor
}

void setRealData(double* data, int rows, int cols) //I'm mapping external memory
{
new (&m_RealData) Map<MatrixXd>(data, rows, cols);
// optionally call m_internalData.resize(0,0); to free internal memory though it will automatically freed in MatrixUser destructor
}

void printRealData()
{
cout << m_RealData << endl;
}

private:
Map<MatrixXd> m_RealData;
MatrixXd m_internalData;
};
martinakos
Registered Member
Posts
53
Karma
0
OS

Re: Is Map enough?

Wed Apr 20, 2011 1:55 pm
Hi ggael,
Thanks for the correction. I see how it works now.

I guess that I could encapsulate this functionality in a class that contains both the m_RealData and the m_internalData, then I could tell the constructor of this new class whether the object owns the data memory or not, if not then pass a pointer to some external memory. Then have this new class as data member in the MatrixUser instead of having a MatrixXd or Map<MatrixXd>.

I wonder if I could implement this same functionality directly in MatrixBase through the plugin system, so that, for example, my MatrixXd could accept a pointer to external (not owned) memory. Would that be difficult? Would that interfere with optimizations?

Thanks
Martin.
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS

Re: Is Map enough?

Wed Apr 20, 2011 9:17 pm
doing so by extending Matrix via MATRIX_PLUGIN is not possible mainly because you would have to remember whether you have external or your own memory buffer, and adapt the behavior of the destructor, of resize and the like to it.
martinakos
Registered Member
Posts
53
Karma
0
OS

Re: Is Map enough?

Wed Apr 20, 2011 10:59 pm
Alright, thanks very much.
Martin


Bookmarks



Who is online

Registered users: bartoloni, Bing [Bot], Evergrowing, Google [Bot], q.ignora