增加超启发式线体优化算法

This commit is contained in:
2024-05-17 22:52:49 +08:00
parent 6fa1f53f69
commit 7c9a900b95
13 changed files with 1731 additions and 1109 deletions

View File

@ -11,13 +11,13 @@ from base_optimizer.result_analysis import *
# TODO: nozzle tool available restriction
# TODO: consider with the PCB placement topology
def assembly_time_estimator(assignment_points, component_feeders, component_nozzle):
def assembly_time_estimator(assignment_points, arranged_feeders, component_data):
nozzle_heads, nozzle_points = defaultdict(int), defaultdict(int)
for idx, points in enumerate(assignment_points):
if points == 0:
continue
nozzle_points[component_nozzle[idx]] += points
nozzle_heads[component_nozzle[idx]] = 1
nozzle_points[component_data.iloc[idx]['nz']] += points
nozzle_heads[component_data.iloc[idx]['nz']] = 1
while sum(nozzle_heads.values()) != max_head_index:
max_cycle_nozzle = None
@ -174,10 +174,11 @@ def assembly_time_estimator(assignment_points, component_feeders, component_nozz
for idx, points in enumerate(assignment_points):
if points == 0:
continue
reminder_points = points % component_feeders[idx]
for _ in range(component_feeders[idx]):
feeder_limit = int(component_data.iloc[idx]['feeder-limit'])
reminder_points = points % feeder_limit
for _ in range(feeder_limit):
cp_info.append(
[idx, points // component_feeders[idx] + (1 if reminder_points > 0 else 0), component_nozzle[idx]])
[idx, points // feeder_limit + (1 if reminder_points > 0 else 0), component_data.iloc[idx]['nz']])
reminder_points -= 1
cp_info.sort(key=lambda x: -x[1])
@ -204,46 +205,35 @@ def assembly_time_estimator(assignment_points, component_feeders, component_nozz
t_place * placement_counter + 0.1 * pickup_movement
def assemblyline_optimizer_heuristic(pcb_data, component_data, machine_number):
def line_optimizer_heuristic(component_data, machine_number):
# the number of placement points, the number of available feeders, and nozzle type of component respectively
component_number = len(component_data)
component_points = [0 for _ in range(component_number)]
component_feeders = [0 for _ in range(component_number)]
component_nozzle = [0 for _ in range(component_number)]
component_part = [0 for _ in range(component_number)]
nozzle_points = defaultdict(int) # the number of placements of nozzle
for _, data in pcb_data.iterrows():
part_index = component_data[component_data['part'] == data['part']].index.tolist()[0]
nozzle = component_data.loc[part_index]['nz']
component_points[part_index] += 1
component_feeders[part_index] = component_data.loc[part_index]['feeder-limit']
# component_feeders[part_index] = math.ceil(component_data.loc[part_index]['feeder-limit'] / max_feeder_limit)
component_nozzle[part_index] = nozzle
component_part[part_index] = data['part']
nozzle_points[nozzle] += 1
total_points = 0
for _, data in component_data.iterrows():
nozzle = data['nz']
nozzle_points[nozzle] += data['points']
total_points += data['point']
# first step: generate the initial solution with equalized workload
assignment_result = [[0 for _ in range(len(component_points))] for _ in range(machine_number)]
assignment_result = [[0 for _ in range(len(component_data))] for _ in range(machine_number)]
assignment_points = [0 for _ in range(machine_number)]
average_points = len(pcb_data) // machine_number
average_points = total_points // machine_number
weighted_points = list(
map(lambda x: x[1] + 1e-5 * nozzle_points[component_nozzle[x[0]]], enumerate(component_points)))
map(lambda _, data: data['points'] + 1e-5 * nozzle_points[data['nz']], component_data.iterrows()))
# for part_index in np.argsort(weighted_points)[::-1]:
for part_index in np.argsort(weighted_points)[::-1]:
if (total_points := component_points[part_index]) == 0: # total placements for each component type
if (total_points := component_data.iloc[part_index]['points']) == 0: # total placements for each component type
continue
machine_set = []
# define the machine that assigning placement points (considering the feeder limitation)
for machine_index in np.argsort(assignment_points):
if len(machine_set) >= component_points[part_index] or len(machine_set) >= component_feeders[part_index]:
if len(machine_set) >= component_data.iloc[part_index]['points'] or len(machine_set) >= \
component_data.iloc[part_index]['feeder-limit']:
break
machine_set.append(machine_index)
@ -308,7 +298,7 @@ def assemblyline_optimizer_heuristic(pcb_data, component_data, machine_number):
arranged_feeders[machine_index] = [0 for _ in range(len(component_data))]
for part_index in range(len(component_data)):
feeder_limit = component_feeders[part_index] # 总体可用数
feeder_limit = component_data.iloc[part_index]['feeder-limit'] # 总体可用数
for machine_index in range(machine_number):
if assignment_result[machine_index][part_index] == 0:
continue
@ -318,7 +308,7 @@ def assemblyline_optimizer_heuristic(pcb_data, component_data, machine_number):
assert feeder_limit >= 0
for part_index in range(len(component_data)):
total_feeder_limit = component_feeders[part_index] - sum(
total_feeder_limit = component_data.iloc[part_index]['feeder-limit'] - sum(
[arranged_feeders[machine_index][part_index] for machine_index in range(machine_number)])
while total_feeder_limit > 0:
max_ratio, max_ratio_machine = None, -1
@ -336,7 +326,7 @@ def assemblyline_optimizer_heuristic(pcb_data, component_data, machine_number):
for machine_index in range(machine_number):
assembly_time.append(
assembly_time_estimator(assignment_result[machine_index], arranged_feeders[machine_index],
component_nozzle))
component_data))
chip_per_hour.append(sum(assignment_result[machine_index]) / (assembly_time[-1] + 1e-10))
max_assembly_time = max(assembly_time)
@ -351,7 +341,6 @@ def assemblyline_optimizer_heuristic(pcb_data, component_data, machine_number):
# third step: adjust the assignment results to reduce maximal assembly time among all machines
# ideal averagely assigned points
total_points = len(pcb_data)
average_assign_points = [round(total_points * chip_per_hour[mi] / sum(chip_per_hour)) for mi in
range(machine_number)]
@ -391,7 +380,7 @@ def assemblyline_optimizer_heuristic(pcb_data, component_data, machine_number):
tmp_reallocate_result[supply_mi] -= reallocate_points
tmp_reallocate_result[demand_mi] += reallocate_points
if sum(1 for pt in tmp_reallocate_result if pt > 0) > component_feeders[part_index]:
if sum(1 for pt in tmp_reallocate_result if pt > 0) > component_data.iloc[part_index]['feeder-limit']:
continue
assignment_result[supply_mi][part_index] -= reallocate_points