Search code examples
c++eigen

Function that takes VectorXf and can modify its values


I am trying to understand how to manipulate Eigen Vector/Matrix. I would like to implement a least-square gauss-newton algorithm (hence why I am learning to use the Eigen library). I have a 1x6 vectors of parameters that I need to update each iteration. Right now, I just want to figure out how a function can take a vector as argument and change its values...

Eigen::VectorXf betas = Eigen::VectorXf::Zero(6);

void SomeFunc(const Eigen::VectorXf& v){  // as per the Eigen guide, one must pass as const
    v(0) = 5;  // error: expression must be a modifiable lvalue
    return;
}

int main()
{
    betas(5) = 5.f;  // works
    SomeFunc(&betas);
    std::cout << "Hello World" << std::endl;
    std::cout << betas(0) << "\t" << betas(5) << std::endl;
}

My question is: How would you make a function take a vector and modify its values?

Edit: Eigen guide


Solution

  • I believe the purpose of that section of the documentation is to make you aware of the potential pitfalls that come from the various temporary objects that Eigen creates as it goes through various operations. You can write functions that take writable references such as foo(Eigen::VectorXf &vector) and it will work. One problem that can occur with this is if you pass a slice of a matrix into the function thinking it is vector linked back the parent matrix. What you actually pass into the function is a temporary vector that will be destroyed. If you are 100% certain of what you are passing you can use references directly. Otherwise there are safer things to do as suggested by the documentation. Here are 3 versions of the same function.

    You can see this stackoverflow question for a discussion of the correct usage of the Eigen::Ref class.

    #include <iostream>
    #include <Eigen/Dense>
    
    void SomeFunc(Eigen::Ref<Eigen::VectorXf> v);
    void SomeFunc2(Eigen::VectorXf &v);
    void SomeFunc3(const Eigen::VectorXf &v);
    
    int main(int argc, char * argv[]) {
    
        Eigen::VectorXf betas = Eigen::VectorXf::Zero(6);
        
        std::cout << "Original\n";
        std::cout << betas << '\n';
        
        SomeFunc(betas);
    
        std::cout << "SomeFunc\n";
        std::cout << betas << '\n';
    
        betas.setZero();
        SomeFunc2(betas);
    
        std::cout << "SomeFunc2\n";
        std::cout << betas << '\n';
    
        betas.setZero();
        SomeFunc3(betas);
    
        std::cout << "SomeFunc3\n";
        std::cout << betas << '\n';
    
        return 0;
    }
    
    void SomeFunc(Eigen::Ref<Eigen::VectorXf> v) {
        v(0) = 5;
    }
    
    void SomeFunc2(Eigen::VectorXf &v) {
        v(2) = 5;
    }
    void SomeFunc3(const Eigen::VectorXf &v) {
        const_cast<Eigen::VectorXf&>(v)(4) = 5;
    }
    

    To quote from the linked question above:

    So in summary, we could recommend Ref for a writable reference, and const Ref& for a const reference.