自学内容网 自学内容网

NX二次开发——矩形排料5(基于最低水平线+遗传算法排料策略实现)

目录

一、概述

二、知识回顾

2.1适应度函数的确定

2.2基因编码

2.3遗传算法复制(选择)

2.4遗传算法交叉操作        通过交叉操作可以增加种群个体的多样性,既可以产生更多的优秀解。下面通过顺序编码方法进行改进(网上有很多方法)。注意这里直接用顺序编码方式会产生非法子代,不是结果不好,本文采取整数编码。

2.5遗传算法变异操作        从遗传算法的角度来看,解的进化主要是靠选择机制和交叉策略来完成,变异只是产生新个体的辅助方法,目的在于提高算法的局部搜索能力,避免陷入早熟。通过交叉算子和变异算子的相互配合,共同完成对搜索空间的全局搜索和局部搜索,从而使遗传算法能够良性的搜索以完成最优化问题的寻优过程,变异概率一般不能太大,本次取为0.05左右。

2.5.1位置交换变异

2.5.2旋转变异(基因正负号变化)

三、所用函数代码与运行结果

3.1所用函数代码

3.2运行结果

3.3结果分析


一、概述

        本文前三篇对矩形排料的理论知识已经做出了讲解,第四篇基于最低水平线搜索策略已经实现了NX基于最低水平线排料,这篇主要详细的记录一下基于最低水平线+遗传算法排料策略实现。

二、知识回顾

2.1适应度函数的确定

        上一篇矩形排料3已经对适应度函数进行了认识,这里我进行简单的叙述。参考“下台阶算法”提出了以板材利用率的大小表示适应度函数值的大小,板材利用率越高,适应度函数值越大,定义如下:

/******************************************************************************************
doubleratio         板材的利用率(适应度函数值)
doubleusedArea  需要排样矩形件的面积总和(*100单位转化)
doublewidth  板材宽度
doublemaxHigh       板材排料后最大使用高度,不包括使用完整后的板材
intsymbol  板料个数标识
******************************************************************************************/
ratio = (usedArea * 100.0) / (width * (maxHigh + (symbol - 1)));
2.2基因编码

        用遗传算法解决实际问题时,必需先确定染色体的编码方法。编码就是将问题的解用一种代码来表示,从而将问题的状态空间与遭传算法的码空间相对应,这在很大程度上依赖于所要求解问题的性质。编码是应用遭传算法求解问题时的一个关键步骤 ,编码方法决定了染色体的排列形式,编码的好坏将直接影响到遭传算法的性能和效率。

       由于板材和零件都是矩形,为了使矩形排放时板材的利用率尽可能高,每个零件在具体排放时只能有横放和竖放两种方式。由于每个基因的编码可以为正或负,在本文中统一规定:矩形的编号为正表示矩形横排,即矩形的长边平行于X轴;矩形的编号为负表示矩形竖排,即矩形的长边平行于Y轴 。

        本文采用整数顺序编码方式:先将要排放的每个矩形都统一进行编号,矩形的编号可以为正或负,矩形编号的正负是根据矩形是横放还是竖放来决定的。一个矩形的编号对应一个基因的编码。设要排放的矩形总数为n,n个矩形的编号构成了一个染色体。种群中每条染色体的长度与待排矩形零件总数相同,染色体中每个基因的编码对应相应矩形的编号,所有基因编码的一个排列顺序构成了一个染色体。

        染色体{-2, 1 , 5 , 3 , -4}表示先排 2 号矩形,矩形竖排;接着排 1 号矩形,矩形横排;接下来横排矩形 5 ,然后横排矩形3 ,最后竖排矩形 4 ,如下图1所示:

图1基因编码

