ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: 饮苦食毒

[求助] 还是靠VBA来帮我计算最少用你多少根棍子吧

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2012-9-22 04:37 | 显示全部楼层
本帖已被收录到知识树中,索引项:其他结构和算法
本帖最后由 灰袍法师 于 2012-9-22 04:44 编辑

0.3 beta 版
什么参数都取消了,扔到程序内部随机生成
本版最大改变是
1 评估切割方案的标准,从之前的 产品权重,改为“本切割方案能够切出最多的产品”,实际上也就是希望尽可能少的方案数完成全部产品
2 随机决定产品的切割顺序,而不是之前的从最长的产品开始切。
3 每次生成全部切割方案以后,把 使用次数只有1的切割方案,其包含的产品,其切割顺序往前提升(即下一次优先切割这些落后分子)
结果还不错。
虽然往往不能找出最低的原料消耗,但相差也极少,而且切割方案数一般比较低。
我现在越来越倾向于“先生成原料切割方案库”,然后从中抽选的做法了,这个做法别的不说,光是不需要每次切割都重新生成一次切割方案,就能提速几十倍。
而且最明显的是,生成了切割方案库以后,找出最优解其实就只是一个线性规划问题
线性规划求解部分 可以扔给其他软件做,如 Lingo 之流
这对于验证自己的程序效率,就有了一个很好的参照物。


一维下料.rar

86.82 KB, 下载次数: 966

评分

5

查看全部评分

TA的精华主题

TA的得分主题

发表于 2012-9-23 03:02 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
灰袍法师 发表于 2012-9-22 04:37
0.3 beta 版
什么参数都取消了,扔到程序内部随机生成
本版最大改变是

测试了这个版本,用理论最优797根这组数据连续运行10次(搜索=100),结果如下:
序号         用量      方案       耗时
1               800       46          98
2               800       44         100
3               800       43         101
4               800       43         98
5               800       45         99
6               800       48         99
7               799       49         101
8               800       43         101
9               800       43         102
10             798       51         97
=====================
从上面数据看,就解的质量而言,我想这个版本应该优于你前面提及的Go Nest 1D了吧(我下了你在哪个地方贴的这个软件,装了后用不起来,不知何故?)。

关于797这组数据,用我的程序记录下的通过随机切割得到的解的分布数据如下:(方案连胜=500,方式连胜=75,总耗时在92s左右)
需求
797
798
799
800
801
802
803
804
频次
0
2
69
208
177
103
13
2
概率
0.0%
0.3%
12.0%
36.2%
30.8%
17.9%
2.3%
0.3%

上面数据说明:随机切能产生最优解(基本可以猜想,797的解不存在),但概率较小,而近优解则很容易出现(800及以下的出现概率为48.5%)。
针对一维的下料问题,随机切与蚁群、遗传、退火等高级算法类似,其算法复杂性与数据量近乎无关,但得到的结果估计应该不会逊色于蚁群、遗传、退火等高级算法。

下面链接中的这篇论文,我只看懂个大概,其解题的思路应该与你现在想的相同的,也是先取得切割方式库,再从中选取80-100个方式,用整数规划法求得最优解。
http://wenku.baidu.com/view/4174c4323968011ca3009143.html
对此种解题思路,我有两点不解:
1.如何从海量的方式中选取用于整数规划的方式集?其中提到的用【有效度】来评价,而其定义的【有效度】来自于之前的线性规划所得的解,那岂不是要用这海量的方式集先进行一次线性规划?可能吗?
2.整数规划法本身就是个NP难问题,对规模稍大一点的数据,其时间能耗得起吗?
======================================
在这个问题上,能与法师在一个层面上进行探讨,倍感荣幸!

TA的精华主题

TA的得分主题

发表于 2012-9-23 03:52 | 显示全部楼层
本帖最后由 灰袍法师 于 2012-9-23 03:58 编辑
三坛老窖 发表于 2012-9-23 03:02
测试了这个版本,用理论最优797根这组数据连续运行10次(搜索=100),结果如下:
序号         用量     ...

