元启发式方法之模拟退火算法

模拟退火也叫做蒙特卡罗退火、统计冷却、概率爬山、随机松弛和概率交换算法,它来自于对热力学过程的模拟。为了生成规则晶体,先将原材料加热到熔化状态,再将晶体熔融液徐徐降温,使之凝固成晶体结构。在冷却过程中,如果降温太快,则会带来一些不良后果,特别是导致所形成的晶体不够规则,并且能量远远高于一个完美结构的晶体。物理系统和优化问题之间有明显的相似点,例如,物理系统中的能量就相当于优化问题的评估函数;快速淬火就相当于局部搜索;徐徐退火就相当于模拟退火的过程;温度就相当于模拟退火的控制参数T(后面有详细内容)等等。

在搜索过程中如果过早结束,就会陷入局部最优的情况,为了跳出局部最优,引入一个接受概率P和参数T。在当前解的邻域内选择一点,如果比当前解好,则总是接受它;如果没有当前解好则以接受概率接受它。注意,接受概率中的T是随着时间从大到小变化的(冷却温度),一开始T值很大,近似于随机搜索(随机选择当前解);后来T很小,近似于普通搜索法(选择最优作为当前解)。其中接受概率的定义为:

 

这是针对极大化问题的,如果是极小化问题则只需将指数的分子的两个变量交换位置。

由公式可以看出,当T很大时,则两个点的质量竞争的重要性就很小,对结果影响不大,这是概率接近于0.5,等同于随机选取;当T很小(T=1)时,概率接近于1,这就退化为普通局部搜索法了(每次都选择较优解作为当前解)。因此,T的值选择依据问题而定,既不能太大,也不能太小。另外,当T值固定时,如果新解与当前解质量相当,那么p为0.5;如果新解好于当前解,那么p大于0.5,而且新解越好,接受的概率就越大。这些事实都是符合常理的。      

下面以TSP问题为例,给出模拟退火算法的一种实现(java实现):

import java.util.ArrayList;
import java.util.Random;

import tools.TSPData;

import interfaces.IRunning;

/*
 * 使用模拟退火方法求解TSP问题
 */
public class SASolver implements IRunning{
	//当前解
	private ArrayList current;
	//邻域内下一个解
	private ArrayList next;
	//城市数量
	private int number;
	
	//开始的城市标号
	private int origin;
	//城市信息文件名
	private String file;
	//近似最优解
	private double shortestDist;
	//距离矩阵
	private double[][] distances;
    
	
	public SASolver(String filename)
	{
		file = filename;
		shortestDist = 0;
		current = new ArrayList();
		next = new ArrayList();
	}
	@Override
	public void run() {
	//搜索迭代次数
	int iteration = number * 2;
	//退火温度
        double T = 10000.0;
        //退火速率
        double cRate = 0.9999;
        //凝固温度
        double ST = 0.00001;
        //随机数发生器
        Random rand = new Random(System.nanoTime());
        
        initialSolution();
        
        double dist = getTotalDist(current);
        shortestDist = dist;
        origin = 0;
        
		while(T > ST)
		{
			int count = iteration;
			double nextDist;
			dist = shortestDist;
			while(count > 0)
			{
				getNextSolution();
				nextDist = getTotalDist(next);

				if (nextDist < dist) {
					current = (ArrayList) next.clone();
					shortestDist = nextDist;
				} else {
					double r = rand.nextDouble();
					if (r < Math.exp((dist - nextDist) / T)) {
						current = (ArrayList) next.clone();
						shortestDist = nextDist;
					}
				}
				count--;
			}
			T *= cRate;
		}
        //shortestDist = dist;
        System.out.println("算法结束");
	}
    /*
     * 总是根据当前解生成邻域新解
     */
	private void getNextSolution() {
		
		next = (ArrayList)current.clone();
		
		Random rand = new Random(System.nanoTime());
		//这里的算子:随机交换两个城市的位置(0作为起始点除外)
		int index1 = rand.nextInt(number - 1) + 1;
		int index2 = index1;
		while(index2 == index1)
			index2 = rand.nextInt(number - 1) + 1;
		int temp = next.get(index1);
		next.set(index1, next.get(index2));
		next.set(index2, temp);
		
	}
	private void initialSolution() {
		int i;
		for(i = 0; i < number; i++)
		{
			if(i != origin)
			    current.add(i);
		}
		current.add(0, origin);
		
	}
	private double getTotalDist(ArrayList list) {
		
		double res = 0;
		int i = 0;
		for(; i < number - 1; i++)
			res += distances[list.get(i)][list.get(i + 1)];
		if(number > 1)
			res += distances[list.get(number - 1)][0];
		return res;
	}
	@Override
	public void init() {
		distances = TSPData.getDistances(file);
		number = distances[0].length;
	}
	@Override
	public void print() {
		System.out.println("算法得到的近似最优解为:" + shortestDist);
		System.out.println("该解对应的路径为:");
		int i;
		for(i = 0; i < number; i++)
			System.out.print(current.get(i) + "-->");
		System.out.println(current.get(0));
		
	}
	

}

   这里使用的算子是随机交换两个城市的位置。 实验得到的解(18左右)与最优解(14)很相近。 (待修订)                         


你可能感兴趣的:(碎片,算法,random,string,优化,file,import)