Commit 111874b6 authored by Tong Li's avatar Tong Li

优化

parent 40085732
......@@ -45,6 +45,16 @@ public class RedisUtils {
@Getter
public static String prefix = "aps:";
/**
* 最大重试次数
*/
private static final int MAX_RETRY_TIMES = 3;
/**
* 重试间隔(毫秒)
*/
private static final long RETRY_DELAY_MS = 500;
/**
* 设置redis前缀进行操作
*
......@@ -62,7 +72,7 @@ public class RedisUtils {
* @return: boolean
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(prefix + key);
return executeWithRetry(() -> redisTemplate.hasKey(prefix + key), "exists(" + key + ")");
}
public Set<String> keys(final String pattern) {
......@@ -164,6 +174,7 @@ public class RedisUtils {
* @param key 可以传一个值 或多个
*/
public void del(String... key) {
executeWithRetry(() -> {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(prefix + key[0]);
......@@ -171,6 +182,7 @@ public class RedisUtils {
redisTemplate.delete(Arrays.asList(key).stream().map(e -> prefix + e).collect(Collectors.toList()));
}
}
}, "del(" + Arrays.toString(key) + ")");
}
public void del(Collection<String> keys) {
......@@ -184,7 +196,7 @@ public class RedisUtils {
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(prefix + key);
return executeWithRetry(() -> key == null ? null : redisTemplate.opsForValue().get(prefix + key), "get(" + key + ")");
}
/**
......@@ -207,6 +219,7 @@ public class RedisUtils {
* @return true成功 false失败
*/
public Boolean set(String key, Object value) {
return executeWithRetry(() -> {
try {
redisTemplate.opsForValue().set(prefix + key, value);
return true;
......@@ -214,6 +227,7 @@ public class RedisUtils {
log.error("Exception: {}", e.getMessage());
return false;
}
}, "set(" + key + ")");
}
/**
......@@ -814,4 +828,120 @@ public class RedisUtils {
redisLockUtil.releaseLock(prefix + key, "");
}
/**
* 通用重试执行器:用于处理 Redis 连接异常
* @param operation Redis 操作函数
* @param operationName 操作名称(用于日志)
* @param <T> 返回值类型
* @return 操作结果
*/
private <T> T executeWithRetry(java.util.function.Supplier<T> operation, String operationName) {
Exception lastException = null;
for (int attempt = 1; attempt <= MAX_RETRY_TIMES; attempt++) {
try {
if (attempt > 1) {
log.warn("Redis 操作重试 {}/{}: {}", attempt, MAX_RETRY_TIMES, operationName);
}
return operation.get();
} catch (Exception e) {
lastException = e;
log.error("Redis 操作失败 {}/{}: {}, 错误: {}", attempt, MAX_RETRY_TIMES, operationName, e.getMessage());
if (attempt < MAX_RETRY_TIMES) {
try {
log.warn("等待 {}ms 后重试...", RETRY_DELAY_MS);
Thread.sleep(RETRY_DELAY_MS);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException("Redis 操作重试被中断", ie);
}
}
}
}
throw new RuntimeException("Redis 操作失败,已重试 " + MAX_RETRY_TIMES + " 次: " + operationName, lastException);
}
/**
* 无返回值的重试执行器
* @param operation Redis 操作函数
* @param operationName 操作名称(用于日志)
*/
private void executeWithRetry(Runnable operation, String operationName) {
executeWithRetry(() -> {
operation.run();
return null;
}, operationName);
}
// ==================== 以下是添加了重试机制的方法 ====================
/**
* 判断是否有这个缓存key(带重试)
* @param key 缓存key
* @return boolean
*/
public boolean existsWithRetry(final String key) {
return executeWithRetry(() -> exists(key), "exists(" + key + ")");
}
/**
* 普通缓存获取(带重试)
* @param key 键
* @return 值
*/
public Object getWithRetry(String key) {
return executeWithRetry(() -> get(key), "get(" + key + ")");
}
/**
* 普通缓存放入(带重试)
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public Boolean setWithRetry(String key, Object value) {
return executeWithRetry(() -> set(key, value), "set(" + key + ")");
}
/**
* 普通缓存放入并设置时间(带重试)
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return true成功 false失败
*/
public Boolean setWithRetry(String key, Object value, Long time) {
return executeWithRetry(() -> set(key, value, time), "set(" + key + ", " + time + "s)");
}
/**
* 删除缓存(带重试)
* @param key 可以传一个值 或多个
*/
public void delWithRetry(String... key) {
executeWithRetry(() -> del(key), "del(" + Arrays.toString(key) + ")");
}
/**
* HashGet(带重试)
* @param key 键 不能为 null
* @param item 项 不能为 null
* @return 值
*/
public Object hgetWithRetry(String key, String item) {
return executeWithRetry(() -> hget(key, item), "hget(" + key + ", " + item + ")");
}
/**
* HashSet(带重试)
* @param key 键
* @param map 对应多个键值
* @return true成功 false失败
*/
public Boolean hmsetWithRetry(String key, Map<String, Object> map) {
return executeWithRetry(() -> hmset(key, map), "hmset(" + key + ")");
}
}
......@@ -116,53 +116,53 @@ public class Chromosome {
private List<GlobalOperationInfo> globalOpList;
private CopyOnWriteArrayList<Entry> allOperations;
private CopyOnWriteArrayList<Order> orders;
private List<Machine> InitMachines;
private List<GlobalOperationInfo> globalOpList = new ArrayList<>();
private CopyOnWriteArrayList<Entry> allOperations = new CopyOnWriteArrayList<>();
private CopyOnWriteArrayList<Order> orders = new CopyOnWriteArrayList<>();
private List<Machine> InitMachines = new ArrayList<>();
private List<OrderMaterialRequirement> orderMaterials;
private List<OrderMaterialRequirement> orderMaterials = new ArrayList<>();
private CopyOnWriteArrayList<GroupResult> OperatRel;
private CopyOnWriteArrayList<GroupResult> OperatRel = new CopyOnWriteArrayList<>();
private ObjectiveWeights objectiveWeights;
private List<Material> materials;
private List<Material> materials = new ArrayList<>();
private List<String> materialIds;
private List<String> materialIds = new ArrayList<>();
/*
* 最早完工时间(最小化) 最小化总加工时间 最小总换型时间
*/
private double[] Objectives ; // 多目标值:[Makespan, TotalFlowTime, TotalChangeover, LoadStd, Delay]
private double[] MaxObjectives ; //
private double[] MinObjectives ; //
private double[] Objectives = new double[0]; // 多目标值:[Makespan, TotalFlowTime, TotalChangeover, LoadStd, Delay]
private double[] MaxObjectives = new double[0]; //
private double[] MinObjectives = new double[0]; //
private int Rank; // 非支配排序等级(1最优)
private double CrowdingDistance =0; // 拥挤距离 越小越优
/*
*(Objectives - min) / (max - min);
*/
private double[] WeightedObjectives;//越靠近1越优
private double[] WeightedObjectives = new double[0];//越靠近1越优
private double WeightedObjective =0; // 加权目标值(用于自定义权重)
/// <summary>
/// 适应度值
/// </summary>
private double[] fitnessLevel;
private double[] fitnessLevel = new double[0];
/// <summary>
/// 适应度值
/// </summary>
private double Fitness;
private double Fitness = 0.0;
/// <summary>
/// 机器
/// </summary>
private List<Machine> Machines;
private List<Machine> Machines = new ArrayList<>();
/// <summary>
/// 解码后的调度结果
/// </summary>
private CopyOnWriteArrayList<GAScheduleResult> Result;
private CopyOnWriteArrayList<GAScheduleResult> Result = new CopyOnWriteArrayList<>();
/// <summary>
/// 解码后的调度结果
......@@ -172,33 +172,33 @@ public class Chromosome {
/// <summary>
/// 最早完工时间
/// </summary>
private double Makespan;
private double Makespan = 0.0;
/// <summary>
/// 总流程时间
/// </summary>
private double TotalFlowTime;
private double TotalFlowTime = 0.0;
/// <summary>
/// 总换型时间
/// </summary>
private double TotalChangeoverTime;
private double TotalChangeoverTime = 0.0;
/// <summary>
/// 机器负载标准差(越小越均衡)
/// </summary>
private double MachineLoadStd;
private double MachineLoadStd = 0.0;
/// <summary>
/// 交付期延迟时间
/// </summary>
private double DelayTime;
private double DelayTime = 0.0;
private String ScenarioID;
private String ScenarioID = "";
private String ScenarioName;
private LocalDateTime BaseTime ; // 当前基准时间
private String ScenarioName = "";
private LocalDateTime BaseTime; // 当前基准时间
private List<Integer> reOrderids=new ArrayList<>();
......
......@@ -165,15 +165,30 @@ public class FitnessCalculator {
* 比较两个染色体的优劣(基于fitnessLevel多层次比较)
*/
public boolean isBetter(Chromosome c1, Chromosome c2) {
for (int i = 0; i < c1.getFitnessLevel().length; i++) {
double[] Fitness1 = c1.getFitnessLevel();
double[] Fitness2 = c2.getFitnessLevel();
if (Fitness1[i] > Fitness2[i]) {
return true;
double[] fitness1 = c1.getFitnessLevel();
double[] fitness2 = c2.getFitnessLevel();
// 处理null或空数组的情况
if (fitness1 == null || fitness1.length == 0) {
return false; // c1没有fitness,认为c2更优
}
if (fitness2 == null || fitness2.length == 0) {
return true; // c2没有fitness,认为c1更优
}
// 取两个数组中较小的长度进行比较
int minLength = Math.min(fitness1.length, fitness2.length);
for (int i = 0; i < minLength; i++) {
if (fitness1[i] > fitness2[i]) {
return true;
} else if (fitness1[i] < fitness2[i]) {
return false;
}
}
// 如果前面都相等,长度更长的视为更优(有更多维度)
return fitness1.length > fitness2.length;
}
......
......@@ -193,7 +193,8 @@ public class GeneticDecoder {
// 缓存命中:复用缓存结果
// 赋值给染色体
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(cachedResult.getInitMachines(),Machine.class));
chromosome.setFitnessLevel(cachedResult.getFitnessLevel());
chromosome.setFitness(cachedResult.getFitness());
chromosome.setObjectives(cachedResult.getObjectives());
chromosome.setMakespan(cachedResult.getMakespan());
chromosome.setTotalFlowTime(cachedResult.getTotalFlowTime());
......
......@@ -643,16 +643,29 @@ public class HillClimbing {
/**
* 比较两个染色体的优劣
*/
private boolean isBetter(Chromosome c1, Chromosome c2) {
public boolean isBetter(Chromosome c1, Chromosome c2) {
double[] fitness1 = c1.getFitnessLevel();
double[] fitness2 = c2.getFitnessLevel();
for (int i = 0; i < c1.getFitnessLevel().length; i++) {
double[] Fitness1 = c1.getFitnessLevel();
double[] Fitness2 = c2.getFitnessLevel();
if (Fitness1[i] > Fitness2[i]) {
return true;
// 处理null或空数组的情况
if (fitness1 == null || fitness1.length == 0) {
return false; // c1没有fitness,认为c2更优
}
if (fitness2 == null || fitness2.length == 0) {
return true; // c2没有fitness,认为c1更优
}
// 取两个数组中较小的长度进行比较
int minLength = Math.min(fitness1.length, fitness2.length);
for (int i = 0; i < minLength; i++) {
if (fitness1[i] > fitness2[i]) {
return true;
} else if (fitness1[i] < fitness2[i]) {
return false;
}
}
// 如果前面都相等,长度更长的视为更优(有更多维度)
return fitness1.length > fitness2.length;
}
}
\ No newline at end of file
......@@ -104,7 +104,7 @@ public class HybridAlgorithm {
GeneticOperations geneticOps = new GeneticOperations(_GlobalParam,allOperations,param);
int opcount=allOperations.size();
// 预生成全局工序列表(所有初始化方法共享同一顺序)
List<GlobalOperationInfo> globalOpList = initialization.generateGlobalOpList();
List<GlobalOperationInfo> globalOpList =new ArrayList<>();// initialization.generateGlobalOpList();
// 初始化变邻域搜索
_vns = new VariableNeighborhoodSearch( allOperations,orders,materials,_entryRel, _fitnessCalculator );
_hillClimbing = new HillClimbing(allOperations,orders,materials,_entryRel, _fitnessCalculator);
......@@ -137,11 +137,13 @@ int opcount=allOperations.size();
// return getBestChromosome(population.get(0), param.getBaseTime(), starttime);
// 步骤2:对初始种群进行爬山法局部优化
if(opcount<20 ) {
if(opcount<100 ) {
Chromosome best=population.get(0);
geneticOps.DelOrder(best);
FileHelper.writeLogFile("爬山法局部优化-----------开始-------");
GeneticDecoder hillClimbingDecoder = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler, materialRequirementService, sceneId);
Chromosome optimized = _hillClimbing.search(population.get(0), hillClimbingDecoder,machines);
Chromosome optimized = _hillClimbing.searchAll(best,machines,hillClimbingDecoder);
FileHelper.writeLogFile("爬山法局部优化-----------结束-------");
return getBestChromosome(optimized, param.getBaseTime(), starttime);
}
......@@ -158,14 +160,17 @@ int opcount=allOperations.size();
if(opcount<800 ) {
Chromosome best=population.get(0);
geneticOps.DelOrder(best);
FileHelper.writeLogFile("模拟退火+爬山法优化-----------开始-------");
Chromosome saHcOptimized = _simulatedAnnealing.searchWithHillClimbing(population.get(0),_vns, saDecoder1, machines);
Chromosome saHcOptimized = _simulatedAnnealing.searchWithHillClimbing(best,_vns, saDecoder1, machines);
FileHelper.writeLogFile("模拟退火+爬山法优化-----------结束-------");
return getBestChromosome(saHcOptimized, param.getBaseTime(), starttime);
}
if(opcount>=800 ) {
Chromosome best=population.get(0);
geneticOps.DelOrder(best);
best = _simulatedAnnealing.search(best, _tabuSearch, _vns, saDecoder1, machines);
best = _vns.search(best, vnsDecoder1, machines);
best = _tabuSearch.search(best, _vns, tabuDecoder1, machines);
......@@ -194,6 +199,7 @@ int opcount=allOperations.size();
int maxNoImprove = 10;
// 步骤2:迭代进化
FileHelper.writeLogFile("迭代进化-----------开始-------"+param.getMaxIterations());
for (int iter = 0; iter < param.getMaxIterations(); iter++) {
// 解码并计算适应度
FileHelper.writeLogFile("迭代进化------"+iter+"-----开始-------");
......@@ -212,7 +218,7 @@ int opcount=allOperations.size();
FileHelper.writeLogFile("选择操作-----------开始-------");
// 选择操作
List<Chromosome> selected = geneticOps.tournamentSelection(population);
List<Chromosome> selected = geneticOps.tournamentSelection2(population);
FileHelper.writeLogFile("选择操作-----------结束-------");
......@@ -230,13 +236,13 @@ int opcount=allOperations.size();
Chromosome parent2 = selected.get(rnd.nextInt(selected.size()));
// 交叉
Chromosome child = parent1;
// if (rnd.nextDouble() < param.getCrossoverProb()) {
// // 假设PoxCrossover返回包含两个子染色体的数组
// Pair<Chromosome, Chromosome> children = geneticOps.poxCrossover(parent1, parent2, ordercount);
// child=children.getFirst();
// initDataToChromosome(child,param, allOperations,globalOpList);
// child.setID(UUID.randomUUID().toString());
// }
if (rnd.nextDouble() < param.getCrossoverProb()) {
// 假设PoxCrossover返回包含两个子染色体的数组
Pair<Chromosome, Chromosome> children = geneticOps.poxCrossover(parent1, parent2, ordercount);
child=children.getFirst();
// initDataToChromosome(child,param, allOperations,globalOpList);
child.setID(UUID.randomUUID().toString());
}
// // 变异
// if (rnd.nextDouble() < param.getMutationProb()) {
// geneticOps.mutate(child, globalOpList);
......@@ -249,7 +255,7 @@ int opcount=allOperations.size();
newPopulation.add(child);
FileHelper.writeLogFile("交叉-----------结束-------"+n);
n++;
}
population= chromosomeDistinctByObjectives(newPopulation);;
......@@ -375,14 +381,7 @@ int opcount=allOperations.size();
* 比较两个染色体的优劣(基于fitnessLevel多层次比较)
*/
private boolean isBetter(Chromosome c1, Chromosome c2) {
for (int i = 0; i < c1.getFitnessLevel().length; i++) {
double[] Fitness1 = c1.getFitnessLevel();
double[] Fitness2 = c2.getFitnessLevel();
if (Fitness1[i] > Fitness2[i]) {
return true;
}
}
return false;
return _fitnessCalculator.isBetter(c1,c2);
}
......
......@@ -149,10 +149,13 @@ public class MaterialRequirementService {
if(MaterialRequirements!=null)
{
List<Entry> Operations= _allOperations.stream()
List<Entry> Operations= _allOperations.stream().filter(t -> t.getOrderId() != null)
.filter(t->t.getOrderId().equals(orderId))
.collect(Collectors.toList());
if(Operations==null)
{
int i=1;
}
for (Entry operation : Operations) {
List<Routingsupporting> MaterialRequirement_entrys = routingsupportings.stream()
.filter(t -> t.getRoutingDetailId().equals(operation.getRoutingDetailId()))
......@@ -524,7 +527,10 @@ public class MaterialRequirementService {
for (Integer groupId : operationSequencing)
{
Order demand=orders.stream().filter(t->t.getId()==groupId).findFirst().orElse(null);
if(demand==null)
{
continue;
}
if (demand.getFinishOrderId() != null && !demand.getFinishOrderId().isEmpty()) {
continue;
}
......@@ -606,7 +612,7 @@ public class MaterialRequirementService {
List<Entry> _allOperations= chromosome.getAllOperations();
List<Entry> Operations= _allOperations.stream()
List<Entry> Operations= _allOperations.stream().filter(t -> t.getOrderId() != null)
.filter(t->t.getOrderId().equals(childorderId))
.collect(Collectors.toList());
......
......@@ -232,6 +232,7 @@ public class RoutingDataService {
entry.setProductCode(order.getMaterialCode());
entry.setProductName(order.getMaterialName());
entry.setPriority(order.getActualPriority());
order.setId(entry.getGroupId());
}
List<ProdEquipment> Equipments = ProdEquipments.stream()
......
......@@ -106,13 +106,13 @@ public class SimulatedAnnealing {
// log("模拟退火+爬山法 - 初始化解码完成");
// 初始化温度
// 初始化温度(优化:更快收敛)
double temperature = 100.0;
double coolingRate = 0.95;
double temperatureThreshold = 1.0;
int maxIterations = 300;
double coolingRate = 0.90; // 优化:降温更快
double temperatureThreshold = 5.0; // 优化:温度阈值更高
int maxIterations = 100; // 优化:从300减少到100次
int noImproveCount = 0;
int maxNoImprove = 30; // 降低最大无改进次数
int maxNoImprove = 15; // 优化:从30减少到15次
// 新增:改进率监控参数
int stagnantWindow = 15; // 观察窗口大小
......@@ -239,13 +239,13 @@ public class SimulatedAnnealing {
// log("模拟退火+爬山法 - 初始化解码完成");
// 初始化温度
// 初始化温度(优化:更快收敛)
double temperature = 100.0;
double coolingRate = 0.95;
double temperatureThreshold = 1.0;
int maxIterations = 300;
double coolingRate = 0.90; // 优化:降温更快
double temperatureThreshold = 5.0; // 优化:温度阈值更高
int maxIterations = 80; // 优化:从300减少到80次
int noImproveCount = 0;
int maxNoImprove = 20; // 降低最大无改进次数,更快提前结束
int maxNoImprove = 10; // 优化:从20减少到10次
// 新增:改进率监控参数
int stagnantWindow = 10; // 观察窗口大小
......@@ -361,10 +361,17 @@ public class SimulatedAnnealing {
StringBuilder sb = new StringBuilder("模拟退火 - 改进详情: 迭代" + iteration + ", ");
double[] currentFitness = best.getFitnessLevel();
for (int i = 0; i < currentFitness.length; i++) {
// 处理null或空数组的情况
if (currentFitness != null && currentFitness.length > 0 &&
initialFitnessLevel != null && initialFitnessLevel.length > 0) {
int minLength = Math.min(currentFitness.length, initialFitnessLevel.length);
for (int i = 0; i < minLength; i++) {
double improvement = currentFitness[i] - initialFitnessLevel[i];
sb.append(String.format("KPI%d: %.4f→%.4f(+%.4f) ", i+1, initialFitnessLevel[i], currentFitness[i], improvement));
}
} else {
sb.append("(KPI数据不可用) ");
}
double totalImprovement = best.getFitness() - initialFitness;
sb.append(String.format("总Fitness: %.4f→%.4f(+%.4f)", initialFitness, best.getFitness(), totalImprovement));
......@@ -392,11 +399,18 @@ public class SimulatedAnnealing {
sb.append(String.format("总迭代%d次, 成功改进%d次, 改进率%.2f%%. ",
totalIterations, improveCount, totalIterations > 0 ? (double)improveCount / totalIterations * 100 : 0));
for (int i = 0; i < currentFitness.length; i++) {
// 处理null或空数组的情况
if (currentFitness != null && currentFitness.length > 0 &&
initialFitnessLevel != null && initialFitnessLevel.length > 0) {
int minLength = Math.min(currentFitness.length, initialFitnessLevel.length);
for (int i = 0; i < minLength; i++) {
double improvement = currentFitness[i] - initialFitnessLevel[i];
sb.append(String.format("KPI%d: %.4f→%.4f(%.2f%%) ", i+1, initialFitnessLevel[i], currentFitness[i],
initialFitnessLevel[i] > 0 ? improvement / initialFitnessLevel[i] * 100 : 0));
}
} else {
sb.append("(KPI数据不可用) ");
}
double totalImprovement = best.getFitness() - initialFitness;
sb.append(String.format("总Fitness: %.4f→%.4f(%.2f%%)", initialFitness, best.getFitness(),
......@@ -408,10 +422,13 @@ public class SimulatedAnnealing {
private void writeKpi(Chromosome chromosome) {
String fitness = "";
double[] fitness1 = chromosome.getFitnessLevel();
if (fitness1 != null) {
for (int i = 0; i < fitness1.length; i++) {
fitness += fitness1[i] + ",";
}
} else {
fitness = "null (未计算)";
}
log(String.format("模拟退火 - kpi:%s", fitness),true);
......
......@@ -65,7 +65,7 @@ public class TabuSearch {
Chromosome current = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
Chromosome best = ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
this.bestFitness = best.getFitnessLevel().clone();
writeKpi(best);
writeKpi(best);
// 记录初始KPI用于计算改进率
double[] initialFitnessLevel = best.getFitnessLevel().clone();
double initialFitness = best.getFitness();
......@@ -73,8 +73,8 @@ writeKpi(best);
int iterations = 0;
int improveCount = 0;
int noImprovementCount = 0;
int maxNoImprovement = 15; // 降低到15次无改进则停止
int maxIterations = Math.min(cachedAllOperations.size(), 80); // 降低到最多80次
int maxNoImprovement = 5; // 优化:5次无改进则停止
int maxIterations = Math.min(cachedAllOperations.size(), 20); // 优化:最多20次迭代
// 改进率监控
int stagnantWindow = 10;
......@@ -213,12 +213,15 @@ writeKpi(best);
private void writeKpi(Chromosome chromosome) {
String fitness = "";
double[] fitness1 = chromosome.getFitnessLevel();
if (fitness1 != null) {
for (int i = 0; i < fitness1.length; i++) {
fitness += fitness1[i] + ",";
}
} else {
fitness = "null (未计算)";
}
log(String.format("变邻域搜索 - kpi:%s", fitness),true);
log(String.format("禁忌搜索 - kpi:%s", fitness),true);
}
/**
......@@ -228,10 +231,17 @@ writeKpi(best);
StringBuilder sb = new StringBuilder("禁忌搜索 - 改进详情: 迭代" + iteration + ", ");
double[] currentFitness = best.getFitnessLevel();
for (int i = 0; i < currentFitness.length; i++) {
// 处理null或空数组的情况
if (currentFitness != null && currentFitness.length > 0 &&
initialFitnessLevel != null && initialFitnessLevel.length > 0) {
int minLength = Math.min(currentFitness.length, initialFitnessLevel.length);
for (int i = 0; i < minLength; i++) {
double improvement = currentFitness[i] - initialFitnessLevel[i];
sb.append(String.format("KPI%d: %.4f→%.4f(+%.4f) ", i+1, initialFitnessLevel[i], currentFitness[i], improvement));
}
} else {
sb.append("(KPI数据不可用) ");
}
double totalImprovement = best.getFitness() - initialFitness;
sb.append(String.format("总Fitness: %.4f→%.4f(+%.4f)", initialFitness, best.getFitness(), totalImprovement));
......@@ -260,11 +270,18 @@ writeKpi(best);
sb.append(String.format("总迭代%d次, 成功改进%d次, 改进率%.2f%%. ",
totalIterations, improveCount, totalIterations > 0 ? (double)improveCount / totalIterations * 100 : 0));
for (int i = 0; i < currentFitness.length; i++) {
// 处理null或空数组的情况
if (currentFitness != null && currentFitness.length > 0 &&
initialFitnessLevel != null && initialFitnessLevel.length > 0) {
int minLength = Math.min(currentFitness.length, initialFitnessLevel.length);
for (int i = 0; i < minLength; i++) {
double improvement = currentFitness[i] - initialFitnessLevel[i];
sb.append(String.format("KPI%d: %.4f→%.4f(%.2f%%) ", i+1, initialFitnessLevel[i], currentFitness[i],
initialFitnessLevel[i] > 0 ? improvement / initialFitnessLevel[i] * 100 : 0));
}
} else {
sb.append("(KPI数据不可用) ");
}
double totalImprovement = best.getFitness() - initialFitness;
sb.append(String.format("总Fitness: %.4f→%.4f(%.2f%%)", initialFitness, best.getFitness(),
......
......@@ -21,7 +21,7 @@ public class VariableNeighborhoodSearch {
// ==================== 常量定义 ====================
private static final int MAX_CONSECUTIVE_SAME_STRATEGY = 3;
private static final int MAX_NEIGHBORHOODS = 7;
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;
......@@ -378,10 +378,17 @@ public class VariableNeighborhoodSearch {
StringBuilder sb = new StringBuilder("变邻域搜索 - 改进详情: 轮次" + round + ", 邻域=" + neighborhoodName + ", ");
double[] currentFitness = best.getFitnessLevel();
for (int i = 0; i < currentFitness.length; i++) {
// 处理null或空数组的情况
if (currentFitness != null && currentFitness.length > 0 &&
initialFitnessLevel != null && initialFitnessLevel.length > 0) {
int minLength = Math.min(currentFitness.length, initialFitnessLevel.length);
for (int i = 0; i < minLength; i++) {
double improvement = currentFitness[i] - initialFitnessLevel[i];
sb.append(String.format("KPI%d: %.4f→%.4f(+%.4f) ", i+1, initialFitnessLevel[i], currentFitness[i], improvement));
}
} else {
sb.append("(KPI数据不可用) ");
}
double totalImprovement = best.getFitness() - initialFitness;
sb.append(String.format("总Fitness: %.4f→%.4f(+%.4f)", initialFitness, best.getFitness(), totalImprovement));
......@@ -409,11 +416,17 @@ public class VariableNeighborhoodSearch {
sb.append("\n");
// 记录KPI改进
for (int i = 0; i < currentFitness.length; i++) {
if (currentFitness != null && currentFitness.length > 0 &&
initialFitnessLevel != null && initialFitnessLevel.length > 0) {
int minLength = Math.min(currentFitness.length, initialFitnessLevel.length);
for (int i = 0; i < minLength; i++) {
double improvement = currentFitness[i] - initialFitnessLevel[i];
sb.append(String.format("KPI%d: %.4f→%.4f(%.2f%%) ", i+1, initialFitnessLevel[i], currentFitness[i],
initialFitnessLevel[i] > 0 ? improvement / initialFitnessLevel[i] * 100 : 0));
}
} else {
sb.append("(KPI数据不可用) ");
}
double totalImprovement = best.getFitness() - initialFitness;
sb.append(String.format("总Fitness: %.4f→%.4f(%.2f%%)", initialFitness, best.getFitness(),
......@@ -424,10 +437,13 @@ public class VariableNeighborhoodSearch {
private void writeKpi(Chromosome chromosome) {
String fitness = "";
double[] fitness1 = chromosome.getFitnessLevel();
if (fitness1 != null) {
for (int i = 0; i < fitness1.length; i++) {
fitness += fitness1[i] + ",";
}
} else {
fitness = "null (未计算)";
}
log(String.format("变邻域搜索 - kpi:%s", fitness),true);
......@@ -2024,6 +2040,7 @@ public class VariableNeighborhoodSearch {
} else {
chromosome.setResultOld(new CopyOnWriteArrayList<>());
}
//decoder.decodeChromosomeWithCache(chromosome,true);
});
log(String.format("变邻域搜索 -复制对象E"));
......
......@@ -39,8 +39,11 @@ public class PlanResultServiceTest {
// TestSortService sortService=new TestSortService();
// sortService.test1();
// nsgaiiUtils.Test();
planResultService.execute2("08B1D87FE1B84ECDBAC2E546DDB6FB81");//2000
// planResultService.execute2("0428340BB4F540938F1FB5599F03E8A4");//2000
planResultService.execute2("F6747C64865D4609989D943709939331");//2000
// planResultService.execute2("08B1D87FE1B84ECDBAC2E546DDB6FB81");//2000
// planResultService.execute2("0428340BB4F540938F1FB5599F03E8A4");//5000
// planResultService.execute2("C8B533BD8944405B9A2F8823C575C204");//500
// planResultService.execute2("EFDD34E4B5BC434BAEAE6A84DFCD4E7B");//20
// planResultService.execute2("00E0C5D3E4AD4F36B56C39395906618D");
......
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