Commit cb20ded9 authored by Tong Li's avatar Tong Li

优化

parent a94f7c82
...@@ -788,7 +788,7 @@ public class GeneticDecoder { ...@@ -788,7 +788,7 @@ public class GeneticDecoder {
Entry currentOp = orderOps.get(scheduledCount); Entry currentOp = orderOps.get(scheduledCount);
FileHelper.writeLogFile("工序:"+currentOp.getId());
int opSequence = currentOp.getSequence(); int opSequence = currentOp.getSequence();
...@@ -863,7 +863,8 @@ public class GeneticDecoder { ...@@ -863,7 +863,8 @@ public class GeneticDecoder {
orderProcessCounter.put(groupId, orderProcessCounter.get(groupId) + 1); orderProcessCounter.put(groupId, orderProcessCounter.get(groupId) + 1);
orderLastEndTime.put(groupId, actualEndTime); orderLastEndTime.put(groupId, actualEndTime);
if (isJit&& orderProcessCounter.get(groupId) >= entrysBygroupId.get(groupId).size()) { if(false){
// if (isJit&& orderProcessCounter.get(groupId) >= entrysBygroupId.get(groupId).size()) {
List<Entry> orderOpsBySeq = entrysBygroupId.get(groupId).stream() List<Entry> orderOpsBySeq = entrysBygroupId.get(groupId).stream()
.sorted(Comparator.comparingInt(Entry::getSequence)) .sorted(Comparator.comparingInt(Entry::getSequence))
...@@ -1503,10 +1504,10 @@ public class GeneticDecoder { ...@@ -1503,10 +1504,10 @@ public class GeneticDecoder {
Entry op= entryIndexById.get(result.getOperationId()); Entry op= entryIndexById.get(result.getOperationId());
Map<String, MaterialDeduction> deductions = readOperationStockDeductions(op); // Map<String, MaterialDeduction> deductions = readOperationStockDeductions(op);
if (deductions != null && !deductions.isEmpty()) { // if (deductions != null && !deductions.isEmpty()) {
rollbackOperationStockDeduction(chromosome, deductions); // rollbackOperationStockDeduction(chromosome, deductions);
} // }
} }
machineTasksCache.clear(); machineTasksCache.clear();
...@@ -1540,10 +1541,10 @@ public class GeneticDecoder { ...@@ -1540,10 +1541,10 @@ public class GeneticDecoder {
Entry op= entryIndexById.get(result.getOperationId()); Entry op= entryIndexById.get(result.getOperationId());
Map<String, MaterialDeduction> deductions = readOperationStockDeductions(op); // Map<String, MaterialDeduction> deductions = readOperationStockDeductions(op);
if (deductions != null && !deductions.isEmpty()) { // if (deductions != null && !deductions.isEmpty()) {
rollbackOperationStockDeduction(chromosome, deductions); // rollbackOperationStockDeduction(chromosome, deductions);
} // }
Machine machine = getMachineById(chromosome, result.getMachineId()); Machine machine = getMachineById(chromosome, result.getMachineId());
if (machine != null) { if (machine != null) {
AddMachineAvailable(machine, result.getGeneDetails()); AddMachineAvailable(machine, result.getGeneDetails());
......
...@@ -115,6 +115,7 @@ public class HybridAlgorithm { ...@@ -115,6 +115,7 @@ public class HybridAlgorithm {
List<GlobalOperationInfo> globalOpList =new ArrayList<>();// initialization.generateGlobalOpList(); List<GlobalOperationInfo> globalOpList =new ArrayList<>();// initialization.generateGlobalOpList();
// 初始化变邻域搜索 // 初始化变邻域搜索
_vns = new VariableNeighborhoodSearch( allOperations,orders,materials,_entryRel, _fitnessCalculator ); _vns = new VariableNeighborhoodSearch( allOperations,orders,materials,_entryRel, _fitnessCalculator );
_vns.initMachineSelectFrequency();
_hillClimbing = new HillClimbing(allOperations,orders,materials,_entryRel, _fitnessCalculator); _hillClimbing = new HillClimbing(allOperations,orders,materials,_entryRel, _fitnessCalculator);
_simulatedAnnealing = new SimulatedAnnealing( allOperations,orders,materials,_entryRel, _fitnessCalculator); _simulatedAnnealing = new SimulatedAnnealing( allOperations,orders,materials,_entryRel, _fitnessCalculator);
_tabuSearch = new TabuSearch(allOperations,orders,materials,_entryRel, _fitnessCalculator); _tabuSearch = new TabuSearch(allOperations,orders,materials,_entryRel, _fitnessCalculator);
...@@ -464,7 +465,7 @@ public class HybridAlgorithm { ...@@ -464,7 +465,7 @@ public class HybridAlgorithm {
FileHelper.writeLogFile("解码---------------"+population.size() ); FileHelper.writeLogFile("解码---------------"+population.size() );
// GeneticDecoder decoder = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler,materialRequirementService, sceneId); // GeneticDecoder decoder = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler,materialRequirementService, sceneId);
boolean ismore=true; boolean ismore=false;
if(ismore) { if(ismore) {
CompletableFuture.allOf(population.stream() CompletableFuture.allOf(population.stream()
.map(chromosome -> CompletableFuture.runAsync(() -> decode(sharedDecoder, chromosome, param, allOperations, globalOpList), decodeExecutor)) .map(chromosome -> CompletableFuture.runAsync(() -> decode(sharedDecoder, chromosome, param, allOperations, globalOpList), decodeExecutor))
......
...@@ -65,6 +65,11 @@ public class VariableNeighborhoodSearch { ...@@ -65,6 +65,11 @@ public class VariableNeighborhoodSearch {
private static final double SIGNIFICANT_IMPROVEMENT_THRESHOLD = 0.01; // 显著改进阈值:提高到0.01以减少无效搜索 private static final double SIGNIFICANT_IMPROVEMENT_THRESHOLD = 0.01; // 显著改进阈值:提高到0.01以减少无效搜索
private static final int MAX_MINOR_IMPROVEMENTS = 3; // 最大连续微小改进次数,超过后提前终止 private static final int MAX_MINOR_IMPROVEMENTS = 3; // 最大连续微小改进次数,超过后提前终止
// ==================== 设备选择多样性参数 ====================
private static final double LOAD_BALANCE_WEIGHT = 0.5; // 负载均衡权重(越高越倾向低负载设备)
private static final double DIVERSITY_WEIGHT = 0.4; // 设备选择多样性权重(越高越倾向选择次数少的设备)
private static final double RANDOM_NOISE_FOR_MACHINE = 0.1; // 机器选择的随机扰动因子
// 日志级别 // 日志级别
private static final int LOG_LEVEL_DEBUG = 0; private static final int LOG_LEVEL_DEBUG = 0;
private static final int LOG_LEVEL_INFO = 1; private static final int LOG_LEVEL_INFO = 1;
...@@ -75,7 +80,7 @@ public class VariableNeighborhoodSearch { ...@@ -75,7 +80,7 @@ public class VariableNeighborhoodSearch {
private static final int MAX_LOCAL_SEARCH_NEIGHBORS = 2; // 从5减少到2,大幅减少解码次数 private static final int MAX_LOCAL_SEARCH_NEIGHBORS = 2; // 从5减少到2,大幅减少解码次数
private void log(String message) { private void log(String message) {
log(message, LOG_LEVEL_INFO, false); log(message, LOG_LEVEL_INFO, true);
} }
private void log(String message, boolean enableLogging) { private void log(String message, boolean enableLogging) {
...@@ -107,6 +112,15 @@ public class VariableNeighborhoodSearch { ...@@ -107,6 +112,15 @@ public class VariableNeighborhoodSearch {
// 预检查:是否有工序有多个机器选项 // 预检查:是否有工序有多个机器选项
private boolean hasMultipleMachineOptions = false; private boolean hasMultipleMachineOptions = false;
// 工序-设备选择频率:opKey(groupId_sequence) -> machineId -> 选择次数(用于鼓励设备选择多样性)
private Map<String, Map<Long, Integer>> opMachineSelectFrequency = new HashMap<>();
// 瓶颈设备选择频率:machineId -> 被当作"瓶颈设备"的次数(用于鼓励探索不同的设备)
private Map<Long, Integer> bottleneckMachineFrequency = new HashMap<>();
// 瓶颈工序选择频率:operationId -> 被当作"优化目标"的次数(用于鼓励探索不同的工序)
private Map<Integer, Integer> bottleneckOpFrequency = new HashMap<>();
// 策略成功率统计 // 策略成功率统计
private int[] strategySuccessCount = new int[4]; private int[] strategySuccessCount = new int[4];
private int[] strategyTotalCount = new int[4]; private int[] strategyTotalCount = new int[4];
...@@ -204,7 +218,7 @@ public class VariableNeighborhoodSearch { ...@@ -204,7 +218,7 @@ public class VariableNeighborhoodSearch {
neighborhoods.add(new NeighborhoodStructure("SmartBottleneckChange", this::ChangeMachineForBottleneckOpWrapper)); neighborhoods.add(new NeighborhoodStructure("SmartBottleneckChange", this::ChangeMachineForBottleneckOpWrapper));
//瓶颈工序在相同设备上移动 //瓶颈工序在相同设备上移动
neighborhoods.add(new NeighborhoodStructure("moveBottleneckSameMachine", this::moveBottleneckSameMachineWrapper)); neighborhoods.add(new NeighborhoodStructure("moveBottleneckSameMachine", this::moveBottleneckSameMachineWrapper));
//瓶颈工序往前移动 //瓶颈工序往前移动
neighborhoods.add(new NeighborhoodStructure("MoveBottleneckForward", this::moveBottleneckForwardWrapper)); neighborhoods.add(new NeighborhoodStructure("MoveBottleneckForward", this::moveBottleneckForwardWrapper));
...@@ -238,7 +252,7 @@ public class VariableNeighborhoodSearch { ...@@ -238,7 +252,7 @@ public class VariableNeighborhoodSearch {
neighborhoods.add(new NeighborhoodStructure("MultiOperationSwap", this::multiOperationSwapWrapper)); neighborhoods.add(new NeighborhoodStructure("MultiOperationSwap", this::multiOperationSwapWrapper));
// MultiMachineChange - 一次改变多个工序的机器选择 // MultiMachineChange - 一次改变多个工序的机器选择
neighborhoods.add(new NeighborhoodStructure("MultiMachineChange", this::multiMachineChangeWrapper)); neighborhoods.add(new NeighborhoodStructure("MultiMachineChange", this::multiMachineChangeWrapper));
// HybridShake - 混合抖动:综合调整 // HybridShake - 混合抖动:综合调整
neighborhoods.add(new NeighborhoodStructure("HybridShake", this::hybridShakeWrapper)); neighborhoods.add(new NeighborhoodStructure("HybridShake", this::hybridShakeWrapper));
...@@ -315,9 +329,13 @@ public class VariableNeighborhoodSearch { ...@@ -315,9 +329,13 @@ public class VariableNeighborhoodSearch {
public Chromosome search(Chromosome chromosome, GeneticDecoder decoder, List<Machine> machines) { public Chromosome search(Chromosome chromosome, GeneticDecoder decoder, List<Machine> machines) {
log("变邻域搜索 - 开始执行",true); log("变邻域搜索 - 开始执行",true);
// 注意:设备选择频率不在这里重置
// 频率在整个优化流程起点(HybridAlgorithm初始化时)调用 initMachineSelectFrequency() 初始化一次
// 这样频率可以跨模拟退火、变邻域搜索、禁忌搜索等所有算法累积,真正鼓励设备选择多样性
// 深拷贝当前染色体 // 深拷贝当前染色体
Chromosome current = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class); Chromosome current = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
// geneticOperations.DelOrder(current); // geneticOperations.DelOrder(current);
Chromosome best = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class); Chromosome best = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
writeKpi(best); writeKpi(best);
...@@ -643,11 +661,71 @@ public class VariableNeighborhoodSearch { ...@@ -643,11 +661,71 @@ public class VariableNeighborhoodSearch {
return result; return result;
} }
// 找出利用率最高的设备 // === 频率驱动的瓶颈设备选择 ===
Long bottleneckMachineId = utilization.entrySet().stream() // 不再总是选利用率最高的,而是给利用率高+历史被选次数少的设备更高评分
.max(Map.Entry.comparingByValue()) List<Map.Entry<Long, Double>> machineEntries = new ArrayList<>(utilization.entrySet());
.map(Map.Entry::getKey) machineEntries.sort((a, b) -> Double.compare(b.getValue(), a.getValue()));
.orElse(null);
// 取利用率前30%的设备作为候选(确保都是高利用率的,不选冷门低负载设备)
int topCount = Math.max(3, Math.min(machineEntries.size(), (int) Math.ceil(machineEntries.size() * 0.3)));
List<Map.Entry<Long, Double>> topMachines = machineEntries.subList(0, topCount);
// 给每个候选设备计算综合评分(利用率 + 频率多样性)
double maxUtil = topMachines.get(0).getValue();
double minUtil = topMachines.get(topMachines.size() - 1).getValue();
double utilRange = Math.max(0.01, maxUtil - minUtil);
List<Object[]> scoredMachines = new ArrayList<>();
int maxFreq = 1;
for (Map.Entry<Long, Double> entry : topMachines) {
int freq = bottleneckMachineFrequency.getOrDefault(entry.getKey(), 0);
maxFreq = Math.max(maxFreq, freq);
}
for (Map.Entry<Long, Double> entry : topMachines) {
Long machineId = entry.getKey();
double util = entry.getValue();
int freq = bottleneckMachineFrequency.getOrDefault(machineId, 0);
// 归一化评分
double normalizedUtil = (util - minUtil) / utilRange; // 0~1
double diversityScore = 1.0 / (1.0 + freq); // 0次→1.0, 次数越多越低
// 综合评分:60% 利用率 + 40% 频率多样性 + 小随机扰动
double score = 0.6 * normalizedUtil + 0.4 * diversityScore + 0.1 * rnd.nextDouble();
scoredMachines.add(new Object[]{machineId, score, util, freq});
}
// 按综合评分降序排序
scoredMachines.sort((a, b) -> Double.compare((Double) b[1], (Double) a[1]));
// 70%选评分最高的,30%按加权随机
Long selectedMachineId;
if (rnd.nextDouble() < 0.7 || scoredMachines.size() <= 1) {
selectedMachineId = (Long) scoredMachines.get(0)[0];
} else {
// 加权轮盘赌
double totalScore = 0;
for (Object[] m : scoredMachines) {
totalScore += (Double) m[1];
}
double r = rnd.nextDouble() * totalScore;
double cumSum = 0;
selectedMachineId = (Long) scoredMachines.get(scoredMachines.size() - 1)[0];
for (Object[] m : scoredMachines) {
cumSum += (Double) m[1];
if (r <= cumSum) {
selectedMachineId = (Long) m[0];
break;
}
}
}
// 更新该设备被选为瓶颈设备的频率
bottleneckMachineFrequency.merge(selectedMachineId, 1, Integer::sum);
Long bottleneckMachineId = selectedMachineId;
result.put("bottleneckMachineId", bottleneckMachineId); result.put("bottleneckMachineId", bottleneckMachineId);
result.put("utilization", utilization); result.put("utilization", utilization);
...@@ -876,7 +954,7 @@ public class VariableNeighborhoodSearch { ...@@ -876,7 +954,7 @@ public class VariableNeighborhoodSearch {
.orElse(0); .orElse(0);
for (GAScheduleResult op : ops) { for (GAScheduleResult op : ops) {
orderCompletionTime.put(op.getGroupId(), maxEndTime); orderCompletionTime.put(op.getGroupId(), maxEndTime);
} }
} }
...@@ -1205,54 +1283,65 @@ public class VariableNeighborhoodSearch { ...@@ -1205,54 +1283,65 @@ public class VariableNeighborhoodSearch {
return null; return null;
} }
// 优先选择订单数多的优先级的工序 // === 频率驱动的瓶颈工序选择 ===
// 构建优先级->订单数的映射 // 不再只按优先级排序,综合考虑优先级+历史被选次数,鼓励探索不同工序
Map<Double, Set<Integer>> priorityToGroupIds = new HashMap<>(); Map<Double, Set<Integer>> priorityToGroupIds = new HashMap<>();
int maxGroupCount = 1;
for (GAScheduleResult op : candidates) { for (GAScheduleResult op : candidates) {
Entry entry = entrybyids.get(op.getOperationId()); Entry entry = entrybyids.get(op.getOperationId());
if (entry != null) { if (entry != null) {
double priority = entry.getPriority(); double priority = entry.getPriority();
priorityToGroupIds.computeIfAbsent(priority, k -> new HashSet<>()).add(op.getGroupId()); int groupCount = priorityToGroupIds.computeIfAbsent(priority, k -> new HashSet<>()).size() + 1;
priorityToGroupIds.get(priority).add(op.getGroupId());
maxGroupCount = Math.max(maxGroupCount, priorityToGroupIds.get(priority).size());
} }
} }
// 按订单数从多到少排序候选工序 // 给每个候选工序计算综合评分
List<GAScheduleResult> sortedCandidates = new ArrayList<>(candidates); List<Object[]> scoredOps = new ArrayList<>();
sortedCandidates.sort((a, b) -> { int maxOpFreq = 1;
Entry entryA = entrybyids.get(a.getOperationId()); for (GAScheduleResult op : candidates) {
Entry entryB = entrybyids.get(b.getOperationId()); int freq = bottleneckOpFrequency.getOrDefault(op.getOperationId(), 0);
maxOpFreq = Math.max(maxOpFreq, freq);
}
for (GAScheduleResult op : candidates) {
Entry entry = entrybyids.get(op.getOperationId());
if (entry == null) continue;
// 统一处理null值:null值排后面 // 优先级评分:订单数多的优先级组排前面(0~1归一化)
if (entryA == null && entryB == null) return 0; int groupCount = priorityToGroupIds.getOrDefault(entry.getPriority(), new HashSet<>()).size();
if (entryA == null) return 1; double priorityScore = (double) groupCount / maxGroupCount;
if (entryB == null) return -1;
int sizeA = priorityToGroupIds.getOrDefault(entryA.getPriority(), new HashSet<>()).size(); // 频率多样性评分(0次→1.0, 次数越多越低)
int sizeB = priorityToGroupIds.getOrDefault(entryB.getPriority(), new HashSet<>()).size(); int freq = bottleneckOpFrequency.getOrDefault(op.getOperationId(), 0);
double diversityScore = 1.0 / (1.0 + freq);
// 订单数多的优先级排前面 // 综合评分:50% 优先级 + 40% 频率多样性 + 10% 随机
int sizeCompare = Integer.compare(sizeB, sizeA); double score = 0.5 * priorityScore + 0.4 * diversityScore + 0.1 * rnd.nextDouble();
if (sizeCompare != 0) {
return sizeCompare;
}
// 订单数相同时,按优先级排序 scoredOps.add(new Object[]{op, score, groupCount, freq});
return Double.compare(entryA.getPriority(), entryB.getPriority()); }
});
// 70%概率选择前3个候选,30%概率随机选择 // 按综合评分降序排序
scoredOps.sort((a, b) -> Double.compare((Double) b[1], (Double) a[1]));
// 70%概率选择前3个候选,30%概率在更后面选
GAScheduleResult selectedOp; GAScheduleResult selectedOp;
if (sortedCandidates.size() <= 3) { if (scoredOps.size() <= 3) {
selectedOp = sortedCandidates.get(rnd.nextInt(sortedCandidates.size())); selectedOp = (GAScheduleResult) scoredOps.get(rnd.nextInt(scoredOps.size()))[0];
} else { } else {
if (rnd.nextDouble() < 0.7) { if (rnd.nextDouble() < 0.7) {
selectedOp = sortedCandidates.get(rnd.nextInt(Math.min(3, sortedCandidates.size()))); selectedOp = (GAScheduleResult) scoredOps.get(rnd.nextInt(Math.min(3, scoredOps.size())))[0];
} else { } else {
int otherCount = sortedCandidates.size() - 3; int otherCount = scoredOps.size() - 3;
selectedOp = sortedCandidates.get(3 + rnd.nextInt(otherCount)); selectedOp = (GAScheduleResult) scoredOps.get(3 + rnd.nextInt(otherCount))[0];
} }
} }
// 更新该工序被选为优化目标的频率
bottleneckOpFrequency.merge(selectedOp.getOperationId(), 1, Integer::sum);
int maPos = -1; int maPos = -1;
Entry entry= entrybyids.get(selectedOp.getOperationId()); Entry entry= entrybyids.get(selectedOp.getOperationId());
...@@ -1300,15 +1389,22 @@ public class VariableNeighborhoodSearch { ...@@ -1300,15 +1389,22 @@ public class VariableNeighborhoodSearch {
} }
/** /**
* 给指定位置的工序换设备 - 考虑设备负载均衡优化 * 给指定位置的工序换设备 - 综合考虑设备负载均衡和选择多样性
* 优先选择负载低的设备 * 优先选择负载低且选择次数少的设备
*/ */
private Chromosome generateMachineChangeForSpecificOp(Chromosome chromosome, List<MachineOption> machineOptions, int idx) { private Chromosome generateMachineChangeForSpecificOp(Chromosome chromosome, List<MachineOption> machineOptions, int idx) {
Chromosome neighbor=copyChromosome(chromosome);// ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class); Chromosome neighbor=copyChromosome(chromosome);
CopyOnWriteArrayList<Integer> ms = neighbor.getMachineSelection(); CopyOnWriteArrayList<Integer> ms = neighbor.getMachineSelection();
if (!ms.isEmpty() && idx >= 0 && idx < ms.size()) { if (!ms.isEmpty() && idx >= 0 && idx < ms.size()) {
if (machineOptions.size() > 1) { if (machineOptions.size() > 1) {
// 获取工序信息,用于频率跟踪
String opKey = null;
if (idx < chromosome.getGlobalOpList().size()) {
Entry op = chromosome.getGlobalOpList().get(idx).getOp();
opKey = op.getGroupId() + "_" + op.getSequence();
}
int currentMachineSeq = ms.get(idx); int currentMachineSeq = ms.get(idx);
List<Integer> availableMachines = new ArrayList<>(); List<Integer> availableMachines = new ArrayList<>();
for (int i = 1; i <= machineOptions.size(); i++) { for (int i = 1; i <= machineOptions.size(); i++) {
...@@ -1318,10 +1414,14 @@ public class VariableNeighborhoodSearch { ...@@ -1318,10 +1414,14 @@ public class VariableNeighborhoodSearch {
} }
if (!availableMachines.isEmpty()) { if (!availableMachines.isEmpty()) {
// 选择负载较低的设备(设备负载均衡优化) // 选择综合考虑负载均衡和选择多样性的设备
int newMachineSeq = selectMachineByLoad(availableMachines, machineOptions, chromosome); int newMachineSeq = selectMachineByLoad(availableMachines, machineOptions, chromosome, opKey);
ms.set(idx, newMachineSeq); ms.set(idx, newMachineSeq);
neighbor.setMachineSelection(ms); neighbor.setMachineSelection(ms);
// 更新该设备被选择的频率记录
Long selectedMachineId = machineOptions.get(newMachineSeq - 1).getMachineId();
updateMachineSelectFrequency(opKey, selectedMachineId);
} }
} }
} }
...@@ -1402,52 +1502,66 @@ public class VariableNeighborhoodSearch { ...@@ -1402,52 +1502,66 @@ public class VariableNeighborhoodSearch {
.collect(Collectors.toList()); .collect(Collectors.toList());
Map<Integer, Integer> orderCompletionTimes = calculateOrderCompletionTimes(allResults); Map<Integer, Integer> orderCompletionTimes = calculateOrderCompletionTimes(allResults);
// 先构建优先级->订单数的映射 // === 频率驱动的瓶颈工序选择(与tryChangeMachineForBottleneckOp相同策略) ===
Map<Double, Set<Integer>> priorityToGroupIds = new HashMap<>(); Map<Double, Set<Integer>> priorityToGroupIds = new HashMap<>();
int maxGroupCount = 1;
for (GAScheduleResult op : bottleneckOps) { for (GAScheduleResult op : bottleneckOps) {
Entry entry = entrybyids.get(op.getOperationId()); Entry entry = entrybyids.get(op.getOperationId());
if (entry != null) { if (entry != null) {
double priority = entry.getPriority(); double priority = entry.getPriority();
priorityToGroupIds.computeIfAbsent(priority, k -> new HashSet<>()).add(op.getGroupId()); int groupCount = priorityToGroupIds.computeIfAbsent(priority, k -> new HashSet<>()).size() + 1;
priorityToGroupIds.get(priority).add(op.getGroupId());
maxGroupCount = Math.max(maxGroupCount, priorityToGroupIds.get(priority).size());
} }
} }
List<GAScheduleResult> sortedBottleneckOps = new ArrayList<>(bottleneckOps); // 给每个候选工序计算综合评分
sortedBottleneckOps.sort((a, b) -> { List<Object[]> scoredOps = new ArrayList<>();
Entry entryA = entrybyids.get(a.getOperationId()); for (GAScheduleResult op : bottleneckOps) {
Entry entryB = entrybyids.get(b.getOperationId()); Entry entry = entrybyids.get(op.getOperationId());
if (entry == null) continue;
// 统一处理null值:null值排后面 // 优先级评分(0~1归一化)
if (entryA == null && entryB == null) return 0; int groupCount = priorityToGroupIds.getOrDefault(entry.getPriority(), new HashSet<>()).size();
if (entryA == null) return 1; double priorityScore = (double) groupCount / maxGroupCount;
if (entryB == null) return -1;
// 优先按订单数从多到少排序 // 订单完成时间评分:完成时间越晚,越需要优化(0~1归一化)
int sizeA = priorityToGroupIds.getOrDefault(entryA.getPriority(), new HashSet<>()).size(); int endTime = orderCompletionTimes.getOrDefault(op.getGroupId(), 0);
int sizeB = priorityToGroupIds.getOrDefault(entryB.getPriority(), new HashSet<>()).size(); int maxEndTime = 0;
int sizeCompare = Integer.compare(sizeB, sizeA); for (int t : orderCompletionTimes.values()) {
if (sizeCompare != 0) { maxEndTime = Math.max(maxEndTime, t);
return sizeCompare;
} }
double timeScore = maxEndTime > 0 ? (double) endTime / maxEndTime : 0.5;
// 订单数相同时,按优先级排序 // 频率多样性评分(0次→1.0, 次数越多越低)
int priorityCompare = Double.compare(entryA.getPriority(), entryB.getPriority()); int freq = bottleneckOpFrequency.getOrDefault(op.getOperationId(), 0);
if (priorityCompare != 0) { double diversityScore = 1.0 / (1.0 + freq);
return priorityCompare;
}
// 优先级相同时,按完成时间排序 // 综合评分:35% 优先级 + 25% 时间 + 40% 频率多样性 + 小随机
int endTimeA = orderCompletionTimes.getOrDefault(a.getGroupId(), 0); double score = 0.35 * priorityScore + 0.25 * timeScore + 0.4 * diversityScore + 0.1 * rnd.nextDouble();
int endTimeB = orderCompletionTimes.getOrDefault(b.getGroupId(), 0);
return Integer.compare(endTimeB, endTimeA); scoredOps.add(new Object[]{op, score, freq});
}); }
if (sortedBottleneckOps.isEmpty()) { // 按综合评分降序排序
scoredOps.sort((a, b) -> Double.compare((Double) b[1], (Double) a[1]));
if (scoredOps.isEmpty()) {
log("tryMoveBottleneckOpForward: 排序后为空"); log("tryMoveBottleneckOpForward: 排序后为空");
return null; return null;
} }
GAScheduleResult selectedOp = sortedBottleneckOps.get(rnd.nextInt(Math.min(5, sortedBottleneckOps.size()))); // 70%选前5个中的随机,30%选更后面的
GAScheduleResult selectedOp;
int topN = Math.min(5, scoredOps.size());
if (rnd.nextDouble() < 0.7 || scoredOps.size() <= 5) {
selectedOp = (GAScheduleResult) scoredOps.get(rnd.nextInt(topN))[0];
} else {
selectedOp = (GAScheduleResult) scoredOps.get(topN + rnd.nextInt(scoredOps.size() - topN))[0];
}
// 更新该工序被选为优化目标的频率
bottleneckOpFrequency.merge(selectedOp.getOperationId(), 1, Integer::sum);
Entry entry = entrybyids.get(selectedOp.getOperationId()); Entry entry = entrybyids.get(selectedOp.getOperationId());
if (entry == null) { if (entry == null) {
...@@ -1788,7 +1902,7 @@ public class VariableNeighborhoodSearch { ...@@ -1788,7 +1902,7 @@ public class VariableNeighborhoodSearch {
* 生成反转邻域解 - 只反转相同优先级的连续工序 * 生成反转邻域解 - 只反转相同优先级的连续工序
*/ */
private Chromosome generateReverseNeighbor(Chromosome chromosome,Map<Integer, Entry> positionIndex,List<List<Integer>> positionByPriority) { private Chromosome generateReverseNeighbor(Chromosome chromosome,Map<Integer, Entry> positionIndex,List<List<Integer>> positionByPriority) {
log("generateReverseNeighbor"+positionIndex.size()); log("generateReverseNeighbor"+positionIndex.size());
Chromosome neighbor = copyChromosome(chromosome); //ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class); Chromosome neighbor = copyChromosome(chromosome); //ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
CopyOnWriteArrayList<Integer> os = neighbor.getOperationSequencing(); CopyOnWriteArrayList<Integer> os = neighbor.getOperationSequencing();
...@@ -1842,10 +1956,10 @@ public class VariableNeighborhoodSearch { ...@@ -1842,10 +1956,10 @@ public class VariableNeighborhoodSearch {
// } // }
//if (allSameGroupId) { //if (allSameGroupId) {
java.util.Collections.reverse(os.subList(start, end + 1)); java.util.Collections.reverse(os.subList(start, end + 1));
neighbor.setOperationSequencing(os); neighbor.setOperationSequencing(os);
break; break;
// } // }
} }
} }
return neighbor; return neighbor;
...@@ -1922,7 +2036,7 @@ public class VariableNeighborhoodSearch { ...@@ -1922,7 +2036,7 @@ public class VariableNeighborhoodSearch {
*/ */
private Chromosome generateMachineChangeNeighbor(Chromosome chromosome) { private Chromosome generateMachineChangeNeighbor(Chromosome chromosome) {
log("generateMachineChangeNeighbor"); log("generateMachineChangeNeighbor");
Chromosome neighbor=copyChromosome(chromosome);// ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class); Chromosome neighbor=copyChromosome(chromosome);
CopyOnWriteArrayList<Integer> ms = neighbor.getMachineSelection(); CopyOnWriteArrayList<Integer> ms = neighbor.getMachineSelection();
if (!ms.isEmpty()) { if (!ms.isEmpty()) {
int idx = rnd.nextInt(ms.size()); int idx = rnd.nextInt(ms.size());
...@@ -1930,6 +2044,9 @@ public class VariableNeighborhoodSearch { ...@@ -1930,6 +2044,9 @@ public class VariableNeighborhoodSearch {
Entry op = globalOp.getOp(); Entry op = globalOp.getOp();
if (op.getMachineOptions().size() > 1) { if (op.getMachineOptions().size() > 1) {
// 构建工序唯一键,用于频率跟踪
String opKey = op.getGroupId() + "_" + op.getSequence();
int currentMachineSeq = ms.get(idx); int currentMachineSeq = ms.get(idx);
List<Integer> availableMachines = new ArrayList<>(); List<Integer> availableMachines = new ArrayList<>();
List<MachineOption> machineOptions = new ArrayList<>(); List<MachineOption> machineOptions = new ArrayList<>();
...@@ -1941,10 +2058,14 @@ public class VariableNeighborhoodSearch { ...@@ -1941,10 +2058,14 @@ public class VariableNeighborhoodSearch {
} }
if (!availableMachines.isEmpty()) { if (!availableMachines.isEmpty()) {
// 选择负载较低的设备(设备负载均衡优化) // 综合考虑负载均衡和选择多样性
int newMachineSeq = selectMachineByLoad(availableMachines, machineOptions, chromosome); int newMachineSeq = selectMachineByLoad(availableMachines, machineOptions, chromosome, opKey);
ms.set(idx, newMachineSeq); ms.set(idx, newMachineSeq);
neighbor.setMachineSelection(ms); neighbor.setMachineSelection(ms);
// 更新频率记录
Long selectedMachineId = op.getMachineOptions().get(newMachineSeq - 1).getMachineId();
updateMachineSelectFrequency(opKey, selectedMachineId);
} }
} }
} }
...@@ -2006,9 +2127,9 @@ public class VariableNeighborhoodSearch { ...@@ -2006,9 +2127,9 @@ public class VariableNeighborhoodSearch {
int idx2 = positions.get(rnd.nextInt(positions.size())); int idx2 = positions.get(rnd.nextInt(positions.size()));
if(idx1>os.size()||idx2>os.size()) if(idx1>os.size()||idx2>os.size())
{ {
int i=0; int i=0;
} }
Collections.swap(os, idx1, idx2); Collections.swap(os, idx1, idx2);
neighbor.setOperationSequencing(os); neighbor.setOperationSequencing(os);
...@@ -2343,54 +2464,132 @@ public class VariableNeighborhoodSearch { ...@@ -2343,54 +2464,132 @@ public class VariableNeighborhoodSearch {
/** /**
* 机器选项和负载信息的辅助类 * 机器选项和负载信息的辅助类
*/ */
private static class MachineOptionWithUtilization { private static class MachineOptionWithScore {
int seq; int seq;
MachineOption option; MachineOption option;
double utilization; double score; // 综合评分(越高越优)
double utilization; // 设备利用率
int frequency; // 该设备被该工序选择的次数
double diversityScore; // 多样性评分
MachineOptionWithUtilization(int seq, MachineOption option, double utilization) { MachineOptionWithScore(int seq, MachineOption option, double utilization, int frequency, double diversityScore) {
this.seq = seq; this.seq = seq;
this.option = option; this.option = option;
this.utilization = utilization; this.utilization = utilization;
this.frequency = frequency;
this.diversityScore = diversityScore;
this.score = 0.0;
} }
} }
/** /**
* 选择负载较低的设备 - 设备负载均衡优化 * 选择设备 - 综合考虑负载均衡和设备选择多样性
* 优先选择负载低的设备 * 综合评分:score = 负载均衡分 * 权重 + 多样性分 * 权重 + 随机扰动
* - 负载均衡分 = 1 - utilization(利用率越低越好)
* - 多样性分 = 1 / (1 + frequency)(选择次数越少越好)
* - 然后使用加权轮盘赌选择,得分最高的设备
*/ */
private int selectMachineByLoad(List<Integer> availableMachineSeqs, List<MachineOption> machineOptions, Chromosome chromosome) { private int selectMachineByLoad(List<Integer> availableMachineSeqs, List<MachineOption> machineOptions, Chromosome chromosome, String opKey) {
// 计算当前各设备的负载(利用率) // 计算当前各设备的负载(利用率)
Map<Long, Double> machineUtilization = calculateMachineUtilization(chromosome,true); Map<Long, Double> machineUtilization = calculateMachineUtilization(chromosome, true);
// 构建可用机器列表,计算综合评分
List<MachineOptionWithScore> availableMachines = new ArrayList<>();
// 构建可用机器列表,按负载从低到高排序
List<MachineOptionWithUtilization> availableMachines = new ArrayList<>();
for (int seq : availableMachineSeqs) { for (int seq : availableMachineSeqs) {
if(seq - 1>=machineOptions.size()) if (seq - 1 >= machineOptions.size()) {
{
break; break;
} }
MachineOption option = machineOptions.get(seq - 1); MachineOption option = machineOptions.get(seq - 1);
Long machineId = option.getMachineId(); Long machineId = option.getMachineId();
double utilization = machineUtilization.getOrDefault(machineId, 0.0); double utilization = machineUtilization.getOrDefault(machineId, 0.0);
availableMachines.add(new MachineOptionWithUtilization(seq, option, utilization));
}
// 按利用率从低到高排序 // 获取该工序对该设备的选择次数
availableMachines.sort(Comparator.comparingDouble(m -> m.utilization)); int frequency = 0;
if (opKey != null && opMachineSelectFrequency.containsKey(opKey)) {
frequency = opMachineSelectFrequency.get(opKey).getOrDefault(machineId, 0);
}
// 归一化多样性分:选择次数越少,分越高(0~1范围
double diversity = 1.0 / (1.0 + frequency); // 0次→1, 1次→0.5, 2次→0.33...
if(availableMachines.size()==0) // 综合评分
{ double loadBalanceScore = (1.0 - utilization);
double noise = rnd.nextDouble() * RANDOM_NOISE_FOR_MACHINE;
double score = LOAD_BALANCE_WEIGHT * loadBalanceScore
+ DIVERSITY_WEIGHT * diversity
+ noise;
MachineOptionWithScore machineWithScore = new MachineOptionWithScore(seq, option, utilization, frequency, diversity);
machineWithScore.score = score;
availableMachines.add(machineWithScore);
}
if (availableMachines.size() == 0) {
return 1; return 1;
} }
// 70%概率选择负载最低的设备,30%概率随机选择
// 按综合评分降序排序
availableMachines.sort((m1, m2) -> Double.compare(m2.score, m1.score));
// 使用加权轮盘赌选择(70%概率选择得分最高的,30%按评分加权随机
if (rnd.nextDouble() < 0.7) { if (rnd.nextDouble() < 0.7) {
return availableMachines.get(0).seq; return availableMachines.get(0).seq;
} else { } else {
return availableMachines.get(rnd.nextInt(availableMachines.size())).seq; // 按评分加权随机选择
double totalScore = 0;
for (MachineOptionWithScore m : availableMachines) {
totalScore += Math.max(m.score, 0.001);
}
double r = rnd.nextDouble() * totalScore;
double cumSum = 0;
for (MachineOptionWithScore m : availableMachines) {
cumSum += Math.max(m.score, 0.001);
if (r <= cumSum) {
return m.seq;
}
}
return availableMachines.get(availableMachines.size() - 1).seq;
} }
} }
/**
* 更新工序-设备选择频率记录
*/
private void updateMachineSelectFrequency(String opKey, Long machineId) {
if (opKey == null || opKey.isEmpty() || machineId == null || machineId <= 0) return;
opMachineSelectFrequency.computeIfAbsent(opKey, k -> new HashMap<>()).merge(machineId, 1, Integer::sum);
}
/**
* 初始化所有频率表(在整个优化流程开始时调用一次)
* 频率在模拟退火、变邻域搜索、禁忌搜索等所有算法中共享,不会随单个算法search调用而重置
* 这样才能真正鼓励探索多样性:
* 1) 同一工序尝试不同的设备
* 2) 尝试不同的瓶颈设备
* 3) 尝试不同的瓶颈工序作为优化目标
*/
public void initMachineSelectFrequency() {
opMachineSelectFrequency.clear();
bottleneckMachineFrequency.clear();
bottleneckOpFrequency.clear();
}
/**
* 获取频率表(用于调试日志)
*/
public Map<String, Map<Long, Integer>> getMachineSelectFrequency() {
return opMachineSelectFrequency;
}
public Map<Long, Integer> getBottleneckMachineFrequency() {
return bottleneckMachineFrequency;
}
public Map<Integer, Integer> getBottleneckOpFrequency() {
return bottleneckOpFrequency;
}
/** /**
* 交换候选对象,包含位置和评分(用于准备时间优化) * 交换候选对象,包含位置和评分(用于准备时间优化)
*/ */
......
...@@ -177,8 +177,8 @@ public class PlanResultService { ...@@ -177,8 +177,8 @@ public class PlanResultService {
* 后续会按场景创建人自动回退到可用的策略配置。 * 后续会按场景创建人自动回退到可用的策略配置。
*/ */
public Chromosome execute2(String SceneId) { public Chromosome execute2(String SceneId) {
return execute2(SceneId, 2361l, 241l, null); // return execute2(SceneId, 2361l, 241l, null);
// return execute2(SceneId, 2321l, 207l, null); return execute2(SceneId, 2321l, 207l, null);
} }
......
...@@ -42,7 +42,7 @@ public class PlanResultServiceTest { ...@@ -42,7 +42,7 @@ public class PlanResultServiceTest {
// nsgaiiUtils.Test(); // nsgaiiUtils.Test();
// planResultService.execute2("64E64F6B68094AF38CEDC418630C3CC2");//2000 // planResultService.execute2("64E64F6B68094AF38CEDC418630C3CC2");//2000
// planResultService.execute2("E1448B3C9C8743DEAB39708F2CFE348A");//倒排bomces // planResultService.execute2("E1448B3C9C8743DEAB39708F2CFE348A");//倒排bomces
planResultService.execute2("197083D0D26A449EB179AC103C753FD3"); planResultService.execute2("197083D0D26A449EB179AC103C753FD3");
// planResultService.execute2("9FEDFD92BB6A4675BF9B1CC64505D1AB"); // planResultService.execute2("9FEDFD92BB6A4675BF9B1CC64505D1AB");
......
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