C#, numerical calculation - calculation method and source program of simulated annealing

Simulated Annealing (SA)

Simulated Annealing (SA) is one of the simplest and best-known metaheuristic method for addressing difficult black box global optimization problems whose objective function is not explicitly given and can only be evaluated via some costly computer simulation. It is massively used in real-life applications. The main advantage of SA is its simplicity. SA is based on an analogy with the physical annealing of materials that avoids the drawback of the Monte-Carlo approach (which can be trapped in local minima), thanks to an efficient Metropolis acceptance criterion. When the evaluation of the objective-function results from complex simulation processes that manipulate a large-dimension state space involving much memory, population-based algorithms are not applicable and SA is the right answer to address such issues. This chapter is an introduction to the subject. It presents the principles of local search optimization algorithms, of which simulated annealing is an extension, and the Metropolis algorithm, a basic component of SA. The basic SA algorithm for optimization is described together with two theoretical properties that are fundamental to SA: statistical equilibrium (inspired from elementary statistical physics) and asymptotic convergence (based on Markov chain theory). The chapter surveys the following practical issues of interest to the user who wishes to implement the SA algorithm for its particular application: finite-time approximation of the theoretical SA, polynomial-time cooling, Markov-chain length, stopping criteria, and simulation-based evaluations. To illustrate these concepts, this chapter presents the straightforward application of SA to two classical and simple classical NP-hard combinatorial optimization problems: the knapsack problem and the traveling salesman problem. The overall SA methodology is then deployed in detail on a real-life application: a large-scale aircraft trajectory planning problem involving nearly 30,000 flights at the European continental scale. This exemplifies how to tackle nowadays complex problems using the simple scheme of SA by exploiting particular features of the problem, by integrating astute computer implementation within the algorithm, and by setting user-defined parameters empirically, inspired by the SA basic theory presented in this chapter.

Simulated Annealing (SA)

Simulated annealing (SA) is one of the simplest and best-known meta-heuristic methods for solving difficult black-box global optimization problems, where the objective function is not explicitly given and can only be evaluated by some expensive computer simulations. It is used a lot in real life. The main advantage of SA is its simplicity. SA is based on an analogy to physical annealing of materials, avoiding the disadvantages of Monte Carlo methods (possibility of being trapped in local minima) due to the effective Metropolis acceptance criterion. When the evaluation of the objective function is produced by complex simulation procedures that deal with large-dimensional state spaces involving large amounts of memory, population-based algorithms are not applicable, and SA is the right answer to these problems. This chapter is an introduction to the topic. The principle of local search optimization algorithm is introduced, in which simulated annealing algorithm is its extension, and Metropolis algorithm is the basic component of SA. The basic SA algorithm for optimization is described, along with two fundamental theoretical properties of SA: statistical equilibrium (inspired by elementary statistical physics) and asymptotic convergence (based on Markov chain theory). This chapter surveys the following practical problems of interest to users wishing to implement SA algorithms for their specific applications: finite-time approximations to theoretical SA, polynomial-time cooling, Markov chain lengths, stopping criteria, and simulation-based evaluation. To illustrate these concepts, this chapter applies SA directly to two classical and simple classical NP-hard combinatorial optimization problems: the knapsack problem and the traveling salesman problem. Then, the overall SA approach is deployed in detail in a practical application: a large-scale aircraft trajectory planning problem involving nearly 30,000 flights across the European continent. This exemplifies how simple schemes of SA can be exploited to solve today's complex problems by exploiting problem-specific features, integrating savvy computer implementations in algorithms, and setting users empirically, inspired by the fundamental theory of SA presented in this chapter. Defined parameters.

Simulated annealing C# source program

using System;

namespace Legalsoft.Truffer
{
    /// <summary>
    /// simulated annealing
    /// </summary>
    public class Anneal
    {
        public Ranq1 myran;

        public Anneal()
        {
            this.myran = new Ranq1(1234);
        }

