Commit cb20ded9 authored by Tong Li's avatar Tong Li

优化

parent a94f7c82
......@@ -788,7 +788,7 @@ public class GeneticDecoder {
Entry currentOp = orderOps.get(scheduledCount);
FileHelper.writeLogFile("工序:"+currentOp.getId());
int opSequence = currentOp.getSequence();
......@@ -863,7 +863,8 @@ public class GeneticDecoder {
orderProcessCounter.put(groupId, orderProcessCounter.get(groupId) + 1);
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()
.sorted(Comparator.comparingInt(Entry::getSequence))
......@@ -1503,10 +1504,10 @@ public class GeneticDecoder {
Entry op= entryIndexById.get(result.getOperationId());
Map<String, MaterialDeduction> deductions = readOperationStockDeductions(op);
if (deductions != null && !deductions.isEmpty()) {
rollbackOperationStockDeduction(chromosome, deductions);
}
// Map<String, MaterialDeduction> deductions = readOperationStockDeductions(op);
// if (deductions != null && !deductions.isEmpty()) {
// rollbackOperationStockDeduction(chromosome, deductions);
// }
}
machineTasksCache.clear();
......@@ -1540,10 +1541,10 @@ public class GeneticDecoder {
Entry op= entryIndexById.get(result.getOperationId());
Map<String, MaterialDeduction> deductions = readOperationStockDeductions(op);
if (deductions != null && !deductions.isEmpty()) {
rollbackOperationStockDeduction(chromosome, deductions);
}
// Map<String, MaterialDeduction> deductions = readOperationStockDeductions(op);
// if (deductions != null && !deductions.isEmpty()) {
// rollbackOperationStockDeduction(chromosome, deductions);
// }
Machine machine = getMachineById(chromosome, result.getMachineId());
if (machine != null) {
AddMachineAvailable(machine, result.getGeneDetails());
......
......@@ -115,6 +115,7 @@ public class HybridAlgorithm {
List<GlobalOperationInfo> globalOpList =new ArrayList<>();// initialization.generateGlobalOpList();
// 初始化变邻域搜索
_vns = new VariableNeighborhoodSearch( allOperations,orders,materials,_entryRel, _fitnessCalculator );
_vns.initMachineSelectFrequency();
_hillClimbing = new HillClimbing(allOperations,orders,materials,_entryRel, _fitnessCalculator);
_simulatedAnnealing = new SimulatedAnnealing( allOperations,orders,materials,_entryRel, _fitnessCalculator);
_tabuSearch = new TabuSearch(allOperations,orders,materials,_entryRel, _fitnessCalculator);
......@@ -464,7 +465,7 @@ public class HybridAlgorithm {
FileHelper.writeLogFile("解码---------------"+population.size() );
// GeneticDecoder decoder = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler,materialRequirementService, sceneId);
boolean ismore=true;
boolean ismore=false;
if(ismore) {
CompletableFuture.allOf(population.stream()
.map(chromosome -> CompletableFuture.runAsync(() -> decode(sharedDecoder, chromosome, param, allOperations, globalOpList), decodeExecutor))
......
......@@ -65,6 +65,11 @@ public class VariableNeighborhoodSearch {
private static final double SIGNIFICANT_IMPROVEMENT_THRESHOLD = 0.01; // 显著改进阈值:提高到0.01以减少无效搜索
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_INFO = 1;
......@@ -75,7 +80,7 @@ public class VariableNeighborhoodSearch {
private static final int MAX_LOCAL_SEARCH_NEIGHBORS = 2; // 从5减少到2,大幅减少解码次数
private void log(String message) {
log(message, LOG_LEVEL_INFO, false);
log(message, LOG_LEVEL_INFO, true);
}
private void log(String message, boolean enableLogging) {
......@@ -107,6 +112,15 @@ public class VariableNeighborhoodSearch {
// 预检查:是否有工序有多个机器选项
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[] strategyTotalCount = new int[4];
......@@ -315,6 +329,10 @@ public class VariableNeighborhoodSearch {
public Chromosome search(Chromosome chromosome, GeneticDecoder decoder, List<Machine> machines) {
log("变邻域搜索 - 开始执行",true);
// 注意:设备选择频率不在这里重置
// 频率在整个优化流程起点(HybridAlgorithm初始化时)调用 initMachineSelectFrequency() 初始化一次
// 这样频率可以跨模拟退火、变邻域搜索、禁忌搜索等所有算法累积,真正鼓励设备选择多样性
// 深拷贝当前染色体
Chromosome current = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
// geneticOperations.DelOrder(current);
......@@ -643,11 +661,71 @@ public class VariableNeighborhoodSearch {
return result;
}
// 找出利用率最高的设备
Long bottleneckMachineId = utilization.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey)
.orElse(null);
// === 频率驱动的瓶颈设备选择 ===
// 不再总是选利用率最高的,而是给利用率高+历史被选次数少的设备更高评分
List<Map.Entry<Long, Double>> machineEntries = new ArrayList<>(utilization.entrySet());
machineEntries.sort((a, b) -> Double.compare(b.getValue(), a.getValue()));
// 取利用率前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("utilization", utilization);
......@@ -1205,54 +1283,65 @@ public class VariableNeighborhoodSearch {
return null;
}
// 优先选择订单数多的优先级的工序
// 构建优先级->订单数的映射
// === 频率驱动的瓶颈工序选择 ===
// 不再只按优先级排序,综合考虑优先级+历史被选次数,鼓励探索不同工序
Map<Double, Set<Integer>> priorityToGroupIds = new HashMap<>();
int maxGroupCount = 1;
for (GAScheduleResult op : candidates) {
Entry entry = entrybyids.get(op.getOperationId());
if (entry != null) {
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);
sortedCandidates.sort((a, b) -> {
Entry entryA = entrybyids.get(a.getOperationId());
Entry entryB = entrybyids.get(b.getOperationId());
// 给每个候选工序计算综合评分
List<Object[]> scoredOps = new ArrayList<>();
int maxOpFreq = 1;
for (GAScheduleResult op : candidates) {
int freq = bottleneckOpFrequency.getOrDefault(op.getOperationId(), 0);
maxOpFreq = Math.max(maxOpFreq, freq);
}
// 统一处理null值:null值排后面
if (entryA == null && entryB == null) return 0;
if (entryA == null) return 1;
if (entryB == null) return -1;
for (GAScheduleResult op : candidates) {
Entry entry = entrybyids.get(op.getOperationId());
if (entry == null) continue;
int sizeA = priorityToGroupIds.getOrDefault(entryA.getPriority(), new HashSet<>()).size();
int sizeB = priorityToGroupIds.getOrDefault(entryB.getPriority(), new HashSet<>()).size();
// 优先级评分:订单数多的优先级组排前面(0~1归一化)
int groupCount = priorityToGroupIds.getOrDefault(entry.getPriority(), new HashSet<>()).size();
double priorityScore = (double) groupCount / maxGroupCount;
// 订单数多的优先级排前面
int sizeCompare = Integer.compare(sizeB, sizeA);
if (sizeCompare != 0) {
return sizeCompare;
// 频率多样性评分(0次→1.0, 次数越多越低)
int freq = bottleneckOpFrequency.getOrDefault(op.getOperationId(), 0);
double diversityScore = 1.0 / (1.0 + freq);
// 综合评分:50% 优先级 + 40% 频率多样性 + 10% 随机
double score = 0.5 * priorityScore + 0.4 * diversityScore + 0.1 * rnd.nextDouble();
scoredOps.add(new Object[]{op, score, groupCount, freq});
}
// 订单数相同时,按优先级排序
return Double.compare(entryA.getPriority(), entryB.getPriority());
});
// 按综合评分降序排序
scoredOps.sort((a, b) -> Double.compare((Double) b[1], (Double) a[1]));
// 70%概率选择前3个候选,30%概率随机选择
// 70%概率选择前3个候选,30%概率在更后面选
GAScheduleResult selectedOp;
if (sortedCandidates.size() <= 3) {
selectedOp = sortedCandidates.get(rnd.nextInt(sortedCandidates.size()));
if (scoredOps.size() <= 3) {
selectedOp = (GAScheduleResult) scoredOps.get(rnd.nextInt(scoredOps.size()))[0];
} else {
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 {
int otherCount = sortedCandidates.size() - 3;
selectedOp = sortedCandidates.get(3 + rnd.nextInt(otherCount));
int otherCount = scoredOps.size() - 3;
selectedOp = (GAScheduleResult) scoredOps.get(3 + rnd.nextInt(otherCount))[0];
}
}
// 更新该工序被选为优化目标的频率
bottleneckOpFrequency.merge(selectedOp.getOperationId(), 1, Integer::sum);
int maPos = -1;
Entry entry= entrybyids.get(selectedOp.getOperationId());
......@@ -1300,15 +1389,22 @@ public class VariableNeighborhoodSearch {
}
/**
* 给指定位置的工序换设备 - 考虑设备负载均衡优化
* 优先选择负载低的设备
* 给指定位置的工序换设备 - 综合考虑设备负载均衡和选择多样性
* 优先选择负载低且选择次数少的设备
*/
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();
if (!ms.isEmpty() && idx >= 0 && idx < ms.size()) {
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);
List<Integer> availableMachines = new ArrayList<>();
for (int i = 1; i <= machineOptions.size(); i++) {
......@@ -1318,10 +1414,14 @@ public class VariableNeighborhoodSearch {
}
if (!availableMachines.isEmpty()) {
// 选择负载较低的设备(设备负载均衡优化)
int newMachineSeq = selectMachineByLoad(availableMachines, machineOptions, chromosome);
// 选择综合考虑负载均衡和选择多样性的设备
int newMachineSeq = selectMachineByLoad(availableMachines, machineOptions, chromosome, opKey);
ms.set(idx, newMachineSeq);
neighbor.setMachineSelection(ms);
// 更新该设备被选择的频率记录
Long selectedMachineId = machineOptions.get(newMachineSeq - 1).getMachineId();
updateMachineSelectFrequency(opKey, selectedMachineId);
}
}
}
......@@ -1402,52 +1502,66 @@ public class VariableNeighborhoodSearch {
.collect(Collectors.toList());
Map<Integer, Integer> orderCompletionTimes = calculateOrderCompletionTimes(allResults);
// 先构建优先级->订单数的映射
// === 频率驱动的瓶颈工序选择(与tryChangeMachineForBottleneckOp相同策略) ===
Map<Double, Set<Integer>> priorityToGroupIds = new HashMap<>();
int maxGroupCount = 1;
for (GAScheduleResult op : bottleneckOps) {
Entry entry = entrybyids.get(op.getOperationId());
if (entry != null) {
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) -> {
Entry entryA = entrybyids.get(a.getOperationId());
Entry entryB = entrybyids.get(b.getOperationId());
// 给每个候选工序计算综合评分
List<Object[]> scoredOps = new ArrayList<>();
for (GAScheduleResult op : bottleneckOps) {
Entry entry = entrybyids.get(op.getOperationId());
if (entry == null) continue;
// 统一处理null值:null值排后面
if (entryA == null && entryB == null) return 0;
if (entryA == null) return 1;
if (entryB == null) return -1;
// 优先级评分(0~1归一化)
int groupCount = priorityToGroupIds.getOrDefault(entry.getPriority(), new HashSet<>()).size();
double priorityScore = (double) groupCount / maxGroupCount;
// 优先按订单数从多到少排序
int sizeA = priorityToGroupIds.getOrDefault(entryA.getPriority(), new HashSet<>()).size();
int sizeB = priorityToGroupIds.getOrDefault(entryB.getPriority(), new HashSet<>()).size();
int sizeCompare = Integer.compare(sizeB, sizeA);
if (sizeCompare != 0) {
return sizeCompare;
// 订单完成时间评分:完成时间越晚,越需要优化(0~1归一化)
int endTime = orderCompletionTimes.getOrDefault(op.getGroupId(), 0);
int maxEndTime = 0;
for (int t : orderCompletionTimes.values()) {
maxEndTime = Math.max(maxEndTime, t);
}
double timeScore = maxEndTime > 0 ? (double) endTime / maxEndTime : 0.5;
// 订单数相同时,按优先级排序
int priorityCompare = Double.compare(entryA.getPriority(), entryB.getPriority());
if (priorityCompare != 0) {
return priorityCompare;
// 频率多样性评分(0次→1.0, 次数越多越低)
int freq = bottleneckOpFrequency.getOrDefault(op.getOperationId(), 0);
double diversityScore = 1.0 / (1.0 + freq);
// 综合评分:35% 优先级 + 25% 时间 + 40% 频率多样性 + 小随机
double score = 0.35 * priorityScore + 0.25 * timeScore + 0.4 * diversityScore + 0.1 * rnd.nextDouble();
scoredOps.add(new Object[]{op, score, freq});
}
// 优先级相同时,按完成时间排序
int endTimeA = orderCompletionTimes.getOrDefault(a.getGroupId(), 0);
int endTimeB = orderCompletionTimes.getOrDefault(b.getGroupId(), 0);
return Integer.compare(endTimeB, endTimeA);
});
// 按综合评分降序排序
scoredOps.sort((a, b) -> Double.compare((Double) b[1], (Double) a[1]));
if (sortedBottleneckOps.isEmpty()) {
if (scoredOps.isEmpty()) {
log("tryMoveBottleneckOpForward: 排序后为空");
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());
if (entry == null) {
......@@ -1922,7 +2036,7 @@ public class VariableNeighborhoodSearch {
*/
private Chromosome generateMachineChangeNeighbor(Chromosome chromosome) {
log("generateMachineChangeNeighbor");
Chromosome neighbor=copyChromosome(chromosome);// ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
Chromosome neighbor=copyChromosome(chromosome);
CopyOnWriteArrayList<Integer> ms = neighbor.getMachineSelection();
if (!ms.isEmpty()) {
int idx = rnd.nextInt(ms.size());
......@@ -1930,6 +2044,9 @@ public class VariableNeighborhoodSearch {
Entry op = globalOp.getOp();
if (op.getMachineOptions().size() > 1) {
// 构建工序唯一键,用于频率跟踪
String opKey = op.getGroupId() + "_" + op.getSequence();
int currentMachineSeq = ms.get(idx);
List<Integer> availableMachines = new ArrayList<>();
List<MachineOption> machineOptions = new ArrayList<>();
......@@ -1941,10 +2058,14 @@ public class VariableNeighborhoodSearch {
}
if (!availableMachines.isEmpty()) {
// 选择负载较低的设备(设备负载均衡优化)
int newMachineSeq = selectMachineByLoad(availableMachines, machineOptions, chromosome);
// 综合考虑负载均衡和选择多样性
int newMachineSeq = selectMachineByLoad(availableMachines, machineOptions, chromosome, opKey);
ms.set(idx, newMachineSeq);
neighbor.setMachineSelection(ms);
// 更新频率记录
Long selectedMachineId = op.getMachineOptions().get(newMachineSeq - 1).getMachineId();
updateMachineSelectFrequency(opKey, selectedMachineId);
}
}
}
......@@ -2343,52 +2464,130 @@ public class VariableNeighborhoodSearch {
/**
* 机器选项和负载信息的辅助类
*/
private static class MachineOptionWithUtilization {
private static class MachineOptionWithScore {
int seq;
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.option = option;
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) {
if(seq - 1>=machineOptions.size())
{
if (seq - 1 >= machineOptions.size()) {
break;
}
MachineOption option = machineOptions.get(seq - 1);
Long machineId = option.getMachineId();
double utilization = machineUtilization.getOrDefault(machineId, 0.0);
availableMachines.add(new MachineOptionWithUtilization(seq, option, utilization));
// 获取该工序对该设备的选择次数
int frequency = 0;
if (opKey != null && opMachineSelectFrequency.containsKey(opKey)) {
frequency = opMachineSelectFrequency.get(opKey).getOrDefault(machineId, 0);
}
// 按利用率从低到高排序
availableMachines.sort(Comparator.comparingDouble(m -> m.utilization));
// 归一化多样性分:选择次数越少,分越高(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;
}
// 70%概率选择负载最低的设备,30%概率随机选择
// 按综合评分降序排序
availableMachines.sort((m1, m2) -> Double.compare(m2.score, m1.score));
// 使用加权轮盘赌选择(70%概率选择得分最高的,30%按评分加权随机
if (rnd.nextDouble() < 0.7) {
return availableMachines.get(0).seq;
} 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 {
* 后续会按场景创建人自动回退到可用的策略配置。
*/
public Chromosome execute2(String SceneId) {
return execute2(SceneId, 2361l, 241l, null);
// return execute2(SceneId, 2321l, 207l, null);
// return execute2(SceneId, 2361l, 241l, null);
return execute2(SceneId, 2321l, 207l, null);
}
......
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