public CircleFitter2D(IEnumerable<Point3D> initialPoints) { this.points = initialPoints.ToList(); // Compute point centroid Point3D center = Point3D.Centroid(this.points); var distances = from x in this.points select x.DistanceTo(center); double radius = distances.Average(); var solver = new LMSolver(); // Guess for x, y, and r double[] guess = new[] {center.X, center.Y, radius}; var fit = solver.Minimize((p, r) => { // unpack the minimization parameters, x, y, and r double x = p[0]; double y = p[1]; double rad = p[2]; Point3D testCenter = new Point3D(x, y, this.points.First().Z); // compute the residuals for (int i = 0; i < this.points.Count; i++) { r[i] = this.points[i].DistanceTo(testCenter) - rad; } }, guess, this.points.Count); this.CircleCenter = new Point3D(fit.OptimizedParameters[0], fit.OptimizedParameters[1], this.points.First().Z); this.CircleRadius = fit.OptimizedParameters[2]; }
/// <summary> /// Demonstrates how to solve systems of non-linear /// equations using the LMA /// </summary> static void SolveExamples(LMBackend solverType) { var solver = new LMSolver(optimizerBackend: solverType); // 1st example: // Aim: Find (x, y) for which // y = -0.5x² + 3.0 && // y = exp(-x) // is true. // Transform to a minimization problem: // r[0] = 0 = y + 0.5x² - 3.0 // r[1] = 0 = y - exp(-x) Action <double[], double[]> f = (p, r) => { // Here: p[0] = x; p[1] = y var x = p[0]; var y = p[1]; r[0] = y + 0.5 * x * x - 3.0; r[1] = y - Math.Exp(-x); }; // -> Find (x, y) that minimizes sum(r²) using LMA // first solution var result1 = solver.Solve(f, new[] { -2.0, 0.0 }); // second solution var result2 = solver.Solve(f, new[] { 2.0, 0.0 }); Console.WriteLine("Find (x, y) for which"); Console.WriteLine(" y = -0.5x² + 3.0 &&"); Console.WriteLine(" y = exp(-x)"); Console.WriteLine("is true."); Console.WriteLine("1st solution: x = {0}, y = {1}", result1.OptimizedParameters[0], result1.OptimizedParameters[1]); Console.WriteLine("2nd solution: x = {0}, y = {1}", result2.OptimizedParameters[0], result2.OptimizedParameters[1]); Console.WriteLine(); // 2nd Example: // Solve // y = -x² + 6 && // y = -2x - 2 result1 = solver.Solve((p, r) => { r[0] = p[1] + p[0] * p[0] - 6.0; // 0 = y + x² - 6 r[1] = p[1] + 2.0 * p[0] + 2.0; // 0 = y + 2x + 2 }, new[] { 0.0, 0.0 }); result2 = solver.Solve((p, r) => { r[0] = p[1] + p[0] * p[0] - 6.0; r[1] = p[1] + 2.0 * p[0] + 2.0; }, new[] { 10.0, 0.0 }); Console.WriteLine("Solve"); Console.WriteLine(" y = -x² + 6 &&"); Console.WriteLine(" y = -2x - 2"); Console.WriteLine("1st solution: x = {0}, y = {1}", result1.OptimizedParameters[0], result1.OptimizedParameters[1]); Console.WriteLine("2nd solution: x = {0}, y = {1}", result2.OptimizedParameters[0], result2.OptimizedParameters[1]); }
public double[] Solve(IReadOnlyList <EquationNode> nodes, IReadOnlyList <double[]> indices) { var indexList = nodes.FormatIndexList(indices); var solver = new LMSolver(); var optimizationResult = solver.Minimize( (p, r) => { indexList.AsParallel() .Select((x, i) => new { Result = nodes.Calculate(x, p), Row = i }) .ForAll(x => r[x.Row] = x.Result); }, new double[indexList.First().Length], indexList.Count); return(optimizationResult.OptimizedParameters); }
/// <summary> /// Demonstrantes the usage of the generic minimization API /// LMSolver.Minimize /// </summary> static void GenericMinimizationExamples(LMBackend solverType) { var solver = new LMSolver(optimizerBackend: solverType); // grid points var xs = new[] { -1.0, -1.0, 1.0, 1.0 }; var zs = new[] { -1.0, 1.0, -1.0, 1.0 }; // data points/samples var ys = new[] { 0.0, 1.0, 1.0, 2.0 }; // Aim: fit a regression model to the samples // Model: y' = β0 + β1 * x + β2 * z // Regressors: x and z (provided as grid points) // Unknown paramters: β0, β1, β2 // Design matrix X = [1 xs zs] (4x3 matrix) // Parameter vector ε = [β0 β1 β2]^T // Residue: ε = y - y' = y - X β // Find β' = argmin_β sum(ε²) var fit = solver.Minimize((p, r) => { // compute the residue vector ε = y - y' based on the // current parameters p (== β0, β1, β2) var β0 = p[0]; var β1 = p[1]; var β2 = p[2]; for (int i = 0; i < ys.Length; ++i) { r[i] = ys[i] - (β0 + β1 * xs[i] + β2 * zs[i]); } }, new[] { 0.0, 0.0, 0.0 }, // initial guess for β' ys.Length); // number of samples Console.WriteLine(); Console.WriteLine("Aim: fit a linear 2D regression model to four samples"); Console.WriteLine(" Model: y' = β0 + β1 * x + β2 * z"); Console.WriteLine(" Regressors: x and z (grid points)"); Console.WriteLine(" Unknown paramters: β0, β1, β2"); Console.WriteLine(" Design matrix X = [1 xs zs] (4x3 matrix)"); Console.WriteLine(" Parameter vector ε = [β0 β1 β2]^T"); Console.WriteLine(" Residue: ε = y - y' = y - X β"); Console.WriteLine(" Find β' = argmin_β sum(ε²)"); Console.WriteLine("Fit: y' = {0} + {1} x + {2} z", fit.OptimizedParameters[0], fit.OptimizedParameters[1], fit.OptimizedParameters[2]); }
/// <summary> /// Curve fitting using the Fit... convenience functions /// </summary> static void CurveFittingExamples(LMBackend solverType) { var solver = new LMSolver(optimizerBackend: solverType); // 1st example: fit a model that is non-linear in its parameters // y' = p1 * sin(p2 * t + p3) + p4 // to some noisy data (t, y) // => minimize sum((y - y')²) // // for generating some noise var rand = new Random(12345); // sample points (here: equidistant) var ts = Enumerable.Range(0, 100).Select(i => i * 0.01).ToArray(); // signal: "measured" values at sample points var sins = Enumerable.Range(0, 100) .Select(i => 2.0 * Math.Sin(3.0 * ts[i] + 0.25) + rand.NextDouble() * 0.02) .ToArray(); // FitCurve evaluates the model p[0] * Math.Sin(p[1] * t + p[2]) + p[3] // for each t and computes the residual based on the corresponding y value var fit1D = solver.FitCurve((t, p) => p[0] * Math.Sin(p[1] * t + p[2]) + p[3], new[] { 1.0, 1.0, 1.0, 1.0 }, ts, sins); Console.WriteLine(); Console.WriteLine("Aim: fit a sine wave to noisy data"); Console.WriteLine("Fit: y' = {0} sin({1} x + {2}) + {3}", fit1D.OptimizedParameters[0], fit1D.OptimizedParameters[1], fit1D.OptimizedParameters[2], fit1D.OptimizedParameters[3]); // 2nd example: fit a linear plane to some sample points // (cf. GenericMinimizationExamples for doing the same with // the generic Minimization API) // grid points var xs = new[] { -1.0, -1.0, 1.0, 1.0 }; var zs = new[] { -1.0, 1.0, -1.0, 1.0 }; // data points/samples var ys = new[] { 0.0, 1.0, 1.0, 2.0 }; var fitPlane = solver.FitSurface((x, z, p) => p[0] + p[1] * x + p[2] * z, new[] { 0.0, 0.0, 0.0 }, xs, zs, ys); Console.WriteLine(); Console.WriteLine("Aim: fit a plane to four data points"); Console.WriteLine("Fit: y = {0} + {1} x + {2} z", fitPlane.OptimizedParameters[0], fitPlane.OptimizedParameters[1], fitPlane.OptimizedParameters[2]); }