pboyer / LilOpt

Non-linear least squares in C++, header-only, inspired by Ceres solver.
MIT License
29 stars 8 forks source link

usage question #1

Closed avnerbarr closed 11 years ago

avnerbarr commented 11 years ago

First, thanks for sharing your library and I hope this is the correct place to post questions. I was able to compile and tried your demo. It is working. Now I'm trying to solve for my own problems :) : I'm trying to minimize a graph mesh of the form

E(q1,....qn) = sigma(eij) of alpha(ij) (||qi - qj || ^2 - dij ^2) ^2

where q1... qn are vertexes (in 2d - qi = (xi.yi)) and alphas/d's are emperical values and the e's are the edges between the q's

I don't understand how to use your library and would really appreciate a quick reference.

Thanks for your time.

pboyer commented 11 years ago

Hi avnerbarr,

Thanks for using LilOpt!

I'd highly recommend taking a look at CircleTest.h. It is a self-contained example of how to use the library. In this case, given a set of input points (in 2d) we try to fit a circle to it. We define an error function (called CircleFunction) that returns the squared distances (i.e. residuals) from the given point set to the circle at a given parameter set.

The test() function should give you a complete example of setting up the functor and minimizing it.

Take a look at this first and let me know if you have any other questions.

~Peter

avnerbarr commented 11 years ago

Thanks for the quick reply.

Just want to clarify before I proceed: I need to inherit from LilOpt::IErrorFunction implement a function Evaluate use a diff function LilOpt::ErrorFunctionNumericDiff and then instantiate a LilOpt::Solver:: with those as params?

Thanks

On Oct 28, 2012, at 7:53 PM, pboyer notifications@github.com wrote:

Hi avnerbarr,

Thanks for using LilOpt!

I'd highly recommend taking a look at CircleTest.h. It is a self-contained example of how to use the library. In this case, given a set of input points (in 2d) we try to fit a circle to it. We define an error function (called CircleFunction) that returns the squared distances (i.e. residuals) from the given point set to the circle at a given parameter set.

The test() function should give you a complete example of setting up the functor and minimizing it.

Take a look at this first and let me know if you have any other questions.

~Peter

— Reply to this email directly or view it on GitHub.

pboyer commented 11 years ago

Yes, that should be sufficient.

I should say, however, that I've only yet tested the library on functors with relatively small number of parameters. The problem that you described seems like it could have a quite a high number of parameters. Keep in mind that you'll have to solve an nxn linear system on every iteration. I've yet to implement sparse solvers or matrices as part of this library.

Let me know if you have any more questions.

~Peter

On Sun, Oct 28, 2012 at 2:03 PM, avnerbarr notifications@github.com wrote:

Thanks for the quick reply.

Just want to clarify before I proceed: I need to inherit from LilOpt::IErrorFunction implement a function Evaluate use a diff function LilOpt::ErrorFunctionNumericDiff and then instantiate a LilOpt::Solver:: with those as params?

Thanks

On Oct 28, 2012, at 7:53 PM, pboyer notifications@github.com wrote:

Hi avnerbarr,

Thanks for using LilOpt!

I'd highly recommend taking a look at CircleTest.h. It is a self-contained example of how to use the library. In this case, given a set of input points (in 2d) we try to fit a circle to it. We define an error function (called CircleFunction) that returns the squared distances (i.e. residuals) from the given point set to the circle at a given parameter set.

The test() function should give you a complete example of setting up the functor and minimizing it.

Take a look at this first and let me know if you have any other questions.

~Peter

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHubhttps://github.com/pboyer/LilOpt/issues/1#issuecomment-9848384.

avnerbarr commented 11 years ago

Ok I'll try that.

Can you clarify in the evaluate function - what should i model in there? . I'm not clear on what the params are (is this a vector the result for fi on that iteration? Not to clear from the example)

virtual bool Evaluate( const Matrix<_Scalar, _NumResiduals, 2>& points, const Matrix<_Scalar, 3, 1>& parms, Matrix<_Scalar, _NumResiduals, 1>& residuals ) const

