/// <summary> /// Computes the maximum descent possible from the vector x in the direction dir. /// </summary> /// <param name="func">Function to find it the greatest descent possible in the given direction.</param> /// <param name="x">Current vector of the minimization Quasi-Newton algorithm.</param> /// <param name="dir">Descent direction vector for the current vector.</param> /// <returns>The value of the maximum descent possible.</returns> public static double Wolfe(CompiledFunc func, Vector x, Vector dir) { double a = 0; double ai = 1; double fPrev = 0, fCurr = 0, diff = 0; double fZero = func.Eval(x); var normDir = dir.Normalize(); double diffZero = (func.Differentiate(x)*normDir).Sum(); while(ai < MaxAlpha) { fPrev = func.Eval(x + a*dir); fCurr = func.Eval(x + ai*dir); if (fCurr > fZero + C1*ai*diffZero || (fCurr > fPrev && ai > 1)) return Zoom(func, x, dir, a, ai, fZero, diffZero); diff = (func.Differentiate(x + ai*dir)*normDir).Sum(); if (Math.Abs(diff) <= -C2*diffZero) return ai; if (diff >= 0) return Zoom(func, x, dir, ai, a, fZero, diffZero); a = ai; ai *= 1.5; } return ai; }
private static double Zoom(CompiledFunc func, Vector x, Vector dir, double aLow, double aHigh, double fZero, double diffZero) { var normDir = dir.Normalize(); double aMid = 0; double fValue = 0; double diff = 0; while (Math.Abs(aLow - aHigh) > EPS) { aMid = aLow + (aHigh - aLow)/2; fValue = func.Eval(x + aMid*dir); if (fValue > fZero + C1*aMid*diffZero || fValue >= func.Eval(x + aLow*dir)) aHigh = aMid; else { diff = (func.Differentiate(x + aMid*dir)*normDir).Sum(); if (Math.Abs(diff) <= -C2*diffZero) return aMid; if (diff*(aHigh - aLow) >= 0) aHigh = aLow; aLow = aMid; } } return aMid; }
protected override Vector Minimize(CompiledFunc f, Vector x = null, Tuple<Vector, Vector> bounds = null) { SeedPopulation(f, bounds); if (x != null) { double fit = f.Eval(x); if (fit < GlobalBestFit) { GlobalBestFit = fit; GlobalBestPosition = x; ParticlesSet[0].BestFit = GlobalBestFit; ParticlesSet[0].BestPosition = GlobalBestPosition; } } while (CurrentIteration < IterationsNumber) { CurrentIteration++; foreach (var particle in ParticlesSet) { particle.Update(); if (particle.BestFit < GlobalBestFit) { GlobalBestFit = particle.BestFit; GlobalBestPosition = particle.BestPosition; } } } return GlobalBestPosition; }
protected override Vector Minimize(CompiledFunc f, Vector x = null, Tuple<Vector, Vector> bounds = null) { CurrentIteration = 0; var b = Matrix.Identity(x.Length); var x1 = new Vector(x); Vector d; double a; while (CurrentIteration < IterationsNumber) { CurrentIteration++; d = -b.Dot(f.Differentiate(x)); a = Searcher(f, x, d); x1 = x + a*d; b = Corrector(f, b, x, x1); if (!Algebra.IsValid(x1) || Algebra.Norm(x1 - x) <= EPS) break; x = x1; } return x; }
/// <summary> /// Computes the BFGS correction formula for inverse hessiana approximation. /// </summary> /// <param name="func">Function to find it the hessiana approximation.</param> /// <param name="b">Current inverse approximation of the hessiana.</param> /// <param name="x">Current vector of the minimization Quasi-Newton algorithm.</param> /// <param name="x1">Next vector of the minimization Quasi-Newton algorithm.</param> /// <returns>Returns a matrix representing the next step in inverse hessiana approximation.s</returns> public static Matrix Bfgs(CompiledFunc func, Matrix b, Vector x, Vector x1) { var sk = new Matrix(x1 - x); var yk = new Matrix(func.Differentiate(x1) - func.Differentiate(x)); var t = b.Dot(sk.Transpose()).Dot(sk).Dot(b)/sk.Dot(b).Dot(sk.Transpose())[0,0]; var t1 = yk.Transpose().Dot(yk)/yk.Dot(sk.Transpose())[0,0]; return b - t + t1; }
public Particle(CompiledFunc func, int dimensions, int neighborsNumber, Tuple<Vector, Vector> bounds, Func<double> random) { Func = func; NumberOfDimensions = dimensions; Bounds = bounds; Neighbors = new Particle[neighborsNumber]; CurrentPosition = BestPosition = new Vector(Enumerable.Range(0, dimensions).Select(i => random())); Velocity = new Vector(Enumerable.Range(0, dimensions).Select(i => random())); CurrentFit = BestFit = func.Eval(CurrentPosition); }
/// <summary> /// Creates the particle set with non-uniform values and selects an initial best position and best fit /// </summary> /// <param name="f">Function to which the minimum will be looking for.</param> /// <param name="bounds">Limits of function space search.</param> private void SeedPopulation(CompiledFunc f, Tuple<Vector, Vector> bounds) { CurrentIteration = 0; double min = bounds.Item1.Min(); double max = bounds.Item2.Max(); var dist = Distributions.ExponentialFunc(1.0 / (min * 2 + max * 2 + 1.5)); ParticlesSet = Enumerable.Range(0, NumberOfParticles) .Select(i => new Particle(f, f.Dimension, NumberOfNeighborsByParticle, bounds, dist)).ToArray(); int index = -1; GlobalBestPosition = new Vector(f.Dimension); for (int i = 0; i < GlobalBestPosition.Length; i++) GlobalBestPosition[i] = bounds.Item1[i] + (bounds.Item2[i] - bounds.Item1[i])/2; GlobalBestFit = f.Eval(GlobalBestPosition); for (int i = 0; i < NumberOfParticles; i++) { if (ParticlesSet[i].IsFeasible() && ParticlesSet[i].BestFit < GlobalBestFit) { index = i; GlobalBestFit = ParticlesSet[i].BestFit; } // Setting particle neighbors for (int j = 0; j < NumberOfNeighborsByParticle; j++) ParticlesSet[i].Neighbors[j] = ParticlesSet[(i + 1 + j) % NumberOfParticles]; } if (index == -1) { ParticlesSet[0].BestPosition = GlobalBestPosition; ParticlesSet[0].BestFit = GlobalBestFit; return; } GlobalBestPosition = ParticlesSet[index].BestPosition; GlobalBestFit = ParticlesSet[index].BestFit; }
/// <summary> /// Algorithmic implementation of optimization model to look for the minimun function value. /// </summary> /// <param name="f">Function to which the minimum will be looking for.</param> /// <param name="x">Optional vector used as started point for the algorithm to look for.</param> /// <param name="bounds">Optional limits of function space search.</param> /// <returns>Returns the minimun vector found by optimizer.</returns> protected abstract Vector Minimize(CompiledFunc f, Vector x = null, Tuple<Vector, Vector> bounds = null);
/// <summary> /// Looks for the vector x that minimizes function f, i.e, vector x such that f(x) <= f(y) for all /// y values in the function search space. /// </summary> /// <param name="f">Function to which the minimum will be looking for.</param> /// <param name="input">Optional vector used as started point for the algorithm to look for.</param> /// <param name="bounds">Optional limits of function space search.</param> /// <returns>Returns a tuple with the minimun vector found by optimizer and the value of the function in this vector.</returns> public Tuple<Vector, double> FindMinimun(CompiledFunc f, Vector input = null, Tuple<Vector, Vector> bounds = null) { var res = Minimize(f, input, bounds); return new Tuple<Vector, double>(res, f.Eval(res)); }