Commit f864f507 authored by Tong Li's avatar Tong Li

优化

parent 6ba23982
......@@ -304,7 +304,7 @@ int opcount=allOperations.size();
best.setScenarioID(sceneId);
// best.setOperatRel(_entryRel);
if(best.getInitMachines()==null)
if(best.getInitMachines()==null||best.getInitMachines().size()==0)
{
best.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines,Machine.class));
}
......
......@@ -19,36 +19,47 @@ import java.util.stream.Collectors;
public class VariableNeighborhoodSearch {
private final Random rnd = new Random();
// ==================== 常量定义 ====================
private static final int MAX_CONSECUTIVE_SAME_STRATEGY = 3;
private static final int MAX_NEIGHBORHOODS = 4; // 优化:从7减少到4个邻域
private static final double HIGH_PRIORITY_GROUP_PROBABILITY = 0.7;
private static final int MAX_ATTEMPTS = 50;
private static final int NEIGHBOR_SELECTION_TOP_K = 3;
private static final int MOVE_STEPS_MIN = 1;
private static final int MOVE_STEPS_MAX = 5;
private static final int NON_BOTTLENECK_MOVE_STEPS_MAX = 3;
private static final int RANDOM_NEIGHBOR_TYPE_COUNT = 5;
private static final double INITIAL_SUCCESS_RATE = 0.3;
private static final double LOW_SUCCESS_RATE_THRESHOLD = 0.1;
private static final int LOW_SUCCESS_RATE_MIN_TRIALS = 10;
private static final double EXPLORATION_BONUS_FOR_LOW_USE = 0.3;
private static final double EXPLORATION_BONUS_FOR_LOW_SUCCESS = 0.2;
private static final double RANDOM_NOISE_FACTOR = 0.15;
private static final double FORCE_ROTATE_PENALTY = 0.5;
private static final double PERCENTILE_90 = 0.90;
private static final double BOTTLENECK_MACHINE_BASE_SCORE = 10000;
private static final double WAIT_TIME_WEIGHT = 30;
private static final double MACHINE_WAIT_TIME_WEIGHT = 30;
private static final double CRITICAL_PATH_WEIGHT_ON_BOTTLENECK = 25;
private static final double CRITICAL_PATH_WEIGHT_OFF_BOTTLENECK = 20;
private static final double DELAY_CONTRIBUTION_WEIGHT_ON_BOTTLENECK = 15;
private static final double DELAY_CONTRIBUTION_WEIGHT_OFF_BOTTLENECK = 10;
private static final double NORMALIZATION_CAP = 1.5;
private static final int TOP_BOTTLENECK_OPS_TO_RETURN = 10;
private static final int TOP_MACHINES_TO_LOG = 5;
private static final double PRIORITY_EPSILON = 0.001;
private static final int MIN_USE_COUNT_FOR_EXPLORATION_BONUS = 5;
// ==================== 策略选择与轮换参数 ====================
private static final int MAX_CONSECUTIVE_SAME_STRATEGY = 4; // 同一策略最多连续使用次数,避免陷入局部最优
private static final int MAX_NEIGHBORHOODS = 4; // 使用的邻域数量(0-3:插单/交换/并行合并/重排)
// ==================== 邻域搜索参数 ====================
private static final double HIGH_PRIORITY_GROUP_PROBABILITY = 0.7; // 优先选择高优先级工单的概率
private static final int MAX_ATTEMPTS = 30; // 每次邻域搜索最大尝试次数,减少无效搜索
private static final int NEIGHBOR_SELECTION_TOP_K = 3; // 每次选择K个候选工序进行操作
// ==================== 工序移动参数 ====================
private static final int MOVE_STEPS_MIN = 1; // 工序移动最小步数
private static final int MOVE_STEPS_MAX = 5; // 工序移动最大步数
private static final int NON_BOTTLENECK_MOVE_STEPS_MAX = 3; // 非瓶颈设备工序移动最大步数
// ==================== 随机邻域参数 ====================
private static final int RANDOM_NEIGHBOR_TYPE_COUNT = 3; // 随机邻域尝试次数
// ==================== 策略成功率评分参数 ====================
private static final double INITIAL_SUCCESS_RATE = 0.3; // 新策略的初始成功率(未使用时的默认值)
private static final double LOW_SUCCESS_RATE_THRESHOLD = 0.1; // 低成功率阈值,低于此值需要额外探索奖励
private static final int LOW_SUCCESS_RATE_MIN_TRIALS = 10; // 低成功率判断的最小尝试次数
private static final double EXPLORATION_BONUS_FOR_LOW_USE = 0.15; // 低使用次数策略的探索奖励分
private static final double EXPLORATION_BONUS_FOR_LOW_SUCCESS = 0.1; // 低成功率策略的探索奖励分
private static final double RANDOM_NOISE_FACTOR = 0.1; // 策略排序时的随机扰动因子,避免陷入局部最优
private static final double FORCE_ROTATE_PENALTY = 0.5; // 强制轮换时的惩罚系数
// ==================== 瓶颈设备评分参数 ====================
private static final double PERCENTILE_90 = 0.90; // 计算瓶颈评分时使用的90分位数,避免极端值影响
private static final double BOTTLENECK_MACHINE_BASE_SCORE = 10000; // 瓶颈设备工序的基础评分,确保排在前面
private static final double WAIT_TIME_WEIGHT = 30; // 工序等待时间在瓶颈评分中的权重
private static final double MACHINE_WAIT_TIME_WEIGHT = 30; // 设备等待时间在瓶颈评分中的权重
private static final double CRITICAL_PATH_WEIGHT_ON_BOTTLENECK = 25; // 关键路径在瓶颈设备评分中的权重
private static final double CRITICAL_PATH_WEIGHT_OFF_BOTTLENECK = 20; // 关键路径在非瓶颈设备评分中的权重
private static final double DELAY_CONTRIBUTION_WEIGHT_ON_BOTTLENECK = 15; // 延迟贡献度在瓶颈设备评分中的权重
private static final double DELAY_CONTRIBUTION_WEIGHT_OFF_BOTTLENECK = 10; // 延迟贡献度在非瓶颈设备评分中的权重
private static final double NORMALIZATION_CAP = 1.5; // 归一化截断值,避免极端值过度影响
// ==================== 日志与输出参数 ====================
private static final int TOP_BOTTLENECK_OPS_TO_RETURN = 10; // 返回的瓶颈工序数量
private static final int TOP_MACHINES_TO_LOG = 5; // 日志输出的设备数量
private static final int MIN_USE_COUNT_FOR_EXPLORATION_BONUS = 5; // 低使用次数判断的最小阈值
// 日志级别
private static final int LOG_LEVEL_DEBUG = 0;
......@@ -729,9 +740,9 @@ public class VariableNeighborhoodSearch {
if (allResults != null && !allResults.isEmpty()) {
List<BottleneckOperationAnalysis> bottleneckAnalyses = analyzeBottleneckOperations(allResults, bottleneckMachineId);
// 输出瓶颈工序TOP 5
log("变邻域搜索 - ===== 瓶颈工序TOP 5 (按瓶颈评分) =====");
for (int i = 0; i < Math.min(5, bottleneckAnalyses.size()); i++) {
// 输出瓶颈工序TOP
log(String.format("变邻域搜索 - ===== 瓶颈工序TOP %d (按瓶颈评分) =====", TOP_MACHINES_TO_LOG));
for (int i = 0; i < Math.min(TOP_MACHINES_TO_LOG, bottleneckAnalyses.size()); i++) {
BottleneckOperationAnalysis boa = bottleneckAnalyses.get(i);
GAScheduleResult op = boa.operation;
log(String.format(
......@@ -745,7 +756,7 @@ public class VariableNeighborhoodSearch {
// 更新关键工序为识别出的瓶颈工序
if (criticalOps != null && !criticalOps.isEmpty() && !bottleneckAnalyses.isEmpty()) {
List<GAScheduleResult> topBottlenecks = bottleneckAnalyses.stream()
.limit(Math.min(10, bottleneckAnalyses.size()))
.limit(Math.min(TOP_BOTTLENECK_OPS_TO_RETURN, bottleneckAnalyses.size()))
.map(boa -> boa.operation)
.collect(Collectors.toList());
analysis.put("criticalOps", topBottlenecks);
......@@ -869,8 +880,8 @@ public class VariableNeighborhoodSearch {
Collections.sort(machineWaitTimes);
// 使用90分位数代替最大值,避免极端值影响
double p90WaitTime = Math.max(1, getPercentile(waitTimes, 0.90)); // 防止0导致NaN
double p90MachineWaitTime = Math.max(1, getPercentile(machineWaitTimes, 0.90)); // 防止0导致NaN
double p90WaitTime = Math.max(1, getPercentile(waitTimes, PERCENTILE_90)); // 防止0导致NaN
double p90MachineWaitTime = Math.max(1, getPercentile(machineWaitTimes, PERCENTILE_90)); // 防止0导致NaN
// 优先找出瓶颈设备上的工序
List<BottleneckOperationAnalysis> bottleneckMachineOps = new ArrayList<>();
......@@ -892,42 +903,42 @@ public class VariableNeighborhoodSearch {
if (isOnBottleneckMachine) {
// 瓶颈设备上的工序:基础分极高,确保排在最前面
score += 10000; // 提高到10000,绝对保证排在前面
score += BOTTLENECK_MACHINE_BASE_SCORE; // 绝对保证排在前面
// 在瓶颈设备工序内部进行排序(使用截断值)
// 工序等待时间 (权重 30%)
double normalizedWaitTime = Math.min(boa.waitTime / p90WaitTime, 1.5);
score += normalizedWaitTime * 30;
// 工序等待时间
double normalizedWaitTime = Math.min(boa.waitTime / p90WaitTime, NORMALIZATION_CAP);
score += normalizedWaitTime * WAIT_TIME_WEIGHT;
// 设备等待时间 (权重 30%)
double normalizedMachineWaitTime = Math.min(boa.machineWaitTime / p90MachineWaitTime, 1.5);
score += normalizedMachineWaitTime * 30;
// 设备等待时间
double normalizedMachineWaitTime = Math.min(boa.machineWaitTime / p90MachineWaitTime, NORMALIZATION_CAP);
score += normalizedMachineWaitTime * MACHINE_WAIT_TIME_WEIGHT;
// 关键路径评分 (权重 25%)
// 关键路径评分
if (boa.onCriticalPath) {
score += 25;
score += CRITICAL_PATH_WEIGHT_ON_BOTTLENECK;
}
// 延迟贡献度评分 (权重 15%)
score += boa.delayContribution * 15;
// 延迟贡献度评分
score += boa.delayContribution * DELAY_CONTRIBUTION_WEIGHT_ON_BOTTLENECK;
} else {
// 非瓶颈设备上的工序:基础分低
score += 0;
// 使用截断值,避免极端值影响
double normalizedMachineWaitTime = Math.min(boa.machineWaitTime / p90MachineWaitTime, 1.5);
score += normalizedMachineWaitTime * 30;
double normalizedMachineWaitTime = Math.min(boa.machineWaitTime / p90MachineWaitTime, NORMALIZATION_CAP);
score += normalizedMachineWaitTime * MACHINE_WAIT_TIME_WEIGHT;
double normalizedWaitTime = Math.min(boa.waitTime / p90WaitTime, 1.5);
score += normalizedWaitTime * 20;
double normalizedWaitTime = Math.min(boa.waitTime / p90WaitTime, NORMALIZATION_CAP);
score += normalizedWaitTime * WAIT_TIME_WEIGHT;
// 关键路径评分 (权重 20%)
// 关键路径评分
if (boa.onCriticalPath) {
score += 20;
score += CRITICAL_PATH_WEIGHT_OFF_BOTTLENECK;
}
// 延迟贡献度评分 (权重 10%)
score += boa.delayContribution * 10;
// 延迟贡献度评分
score += boa.delayContribution * DELAY_CONTRIBUTION_WEIGHT_OFF_BOTTLENECK;
}
boa.bottleneckScore = score;
......@@ -937,12 +948,12 @@ public class VariableNeighborhoodSearch {
log(String.format("变邻域搜索 - 瓶颈设备ID=%d, 其上工序数=%d",
bottleneckMachineId, bottleneckMachineOps.size()));
// 输出各设备工序数量统计(前5个)
// 输出各设备工序数量统计
List<Map.Entry<Long, Long>> topMachinesByCount = machineOpCount.entrySet().stream()
.sorted((a, b) -> Long.compare(b.getValue(), a.getValue()))
.limit(5)
.limit(TOP_MACHINES_TO_LOG)
.collect(Collectors.toList());
StringBuilder machineCountStr = new StringBuilder("变邻域搜索 - 设备工序数(前5): ");
StringBuilder machineCountStr = new StringBuilder(String.format("变邻域搜索 - 设备工序数(前%d): ", TOP_MACHINES_TO_LOG));
for (Map.Entry<Long, Long> entry : topMachinesByCount) {
machineCountStr.append(String.format("[%d:%d] ", entry.getKey(), entry.getValue()));
}
......@@ -983,37 +994,37 @@ public class VariableNeighborhoodSearch {
// 按成功率排序,但加入随机扰动和探索机制
strategies.sort((a, b) -> {
double successRateA = strategyTotalCount[a] > 0 ?
(double) strategySuccessCount[a] / strategyTotalCount[a] : 0.3;
(double) strategySuccessCount[a] / strategyTotalCount[a] : INITIAL_SUCCESS_RATE;
double successRateB = strategyTotalCount[b] > 0 ?
(double) strategySuccessCount[b] / strategyTotalCount[b] : 0.3;
(double) strategySuccessCount[b] / strategyTotalCount[b] : INITIAL_SUCCESS_RATE;
// 强制轮换:给最后使用的策略降权
if (needForceRotate && a == lastUsedStrategy) {
successRateA -= 0.5; // 大幅降权
successRateA -= FORCE_ROTATE_PENALTY; // 大幅降权
}
if (needForceRotate && b == lastUsedStrategy) {
successRateB -= 0.5;
successRateB -= FORCE_ROTATE_PENALTY;
}
// 给使用次数少的策略加分,鼓励探索
if (strategyTotalCount[a] < 5) {
successRateA += 0.3;
if (strategyTotalCount[a] < MIN_USE_COUNT_FOR_EXPLORATION_BONUS) {
successRateA += EXPLORATION_BONUS_FOR_LOW_USE;
}
if (strategyTotalCount[b] < 5) {
successRateB += 0.3;
if (strategyTotalCount[b] < MIN_USE_COUNT_FOR_EXPLORATION_BONUS) {
successRateB += EXPLORATION_BONUS_FOR_LOW_USE;
}
// 如果策略被尝试次数很多但成功率很低,给它额外加分鼓励探索
if (strategyTotalCount[a] > 10 && successRateA < 0.1) {
successRateA += 0.2;
if (strategyTotalCount[a] > LOW_SUCCESS_RATE_MIN_TRIALS && successRateA < LOW_SUCCESS_RATE_THRESHOLD) {
successRateA += EXPLORATION_BONUS_FOR_LOW_SUCCESS;
}
if (strategyTotalCount[b] > 10 && successRateB < 0.1) {
successRateB += 0.2;
if (strategyTotalCount[b] > LOW_SUCCESS_RATE_MIN_TRIALS && successRateB < LOW_SUCCESS_RATE_THRESHOLD) {
successRateB += EXPLORATION_BONUS_FOR_LOW_SUCCESS;
}
// 加入少量随机扰动,避免陷入局部最优
successRateA += rnd.nextDouble() * 0.15;
successRateB += rnd.nextDouble() * 0.15;
successRateA += rnd.nextDouble() * RANDOM_NOISE_FACTOR;
successRateB += rnd.nextDouble() * RANDOM_NOISE_FACTOR;
return Double.compare(successRateB, successRateA);
});
......@@ -2040,7 +2051,6 @@ public class VariableNeighborhoodSearch {
} else {
chromosome.setResultOld(new CopyOnWriteArrayList<>());
}
//decoder.decodeChromosomeWithCache(chromosome,true);
});
log(String.format("变邻域搜索 -复制对象E"));
......
......@@ -40,7 +40,7 @@ public class PlanResultServiceTest {
// sortService.test1();
// nsgaiiUtils.Test();
planResultService.execute2("F6747C64865D4609989D943709939331");//2000
planResultService.execute2("E29F2B3ADA8149F6B916B5119296A92B");//2000
// planResultService.execute2("08B1D87FE1B84ECDBAC2E546DDB6FB81");//2000
// planResultService.execute2("0428340BB4F540938F1FB5599F03E8A4");//5000
......
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