2022 年度全国大学院数学モデリング コンテスト Huawei Cup 問題 B 四角形部品の組み立てバッチの最適化 問題解決のドキュメントとプロセス全体の手順

2022 全国大学院数学モデリングコンテスト Huawei Cup

問題 B: 正方形パーツの組み立てバッチ最適化問題

元のタイトルを再掲:

  背景 はじめに
  インテリジェント製造が「中国製造 2025」の主な方向性として挙げられており、パーソナライズされたカスタマイズ、製品とシステムのライフサイクルの短縮、相互接続されたサービスモデルなどが、インテリジェント製造の変革における企業の主な競争ポイントとなっています。電子機器、自動車、航空宇宙部品などのディスクリート産業の製品を例に挙げます。これらの製品はすべて機械設計に依存しており、分散処理が可能で、柔軟に組み立てることができ、多くのスタイルの類似製品があります。このような製品に対して、顧客は無尽蔵の製品要求、予測できない注文量、および非常に高い製品品質要件を抱えている可能性があります。現時点では、「パーソナライズされたカスタマイズ」に対するサービス需要により、企業には効率的かつ迅速な需要分析と製品設計能力、柔軟で無駄のない生産プロセス、そして完全かつ洗練された全プロセス生産管理能力が求められています。
  角型パーツ製品(プレート製品とも呼ばれます)は、板を主体とし、平面加工後に複数の板付属品を組み立てて形成される製品です。3C(コンピューティング、通信、家電)、パネル家具、ガラス、板金部品などの一般的な角形部品製品の製造会社は、ほとんどが「多品種・小ロット」の個別カスタマイズ生産を採用しています。企業の注文、生産組織は通常、「注文バッチ+大量生産+注文仕分け」モデルを採用しており、注文バッチを使用してバッチカットを実現し、原材料の利用率を向上させます。処理が完了した後、さまざまな顧客に応じて仕分けされます。命令。
  前述のパーソナライズされたカスタマイズ生産モデルでは、注文のバッチ処理とレイアウトの最適化が重要であり、注文のバッチ処理とは、異なる注文をいくつかのバッチに結合して、注文のバッチ生産を実現することです。小ロット、多品種、大量注文の一括生産の場合、バッチが小さすぎると材料利用率が低く生産効率が低くなり、バッチが大きすぎると材料利用率が低下します。受注量は増加するが、納期が保証できない、仕分けが困難になる、生産効率が低下する、バッファ容量が不足して混雑するなど、個別化と生産効率の矛盾を解決する必要がある。
  レイアウトの最適化は本質的にブランキング問題 (切断および充填問題とも呼ばれます) です。最適化の目的は、プレート上の正方形のパーツのレイアウトを合理的に計画して、ブランキング プロセス中のプレートの無駄を削減し、切断プロセスを簡素化することです。この問題は、計算の複雑さが高い組み合わせ最適化問題であり、オペレーションズ リサーチの重要な分野でもあります。多くの製造会社の生産チェーンにおける製品や部品の生産の最初のステップであるブランキングは、過小評価できない材料と資源を消費します。材料の利用率を向上させ、原材料の消費量を削減する方法は、企業が資源と部品を削減するための重要なステップです。エネルギーの無駄を省き、環境への責任を負うという、解決すべき重要な問題です。
  問題の説明
  注文のバッチ処理の問題: 注文の納期、設備容量負荷、保管容量、材料使用率、生産効率、生産プロセスの制約などの要素を考慮して、製造注文のバッチ処理を最適化します。同一の材料、類似の納期、類似の工程の発注を同一の生産バッチにまとめ、納期の確保、原材料の稼働率の向上、設備の生産効率の向上などを図るため、発注バッチ最適化を実施します。データの統一処理を容易にし、問題の本質を反映するために、このコンテストではすべての注文の納期が同じであり、区別はありません。バッチは、複数のオーダーのすべてのタスクを完了し、未完了のオーダー タスクを含まないオーダーの集合として定義されます。
  ブランキング最適化問題 (レイアウト最適化問題とも呼ばれます): 同じ生産バッチ内の正方形部品のサイズと数量に応じて、オリジナル部品の仕様と数量を選択し、ブランキングとレイアウトを最適化し、オリジナルの利用率を最大化します。シート。切断プロセスのプロセス要件に従って、レイアウト計画は「フリー サイズ」(ギロチン カットとも呼ばれる) 制約を満たす必要があります (直線切断では基板が分離可能であること、つまり各直線が確実に切断される必要があります)カットはボードを 2 つの部分に分離します)。ブランキング最適化問題は、「フリー サイズ」制約を持つプレート プロファイル正方形部品のレイアウト最適化問題に属します。
  切断加工の方法の違いを考慮すると、ギロチンカットと非ギロチンカットに分けることができます(図1参照)。図 2 の 3 段階レイアウト方法には、主に 3 段階ノンイグザクト レイアウト方法 (3NE)、3 段階ホモジニアス レイアウト方法 (3E)、3 段階ホモジニアス レイアウトの 3 つの異なるタイプがあります。方法(3H) 。このうち、3Eと3Hのレイアウト方法は、正方形のパーツを3段階で正確な寸法でカットできるため、どちらも正確なレイアウト方法です。3NE レイアウト方法では、一部の正方形のパーツでは、サイズ要件を満たすためにさらに 4 段階目の切断が必要になります。