2.3遗传算法复制(选择)

        选择操作是为了保证个体的优良特性得以保存并能有效的遗传到下一代中,目的在于保留有效、优良基因,以保证解的质量,提高收敛速度。选择算子,就是依适应度大小,按照某种规则,从当前的种群中选择适应度高的个体遗传到下一代种群中同时淘汰那些适应度值低的个体。本次利用轮盘赌进行选择,其主要实现的思路如下:将种群中所有染色体编号,并根据各自适应值计算按比例分配的概率,依次计算染色体累加概率,产生(0,1)之间随机数,若其最多能大于序列中第m个值,则第m个染色体被随机选择。

  

        个体放入适应度越大,其被选中的概率越高,个体被选择的概率值可以看做在轮盘区间范围,每次轮盘赌算法都会在(0,1)之间产生一个随机数,通过随机数落在轮盘哪个区间来确定被选中个体。注意累计所占比例最后一定是1,如果不为1的话一定计算有误。

2.4遗传算法交叉操作
        通过交叉操作可以增加种群个体的多样性,既可以产生更多的优秀解。下面通过顺序编码方法进行改进(网上有很多方法)。注意这里直接用顺序编码方式会产生非法子代,不是结果不好,本文采取整数编码。

         根据交叉概率p_{i},选择 2个个体 x_{i}x_{j}进行交叉操作。随机选择一个交叉点,在交叉点处,交换 2个个体后半部分得到 2个新的个体x_{i}^{'}x_{j}^{'}, 如下图所示:注意这里数字前的负号只表示矩形是横放还是竖放(在考虑交叉时,看做标记即可)

61354279810

个体x_{i}

97568321410

个体x_{j}

61354321410

