--- /dev/null
+// Optimizes general sigmoid function 1/(1 + exp(-a(t-m))) over a set of points.
+
+#include <stdio.h>
+#include <vector>
+#include "ceres/ceres.h"
+#include "gflags/gflags.h"
+#include "glog/logging.h"
+
+using namespace ceres;
+using std::vector;
+
+struct Point {
+ float t;
+ float adoption_rate;
+};
+
+class DistanceFromSigmoidCostFunction {
+ public:
+ DistanceFromSigmoidCostFunction(Point p) : p_(p) {}
+
+ template<class T>
+ bool operator() (const T * const a, const T * const m, T* e) const {
+ *e = T(p_.adoption_rate) - T(1.0) / (T(1.0) + ceres::exp(- *a * (T(p_.t) - *m)));
+ return true;
+ }
+
+ private:
+ Point p_;
+};
+
+int main(int argc, char** argv) {
+ google::ParseCommandLineFlags(&argc, &argv, true);
+ google::InitGoogleLogging(argv[0]);
+
+ Problem problem;
+
+ FILE *fp = fopen(argv[1], "r");
+ if (fp == NULL) {
+ perror(argv[1]);
+ exit(1);
+ }
+
+ // The two parameters to be optimized.
+ double a = 1.0;
+ double m = 0.5;
+
+ int line_num = 0;
+ while (!feof(fp)) {
+ char buf[256];
+ if (fgets(buf, 256, fp) == NULL) {
+ break;
+ }
+ Point p;
+ p.t = line_num;
+ p.adoption_rate = atof(buf) * 0.01;
+ problem.AddResidualBlock(
+ new AutoDiffCostFunction<DistanceFromSigmoidCostFunction, 1, 1, 1>(
+ new DistanceFromSigmoidCostFunction(p)),
+ NULL,
+ &a, &m);
+ ++line_num;
+ }
+ fclose(fp);
+
+ a = 1.0 / line_num;
+
+ // Run the solver!
+ Solver::Options options;
+ options.max_num_iterations = 1000000;
+ options.linear_solver_type = ceres::DENSE_QR;
+ options.minimizer_progress_to_stdout = true;
+
+ Solver::Summary summary;
+ Solve(options, &problem, &summary);
+
+ std::cout << summary.BriefReport() << "\n";
+ std::cout << "a=" << a << std::endl;
+ std::cout << "m=" << m << std::endl;
+
+ return 0;
+}