ここに画像の説明を挿入します
  切断の段階数が異なるため、文書によっては切断段階ごとに名称が異なりますが、理解を容易にし表現形式を統一するため、主要な段階モジュールの説明には英語を使用しています。詳細は図3を参照してください。 (実際の切断工程では、Aナイフは長辺に対して垂直な場合もあれば、短辺に対して垂直な場合もあります。図3では一方の辺に対して垂直である場合を例にしています。)
ここに画像の説明を挿入します
  3 段階切断方法を例にとると、共通の段階は最大 3 ~ 4 段階であるため (図 3)、最初の段階の横方向の切断生成モジュールは Stripe1 や Strip2 などと呼ばれ、2 段階目の垂直方向の切断生成モジュールはストライプと呼ばれます。たとえば、Strip1 が Stack1、Stack2、Stack3 にカットされ続けるなど、ステージ内のカッティング生成モジュールはスタック (スタック) と呼ばれ、3 段目の水平カッティング生成モジュールはアイテム (製品アイテム) と呼ばれ、たとえば Stack1 が継続されます。アイテム 1、アイテム 2、アイテム 3 に切り分けます。
  この競争問題は
  2 つのサブ問題で構成されています。2 番目のサブ問題の制約は最初のサブ問題に基づいており、互換性がありますが、2 つのサブ問題によって提供されるデータは関連しません。概念の定義とプロセスの説明が業界のものと異なる場合は、この競争上の質問が優先されます。この質問は次のことを前提としています。
  1. 面一切断の切断方法のみが考慮されます (直線切断、切断方向は基板の一端に対して垂直であり、直線ごとに基板が 2 つの部分に分離されることが保証されます)。ラインカット); 2. カット段階の数は 3 を超えず、同じです
  各段階でのカット方向は同じです;
  3. レイアウト方法は精密レイアウトです;
  4. 元のシートは 1 つだけであると仮定します仕様と十分な数量。
  5. レイアウト計画では、鋸のカーフ幅 (つまり、切断ギャップの幅) の影響を考慮する必要はありません。
  副問題 1: レイアウトの最適化の問題。製造オーダーの要件と関連する制約を満たしながら、プレート材料の量を可能な限り削減するには、混合整数計画モデルを確立する必要があります。
  制約:
  1. 同じスタック内の製品アイテムの幅 (または長さ) は同じである必要があります;
  2. 最終切断によって生成された製品アイテムは完全であり、接合されていません。
  このサブ問題には、データ セット A を入力として受け取るプログラミングが必要です。出力要件はパート 5 に示されています。
  サブ問題 2: 注文のバッチ処理の問題。データセット B 内のすべての注文をバッチにグループ化し、各バッチを独立して配置する混合整数計画モデルを確立して、注文要件と関連制約を満たしながら、使用する元のシートの量をできるだけ少なくする必要があります。 。
  副問題 1 の制約を満たすことに基づいて、さらなる要件が必要です:
  1) 各注文はバッチ内にのみ存在する必要があります;
  2) 各バッチ内の同じ材料の製品アイテム (アイテム) は同じプレート生を使用できます。レイアウト用の材料スライス;
  3) 処理リンクの迅速な流れを確保するために、各バッチの製品アイテム (項目) の合計数は制限を超えることはできません; 4) 工場の能力制限により、各バッチの合計面積は制限を超えてはなりません
  。製品アイテム (項目) のバッチは制限値を超えることはできません。
