热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

混合整数非线性规划_OM|二维剪板机下料问题(2DGCSP)的混合整数规划精确求解——数学规划的计算智能特征...

作者:路军编者按混合整数规划(MIP),是指同时包含整数变量和连续变量的数学规划。针对二维剪板机下料问题等大规模组合问题,混合整数规划是一
52882e0134a3ad0100a86cc61fa5bcde.png

作者:路军

编者按

混合整数规划(MIP),是指同时包含整数变量和连续变量的数学规划。针对二维剪板机下料问题等大规模组合问题,混合整数规划是一种速度快,精度高的求解途径,上较其他方法具有明显优势。本文介绍了二维剪板机下料问题(2D-GCSP)的混合整数规划模型并基于BWMV bin packing数据库进行模型的实现,生成排样图,为数据库中的案例提出解决方案。

二维剪板机下料问题(2D-GCSP) 的混合整数规划是最优美的整数规划模型之一。以往很多人认为像2D-GCSP这样的问题由于本质上的递归性,很难建立成混合整数规划模型,但是持这种观点的人忽略了数学规划的智能特征。所谓计算智能是如果将问题描述给机器,则机器可以自行得到问题的结果。例如很多元启发算法都被称为计算智能算法,就是因为他们好像能够通用性地解决一些问题。这也给我们一个启示,就是不怕问题刁钻,只要我们把问题的特征用建模逻辑描述出来,那么它就是合理的数学规划模型,就能为我们工作。

2D-GCSP二维剪板机下料问题

2D-GCSP中的G来自法文Guillotine。约瑟夫·吉约坦( Joseph Guillotin )是法国一名信仰人文主义的医生,他提出认为死刑应以快速及人道的方式执行以降低死刑的痛苦。1792年,吉约坦医生与一位法国刽子手合作,动手制造了一台断头台的原型机,从此新型断头台便正式面世,并以他的姓氏Guillotine命名 。为了纪念这位医生,以后凡是瞬间切断东西的方式都被命名为Guillotine。在航母、飞机、建筑等制造工业上经常会使用一种剪板机对金属板材进行切割下料,每次必须横向或纵向切断整个板材,下料图案十分独特,无论多少次切割,就是你总能找到一刀切位置。下图是剪板机。

3aa9fe48b23212697e5bc1f6fbc59258.png
e590aa077425863e92267fe016ac1492.png

问题数据

附件一是BWMV bin packing数据库中第40个例子。第一行表示例子编号,第二行30,30表示原始板材大小,80表示总计下料需求板材的种类数。第三行开始是需求定义,例如第三行表示需要5X8的小板材1件,第四行表示需要8X8的小板材1件。所有板材必须从WXH=30X30的大板材上G方式剪裁下来,目标是规划下料方式以极小化所需要的大板材数量。对原始数据,用以下符号表示:W-原始板材宽度,H-原始板材高度,n-需求小板材数量,ai, bi-第i类小板材宽度和高度,mi-第i类小板材的需求数量。

整数规划模型

Silva等[1]首次给出G-下料的整数规划模型,此模型描述真实下料时的逻辑。如下图所示,工人在下料时候要依照给出的需求下料,那么下料后的余料被放起来准备之后的小板材下料。于是除了原始板材外,随着下料的进展,待切割板材会堆积成板材库。那么逻辑是要保证某类待切割的板材数量大于从该类下料小板材的数量。

用xij表示第i种需求小板材从第j种余料(包括原始板材)中下料的数量。用0-1数值矩阵aijk表示从j类余料中下料i类小板擦会产生一件余料k,于是根据逻辑(即工人始终能够找到需要的余料,或者说余料的数量大于将要在该类余料进行下料的数量):

4816966ef38c2da0a4eaf0c9ec738f12.png

这里的m是所有的余料种类,j=0表示原始板材(即W×H板材)。

另外,下料需求需要被满足:

562a165009dab205a10f108910ab23a8.png

目标当然是原始板材使用数量最少:

394308e864599f1ee45753e7c0a81038.png

下图是根本逻辑:从余料j(j=0表示原始板材)上下料i会产生两块 新生的余料备用。生成何种余料用三维0-1常数矩阵aijk。约束(1)表示一定要保证有足够的余料可用于需求小板材的下料。

f3f2bf21882bd5a935e44844b3315362.png

至于如何生成aijk, Silva等[1]建议首先做枚举。本文以下直接将这个枚举写进模型里!

模型实现

上面的模型(1)-(3)比较抽象,现在把它具体化,并把对aijk的枚举写进模型。

