Commit 25c58c5b authored by Tong Li's avatar Tong Li

算法优化

parent 9d08cc4f
...@@ -465,7 +465,7 @@ public class ResourceGanttController { ...@@ -465,7 +465,7 @@ public class ResourceGanttController {
ParamValidator.validateSceneExists(sceneService, sceneId); ParamValidator.validateSceneExists(sceneService, sceneId);
planResultService.InsertOrderAuto(sceneId, newOrderData); // planResultService.InsertOrderAuto(sceneId, newOrderData);
return R.ok("自动插单成功"); return R.ok("自动插单成功");
} }
......
...@@ -17,7 +17,7 @@ public class ScheduleParams { ...@@ -17,7 +17,7 @@ public class ScheduleParams {
private static final int MIN_POPULATION_SIZE = 10; private static final int MIN_POPULATION_SIZE = 10;
private static final int MAX_POPULATION_SIZE = 50; private static final int MAX_POPULATION_SIZE = 50;
private static final int MIN_MAX_ITERATIONS = 50; private static final int MIN_MAX_ITERATIONS = 50;
private static final int MAX_MAX_ITERATIONS = 250; private static final int MAX_MAX_ITERATIONS = 100;
private static final float MIN_CROSSOVER_PROB = 0.6f; private static final float MIN_CROSSOVER_PROB = 0.6f;
private static final float MAX_CROSSOVER_PROB = 0.9f; private static final float MAX_CROSSOVER_PROB = 0.9f;
private static final float MIN_MUTATION_PROB = 0.2f; private static final float MIN_MUTATION_PROB = 0.2f;
......
...@@ -417,13 +417,13 @@ public class GeneticAlgorithm { ...@@ -417,13 +417,13 @@ public class GeneticAlgorithm {
} }
// 加载锁定工单到ResultOld // 加载锁定工单到ResultOld
List<GAScheduleResult> lockedOrders = GlobalCacheUtil.get("locked_orders_" + sceneId); // List<GAScheduleResult> lockedOrders = GlobalCacheUtil.get("locked_orders_" + sceneId);
if (lockedOrders != null && !lockedOrders.isEmpty()) { // if (lockedOrders != null && !lockedOrders.isEmpty()) {
chromosome.setResultOld(ProductionDeepCopyUtil.deepCopyList(lockedOrders, GAScheduleResult.class)); // chromosome.setResultOld(ProductionDeepCopyUtil.deepCopyList(lockedOrders, GAScheduleResult.class));
FileHelper.writeLogFile("将 " + lockedOrders.size() + " 个锁定工单加载到初始种群中"); // FileHelper.writeLogFile("将 " + lockedOrders.size() + " 个锁定工单加载到初始种群中");
} else { // } else {
chromosome.setResultOld(new CopyOnWriteArrayList<>()); // chromosome.setResultOld(new CopyOnWriteArrayList<>());
} // }
decoder.decodeChromosomeWithCache(chromosome); decoder.decodeChromosomeWithCache(chromosome);
if (chromosome.getFitness() == 0) { if (chromosome.getFitness() == 0) {
......
...@@ -471,10 +471,14 @@ if(finishedOrder==null||finishedOrder.size()==0) ...@@ -471,10 +471,14 @@ if(finishedOrder==null||finishedOrder.size()==0)
// 步骤2:按OperationSequencing顺序调度工序 // 步骤2:按OperationSequencing顺序调度工序
Map<Integer, Integer> orderProcessCounter = new HashMap<>(); Map<Integer, Integer> orderProcessCounter = new HashMap<>();
Map<Integer, Integer> orderLastEndTime = new HashMap<>(); Map<Integer, Integer> orderLastEndTime = new HashMap<>();
Map<Integer, Entry> entryIndexById = new HashMap<>();
Map<Integer, List<Entry>> entrysBygroupId = new HashMap<>();
for (Entry op : allOperations) { for (Entry op : allOperations) {
int groupId = op.getGroupId(); int groupId = op.getGroupId();
orderProcessCounter.putIfAbsent(groupId, 0); orderProcessCounter.putIfAbsent(groupId, 0);
orderLastEndTime.putIfAbsent(groupId, 0); orderLastEndTime.putIfAbsent(groupId, 0);
entryIndexById.put(op.getId(),op);
entrysBygroupId.computeIfAbsent(groupId, k -> new ArrayList<>()).add(op);
} }
// Map<Long, String> machineState = chromosome.getMachines().stream() // Map<Long, String> machineState = chromosome.getMachines().stream()
...@@ -483,10 +487,12 @@ if(finishedOrder==null||finishedOrder.size()==0) ...@@ -483,10 +487,12 @@ if(finishedOrder==null||finishedOrder.size()==0)
// List<Entry> allScheduledOps = new ArrayList<>(); // List<Entry> allScheduledOps = new ArrayList<>();
// 缓存机器任务 // 缓存机器任务
Map<Long, CopyOnWriteArrayList<GAScheduleResult>> machineTasksCache = new HashMap<>(); Map<Long, CopyOnWriteArrayList<GAScheduleResult>> machineTasksCache = new HashMap<>();
for (Entry op : allOperations) {
}
for (int groupId : chromosome.getOperationSequencing()) { for (int groupId : chromosome.getOperationSequencing()) {
int scheduledCount = orderProcessCounter.get(groupId); int scheduledCount = orderProcessCounter.get(groupId);
List<Entry> orderOps = allOperations.stream() List<Entry> orderOps = entrysBygroupId.get(groupId).stream()
.filter(t -> t.getGroupId() == groupId)
.sorted(Comparator.comparing(Entry::getSequence)) .sorted(Comparator.comparing(Entry::getSequence))
.collect(Collectors.toList()); .collect(Collectors.toList());
...@@ -1243,12 +1249,12 @@ return actualEndTime; ...@@ -1243,12 +1249,12 @@ return actualEndTime;
} }
machineTasks =chromosome.getResult().stream() // machineTasks =chromosome.getResult().stream()
.filter(t -> t.getMachineId() == machine.getId()) // .filter(t -> t.getMachineId() == machine.getId())
.sorted(Comparator.comparingInt(GAScheduleResult::getStartTime)) // .sorted(Comparator.comparingInt(GAScheduleResult::getStartTime))
.collect(Collectors.toCollection(CopyOnWriteArrayList::new)); // .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
//
machineTasksCache.put(machine.getId(), machineTasks); // machineTasksCache.put(machine.getId(), machineTasks);
if(machineTasks!=null&&machineTasks.size()>0&&_globalParam.is_smoothChangeOver()) if(machineTasks!=null&&machineTasks.size()>0&&_globalParam.is_smoothChangeOver())
{ {
...@@ -1385,7 +1391,9 @@ return actualEndTime; ...@@ -1385,7 +1391,9 @@ return actualEndTime;
// FileHelper.writeLogFile(" 结束 "+ConvertTime(startTime)+"--"+ConvertTime(endTime)+" "+operation.getGroupId()+" : "+operation.getId()+",处理时间: " + processingTime + ", 后处理: " + teardownTime + // FileHelper.writeLogFile(" 结束 "+ConvertTime(startTime)+"--"+ConvertTime(endTime)+" "+operation.getGroupId()+" : "+operation.getId()+",处理时间: " + processingTime + ", 后处理: " + teardownTime +
// ", 前处理: " + preTime + ", 换型: " + setupTime+ ", 数量: " + operation.getQuantity()+ ", 设备: "+machine.getId()+ ", 是否可中断: "+operation.getIsInterrupt()); // ", 前处理: " + preTime + ", 换型: " + setupTime+ ", 数量: " + operation.getQuantity()+ ", 设备: "+machine.getId()+ ", 是否可中断: "+operation.getIsInterrupt());
machineTasksCache.remove(machine.getId()); if (machineTasks != null) {
machineTasks.add(result);
}
return endTime; return endTime;
} }
...@@ -2399,96 +2407,90 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0) ...@@ -2399,96 +2407,90 @@ if(MaterialRequirements==null||MaterialRequirements.size()==0)
private void calculateScheduleResult(Chromosome chromosome) { private void calculateScheduleResult(Chromosome chromosome) {
double[] Objectives=new double[_globalParam.getObjectiveWeights().size()]; double[] Objectives = new double[_globalParam.getObjectiveWeights().size()];
int i=0; int i = 0;
for (ObjectiveConfig config : _globalParam.getObjectiveConfigs()) { for (ObjectiveConfig config : _globalParam.getObjectiveConfigs()) {
if( config.isEnabled()) if (config.isEnabled()) {
{ if (config.getName() == GlobalParam.OBJECTIVE_MAKESPAN) {
if(config.getName()==GlobalParam.OBJECTIVE_MAKESPAN) // 1. 最早完工时间(最小化)
{ double makespan = chromosome.getResult().stream()
// 1. 最早完工时间(最小化) .mapToInt(GAScheduleResult::getEndTime)
double makespan = chromosome.getResult().stream() .max()
.mapToInt(GAScheduleResult::getEndTime) .orElse(0);
.max() Objectives[i] = makespan;
.orElse(0); chromosome.setMakespan(makespan);
Objectives[i]=makespan; }
chromosome.setMakespan(makespan); if (config.getName() == GlobalParam.OBJECTIVE_TARDINESS) {
} // 2. 交付期满足情况(最小化延迟)
if(config.getName()==GlobalParam.OBJECTIVE_TARDINESS) double tardiness = 0;
{
// 2. 交付期满足情况(最小化延迟) Map<Integer, List<GAScheduleResult>> orderGroups = chromosome.getResult().stream()
double tardiness = 0; .collect(Collectors.groupingBy(GAScheduleResult::getGroupId));
Map<Integer, List<GAScheduleResult>> orderGroups = chromosome.getResult().stream() for (Map.Entry<Integer, List<GAScheduleResult>> group : orderGroups.entrySet()) {
.collect(Collectors.groupingBy(GAScheduleResult::getGroupId)); int groupId = group.getKey();
int orderCompletion = group.getValue().stream()
for (Map.Entry<Integer, List<GAScheduleResult>> group : orderGroups.entrySet()) { .mapToInt(GAScheduleResult::getEndTime)
int groupId = group.getKey(); .max()
int orderCompletion = group.getValue().stream() .orElse(0);
.mapToInt(GAScheduleResult::getEndTime) List<String> orderIds = group.getValue().stream()
.max() .map(GAScheduleResult::getOrderId)
.orElse(0); .distinct()
List<String> orderIds = group.getValue().stream() .sorted()
.map(GAScheduleResult::getOrderId) .collect(Collectors.toList());
.distinct() Order order = chromosome.getOrders().stream()
.sorted() .filter(t -> orderIds.contains(t.getOrderId()))
.collect(Collectors.toList()); .max(Comparator.comparing(Order::getDueDate))
Order order = chromosome.getOrders().stream() .orElse(null);
.filter(t->orderIds.contains(t.getOrderId())) if (order.isNewCreate()) {
.max(Comparator.comparing(Order::getDueDate)) continue;
.orElse(null); }
if(order.isNewCreate()) LocalDateTime dueDateTime = order.getDueDate();
{continue;}
LocalDateTime dueDateTime=order.getDueDate();
LocalDateTime completionTime = baseTime.plusSeconds(orderCompletion);
LocalDateTime completionTime =baseTime.plusSeconds(orderCompletion); if (completionTime.isAfter(dueDateTime)) {
// 计算延迟小时数(修复时间计算)
long hours = ChronoUnit.HOURS.between(dueDateTime, completionTime);
if (completionTime.isAfter(dueDateTime)) { long minutes = ChronoUnit.MINUTES.between(dueDateTime, completionTime) % 60;
// 计算延迟小时数(修复时间计算) tardiness += hours * 60 + (double) minutes;
long hours = ChronoUnit.HOURS.between(dueDateTime, completionTime); }
long minutes = ChronoUnit.MINUTES.between(dueDateTime, completionTime) % 60;
tardiness += hours*60 + (double) minutes ; }
}
Objectives[i] = tardiness;
} chromosome.setDelayTime(tardiness);
}
Objectives[i]=tardiness; if (config.getName() == GlobalParam.OBJECTIVE_SETUP_TIME) {
chromosome.setDelayTime(tardiness); // 3. 最小总换型时间
} double totalSetupTime = calculateTotalSetupTime(chromosome);
if(config.getName()==GlobalParam.OBJECTIVE_SETUP_TIME) chromosome.setTotalChangeoverTime(totalSetupTime);
{ Objectives[i] = totalSetupTime;
// 3. 最小总换型时间 }
double totalSetupTime = calculateTotalSetupTime(chromosome); if (config.getName() == GlobalParam.OBJECTIVE_FLOW_TIME) {
chromosome.setTotalChangeoverTime(totalSetupTime); // 4. 最小化总流程时间 所有工序加工时间的总和
Objectives[i]=totalSetupTime; double totalFlowTime = calculateTotalFlowTime(chromosome);
} chromosome.setTotalFlowTime(totalFlowTime);
if(config.getName()==GlobalParam.OBJECTIVE_FLOW_TIME) Objectives[i] = totalFlowTime;
{ }
// 4. 最小化总流程时间 所有工序加工时间的总和 if (config.getName() == GlobalParam.OBJECTIVE_MACHINE_LOAD) {
double totalFlowTime = calculateTotalFlowTime(chromosome); // 5. 机器负载均衡
chromosome.setTotalFlowTime(totalFlowTime); double machineLoadBalance = calculateMachineLoadBalance(chromosome);
Objectives[i]=totalFlowTime; chromosome.setMachineLoadStd(machineLoadBalance);
} Objectives[i] = machineLoadBalance;
if(config.getName()==GlobalParam.OBJECTIVE_MACHINE_LOAD) }
{ i++;
// 5. 机器负载均衡 }
double machineLoadBalance = calculateMachineLoadBalance(chromosome);
chromosome.setMachineLoadStd(machineLoadBalance);
Objectives[i]=machineLoadBalance;
}
i++;
}
} }
chromosome.setObjectives(Objectives); chromosome.setObjectives(Objectives);
FitnessCalculator fitnessCalculator=new FitnessCalculator(); FitnessCalculator fitnessCalculator = new FitnessCalculator();
if (chromosome.getFitnessLevel()==null) {
chromosome.setFitnessLevel(fitnessCalculator.calculateFitness(chromosome, _globalParam)); chromosome.setFitnessLevel(fitnessCalculator.calculateFitness(chromosome, _globalParam));
}
} }
private double calculateTotalFlowTime(Chromosome chromosome) { private double calculateTotalFlowTime(Chromosome chromosome) {
......
...@@ -11,6 +11,7 @@ import java.util.concurrent.CompletableFuture; ...@@ -11,6 +11,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.stream.Collectors;
/** /**
* 爬山法算法 * 爬山法算法
...@@ -38,7 +39,7 @@ public class HillClimbing { ...@@ -38,7 +39,7 @@ public class HillClimbing {
// 按优先级从高到低处理 // 按优先级从高到低处理
sortedPriorities= new ArrayList<>(priorityGroups.keySet()); sortedPriorities= new ArrayList<>(priorityGroups.keySet());
Collections.sort(sortedPriorities);
entrys = buildEntryKey(); entrys = buildEntryKey();
} }
...@@ -71,13 +72,54 @@ public class HillClimbing { ...@@ -71,13 +72,54 @@ public class HillClimbing {
// 构建位置到Entry的映射:position -> Entry // 构建位置到Entry的映射:position -> Entry
Map<Integer, Entry> entryIndex = buildEntryIndex(current, entrys); Map<Integer, Entry> entryIndex = buildEntryIndex(current, entrys);
boolean improved = true;
for (Double priority : sortedPriorities) { for (Double priority : sortedPriorities) {
List<Entry> priorityOps = priorityGroups.get(priority); List<Entry> priorityOps = priorityGroups.get(priority);
if (priorityOps.isEmpty()) { if (priorityOps.isEmpty()) {
continue; continue;
} }
// 1. 优先处理有多设备选项的工序(最有可能带来改进)
List<Entry> multiMachineOps = priorityOps.stream()
.filter(op -> op.getMachineOptions().size() > 1)
.collect(Collectors.toList());
if (!multiMachineOps.isEmpty()) {
for (Entry op : multiMachineOps) {
String key = op.getGroupId() + "_" + op.getSequence();
Integer maPos = MachinePositionIndex.get(key);
if (maPos == null) continue;
Chromosome machineChange = generateMachineChange(current, op.getMachineOptions(), maPos);
if (machineChange != null) {
decode(decoder, machineChange);
if (isBetter(machineChange, current)) {
current = machineChange;
if (isBetter(current, best)) {
best = current;
}
improved = true;
positionIndex = buildPositionIndex(current);
entryIndex = buildEntryIndex(current, entrys);
MachinePositionIndex = buildEntryMachinePositionIndex(current);
break;
}
}
}
if (improved) break;
}
if (improved) continue;
// 2. 检查是否是单一订单(如果只有一个订单,不需要交换位置
Set<Integer> groupIds = priorityOps.stream()
.map(Entry::getGroupId)
.collect(Collectors.toSet());
if (groupIds.size() <= 1) {
continue;
}
// 根据当前优先级的工序数确定迭代次数和step // 根据当前优先级的工序数确定迭代次数和step
int priorityIterations = Math.max(5, priorityOps.size() / 2); int priorityIterations = Math.max(5, priorityOps.size() / 2);
// 200/10 =20 // 200/10 =20
...@@ -109,13 +151,7 @@ public class HillClimbing { ...@@ -109,13 +151,7 @@ public class HillClimbing {
List<Chromosome> candidates = new ArrayList<>(); List<Chromosome> candidates = new ArrayList<>();
List<Chromosome> candidates1 = new ArrayList<>(); List<Chromosome> candidates1 = new ArrayList<>();
if (MachineOptions.size() > 1) {
Chromosome machineChange = generateMachineChange(current, MachineOptions, maPos);
if (machineChange != null) {
candidates.add(machineChange);
candidates1.add(machineChange);
}
}
// 向左多次移动(step 1, 2, 3...) // 向左多次移动(step 1, 2, 3...)
for (int s = 1; s <= stepCount; s++) { for (int s = 1; s <= stepCount; s++) {
...@@ -197,185 +233,161 @@ public class HillClimbing { ...@@ -197,185 +233,161 @@ public class HillClimbing {
Chromosome best = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class); Chromosome best = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
// 构建位置索引映射:groupId_sequence -> position // 构建位置索引映射:groupId_sequence -> position
Map<String, Integer> positionIndex = buildPositionIndex(current); Map<String, Integer> positionIndex = buildPositionIndex(current);
Map<String, Integer> MachinePositionIndex = buildEntryMachinePositionIndex(current); Map<String, Integer> MachinePositionIndex = buildEntryMachinePositionIndex(current);
int totalCount = 0;
int noImproveCount = 0;
int maxNoImprove = 50; // 连续50次没改进就提前停止
// 构建位置到Entry的映射:position -> Entry // 构建位置到Entry的映射:position -> Entry
Map<Integer, Entry> entryIndex = buildEntryIndex(current,entrys); Map<Integer, Entry> entryIndex = buildEntryIndex(current, entrys);
boolean improved = true; boolean improved = false;
for (Double priority : sortedPriorities) { for (Double priority : sortedPriorities) {
List<Entry> priorityOps = priorityGroups.get(priority); List<Entry> priorityOps = priorityGroups.get(priority);
if (priorityOps.isEmpty()) { if (priorityOps.isEmpty()) {
continue; continue;
} }
// 1. 优先处理有多设备选项的工序(最有可能带来改进)
List<Entry> multiMachineOps = priorityOps.stream()
.filter(op -> op.getMachineOptions().size() > 1)
.collect(Collectors.toList());
if (!multiMachineOps.isEmpty()) {
for (Entry op : multiMachineOps) {
String key = op.getGroupId() + "_" + op.getSequence();
Integer maPos = MachinePositionIndex.get(key);
if (maPos == null) continue;
Chromosome machineChange = generateMachineChange(current, op.getMachineOptions(), maPos);
if (machineChange != null) {
decode(decoder, machineChange);
if (isBetter(machineChange, current)) {
current = machineChange;
if (isBetter(current, best)) {
best = ProductionDeepCopyUtil.deepCopy(current, Chromosome.class);
}
improved = true;
noImproveCount=0;
positionIndex = buildPositionIndex(current);
entryIndex = buildEntryIndex(current, entrys);
MachinePositionIndex = buildEntryMachinePositionIndex(current);
break;
}
}
}
if (improved) break;
}
if (improved) continue;
// 2. 检查是否是单一订单(如果只有一个订单,不需要交换位置
Set<Integer> groupIds = priorityOps.stream()
.map(Entry::getGroupId)
.collect(Collectors.toSet());
if (groupIds.size() <= 1) {
continue;
}
// 根据当前优先级的工序数确定迭代次数和step // 根据当前优先级的工序数确定迭代次数和step
int priorityIterations = Math.max(5, priorityOps.size()/2); int priorityIterations = Math.max(5, priorityOps.size() / 2);
// 200/10 =20 // 200/10 =20
// 1 // 1
int step = Math.max(1, (int) Math.ceil(priorityOps.size() / 10.0)); int step = Math.max(1, (int) Math.ceil(priorityOps.size() / 10.0));
// 200/20=10; // 200/20=10;
// //
int stepCount = Math.max(1, (int) Math.ceil(priorityOps.size() / step)); int stepCount = Math.max(1, (int) Math.ceil(priorityOps.size() / step));
Set<Integer> Groupid=new HashSet<>(); Set<Integer> processedGroupIds = new HashSet<>();
int noImproveCount = 0;
int maxNoImprove = 20; // 连续50次没改进就提前停止
for (int pi = 0; pi < priorityIterations; pi++) { for (int pi = 0; pi < priorityIterations; pi++) {
improved = false;
// 随机取该优先级的工序
Entry randomOp = priorityOps.get(rnd.nextInt(priorityOps.size())); Entry randomOp = priorityOps.get(rnd.nextInt(priorityOps.size()));
if (processedGroupIds.contains(randomOp.getGroupId())) {
continue;
}
processedGroupIds.add(randomOp.getGroupId());
// 从索引中快速查找位置(O(1)复杂度)
String key = randomOp.getGroupId() + "_" + randomOp.getSequence(); String key = randomOp.getGroupId() + "_" + randomOp.getSequence();
Integer opPos = positionIndex.get(key); Integer opPos = positionIndex.get(key);
Integer maPos = MachinePositionIndex.get(key);
List<MachineOption> MachineOptions=randomOp.getMachineOptions();
if (opPos == null) { if (opPos == null) {
continue; continue;
} }
List<Integer> os = current.getOperationSequencing(); boolean foundBetter = false;
// 生成多个候选方案
List<Chromosome> candidates = new ArrayList<>();
if(MachineOptions.size()>1) {
Chromosome machineChange = generateMachineChange(current, MachineOptions, maPos);
if (machineChange != null) {
candidates.add(machineChange);
}
}
// 向左多次移动(step 1, 2, 3...) // 向左逐步尝试
for (int s = 1; s <= stepCount; s++) { for (int s = 1; s <= stepCount; s++) {
int targetPos = opPos - s * step;
Entry leftOp = entryIndex.get(targetPos);
Entry leftOp = entryIndex.get(opPos - s * step); if (leftOp == null || randomOp.getGroupId() == leftOp.getGroupId()
if (leftOp != null&&randomOp.getGroupId()!=leftOp.getGroupId() && Math.abs(leftOp.getPriority() - priority) <= 0.001) { || Math.abs(leftOp.getPriority() - priority) > 0.001) {
break;
Chromosome newChromosome = swapAtDistance(current, opPos, -s * step); }
candidates.add(newChromosome);
if(MachineOptions.size()>1) { Chromosome newChromosome = swapAtDistance(current, opPos, -s * step);
Chromosome machineChange = generateMachineChange(newChromosome, MachineOptions, maPos); decode(decoder, newChromosome);
if (machineChange != null) {
candidates.add(machineChange);
} if (isBetter(newChromosome, current)) {
current = newChromosome;
if (isBetter(current, best)) {
best = ProductionDeepCopyUtil.deepCopy(current, Chromosome.class);
} }
improved = true;
foundBetter = true;
}else { noImproveCount=0;
positionIndex = buildPositionIndex(current);
entryIndex = buildEntryIndex(current, entrys);
break; break;
} }
if (candidates.size() > 5) {
batchDecode(decoder,candidates,machines);
int bestidx= Getbest(candidates,best);
if(bestidx>-1)
{
best=candidates.get(bestidx);
current=ProductionDeepCopyUtil.deepCopy(best, Chromosome.class);;
improved=true;
// 更新索引
noImproveCount=0;
positionIndex = buildPositionIndex(current);
entryIndex = buildEntryIndex(current,entrys);
break;
}
candidates.clear();
}
} }
if(improved) if (foundBetter) break;
{
break;
}
// 向右多次移动(step 1, 2, 3...) // 向右逐步尝试
for (int s = 1; s <= stepCount; s++) { for (int s = 1; s <= stepCount; s++) {
int targetPos = opPos + s * step;
Entry rightOp = entryIndex.get(targetPos);
Entry rightOp = entryIndex.get(opPos + s * step); if (rightOp == null || randomOp.getGroupId() == rightOp.getGroupId()
if (rightOp != null && randomOp.getGroupId() != rightOp.getGroupId() && Math.abs(rightOp.getPriority() - priority) <= 0.001) { || Math.abs(rightOp.getPriority() - priority) > 0.001) {
Chromosome newChromosome = swapAtDistance(current, opPos, s * step); break;
candidates.add(newChromosome); }
if(MachineOptions.size()>1) { Chromosome newChromosome = swapAtDistance(current, opPos, s * step);
Chromosome machineChange = generateMachineChange(newChromosome, MachineOptions, maPos); decode(decoder, newChromosome);
if (machineChange != null) {
candidates.add(machineChange);
} if (isBetter(newChromosome, current)) {
current = newChromosome;
if (isBetter(current, best)) {
best = ProductionDeepCopyUtil.deepCopy(current, Chromosome.class);
} }
improved = true;
} else { foundBetter = true;
noImproveCount=0;
positionIndex = buildPositionIndex(current);
entryIndex = buildEntryIndex(current, entrys);
break; break;
} }
if (candidates.size() > 5) {
batchDecode(decoder,candidates,machines);
int bestidx= Getbest(candidates,best);
if(bestidx>-1)
{
best=candidates.get(bestidx);
current=ProductionDeepCopyUtil.deepCopy(best, Chromosome.class);;
// 更新索引
noImproveCount=0;
positionIndex = buildPositionIndex(current);
entryIndex = buildEntryIndex(current,entrys);
improved=true;
break;
}
candidates.clear();
}
}
if(improved)
{
break;
}
if(candidates.size()== 0)
{
break;
}else {
batchDecode(decoder, candidates,machines);
} }
int bestidx= Getbest(candidates,best); if (foundBetter) break;
if(bestidx>-1) noImproveCount++;
totalCount++;
if(noImproveCount>maxNoImprove)
{ {
best=candidates.get(bestidx); FileHelper.writeLogFile(String.format("爬山法 - 提前停止:迭代%d次",
current=ProductionDeepCopyUtil.deepCopy(best, Chromosome.class);; totalCount));
// 更新索引
noImproveCount=0;
positionIndex = buildPositionIndex(current);
entryIndex = buildEntryIndex(current,entrys);
improved=true; improved=true;
break; break;
} }
if (noImproveCount >= maxNoImprove) {
FileHelper.writeLogFile(String.format("爬山法 - 提前停止:连续未优化 迭代%d次", pi + 1));
noImproveCount=0;
}
noImproveCount++;
} }
if (improved) break;
} }
return best; return best;
} }
...@@ -497,7 +509,27 @@ boolean improved = true; ...@@ -497,7 +509,27 @@ boolean improved = true;
double priority = op.getPriority(); double priority = op.getPriority();
groups.computeIfAbsent(priority, k -> new ArrayList<>()).add(op); groups.computeIfAbsent(priority, k -> new ArrayList<>()).add(op);
} }
return groups; // 过滤掉:设备只有一个且只有一个GroupId的优先级组
Map<Double, List<Entry>> filteredGroups = new HashMap<>();
for (Map.Entry<Double, List<Entry>> entry : groups.entrySet()) {
List<Entry> ops = entry.getValue();
// 检查是否所有工序都只有一个设备选项
boolean allSingleMachine = ops.stream()
.allMatch(op -> op.getMachineOptions().size() <= 1);
// 检查是否只有一个GroupId
Set<Integer> groupIds = ops.stream()
.map(Entry::getGroupId)
.collect(Collectors.toSet());
// 如果两个条件都满足,过滤掉这个优先级组
if (!(allSingleMachine && groupIds.size() <= 1)) {
filteredGroups.put(entry.getKey(), ops);
}
}
return filteredGroups;
} }
/** /**
......
...@@ -111,7 +111,7 @@ int opcount=allOperations.size(); ...@@ -111,7 +111,7 @@ int opcount=allOperations.size();
// 初始化变邻域搜索 // 初始化变邻域搜索
_vns = new VariableNeighborhoodSearch(_GlobalParam, allOperations, globalOpList, _fitnessCalculator, _objectiveWeights); _vns = new VariableNeighborhoodSearch(_GlobalParam, allOperations, globalOpList, _fitnessCalculator, _objectiveWeights);
_hillClimbing = new HillClimbing(allOperations); _hillClimbing = new HillClimbing(allOperations);
_simulatedAnnealing = new SimulatedAnnealing(_GlobalParam, allOperations, globalOpList, _fitnessCalculator, _objectiveWeights); _simulatedAnnealing = new SimulatedAnnealing( allOperations);
_parallelLocalSearch = new ParallelLocalSearch(_GlobalParam, allOperations, globalOpList, _fitnessCalculator, _objectiveWeights); _parallelLocalSearch = new ParallelLocalSearch(_GlobalParam, allOperations, globalOpList, _fitnessCalculator, _objectiveWeights);
_tabuSearch = new TabuSearch(_GlobalParam, allOperations, globalOpList, _fitnessCalculator, _objectiveWeights); _tabuSearch = new TabuSearch(_GlobalParam, allOperations, globalOpList, _fitnessCalculator, _objectiveWeights);
_tabuSearchWithSA = new TabuSearchWithSA(_GlobalParam, allOperations, globalOpList, _fitnessCalculator, _objectiveWeights); _tabuSearchWithSA = new TabuSearchWithSA(_GlobalParam, allOperations, globalOpList, _fitnessCalculator, _objectiveWeights);
...@@ -142,7 +142,7 @@ int opcount=allOperations.size(); ...@@ -142,7 +142,7 @@ int opcount=allOperations.size();
// 步骤2:对初始种群进行爬山法局部优化 // 步骤2:对初始种群进行爬山法局部优化
if(population.size()<5||opcount<10 ) { if(opcount<20 ) {
FileHelper.writeLogFile("爬山法局部优化-----------开始-------"); FileHelper.writeLogFile("爬山法局部优化-----------开始-------");
GeneticDecoder hillClimbingDecoder = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler, materialRequirementService, sceneId); GeneticDecoder hillClimbingDecoder = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler, materialRequirementService, sceneId);
...@@ -156,7 +156,7 @@ int opcount=allOperations.size(); ...@@ -156,7 +156,7 @@ int opcount=allOperations.size();
// 步骤2:对初始种群进行模拟退火+爬山法优化 // 步骤2:对初始种群进行模拟退火+爬山法优化
GeneticDecoder saDecoder1 = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler, materialRequirementService, sceneId); GeneticDecoder saDecoder1 = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler, materialRequirementService, sceneId);
if(population.size()>5||opcount<2000 ) { if(opcount<800 ) {
FileHelper.writeLogFile("模拟退火+爬山法优化-----------开始-------"); FileHelper.writeLogFile("模拟退火+爬山法优化-----------开始-------");
Chromosome saHcOptimized = _simulatedAnnealing.batchSearchGetMax(population, saDecoder1, machines); Chromosome saHcOptimized = _simulatedAnnealing.batchSearchGetMax(population, saDecoder1, machines);
FileHelper.writeLogFile("模拟退火+爬山法优化-----------结束-------"); FileHelper.writeLogFile("模拟退火+爬山法优化-----------结束-------");
......
...@@ -934,6 +934,9 @@ public class MachineCalculator { ...@@ -934,6 +934,9 @@ public class MachineCalculator {
LocalDateTime end) { LocalDateTime end) {
CopyOnWriteArrayList<TimeSegment> conflictIntervals = new CopyOnWriteArrayList<>(); CopyOnWriteArrayList<TimeSegment> conflictIntervals = new CopyOnWriteArrayList<>();
// 1. 维护窗口冲突(优化重叠判断,更严谨) // 1. 维护窗口冲突(优化重叠判断,更严谨)
if (machine.getMaintenanceWindows() != null && !machine.getMaintenanceWindows().isEmpty()) { if (machine.getMaintenanceWindows() != null && !machine.getMaintenanceWindows().isEmpty()) {
// 过滤重叠的维护窗口并转换为TimeSegment // 过滤重叠的维护窗口并转换为TimeSegment
......
...@@ -474,18 +474,18 @@ public class OrderSortService { ...@@ -474,18 +474,18 @@ public class OrderSortService {
if (!Objects.equals(prev.getSerie(), order.getSerie())) flags.append("serie变 "); if (!Objects.equals(prev.getSerie(), order.getSerie())) flags.append("serie变 ");
if (!Objects.equals(prev.getMaterialCode(), order.getMaterialCode())) flags.append("material变"); if (!Objects.equals(prev.getMaterialCode(), order.getMaterialCode())) flags.append("material变");
} }
costLog.append(String.format(" %2d. %s, routingId=%s, serie=%s, materialCode=%s, cost=%.0f %s\n", // costLog.append(String.format(" %2d. %s, routingId=%s, serie=%s, materialCode=%s, cost=%.0f %s\n",
(i + 1), // (i + 1),
order.getOrderCode(), // order.getOrderCode(),
order.getRoutingId(), // order.getRoutingId(),
order.getSerie(), // order.getSerie(),
order.getMaterialCode(), // order.getMaterialCode(),
costToPrev, // costToPrev,
flags.toString())); // flags.toString()));
totalCost += costToPrev; totalCost += costToPrev;
} }
costLog.append(String.format("[换线明细] 总换线成本 = %.0f\n", totalCost)); // costLog.append(String.format("[换线明细] 总换线成本 = %.0f\n", totalCost));
log.debug(costLog.toString()); // log.debug(costLog.toString());
// ================================== // ==================================
// 为最小化换线后的订单分配层级序号 // 为最小化换线后的订单分配层级序号
......
...@@ -6,27 +6,32 @@ import com.aps.entity.Algorithm.*; ...@@ -6,27 +6,32 @@ import com.aps.entity.Algorithm.*;
import com.aps.entity.basic.Entry; import com.aps.entity.basic.Entry;
import com.aps.entity.basic.GlobalParam; import com.aps.entity.basic.GlobalParam;
import com.aps.entity.basic.Machine; import com.aps.entity.basic.Machine;
import com.aps.entity.basic.MachineOption;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.stream.Collectors;
/** /**
* 模拟退火算法 * 模拟退火算法
*/ */
public class SimulatedAnnealing { public class SimulatedAnnealing {
private final Random rnd = new Random(); private final Random rnd = new Random();
private GlobalParam globalParam;
private List<Entry> allOperations; private List<Entry> allOperations;
private List<GlobalOperationInfo> globalOpList;
private FitnessCalculator fitnessCalculator;
private ObjectiveWeights objectiveWeights;
public SimulatedAnnealing(GlobalParam globalParam, List<Entry> allOperations, List<GlobalOperationInfo> globalOpList, FitnessCalculator fitnessCalculator, ObjectiveWeights objectiveWeights) { private Map<String, Entry> entrys;
this.globalParam = globalParam; private Map<Integer, Entry> entrybyids;
public SimulatedAnnealing( List<Entry> allOperations) {
this.allOperations = allOperations; this.allOperations = allOperations;
this.globalOpList = globalOpList;
this.fitnessCalculator = fitnessCalculator; Map<Integer, Object> mp = buildEntryKey();
this.objectiveWeights = objectiveWeights;
entrys=(Map<String, Entry>)mp.get(1);
entrybyids=(Map<Integer, Entry>)mp.get(2);
} }
private final ExecutorService decodeExecutor = new ThreadPoolExecutor( private final ExecutorService decodeExecutor = new ThreadPoolExecutor(
Runtime.getRuntime().availableProcessors() - 1, // 核心线程数=CPU-1,无切换开销 Runtime.getRuntime().availableProcessors() - 1, // 核心线程数=CPU-1,无切换开销
...@@ -47,7 +52,7 @@ public class SimulatedAnnealing { ...@@ -47,7 +52,7 @@ public class SimulatedAnnealing {
for (Chromosome chromosome:chromosomes) { for (Chromosome chromosome:chromosomes) {
Chromosome optimized = searchWithHillClimbing(chromosome, decoder, machines); Chromosome optimized = searchWithHillClimbing(chromosome, decoder, machines);
saHcOptimized.add(optimized); saHcOptimized.add(optimized);
break;
} }
return saHcOptimized; return saHcOptimized;
} }
...@@ -63,57 +68,63 @@ public class SimulatedAnnealing { ...@@ -63,57 +68,63 @@ public class SimulatedAnnealing {
} }
/**
/** * 模拟退火搜索,当温度降低到一定程度后切换到爬山法
* 模拟退火搜索,当温度降低到一定程度后切换到爬山法 * 流程:模拟退火全局探索(按概率接受劣解)→ 降温 → 温度低时爬山法局部求精 → 输出最优
* 流程:模拟退火迭代 → 随机生成新排产 → 按概率接受 → 降温 → 温度低时爬山法求精 → 输出最优 */
*/
public Chromosome searchWithHillClimbing(Chromosome chromosome, GeneticDecoder decoder, List<Machine> machines) { public Chromosome searchWithHillClimbing(Chromosome chromosome, GeneticDecoder decoder, List<Machine> machines) {
FileHelper.writeLogFile("模拟退火+爬山法 - 开始执行");
Chromosome current = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class); Chromosome current = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
Chromosome best = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class); Chromosome best = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
writeKpi(best);
// 初始化解码
Map<String, Entry> Entrys = buildEntryKey(current); // FileHelper.writeLogFile("模拟退火+爬山法 - 初始化解码完成");
FileHelper.writeLogFile("模拟退火+爬山法 - 初始化索引完成");
// 初始化温度 - 优化速度:更快降温,更快切换到爬山法 // 初始化温度
double temperature = 100.0; double temperature = 100.0;
double coolingRate = 0.95; double coolingRate = 0.95;
double temperatureThreshold = 1.0; // 提高阈值,更快切换到爬山法 double temperatureThreshold = 1.0;
int maxIterations = 300; // 减少最大迭代次数 int maxIterations = 300;
int noImproveCount = 0;
int maxNoImprove = 50;
FileHelper.writeLogFile(String.format("模拟退火+爬山法 - 参数配置:温度=%.1f, 降温率=%.2f, 阈值=%.1f, 最大迭代=%d", FileHelper.writeLogFile(String.format("模拟退火+爬山法 - 参数配置:温度=%.1f, 降温率=%.2f, 阈值=%.1f, 最大迭代=%d",
temperature, coolingRate, temperatureThreshold, maxIterations)); temperature, coolingRate, temperatureThreshold, maxIterations));
int noImproveCount = 0;
int maxNoImprove = 50; // 连续50次没改进就提前停止
int acceptCount = 0; int acceptCount = 0;
int improveCount = 0; int improveCount = 0;
for (int i = 0; i < maxIterations; i++) { for (int i = 0; i < maxIterations; i++) {
boolean improved = false; boolean improved = false;
// 1. 随机生成新排产(邻域解 // 1. 使用智能策略生成邻域解(找瓶颈工序/设备
Chromosome neighbor = generateNeighbor(current,Entrys); Chromosome neighbor = generateNeighbor(current);
// 2. 解码并计算适应度(只解码neighbor,current已经解码过了) // 2. 解码
decode(decoder, neighbor, machines); decode(decoder, neighbor,machines);
// 3. 计算能量差(fitness差) // 3. 计算能量差
double energyDifference = calculateEnergyDifference(neighbor, current); double energyDifference = calculateEnergyDifference(neighbor, current);
// 4. 按概率接受新解 // 4. 按概率接受新解(模拟退火核心:有概率接受劣解)
// - 更优:直接接受
// - 较差:概率接受(高温更容易接受)
boolean accepted = false; boolean accepted = false;
if (energyDifference > 0 || rnd.nextDouble() < Math.exp(energyDifference / temperature)) { if (energyDifference > 0 || rnd.nextDouble() < Math.exp(energyDifference / temperature)) {
current = neighbor; current = neighbor;
accepted = true; accepted = true;
acceptCount++; acceptCount++;
// 更新全局最优 // 更新全局最优
if (isBetter(current, best)) { if (isBetter(current, best)) {
best = ProductionDeepCopyUtil.deepCopy(current, Chromosome.class); best = ProductionDeepCopyUtil.deepCopy(current, Chromosome.class);
writeKpi(best);
improved = true; improved = true;
improveCount++; improveCount++;
noImproveCount = 0; noImproveCount = 0;
FileHelper.writeLogFile(String.format("模拟退火+爬山法 - 迭代%d:找到更优解,fitness=%.4f", i, best.getFitness()));
} }
} }
...@@ -123,10 +134,13 @@ public class SimulatedAnnealing { ...@@ -123,10 +134,13 @@ public class SimulatedAnnealing {
// 5. 降温 // 5. 降温
temperature *= coolingRate; temperature *= coolingRate;
if ((i + 1) % 10 == 0) {
// 每50次迭代输出一次状态
if ((i + 1) % 50 == 0) {
FileHelper.writeLogFile(String.format("模拟退火+爬山法 - 迭代%d/%d:温度=%.4f, 接受数=%d, 改进数=%d, 无改进连续=%d", FileHelper.writeLogFile(String.format("模拟退火+爬山法 - 迭代%d/%d:温度=%.4f, 接受数=%d, 改进数=%d, 无改进连续=%d",
i + 1, maxIterations, temperature, acceptCount, improveCount, noImproveCount)); i + 1, maxIterations, temperature, acceptCount, improveCount, noImproveCount));
} }
// 6. 提前停止条件:温度低于阈值 或 连续多次没改进 // 6. 提前停止条件:温度低于阈值 或 连续多次没改进
if (temperature < temperatureThreshold || noImproveCount >= maxNoImprove) { if (temperature < temperatureThreshold || noImproveCount >= maxNoImprove) {
String stopReason = temperature < temperatureThreshold ? "温度低于阈值" : "连续无改进达到上限"; String stopReason = temperature < temperatureThreshold ? "温度低于阈值" : "连续无改进达到上限";
...@@ -134,20 +148,31 @@ public class SimulatedAnnealing { ...@@ -134,20 +148,31 @@ public class SimulatedAnnealing {
stopReason, i + 1, temperature)); stopReason, i + 1, temperature));
FileHelper.writeLogFile("模拟退火+爬山法 - 切换到爬山法求精"); FileHelper.writeLogFile("模拟退火+爬山法 - 切换到爬山法求精");
HillClimbing hillClimbing = new HillClimbing( allOperations);
HillClimbing hillClimbing = new HillClimbing( allOperations ); Chromosome refined = hillClimbing.search(best, decoder, machines);
Chromosome refined = hillClimbing.search(best, decoder,machines);
FileHelper.writeLogFile("模拟退火+爬山法 - 爬山法求精完成"); FileHelper.writeLogFile("模拟退火+爬山法 - 爬山法求精完成");
// 返回爬山法求精后的结果
return refined; return refined;
} }
} }
FileHelper.writeLogFile(String.format("模拟退火+爬山法 - 完成所有%d次迭代,最终fitness=%.4f", maxIterations, best.getFitness()));
FileHelper.writeLogFile(String.format("模拟退火+爬山法 - 完成所有%d次迭代,最终fitness=%.4f",
maxIterations, best.getFitness()));
// 7. 输出全局最优排产 // 7. 输出全局最优排产
return best; return best;
} }
private void writeKpi(Chromosome chromosome) {
String fitness = "";
double[] fitness1 = chromosome.getFitnessLevel();
for (int i = 0; i < fitness1.length; i++) {
fitness += fitness1[i] + ",";
}
FileHelper.writeLogFile(String.format("爬山法 - kpi:%s", fitness));
}
/** /**
* 计算能量差(基于fitnessLevel数组的比较) * 计算能量差(基于fitnessLevel数组的比较)
...@@ -163,6 +188,77 @@ public class SimulatedAnnealing { ...@@ -163,6 +188,77 @@ public class SimulatedAnnealing {
} }
return diff; return diff;
} }
/**
* 按优先级分组工序
*/
private Map<Double, List<Entry>> groupOperationsByPriority() {
Map<Double, List<Entry>> groups = new HashMap<>();
for (Entry op : allOperations) {
double priority = op.getPriority();
groups.computeIfAbsent(priority, k -> new ArrayList<>()).add(op);
}
// 过滤掉:设备只有一个且只有一个GroupId的优先级组
Map<Double, List<Entry>> filteredGroups = new HashMap<>();
for (Map.Entry<Double, List<Entry>> entry : groups.entrySet()) {
List<Entry> ops = entry.getValue();
// 检查是否所有工序都只有一个设备选项
boolean allSingleMachine = ops.stream()
.allMatch(op -> op.getMachineOptions().size() <= 1);
// 检查是否只有一个GroupId
Set<Integer> groupIds = ops.stream()
.map(Entry::getGroupId)
.collect(Collectors.toSet());
// 如果两个条件都满足,过滤掉这个优先级组
if (!(allSingleMachine && groupIds.size() <= 1)) {
filteredGroups.put(entry.getKey(), ops);
}
}
return filteredGroups;
}
/**
* 构建位置索引:groupId_sequence -> position
*/
private Map<String, Integer> buildPositionIndex(Chromosome chromosome) {
Map<String, Integer> index = new HashMap<>();
List<Integer> os = chromosome.getOperationSequencing();
Map<Integer, Integer> orderProcessCounter = new HashMap<>();
for (int i = 0; i < os.size(); i++) {
int groupId = os.get(i);
int count = orderProcessCounter.getOrDefault(groupId, 0) + 1;
orderProcessCounter.put(groupId, count);
String key = groupId + "_" + count;
index.put(key, i);
}
return index;
}
/**
* 构建位置索引:groupId_sequence -> Machines position
*/
private Map<String, Integer> buildEntryMachinePositionIndex(Chromosome chromosome) {
Map<String, Integer> index = new HashMap<>();
List<GlobalOperationInfo> globalOpList = chromosome.getGlobalOpList();
for (int i = 0; i < globalOpList.size(); i++) {
GlobalOperationInfo globalOp = globalOpList.get(i);
Entry op = globalOp.getOp();
int groupId = op.getGroupId();
int count = op.getSequence();
String key = groupId + "_" + count;
index.put(key, i);
}
return index;
}
/** /**
* 构建位置->Entry索引 * 构建位置->Entry索引
*/ */
...@@ -188,39 +284,428 @@ public class SimulatedAnnealing { ...@@ -188,39 +284,428 @@ public class SimulatedAnnealing {
/** /**
* 构建Entry索引:op.getGroupId() + "_" + op.getSequence() -> Entry * 构建Entry索引:op.getGroupId() + "_" + op.getSequence() -> Entry
*/ */
private Map<String, Entry> buildEntryKey(Chromosome chromosome) { private Map<Integer, Object> buildEntryKey() {
Map<Integer, Object> index0 = new HashMap<>();
Map<String, Entry> index = new HashMap<>(); Map<String, Entry> index = new HashMap<>();
Map<Integer, Entry> index2 = new HashMap<>();
List<Entry> allOps = chromosome.getAllOperations(); List<Entry> allOps = this.allOperations;
for (Entry op : allOps) { for (Entry op : allOps) {
String key = op.getGroupId() + "_" + op.getSequence(); String key = op.getGroupId() + "_" + op.getSequence();
index.put(key, op); index.put(key, op);
index2.put(op.getId(), op);
}
index0.put(1,index);
index0.put(2,index2);
return index0;
}
/**
* 生成邻域解 - 智能策略:优先处理瓶颈工序/设备
* 策略:
* 1. 优先处理瓶颈设备上的工序(换设备)
* 2. 瓶颈设备上的工序往前移动
* 3. 非瓶颈设备上的工序往后移动(给瓶颈工序腾位置)
*/
private Chromosome generateNeighbor(Chromosome chromosome) {
List<GAScheduleResult> results = chromosome.getResult();
if (results == null || results.isEmpty()) {
return generateRandomNeighbor(chromosome, entrys);
} }
return index; // 构建位置索引
Map<String, Integer> positionIndex = buildPositionIndex(chromosome);
Map<Integer, Entry> positionToEntryIndex = buildPositionToEntryIndex(chromosome, entrys);
Map<String, Integer> MachinePositionIndex = buildEntryMachinePositionIndex(chromosome);
// 1. 找出瓶颈设备
Long bottleneckMachineId = findBottleneckMachine(chromosome);
if (bottleneckMachineId != null) {
// 找出瓶颈设备上的工序
List<GAScheduleResult> bottleneckOps = findOpsOnBottleneckMachine(chromosome, bottleneckMachineId);
if (!bottleneckOps.isEmpty()) {
// 70%概率优先处理瓶颈设备
if (rnd.nextDouble() < 0.7) {
int strategy = rnd.nextInt(10);
if(strategy<=3)
{
// 策略1:瓶颈设备上的工序换设备
return tryChangeMachineForBottleneckOp(chromosome, bottleneckOps, entrys, MachinePositionIndex);
}
else if(strategy<=8) {
// 策略2:瓶颈设备上的工序往前移动
return tryMoveBottleneckOpForward(chromosome, bottleneckOps, positionIndex, positionToEntryIndex, entrys);
}else if(strategy<=10) {
// 策略3:非瓶颈设备上的工序往后移动
return tryMoveNonBottleneckOpBackward(chromosome, bottleneckMachineId, positionIndex, positionToEntryIndex, entrys);
}
}
}
}
// 默认策略:随机邻域
return generateRandomNeighbor(chromosome, entrys);
}
/**
* 识别瓶颈设备(利用率最高的设备)
*/
private Long findBottleneckMachine(Chromosome chromosome) {
Map<Long, Double> utilization = calculateMachineUtilization(chromosome);
if (utilization.isEmpty()) {
return null;
}
return utilization.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse(null);
}
/**
* 查找在瓶颈设备上的工序
*/
private List<GAScheduleResult> findOpsOnBottleneckMachine(Chromosome chromosome, Long bottleneckMachineId) {
if (bottleneckMachineId == null) {
return new ArrayList<>();
}
return chromosome.getResult().stream()
.filter(r -> r.getMachineId() == bottleneckMachineId)
.collect(Collectors.toList());
}
/**
* 计算设备利用率
*/
private Map<Long, Double> calculateMachineUtilization(Chromosome chromosome) {
Map<Long, Double> utilization = new HashMap<>();
List<GAScheduleResult> results = chromosome.getResult();
if (results == null || results.isEmpty()) {
return utilization;
}
int maxEndTime = results.stream()
.mapToInt(GAScheduleResult::getEndTime)
.max()
.orElse(1);
Map<Long, List<GAScheduleResult>> machineResults = results.stream()
.collect(Collectors.groupingBy(GAScheduleResult::getMachineId));
for (Map.Entry<Long, List<GAScheduleResult>> entry : machineResults.entrySet()) {
long machineId = entry.getKey();
List<GAScheduleResult> machineOps = entry.getValue();
int totalProcessingTime = machineOps.stream()
.mapToInt(r -> r.getEndTime() - r.getStartTime())
.sum();
double util = (double) totalProcessingTime / maxEndTime;
utilization.put(machineId, util);
}
return utilization;
}
/**
* 尝试给瓶颈设备上的工序换设备
*/
private Chromosome tryChangeMachineForBottleneckOp(Chromosome chromosome, List<GAScheduleResult> bottleneckOps, Map<String, Entry> entrys,Map<String, Integer> MachinePositionIndex) {
// 优先选择有多设备选项的工序
List<GAScheduleResult> candidates = bottleneckOps.stream()
.filter(op -> {
Entry entry = entrybyids.get(op.getOperationId());
return entry != null && entry.getMachineOptions().size() > 1;
})
.collect(Collectors.toList());
if (candidates.isEmpty()) {
return generateRandomNeighbor(chromosome, entrys);
}
// 从候选中随机选择一个工序,给它换设备
GAScheduleResult selectedOp = candidates.get(rnd.nextInt(candidates.size()));
// 找到这个工序在globalOpList中的位置
int maPos = -1;
Entry entry= entrybyids.get(selectedOp.getOperationId());
if (entry != null && entry.getMachineOptions().size() > 1) {
maPos = MachinePositionIndex.get(entry.getGroupId() + "_" + entry.getSequence());
if (maPos >= 0) {
return generateMachineChangeForSpecificOp(chromosome, entry.getMachineOptions(), maPos);
}
}
// 直接换设备
return generateMachineChangeNeighbor(chromosome);
}
/**
* 给指定位置的工序换设备
*/
private Chromosome generateMachineChangeForSpecificOp(Chromosome chromosome, List<MachineOption> machineOptions, int idx) {
Chromosome neighbor = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
List<Integer> ms = neighbor.getMachineSelection();
if (!ms.isEmpty() && idx >= 0 && idx < ms.size()) {
if (machineOptions.size() > 1) {
int currentMachineSeq = ms.get(idx);
List<Integer> availableMachines = new ArrayList<>();
for (int i = 1; i <= machineOptions.size(); i++) {
if (i != currentMachineSeq) {
availableMachines.add(i);
}
}
if (!availableMachines.isEmpty()) {
int newMachineSeq = availableMachines.get(rnd.nextInt(availableMachines.size()));
ms.set(idx, newMachineSeq);
neighbor.setMachineSelection(ms);
}
}
}
return neighbor;
}
/**
* 尝试将瓶颈设备上的工序往前移动
*/
private Chromosome tryMoveBottleneckOpForward(Chromosome chromosome, List<GAScheduleResult> bottleneckOps,
Map<String, Integer> positionIndex,
Map<Integer, Entry> positionToEntryIndex,
Map<String, Entry> entrys) {
if (bottleneckOps.isEmpty()) {
return generateSwapNeighbor(chromosome, entrys);
}
// 随机选择一个瓶颈工序
// GAScheduleResult randomOp = bottleneckOps.get(rnd.nextInt(bottleneckOps.size()));
// 计算所有订单的完成时间
List<GAScheduleResult> allResults = chromosome.getResult();
Map<Integer, Integer> orderCompletionTimes = calculateOrderCompletionTimes(allResults);
// 找出最晚完成的订单(延期候选)
int latestCompletionTime = orderCompletionTimes.values().stream()
.mapToInt(Integer::intValue)
.max()
.orElse(0);
// 按优先级和订单完成时间排序:优先选择高优先级+延期订单的工序
List<GAScheduleResult> sortedBottleneckOps = new ArrayList<>(bottleneckOps);
sortedBottleneckOps.sort((a, b) -> {
Entry entryA = entrybyids.get(a.getOperationId());
Entry entryB = entrybyids.get(b.getOperationId());
if (entryA != null && entryB != null) {
// 首先比较优先级(高优先级在前)
int priorityCompare = Double.compare(entryB.getPriority(), entryA.getPriority());
if (priorityCompare != 0) {
return priorityCompare;
}
// 优先级相同,比较订单完成时间(晚完成的在前,即更可能延期)
int endTimeA = orderCompletionTimes.getOrDefault(a.getGroupId(), 0);
int endTimeB = orderCompletionTimes.getOrDefault(b.getGroupId(), 0);
return Integer.compare(endTimeB, endTimeA);
}
return 0;
});
GAScheduleResult selectedOp = sortedBottleneckOps.get(rnd.nextInt(Math.min(5, sortedBottleneckOps.size())));
Entry entry=entrybyids.get(selectedOp.getOperationId()) ;
String key = entry.getGroupId() + "_" + entry.getSequence();
Integer opPos = positionIndex.get(key);
if (opPos == null || opPos <= 0) {
return generateSwapNeighbor(chromosome, entrys);
}
// 往前移动1-3步
// int steps = rnd.nextInt(3) + 1;
// return moveOperationForward(chromosome,positionToEntryIndex, opPos, steps);
// 使用插入方式往前移动(1-5步)
int steps = rnd.nextInt(5) + 1;
return insertOperationForward(chromosome, opPos, steps, entrys);
}
/**
* 计算每个订单的最后完成时间
*/
private Map<Integer, Integer> calculateOrderCompletionTimes(List<GAScheduleResult> allResults) {
Map<Integer, Integer> orderEndTimes = new HashMap<>();
for (GAScheduleResult result : allResults) {
int groupId = result.getGroupId();
int endTime = result.getEndTime();
orderEndTimes.put(groupId, Math.max(orderEndTimes.getOrDefault(groupId, 0), endTime));
}
return orderEndTimes;
} }
/**
* 尝试将非瓶颈设备上的工序往后移动(给瓶颈工序腾位置)
*/
private Chromosome tryMoveNonBottleneckOpBackward(Chromosome chromosome, Long bottleneckMachineId,
Map<String, Integer> positionIndex,
Map<Integer, Entry> positionToEntryIndex,
Map<String, Entry> entrys) {
List<GAScheduleResult> results = chromosome.getResult();
if (results == null) {
return generateSwapNeighbor(chromosome, entrys);
}
// 找出非瓶颈设备上的工序
List<GAScheduleResult> nonBottleneckOps = results.stream()
.filter(r -> r.getMachineId() != bottleneckMachineId)
.collect(Collectors.toList());
if (nonBottleneckOps.isEmpty()) {
return generateSwapNeighbor(chromosome, entrys);
}
// 随机选择一个非瓶颈工序
GAScheduleResult randomOp = nonBottleneckOps.get(rnd.nextInt(nonBottleneckOps.size()));
Entry entry=entrybyids.get(randomOp.getOperationId());
String key = entry.getGroupId()+"_"+entry.getSequence();
Integer opPos = positionIndex.get(key);
if (opPos == null || opPos >= chromosome.getOperationSequencing().size() - 1) {
return generateSwapNeighbor(chromosome, entrys);
}
// 往后移动1-3步
int steps = rnd.nextInt(3) + 1;
return moveOperationBackward(chromosome,positionToEntryIndex, opPos, steps);
}
/** /**
* 生成邻域解 * 将工序往前移动
*/ */
private Chromosome generateNeighbor(Chromosome chromosome,Map<String, Entry> entrys) { private Chromosome moveOperationForward(Chromosome chromosome, Map<Integer, Entry> originalPositionIndex,int pos, int steps) {
Chromosome neighbor = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
List<Integer> os = neighbor.getOperationSequencing();
if (pos <= 0 || pos >= os.size()) {
return neighbor;
}
// 获取要移动的工序和目标位置的工序(基于原始chromosome)
Entry opToMove = originalPositionIndex.get(pos);
if (opToMove == null) {
return neighbor;
}
int targetPos = Math.max(0, pos - steps);
Entry targetOp = originalPositionIndex.get(targetPos);
// 检查是否可以交换
if (targetOp != null && opToMove.getGroupId() == targetOp.getGroupId()) {
return neighbor;
}
if (targetOp != null && Math.abs(targetOp.getPriority() - opToMove.getPriority()) > 0.001) {
return neighbor;
}
// 直接交换到目标位置
java.util.Collections.swap(os, pos, targetPos);
neighbor.setOperationSequencing(os);
return neighbor;
}
/**
* 将工序往后移动
*/
private Chromosome moveOperationBackward(Chromosome chromosome,Map<Integer, Entry> originalPositionIndex, int pos, int steps) {
Chromosome neighbor = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
List<Integer> os = neighbor.getOperationSequencing();
if (pos < 0 || pos >= os.size() - 1) {
return neighbor;
}
// 获取要移动的工序和目标位置的工序(基于原始chromosome)
Entry opToMove = originalPositionIndex.get(pos);
if (opToMove == null) {
return neighbor;
}
int targetPos = Math.min(os.size() - 1, pos + steps);
Entry targetOp = originalPositionIndex.get(targetPos);
// 检查是否可以交换
if (targetOp != null && opToMove.getGroupId() == targetOp.getGroupId()) {
return neighbor;
}
if (targetOp != null && Math.abs(targetOp.getPriority() - opToMove.getPriority()) > 0.001) {
return neighbor;
}
// 直接交换到目标位置
java.util.Collections.swap(os, pos, targetPos);
neighbor.setOperationSequencing(os);
return neighbor;
}
/**
* 将工序往前插入(不交换,直接插入到目标位置)
*/
private Chromosome insertOperationForward(Chromosome chromosome, int pos, int steps, Map<String, Entry> entrys) {
Chromosome neighbor = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
List<Integer> os = neighbor.getOperationSequencing();
if (pos <= 0 || pos >= os.size()) {
return neighbor;
}
// 获取要移动的工序(基于原始chromosome)
Map<Integer, Entry> originalPositionIndex = buildPositionToEntryIndex(chromosome, entrys);
Entry opToMove = originalPositionIndex.get(pos);
if (opToMove == null) {
return neighbor;
}
// 找到最远可以插入的位置(不打破优先级)
int targetPos = Math.max(0, pos - steps);
int finalTargetPos = pos;
for (int i = pos - 1; i >= targetPos; i--) {
Entry leftOp = originalPositionIndex.get(i);
if (leftOp != null && opToMove.getGroupId() == leftOp.getGroupId()) {
break;
}
if (leftOp != null && Math.abs(leftOp.getPriority() - opToMove.getPriority()) > 0.001) {
break;
}
finalTargetPos = i;
}
if (finalTargetPos == pos) {
return neighbor;
}
// 执行插入:移除原位置,插入到目标位置
int value = os.remove(pos);
os.add(finalTargetPos, value);
neighbor.setOperationSequencing(os);
return neighbor;
}
/**
* 随机生成邻域解(兜底策略)
*/
private Chromosome generateRandomNeighbor(Chromosome chromosome, Map<String, Entry> entrys) {
int neighborType = rnd.nextInt(4); int neighborType = rnd.nextInt(4);
switch (neighborType) { switch (neighborType) {
case 0: case 0:
return generateSwapNeighbor(chromosome,entrys); return generateSwapNeighbor(chromosome, entrys);
case 1: case 1:
return generateReverseNeighbor(chromosome,entrys); return generateReverseNeighbor(chromosome, entrys);
case 2: case 2:
return generateInsertNeighbor(chromosome,entrys); return generateInsertNeighbor(chromosome, entrys);
case 3: case 3:
return generateMachineChangeNeighbor(chromosome); return generateMachineChangeNeighbor(chromosome);
default: default:
return generateSwapNeighbor(chromosome,entrys); return generateSwapNeighbor(chromosome, entrys);
} }
} }
/** /**
* 生成交换邻域解 - 只在相同优先级的工序之间交换 * 生成交换邻域解 - 只在相同优先级的工序之间交换
*/ */
...@@ -332,7 +817,7 @@ public class SimulatedAnnealing { ...@@ -332,7 +817,7 @@ public class SimulatedAnnealing {
List<Integer> ms = neighbor.getMachineSelection(); List<Integer> ms = neighbor.getMachineSelection();
if (!ms.isEmpty()) { if (!ms.isEmpty()) {
int idx = rnd.nextInt(ms.size()); int idx = rnd.nextInt(ms.size());
GlobalOperationInfo globalOp = globalOpList.get(idx); GlobalOperationInfo globalOp = chromosome.getGlobalOpList().get(idx);
Entry op = globalOp.getOp(); Entry op = globalOp.getOp();
if (op.getMachineOptions().size() > 1) { if (op.getMachineOptions().size() > 1) {
......
...@@ -29,6 +29,8 @@ public class TabuSearch { ...@@ -29,6 +29,8 @@ public class TabuSearch {
this.fitnessCalculator = fitnessCalculator; this.fitnessCalculator = fitnessCalculator;
this.objectiveWeights = objectiveWeights; this.objectiveWeights = objectiveWeights;
this.tabuList = new ArrayList<>(); this.tabuList = new ArrayList<>();
// 工序越多,禁忌表越长(适配1000+工序)
this.tabuListSize = Math.min(50, allOperations.size() / 30);
} }
/** /**
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -39,9 +39,9 @@ public class PlanResultServiceTest { ...@@ -39,9 +39,9 @@ public class PlanResultServiceTest {
// TestSortService sortService=new TestSortService(); // TestSortService sortService=new TestSortService();
// sortService.test1(); // sortService.test1();
// nsgaiiUtils.Test(); // nsgaiiUtils.Test();
// planResultService.execute2("0428340BB4F540938F1FB5599F03E8A4");//2000 planResultService.execute2("0428340BB4F540938F1FB5599F03E8A4");//2000
planResultService.execute2("C8B533BD8944405B9A2F8823C575C204");//500 // planResultService.execute2("C8B533BD8944405B9A2F8823C575C204");//500
// planResultService.execute2("EFDD34E4B5BC434BAEAE6A84DFCD4E7B");//20 // planResultService.execute2("EFDD34E4B5BC434BAEAE6A84DFCD4E7B");//20
// planResultService.execute2("00E0C5D3E4AD4F36B56C39395906618D"); // planResultService.execute2("00E0C5D3E4AD4F36B56C39395906618D");
// planResultService.execute2("92BB773E1E2447C99D8176C991D5C9D2"); // planResultService.execute2("92BB773E1E2447C99D8176C991D5C9D2");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment