Is it possible to formulate a nested cost function?

62 views
Skip to first unread message

zhexu...@outlook.com

unread,
Apr 23, 2022, 11:27:01 PM4/23/22
to Ceres Solver
For the convinience of modelling, I may want to creat a nested cost function. Take rosenbrock cost function for example:  f(x,y) = (1-x)^2 + 100(y - x^2)^2.
Instead of directed calculate residue like rosenbrock.cc, can i have:
function 1: f1 = x^2
function 2: f2 = y - f1
function 3: f3 = 1-x
cost function f(x, y) = (1-x)^2 + 100(y - f1)^2

I tried to do like this but fail to compile. Error was generated at line that call F1. I use MSVC 2022.
struct F1 {
    template <typename T>
    bool operator()(const T* const x, T* residual) const {
        // f1 = x * x;
        residual[0] = x[0] * x[0];
        return true;
    }
};

struct F2 {
    template <typename T>
    bool operator()(const T* const x, const T* const y, T* residual) const {
        // f2 = y - f1
        T* temp;
        F1(x, temp); //error C2440
        //F1<T>(x, temp); //error C2760
        residual = y[0] - temp;
        return true;
    }
};
Can someone help me? Thanks!

Sameer Agarwal

unread,
Apr 26, 2022, 3:01:36 AM4/26/22
to ceres-...@googlegroups.com
This works.

struct F1 {
    template <typename T>
    bool operator()(const T* const x, T* residual) const {
        // f1 = x * x;
        residual[0] = x[0] * x[0];
        return true;
    }
};

struct F2 {
    template <typename T>
    bool operator()(const T* const x, const T* const y, T* residual) const {
        // f2 = y - f1
        T temp;
        F1()(x, &temp);
        residual[0] = y[0] - temp;
        return true;
    }
};

// f(x,y) = (1-x)^2 + 100(y - x^2)^2;
struct Rosenbrock {
  template <typename T>
  bool operator()(const T* parameters, T* cost) const {
    const T x = parameters[0];
    const T y = parameters[1];
    T temp;
    cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * F2()(&x,&y, &temp);
    return true;
  }
};


--
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/b8bd7665-7624-4caf-880d-2de8649b7529n%40googlegroups.com.

zhexu...@outlook.com

unread,
Apr 26, 2022, 5:14:56 AM4/26/22
to Ceres Solver
Thank you for your reply! The code you provided was able to compile, but failed to get the right answer (1.0, 1.0).  Optimization of rosenbrock.cc in example folder was suceessful. I tried to figure out why and modified the line cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * F2()(&x,&y, &temp); because the F2() function seems to return 1 or 0 after conversion. But my code still cannot get (1.0, 1.0), It went to (-1.1056, 1.22376). Followed is my full code. Thanks for your kindly help again!

#include <vector>

#include "ceres/ceres.h"
#include "gflags/gflags.h"
#include "glog/logging.h"

using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solve;
using ceres::Solver;


struct F1 {
    template <typename T>
    bool operator()(const T* const x, T* residual) const {
        // f1 = x * x;
        residual[0] = x[0] * x[0];
        return true;
    }
};

struct F2 {
    template <typename T>
    bool operator()(const T* const x, const T* const y, T* residual) const {
        // f2 = y - f1
        T temp;
        F1()(x, &temp);
        residual[0] = y[0] - temp;
        return true;
    }
};

// f(x,y) = (1-x)^2 + 100(y - x^2)^2;
struct Rosenbrock {
    template <typename T>
    bool operator()(const T* parameters, T* cost) const {
        const T x = parameters[0];
        const T y = parameters[1];
        T temp;
        //cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * F2()(&x, &y, &temp);
        F2()(&x, &y, &temp);
        cost[0] = (1.0 - x) * (1.0 - x) + 100.0 * temp * temp;
        return true;
    }
};

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

    double x[2] = { -1.2, 1 };

    Problem problem;

    problem.AddResidualBlock(
        new AutoDiffCostFunction<Rosenbrock, 1, 2>(new Rosenbrock), nullptr, x);

    Solver::Options options;

    std::cout << "Initial x = " << x[0]
        << ", y = " << x[1]
        << "\n";

    Solver::Summary summary;
    Solve(options, &problem, &summary);

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

    std::cout << "Final x = " << x[0]
        << ", y = " << x[1]
        << "\n";

    return 0;
}

zhexu...@outlook.com

unread,
Apr 26, 2022, 5:42:48 AM4/26/22
to Ceres Solver
I know what's wrong here... It is solved as a Non-linear Least Squares instead of normal problem, which make it harder to solve. Followed code works. Thanks!

#include <vector>

#include "ceres/ceres.h"
#include "gflags/gflags.h"
#include "glog/logging.h"

using ceres::AutoDiffCostFunction;
using ceres::CostFunction;
using ceres::Problem;
using ceres::Solve;
using ceres::Solver;

struct F1 {
    template <typename T>
    bool operator()(const T* const x, T* residual) const {
        // f1 = x * x;
        residual[0] = x[0] * x[0];
        return true;
    }
};

struct RosenbrockPart2 {

    template <typename T>
    bool operator()(const T* const x, const T* const y, T* residual) const {
        // f2 = y - f1
        T temp;
        F1()(x, &temp);
        residual[0] = y[0] - temp;
        return true;
    }
};

struct RosenbrockPart1 {

    template <typename T>
    bool operator()(const T* const x, T* residual) const {
        residual[0] = 1.0 - x[0];

        return true;
    }
};


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

    double x = -1.2;
    double y = 1;

    Problem problem;

    problem.AddResidualBlock(
        new AutoDiffCostFunction<RosenbrockPart1, 1, 1>(new RosenbrockPart1), nullptr, &x);
    problem.AddResidualBlock(
        new AutoDiffCostFunction<RosenbrockPart2, 1, 1, 1>(new RosenbrockPart2), nullptr, &x, &y);

    Solver::Options options;
    options.minimizer_progress_to_stdout = true;
    options.max_num_iterations = 300;


    std::cout << "Initial x = " << x
        << ", y = " << y

        << "\n";

    Solver::Summary summary;
    Solve(options, &problem, &summary);

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

    std::cout << "Final x = " << x
        << ", y = " << y
        << "\n";

    return 0;
}
Reply all
Reply to author
Forward
0 new messages