首先,对余料从0到M的编码抽象性太强,这里把他们具体化为板材的长度和宽度,即使用x[w][h][i]表示从大小为wXh余料上切割第i类小板材的数量。于是目标是极小化从WxH板材(原始板材)上切割出所有小板材的数量,即:

6c69df1de2e41223025402f3a0496061.png

也就是使用(4)代替上面的(3)。

其次必须满足所有需求:

90b8b18a8561a7a1b501b34d721c6f59.png

也就是用(5)取代上面的(2)。

最后用下面的(6)取代上面的(1):

846e52375499b8e1d6fdab38ed2d1965.png

这个看起来复杂,仔细分析会发现跟上面的(1)是一丘之貉,不过好处是扔掉了aijk。

整体模型看起来是这个样子的(数据区采用小案例,节省空间):

min sum{i=1,...,n}x[W][H][i] //(4)
subject tosum{w&#61;1,...,W;h&#61;1,...,H;w>&#61;a[i];h>&#61;b[i]}x[w][h][i] >&#61;m[i]|i&#61;1,...,n //(5)sum{w&#61;1,...,W;h&#61;1,...,H;i&#61;1,...,n;w>&#61;a[i];h>&#61;b[i];w&#61;&#61;(a[i]&#43;w1);b[i]&#61;&#61;h1}x[w][h][i]&#43;-->sum{w&#61;1,...,W;h&#61;1,...,H;i&#61;1,...,n;w>&#61;a[i];h>&#61;b[i];h&#61;&#61;(b[i]&#43;h1);w1&#61;&#61;w}x[w][h][i]-->>&#61;sum{i&#61;1,...,n;w1>&#61;a[i];h1>&#61;b[i]}x[w1][h1][i]-->| w1&#61;1,...,W;h1&#61;1,...H;(h1&#43;w1)<(H&#43;W) //(6)
wheren is an integerW,H are numbersdt is a set of numbera[i],b[i],m[i] are numbers|i&#61;1,...,nx[w][h][i] is a variable of nonnegative integer|w&#61;1,...,W;h&#61;1,...,H;i&#61;1,...,n
data_relationn&#61;_$(dt)/3a[i]&#61;dt[3(i-1)&#43;1] | i&#61;1,...,nb[i]&#61;dt[3(i-1)&#43;2] | i&#61;1,...,nm[i]&#61;dt[3i] | i&#61;1,...,n
dataW&#61;10H&#61;10dt&#61;{
2 1
6 1
10 1
1 1
8 1
3 1
1 1
1 1
6 1
1 1
4 1
9 1
1 1
9 1
4 1
2 1
3 1
9 1
4 1
9 1}

上面的模型用&#43;Leapms解析并用cplex命令调用cplex求解即可秒解。

下料排样图的生成

上面的模型只给出x[w][h][i]的最优值&#xff0c;即从wxh余料中切割第i类小板材的具体数量&#xff0c;由此信息得到排样图是另外一个挑战。首先看结果样子&#xff08;以上面80小板材数据为例&#xff09;&#xff1a;

f6a4084151ad52c44c66c0cb3ed81943.png

而后看技术。这里技术包括用&#43;Leampms编程接口&#xff0c;还有细致的逻辑思考&#xff0c;这里不再赘述&#xff0c;只贴出c&#43;&#43;代码&#xff0c;此源码能够一次求出文件中500个案例&#xff1a;