このサブ質問にはプログラミングが必要で、データ セット B を入力として受け取り、出力結果の要件はパート 5 に示されています。

ソリューションプロセス全体の概要 (要約)

  本論文は,混合整数計画法モデルを解くために反復法とK平均クラスタ分析法を用いて,正方形部品の配置最適化とバッチング問題を研究した。
  問題 1 では、パネルの切断問題がプロジェクト部品の積み上げ問題として扱われます。まず、オリジナルのフィルム消耗品の最小量を目的関数として使用して、所定の制約を備えた混合整数計画法モデル I が確立されます。各アイテムは一度ずつスタックし、そのスタックの高さも適度でなければならないと規定されているため、アイテム、スタック、ストライプ、ビンが順に含まれるかどうかを決定するダミー変数α、β、γを設定します。アイテムのスタッキング高さは北鉄に制限されており、スタックの高さを超えてはならず、スタックの幅は元のピースの幅を超えてはならず、ストリップの高さは元のピースの高さを超えてはなりません。実際のアプリケーションでは、アイテムの高さ h がレイアウトの基礎として使用され、モデル I に入力されてダミー変数パラメーター値 α、β、γ、... が取得されます。スタックの数値指標が不明であるため、調整パラメータH、平均値、中央値を設定してモデルを最適化します.最終的に、調整パラメータとしてソートの高さ、平均値、中央値を使用するモデルが最良のフィッティング効果を持つことがわかりますデータセット A では、平均プレート使用率は 94.06% に達しました。
  問 2 では、注文番号がバッチ化できない、板材が異なるなどの理由から、データ量が多い場合の制約付きオーダー部品のバッチ化問題の解決を検討する必要があります。まず、同じ注文番号をまとめ、K-Meansクラスタリングの基礎となる材料関連指数構築マトリックスを設定し、1バッチの製品アイテムの総数を1,000個、面積の合計上限を1,000個に制限します。製品の単一バッチは 250 平方メートルまで。ユークリッド距離とクラス平均距離によってクラスター ファミリを分割し、分類要件を満たすカテゴリの最小数 K を見つけます。最適な実行可能なソリューションが見つかり、製品アイテムがバッチ化されるまで、ハイパーパラメーター max_order、min_order、および K を継続的に調整します。製品アイテムがバッチで完成した後、各バッチ内の異なる材料の製品アイテムがグループ化され、モデル I のレイアウト最適化手法がグループごとに個別に使用され、最終的な出力結果は 83.32% になります。
  この記事の質問 1 の反復法の解決コードは、サードパーティのライブラリを呼び出さず、すべて自身で記述およびカプセル化されており、動作速度が速く、変更可能性が強いという特徴があります。この記事では、正方形部品の注文バッチ処理とレイアウト最適化モデリングの結果は比較的堅牢で、荷物の問題やブランキングの問題に対して一定の指針を提供できます。PCB 回路基板、バンシ家具、3C 家電などの分野にも実用的です。 . アプリケーションには一定の基準値があります。