逐点讨论一下吧
我的VBA跟 Go Nest 1D 相比,确实在很多情况都能做得比它更好
不过 也有很多情况比不上它。
比如 多根可用原料,我的程序目前完全没处理。

选取 方案集,然后再从方案集选最终结果
其实是把原来的 多重背包 问题(n个产品放入m个原料),这是整数规划问题。
转化为 线性规划问题 (k种切割方案组合出n种产品),这只是求解线性方程组而已。
求解线性方程组是很容易的,目前的常见软件求解几十万个变量的线性方程组应该没啥问题。
虽然这个线性方程组还是要求整数解,但是求到小数解以后,也大致可以判断整数解的可行范围,上下限。
实际上有个算法是:线性方程组的精确小数解直接取整丢弃小数位,这样就会得到一个没有足够产品的解
这时候再对 不够的产品 进行一次求解。
等于不断减少需要的产品。

另一方面,我也想试一下 Lingo 求解整数约束的线性方程组有多强(直接求解多重背包是完全不可行的,我试过了,速度慢的要自杀,而且求解结果非常差。)
这种做法其实是作了一个假设:选出来的 方案集,必然包括最优解的所有方案,或者包括近似最优解的所有方案。
这个假设可以这样证明:
如果存在最优解797根原料,那么最优解的每个切割方案,都必定接近 99.99% 的利用率
所以,只要列举全部利用率高于 99.99 的切割方案即可,这样的切割方案其实并不多。
又,有些切割方案是可以互相等价的,所以只需要找到其中一种组合,则所有与它等价的组合都可以算找到了。
如 1a+2b 和 1A+2c 等价于 2 x (1a + 1b +1c)
所以,方案集虽然不大,但是它组合出来的 可能方案 却是非常大的!
又,实际上我们也不追求最优解,而是所有接近最优解的方案都可以,这也进一步放宽了 对方案集的质量要求。

TA的精华主题

TA的得分主题

发表于 2012-9-23 04:33 | 显示全部楼层
灰袍法师 发表于 2012-9-23 03:52
逐点讨论一下吧
我的VBA跟 Go Nest 1D 相比,确实在很多情况都能做得比它更好
不过 也有很多情况比不上 ...

看你的回帖,有三点收获,不枉熬夜了。
1.求解线性方程组是很容易的,目前的常见软件求解几十万个变量的线性方程组应该没啥问题。----此前不知
2.线性方程组的精确小数解直接取整丢弃小数位,对不够的产品进行一次求解-----从未见过,也不曾想到是思路
3.假设及其证明--------豁然开朗
------------------------
谢谢法师的解惑!

TA的精华主题

TA的得分主题

发表于 2012-9-23 20:19 | 显示全部楼层
本帖最后由 灰袍法师 于 2012-9-25 02:56 编辑

啊哈
列出所有方案,然后 线性求解 是可行的
我用理论最佳797的数据测试
先用 VBA 生成 2万多个方案,耗时才几秒。
然后 Lingo 对其 进行整数线性规划,求解时间才20秒,得到 799 用料,方案数55,最大余料 3970 的结果,还不错嘛。

又用6000x1500的一组数据测试,可以轻松找出1504的解,不过切割方案数就比 三坛老窖 的多,要17个

附件包括 自动生成所有原料的 指定数量的切割方案,以及 Lingo 整数线性规划 的求解模型
好处是:
1 支持多种原料同时求解
2 Lingo 求解几万个切割方案也就几十秒到几分钟不等(当然,最好还是运行 .lg4 而不是在Excel里面运行,避免时间太长造成OLE超时)

坏处是:
1 无法进一步追求最大余料,或者最少切割方案,如果Lingo的求解模型加上这些要求,就会变得很慢很慢,求解时间超过一小时,而且结果很差劲!
2 经常出现超额生产产品,需要人手减掉多出来的产品(或者加一段程序处理)
一维下料 方案库 Lingo.rar (596.79 KB, 下载次数: 671)

