C#,数值计算——模拟退火(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.

模拟退火(SA)

模拟退火(SA)是解决困难的黑盒全局优化问题的最简单和最著名的元启发式方法之一,其目标函数没有明确给定,只能通过一些昂贵的计算机模拟来评估。它在现实生活中被大量使用。SA的主要优点是它的简单性。SA基于与材料物理退火的类比,由于有效的Metropolis验收标准,避免了蒙特卡罗方法的缺点(可能被困在局部极小值中)。当目标函数的评估是由复杂的模拟过程产生的,这些模拟过程处理涉及大量内存的大维状态空间时,基于群体的算法不适用,SA是解决这些问题的正确答案。本章是对这个主题的介绍。介绍了局部搜索优化算法的原理,其中模拟退火算法是其扩展,Metropolis算法是SA的基本组成部分。描述了优化的基本SA算法,以及SA的两个基本理论性质:统计平衡(受初等统计物理学启发)和渐近收敛(基于马尔可夫链理论)。本章调查了希望为其特定应用实现SA算法的用户感兴趣的以下实际问题:理论SA的有限时间近似、多项式时间冷却、马尔可夫链长度、停止标准和基于模拟的评估。为了说明这些概念,本章将SA直接应用于两个经典和简单的经典NP-难组合优化问题:背包问题和旅行商问题。然后,将总体SA方法详细部署在实际应用中:一个涉及欧洲大陆近30000次飞行的大型飞机轨迹规划问题。这举例说明了如何利用SA的简单方案来解决当今复杂的问题,方法是利用问题的特定特征,在算法中集成精明的计算机实现,并在本章提出的SA基本理论的启发下,根据经验设置用户定义的参数。

模拟退火C#源程序

using System;

namespace Legalsoft.Truffer
{
    ///


    /// simulated annealing
    ///

    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));
        }
    }
}
 

你可能感兴趣的:(C#数值计算,Numerical,Recipes,算法,开发语言,c#,数值计算,模拟退火算法)