モデルの仮定:

  1. オリジナルの部品は均一な仕様を持ち、材料は均一に分布しており、不純物領域はありません
  2. 切断プロセスはヘッドツーヘッド切断方式を採用しています
  3. 完成した部品は互いに独立しており、重なり合いはありません製品アイテム間[3];
  4. カットされた製品は完成しており、継ぎ合わせて作成することはできません;
  5. 最初のカットは元のピースの短辺の水平方向と平行です;
  6. 各カットは常に垂直です前のカットの切断方向 [4];
  7. 最大 3 段階の切断のみが考慮されます;
  8. レイアウト この方法では正確なレイアウトのみが考慮されます。

問題分析:

  問題 1 の分析 問題
  1 では、プレートのレイアウトを最適化し、元のプレートの消費量を最小限に抑えるために、混合整数計画法モデルを確立する必要があります。この目標を達成するために、原稿フィルムの消耗品の最小量を目的関数とし、制約条件を十分に考慮した上で、ビン(原稿フィルム)、ストライプ(ストリップ)、スタック(スタック)、アイテム(製品項目) )、各切断段階間の特定の関係を解釈し、一致するパラメーターを設定することにより、この質問の目的に関連する方程式系を構築できます。オリジナルフィルムのカット問題を逆算してオーダーパーツの組み合わせ問題として捉え、必要なオーダーパーツを積み上げ、アイテムを組み合わせてスタックにし、そのスタックをストライプに組み合わせ、さらにストライプを積み上げる情報を収集し、最終的にタイトルに設定されたオリジナルのフィルムが形成されます。モデルを決定したら、まず、順序要件を継続的に入力して局所的な最適解を見つける反復法を使用することを検討します。
  質問 2 の分析 質問
  1 に基づいて、質問 2 では新しい制約が追加されています。1 つ目は、バッチアイテムの制限であり、各バッチ内の製品アイテムの数が 1,000 を超えてはならず、単一の製品の総面積が以下である必要があります。製品アイテムのバッチは 1,000 を超えてはなりません. 250 平方メートルを超えてはなりません. 第 2 に、バッチ分割の基礎として注文番号と材料が与えられます. 同じ注文を異なるバッチに分割することはできないことが要求されます、各注文の素材が異なる場合があります。そのためには、まず制約に従って注文を分類し、次に分類された各バッチのレイアウトを個別に最適化する必要があります。レイアウトの最適化が主な問題とみなされる場合、バッチ問題は 3 段階のレイアウトの副次的な問題とみなすことができます。注文のバッチ化問題 [1] に直面して、まず製品部品を注文番号に従って 1 つのカテゴリに分類し、次に制約付きで K-Means クラスタリングを実行することを考えます。プレート オリジナルフィルムの利用率が高く、できるだけ同じ材料を同じバッチに入れる必要があります。クラスタリングが完了した後、各カテゴリをバッチに分類し、質問 1 の混合整数計画法モデルを使用して、各バッチ内の異なる材料の製品項目を反復処理し、最終的に各バッチの近似解を取得します [2] 。

モデルの確立とソリューション全体の論文のサムネイル

ここに画像の説明を挿入します

ここに画像の説明を挿入します

すべての論文については、以下の「QQ 名刺のモデリングのみ」を参照してください。QQ 名刺をクリックしてください。

コード:

いくつかの Python プログラムは次のとおりです。

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import time
import pandas as pd
from demo import Cycle_solution_A
# 衡量指标
def metrics(data, number, max_length, max_width):
 """
 :parameter
 data:[[序号:index, 订单 id:item_id, 订单材料:item_material, 订单所需要数
量:item_num, 材料长度:item_length, 材料宽度:item_width, 订单号:item_order]*size]
 number:消耗的总板材
 max_length:板材长
 max_width:板材宽
 """
 total_item = 0.
 for vector in data:
 total_item += vector[4] * vector[5]
 run_rate = total_item / (number*max_length*max_width)
 return run_rate
