david-cattermole / mayaMatchMoveSolver

A Bundle Adjustment solver for MatchMove related tasks.
https://david-cattermole.github.io/mayaMatchMoveSolver/
Other
102 stars 26 forks source link

Core Solver - Add CMinpack Library #9

Closed david-cattermole closed 5 years ago

david-cattermole commented 5 years ago

We should add support for the "cminpack" library for optimization.

http://devernay.free.fr/hacks/cminpack/

CMinpack is stable and robust and has been used for many years. CMinpack has no dependencies (unless users wish to optionally use BLAS with it). CMinpack has a CMake build script, which will be easy to integrate into mmSolver.

Both CMinpack and levmar libraries should work together in the same plug-in. Only one library should be required. If one library is not available the other library will be used instead.

Depending on performance, CMinpack may become the new default solver (replacing levmar), if both solvers are availible

Adding support for CMinpack will require:

david-cattermole commented 5 years ago

The Solver engine for CMinpack should support minimum / maximum values. CMinpack does not support this natively, but shows in the homepage a technique for getting this functionality. I have copy-pasted this information here for safe-keeping.

Simulating box constraints; from http://devernay.free.fr/hacks/cminpack/

Simulating box constraints

Note that box constraints can easily be simulated in C++ Minpack, using a change of variables in the function (that hint was found in the lmfit documentation).

For example, say you want xmin[j] < x[j] < xmax[j], just apply the following change of variable at the beginning of fcn on the variables vector, and also on the computed solution after the optimization was performed:

  for (j = 0; j < 3; ++j) {
    real xmiddle = (xmin[j]+xmax[j])/2.;
    real xwidth = (xmax[j]-xmin[j])/2.;
    real th =  tanh((x[j]-xmiddle)/xwidth);
    x[j] = xmiddle + th * xwidth;
    jacfac[j] = 1. - th * th;
  }

This change of variables preserves the variables scaling, and is almost the identity near the middle of the interval.

Of course, if you use lmder, lmder1, hybrj or hybrj1, the Jacobian must be also consistent with that new function, so the column of the original Jacobian corresponding to x1 must be multiplied by the derivative of the change of variable, i.e jacfac[j].

Similarly, each element of the covariance matrix must be multiplied by jacfac[i]*jacfac[j].

For examples on how to implement this in practice, see the portions of code delimited by #ifdef BOX_CONSTRAINTS in the following source files: tlmderc.c, thybrj.c, tchkderc.c.

david-cattermole commented 5 years ago

CMinpack has been merged into master, and is considered stable but not yet for production.

A new Command has been added maya.cmds.mmSolverType, which allows querying for the different solver types, and can be used to determine the "default" solver (if both CMinpack and Levmar are available).

Still on the todo list are:

david-cattermole commented 5 years ago

CMinpack has been integrated with mmSolver, but currently lacks proper Box Constraints. This will be added in #64.

Closing this issue.