On Oct 28, 2012, at 8:37 PM, pboyer notifications@github.com wrote:

Yes, that should be sufficient.

I should say, however, that I've only yet tested the library on functors with relatively small number of parameters. The problem that you described seems like it could have a quite a high number of parameters. Keep in mind that you'll have to solve an nxn linear system on every iteration. I've yet to implement sparse solvers or matrices as part of this library.

Let me know if you have any more questions.

~Peter

On Sun, Oct 28, 2012 at 2:03 PM, avnerbarr notifications@github.com wrote:

Thanks for the quick reply.

Just want to clarify before I proceed: I need to inherit from LilOpt::IErrorFunction implement a function Evaluate use a diff function LilOpt::ErrorFunctionNumericDiff and then instantiate a LilOpt::Solver:: with those as params?

Thanks

On Oct 28, 2012, at 7:53 PM, pboyer notifications@github.com wrote:

Hi avnerbarr,

Thanks for using LilOpt!

I'd highly recommend taking a look at CircleTest.h. It is a self-contained example of how to use the library. In this case, given a set of input points (in 2d) we try to fit a circle to it. We define an error function (called CircleFunction) that returns the squared distances (i.e. residuals) from the given point set to the circle at a given parameter set.

The test() function should give you a complete example of setting up the functor and minimizing it.

Take a look at this first and let me know if you have any other questions.

~Peter

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHubhttps://github.com/pboyer/LilOpt/issues/1#issuecomment-9848384.

— Reply to this email directly or view it on GitHub.

pboyer commented 11 years ago

An evaluate function in the LilOpt library asks, in essence, "How far is the function with the following parameters from the sampled points?" The evaluate function returns a bool determining whether the function evaluation was successful (typically it returns true). It stores the residuals in the residuals vector, which is passed by reference.

I'll go parameter by parameter to clarify:

virtual bool Evaluate( const Matrix<_Scalar, _NumResiduals, 2>& points, const Matrix<_Scalar, 3, 1>& parms, Matrix<_Scalar, _NumResiduals, 1>& residuals ) const

Note the function is const as it does not affect the state of the functor object, which is stateless.

_const Matrix<_Scalar, NumResiduals, 2>& points

These are the sampled points in 2D passed as a matrix of doubles with size _NumResiduals x 2. That is each row is a (x,y) vector. This is a const parameter passed by reference - i.e. it's unaffected by the evaluate function and not copied.

_const Matrix<Scalar, 3, 1>& parms

This is the current parameter vector for which the functor should be evaluated (center.x, center.y, radius).

_Matrix<_Scalar, NumResiduals, 1>& residuals

This is a vector of doubles, where each row is the squared distance of the point from the circle with the given params.

Does that make sense?

On Sun, Oct 28, 2012 at 2:53 PM, avnerbarr notifications@github.com wrote:

Ok I'll try that.

Can you clarify in the evaluate function - what should i model in there? . I'm not clear on what the params are (is this a vector the result for fi on that iteration? Not to clear from the example)

virtual bool Evaluate( const Matrix<_Scalar, _NumResiduals, 2>& points, const Matrix<_Scalar, 3, 1>& parms, Matrix<_Scalar, _NumResiduals, 1>& residuals ) const

On Oct 28, 2012, at 8:37 PM, pboyer notifications@github.com wrote:

Yes, that should be sufficient.

I should say, however, that I've only yet tested the library on functors with relatively small number of parameters. The problem that you described seems like it could have a quite a high number of parameters. Keep in mind that you'll have to solve an nxn linear system on every iteration. I've yet to implement sparse solvers or matrices as part of this library.

Let me know if you have any more questions.

~Peter

On Sun, Oct 28, 2012 at 2:03 PM, avnerbarr notifications@github.com wrote:

Thanks for the quick reply.

Just want to clarify before I proceed: I need to inherit from LilOpt::IErrorFunction implement a function Evaluate use a diff function LilOpt::ErrorFunctionNumericDiff and then instantiate a LilOpt::Solver:: with those as params?