# 问题一
# 加载数据
file_A = []
for i in range(1, 5):
 file_path = os.path.join(r"E:\python document\challenge\2022 年 B 题\子问题 1-数
据集 A", "dataA"+str(i)+".csv")
 if os.path.exists(file_path):
 file_A.append(pd.read_csv(file_path))
data_A_lis = []
avg_length = []
for i in file_A:
 avg_length.append(i['item_length'].mean())
 j = i.sort_values(by='item_length', ascending=False)
 j = j.values.tolist()
 data_A_lis.append(j)
# [序号:index, 订单 id:item_id, 订单材料:item_material, 订单所需要数量:item_num, 
材料长度:item_length, 材料宽度:item_width, 订单号:item_order]
print(data_A_lis)
# 参数
max_length = 2440
max_width = 1220
path = r"E:\python document\challenge\2022 年 B 题\solution_A"
f_txt = open(r"E:\python document\challenge\2022 年 B 题\solution_A\min_n.txt", "w")
# 求解
min_n_data_A = []
rate_A_lis = []
run_time_lis = []
_time = time.time()
for A_index, data_set in enumerate(data_A_lis):
 data_size = len(data_set)
 paths = os.path.join(path, "A{0}".format(A_index+1))
 solution = Cycle_solution_A(data_size, paths, avg_length[A_index], max_length, 
max_width)
 min_n, cut_program = solution.cycle_com(data_set)
 cut_program.to_csv(r"E:\python document\challenge\2022 年 B 题
\solution_A\A{
    
    0}\data_A{
    
    0}_cut_program.csv".format(A_index+1), index=None, 
encoding='utf_8_sig')
 rate = metrics(data_set, min_n, max_length, max_width)
 run_time_lis.append(time.time() - _time)
 min_n_data_A.append(min_n)
 rate_A_lis.append(rate)
 print("data_A{0}:finish".format(A_index+1))
f_txt.write("min_n_data_A:" + "\n")
f_txt.write(str(min_n_data_A) + "\n" + "\n")
f_txt.write("rate_A_lis:" + "\n")
f_txt.write(str(rate_A_lis) + "\n" + "\n")
f_txt.write("run_time:" + "\n")
f_txt.write(str(run_time_lis) + "\n" + "\n")
print(min_n_data_A)
print(rate_A_lis)
class Cycle_solution_A():
def __init__(self, data_size, path, average_length, max_length=2440, 
max_width=1220):
 self.max_length = max_length
 self.path = path
 self.average_length = average_length
 self.max_width = max_width
 self.data_size = data_size
 # alpha、beta、gamma 的定义
 self.alpha = []
 self.beta = []
 self.gamma = []
 for j in range(data_size):
 self.alpha.append([0 if j > i else 1 for i in range(data_size)])
 for j in range(data_size):
 self.beta.append([0 if j > i else 1 for i in range(data_size)])
 for j in range(data_size):
 self.gamma.append([0 if j > i else 1 for i in range(data_size)])
 def cycle_com(self, data):
 """
 :parameter
 data:[[序号:index, 订单 id:item_id, 订单材料:item_material, 订单所需要
数 量 :item_num, 材 料 长 度 :item_length, 材料宽度 :item_width, 订 单
号:item_order]*size]
 """
 stack_lis, info_stack_lis, alpha = self.item_into_stack(data, self.alpha)
 stripe_lis, stripe_index_lis, info_stripe_lis, beta = 
self.stack_into_stripe(stack_lis, info_stack_lis, self.beta)
 bin_lis, bin_lis_index, info_bin_lis, gamma = self.stripe_into_bin(stripe_lis, 
info_stripe_lis, self.gamma)
 file = self.picture(data, stack_lis, info_stack_lis, stripe_lis, info_stripe_lis, 
bin_lis)
 min_number = 0
 for index, i in enumerate(gamma):
 min_number += i[index]
 return min_number, file
 def item_into_stack(self, data, alpha):
 # 构造出 stack stak:[list1, list2,....],list 的第一个元素为 stack 的计算标号
 stack_lis = []
 for item_index, item in enumerate(data):
 if len(stack_lis) == 0:
stack_lis.append([item_index+1])
 else:
 for index, i in enumerate(stack_lis):
 if data[i[0] - 1][5] == item[5]:
 stack_length = 0
