python:关于三维装箱问题的算法研究-1

先准备一个用来图显的函数

# -*- coding: utf-8 -*-
from matplotlib import pyplot as plt
#设置图表刻度等格式
from matplotlib.ticker import MultipleLocator, FormatStrFormatter 
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

#make_pic的内置函数,用来在图像里面不断添加立方体
def box(ax,x, y, z, dx, dy, dz, color='red'):
    xx = [x, x, x+dx, x+dx, x]
    yy = [y, y+dy, y+dy, y, y]
    kwargs = {'alpha': 1, 'color': color}
    ax.plot3D(xx, yy, [z]*5, **kwargs)#下底
    ax.plot3D(xx, yy, [z+dz]*5, **kwargs)#上底
    ax.plot3D([x, x], [y, y], [z, z+dz], **kwargs)
    ax.plot3D([x, x], [y+dy, y+dy], [z, z+dz], **kwargs)
    ax.plot3D([x+dx, x+dx], [y+dy, y+dy], [z, z+dz], **kwargs)
    ax.plot3D([x+dx, x+dx], [y, y], [z, z+dz], **kwargs)
    return ax
#显示图形的函数:Items = [[num[0],num[1],num[2],num[3],num[4],num[5],num[6]],]
#Items是N个列表的列表,里面的每个列表数据[放置点O三维坐标,长宽高,颜色]
def make_pic(Items):
    fig = plt.figure()
    ax = Axes3D(fig)
    ax.xaxis.set_major_locator(MultipleLocator(50)) 
    ax.yaxis.set_major_locator(MultipleLocator(50)) 
    ax.zaxis.set_major_locator(MultipleLocator(50)) 
    for num in Items:
        box(ax,num[0],num[1],num[2],num[3],num[4],num[5],num[6])
    plt.title('Cube')
    plt.show()
#根据图显需要的数据,把尺寸数据生成绘图数据的函数
def make(O,C,color):
    data = [O[0],O[1],O[2],C[0],C[1],C[2],color]
    return data

准备好图显函数后,先制作一个容器-货柜

#1.给定空间容器C      
#内容积为:长4.2x宽1.9x高1.8米
O = (0,0,0)           #原点坐标
C = (420,190,180)    #箱体长宽高
color = 'red'         #箱体颜色
#显示箱体
# make_pic([make(O,C,color)]) #这个为直接显示箱体看下效果
#show_num = [make(O,C,color)] #这个为后面组合显示时,把箱体显示数据添加到所有要显示的数据里面

在这里插入图片描述

接着制作N个需要装箱的货物

#2.给定有限量个方体 1200个(60,40,50)的方体
B=[]
for num in range(0,1200):
    B.append((60,40,50))
#如果在后面的考虑不同方体的装箱时,方体大小存在差异,我们将优先按照体积大小降序排列,优先摆放大体积的
#因为按照模拟装箱的情况,当大箱子摆放后产生的可放置点,能在上方放置边长不大于或者大于小部分的物体,可选物体范围更大

#3.拟人化依次堆叠方体,假设这里不考虑方体朝向/重心/堆叠限制,如果有大小差异考虑方体最大悬空面积为30%
#第一个方体的位置从原点开始
color2='blue'
show_num.append(make(O,B[0],color2))
make_pic(show_num)#查看图显效果

在这里插入图片描述
由图片我们可以看到,每放置一个货物,就会消耗一个放置点,并且产生三个新的放置点
在这里插入图片描述
当然,这里最少有两个情况需要注意:
1.当因为货物大小和残余空间不足的时候,放置点也会失效
2.如果货物的长宽高有一项一致时,可能会产生相同的放置点(发生放置点覆盖),我们在计算放置点的时候,要保证放置点是唯一的

这里按照放置点产生的逻辑,写一个放置点产生函数

#可用点的生成方法
def newsite(O,B_i):
    # 在X轴方向上生成
    O1 = (O[0]+B_i[0],O[1],O[2])
    # 在Y轴方向上生成
    O2 = (O[0],O[1]+B_i[1],O[2])
    # 在Z轴方向上生成
    O3 = (O[0],O[1],O[2]+B_i[2])
    return [O1,O2,O3]
#这个时候新产生3个可用摆放点,把放入第一个货物时产生的三个放置点加入放置点列表
O_items = []
O_items = O_items + newsite(O,B[0])

所以根据这三个放置点,我们又可以进行货物堆叠,并产生新的放置点

