C# Simulated Annealing Example

[TOC]

using System;

using CenterSpace.NMath.Core;
using CenterSpace.NMath.Analysis;

namespace CenterSpace.NMath.Analysis.Examples.CSharp
{
  class SimulatedAnnealingExample
  {
    /// <summary>
    /// A .NET example in C# showing how to find the minimum of a function using simulated annealing.
    /// </summary>
    static void Main(string[] args)
    {
      Console.WriteLine();

      // The function 0.25x^4 - 0.1x^3 - 20x^2 + 10x + 0.25y^4 - 0.1y^3 - 20y^2 + 10y
      // has a global minimum near (-6.3, -6.3) and three local minima.

      // Using Powell's Method starting at (-1, -1), we always find the global minimum.
      PowellMinimizer powell = new PowellMinimizer();
      DoubleVector minimum = powell.Minimize(bumpyFunction, new DoubleVector(-1.0, -1.0));
      Console.WriteLine("PowellMinimizer starting at (-1, -1) found global minimum: " + bumpyFunction.Evaluate(minimum));
      Console.WriteLine();

      // However, if you're not sure what a good starting point is, you might start
      // at (0, 0 ). In this case, Powell's Method always finds a local minimum.
      minimum = powell.Minimize(bumpyFunction, new DoubleVector(0.0, 0.0));
      Console.WriteLine("But PowellMinimizer starting at (0, 0) found local minimum: " + bumpyFunction.Evaluate(minimum));
      Console.WriteLine();

      // Using simulated annealing, with 10 steps of 100 iterations each, a
      // starting temperature of 10, and a starting point of (0, 0), we sometimes find
      // the global minimum.
      AnnealingScheduleBase schedule = new LinearAnnealingSchedule(3, 100, 3);
      AnnealingMinimizer annealing = new AnnealingMinimizer(schedule);
      // Set keep history flag to true in order to get enough data to improve our annealing schedule.
      annealing.KeepHistory = true;

      int global = 0;
      int reps = 100;
      for (int i = 0; i < reps; i++)
      {
        minimum = annealing.Minimize(bumpyFunction, new DoubleVector(-1.0, -1.0));
        if (bumpyFunction.Evaluate(minimum) < -874)
        {
          global++;
        }
      }

      Console.WriteLine("AnnealingMinimizer starting at (0, 0) found global minimum " + global + " times ");
      Console.WriteLine("in " + reps + " repetitions.");
      Console.WriteLine();

      Console.WriteLine("Annealing history... ");
      Console.WriteLine();
      Console.WriteLine(annealing.History);
      Console.WriteLine();

      // After analysis of the annealing history (annealing.History), we can improve the schedule 
      // with a higher starting temperature to try and get us over the hump between the local and 
      // global minima.
      annealing.Schedule = new LinearAnnealingSchedule(100, 20, 30);

      // Let's increase the steps to 100, the iterations to 20 and the starting
      // temperature to 30.
      global = 0;
      for (int i = 0; i < reps; i++)
      {
        minimum = annealing.Minimize(bumpyFunction, new DoubleVector(-1.0, -1.0));
        if (bumpyFunction.Evaluate(minimum) < -874)
        {
          global++;
        }
      }
      Console.WriteLine("AnnealingMinimizer starting at (0, 0) found global minimum " + global + " times ");
      Console.WriteLine("in " + reps + " repetitions.");

      Console.WriteLine();
      Console.WriteLine("Press Enter Key");
      Console.Read();
    }

    private static MultiVariableFunction bumpyFunction = new MultiVariableFunction(new NMathFunctions.DoubleVectorDoubleFunction(Bumpy));

    private static double Bumpy(DoubleVector v)
    {
      double x = v[0];
      double y = v[1];
      double xTerm = 0.25 * Math.Pow(x, 4) - 0.1 * Math.Pow(x, 3) - 20 * Math.Pow(x, 2) + 10 * x;
      double yTerm = 0.25 * Math.Pow(y, 4) - 0.1 * Math.Pow(y, 3) - 20 * Math.Pow(y, 2) + 10 * y;
      return xTerm + yTerm;
    }

  }  // class

} // namespace


[TOC]