Analytic Jacobian w/ Multiple Residuals

813 views
Skip to first unread message

Eric

unread,
Nov 11, 2015, 10:40:07 AM11/11/15
to Ceres Solver
Hi,

I think this is a simple problem stemming from my confusion about how to properly specify parameters and residuals using an analytic Jacobian cost function.  I understand from the tutorial how to set-up an analytic Jacobian where there is 1 parameter and 1 residual.  I'm trying to figure out the general application / definition of an analytic Jacobian with multiple parameters & residuals.  As an example, I'm trying to implement the Powell function example from the tutorial by using an analytic Jacobian.  My code compiles but when I run it, it fails with the error:   Check failed: parameter_blocks.size() == cost_function->parameter_block_sizes().size() (1 vs. 4)"

The relevant changes I've made to the code from the tutorial are as follows:

Here's my QuadraticCostFunction class:
class QuadraticCostFunction : public ceres::SizedCostFunction < 4, 1, 1, 1, 1 >
{
public:
virtual ~QuadraticCostFunction() {}
virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
{
const double x1 = parameters[0][0];
const double x2 = parameters[1][0];
const double x3 = parameters[2][0];
const double x4 = parameters[3][0];
residuals[0] = x1 + 10.0*x2;
residuals[1] = sqrt(5)*(x3 - x4);
residuals[2] = pow((x2 - 2.0*x3), 2);
residuals[3] = sqrt(10.0)*pow((x1 - x4), 2);

if (jacobians != NULL && jacobians[0] != NULL)
{
jacobians[0][0] = 1.0;
jacobians[0][1] = 10.0;
jacobians[0][2] = 0.0;
jacobians[0][3] = 0.0;

jacobians[1][0] = 0.0;
jacobians[1][1] = 0.0;
jacobians[1][2] = sqrt(5.0);
jacobians[1][3] = -sqrt(5.0);

jacobians[2][0] = 0.0;
jacobians[2][1] = 2.0*(x2 - 2.0*x3);
jacobians[2][2] = -4.0*(x2 - 2.0*x3);
jacobians[2][3] = 0.0;

jacobians[3][0] = 2.0*sqrt(10)*(x1 - x4);
jacobians[3][1] = 0.0;
jacobians[3][2] = 0.0;
jacobians[3][3] = -2.0*sqrt(10)*(x1 - x4);
}
return true;
}
};

And then w/in the main function I have:

double params[4] = { 0.0, 0.0, 0.0, 0.0 };
        Problem problem;
CostFunction * cost_function = new QuadraticCostFunction;
problem.AddResidualBlock(cost_function, NULL, params);
        Solver::Options options;
options.linear_solver_type = ceres::DENSE_QR;
options.minimizer_progress_to_stdout = true;
Solver::Summary summary;
Solve(options, &problem, &summary);



I've also tried to duplicate the problem.AddResidualBlock(cost_function, NULL, params); four times in a row to, I guess, create four residuals - but I'm confused b/c I create the four elements of the residual array w/in the QuadraticCostFunction::Evaluate method.  

What am I doing wrong?

Thanks in advance.

Sameer Agarwal

unread,
Nov 11, 2015, 11:14:52 AM11/11/15
to Ceres Solver
Eric,
class QuadraticCostFunction : public ceres::SizedCostFunction < 4, 1, 1, 1, 1 >

says that you are defining a costfunction with with 4 residuals and four different parameter blocks of size one each.

where as

problem.AddResidualBlock(cost_function, NULL, params);

says that you have a single parameter block, which is why ceres complains because it is expecting four parameter blocks.

there are two ways to fix this.

1. Change the CostFunction to be of the form 

class QuadraticCostFunction : public ceres::SizedCostFunction < 4, 4 >
and update the Evaluate  method accordingly.

2. Change the problem construction to
problem.AddResidualBlock(cost_function, NULL, params, params + 1, params + 2, params + 3);

Sameer


--
You received this message because you are subscribed to the Google Groups "Ceres Solver" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ceres-solver...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ceres-solver/48caec29-8658-48ea-8456-8446f356c260%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Eric

unread,
Nov 11, 2015, 12:47:42 PM11/11/15
to Ceres Solver
Sameer,

Thanks for the quick reply.  Let's say I go with your fix #1.  My QuadraticCostFunction now looks like:

class QuadraticCostFunction : public ceres::SizedCostFunction < 4, 4 > /* I believe these entries are Num_residuals, size of x1, x2, x3 & x4... */
{
public:
virtual ~QuadraticCostFunction() {}
virtual bool Evaluate(double const* const* parameters, double* residuals, double** jacobians) const
{
const double x1 = parameters[0][0];
const double x2 = parameters[0][1];
const double x3 = parameters[0][2];
const double x4 = parameters[0][3];
residuals[0] = x1 + 10.0*x2;
residuals[1] = sqrt(5)*(x3 - x4);
residuals[2] = pow((x2 - 2.0*x3), 2);
residuals[3] = sqrt(10.0)*pow((x1 - x4), 2);

if (jacobians != NULL && jacobians[0] != NULL)
{
jacobians[0][0] = 1.0;
jacobians[0][1] = 10.0;
jacobians[0][2] = 0.0;
jacobians[0][3] = 0.0;

jacobians[1][0] = 0.0;
jacobians[1][1] = 0.0;
jacobians[1][2] = sqrt(5.0);
jacobians[1][3] = -sqrt(5.0);

jacobians[2][0] = 0.0;
jacobians[2][1] = 2.0*(x2 - 2.0*x3);
jacobians[2][2] = -4.0*(x2 - 2.0*x3);
jacobians[2][3] = 0.0;

jacobians[3][0] = 2.0*sqrt(10)*(x1 - x4);
jacobians[3][1] = 0.0;
jacobians[3][2] = 0.0;
jacobians[3][3] = -2.0*sqrt(10)*(x1 - x4);
}
return true;
}
};


But the code is failing when it gets to the 2nd row of my jacobians calculation "jacobians[1][0] = 0.0;"  I tend to think of the 4 residuals forming a 4x1 vector, f, and we form the Jacobian as df/dp (where p is a vector of the parameters - in this case x1 - x4).  So the (i,j) entry in the Jacobian should be df(i)/dp(j).  But ceres does not seem to be in agreement.  How should I structure the Jacobian in this case?

Sameer Agarwal

unread,
Nov 11, 2015, 12:52:41 PM11/11/15
to Ceres Solver
you are going to get a single jacobian array in row major order which you should fill, you are trying to fill out four different arrays.
Sameer


William Rucklidge

unread,
Nov 11, 2015, 12:55:32 PM11/11/15
to ceres-...@googlegroups.com
Elaborating on Sameer's answer:

Before, you had
- 4 residuals
- 4 parameter blocks, each of size 1.
That means that your Jacobians would be four 4x1 vectors. So you were doing
jacobians[0][0...3]
jacobians[1][0...3]
etc. to populate these four vectors.

Now, you have 
- 4 residuals
- 1 parameter block, of size 4
so you will have a single Jacobian, whose size is 4x4. You need to fill it out as
jacobians[0][0...15]
in row-major order.

-wjr


Eric

unread,
Nov 11, 2015, 1:09:03 PM11/11/15
to Ceres Solver
William & Sameer,

That was it.  Just changed my jacobians indices as you specified and it worked!  Got the same answers as the tutorial w/ automatic differentiation.

Thank you both!
Reply all
Reply to author
Forward
0 new messages