1

I am trying to solve a nonlinear system using Ceres Solver by Google. The example below comes from this page: http://terpconnect.umd.edu/~petersd/460/html/newtonex1z.html

I first create a class called MatlabExample, where I compute the residuals and jacobians:

class MatlabExample
: public SizedCostFunction<2,2> {
public:
virtual ~MatlabExample() {}
virtual bool Evaluate(double const* const* parameters,
                    double* residuals,
                    double** jacobians) const {

double x1 = parameters[0][0];
double x2 = parameters[0][1];

residuals[0] = 2*x1+x1*x2-2;
residuals[1] = 2*x2-x1*pow(x2,2)-2 ;

if (jacobians != NULL && jacobians[0] != NULL) {
  jacobians[0][0] = 2+x2;
  jacobians[0][1] = x1;
  jacobians[1][0] = -pow(x2,2);
  jacobians[1][1] = 2-2*x1*x2;
}

return true;
}
};

The main file is as follows:

int main(int argc, char** argv) {
  google::InitGoogleLogging(argv[0]);

  double x[] = { 0.0,0.0 };

  Problem problem;
  CostFunction* cost_function = new MatlabExample;
  problem.AddResidualBlock(cost_function, NULL, &x);
  Solver::Options options;
  options.minimizer_progress_to_stdout = true;
  Solver::Summary summary;
  Solve(options, &problem, &summary);

  std::cout << summary.BriefReport() << "\n";

  return 0;
}

When compiling, I got a Segmentation fault: 11 error. Any ideas?

RangerBob
  • 473
  • 3
  • 13
  • 1
    `double const* const* parameters` - Wow. Why would you do that? Why not just pass a `std::array` or `std::vector` (possibly by const reference)? – Jesper Juhl Jun 04 '19 at 20:36
  • Nitpick: prefer `nullptr` over `NULL`. We are not living in C++98 land any more. – Jesper Juhl Jun 04 '19 at 20:39
  • Because the abstract class 'SizedCostFunction' defines the virtual function 'Evaluate' in this way. I have no way to change this because this comes from Ceres Solver. – RangerBob Jun 04 '19 at 20:51
  • I have extended this file: https://github.com/ceres-solver/ceres-solver/blob/master/examples/helloworld_analytic_diff.cc – RangerBob Jun 04 '19 at 20:57
  • That null check for `jacobians` is practically worthless. That does not adequately determine if `jacobians` is valid for how you're using it. – PaulMcKenzie Jun 04 '19 at 21:17
  • So, it also means that, in the example from the link I provide above, this check for jacobians is also worthless? – RangerBob Jun 04 '19 at 21:25
  • Do you understand why it's worthless? You are placing pure trust that there are at least 2 columns and 2 rows. If that trust is violated, then you're accessing outside the bounds of what was allotted. You also cannot check for this, since all you have is a pointer with no additional size arguments. – PaulMcKenzie Jun 04 '19 at 21:33
  • Yes I understand but it's not clear what to do – RangerBob Jun 04 '19 at 21:51
  • You can first determine which line is causing the issue. If it's one of those pointer accesses in the `Evaluate` function, then you have more debugging to do to determine what the actual size allocated that those pointers are pointing to. This is why doing things using modern C++ techniques like using containers are much safer. I don't know why the original authors of your code didn't take advantage of this. – PaulMcKenzie Jun 04 '19 at 22:01

1 Answers1

1

You are accessing the jacobians array wrong. Here is why.

When you added the residual block, you told Ceres that the cost function only depends on one parameter block of size 2 and produces a residual of size 2.

The jacobians array is an array of row-major jacobians. One for each parameter block. So in this case it is of size 1, and contains a pointer to size 4 array that should contain a row major Jacobian.

Your Jacobian filling code should instead read

if (jacobians != NULL && jacobians[0] != NULL) {
  jacobians[0][0] = 2+x2;
  jacobians[0][1] = x1;
  jacobians[0][2] = -pow(x2,2);
  jacobians[0][3] = 2-2*x1*x2;
}
Sameer Agarwal
  • 592
  • 2
  • 4
  • Thanks. So, by doing this, it means that `jacobians[0][0]=d f1/x1`, `jacobians[0][1]=d f1/x2`, `jacobians[0][2]=d f2/x1`, and `jacobians[0][3]=d f2/x2`. Are we sure about this order? – RangerBob Jun 05 '19 at 13:55
  • Yes jacobians in Ceres are row major matrices. – Sameer Agarwal Jun 06 '19 at 14:34
  • It's too bad the authors of the Ceres wrapper didn't wrap the `double**` in a class, so at the very least, `size()` or similar function could have been used to verify the dimension sizes. – PaulMcKenzie Jun 06 '19 at 20:16