        public void order(double[] x, double[] y, int[] iorder)
        {
            const double TFACTR = 0.9;

            int i1;
            int i2;
            int nn;
            int[] n = new int[6];
            double path = 0.0;
            double t = 0.5;
            int ncity = x.Length;
            int nover = 100 * ncity;
            int nlimit = 10 * ncity;
            for (int i = 0; i < ncity - 1; i++)
            {
                i1 = iorder[i];
                i2 = iorder[i + 1];
                path += alen(x[i1], x[i2], y[i1], y[i2]);
            }
            i1 = iorder[ncity - 1];
            i2 = iorder[0];
            path += alen(x[i1], x[i2], y[i1], y[i2]);

            //Console.Write(@fixed);
            for (int j = 0; j < 100; j++)
            {
                int nsucc = 0;
                for (int k = 0; k < nover; k++)
                {
                    do
                    {
                        n[0] = (int)(ncity * myran.doub());
                        n[1] = (int)((ncity - 1) * myran.doub());
                        if (n[1] >= n[0])
                        {
                            ++n[1];
                        }
                        nn = (n[0] - n[1] + ncity - 1) % ncity;
                    } while (nn < 2);
                    if (myran.doub() < 0.5)
                    {
                        n[2] = n[1] + (int)(Math.Abs(nn - 1) * myran.doub()) + 1;
                        n[2] %= ncity;
                        double de = trncst(x, y, iorder, n);
                        bool ans = metrop(de, t);
                        if (ans)
                        {
                            ++nsucc;
                            path += de;
                            trnspt(iorder, n);
                        }
                    }
                    else
                    {
                        double de = revcst(x, y, iorder, n);
                        bool ans = metrop(de, t);
                        if (ans)
                        {
                            ++nsucc;
                            path += de;
                            reverse(iorder, n);
                        }
                    }
                    if (nsucc >= nlimit)
                    {
                        break;
                    }
                }
                //Console.Write("{0:6}", "\n");
                //Console.Write("{0:6}", "T = ");
                //Console.Write("{0,12:6}", t);
                //Console.Write("{0,12:6}", "     Path Length = ");
                //Console.Write("{0,12:6}", path);
                //Console.Write("{0:6}", "\n");
                //Console.Write("{0:6}", "Successful Moves: ");
                //Console.Write("{0:6}", nsucc);
                //Console.Write("{0:6}", "\n");
                t *= TFACTR;
                if (nsucc == 0)
                {
                    return;
                }
            }
        }

        public double revcst(double[] x, double[] y, int[] iorder, int[] n)
        {
            double[] xx = new double[4];
            double[] yy = new double[4];
            int ncity = x.Length;
            n[2] = (n[0] + ncity - 1) % ncity;
            n[3] = (n[1] + 1) % ncity;
            for (int j = 0; j < 4; j++)
            {
                int ii = iorder[n[j]];
                xx[j] = x[ii];
                yy[j] = y[ii];
            }
            double de = -alen(xx[0], xx[2], yy[0], yy[2]);
            de -= alen(xx[1], xx[3], yy[1], yy[3]);
            de += alen(xx[0], xx[3], yy[0], yy[3]);
            de += alen(xx[1], xx[2], yy[1], yy[2]);
            return de;
        }

        public void reverse(int[] iorder, int[] n)
        {
            int ncity = iorder.Length;
            int nn = (1 + ((n[1] - n[0] + ncity) % ncity)) / 2;
            for (int j = 0; j < nn; j++)
            {
                int k = (n[0] + j) % ncity;
                int l = (n[1] - j + ncity) % ncity;
                int itmp = iorder[k];
                iorder[k] = iorder[l];
                iorder[l] = itmp;
            }
        }

        public double trncst(double[] x, double[] y, int[] iorder, int[] n)
        {
            double[] xx = new double[6];
            double[] yy = new double[6];
            int ncity = x.Length;
            n[3] = (n[2] + 1) % ncity;
            n[4] = (n[0] + ncity - 1) % ncity;
            n[5] = (n[1] + 1) % ncity;
            for (int j = 0; j < 6; j++)
            {
                int ii = iorder[n[j]];
                xx[j] = x[ii];
                yy[j] = y[ii];
            }
            double de = -alen(xx[1], xx[5], yy[1], yy[5]);
            de -= alen(xx[0], xx[4], yy[0], yy[4]);
            de -= alen(xx[2], xx[3], yy[2], yy[3]);
            de += alen(xx[0], xx[2], yy[0], yy[2]);
            de += alen(xx[1], xx[3], yy[1], yy[3]);
            de += alen(xx[4], xx[5], yy[4], yy[5]);
            return de;
        }

        public void trnspt(int[] iorder, int[] n)
        {
            int ncity = iorder.Length;
            int[] jorder = new int[ncity];
            int m1 = (n[1] - n[0] + ncity) % ncity;
            int m2 = (n[4] - n[3] + ncity) % ncity;
            int m3 = (n[2] - n[5] + ncity) % ncity;
            int nn = 0;
            for (int j = 0; j <= m1; j++)
            {
                int jj = (j + n[0]) % ncity;
                jorder[nn++] = iorder[jj];
            }
            for (int j = 0; j <= m2; j++)
            {
                int jj = (j + n[3]) % ncity;
                jorder[nn++] = iorder[jj];
            }
            for (int j = 0; j <= m3; j++)
            {
                int jj = (j + n[5]) % ncity;
                jorder[nn++] = iorder[jj];
            }
            for (int j = 0; j < ncity; j++)
            {
                iorder[j] = jorder[j];
            }
        }

        public bool metrop(double de, double t)
        {
            return de < 0.0 || myran.doub() < Math.Exp(-de / t);
        }

        public double alen(double a, double b, double c, double d)
        {
            return Math.Sqrt((b - a) * (b - a) + (d - c) * (d - c));
        }
    }
}
 

Guess you like

Origin blog.csdn.net/beijinghorn/article/details/132128391