不过。。。。。。
至少验证了生成一个方案库,然后从中选择“好”的方案,最终也可以得到很不错的结果。
也可以自己用VBA代替Lingo做挑选工作,估计会更快。。。。。。


评分

1

查看全部评分

TA的精华主题

TA的得分主题

发表于 2012-9-24 11:03 | 显示全部楼层
pp9257 发表于 2012-9-20 18:45
其实我发这个图片,只是想说,国内已经有了成熟的 线性材料下料优化软件

42种不同规格,耗时0.3s

既然不愿意与别人分享代码,就别卖弄这些图片

TA的精华主题

TA的得分主题

发表于 2012-9-24 12:19 | 显示全部楼层
840205910 发表于 2012-9-24 11:03
既然不愿意与别人分享代码,就别卖弄这些图片

这个是MSTEEL  里面其中的一个功能---线性优化  免费的,我也没代码啊。。。。

TA的精华主题

TA的得分主题

发表于 2012-9-24 19:40 | 显示全部楼层
本帖最后由 灰袍法师 于 2012-9-24 20:19 编辑
pp9257 发表于 2012-9-24 12:19
这个是MSTEEL  里面其中的一个功能---线性优化  免费的,我也没代码啊。。。。

今天测试了一下 MSteel
这其实是一个 Autocad 的插件,还要安装 autocad ,超级麻烦
使用界面一个窗口+N个弹窗,简洁是简洁,但。。。操作很麻烦!!!
不能导入Excel,只能导入自定格式的txt,又是一件麻烦事。

性能测试如下,左边是已知较优解,右边是MSteel运行结果:

6300x29  x29_8方案 或者 x30_7方案 : MSteel只能算出 6300x30 15方案

6000x58_14方案 : MSteel算出 6000x58 33方案 余料2328

5600x73_12方案 : 只能算出5600x74 12方案

6000x1500 目前已知较优解是 1504 : MSteel默认参数算出 1598,佩服作者真敢把这个结果放出来吖??? 多次人手调允许余料长度,最佳一次算出 1513 (超级麻烦!干吗不做成程序自动!)

3000x797 目前已知较优解是 798原料 56方案,或者799原料 44方案 : MSteel多次人手调参数算出 804 原料 59方案

意见:
最起码,允许余料长度,这个参数就是多余的,明显应该程序自动扫描出最佳的参数,而不是要用户一次一次地输入,运行,拉滑动条看结果。。。。。。
优点是:运行时间很快,不过作为一个c++编译的程序,对数据又只用贪婪发计算一次,不快的话就真该跳楼自杀了。

结论:作为autocad插件,不予置评,作为线材下料计算软件,就是一垃圾!明显没有经过仔细测试和优化。

TA的精华主题

TA的得分主题

发表于 2012-11-29 19:41 | 显示全部楼层
本帖最后由 lee1892 于 2012-11-29 19:53 编辑
灰袍法师 发表于 2012-9-23 20:19
啊哈
列出所有方案,然后 线性求解 是可行的
我用理论最佳797的数据测试

从头到尾仔细看了遍贴子,发现以我目前的水平和精力是不可能自己写出高效的代码了。
貌似前面老窖有很好的算法,奈何即未共享代码也没有把成品的库分享一下。。。
我自己的需求是多种料长求最优排料,把法师的方案库仔细学习了一下,改成了类文件,打算编译后结合Lingo自用。貌似还需要学习一下Lingo。。。

貌似还要学学Lingo的DLL调用。。。

附件是法师的生成方案的类代码,变量名都改成俺习惯的方式了,呵呵。。。

另外,那个超额出来是没错的,另加代码处理就是了。
下料原则本身就是让余料尽可能的集中,我有时间琢磨琢磨你这个代码,不知道有没有可能加入余料长度控制。比如余料在某个不易利用的范围内则该方案得分低,而余料即便很大但可利用价值高则该方案得分反而高。
对于经常性的较小规模是有实际意义的。