for j in i:
 stack_length += data[j-1][4]
 if stack_length + item[4] <= self.average_length:
 stack_lis[index].append(item_index+1)
 else:
 # 转换 h 和 w
 # if data[i[0] - 1][5] == item[4]:
 # data[item_index][4], data[item_index][5] = 
data[item_index][5], data[item_index][4]
 # if stack_length + item[4] <= 
self.average_length:
 # stack_lis[index].append(item_index + 1)
 # else:
 # stack_lis.append([item_index+1])
stack_lis.append([item_index+1])
break
 else:
 continue
 sum = 0
 for i in stack_lis:
 for j in i:
 if item_index + 1 == j:
 sum += 1
 if sum == 0:
 stack_lis.append([item_index + 1])
 # 处理 alpha
 for vector in stack_lis:
 # 计算序号变为 python 序号
 set_vector = []
 for number in vector:
 set_vector.append(number - 1)
 cycle_set = list(set(range(self.data_size)) - set(set_vector))
 for j in cycle_set:
 alpha[vector[0] - 1][j] = 0
 if len(vector) > 1:
 for j in vector[1:]:
 for k in range(self.data_size):
 alpha[j - 1][k] = 0
 # 输出 stack 的高度和宽度信息(先高后宽)
info_stack = [[],[]]
 for i in stack_lis:
 stack_length = 0
 for j in i:
 stack_length += data[j - 1][4]
 info_stack[0].append(stack_length)
 info_stack[1].append(data[i[0] - 1][5])
 return stack_lis, info_stack, alpha
 def stack_into_stripe(self, stack, info_stack, beta):
 # 先对 stack 做一次排序
 stack_length = info_stack[0]
 stack_width = info_stack[1]
 sort_stack = []
 for index, i in enumerate(stack_width):
 sort_stack.append([stack_length[index], i, stack[index]])
 # 排序
 n = len(sort_stack)
 for i in range(n):
 min = i
 for j in range(i+1, n):
 if sort_stack[j][0] < sort_stack[min][0]:
 min = j
 sort_stack[min], sort_stack[i] = sort_stack[i], sort_stack[min]
 sort_stack = sort_stack[::-1]
 # 分出数据
 finish_sort_stack = []
 sort_info_stack = []
 for i in sort_stack:
 sort_info_stack.append([i[0], i[1]])
 finish_sort_stack.append(i[2])
 # 构造出 stripe, stripe:[[number,element1, element2, ....], .....],number 为其
序号,element 为包含的 stack 序号
 stripe_lis = []
 for item_index, item in enumerate(finish_sort_stack):
 if len(stripe_lis) == 0:
 stripe_lis.append([item_index])
 else:
 for i_index, i in enumerate(stripe_lis):
 stripe_width = 0
for j in i:
 stripe_width += sort_info_stack[j][1]
 if stripe_width + sort_info_stack[item_index][1] <= 
self.max_width:
 stripe_lis[i_index].append(item_index)
break
 else:
 continue
 sum = 0
 for i in stripe_lis:
 for j in i:
 if item_index == j:
 sum += 1
 if sum == 0:
 stripe_lis.append([item_index])
 # 输出 stripe 的宽度信息
 info_stripe = []
 max_length_index = []
 for v_index, vector in enumerate(stripe_lis):
 stripe_width = 0
 stripe_length = []
 for j_index, j in enumerate(vector):
 stripe_length.append(sort_info_stack[j][0])
 stripe_width += sort_info_stack[j][1]
 info_stripe.append([max(stripe_length), stripe_width])
 max_length_index.append(stripe_length.index(max(stripe_length)))
 # 将 stripe 做序号转变
 true_stripe_lis = []
 for v_index, vector in enumerate(stripe_lis):
 max_index = max_length_index[v_index]
 true_stripe_lis.append([finish_sort_stack[vector[max_index]][0]])
 for j_index, j in enumerate(vector):
 true_stripe_lis[v_index].append(finish_sort_stack[j][0])
 # 处理 beta
 first_vector = []
 for vector in true_stripe_lis:
 # 计算序号变为 python 序号
 first_vector.append(vector[0]-1)
 set_vector = []
 for number in vector[1:]:
 set_vector.append(number - 1)
 cycle_set = list(set(range(self.data_size)) - set(set_vector))
 for j in cycle_set:
 beta[vector[0] - 1][j] = 0
 zero_lis = list(set(range(self.data_size)) - set(first_vector))
 for i in zero_lis:
 for j in range(self.data_size):
 beta[i][j] = 0
 return true_stripe_lis, stripe_lis, info_stripe, beta
 def stripe_into_bin(self, stripe, info_stripe, gamma):
