您的位置:首页 > 其它

基于退火算法的启发式下料问题

2016-04-29 15:58 357 查看
刚刚做完最优控制的大作业,总结下所用的模拟退火算法,谈谈自己的理解。
问题就是典型的下料问题。把板材切割成要求数量和规格的产品。其中,输入为板材的大小、产品的数量和大小,输出为余料率、产品的坐标。
第一次接触模拟退火算法,表示这的确是一个不错的方法。对于就最优解的问题,的确能节约不少计算时间。模拟退火算法的精髓就在于其将**收缩**和**扩张**动态结合在一起,得到最优解是收缩的过程,而为了避免陷入局部最优解,又得有扩张的表现。再次印证了我一直以来坚信的一个想法,大自然演化的很巧妙,如果有什么无法解决的问题,或者想有什么创新,就到大自然中去找吧,哈哈,说多了。下面具体谈谈模拟退火。
具体算法概述参见百度百科吧[模拟退火](http://baike.baidu.com/link?url=gPZzOBtDyvJh3KpKlV-kF-YCgIbAxaYxjiIqc6DSyfOULq25aNHB3LeUUHYhDbwbPBkD5m9_yk7t1OKQwOUxrq),我就不写了,我主要说说我的理解。
退火过程中的每个金属分子有能量和状态两种属性,将能量最低时的状态记做r,能量和状态的概率有对应关系,能量越高,分子状态为r的概率越低,反之在最低温度时,r状态的概率趋近于1。将组合优化问题看做金属,解看做状态,那么最优解就是能量最低的状态,同时也定义一个费用函数来表示能量,通常都用T乘某个略小于1的系数。当T值比较高时,状态变化比较活跃,当T值达到最低时,达到最优解的概率趋近于1。
算法步骤:
1,任选一初始解X0。 给定初始温度Tmax;
2,若在该温度达到内循环停止条件,转第3步,否则,从解邻域N(Xi)中随机选取一Xj,计算目标函数的差值,如果小于0,则Xi=Xj,否则,计算exp[(-f(Xj)-f(xi))/T]>random(0,1),则Xi=Xj;重复2
3,更新温度T=d(T),若满足外循环停止条件,中止计算,否则,返回2。
更详细的介绍请看我上传的我们老师讲课的PPT,里面证明了此算法的适用条件,并证明了此算法能够达到全局最优解。
要想应用此算法,问题必须满足以下条件:
1.可达性,即无论起点如何,任何一个状态都可以到达。这样才使我们有得到最优解的可能
2,渐进不依赖起点。由于起点的选择有非常大的随机性,我们的目的是达到全局最优,因此,应渐进的不依赖起点。
3,分布稳定性。包含两个内容:其一是当温度不变时,其马尔科夫链的极限分布存在;其二是当温度渐进0时,其马尔科夫链也有极限分布。(马尔科夫链就是一种随机状态序列,可以直观的理解为一个解)
然后需要确定以下几个量:
1,解的形式
2,邻域的选取
3,初始温度的选取
4,温度下降的规则
5,每一温度下马氏链的迭代步长和停止规则
只要确定了这些,就可以根据上面提到的步骤进行计算了。
对于下料问题,1,将产品的下料顺序看成问题的一个解,启发式安排下料,得出余料率(余料率就是目标函数,其值越小越好,最优解即是余料率最小时的下料顺序)。余料率小于5%时,停止计算;
2,邻域的构造采用2-opt,即随机改变其中两个产品的生产顺序。因为是随机改变两个顺序,所以邻域中每个解的选取概率都是相同的
3,起始温度可以选择T=100,温度下降就用T=T*k,k可以去略小于1的数,比如0.96,终止温度可选10;
4,迭代步长就选用最简单的非时齐,每一温度下只迭代一步。

最后,对于每个解计算余料率时用的启发式方法(对于每个要生产的产品,优先占角)(此部分算法是参考别的论文写的)如下:
1,找到当前板材中的可用角,(只考虑左下角,即└形状的角),如果没有就取一张新的板材,
2,计算下一个要切割的产品占哪个角比较好,规则如下:
1,计算到产品到形成该角以外的其他矩形块(包括板材边)的最小距离Dmin,此值越小越好。
2,如果有n个角的Dmin值相同,则计算此角的贴边率(边重叠总长/产品周长)
3,如果还是有相同的角,就按序号优先级了
3,直到所有的产品都切割完,输出余料率。


//主程序部分
for (; T > 10; T*=0.96)
{
tuihuo(productbuf, material, alproduct, T, ExceStock);//迭代一步
cout << ExceStock << " " << endl;
if (ExceStock <= 0.01)break;
}


//退火算法部分
void tuihuo(deque<stock> &probuf, const stock &matrl, vector<stock> &alpro, double &T, double &excestock)
{
deque<stock> probuf1(probuf);//放置交换后的一个邻域
vector<stock> alpro1;        //放置交换后的解启发式运算结果
twoOpt(probuf, probuf1);
double exstock, exstock1;//余料率
alpro.clear();
exstock = ProductLayout(probuf, matrl, alpro);
exstock1 = ProductLayout(probuf1, matrl, alpro1);

if (exstock1 <= exstock)//如果邻域更好
{
probuf.swap(probuf1);
exstock = exstock1;
alpro = alpro1;
}
else
{
double P = exp((exstock - exstock1)/T);//概率
static default_random_engine e1;
static uniform_int_distribution<unsigned> u1(0, 1);
if (P > u1(e1))
{
probuf.swap(probuf1);
exstock = exstock1;
alpro = alpro1;
}
}
excestock = exstock;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息