个体x_{i}^{'}

97568279810

个体x_{j}^{'}

        很显然,交叉操作可能产生非法个体,即个体中有重复的基因。所以必须对2个新个体的基因进行调整。

**1**找出个体x_{i}^{'}的重复基因1,3,4;个体x_{j}^{'}的重复基因9,7,8;

**2**将1,3,4与9,7,8以及其关联的负号对应交换,得到两个合法的新个体x_{i}^{''}x_{j}^{''},如下所示:

69758321410

个体x_{i}^{''}

13564279810

个体x_{j}^{''}

2.5遗传算法变异操作
        从遗传算法的角度来看,解的进化主要是靠选择机制和交叉策略来完成,变异只是产生新个体的辅助方法,目的在于提高算法的局部搜索能力,避免陷入早熟。通过交叉算子和变异算子的相互配合,共同完成对搜索空间的全局搜索和局部搜索,从而使遗传算法能够良性的搜索以完成最优化问题的寻优过程,变异概率一般不能太大,本次取为0.05左右。
2.5.1位置交换变异

        位置变异的思想是产生[1,n]之间的两个正整数随机数,num1、num2,将两个位置交换。例如:产生的随机数num1=2、num2=6

原染色体:

61354279810

变异后染色体:

62354179810

具体步骤:

**1**在要进行变异的个体中,随机选择2个基因位;

**2**将所选择 2个基因位上的基因值交换,得到 1个新个体。

2.5.2旋转变异(基因正负号变化)

 排列方式变异的思想是:第一步在[1,n]之间产生一个随机数num;第二步在[0,1]之间产生一个随机数 rand,若rand>0.5,刚将其排列方式进行改变,反之,不予理睬,这里所说的变是指排列时矩形是横放还是竖放。

例如:产生的随机数分别为num=5,rand=0.7。

原染色体:

61354279810

变异后染色体:

6135-4279810

三、所用函数代码与运行结果

3.1所用函数代码
//用户定义头文件
#include <atlbase.h>
#include <Windows.h>
#include <vector>
#include <algorithm>
#include "uf.h"
#include "uf_modl.h"
#include "uf_obj.h"
#include "uf_ui.h"
#include "uf_eval.h"
#include "uf_csys.h"
#include <numeric>
#include <algorithm>
#include <random>
#include <stdio.h>
#include <random>
#include <cmath>
#include <numeric>
#include <iostream>
#include <unordered_map>


/*****************************************************************************************************
struct:OutLine1水平线类结构体
doubleOrigin水平线起始x位置
doubleEnd水平线终止x位置
doubleHeight水平线高度
******************************************************************************************************/
struct OutLine1
{
double Origin;
double End;
double Height;
// 有参数构造函数
OutLine1(const double& origin, const double& end, const double&  height)
: Origin(origin), End(end), Height(height)
{

}
};


//用户定义
/*****************************************************************************************************
Function:vector<vector<int>>NXOpen_GA_RectangularLayout初始化种群
input:intProductsNum每个染色体的尺寸大小
input:intPopulation_size种群大小
return:vector<vector<int>>Population初始化种群后的数据
******************************************************************************************************/
vector<vector<int>> NXOpen_GA_RectangularLayout::Initial_population(int ProductsNum, int Population_size)
{
。。。。。。
}

/*****************************************************************************************************
Function:voidinitLineList1初始化水平线集
input:doubleorigin水平线起始x位置
input:doubleend水平线终止x位置
input:doubleheight水平线高度
input,output:vector<OutLine1>lineList水平线集合
input,output:OutLine1lowestLine最低水平线
input,output:intlowestLineIdx水平线集合中的最低水平线所在位置的ID
******************************************************************************************************/
void NXOpen_GA_RectangularLayout::initLineList1(double origin, double end, double height, vector<OutLine1> &lineList, OutLine1 &lowestLine, int &lowestLineIdx)
{
。。。。。。
}

/*******************************************************************************************************************
Function:voidfindLowestLine1找出最低水平线(如果最低水平线不止一条则选取最左边的那条)
input,output:vector<OutLine1>lineList水平线集合
input,output:OutLine1lowestLine最低水平线
input,output:intlowestLineIdx水平线集合中的最低水平线所在位置的ID
*********************************************************************************************************************/
void NXOpen_GA_RectangularLayout::findLowestLine1(vector<OutLine1> lineList, int &lowestLineIdx, OutLine1 &lowestLine)
{
。。。。。。
}

/*******************************************************************************************************************
Function:doublelineWidth1获得放置矩形件的可用长度
input:intindex水平线集合中的最低水平线所在位置的ID
input:OutLine1lineList水平线集合
return:doubleavailableWidth返回放置矩形件的可用长度
*********************************************************************************************************************/
double NXOpen_GA_RectangularLayout::lineWidth1(int index, vector<OutLine1> lineList)
{

。。。。。。
}

/*******************************************************************************************************************
Function:doublelineHigh1获得放置矩形件的可用高度
input:intindex水平线集合中的最低水平线所在位置的ID
input:OutLine1lineList水平线集合
input,output:doublecontainerHigh板材的高度
return:doubleavailableHigh返回放置矩形件的可用高度
*********************************************************************************************************************/
double NXOpen_GA_RectangularLayout::lineHigh1(int index, vector<OutLine1> lineList, double containerHigh)
{

。。。。。。
}

/*******************************************************************************************************************
Function:doublemaxlineHigh1水平线集合中最大的高度
input:OutLine1lineList水平线集合
return:doublemaxlineHigh1返回放置矩形件的可用高度
*********************************************************************************************************************/
double NXOpen_GA_RectangularLayout::maxlineHigh1(vector<OutLine1> lineList)
{
。。。。。。
}

/*******************************************************************************************************************************************
Function:intsearchBySize1获得候选物品的索引;根据长度搜索矩形件(找出宽度或高度小于目标长度的首个矩形件)
input:doubletargetWidth放置矩形件的可用长度
input:vector<vector<double>>data要放置的矩形物品列表
return:intcandidateIdx返回候选物品的索引
********************************************************************************************************************************************/
int NXOpen_GA_RectangularLayout::searchBySize1(double targetWidth, vector<vector<double>> data)
{
。。。。。。
}

/*******************************************************************************************************************************************
Function:intsearchBySize2获得候选物品的索引;根据长度搜索矩形件(找出宽度或高度小于目标长度的首个矩形件)
input:doubletargetWidth放置矩形件的可用长度
input:doubletargetHigh放置矩形件的可用高度
input:vector<vector<double>>data要放置的矩形物品列表
return:intcandidateIdx返回候选物品的索引
********************************************************************************************************************************************/
int NXOpen_GA_RectangularLayout::searchBySize2(double targetWidth, double targetHigh, vector<vector<double>> data)
{
。。。。。。
}

/***********************************************************************************************************************************
Function:vector<double>rotateNew1对于满足长度小于可用长度的矩形件进行旋转放置(宽度放不下时,对矩形件进行旋转)
input:vector<double>pro要放置的矩形件
return:vector<double>temp返回放置矩形件
*************************************************************************************************************************************/
vector<double> NXOpen_GA_RectangularLayout::rotateNew1(vector<double> pro)
{
。。。。。。
}

/***********************************************************************************************************************************
Function:voidupdateLineList在水平线集合中更新最低水平线
input:intindex水平线集合中的最低水平线所在位置的ID
intput,output:OutLine1newLine新的最低水平线
intput,output:vector<OutLine1>lineList替换新的最低水平线后的水平线集合
*************************************************************************************************************************************/
void NXOpen_GA_RectangularLayout::updateLineList(int index, OutLine1& newLine, vector<OutLine1> &lineList)
{
。。。。。。
}

/***********************************************************************************************************************************
Function:voidinsertLineList在水平线集合的最低水平线后插入新的最低水平线
input:intindex水平线集合中的最低水平线所在位置的ID
intput,output:OutLine1newLine新的最低水平线
intput,output:vector<OutLine1>lineList替换新的最低水平线后的水平线集合
*************************************************************************************************************************************/
void NXOpen_GA_RectangularLayout::insertLineList(int index, OutLine1& newLine, vector<OutLine1> &lineList)
{
。。。。。。
}

/**************************************************************************************************
Function:voidpacking将候选物品排样
input,output:vector<double>pro要放置的矩形件
intput:intlowestLineIdx水平线集合中的最低水平线所在位置的ID
input,output:OutLine1lineList水平线集合
input,output:vector<vector<double>>resultPos排序后的矩形物品列表
intput:OutLine1lowestLine最低水平线
***************************************************************************************************/
void NXOpen_GA_RectangularLayout::packing(vector<double> pro, int &lowestLineIdx, vector<OutLine1> &lineList, vector<vector<double>> &resultPos, OutLine1 lowestLine)
{
。。。。。。
}

/*****************************************************************************************************************
Function:voidenhanceLine1最低水平线宽度小于要排样矩形宽度,提升水平线
intput,output:intindex水平线集合中的最低水平线所在位置的ID
input,output:vector<OutLine1>lineList水平线集合
input,output:  OutLine1lowestLine最低水平线
input:doublecontainerHigh板料高度
input:doublecontainerWidth板料宽度
input:doublelingjianjuli零件距离
input,output:intsymbol板料个数标识
******************************************************************************************************************/
void NXOpen_GA_RectangularLayout::enhanceLine1(int &index, vector<OutLine1> &lineList, double containerHigh, double containerWidth, double lingjianjuli, OutLine1 &lowestLine)
{
。。。。。。
}

/*****************************************************************************************************************
Function:doublecalHighLine1计算板材的最大使用高度
intput:vector<OutLine1>lineList水平线集合
return:doublemaxHigh最大高度
******************************************************************************************************************/
double NXOpen_GA_RectangularLayout::calHighLine1(vector<OutLine1> lineList)
{
。。。。。。
}

/***********************************************************************************************************************************
Function:doublecalUsedRatio1计算排料矩形件的总面积、板材的最低水平线高度,板材利用率1,板材利用率2
intput,output:doubleusedArea排样矩形件的面积总和
input:vector<vector<double>>resultPos排样矩形件信息集合
input:doublewidth板材宽度
input:doubleHigh板料使用的最小高度,不包括使用完整后的板材
input:vector<OutLine1>lineList水平线集合
input:intsymbol板料个数标识
intput,output:doubleratio板材利用率
************************************************************************************************************************************/
void NXOpen_GA_RectangularLayout::calUsedRatio1(double &usedArea, vector<vector<double>> resultPos, double width, double High, vector<OutLine1> lineList, int symbol, double &ratio)
{
。。。。。。
}

/**************************************************************************************************
Function:voidPacking_main将候选物品排样主函数(放置个体)
intput,output:doubleusedArea排样矩形件的面积总和
intput,output:doubleratio板材利用率
intput,output:doubleMaxHeight板料排放物品后达到的最大高度,不包括使用完整后的板材
input:doublecontainer_height板材高度
input:doublecontainer_width板材宽度
input:vector<vector<double>>products要排放的矩形物件集合
return:vector<vector<vector<double>>>resultPos返回将多个板料候选物品排样数据集合
***************************************************************************************************/
vector<vector<vector<double>>> NXOpen_GA_RectangularLayout::Packing_main(double &usedArea,double &ratio, double&MaxHeight, double container_height, double container_width, vector<vector<double>> products)
{
。。。。。。
}

/*****************************************************************************************************************
Function:vector<double>Get_Fitness获得适应度函数
input:vector<vector<double>>products要排放的矩形物件集合
input:doublecontainer_height板材高度
input:doublecontainer_width板材宽度
intput:vector<vector<int>>Population种群集合
return:vector<double>fitness当代种群中的适应度函数值大小集合
******************************************************************************************************************/
vector<double> NXOpen_GA_RectangularLayout::Get_Fitness(vector<vector<double>> products, double container_height, double container_width, vector<vector<int>> Population)
{
。。。。。。
}

/*****************************************************************************************************************
Function:voidGet_bestAndworst获得当代最佳和最差个体索引
intput,output:intbest_idx当代最佳个体索引
intput,output:doubleworst_idx当代最差个体索引
input:vector<double>fitness当代适应度函数值集合
******************************************************************************************************************/ 
void NXOpen_GA_RectangularLayout::Get_bestAndworst(int &best_idx, int &worst_idx, vector<double> fitness)
{
。。。。。。
}

/*****************************************************************************************************************
Function:voidselect遗传算法选择(复制)操作——轮盘赌思想
intput:vector<vector<int>>Population种群集合
input:vector<double>fitness当代适应度函数值集合
return:vector<vector<int>>Population新的种群集合
******************************************************************************************************************/
vector<vector<int>> NXOpen_GA_RectangularLayout::select(vector<vector<int>> Population, vector<double> fitness)
{
。。。。。。
}

/*****************************************************************************************************************
Function:vector<int>randNum随机产生1到n的数,一共n个,每个只出现一次
intput:int number需要产生的个数
return:vector<vector<int>>random_combination产生随机数集合
******************************************************************************************************************/
vector<int> NXOpen_GA_RectangularLayout::randNum(int number)
{
。。。。。。
}

/*****************************************************************************************************************
Function:intgetRandomNumber随机产生一个在[main,max]区间内的正整数
intput:int min产生随机数的下限
intput:intmax产生随机数的上限
return:intRandomNumber返回产生的随机数
******************************************************************************************************************/
int NXOpen_GA_RectangularLayout::getRandomNumber(int min, int max)
{
。。。。。。
}

/*****************************************************************************************************************
Function:doublegetRandomNumber随机产生一个在[main,max]区间内的double类型
intput:double min产生随机数的下限
intput:doublemax产生随机数的上限
return:doubleRandomNumber返回产生的随机数
******************************************************************************************************************/
double NXOpen_GA_RectangularLayout::getRandomNumber(double min, double max)
{

。。。。。。
}

/*****************************************************************************************************************
Function:voidfindDuplicatePositions查询两个vector中重复的元素并记录下其位置
intput:vector<int> nums1第一个vector
intput:vector<int>nums2第二个vector
intput,output:vector<int> Element第一个与第二个重复数字集合
intput,output:vector<int>positions第一个与第二个重复数字位置集合
******************************************************************************************************************/
void NXOpen_GA_RectangularLayout::findDuplicatePositions(vector<int> nums1, vector<int> nums2, vector<int> &Element, vector<int> &positions)
{
。。。。。。
}

/*****************************************************************************************************************
Function:voidcrossover_inner两个个体进行交叉操作
intput,output:vector<int> individual1第一个个体
intput,output:vector<int> individual2第二个个体
intput:intposition要交叉的位置
******************************************************************************************************************/
void NXOpen_GA_RectangularLayout::crossover_inner(vector<int> &individual1, vector<int> &individual2, int position)
{
。。。。。。
}

/*****************************************************************************************************************
Function:voidcrossover交叉操作
intput,output:vector<vector<int>> Population种群集合
intput:double PC交叉概率
******************************************************************************************************************/
void NXOpen_GA_RectangularLayout::crossover(vector<vector<int>> &Population, double PC)
{
。。。。。。
}

/*****************************************************************************************************************
Function:voidmutation变异操作
intput,output:vector<vector<int>> Population种群集合
intput:double PM变异概率
******************************************************************************************************************/
void NXOpen_GA_RectangularLayout::mutation(vector<vector<int>> &Population, double PM)
{
。。。。。。
}

/*****************************************************************************
Function:voidprint打印输出信息
intput,output:doubled排样矩形件的面积总和
input:boolISEnter是否换行
注意:下边重载函数类似
******************************************************************************/
void NXOpen_GA_RectangularLayout::print(const double &d, bool ISEnter)
{
char msg[50];
sprintf(msg, "%f", d);
logical response = 0;
UF_UI_is_listing_window_open(&response);
if (!response) UF_UI_open_listing_window();
UF_UI_write_listing_window(msg);
if (ISEnter) UF_UI_write_listing_window("\n");
}

void NXOpen_GA_RectangularLayout::print(const char * msg, bool ISEnter)
{
logical response = 0;
UF_UI_is_listing_window_open(&response);
if (!response) UF_UI_open_listing_window();
UF_UI_write_listing_window(msg);
if (ISEnter) UF_UI_write_listing_window("\n");
}

void NXOpen_GA_RectangularLayout::print(const int &i, bool ISEnter)
{
char msg[50];
sprintf(msg, "%d", i);
logical response = 0;
UF_UI_is_listing_window_open(&response);
if (!response) UF_UI_open_listing_window();
UF_UI_write_listing_window(msg);
if (ISEnter) UF_UI_write_listing_window("\n");
}
3.2运行结果

基于最低水平线算法+遗传算法的NX矩形排料-CSDN直播具体运行结果看下图所示:

动图太大上传不了,这里有视频链接,大家可以查看。

3.3结果分析

        有3.2运行结果效果图可以看出,遗传算法计算的并不是最好的,只是在有限的时间内进行相对最优的求解,与第四章中的基于最低水平线搜索策略相比总是给人的很差的感觉,这里值得说明的是,本次采用的是最低水平线法,由于相较于基于最低水平线搜索策略其存在弊端,所以避免不了,下一篇我想利用基于最低水平线搜索策略+遗传算法看一看效果。当然这里所说的效果不好只是相对的,因为我主要是思路是做一款支持设置零件间距离修改,和零件与板料间距离,以及超过最大板材高度后可以自动在另一个完整的板材上进行排料,为了效果明显,我故意设置其宽度和高度,实际的应用中并不是这样差,应该可以达到80%左右。


原文地址:https://blog.csdn.net/weixin_47753171/article/details/137993043

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!