Thanks

On Oct 28, 2012, at 7:53 PM, pboyer notifications@github.com wrote:

Hi avnerbarr,

Thanks for using LilOpt!

I'd highly recommend taking a look at CircleTest.h. It is a self-contained example of how to use the library. In this case, given a set of input points (in 2d) we try to fit a circle to it. We define an error function (called CircleFunction) that returns the squared distances (i.e. residuals) from the given point set to the circle at a given parameter set.

The test() function should give you a complete example of setting up the functor and minimizing it.

Take a look at this first and let me know if you have any other questions.

~Peter

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHub< https://github.com/pboyer/LilOpt/issues/1#issuecomment-9848384>.

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHubhttps://github.com/pboyer/LilOpt/issues/1#issuecomment-9848946.

avnerbarr commented 11 years ago

Sorry, still not totally so.

In your case you defined the param to be the center of the circle - so checking to see that all points are of equal length from there would yield the minimum error

In my case Should r[i] be " put the values from the matrix in the i'th row into my i'th function minus the value that I got from the param vector in the i'th index" :)

On Oct 28, 2012, at 10:29 PM, pboyer notifications@github.com wrote:

An evaluate function in the LilOpt library asks, in essence, "How far is the function with the following parameters from the sampled points?" The evaluate function returns a bool determining whether the function evaluation was successful (typically it returns true). It stores the residuals in the residuals vector, which is passed by reference.

I'll go parameter by parameter to clarify:

virtual bool Evaluate( const Matrix<_Scalar, _NumResiduals, 2>& points, const Matrix<_Scalar, 3, 1>& parms, Matrix<_Scalar, _NumResiduals, 1>& residuals ) const \

Note the function is const as it does not affect the state of the functor object, which is stateless.

_const Matrix<_Scalar, NumResiduals, 2>& points

These are the sampled points in 2D passed as a matrix of doubles with size _NumResiduals x 2. That is each row is a (x,y) vector. This is a const parameter passed by reference - i.e. it's unaffected by the evaluate function and not copied.

_const Matrix<Scalar, 3, 1>& parms

This is the current parameter vector for which the functor should be evaluated (center.x, center.y, radius).

_Matrix<_Scalar, NumResiduals, 1>& residuals

This is a vector of doubles, where each row is the squared distance of the point from the circle with the given params.

Does that make sense?

On Sun, Oct 28, 2012 at 2:53 PM, avnerbarr notifications@github.com wrote:

Ok I'll try that.

Can you clarify in the evaluate function - what should i model in there? . I'm not clear on what the params are (is this a vector the result for fi on that iteration? Not to clear from the example)

virtual bool Evaluate( const Matrix<_Scalar, _NumResiduals, 2>& points, const Matrix<_Scalar, 3, 1>& parms, Matrix<_Scalar, _NumResiduals, 1>& residuals ) const

On Oct 28, 2012, at 8:37 PM, pboyer notifications@github.com wrote:

Yes, that should be sufficient.

I should say, however, that I've only yet tested the library on functors with relatively small number of parameters. The problem that you described seems like it could have a quite a high number of parameters. Keep in mind that you'll have to solve an nxn linear system on every iteration. I've yet to implement sparse solvers or matrices as part of this library.

Let me know if you have any more questions.

~Peter

On Sun, Oct 28, 2012 at 2:03 PM, avnerbarr notifications@github.com wrote:

Thanks for the quick reply.

Just want to clarify before I proceed: I need to inherit from LilOpt::IErrorFunction implement a function Evaluate use a diff function LilOpt::ErrorFunctionNumericDiff and then instantiate a LilOpt::Solver:: with those as params?

Thanks

On Oct 28, 2012, at 7:53 PM, pboyer notifications@github.com wrote:

Hi avnerbarr,

Thanks for using LilOpt!

I'd highly recommend taking a look at CircleTest.h. It is a self-contained example of how to use the library. In this case, given a set of input points (in 2d) we try to fit a circle to it. We define an error function (called CircleFunction) that returns the squared distances (i.e. residuals) from the given point set to the circle at a given parameter set.