# 先对 stack 做一次排序
 sort_stripe = []
 for index, i in enumerate(stripe):
 sort_stripe.append([info_stripe[index][0], info_stripe[index][1], i])
 # 排序
 n = len(sort_stripe)
 for i in range(n):
 min = i
 for j in range(i + 1, n):
 if sort_stripe[j][0] < sort_stripe[min][0]:
 min = j
 sort_stripe[min], sort_stripe[i] = sort_stripe[i], sort_stripe[min]
 sort_stripe = sort_stripe[::-1]
 # 分出数据
 finish_sort_stripe = []
 sort_info_stripe = []
 for i in sort_stripe:
 sort_info_stripe.append([i[0], i[1]])
 finish_sort_stripe.append(i[2])
 # 构造出 bin, bin:[[number,element1, element2, ....], .....],number 为其序,element 为包含的 bin 序号
 bin_lis = []
 for item_index, item in enumerate(finish_sort_stripe):
 if len(bin_lis) == 0:
 bin_lis.append([item_index])
 else:
 for i_index, i in enumerate(bin_lis):
 bin_length = 0
for j in i:
 bin_length += sort_info_stripe[j][0]
 if bin_length + sort_info_stripe[item_index][0] <= 
self.max_length:
 bin_lis[i_index].append(item_index)
break
 else:
 continue
 sum = 0
 for i in bin_lis:
 for j in i:
 if item_index == j:
 sum += 1
 if sum == 0:
 bin_lis.append([item_index])
 # 输出 bin 的高宽信息
 info_bin = []
max_length_index = []
 for v_index, vector in enumerate(bin_lis):
 bin_width = []
 bin_length = 0
 for j_index, j in enumerate(vector):
 bin_width.append(sort_info_stripe[j][1])
 bin_length += sort_info_stripe[j][0]
 info_bin.append([bin_length, max(bin_width)])
 max_length_index.append(bin_width.index(max(bin_width)))
 # 将 bin 做序号转变
 true_bin_lis = []
 for v_index, vector in enumerate(bin_lis):
 
true_bin_lis.append([finish_sort_stripe[vector[max_length_index[v_index]]][0]])
 for j_index, j in enumerate(vector):
 true_bin_lis[v_index].append(finish_sort_stripe[j][0])
 # 处理 gamma
 first_vector = []
 for vector in true_bin_lis:
 # 计算序号变为 python 序号
 first_vector.append(vector[0] - 1)
 set_vector = []
 for number in vector[1:]:
 set_vector.append(number - 1)
 cycle_set = list(set(range(self.data_size)) - set(set_vector))
 for j in cycle_set:
 gamma[vector[0] - 1][j] = 0
 zero_lis = list(set(range(self.data_size)) - set(first_vector))
 for i in zero_lis:
 for j in range(self.data_size):
 gamma[i][j] = 0
 return true_bin_lis, bin_lis, info_bin, gamma
 def picture(self, data, stack_lis, info_stack_lis, stripe_lis, info_stripe_lis, bin_lis):
 # 找出每个 bin 所含的订单 id
 # 制作 bin、stripe、stack 的高宽信息字典
 info_stack_dict = {
    
    }
 for stack_index, stack_i in enumerate(stack_lis):
 info_stack_dict[stack_i[0]] = [info_stack_lis[0][stack_index], 
info_stack_lis[1][stack_index]]
 info_stripe_dict = {
    
    }
 for stripe_index, stripe_i in enumerate(stripe_lis):
 info_stripe_dict[stripe_i[0]] = info_stripe_lis[stripe_index]
 stripe_dict = {
    
    }
 for v_index, vector in enumerate(stripe_lis):
