调整工程架构,增补了几种算法,初步添加神经网路训练拟合代码

This commit is contained in:
2024-03-29 22:10:07 +08:00
parent 800057e000
commit bae7e4e2c3
18 changed files with 2459 additions and 354 deletions

View File

@ -1,18 +1,8 @@
import copy
import math
import matplotlib.pyplot as plt
import pandas as pd
from base_optimizer.optimizer_scanbased import *
from base_optimizer.optimizer_celldivision import *
from base_optimizer.optimizer_hybridgenetic import *
from base_optimizer.optimizer_feederpriority import *
from dataloader import *
from optimizer_genetic import *
from optimizer_heuristic import *
from optimizer_reconfiguration import *
from base_optimizer.optimizer_interface import *
def deviation(data):
@ -23,16 +13,20 @@ def deviation(data):
return variance / len(data)
def optimizer(pcb_data, component_data, assembly_line_optimizer, single_machine_optimizer):
# todo: 由于吸嘴更换更因素的存在在处理PCB8数据时遗传算法因在负载均衡过程中对这一因素进行了考虑性能更优
# assignment_result = assemblyline_optimizer_heuristic(pcb_data, component_data)
# assignment_result = assemblyline_optimizer_genetic(pcb_data, component_data)
assignment_result = reconfiguration_optimizer(pcb_data, component_data)
def optimizer(pcb_data, component_data, line_optimizer, machine_optimizer, machine_number):
if line_optimizer == "heuristic":
assignment_result = assemblyline_optimizer_heuristic(pcb_data, component_data, machine_number)
elif line_optimizer == "genetic":
assignment_result = assemblyline_optimizer_genetic(pcb_data, component_data, machine_number)
elif line_optimizer == "reconfiguration":
assignment_result = reconfiguration_optimizer(pcb_data, component_data, machine_number)
else:
return
assignment_result_cpy = copy.deepcopy(assignment_result)
placement_points, placement_time = [], []
partial_pcb_data, partial_component_data = defaultdict(pd.DataFrame), defaultdict(pd.DataFrame)
for machine_index in range(max_machine_index):
for machine_index in range(machine_number):
partial_pcb_data[machine_index] = pd.DataFrame(columns=pcb_data.columns)
partial_component_data[machine_index] = component_data.copy(deep=True)
placement_points.append(sum(assignment_result[machine_index]))
@ -42,29 +36,29 @@ def optimizer(pcb_data, component_data, assembly_line_optimizer, single_machine_
# === averagely assign available feeder ===
for part_index, data in component_data.iterrows():
feeder_limit = data['feeder-limit']
feeder_points = [assignment_result[machine_index][part_index] for machine_index in range(max_machine_index)]
feeder_points = [assignment_result[machine_index][part_index] for machine_index in range(machine_number)]
for machine_index in range(max_machine_index):
for machine_index in range(machine_number):
if feeder_points[machine_index] == 0:
continue
arg_feeder = max(math.floor(feeder_points[machine_index] / sum(feeder_points) * data['feeder-limit']), 1)
partial_component_data[machine_index].loc[part_index]['feeder-limit'] = arg_feeder
partial_component_data[machine_index].loc[part_index, 'feeder-limit'] = arg_feeder
feeder_limit -= arg_feeder
for machine_index in range(max_machine_index):
for machine_index in range(machine_number):
if feeder_limit <= 0:
break
if feeder_points[machine_index] == 0:
continue
partial_component_data[machine_index].loc[part_index]['feeder-limit'] += 1
partial_component_data[machine_index].loc[part_index, 'feeder-limit'] += 1
feeder_limit -= 1
for machine_index in range(max_machine_index):
for machine_index in range(machine_number):
if feeder_points[machine_index] > 0:
assert partial_component_data[machine_index].loc[part_index]['feeder-limit'] > 0
assert partial_component_data[machine_index].loc[part_index, 'feeder-limit'] > 0
# === assign placements ===
component_machine_index = [0 for _ in range(len(component_data))]
@ -102,7 +96,7 @@ def optimizer(pcb_data, component_data, assembly_line_optimizer, single_machine_
assign_part_index.append(idx_)
variance = deviation(assign_part_point)
while start_index != end_index:
while start_index <= end_index:
part_info_index = assign_part_index[np.argmax(assign_part_point)]
if part_info[part_info_index][2] < part_info[part_info_index][3]: # 供料器数目上限的限制
@ -122,7 +116,7 @@ def optimizer(pcb_data, component_data, assembly_line_optimizer, single_machine_
break
variance = new_variance
assign_part_index, assign_part_point = new_assign_part_index, new_assign_part_point
assign_part_index, assign_part_point = new_assign_part_index.copy(), new_assign_part_point.copy()
else:
break
@ -132,108 +126,39 @@ def optimizer(pcb_data, component_data, assembly_line_optimizer, single_machine_
# update available feeder number
max_avl_feeder = max(part_info, key=lambda x: x[2])[2]
for info in part_info:
partial_component_data[machine_index].loc[info[0]]['feeder-limit'] = math.ceil(info[2] / max_avl_feeder)
partial_component_data[machine_index].loc[info[0], 'feeder-limit'] = math.ceil(info[2] / max_avl_feeder)
placement_time.append(base_optimizer(machine_index + 1, data, partial_component_data[machine_index],
feeder_data=pd.DataFrame(columns=['slot', 'part', 'arg']),
method=single_machine_optimizer, hinter=True))
method=machine_optimizer, hinter=True).placement_time)
average_time, standard_deviation_time = sum(placement_time) / max_machine_index, 0
for machine_index in range(max_machine_index):
average_time, standard_deviation_time = sum(placement_time) / machine_number, 0
for machine_index in range(machine_number):
total_component_types = 0
for points in assignment_result_cpy[machine_index]:
if points:
total_component_types += 1
print('assembly time for machine ' + str(machine_index + 1) + ': ' + str(
placement_time[machine_index]) + ' s, ' + 'total placements: ' + str(placement_points[machine_index]))
placement_time[machine_index]) + ' s, ' + 'total placements: ' + str(placement_points[machine_index])
+ ', total component types: ' + str(total_component_types))
standard_deviation_time += pow(placement_time[machine_index] - average_time, 2)
standard_deviation_time /= max_machine_index
standard_deviation_time /= machine_number
standard_deviation_time = math.sqrt(standard_deviation_time)
print('finial assembly time: ' + str(max(placement_time)) + 's, standard deviation: ' + str(standard_deviation_time))
# todo: 不同类型元件的组装时间差异
def base_optimizer(machine_index, pcb_data, component_data, feeder_data=None, method='', hinter=False):
if method == 'cell_division': # 基于元胞分裂的遗传算法
component_result, cycle_result, feeder_slot_result = optimizer_celldivision(pcb_data, component_data,
hinter=False)
placement_result, head_sequence = greedy_placement_route_generation(component_data, pcb_data, component_result,
cycle_result, feeder_slot_result)
elif method == 'feeder_scan': # 基于基座扫描的供料器优先算法
# 第1步分配供料器位置
nozzle_pattern = feeder_allocate(component_data, pcb_data, feeder_data, figure=False)
# 第2步扫描供料器基座确定元件拾取的先后顺序
component_result, cycle_result, feeder_slot_result = feeder_base_scan(component_data, pcb_data, feeder_data,
nozzle_pattern)
# 第3步贴装路径规划
placement_result, head_sequence = greedy_placement_route_generation(component_data, pcb_data, component_result,
cycle_result, feeder_slot_result)
# placement_result, head_sequence = beam_search_for_route_generation(component_data, pcb_data, component_result,
# cycle_result, feeder_slot_result)
elif method == 'hybrid_genetic': # 基于拾取组的混合遗传算法
component_result, cycle_result, feeder_slot_result, placement_result, head_sequence = optimizer_hybrid_genetic(
pcb_data, component_data, hinter=False)
elif method == 'aggregation': # 基于batch-level的整数规划 + 启发式算法
component_result, cycle_result, feeder_slot_result, placement_result, head_sequence = optimizer_aggregation(
component_data, pcb_data)
elif method == 'genetic_scanning':
component_result, cycle_result, feeder_slot_result, placement_result, head_sequence = optimizer_genetic_scanning(
component_data, pcb_data, hinter=False)
else:
raise 'method is not existed'
if hinter:
optimization_assign_result(component_data, pcb_data, component_result, cycle_result, feeder_slot_result,
nozzle_hinter=True, component_hinter=False, feeder_hinter=False)
print('----- Placement machine ' + str(machine_index) + ' ----- ')
print('-Cycle counter: {}'.format(sum(cycle_result)))
total_nozzle_change_counter, total_pick_counter = 0, 0
total_pick_movement = 0
assigned_nozzle = ['' if idx == -1 else component_data.loc[idx]['nz'] for idx in component_result[0]]
for cycle in range(len(cycle_result)):
pick_slot = set()
for head in range(max_head_index):
if (idx := component_result[cycle][head]) == -1:
continue
nozzle = component_data.loc[idx]['nz']
if nozzle != assigned_nozzle[head]:
if assigned_nozzle[head] != '':
total_nozzle_change_counter += 1
assigned_nozzle[head] = nozzle
pick_slot.add(feeder_slot_result[cycle][head] - head * interval_ratio)
total_pick_counter += len(pick_slot) * cycle_result[cycle]
pick_slot = list(pick_slot)
pick_slot.sort()
for idx in range(len(pick_slot) - 1):
total_pick_movement += abs(pick_slot[idx+1] - pick_slot[idx])
print('-Nozzle change counter: {}'.format(total_nozzle_change_counter))
print('-Pick operation counter: {}'.format(total_pick_counter))
print('-Pick movement: {}'.format(total_pick_movement))
print('------------------------------ ')
# 估算贴装用时
return placement_time_estimate(component_data, pcb_data, component_result, cycle_result, feeder_slot_result,
placement_result, head_sequence, hinter=False)
@timer_wrapper
def main():
# warnings.simplefilter('ignore')
warnings.simplefilter(action='ignore', category=FutureWarning)
# 参数解析
parser = argparse.ArgumentParser(description='assembly line optimizer implementation')
parser.add_argument('--filename', default='PCB.txt', type=str, help='load pcb data')
parser.add_argument('--auto_register', default=1, type=int, help='register the component according the pcb data')
parser.add_argument('--base_optimizer', default='feeder_scan', type=str, help='base optimizer for single machine')
parser.add_argument('--assembly_optimizer', default='heuristic', type=str, help='optimizer for PCB Assembly Line')
parser.add_argument('--feeder_limit', default=2, type=int,
parser.add_argument('--machine_number', default=3, type=int, help='the number of machine in the assembly line')
parser.add_argument('--machine_optimizer', default='feeder_scan', type=str, help='optimizer for single machine')
parser.add_argument('--line_optimizer', default='genetic', type=str, help='optimizer for PCB Assembly Line')
parser.add_argument('--feeder_limit', default=1, type=int,
help='the upper feeder limit for each type of component')
params = parser.parse_args()
@ -243,9 +168,8 @@ def main():
# 加载PCB数据
pcb_data, component_data, _ = load_data(params.filename, default_feeder_limit=params.feeder_limit,
cp_auto_register=params.auto_register) # 加载PCB数据
optimizer(pcb_data, component_data, params.assembly_optimizer, params.base_optimizer)
cp_auto_register=params.auto_register, load_feeder_data=False) # 加载PCB数据
optimizer(pcb_data, component_data, params.line_optimizer, params.machine_optimizer, params.machine_number)
if __name__ == '__main__':