Search code examples
c++eigeneigen3

Using valuePtr() etc to allocate space for Eigen3 SparseMatrix


I am trying to initialize Eigen::SparseMatrix A by using malloc like this

A.valuePtr() = static_cast<T*>(std::malloc(nnz*sizeof(T)));
A.innerIndexPtr() = static_cast<int*>(std::malloc(nnz*sizeof(int)));

but I get the error

error: lvalue required as left operand of assignment

for both statements. In case it matters, the function containing the lines takes a Eigen::SparseMatrix<T, Eigen::RowMajor> by reference.

Can anyone help me with this? I'm using g++ 5.2.

EDIT: The function valuePtr of class SparseMatrix is

inline Scalar* valuePtr() { return &m_data.value(0); }

Scalar is a template paramter. m_data is a protected variable of type CompressedStorage whose method value(size_t i) returns a reference to the ith member of its internal data array.

 inline Scalar& value(size_t i) { return m_values[i]; }

So, I concluded that valuePtr() returns the address of the first element of an array. I should, then, be able to allocate space for that array by malloc.

In case someone is interested, I include a link for reference - please see lines after 84, and 131. Eigen3 SparseMatrix class


Solution

  • The problem is most likely due to you trying to assign a object to a method!

    You lines equate to: A.valuePtr() = Sometype_Pointer;, A.valuePTR() will Call the Eigen::SparseMatrix::valuePTR method(function) of object A.

    If this method returns a pointer (T* A::valuePtr()) then the pointer returned isn't what you want! the method would be returning a rvalue; an rvalue is not a lvalue that isn't the pointer contained in A, rather it's a temporary copy of the pointer.
    You can't assign anything directly to it, just like you can't touch the people on a television screen.

    I'm making a massive assumption that your trying to do what I described above, and that would be impossible unless that method looked like this:

    T ** Eigen::SparseMatrix::valuePTR()
    {
        return &T;
    }
    *A.valuePtr() = static_cast<T*>(std::malloc(nnz*sizeof(T)));
    

    However, note that using malloc is considered very, very out-dated for c++ objects, something like this line would be more correct *A.valuePtr() = static_cast(new T[nnz]));

    [edit/]

    Honestly I'm trying very hard to understand what your code is supposed to accomplish. And most people (including myself) will not be familair with this "Eigen" class. Though I think you may very-much misunderstand how it's supposed to be used.

    Could you possibly provide a link to documentation, or an example of how your creating / using this class?

    [Edit 2/]

    After some research I came across This article as well as This Question, could it be possible you need to use a MappedSparseMatrix

    [edit 3/]

    inline Scalar* valuePtr() { return &m_data.value(0); } will return a rvalue pointer. This isn't the object held in m_data, nor is it the pointer used internally. It's a temporary copy of a pointer to an existing object, trying to say "make this temporary copy point to something else" doesn't make sense.

    inline Scalar& value(size_t i) { return m_values[i]; } In this case, the method returns a reference to an object, a reference is not a pointer - (though the & often confuses people).
    A reference can be understood as the original object, you don't need to dereference a reference. Consider the following.

    int A;
    int * A_p = &A;
    int & A_r = A;
    int & A_r_2 = *A_p;
    
    //de-reference the pointer (to create a reference)
    *A_p = 10;  //A == 10
    //Assign directly to A (via the reference)
    A_r = 12; // A == 12
    //assign directy to A (via the reference to A, that was taken from A_p
    A_r_2 = 15; // A == 15
    //attempt to de-reference a reference
    *A_r = 10; //ERROR, A_r is not a pointer.
    

    In short, The reference being returned isn't a pointer to the object (that already exists), rather it is the object. This would allow you to set the object to something, or call methods on the object using the . operator, however you cannot re-allocate something that already exists, and as such is an error.

    Please consider reading this article on the difference between rvale and lvalue's in C++ understanding rvalue and lvalue