#所以在新的点位上摆放新的箱子,同时生成逻辑上的新的三个点
#实际好像当箱体一样大的时候没有三个点,而且当箱体体积接近时,有的点无法使用
#后期解决方法为当点可用性不够时,优先在水平面扩散,让点可用
show_num.append(make(O_items[0],B[1],color2))
O_items = O_items + newsite(O_items[0],B[1])

show_num.append(make(O_items[1],B[2],color2))
O_items = O_items + newsite(O_items[1],B[2])

show_num.append(make(O_items[2],B[3],color2))
O_items = O_items + newsite(O_items[2],B[3])

在这里插入图片描述
按照图显可以看到,实际在"打X"的三个点的放置点发生了覆盖

开始写我们的放置逻辑

所以从第二个货物开始,我们就开始重复性的发生货物的堆叠
并重复性的产生新的放置点,直到放置点不再可用

#所以从我们的仓库B不断的把货物B_i搬到箱体里,限制条件为在X,Y,Z方向上可用点小于箱体长宽高
canput = 1 #初始放了一个货物

for i in range(1,len(B)):
    #货物次序应小于等于可用点数量,如:第四个货物i=4,使用列表内的第三个放置点O_items[2],所以i-1应小于等于len-1
    if i-1 <= len(O_items)-1:
        #如果放置点放置货物后,三个方向都不会超过箱体限制
        if O_items[i-1][0]+B[i][0]<=C[0] and O_items[i-1][1]+B[i][1]<=C[1] and O_items[i-1][2]+B[i][2]<=C[2]:
            #使用放置点,添加一个图显信息
            show_num.append(make(O_items[i-1],B[i],color2))
            #计数加1
            canput = canput + 1
            #把堆叠后产生的新的点,加入放置点列表
            for new_O in newsite(O_items[i-1],B[i]):
                #保证放入的可用点是不重复的
                if new_O not in O_items:
                    O_items.append(new_O)
        
        #如果轮到的这个放置点不可用
        else:
            #把这个可用点弹出弃用
            O_items.pop(i-1)
            #弃用可用点后,货物次序应小于等于剩余可用点数量
            if i-1 <= len(O_items)-1:
                #当可用点一直不可用时
                while O_items[i-1][0]+B[i][0]>C[0] or O_items[i-1][1]+B[i][1]>C[1] or O_items[i-1][2]+B[i][2]>C[2]:
                    #一直把可用点弹出弃用
                    O_items.pop(i-1)
                    #如果弹出后货物次序超出剩余可用点,则认为无法继续放置
                    if i-1 > len(O_items)-1:
                        break
                #货物次序应小于等于剩余可用点数量
                if i-1 <= len(O_items)-1:
                    #如果不再超出限制,在这个可用点上堆叠
                    show_num.append(make(O_items[i-1],B[i],color2))
                    #计数加1
                    canput = canput + 1
                    #把堆叠后产生的新的点,加入放置点列表
                    for new_O in newsite(O_items[i-1],B[i]):
                        #保证放入的可用点是不重复的
                        if new_O not in O_items:
                            O_items.append(new_O)

print(canput)
make_pic(show_num)

最终运行结果:canput = 84
在这里插入图片描述
可以看到装箱后在上部和侧部仍有较大剩余空间

结论:如果在货物摆放方向和朝向固定的时候,最大装货量为84/箱

但是我们在实际装箱的时候,如果没有特殊限定,
货物的三个边a,b,c选为底边的组合方式应该有:(a,b),(b,a),(a,c),(c,a),(b,c),(c,b)六种方式

在这里插入图片描述
在简单由原来的60-40-50修改为40-60-50之后,装箱的空间利用率马上上升为了90/箱

很明显,每个货物摆放之后,因为摆放朝向的六种可能,剩余点的可用性也会发生改变
也就是说,假设装载数为80-90/箱时,理想摆放方案数为6的80-90次方左右