#include
#include
using namespace std;extern int W,H,n;
extern int w[1000],h[1000],m[1000];
extern ofstream ofcad;
extern int nInstance;class c_sheet{
public:int w,h; //尺寸int n,nl; //数量&#xff0c;已定位的数量int x[1000],y[1000]; //坐标int item[1000]; //下料bool good;c_sheet(){w&#61;W;h&#61;H;n&#61;nl&#61;0;}c_sheet(int w,int h){this->w&#61;w;this->h&#61;h;n&#61;0;good&#61;false;}void reset(){w&#61;h&#61;n&#61;nl&#61;0;good&#61;false;}void addItem(int item);void print();void draw(ofstream &off);bool cut();bool cut(int x, int y);
};int prepare(int instance&#61;0);//准备模型
int findSheet(int w, int h);
extern int nSheet;
extern c_sheet sheet[1000];
#include
#include
using namespace std;extern int W,H,n;
extern int w[1000],h[1000],m[1000];
extern ofstream ofcad;
extern int nInstance;class c_sheet{
public:int w,h; //尺寸int n,nl; //数量&#xff0c;已定位的数量int x[1000],y[1000]; //坐标int item[1000]; //下料bool good;c_sheet(){w&#61;W;h&#61;H;n&#61;nl&#61;0;}c_sheet(int w,int h){this->w&#61;w;this->h&#61;h;n&#61;0;good&#61;false;}void reset(){w&#61;h&#61;n&#61;nl&#61;0;good&#61;false;}void addItem(int item);void print();void draw(ofstream &off);bool cut();bool cut(int x, int y);
};int prepare(int instance&#61;0);//准备模型
int findSheet(int w, int h);
extern int nSheet;
extern c_sheet s

#include
#include
#include "leap.h"
#include "Guillotine.h"
using namespace std;int W,H,n;
int w[1000],h[1000],m[1000];
ofstream ofcad;void addSheet(int w, int h, int item, int ns);
int dealInstance();//主函数&#xff0c;循环计算所有500案例
int main(){while(1){if(dealInstance()<0)break;}return 0;
}int dealInstance(){//设置时间char time[]&#61;"600";//准备模型if(prepare()<0)return -1;//if(nInstance<41)return 0;//求解模型c_leap lp;lp.loadLeap("current.leap");lp.cplex("",time,"");//生成板材int ns;for(int w&#61;W;w>0;w--){for(int h&#61;H;h>0;h--){for(int i&#61;0;i0){addSheet(w,h,i,ns);}}}}//剪切板材if(nSheet>1)sheet[0].cut();//输出板材图形char cadfname[64];if(lp.getState()!&#61;IP_OPTIMAL)sprintf_s(cadfname,64,"graphic(%d)(%d_%d)!.scr",nInstance,(int)((nInstance-1)/50)&#43;1,nInstance-(int)((nInstance-1)/50)*50);else sprintf_s(cadfname,64,"graphic(%d)(%d_%d).scr",nInstance,(int)((nInstance-1)/50)&#43;1,nInstance-(int)((nInstance-1)/50)*50);ofcad.open(cadfname);ofcad<<"erase all "<}void addSheet(int w, int h, int item, int ns){int sht&#61;findSheet(w,h);if(sht<0){sht&#61;nSheet&#43;&#43;;sheet[sht].w&#61;w;sheet[sht].h&#61;h;}for(int k&#61;0;k}

#include
#include
#include "leap.h"
#include "Guillotine.h"
using namespace std;ifstream iffd;//原始数据文件句柄
bool iffdOpen&#61;false;
int nInstance&#61;0;//案例编号int prepare(int instance){ //准备模型if(nInstance>500)return -1;//如果没有打开原始数据文件&#xff0c;打开之&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;&#61;const char iffdname[]&#61;"BWMV bin packing instances.txt";if(!iffdOpen){int ntmp;iffd.open(iffdname);iffd>>ntmp;cout<<"ntmp&#61;"<>dummy;iffd>>W>>H>>n;off<<"tW&#61;"<>w[i]>>h[i]>>m[i];off<<"tt"<}
#include
#include
#include "Guillotine.h"int nSheet&#61;0;
c_sheet sheet[1000];int findSheet(int w,int h){for(int i&#61;0;i}void c_sheet::addItem(int item){this->item[n]&#61;item;n&#43;&#43;;
}void c_sheet::print(){cout<<"Sheet"<}bool c_sheet::cut(){bool rt&#61;true;int w1,h1,w2,h2,s1,s2;if(w&#61;&#61;W&&h&#61;&#61;H){nl&#61;n;for(int i&#61;0;i<&#61;n;i&#43;&#43;){x[i]&#61;(int)(i*1.2*W&#43;.5);y[i]&#61;0;w1&#61;w-::w[item[i]];h1&#61;::h[item[i]];s1&#61;findSheet(w1,h1);if(s1>&#61;0)sheet[s1].cut(x[i]&#43;::w[item[i]],y[i]);w2&#61;w;h2&#61;h-::h[item[i]];s2&#61;findSheet(w2,h2);if(s2>&#61;0)sheet[s2].cut(x[i],y[i]&#43;::h[item[i]]);}}return rt;
}bool c_sheet::cut(int xx, int yy){if(nl&#61;&#61;n)return false;int w1,h1,w2,h2,s1,s2;x[nl]&#61;xx;y[nl]&#61;yy;w1&#61;w-::w[item[nl]];h1&#61;::h[item[nl]];s1&#61;findSheet(w1,h1);if(s1>&#61;0)sheet[s1].cut(xx&#43;::w[item[nl]],yy);w2&#61;w;h2&#61;h-::h[item[nl]];s2&#61;findSheet(w2,h2);if(s2>&#61;0)sheet[s2].cut(xx,yy&#43;::h[item[nl]]);nl&#43;&#43;;return true;
}void c_sheet::draw(ofstream &off){bool hangle&#61;true;for(int i&#61;0;i}

原始数据文件见附件二

附件二.txt

参考文献&#xff1a;

[1] Silva E , Alvelos F , J.M. Valério de Carvalho. An integer programming model for two- and three-stage two-dimensional cutting stock problems[J]. European Journal of Operational Research, 2010, 205(3):



推荐阅读
  • 本文介绍了一道来自《紫书》的编程题目——UVa11212 编辑书稿。该问题通过迭代加深搜索(IDA*)算法解决,旨在找到将给定排列转换为升序排列所需的最少步骤。文章提供了详细的解题思路和代码实现。 ... [详细]
  • YB02 防水车载GPS追踪器
    YB02防水车载GPS追踪器由Yuebiz科技有限公司设计生产,适用于车辆防盗、车队管理和实时追踪等多种场合。 ... [详细]
  • 深入解析Android中的SQLite数据库使用
    本文详细介绍了如何在Android应用中使用SQLite数据库进行数据存储。通过自定义类继承SQLiteOpenHelper,实现数据库的创建与版本管理,并提供了具体的学生信息管理示例代码。 ... [详细]
  • 本文介绍了一个使用 C++ 实现的进度条功能,通过自定义函数指针和控制台输出来展示任务完成的进度。 ... [详细]
  • ▶书中第四章部分程序,包括在加上自己补充的代码,有边权有向图的邻接矩阵,FloydWarshall算法可能含负环的有边权有向图任意两点之间的最短路径●有边权有向图的邻接矩阵1 ... [详细]
  • BFS深搜hashtable来判断是横线还是竖线但是为啥还是90分啊呜呜!找不到原因#define_CRT_SECURE_NO_WARNINGS1#include ... [详细]
  • 本文探讨了C++编程语言中声明与定义的区别,以及如何通过内部连接和外部连接来组织源文件,确保代码的正确链接与编译。文章详细解析了不同类型、变量、函数以及类的连接属性,并提供了实用的示例。 ... [详细]
  • 智慧城市建设现状及未来趋势
    随着新基建政策的推进及‘十四五’规划的实施,我国正步入以5G、人工智能等先进技术引领的智慧经济新时代。规划强调加速数字化转型,促进数字政府建设,新基建政策亦倡导城市基础设施的全面数字化。本文探讨了智慧城市的发展背景、全球及国内进展、市场规模、架构设计,以及百度、阿里、腾讯、华为等领军企业在该领域的布局策略。 ... [详细]
  • 辗转相减法在求解最大等比值问题中的应用
    本文探讨了如何利用辗转相减法解决X星球大奖赛中奖金分配的数学问题,通过分析给定的数据点,计算出可能的最大等比值。 ... [详细]
  • 本文介绍了在Windows 7操作系统中设置电脑自动启动的步骤,包括通过BIOS设置来电启动以及使用任务计划程序实现定时开机的功能。此外,还提供了通过键盘、鼠标和网络唤醒等方式实现自动开机的多种方法。 ... [详细]
  • 华硕主板BIOS更新指南(图文)
    本文详细介绍了如何安全有效地更新华硕主板的BIOS,包括准备工作、具体步骤以及注意事项。BIOS是计算机基本输入输出系统的关键组成部分,负责初始化硬件并加载操作系统,定期更新BIOS可以增强系统的稳定性和兼容性。 ... [详细]
  • 本文将指导您如何在Docker环境中高效地搜索、下载Redis镜像,并通过指定或不指定配置文件的方式启动Redis容器。同时,还将介绍如何使用redis-cli工具连接到您的Redis实例。 ... [详细]
  • 本文详细介绍了如何在现有的Android Studio项目中集成JNI(Java Native Interface),包括下载必要的NDK和构建工具,配置CMakeLists.txt文件,以及编写和调用JNI函数的具体步骤。 ... [详细]
  • 机器学习公开课备忘录(三)机器学习算法的应用与大数据集
    机器学习公开课备忘录(三)机器学习算法的应用与大数据集对应机器学习公开课第六周和第10周机器学习算法模型的选择与评价1、对于一个data,可以将data划分为trainingset、t ... [详细]
  • 深入理解Python中的sorted高阶函数
    排序是编程中常见的需求,无论是简单的数字排序还是复杂的对象排序,其核心都是比较两个元素。本文将探讨如何利用Python的高阶函数`sorted()`,通过自定义键函数来实现灵活多样的排序逻辑。 ... [详细]
author-avatar
Mr_ZERO0000000
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有