调整工程架构,增补了几种算法,初步添加神经网路训练拟合代码
This commit is contained in:
@ -1,12 +1,8 @@
|
||||
import copy
|
||||
import math
|
||||
import random
|
||||
import numpy as np
|
||||
|
||||
from base_optimizer.optimizer_common import *
|
||||
|
||||
|
||||
def objective_value_calculate(component_assignment, component_nozzle, task_block_weight):
|
||||
# 生产过程中不允许吸嘴更换/点的拾取贴装仅与供料器槽位/模组相关
|
||||
def objective_value_calculate(component_assignment, component_nozzle, task_block_weight, machine_number):
|
||||
machine_assembly_time = []
|
||||
for machine_index in range(max_machine_index):
|
||||
task_block_number, total_point_number = 0, sum(component_assignment[machine_index])
|
||||
@ -39,10 +35,10 @@ def objective_value_calculate(component_assignment, component_nozzle, task_block
|
||||
return max(machine_assembly_time)
|
||||
|
||||
|
||||
def random_component_assignment(component_points, component_nozzle, component_feeders, task_block_weight):
|
||||
def random_component_assignment(component_points, component_nozzle, component_feeders, task_block_weight, machine_number):
|
||||
component_points_cpy = copy.deepcopy(component_points)
|
||||
component_number = len(component_points_cpy)
|
||||
assignment_result = [[0 for _ in range(component_number)] for _ in range(max_machine_index)]
|
||||
assignment_result = [[0 for _ in range(component_number)] for _ in range(machine_number)]
|
||||
|
||||
# == the set of feasible component type for each nozzle type
|
||||
nozzle_part_list = defaultdict(list)
|
||||
@ -52,7 +48,7 @@ def random_component_assignment(component_points, component_nozzle, component_fe
|
||||
selected_part = []
|
||||
for part_list in nozzle_part_list.values():
|
||||
part = random.sample(part_list, 1)[0]
|
||||
machine_index = random.randint(0, max_machine_index - 1)
|
||||
machine_index = random.randint(0, machine_number - 1)
|
||||
|
||||
assignment_result[machine_index][part] += 1
|
||||
component_points_cpy[part] -= 1
|
||||
@ -63,24 +59,24 @@ def random_component_assignment(component_points, component_nozzle, component_fe
|
||||
if part in selected_part:
|
||||
continue
|
||||
|
||||
assignment_result[random.randint(0, max_machine_index - 1)][part] += 1
|
||||
assignment_result[random.randint(0, machine_number - 1)][part] += 1
|
||||
component_points_cpy[part] -= 1
|
||||
|
||||
machine_assign = list(range(max_machine_index))
|
||||
machine_assign = list(range(machine_number))
|
||||
random.shuffle(machine_assign)
|
||||
finished_assign_counter = 0
|
||||
while finished_assign_counter < component_number:
|
||||
# todo: feeder limit restriction
|
||||
for machine_index in machine_assign:
|
||||
part = random.randint(0, component_number - 1)
|
||||
feeder_counter = 0
|
||||
for idx in range(max_machine_index):
|
||||
for idx in range(machine_number):
|
||||
if assignment_result[idx][part] > 0 or idx == machine_index:
|
||||
feeder_counter += 1
|
||||
|
||||
if component_points_cpy[part] == 0 or feeder_counter > component_feeders[part]:
|
||||
continue
|
||||
|
||||
# feeder limit restriction
|
||||
points = random.randint(1, component_points_cpy[part])
|
||||
assignment_result[machine_index][part] += points
|
||||
component_points_cpy[part] -= points
|
||||
@ -96,15 +92,16 @@ def greedy_component_assignment(component_points, component_nozzle, component_fe
|
||||
pass # 不清楚原文想说什么
|
||||
|
||||
|
||||
def local_search_component_assignment(component_points, component_nozzle, component_feeders, task_block_weight):
|
||||
def local_search_component_assignment(component_points, component_nozzle, component_feeders, task_block_weight,
|
||||
machine_number):
|
||||
# maximum number of iterations : 5000
|
||||
# maximum number of unsuccessful iterations: 50
|
||||
component_number = len(component_points)
|
||||
iteration_counter, unsuccessful_iteration_counter = 5000, 50
|
||||
optimal_val, optimal_assignment = random_component_assignment(component_points, component_nozzle, component_feeders,
|
||||
task_block_weight)
|
||||
task_block_weight, machine_number)
|
||||
for _ in range(iteration_counter):
|
||||
machine_index = random.randint(0, max_machine_index - 1)
|
||||
machine_index = random.randint(0, machine_number - 1)
|
||||
if sum(optimal_assignment[machine_index]) == 0:
|
||||
continue
|
||||
|
||||
@ -120,9 +117,9 @@ def local_search_component_assignment(component_points, component_nozzle, compon
|
||||
swap_machine_index = None
|
||||
while cyclic_counter <= 2 * machine_index:
|
||||
cyclic_counter += 1
|
||||
swap_machine_index = random.randint(0, max_machine_index - 1)
|
||||
swap_machine_index = random.randint(0, machine_number - 1)
|
||||
feeder_available = 0
|
||||
for machine in range(max_machine_index):
|
||||
for machine in range(machine_number):
|
||||
if optimal_assignment[machine][component_index] or machine == swap_machine_index:
|
||||
feeder_available += 1
|
||||
|
||||
@ -143,18 +140,18 @@ def local_search_component_assignment(component_points, component_nozzle, compon
|
||||
return optimal_val, optimal_assignment
|
||||
|
||||
|
||||
def reconfig_crossover_operation(component_points, component_feeders, parent1, parent2):
|
||||
def reconfig_crossover_operation(component_points, component_feeders, parent1, parent2, machine_number):
|
||||
offspring1, offspring2 = copy.deepcopy(parent1), copy.deepcopy(parent2)
|
||||
component_number = len(component_points)
|
||||
|
||||
# === crossover ===
|
||||
mask_bit = []
|
||||
for _ in range(max_machine_index):
|
||||
for _ in range(machine_number):
|
||||
mask_bit.append(random.randint(0, 1))
|
||||
if sum(mask_bit) == 0 or sum(mask_bit) == max_machine_index:
|
||||
if sum(mask_bit) == 0 or sum(mask_bit) == machine_number:
|
||||
return offspring1, offspring2
|
||||
|
||||
for machine_index in range(max_machine_index):
|
||||
for machine_index in range(machine_number):
|
||||
if mask_bit:
|
||||
offspring1[machine_index] = copy.deepcopy(parent1[machine_index])
|
||||
offspring2[machine_index] = copy.deepcopy(parent2[machine_index])
|
||||
@ -166,20 +163,20 @@ def reconfig_crossover_operation(component_points, component_feeders, parent1, p
|
||||
# equally to reach the correct number
|
||||
for component_index in range(component_number):
|
||||
for offspring in [offspring1, offspring2]:
|
||||
additional_points = sum([offspring[mt][component_index] for mt in range(max_machine_index)]) - \
|
||||
additional_points = sum([offspring[mt][component_index] for mt in range(machine_number)]) - \
|
||||
component_points[component_index]
|
||||
if additional_points > 0:
|
||||
# if a component type has more placements, decrease the assigned values on every head equally keeping
|
||||
# the proportion of the number of placement among the heads
|
||||
points_list = []
|
||||
for machine_index in range(max_machine_index):
|
||||
for machine_index in range(machine_number):
|
||||
points = math.floor(
|
||||
additional_points * offspring[machine_index][component_index] / component_points[component_index])
|
||||
points_list.append(points)
|
||||
offspring[machine_index][component_index] -= points
|
||||
additional_points -= sum(points_list)
|
||||
|
||||
for machine_index in range(max_machine_index):
|
||||
for machine_index in range(machine_number):
|
||||
if additional_points == 0:
|
||||
break
|
||||
if offspring[machine_index][component_index] == 0:
|
||||
@ -189,7 +186,7 @@ def reconfig_crossover_operation(component_points, component_feeders, parent1, p
|
||||
elif additional_points < 0:
|
||||
# otherwise, increase the assigned nonzero values equally
|
||||
machine_set = []
|
||||
for machine_index in range(max_machine_index):
|
||||
for machine_index in range(machine_number):
|
||||
if offspring[machine_index][component_index] == 0:
|
||||
continue
|
||||
machine_set.append(machine_index)
|
||||
@ -205,29 +202,23 @@ def reconfig_crossover_operation(component_points, component_feeders, parent1, p
|
||||
offspring[machine_index][component_index] += 1
|
||||
additional_points -= 1
|
||||
|
||||
for part in range(component_number):
|
||||
pt = 0
|
||||
for mt in range(max_machine_index):
|
||||
pt+= offspring1[mt][part]
|
||||
if pt!=component_points[part]:
|
||||
print('')
|
||||
for part in range(component_number):
|
||||
pt = 0
|
||||
for mt in range(max_machine_index):
|
||||
pt+= offspring2[mt][part]
|
||||
if pt!=component_points[part]:
|
||||
print('')
|
||||
# === 结果校验 ===
|
||||
for offspring in [offspring1, offspring2]:
|
||||
for part in range(component_number):
|
||||
pt = sum(offspring[mt][part] for mt in range(machine_number))
|
||||
assert pt == component_points[part]
|
||||
|
||||
return offspring1, offspring2
|
||||
|
||||
|
||||
def reconfig_mutation_operation(component_feeders, parent):
|
||||
def reconfig_mutation_operation(component_feeders, parent, machine_number):
|
||||
offspring = copy.deepcopy(parent)
|
||||
|
||||
swap_direction = random.randint(0, 1)
|
||||
if swap_direction:
|
||||
swap_machine1, swap_machine2 = random.sample(list(range(max_machine_index)), 2)
|
||||
swap_machine1, swap_machine2 = random.sample(list(range(machine_number)), 2)
|
||||
else:
|
||||
swap_machine2, swap_machine1 = random.sample(list(range(max_machine_index)), 2)
|
||||
swap_machine2, swap_machine1 = random.sample(list(range(machine_number)), 2)
|
||||
|
||||
component_list = []
|
||||
for component_index, points in enumerate(offspring[swap_machine1]):
|
||||
@ -248,7 +239,7 @@ def reconfig_mutation_operation(component_feeders, parent):
|
||||
return offspring
|
||||
|
||||
|
||||
def evolutionary_component_assignment(component_points, component_nozzle, component_feeders, task_block_weight):
|
||||
def evolutionary_component_assignment(component_points, component_nozzle, component_feeders, task_block_weight, machine_number):
|
||||
# population size: 10
|
||||
# probability of the mutation: 0.1
|
||||
# probability of the crossover: 0.8
|
||||
@ -260,7 +251,8 @@ def evolutionary_component_assignment(component_points, component_nozzle, compon
|
||||
population = []
|
||||
for _ in range(population_size):
|
||||
population.append(
|
||||
random_component_assignment(component_points, component_nozzle, component_feeders, task_block_weight)[1])
|
||||
random_component_assignment(component_points, component_nozzle, component_feeders, task_block_weight,
|
||||
machine_number)[1])
|
||||
|
||||
with tqdm(total=generation_number) as pbar:
|
||||
pbar.set_description('evolutionary algorithm process for PCB assembly line balance')
|
||||
@ -270,7 +262,7 @@ def evolutionary_component_assignment(component_points, component_nozzle, compon
|
||||
# calculate fitness value
|
||||
pop_val = []
|
||||
for individual in population:
|
||||
pop_val.append(objective_value_calculate(individual, component_nozzle, task_block_weight))
|
||||
pop_val.append(objective_value_calculate(individual, component_nozzle, task_block_weight, machine_number))
|
||||
|
||||
select_index = get_top_k_value(pop_val, population_size - len(new_population), reverse=False)
|
||||
population = [population[idx] for idx in select_index]
|
||||
@ -278,7 +270,7 @@ def evolutionary_component_assignment(component_points, component_nozzle, compon
|
||||
|
||||
population += new_population
|
||||
for individual in new_population:
|
||||
pop_val.append(objective_value_calculate(individual, component_nozzle, task_block_weight))
|
||||
pop_val.append(objective_value_calculate(individual, component_nozzle, task_block_weight, machine_number))
|
||||
|
||||
# min-max convert
|
||||
max_val = max(pop_val)
|
||||
@ -297,13 +289,14 @@ def evolutionary_component_assignment(component_points, component_nozzle, compon
|
||||
break
|
||||
|
||||
offspring1, offspring2 = reconfig_crossover_operation(component_points, component_feeders,
|
||||
population[index1], population[index2])
|
||||
population[index1], population[index2],
|
||||
machine_number)
|
||||
|
||||
if np.random.random() < mutation_rate:
|
||||
offspring1 = reconfig_mutation_operation(component_feeders, offspring1)
|
||||
offspring1 = reconfig_mutation_operation(component_feeders, offspring1, machine_number)
|
||||
|
||||
if np.random.random() < mutation_rate:
|
||||
offspring2 = reconfig_mutation_operation(component_feeders, offspring2)
|
||||
offspring2 = reconfig_mutation_operation(component_feeders, offspring2, machine_number)
|
||||
|
||||
new_population.append(offspring1)
|
||||
new_population.append(offspring2)
|
||||
@ -313,7 +306,7 @@ def evolutionary_component_assignment(component_points, component_nozzle, compon
|
||||
return min(pop_val), population[np.argmin(pop_val)]
|
||||
|
||||
|
||||
def reconfiguration_optimizer(pcb_data, component_data):
|
||||
def reconfiguration_optimizer(pcb_data, component_data, machine_number):
|
||||
# === data preparation ===
|
||||
component_number = len(component_data)
|
||||
|
||||
@ -335,20 +328,28 @@ def reconfiguration_optimizer(pcb_data, component_data):
|
||||
# === assignment of heads to modules is omitted ===
|
||||
optimal_assignment, optimal_val = [], None
|
||||
|
||||
task_block_weight = 5 # element from list [0, 1, 2, 5, 10]
|
||||
task_block_weight = 5 # element from list [0, 1, 2, 5, 10] task_block ~= cycle
|
||||
# === assignment of components to heads
|
||||
for i in range(4):
|
||||
for i in range(5):
|
||||
if i == 0:
|
||||
# random
|
||||
val, assignment = random_component_assignment(component_points, component_nozzle, component_feeders,
|
||||
task_block_weight)
|
||||
task_block_weight, machine_number)
|
||||
elif i == 1:
|
||||
# brute force
|
||||
# which is proved to be useless, since it only ran in reasonable time for the smaller test instances
|
||||
continue
|
||||
elif i == 2:
|
||||
val, assignment = local_search_component_assignment(component_points, component_nozzle,
|
||||
component_feeders, task_block_weight)
|
||||
# local search
|
||||
val, assignment = local_search_component_assignment(component_points, component_nozzle, component_feeders,
|
||||
task_block_weight, machine_number)
|
||||
elif i == 3:
|
||||
# evolutionary
|
||||
val, assignment = evolutionary_component_assignment(component_points, component_nozzle, component_feeders,
|
||||
task_block_weight, machine_number)
|
||||
else:
|
||||
val, assignment = evolutionary_component_assignment(component_points, component_nozzle,
|
||||
component_feeders, task_block_weight)
|
||||
# greedy: unclear description
|
||||
continue
|
||||
|
||||
if optimal_val is None or val < optimal_val:
|
||||
optimal_val, optimal_assignment = val, assignment.copy()
|
||||
|
Reference in New Issue
Block a user