The test() function should give you a complete example of setting up the functor and minimizing it.

Take a look at this first and let me know if you have any other questions.

~Peter

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHub< https://github.com/pboyer/LilOpt/issues/1#issuecomment-9848384>.

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHubhttps://github.com/pboyer/LilOpt/issues/1#issuecomment-9848946.

— Reply to this email directly or view it on GitHub.

pboyer commented 11 years ago

"In your case you defined the param to be the center of the circle - so checking to see that all points are of equal length from there would yield the minimum error"

This is incorrect. I defined the params for CircleFunction to be (center.x, center.y, radius). When the distance of the points from the circle cannot be decreased significantly, the minimization terminates. See line 109 in CircleTest.h.

"In my case Should r[i] be " put the values from the matrix in the i'th row into my i'th function minus the value that I got from the param vector in the i'th index" :) "

I'm not totally sure if I understand your problem, yet. It appears that you have a 2d graph (maybe a mesh, but I'm not sure if you allow edge crossings), and you have empirical values associated with the edges (sigma or d). You are trying to find a configuration of the vertices such that the difference between the edge length ( ||qi - qj|| ) and corresponding empirical value (dij) is minimized. Is that correct?

I want to confirm this before I offer a response.

On Sun, Oct 28, 2012 at 4:51 PM, avnerbarr notifications@github.com wrote:

Sorry, still not totally so.

In your case you defined the param to be the center of the circle - so checking to see that all points are of equal length from there would yield the minimum error

In my case Should r[i] be " put the values from the matrix in the i'th row into my i'th function minus the value that I got from the param vector in the i'th index" :)

On Oct 28, 2012, at 10:29 PM, pboyer notifications@github.com wrote:

An evaluate function in the LilOpt library asks, in essence, "How far is the function with the following parameters from the sampled points?" The evaluate function returns a bool determining whether the function evaluation was successful (typically it returns true). It stores the residuals in the residuals vector, which is passed by reference.

I'll go parameter by parameter to clarify:

virtual bool Evaluate( const Matrix<_Scalar, _NumResiduals, 2>& points, const Matrix<_Scalar, 3, 1>& parms, Matrix<_Scalar, _NumResiduals, 1>& residuals ) const

Note the function is const as it does not affect the state of the functor object, which is stateless.

_const Matrix<_Scalar, NumResiduals, 2>& points

These are the sampled points in 2D passed as a matrix of doubles with size _NumResiduals x 2. That is each row is a (x,y) vector. This is a const parameter passed by reference - i.e. it's unaffected by the evaluate function and not copied.

_const Matrix<Scalar, 3, 1>& parms

This is the current parameter vector for which the functor should be evaluated (center.x, center.y, radius).

_Matrix<_Scalar, NumResiduals, 1>& residuals

This is a vector of doubles, where each row is the squared distance of the point from the circle with the given params.

Does that make sense?

On Sun, Oct 28, 2012 at 2:53 PM, avnerbarr notifications@github.com wrote:

Ok I'll try that.

Can you clarify in the evaluate function - what should i model in there? . I'm not clear on what the params are (is this a vector the result for fi on that iteration? Not to clear from the example)

virtual bool Evaluate( const Matrix<_Scalar, _NumResiduals, 2>& points, const Matrix<_Scalar, 3, 1>& parms, Matrix<_Scalar, _NumResiduals, 1>& residuals ) const

On Oct 28, 2012, at 8:37 PM, pboyer notifications@github.com wrote:

Yes, that should be sufficient.

I should say, however, that I've only yet tested the library on functors with relatively small number of parameters. The problem that you described seems like it could have a quite a high number of parameters. Keep in mind that you'll have to solve an nxn linear system on every iteration. I've yet to implement sparse solvers or matrices as part of this library.

Let me know if you have any more questions.

~Peter

On Sun, Oct 28, 2012 at 2:03 PM, avnerbarr notifications@github.com

wrote:

