11d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling/* Ceres Solver - A fast non-linear least squares minimizer
21d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * Copyright 2013 Google Inc. All rights reserved.
31d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * http://code.google.com/p/ceres-solver/
41d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *
51d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * Redistribution and use in source and binary forms, with or without
61d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * modification, are permitted provided that the following conditions are met:
71d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *
81d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * - Redistributions of source code must retain the above copyright notice,
91d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   this list of conditions and the following disclaimer.
101d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * - Redistributions in binary form must reproduce the above copyright notice,
111d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   this list of conditions and the following disclaimer in the documentation
121d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   and/or other materials provided with the distribution.
131d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * - Neither the name of Google Inc. nor the names of its contributors may be
141d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   used to endorse or promote products derived from this software without
151d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   specific prior written permission.
161d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *
171d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
181d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
211d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
221d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
231d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
241d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
251d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
261d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
271d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * POSSIBILITY OF SUCH DAMAGE.
281d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *
291d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * Author: mierle@gmail.com (Keir Mierle)
301d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *
311d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * This is a port of curve_fitting.cc to the minimal C API for Ceres.
321d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling */
331d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
341d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling#include <math.h>
351d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling#include <stdio.h>
361d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling#include <string.h>  // For NULL
371d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling#include "ceres/c_api.h"
381d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
391d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling/* Data generated using the following octave code.
401d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *
411d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   randn('seed', 23497);
421d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   m = 0.3;
431d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   c = 0.1;
441d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   x=[0:0.075:5];
451d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   y = exp(m * x + c);
461d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   noise = randn(size(x)) * 0.2;
471d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   y_observed = y + noise;
481d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *   data = [x', y_observed'];
491d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling *
501d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling */
511d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
521d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberlingint num_observations = 67;
531d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberlingdouble data[] = {
541d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  0.000000e+00, 1.133898e+00,
551d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  7.500000e-02, 1.334902e+00,
561d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.500000e-01, 1.213546e+00,
571d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.250000e-01, 1.252016e+00,
581d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.000000e-01, 1.392265e+00,
591d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.750000e-01, 1.314458e+00,
601d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.500000e-01, 1.472541e+00,
611d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  5.250000e-01, 1.536218e+00,
621d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  6.000000e-01, 1.355679e+00,
631d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  6.750000e-01, 1.463566e+00,
641d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  7.500000e-01, 1.490201e+00,
651d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  8.250000e-01, 1.658699e+00,
661d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  9.000000e-01, 1.067574e+00,
671d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  9.750000e-01, 1.464629e+00,
681d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.050000e+00, 1.402653e+00,
691d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.125000e+00, 1.713141e+00,
701d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.200000e+00, 1.527021e+00,
711d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.275000e+00, 1.702632e+00,
721d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.350000e+00, 1.423899e+00,
731d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.425000e+00, 1.543078e+00,
741d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.500000e+00, 1.664015e+00,
751d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.575000e+00, 1.732484e+00,
761d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.650000e+00, 1.543296e+00,
771d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.725000e+00, 1.959523e+00,
781d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.800000e+00, 1.685132e+00,
791d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.875000e+00, 1.951791e+00,
801d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  1.950000e+00, 2.095346e+00,
811d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.025000e+00, 2.361460e+00,
821d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.100000e+00, 2.169119e+00,
831d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.175000e+00, 2.061745e+00,
841d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.250000e+00, 2.178641e+00,
851d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.325000e+00, 2.104346e+00,
861d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.400000e+00, 2.584470e+00,
871d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.475000e+00, 1.914158e+00,
881d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.550000e+00, 2.368375e+00,
891d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.625000e+00, 2.686125e+00,
901d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.700000e+00, 2.712395e+00,
911d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.775000e+00, 2.499511e+00,
921d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.850000e+00, 2.558897e+00,
931d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  2.925000e+00, 2.309154e+00,
941d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.000000e+00, 2.869503e+00,
951d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.075000e+00, 3.116645e+00,
961d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.150000e+00, 3.094907e+00,
971d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.225000e+00, 2.471759e+00,
981d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.300000e+00, 3.017131e+00,
991d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.375000e+00, 3.232381e+00,
1001d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.450000e+00, 2.944596e+00,
1011d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.525000e+00, 3.385343e+00,
1021d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.600000e+00, 3.199826e+00,
1031d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.675000e+00, 3.423039e+00,
1041d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.750000e+00, 3.621552e+00,
1051d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.825000e+00, 3.559255e+00,
1061d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.900000e+00, 3.530713e+00,
1071d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  3.975000e+00, 3.561766e+00,
1081d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.050000e+00, 3.544574e+00,
1091d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.125000e+00, 3.867945e+00,
1101d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.200000e+00, 4.049776e+00,
1111d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.275000e+00, 3.885601e+00,
1121d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.350000e+00, 4.110505e+00,
1131d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.425000e+00, 4.345320e+00,
1141d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.500000e+00, 4.161241e+00,
1151d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.575000e+00, 4.363407e+00,
1161d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.650000e+00, 4.161576e+00,
1171d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.725000e+00, 4.619728e+00,
1181d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.800000e+00, 4.737410e+00,
1191d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.875000e+00, 4.727863e+00,
1201d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  4.950000e+00, 4.669206e+00,
1211d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling};
1221d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
1231d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling/* This is the equivalent of a use-defined CostFunction in the C++ Ceres API.
1241d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * This is passed as a callback to the Ceres C API, which internally converts
1251d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling * the callback into a CostFunction. */
1261d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberlingint exponential_residual(void* user_data,
1271d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                         double** parameters,
1281d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                         double* residuals,
1291d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling                         double** jacobians) {
1301d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  double* measurement = (double*) user_data;
1311d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  double x = measurement[0];
1321d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  double y = measurement[1];
1331d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  double m = parameters[0][0];
1341d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  double c = parameters[1][0];
1351d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
1361d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  residuals[0] = y - exp(m * x + c);
1371d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  if (jacobians == NULL) {
1381d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    return 1;
1391d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  }
1401d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  if (jacobians[0] != NULL) {
1411d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    jacobians[0][0] = - x * exp(m * x + c);  /* dr/dm */
1421d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  }
1431d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  if (jacobians[1] != NULL) {
1441d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    jacobians[1][0] =     - exp(m * x + c);  /* dr/dc */
1451d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  }
1461d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  return 1;
1471d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling}
1481d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
1491d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberlingint main(int argc, char** argv) {
1501d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  /* Note: Typically it is better to compact m and c into one block,
1511d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling   * but in this case use separate blocks to illustrate the use of
1521d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling   * multiple parameter blocks. */
1531d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  double m = 0.0;
1541d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  double c = 0.0;
1551d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
1561d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  double *parameter_pointers[] = { &m, &c };
1571d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  int parameter_sizes[] = { 1, 1 };
1581d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  int i;
1591d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
1601d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  ceres_problem_t* problem;
1611d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
1621d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  /* Ceres has some internal stuff that needs to get initialized. */
1631d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  ceres_init();
1641d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
1651d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  problem = ceres_create_problem();
1661d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
1671d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  /* Add all the residuals. */
1681d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  for (i = 0; i < num_observations; ++i) {
1691d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling    ceres_problem_add_residual_block(
1701d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        problem,
1711d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        exponential_residual,  /* Cost function */
1721d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        &data[2 * i],          /* Points to the (x,y) measurement */
1731d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        NULL,                  /* No loss function */
1741d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        NULL,                  /* No loss function user data */
1751d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        1,                     /* Number of residuals */
1761d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        2,                     /* Number of parameter blocks */
1771d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        parameter_sizes,
1781d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling        parameter_pointers);
1791d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  }
1801d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
1811d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  ceres_solve(problem);
1821d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  ceres_free_problem(problem);
1831d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling
1841d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  printf("Initial m: 0.0, c: 0.0\n");
1851d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  printf("Final m: %g, c: %g\n", m, c);
1861d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling  return 0;
1871d2624a10e2c559f8ba9ef89eaa30832c0a83a96Sascha Haeberling}
188