既然要考虑货物朝向的可利用性,那就要考虑货物大小,最大悬空比例,因为朝向不一致带来的放置点不可用问题,这里接下来的思路是,货物和货物之间的位差也会产生新的放置点且放置点的可用受限于被贴合货物的大小。

  • 20
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
【资源介绍】 基于DQN深度强化学习解决三维在线装箱问题python源码+项目说明.zip 问题描述 物流公司在流通过程中,需要将打包完毕的箱子装入到一个货车的车厢中,为了提高物流效率,需要将车厢尽量填满,显然,车厢如果能被100%填满是最优的,但通常认为,车厢能够填满85%,可认为装箱是比较优化的。 设车厢为长方形,其长宽高分别为L,W,H;共有n个箱子,箱子也为长方形,第i个箱子的长宽高为li,wi,hi(n个箱子的体积总和是要远远大于车厢的体积),做以下假设和要求: 1. 长方形的车厢共有8个角,并设靠近驾驶室并位于下端的一个角的坐标为(0,0,0),车厢共6个面,其中长的4个面,以及靠近驾驶室的面是封闭的,只有一个面是开着的,用于工人搬运箱子; 2. 需要计算出每个箱子在车厢中的坐标,即每个箱子摆放后,其和车厢坐标为(0,0,0)的角相对应的角在车厢中的坐标,并计算车厢的填充率。 运行环境 主机 |内存 | 显卡 | IDE | Python | torch -----|------|------|-----|--------|----- CPU:12th Gen Intel(R) Core (TM) i7-12700H 2.30 GHz | 6GB RAM | NVIDIA GEFORCE RTX 3050 | Pycharm2022.2.1 | python3.8 | 1.13.0 思路 (1)箱子到来后,根据车厢的实际空间情况,按照策略选择放置点; (2)当摆放箱子时,以6种姿态摆放,并对其进行评估,使用评估值最高的姿态将箱子摆放在选中的角点上; (3)重复以上步骤,直到摆放完毕。 建立模型 在车厢内部设置坐标系,靠近驾驶室并位于下端的一个角的坐标为(0,0,0),相交于原点的车厢长边、宽边和高边分别为x轴,y轴和z轴方向,L、W、H分别为车厢的长、宽、高。箱子具有六种摆放姿态,分别以箱子的长宽、长高、宽高平面为底,旋转90°可以得到另外三种摆放姿态。 核心 # 箱子放置策略 本算法将角点作为车厢内部空间中箱子的摆放位置,每次放入新箱子后搜索新生成的角点,当向车厢中放入第一个箱子时,假设车厢中只有原点一个角点,当一个箱子放入后,会产生新的角点,再放置箱子后,又会产生新的角点。 建立箱子可放置点列表,表示箱子i到来时,车厢内部所有可选的摆放位置,在放置新箱子后更新可放置点列表,并记录已放置箱子到车厢顶部距离,用于后续的奖励函数。 # DQN (1)设置一些超参数,包括ε-greedy使用的ε,折扣因子γ,目标网络更新频率,经验池容量等。 (2)由于给定的箱子数据较少,为了增加模型训练数据数量,将给定的箱子数据打乱,以随机的形式生成并保存,作为训练数据,训练网络模型。 (3)奖励函数 使用x-y平面中两个最大剩余矩形面积(如下图)之和与箱子到车厢顶部的距离作为奖励值R,奖励函数表示如下 【说明】 该项目是个人毕设项目,答辩评审分达到95分,代码都经过调试测试,确保可以运行!欢迎下载使用,可用于小白学习、进阶。 该资源主要针对计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者下载使用,亦可作为期末课程设计、课程大作业、毕业设计等。 项目整体具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现不同的功能。 欢迎下载交流,互相学习,共同进步!
三维装箱问题是一个组合优化问题,即如何将一组不同大小的三维物体放入最小数量的三维容器中。而遗传算法是解决这类问题的有效工具之一。下面是使用Python实现三维装箱遗传算法的步骤: 1. 定义问题:首先,需要定义三维装箱问题的目标函数和约束条件。目标函数可以是最小化使用的容器数量,约束条件可以包括容器的最大尺寸、物体的尺寸和数量限制等。 2. 初始化种群:随机生成一组初始解作为种群,并计算每个解的适应度。适应度可以根据目标函数的值来评估解的优劣程度。 3. 选择操作:根据适应度选择一部分优秀的个体作为父代。可以使用轮盘赌选择、锦标赛选择等策略。 4. 交叉操作:从选出的父代中随机选择两个个体,进行交叉操作,生成新的个体。交叉可以按照一定的概率在两个个体之间进行交叉。 5. 变异操作:对交叉后的个体进行变异操作,以增加种群的多样性。变异可以随机改变个体中的某些基因值。 6. 更新种群:将交叉和变异得到的个体加入种群,并计算每个个体的适应度。 7. 父代选择:根据适应度选择一部分优秀的个体作为下一代的父代。 8. 终止条件判断:判断是否达到终止条件,如迭代次数达到预设值或找到满足要求的解。 9. 重复步骤3到步骤8,直到达到终止条件。 通过以上步骤,可以使用遗传算法求解三维装箱问题。具体实现时,可以使用Python中的遗传算法库,如DEAP (Distributed Evolutionary Algorithms in Python)等,来简化编码和实现过程。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [遗传算法python(含例程代码与详解)](https://blog.csdn.net/qq_38048756/article/details/109256062)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

isSamle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值