Thanks for the quick reply.

Just want to clarify before I proceed: I need to inherit from LilOpt::IErrorFunction implement a function Evaluate use a diff function LilOpt::ErrorFunctionNumericDiff and then instantiate a LilOpt::Solver:: with those as params?

Thanks

On Oct 28, 2012, at 7:53 PM, pboyer notifications@github.com wrote:

Hi avnerbarr,

Thanks for using LilOpt!

I'd highly recommend taking a look at CircleTest.h. It is a self-contained example of how to use the library. In this case, given a set of input points (in 2d) we try to fit a circle to it. We define an error function (called CircleFunction) that returns the squared distances (i.e. residuals) from the given point set to the circle at a given parameter set.

The test() function should give you a complete example of setting up the functor and minimizing it.

Take a look at this first and let me know if you have any other questions.

~Peter

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHub< https://github.com/pboyer/LilOpt/issues/1#issuecomment-9848384>.

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHub< https://github.com/pboyer/LilOpt/issues/1#issuecomment-9848946>.

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHubhttps://github.com/pboyer/LilOpt/issues/1#issuecomment-9850375.

avnerbarr commented 11 years ago

can i send you a picture somehow?

On Oct 29, 2012, at 5:01 PM, pboyer notifications@github.com wrote:

"In your case you defined the param to be the center of the circle - so checking to see that all points are of equal length from there would yield the minimum error"

This is incorrect. I defined the params for CircleFunction to be (center.x, center.y, radius). When the distance of the points from the circle cannot be decreased significantly, the minimization terminates. See line 109 in CircleTest.h.

"In my case Should r[i] be " put the values from the matrix in the i'th row into my i'th function minus the value that I got from the param vector in the i'th index" :) "

I'm not totally sure if I understand your problem, yet. It appears that you have a 2d graph (maybe a mesh, but I'm not sure if you allow edge crossings), and you have empirical values associated with the edges (sigma or d). You are trying to find a configuration of the vertices such that the difference between the edge length ( ||qi - qj|| ) and corresponding empirical value (dij) is minimized. Is that correct?

I want to confirm this before I offer a response.

On Sun, Oct 28, 2012 at 4:51 PM, avnerbarr notifications@github.com wrote:

Sorry, still not totally so.

In your case you defined the param to be the center of the circle - so checking to see that all points are of equal length from there would yield the minimum error

In my case Should r[i] be " put the values from the matrix in the i'th row into my i'th function minus the value that I got from the param vector in the i'th index" :)

On Oct 28, 2012, at 10:29 PM, pboyer notifications@github.com wrote:

An evaluate function in the LilOpt library asks, in essence, "How far is the function with the following parameters from the sampled points?" The evaluate function returns a bool determining whether the function evaluation was successful (typically it returns true). It stores the residuals in the residuals vector, which is passed by reference.

I'll go parameter by parameter to clarify:

virtual bool Evaluate( const Matrix<_Scalar, _NumResiduals, 2>& points, const Matrix<_Scalar, 3, 1>& parms, Matrix<_Scalar, _NumResiduals, 1>& residuals ) const \

Note the function is const as it does not affect the state of the functor object, which is stateless.

_const Matrix<_Scalar, NumResiduals, 2>& points

These are the sampled points in 2D passed as a matrix of doubles with size _NumResiduals x 2. That is each row is a (x,y) vector. This is a const parameter passed by reference - i.e. it's unaffected by the evaluate function and not copied.

_const Matrix<Scalar, 3, 1>& parms

This is the current parameter vector for which the functor should be evaluated (center.x, center.y, radius).

_Matrix<_Scalar, NumResiduals, 1>& residuals

This is a vector of doubles, where each row is the squared distance of the point from the circle with the given params.

Does that make sense?

On Sun, Oct 28, 2012 at 2:53 PM, avnerbarr notifications@github.com wrote:

Ok I'll try that.

Can you clarify in the evaluate function - what should i model in there? . I'm not clear on what the params are (is this a vector the result for fi on that iteration? Not to clear from the example)