tem in enumerate(stack):
 all_bin_lis[b_index][sp_index + 1][sc_index + 1][it_index] 
= [item, stack_dict.get(item)]
 # 制作 cut_program.csv 表
 # 小心计算序号是 1 到 n,引用序号要变成 0 到 n-1
 # [材质, bin_index, item_index, 起点 x 坐标, 起点 y 坐标, x 方向长度(width), 
y 方向长度(length)]
 cut_program_lis = []
 for bin_index, bin in enumerate(all_bin_lis):
 # 整个图
 fig, ax = plt.subplots()
 ax.spines['right'].set_visible(False)
 ax.spines['top'].set_visible(False)
 ax.spines['left'].set_visible(False)
 ax.spines['bottom'].set_visible(False)
 ax.plot([0, 1220], [0, 0], color="k", linewidth=2.5)
 ax.plot([1220, 1220], [0, 2440], color="k", linewidth=2.5)
 ax.plot([0, 0], [0, 2440], color="k", linewidth=2.5)
 ax.plot([0, 1220], [2440, 2440], color="k", linewidth=2.5)
 # stripe 的直线位置
 total_stripe_length = 0.
 for stripe_index, stripe in enumerate(bin[1:]):
 stripe_length, stripe_width = info_stripe_dict.get(stripe[0])[0], 
info_stripe_dict.get(stripe[0])[1]
 total_stripe_length += stripe_length
 ax.plot([0, 1220], [total_stripe_length, total_stripe_length], color="k", 
linewidth=2)
 # stack 的竖线位置
 total_stack_width = 0.
 for stack_index, stack in enumerate(*stripe[1:]):
stack_length, stack_width = info_stack_dict.get(stack[0])[0], 
info_stack_dict.get(stack[0])[1]
 total_stack_width += stack_width
ax.plot([total_stack_width, total_stack_width], 
[total_stripe_length - stripe_length, total_stripe_length], color="g", linewidth=1.5)
 # item 的位置
 total_item_length = 0.
 for item_index, item in enumerate(*stack[1:]):
 item_length, item_width = data[item - 1][4], data[item - 1][5]
 total_item_length += item_length
 cut_program_lis.append([data[item - 1][2], bin[0], data[item - 1][1], 
total_stack_width - stack_width, total_item_length - item_length + total_stripe_length -
stripe_length, stack_width, item_length])
 ax.plot([total_stack_width - stack_width, total_stack_width], 
[total_item_length + total_stripe_length - stripe_length, total_item_length+ 
total_stripe_length - stripe_length], color="y", linewidth=1)
 adjust_text([ax.text(x=(total_stack_width - stack_width + 
total_stack_width) / 2, y= (total_item_length - 3*item_length/10) + total_stripe_length -
stripe_length , rotation=60, s="id:{0}".format(data[item - 1][1]), ha="left")])
 ax.fill_between([total_stack_width - stack_width, total_stack_width], 
total_item_length + total_stripe_length - stripe_length, stripe_length + total_stripe_length 
- stripe_length, facecolor='dimgray', alpha=1)
 ax.fill_between([total_stack_width, 1220], total_stripe_length - stripe_length, 
total_stripe_length, facecolor='dimgray', alpha=1)
 ax.fill_between([0, 1220], total_stripe_length, 2440, facecolor='dimgray', alpha=1)
 paths = os.path.join(self.path, "cutting_pic{0}.jpg".format(bin[0]))
 plt.savefig(paths)
 plt.close()
cut_program = pd.DataFrame(cut_program_lis)
cut_program.columns = ['原片材质', '原片序号', '产品 id', '产品 x 坐标', '产品 y 坐标', '
产品 x 方向长度', '产品 y 方向长度']
return cut_program
すべての論文については、以下の「QQ 名刺のモデリングのみ」を参照してください。QQ 名刺をクリックしてください。

おすすめ

転載: blog.csdn.net/weixin_43292788/article/details/132834908