NP1D_Plans.rar

2.5 KB, 下载次数: 269

点评

余料长度控制也是可以的,修改 估值函数 的代码,把打分标准改掉就是了  发表于 2012-11-29 20:21

TA的精华主题

TA的得分主题

发表于 2012-12-1 13:47 | 显示全部楼层
本帖最后由 lee1892 于 2012-12-1 14:15 编辑

花了2天时间研究LindoAPI,总算模型搞定,给我来这么个消息:
"License is too small for the given problem."
我吐血啊。。。

查了一下人家的API价格
变量2000->$195,变量8000->$395,变量32000->$695,变量无限->$995
法师这个要设置60000个方案,贵死。。。6000+RMB啊

API快是快,实在是不值得买啊,俺还是用那个OLE的办法吧,跳对话框烦就烦点吧。。。

找LindoAPI Crack中。。。
调用LindoAPI的办法,结合上面那个CLASS文件的,要编译成DLL用。。。
可惜了。。。

  1. Public Sub Calculate()
  2.     Dim i As Long, j As Long
  3.     '----------------------------
  4.     '  获得检查证书
  5.     '----------------------------
  6.     Dim pEnv As Long, nErr As Long
  7.     Dim LicenseKey As String * LS_MAX_ERROR_MESSAGE_LENGTH
  8.     nErr = LSloadLicenseString(strLicensePath, LicenseKey)
  9.     Call CheckErr(pEnv, nErr)
  10.     '----------------------------
  11.     '  创建Lindo环境
  12.     '----------------------------
  13.     pEnv = LScreateEnv(nErr, LicenseKey)
  14.     If nErr > 0 Then
  15.         Err.Raise Number:=1000, Description:="创建Lindo环境失败"
  16.         Exit Sub
  17.     End If
  18.     '----------------------------
  19.     '  计算切割方案
  20.     '----------------------------
  21.     Call GeneratePatterns
  22.     '----------------------------
  23.     '  创建计算模型实例
  24.     '----------------------------
  25.     Dim pMod As Long
  26.     pMod = LScreateModel(pEnv, nErr)
  27.     Call CheckErr(pEnv, nErr)
  28.     '----------------------------
  29.     '  构造计算模型
  30.     '----------------------------
  31.         '变量数量,即所获得的方案数量
  32.         Dim nVars As Long
  33.         nVars = lngPlansCount
  34.         '约束数量,等于产品种类个数
  35.         Dim nRows As Long
  36.         nRows = lngProdCount
  37.         '目标方向,最小
  38.         Dim nDir As Long
  39.         nDir = LS_MIN
  40.         '目标常数,A constant value to be added to the objective value.
  41.         Dim dObjConst As Double
  42.         dObjConst = 0
  43.         '目标参数,即方案原材料长度数组
  44.         Dim dObjCoef() As Double
  45.         ReDim dObjCoef(0 To nVars)
  46.         For i = 0 To nVars - 1
  47.             dObjCoef(i) = arrLngAllRaws(i + 1, 1)
  48.         Next
  49.         '约束值数组,即产品数量数组
  50.         Dim dB() As Double
  51.         ReDim dB(0 To nRows)
  52.         For i = 0 To nRows - 1
  53.             dB(i) = arrLngProdReq(i + 1)
  54.         Next
  55.         '约束条件
  56.         Dim cConTypes As String
  57.         For i = 0 To nRows - 1
  58.             cConTypes = cConTypes & Chr(LS_CONTYPE_LE) '"L"
  59.         Next
  60.         '约束非0参数个数,即全部方案中非0数值的个数
  61.         Dim nNZ As Long
  62.         nNZ = 0
  63.         '约束非0参数数组
  64.         Dim dA() As Double
  65.         ReDim dA(0 To nVars * nRows)
  66.         '约束非0参数的列起始编号数组,个数为方案个数+1
  67.         Dim nBegCol() As Long
  68.         ReDim nBegCol(0 To nVars + 1)
  69.         '约束非0参数的行编号数组
  70.         Dim nRowX() As Long
  71.         ReDim nRowX(0 To nVars * nRows)

  72.         Dim dMaxBound As Double     '变量最大值
  73.         dMaxBound = 0
  74.         Dim bNewRow As Boolean
  75.         For i = 1 To nVars          '列为方案
  76.             bNewRow = True
  77.             For j = 1 To nRows      '行为产品种类
  78.                 If arrLngAllPlans(i, j) > 0 Then
  79.                     dA(nNZ) = arrLngAllPlans(i, j)
  80.                     If bNewRow Then
  81.                         nBegCol(i - 1) = nNZ
  82.                         bNewRow = False
  83.                     End If
  84.                     nRowX(nNZ) = j - 1
  85.                     nNZ = nNZ + 1
  86.                     If dMaxBound < arrLngProdReq(j) / arrLngAllPlans(i, j) Then
  87.                         dMaxBound = arrLngProdReq(j) / arrLngAllPlans(i, j)
  88.                     End If
  89.                 End If
  90.             Next
  91.         Next
  92.         ReDim Preserve dA(nNZ)
  93.         nBegCol(nVars) = nNZ
  94.         ReDim Preserve nRowX(nNZ)
  95.         '变量左边界数组
  96.         Dim dLower() As Double
  97.         ReDim dLower(0 To nVars)
  98.         For i = 0 To nVars - 1
  99.             dLower(i) = 0
  100.         Next
  101.         '变量右边界数组
  102.         Dim dUpper() As Double
  103.         ReDim dUpper(0 To nVars)
  104.         For i = 0 To nVars - 1
  105.             dUpper(i) = dMaxBound
  106.         Next

  107.     '----------------------------
  108.     '  输入到计算模型
  109.     '----------------------------
  110.     nErr = LSloadLPData(pMod, nRows, nVars, nDir, _
  111.                         dObjConst, dObjCoef(0), dB(0), _
  112.                         cConTypes, nNZ, nBegCol(0), ByVal 0, _
  113.                         dA(0), nRowX(0), dLower(0), dUpper(0))
  114.     Call CheckErr(pEnv, nErr)
  115.     '----------------------------
  116.     '  设置变量类型
  117.     '----------------------------
  118.     '变量类型
  119.     Dim cVarType As String
  120.     For i = 0 To lngPlansCount
  121.         cVarType = cVarType & Chr(LS_VARTYPE_INT) '"I"
  122.     Next
  123.     nErr = LSloadVarType(pMod, cVarType)
  124.     Call CheckErr(pEnv, nErr)
  125.     '----------------------------
  126.     '  模型计算
  127.     '----------------------------
  128.     nErr = LSsolveMIP(pMod, ByVal 0)
  129.     Call CheckErr(pEnv, nErr)

  130.     'Dim nSolStat As Long
  131.     'nErr = LSoptimize(pMod, LS_METHOD_PSIMPLEX, nSolStat)
  132.     'Call CheckErr(pEnv, nErr)
  133.     '----------------------------
  134.     '  获取计算结果
  135.     '----------------------------
  136.     Dim dObj As Long
  137.     nErr = LSgetInfo(pMod, LS_DINFO_POBJ, dObj)
  138.     Call CheckErr(pEnv, nErr)

  139.     Dim dX() As Double
  140.     ReDim dX(0 To lngPlansCount)
  141.     nErr = LSgetPrimalSolution(pMod, dX(0))
  142.     Call CheckErr(pEnv, nErr)
  143.     '********************************************
  144.     '*  变量太多,免费证书不支持,后面不写了。。。*
  145.     '********************************************
  146.     '----------------------------
  147.     '  删除Lindo环境
  148.     '----------------------------
  149.     Call LSdeleteEnv(pEnv)
  150. End Sub

复制代码

您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-16 19:26 , Processed in 0.046963 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表