virtual bool Evaluate( const Matrix<_Scalar, _NumResiduals, 2>& points, const Matrix<_Scalar, 3, 1>& parms, Matrix<_Scalar, _NumResiduals, 1>& residuals ) const

On Oct 28, 2012, at 8:37 PM, pboyer notifications@github.com wrote:

Yes, that should be sufficient.

I should say, however, that I've only yet tested the library on functors with relatively small number of parameters. The problem that you described seems like it could have a quite a high number of parameters. Keep in mind that you'll have to solve an nxn linear system on every iteration. I've yet to implement sparse solvers or matrices as part of this library.

Let me know if you have any more questions.

~Peter

On Sun, Oct 28, 2012 at 2:03 PM, avnerbarr notifications@github.com

wrote:

Thanks for the quick reply.

Just want to clarify before I proceed: I need to inherit from LilOpt::IErrorFunction implement a function Evaluate use a diff function LilOpt::ErrorFunctionNumericDiff and then instantiate a LilOpt::Solver:: with those as params?

Thanks

On Oct 28, 2012, at 7:53 PM, pboyer notifications@github.com wrote:

Hi avnerbarr,

Thanks for using LilOpt!

I'd highly recommend taking a look at CircleTest.h. It is a self-contained example of how to use the library. In this case, given a set of input points (in 2d) we try to fit a circle to it. We define an error function (called CircleFunction) that returns the squared distances (i.e. residuals) from the given point set to the circle at a given parameter set.

The test() function should give you a complete example of setting up the functor and minimizing it.

Take a look at this first and let me know if you have any other questions.

~Peter

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHub< https://github.com/pboyer/LilOpt/issues/1#issuecomment-9848384>.

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHub< https://github.com/pboyer/LilOpt/issues/1#issuecomment-9848946>.

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHubhttps://github.com/pboyer/LilOpt/issues/1#issuecomment-9850375.

— Reply to this email directly or view it on GitHub.

pboyer commented 11 years ago

Sure, you can send it to my e-mail at peter.b.boyer at gmail.

pboyer commented 11 years ago

Hi Avner,

The code will look something like this, although I haven't debugged it yet. You will need to assign the m_topology vector appropriately, which is a std::vector of std::pair.

You will also want to populate the params vector with your closest approximation to the solution.

Hopefully this helps. I admit that I've never tried LilOpt with the number of parameters you are talking about (hundreds). If it doesn't work out, you might try Google's Ceres solver project, although it takes some more legwork to get going. My aim here was to make the library super easy to make part of an existing C++ project. Once I make SparseMatrix part of the library (an ongoing part of Eigen) your problem will be better supported.

template<typename _Scalar, unsigned int _NumEdges, unsigned int _NumVertices >
class GraphFunction : public LilOpt::IErrorFunction <_Scalar, _NumEdges, _NumVertices*2, 2> {

public:

    std::vector< std::pair<unsigned> > m_topology;

    virtual bool Evaluate(  const Matrix<_Scalar, _NumEdges, 2>&      points, 
                            const Matrix<_Scalar, _NumVertices*2, 1>&  params, 
                            Matrix<_Scalar, _NumEdges, 1>&            residuals ) const
    {

        // points:  a matrix of size _NumEdges x 2 where we store the alpha and d in first and second column
        // params:  the x and y vertices of each vertex stored in a column vector
        // residuals: each row is alphaij * ( (qi-qj).squaredNorm() - dij * dij) 

        residuals = Matrix<_Scalar, _NumEdges, 1>();

        for (unsigned i = 0; i < _NumEdges; i++)
        {

            // use the topology vector to obtain the two sides of the edge
            // look up the alpha value in the points vector
            // look up dij in points vector (second column)

            unsigned qi = m_topology[i].first;
            unsigned qj = m_topology[i].second;

            unsigned alphaij = points(i,0);
            unsigned dij = points(i,1);

            residuals[i] = alphaij * ( (qi-qj).squaredNorm() - dij * dij) ;

        }

        return true;

    }

};