整线优化第一版论文定稿工程

增加了整线批量测试
修改了现有min-max模型路径
修改了遗传算法整体框架
估计器增加异常数据剔除
封装优化结果类
修改供料器扫描算法中重复吸嘴组的判定
This commit is contained in:
2024-06-26 09:44:08 +08:00
parent cbeba48da0
commit 37f4e5b02c
14 changed files with 749 additions and 669 deletions

View File

@ -1,11 +1,3 @@
import os
import pickle
import random
import numpy as np
import pandas as pd
import torch.nn
from base_optimizer.optimizer_interface import *
from generator import *
from estimator import *
@ -22,8 +14,6 @@ class Heuristic:
class LeastPoints(Heuristic):
@staticmethod
def apply(cp_points, cp_nozzle, cp_assign, machine_assign):
if len(machine_assign) == 1:
return machine_assign[0]
machine_points = []
for machine_idx in machine_assign:
if len(cp_assign[machine_idx]) == 0:
@ -35,8 +25,6 @@ class LeastPoints(Heuristic):
class LeastNzTypes(Heuristic):
@staticmethod
def apply(cp_points, cp_nozzle, cp_assign, machine_assign):
if len(machine_assign) == 1:
return machine_assign[0]
machine_nozzle = []
for machine_idx in machine_assign:
if len(cp_assign[machine_idx]) == 0:
@ -51,11 +39,7 @@ class LeastNzTypes(Heuristic):
class LeastCpTypes(Heuristic):
@staticmethod
def apply(cp_points, cp_nozzle, cp_assign, machine_assign):
if len(machine_assign) == 1:
return machine_assign[0]
machine_types = []
if len(machine_assign) == 1:
return machine_assign[0]
for machine_idx in machine_assign:
machine_types.append(
len(cp_assign[machine_idx]) + 1e-5 * sum(cp_points[cp] for cp in cp_assign[machine_idx]))
@ -65,20 +49,16 @@ class LeastCpTypes(Heuristic):
class LeastCpNzRatio(Heuristic):
@staticmethod
def apply(cp_points, cp_nozzle, cp_assign, machine_assign):
if len(machine_assign) == 1:
return machine_assign[0]
machine_nz_type, machine_cp_type = [], []
if len(machine_assign) == 1:
return machine_assign[0]
for machine_idx in machine_assign:
if len(cp_assign[machine_idx]) == 0:
return machine_idx
machine_nz_type.append(set(cp_nozzle[cp_idx] for cp_idx in cp_assign[machine_idx]))
machine_cp_type.append(len(cp_assign[machine_idx]))
min_idx = np.argmin([(machine_cp_type[idx] + 1e-5 * sum(cp_points[c] for c in cp_assign[idx])) / (
len(machine_nz_type[idx]) + 1e-5) for idx in range(len(machine_assign))])
min_idx = np.argmin([(machine_cp_type[idx] + 1e-5 * sum(
cp_points[c] for c in cp_assign[machine_assign[idx]])) / (len(machine_nz_type[idx]) + 1e-5) for idx in
range(len(machine_assign))])
return machine_assign[min_idx]
@ -104,8 +84,6 @@ def nozzle_assignment(cp_points, cp_nozzle, cp_assign):
class LeastCycle(Heuristic):
@staticmethod
def apply(cp_points, cp_nozzle, cp_assign, machine_assign):
if len(machine_assign) == 1:
return machine_assign[0]
machine_cycle = []
for machine_idx in machine_assign:
assign_component = cp_assign[machine_idx]
@ -123,8 +101,6 @@ class LeastCycle(Heuristic):
class LeastNzChange(Heuristic):
@staticmethod
def apply(cp_points, cp_nozzle, cp_assign, machine_assign):
if len(machine_assign) == 1:
return machine_assign[0]
machine_nozzle_change = []
for machine_idx in machine_assign:
assign_component = cp_assign[machine_idx]
@ -144,8 +120,6 @@ class LeastNzChange(Heuristic):
class LeastPickup(Heuristic):
@staticmethod
def apply(cp_points, cp_nozzle, cp_assign, machine_assign):
if len(machine_assign) == 1:
return machine_assign[0]
machine_pick_up = []
for machine_idx in machine_assign:
assign_component = cp_assign[machine_idx]
@ -208,18 +182,37 @@ def population_initialization(population_size, heuristic_map, cp_points):
def convert_assignment_result(heuristic_map, cp_index, cp_points, cp_nozzle, cp_feeders, component_list, individual,
machine_number):
component_number = len(cp_feeders.keys())
cp_assign = [[] for _ in range(machine_number)]
machine_all, machine_assign = list(range(machine_number)), defaultdict(set)
component_machine_assign = [[0 for _ in range(machine_number)] for _ in range(component_number)]
machine_assign_counter = [0 for _ in range(machine_number)]
data_mgr = DataMgr()
for idx, div_cp_idx in enumerate(component_list):
h = individual[idx % len(individual)]
cp_idx = cp_index[div_cp_idx]
if len(machine_assign[cp_idx]) < cp_feeders[cp_idx]:
machine_idx = heuristic_map[h].apply(cp_points, cp_nozzle, cp_assign, machine_all)
machine_assign = [] # 可被分配的机器索引
if sum(component_machine_assign[cp_idx][:]) < cp_feeders[cp_idx]:
for machine_idx in range(machine_number):
if component_machine_assign[cp_idx][machine_idx] or machine_assign_counter[
machine_idx] < data_mgr.max_component_types:
machine_assign.append(machine_idx)
machine_idx = heuristic_map[h].apply(cp_points, cp_nozzle, cp_assign, machine_assign)
else:
machine_idx = heuristic_map[h].apply(cp_points, cp_nozzle, cp_assign, list(machine_assign[cp_idx]))
for machine_idx in range(machine_number):
if component_machine_assign[cp_idx][machine_idx]:
machine_assign.append(machine_idx)
machine_idx = heuristic_map[h].apply(cp_points, cp_nozzle, cp_assign, machine_assign)
cp_assign[machine_idx].append(div_cp_idx)
machine_assign[cp_idx].add(machine_idx)
if component_machine_assign[cp_idx][machine_idx] == 0:
machine_assign_counter[machine_idx] += 1
component_machine_assign[cp_idx][machine_idx] = 1
return cp_assign
@ -292,30 +285,34 @@ def line_optimizer_hyperheuristic(component_data, pcb_data, machine_number):
'g': LeastNzChange,
'u': LeastPickup,
}
division_part = []
for _, data in component_data.iterrows():
division_part.extend([data.points / data.fdn for _ in range(data.fdn)])
division_points = sum(division_part) / len(division_part)
# genetic-based hyper-heuristic
crossover_rate, mutation_rate = 0.6, 0.1
population_size, n_generations = 20, 50
n_iterations = 10
population_size, total_generation = 20, 50
group_size = 10
estimator = NeuralEstimator()
best_val = None
best_heuristic_list = None
best_component_list = None
best_heuristic_list, best_component_list = None, None
cp_feeders, cp_nozzle = defaultdict(int), defaultdict(str)
cp_points, cp_index = defaultdict(int), defaultdict(int)
division_component_data = pd.DataFrame(columns=component_data.columns)
division_points = min(component_data['points'])
idx = 0
for cp_idx, data in component_data.iterrows():
cp_feeders[cp_idx] = data['fdn']
cp_feeders[cp_idx] = data.fdn
division_data = copy.deepcopy(data)
feeder_limit, total_points = division_data.fdn, division_data.points
feeder_limit = max(total_points // division_points * 3, feeder_limit)
if feeder_limit != 1:
feeder_limit = round(min(max(total_points // division_points * 1.5, feeder_limit), total_points))
# feeder_limit = total_points # 小规模数据启用
surplus_points = total_points % feeder_limit
for _ in range(feeder_limit):
division_data.fdn, division_data.points = 1, math.floor(total_points / feeder_limit)
@ -331,10 +328,9 @@ def line_optimizer_hyperheuristic(component_data, pcb_data, machine_number):
component_list = [idx for idx, data in division_component_data.iterrows() if data.points > 0]
board_width, board_height = pcb_data['x'].max() - pcb_data['x'].min(), pcb_data['y'].max() - pcb_data['y'].min()
with tqdm(total=n_generations * n_iterations) as pbar:
with tqdm(total=total_generation * group_size) as pbar:
pbar.set_description('hyper-heuristic algorithm process for PCB assembly line balance')
for _ in range(n_iterations):
for _ in range(group_size):
random.shuffle(component_list)
new_population = []
population = population_initialization(population_size, heuristic_map, cp_points)
@ -346,16 +342,17 @@ def line_optimizer_hyperheuristic(component_data, pcb_data, machine_number):
board_height, component_list, individual, machine_number, estimator)
pop_val.append(max(val))
for _ in range(n_generations):
select_index = get_top_k_value(pop_val, population_size - len(new_population), reverse=False)
population = [population[idx] for idx in select_index]
pop_val = [pop_val[idx] for idx in select_index]
for _ in range(total_generation):
population += new_population
for individual in new_population:
val = cal_individual_val(heuristic_map, cp_index, cp_points, cp_nozzle, cp_feeders, board_width,
board_height, component_list, individual, machine_number, estimator)
pop_val.append(max(val))
select_index = get_top_k_value(pop_val, population_size, reverse=False)
population = [population[idx] for idx in select_index]
pop_val = [pop_val[idx] for idx in select_index]
# min-max convert
max_val = max(pop_val)
sel_pop_val = list(map(lambda v: max_val - v, pop_val))
@ -383,8 +380,6 @@ def line_optimizer_hyperheuristic(component_data, pcb_data, machine_number):
new_population.append(offspring1)
new_population.append(offspring2)
if len(new_population) >= population_size * crossover_rate:
break
pbar.update(1)
val = cal_individual_val(heuristic_map, cp_index, cp_points, cp_nozzle, cp_feeders, board_width,
@ -407,6 +402,8 @@ def line_optimizer_hyperheuristic(component_data, pcb_data, machine_number):
continue
val = max(val,
exact_assembly_time(partial_pcb_data[machine_idx], partial_component_data[machine_idx]))
if best_val is not None and val > best_val:
break
if best_val is None or val < best_val:
best_val = val
@ -415,7 +412,7 @@ def line_optimizer_hyperheuristic(component_data, pcb_data, machine_number):
val = cal_individual_val(heuristic_map, cp_index, cp_points, cp_nozzle, cp_feeders, board_width, board_height,
best_component_list, best_heuristic_list, machine_number, estimator)
print(val)
machine_cp_points = convert_assignment_result(heuristic_map, cp_index, cp_points, cp_nozzle, cp_feeders,
best_component_list, best_heuristic_list, machine_number)
@ -423,7 +420,6 @@ def line_optimizer_hyperheuristic(component_data, pcb_data, machine_number):
for machine_idx in range(machine_number):
for idx in machine_cp_points[machine_idx]:
assignment_result[machine_idx][cp_index[idx]] += cp_points[idx]
return assignment_result