Commit f081f29e authored by Tong Li's avatar Tong Li

Merge remote-tracking branch 'origin/tl'

parents 99817cb4 34d7e700
...@@ -20,8 +20,8 @@ public class ScheduleParams { ...@@ -20,8 +20,8 @@ public class ScheduleParams {
private static final int MAX_MAX_ITERATIONS = 200; private static final int MAX_MAX_ITERATIONS = 200;
private static final float MIN_CROSSOVER_PROB = 0.6f; private static final float MIN_CROSSOVER_PROB = 0.6f;
private static final float MAX_CROSSOVER_PROB = 0.9f; private static final float MAX_CROSSOVER_PROB = 0.9f;
private static final float MIN_MUTATION_PROB = 0.3f; private static final float MIN_MUTATION_PROB = 0.2f;
private static final float MAX_MUTATION_PROB = 0.7f; private static final float MAX_MUTATION_PROB = 0.5f;
private static final int MIN_TOURNAMENT_SIZE = 3; private static final int MIN_TOURNAMENT_SIZE = 3;
private static final int MAX_TOURNAMENT_SIZE = 7; private static final int MAX_TOURNAMENT_SIZE = 7;
...@@ -81,6 +81,13 @@ public class ScheduleParams { ...@@ -81,6 +81,13 @@ public class ScheduleParams {
return maxIterations; return maxIterations;
} }
/// <summary>
/// 交叉概率
/// </summary>
public float setCrossoverProb(float crossoverProb) {
return this.crossoverProb=crossoverProb;
}
/// <summary> /// <summary>
/// 交叉概率 /// 交叉概率
/// </summary> /// </summary>
...@@ -235,6 +242,26 @@ public class ScheduleParams { ...@@ -235,6 +242,26 @@ public class ScheduleParams {
} }
} }
public void fineTuneParams() {
// 适应度标准差阈值(可调整):小于0.05视为收敛过慢,大于0.2视为收敛过快
final float LOW_STD_THRESHOLD = 0.05f;
final float HIGH_STD_THRESHOLD = 0.2f;
final float ADJUST_STEP = 0.05f; // 调整步长
DecimalFormat df = new DecimalFormat("#.000");
// 1. 收敛过慢(适应度方差小):增加变异概率,降低交叉概率
mutationProb = Math.max(MIN_MUTATION_PROB,
Math.min(MAX_MUTATION_PROB, mutationProb + 0.05f));
crossoverProb = Math.max(MIN_CROSSOVER_PROB,
Math.min(MAX_CROSSOVER_PROB, crossoverProb - 0.1f));
}
// 测试示例 // 测试示例
public void test() { public void test() {
ScheduleParams params = new ScheduleParams(); ScheduleParams params = new ScheduleParams();
......
package com.aps.entity.Algorithm; package com.aps.entity.Algorithm;
import com.aps.entity.basic.TimeSegment;
import lombok.Data; import lombok.Data;
import java.util.List;
/** /**
* 作者:佟礼 * 作者:佟礼
* 时间:2025-11-21 * 时间:2025-11-21
...@@ -14,6 +17,9 @@ public class ScheduleResultDetail { ...@@ -14,6 +17,9 @@ public class ScheduleResultDetail {
private double OneTime; // 单件工时 private double OneTime; // 单件工时
private double Quantity; // 时间段 private double Quantity; // 时间段
private List<TimeSegment> usedSegment;
// Key 的 getter/setter // Key 的 getter/setter
public String getKey() { public String getKey() {
return Key; return Key;
......
...@@ -13,6 +13,9 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -13,6 +13,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.*; import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
...@@ -98,7 +101,7 @@ public class GeneticAlgorithm { ...@@ -98,7 +101,7 @@ public class GeneticAlgorithm {
List<Chromosome> population = initialization.generateInitialPopulation(param, globalOpList); List<Chromosome> population = initialization.generateInitialPopulation(param, globalOpList);
//population= chromosomeDistinct(population); population= chromosomeDistinct(population);
...@@ -137,8 +140,14 @@ public class GeneticAlgorithm { ...@@ -137,8 +140,14 @@ public class GeneticAlgorithm {
} }
FileHelper.writeLogFile("选择操作-----------开始-------"); FileHelper.writeLogFile("选择操作-----------开始-------");
// 选择前移除适应度为 0 或明显劣于当前最优解的个体,减少选择池规模:
double minValidFitness = bestFitness * 0.5; // 保留最优解50%以上的个体
List<Chromosome> validPopulation = population.stream()
.filter(c -> c.getFitness() >= minValidFitness)
.collect(Collectors.toList());
// 选择操作 // 选择操作
List<Chromosome> selected = geneticOps.tournamentSelection(population); List<Chromosome> selected = geneticOps.tournamentSelection(validPopulation);
FileHelper.writeLogFile("选择操作-----------结束-------"); FileHelper.writeLogFile("选择操作-----------结束-------");
// 交叉操作 // 交叉操作
FileHelper.writeLogFile("交叉操作-----------开始-------"); FileHelper.writeLogFile("交叉操作-----------开始-------");
...@@ -178,7 +187,7 @@ public class GeneticAlgorithm { ...@@ -178,7 +187,7 @@ public class GeneticAlgorithm {
FileHelper.writeLogFile("变异批量解码-----------开始-------"); FileHelper.writeLogFile("变异批量解码-----------开始-------");
nextPopulation= chromosomeDistinct(nextPopulation);
Chromosomedecode(param,allOperations,globalOpList,nextPopulation); Chromosomedecode(param,allOperations,globalOpList,nextPopulation);
FileHelper.writeLogFile("变异批量解码-----------结束-------"); FileHelper.writeLogFile("变异批量解码-----------结束-------");
// // 精英保留 // // 精英保留
...@@ -192,7 +201,7 @@ public class GeneticAlgorithm { ...@@ -192,7 +201,7 @@ public class GeneticAlgorithm {
List<Chromosome> newPopulation = new ArrayList<>(); List<Chromosome> newPopulation = new ArrayList<>();
newPopulation.addAll(population); newPopulation.addAll(population);
newPopulation.addAll(nextPopulation); newPopulation.addAll(nextPopulation);
newPopulation= chromosomeDistinct(newPopulation); newPopulation= chromosomeDistinct1(newPopulation);
FileHelper.writeLogFile("非支配排序-----------开始-------"); FileHelper.writeLogFile("非支配排序-----------开始-------");
// 2.7 非支配排序 // 2.7 非支配排序
List<List<Chromosome>> combinedFronts = _nsgaIIUtils.parallelFastNonDominatedSort(newPopulation); List<List<Chromosome>> combinedFronts = _nsgaIIUtils.parallelFastNonDominatedSort(newPopulation);
...@@ -208,19 +217,26 @@ public class GeneticAlgorithm { ...@@ -208,19 +217,26 @@ public class GeneticAlgorithm {
best= GetBest(combinedFronts,String.valueOf(iter)); best= GetBest(combinedFronts,String.valueOf(iter));
if(bestFitness<best.getFitness()) if(bestFitness<best.getFitness())
{ {
bestFitness=best.getFitness(); bestFitness=best.getFitness();
Iteration=1; Iteration=1;
}else { }else {
Iteration++; Iteration++;
if (Iteration > 5) {
// 当连续 5 代无最优解提升时,降低交叉概率(如从 0.8 降至 0.5)、提高变异概率(如从 0.1 升至 0.2)
param.fineTuneParams();
}
} }
if(Iteration>10) if(Iteration>10)
{ {
break; break;
} }
// 当种群适应度标准差小于阈值(如 0.001)时,说明种群已收敛,提前终止迭代
fitnessStd = _fitnessCalculator.calculateFitnessStd(population);
if (fitnessStd < 0.001) {
FileHelper.writeLogFile("种群已收敛,提前终止迭代");
break;
}
FileHelper.writeLogFile("迭代进化------"+iter+"-----结束-------"); FileHelper.writeLogFile("迭代进化------"+iter+"-----结束-------");
} }
...@@ -256,21 +272,34 @@ public class GeneticAlgorithm { ...@@ -256,21 +272,34 @@ public class GeneticAlgorithm {
// WriteKpi(best,"最大"); // WriteKpi(best,"最大");
return best; return best;
} }
private List<Chromosome> chromosomeDistinct(List<Chromosome> population) private List<Chromosome> chromosomeDistinct(List<Chromosome> population)
{ {
if(orders.size()<10)
{ population = population.stream()
.collect(Collectors.toMap(
Chromosome::getGeneStr, // key:去重的字段(GeneStr)
u -> u, // value:Chromosome对象
(u1, u2) -> u1 // 重复时保留第一个元素
))
.values() // 获取去重后的
.stream()
.collect(Collectors.toList());
return population;
}
private List<Chromosome> chromosomeDistinct1(List<Chromosome> population)
{
population = population.stream() population = population.stream()
.collect(Collectors.toMap( .collect(Collectors.toMap(
Chromosome::getGeneStr, // key:去重的字段(GeneStr) Chromosome::getGeneStr, // key:去重的字段(GeneStr)
u -> u, // value:Chromosome对象 u -> u, // value:Chromosome对象
(u1, u2) -> u1 // 重复时保留第一个元素 (u1, u2) -> u1.getFitness() > u2.getFitness() ? u1 : u2 // 重复时保留第一个元素
)) ))
.values() // 获取去重后的 .values() // 获取去重后的
.stream() .stream()
.collect(Collectors.toList()); .collect(Collectors.toList());
}
return population; return population;
} }
...@@ -292,6 +321,7 @@ public class GeneticAlgorithm { ...@@ -292,6 +321,7 @@ public class GeneticAlgorithm {
FileHelper.writeLogFile(String.format(" KPI---%f-------",d)); FileHelper.writeLogFile(String.format(" KPI---%f-------",d));
} }
} }
private ExecutorService decodeExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
private void Chromosomedecode(ScheduleParams param, List<Entry> allOperations,List<GlobalOperationInfo> globalOpList,List<Chromosome> population) private void Chromosomedecode(ScheduleParams param, List<Entry> allOperations,List<GlobalOperationInfo> globalOpList,List<Chromosome> population)
{ {
...@@ -299,26 +329,51 @@ public class GeneticAlgorithm { ...@@ -299,26 +329,51 @@ public class GeneticAlgorithm {
GeneticDecoder decoder = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler,orderMaterials); GeneticDecoder decoder = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler,orderMaterials);
if(population!=null&&population.size()>0) { CompletableFuture.allOf(population.stream()
population.parallelStream().forEach(chromosome -> { .map(chromosome -> CompletableFuture.runAsync(() -> decode(decoder,chromosome,param,allOperations,globalOpList), decodeExecutor))
chromosome.setResult(new ArrayList<>()); .toArray(CompletableFuture[]::new))
.join();
// 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines)); // 简单拷贝,实际可能需要深拷贝 if(1==2) {
chromosome.setMachines(ProductionDeepCopyUtil.deepCopyList(machines)); // 简单拷贝,实际可能需要深拷贝 if (population != null && population.size() > 0) {
chromosome.setAllOperations(allOperations); // 简单拷贝,实际可能需要深拷贝 population.parallelStream().forEach(chromosome -> {
chromosome.setGlobalOpList(globalOpList); // 简单拷贝,实际可能需要深拷贝 chromosome.setResult(new ArrayList<>());
//chromosome.setObjectiveWeights(_objectiveWeights);
chromosome.setBaseTime(param.getBaseTime());
// _sceneService.saveChromosomeToFile(chromosome, "12345679");
decoder.decodeChromosomeWithCache(chromosome);
if (chromosome.getFitness() == 0) {
chromosome.setFitness(_fitnessCalculator.calculateFitness(chromosome,_objectiveWeights));
}
});
// 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines)); // 简单拷贝,实际可能需要深拷贝
chromosome.setMachines(ProductionDeepCopyUtil.deepCopyList(machines,Machine.class)); // 简单拷贝,实际可能需要深拷贝
chromosome.setAllOperations(allOperations); // 简单拷贝,实际可能需要深拷贝
chromosome.setGlobalOpList(globalOpList); // 简单拷贝,实际可能需要深拷贝
//chromosome.setObjectiveWeights(_objectiveWeights);
chromosome.setBaseTime(param.getBaseTime());
// _sceneService.saveChromosomeToFile(chromosome, "12345679");
decoder.decodeChromosomeWithCache(chromosome);
if (chromosome.getFitness() == 0) {
chromosome.setFitness(_fitnessCalculator.calculateFitness(chromosome, _objectiveWeights));
}
});
}
}
}
private void decode(GeneticDecoder decoder,Chromosome chromosome,ScheduleParams param, List<Entry> allOperations,List<GlobalOperationInfo> globalOpList) {
chromosome.setResult(new ArrayList<>());
// 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines)); // 简单拷贝,实际可能需要深拷贝
chromosome.setMachines(ProductionDeepCopyUtil.deepCopyList(machines,Machine.class)); // 简单拷贝,实际可能需要深拷贝
chromosome.setAllOperations(allOperations); // 简单拷贝,实际可能需要深拷贝
chromosome.setGlobalOpList(globalOpList); // 简单拷贝,实际可能需要深拷贝
//chromosome.setObjectiveWeights(_objectiveWeights);
chromosome.setBaseTime(param.getBaseTime());
// _sceneService.saveChromosomeToFile(chromosome, "12345679");
decoder.decodeChromosomeWithCache(chromosome);
if (chromosome.getFitness() == 0) {
chromosome.setFitness(_fitnessCalculator.calculateFitness(chromosome, _objectiveWeights));
} }
} }
......
...@@ -374,6 +374,7 @@ if(finishedOrder==null||finishedOrder.size()==0) ...@@ -374,6 +374,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
int teardownTime = machineOption.getTeardownTime(); int teardownTime = machineOption.getTeardownTime();
int preTime = machineOption.getPreTime(); int preTime = machineOption.getPreTime();
int setupTime = calculateSetupTime(chromosome.getResult(), operation, machine, machineOption); int setupTime = calculateSetupTime(chromosome.getResult(), operation, machine, machineOption);
......
...@@ -33,11 +33,80 @@ public class GeneticOperations { ...@@ -33,11 +33,80 @@ public class GeneticOperations {
* 锦标赛选择 * 锦标赛选择
*/ */
public List<Chromosome> tournamentSelection(List<Chromosome> population, int tournamentSize) { public List<Chromosome> tournamentSelection(List<Chromosome> population, int tournamentSize) {
// 前置边界校验(避免NPE和无效计算)
if (population == null || population.isEmpty()) {
return new ArrayList<>();
}
int populationSize = population.size(); int populationSize = population.size();
// 预计算需要选中的个体数量,避免动态判断
int needSelectCount = populationSize - Math.max(1, Math.min(tournamentSize, populationSize));
List<Chromosome> selected = new ArrayList<>(needSelectCount); // 预初始化容量
// 边界值处理:锦标赛规模不能超过种群规模,且至少为1
int effectiveTournamentSize = Math.max(1, Math.min(tournamentSize, populationSize));
List<Chromosome> selectedtemp = new ArrayList<>(needSelectCount); // 预初始化容量
// 预生成随机索引,减少Random对象创建开销
Random random = this.rnd;
// 固定次数循环,替代动态终止条件
for (int selectIdx = 0; selectIdx < needSelectCount; selectIdx++) {
// 优化1:Fisher-Yates抽样(无重复、无冲突,比HashSet高效)
List<Integer> indices = new ArrayList<>(populationSize);
for (int i = 0; i < populationSize; i++) {
indices.add(i);
}
// 仅打乱前effectiveTournamentSize个索引,减少计算量
for (int i = 0; i < effectiveTournamentSize; i++) {
int swapIdx = i + random.nextInt(populationSize - i);
Collections.swap(indices, i, swapIdx);
}
Chromosome bestCandidate=null;
for (int i = 0; i < effectiveTournamentSize; i++) {
int idx = indices.get(i);
Chromosome curr= population.get(idx);
if(bestCandidate!=null)
{
int rankCompare = Integer.compare(curr.getRank(), bestCandidate.getRank());
if(rankCompare==0)
{
int crowdingCompare = Double.compare(curr.getCrowdingDistance(), bestCandidate.getCrowdingDistance());
if(crowdingCompare<0)
{
bestCandidate=curr;
}
}else {
if(rankCompare<0)
{
bestCandidate=curr;
}
}
}else {
bestCandidate=curr;
}
}
if (bestCandidate != null) {
selected.add(bestCandidate);
}
}
return selected;// ProductionDeepCopyUtil.deepCopyList(selected, Chromosome.class);
}
/**
* 锦标赛选择
*/
public List<Chromosome> tournamentSelection1(List<Chromosome> population, int tournamentSize) {
int populationSize = population.size();
List<Chromosome> selected = new ArrayList<>(); // 预初始化容量 List<Chromosome> selected = new ArrayList<>(); // 预初始化容量
// 边界值处理:锦标赛规模不能超过种群规模,且至少为1 // 边界值处理:锦标赛规模不能超过种群规模,且至少为1
int effectiveTournamentSize = Math.max(1, Math.min(tournamentSize, populationSize)); int effectiveTournamentSize = Math.max(1, Math.min(tournamentSize, populationSize));
while (selected.size() < populationSize-tournamentSize) { while (selected.size() < populationSize-tournamentSize) {
// 优化1:不复制整个种群,直接随机抽取有效锦标赛规模的个体,避免大量内存拷贝和shuffle开销 // 优化1:不复制整个种群,直接随机抽取有效锦标赛规模的个体,避免大量内存拷贝和shuffle开销
...@@ -46,9 +115,9 @@ public class GeneticOperations { ...@@ -46,9 +115,9 @@ public class GeneticOperations {
List<Chromosome> chromosomes=population.subList(0, endIndex); List<Chromosome> chromosomes=population.subList(0, endIndex);
chromosomes.sort((c1, c2) -> { chromosomes.sort((c1, c2) -> {
int rankCompare = Integer.compare(c1.getRank(), c2.getRank()); int rankCompare = Integer.compare(c1.getRank(), c2.getRank());
return rankCompare != 0 ? rankCompare : Double.compare(c1.getCrowdingDistance(), c2.getCrowdingDistance()); return rankCompare != 0 ? rankCompare : Double.compare(c1.getCrowdingDistance(), c2.getCrowdingDistance());
}); });
Chromosome bestCandidate = chromosomes.get(0); Chromosome bestCandidate = chromosomes.get(0);
...@@ -60,6 +129,7 @@ public class GeneticOperations { ...@@ -60,6 +129,7 @@ public class GeneticOperations {
return selected; return selected;
} }
// 重载,使用默认锦标赛大小3 // 重载,使用默认锦标赛大小3
public List<Chromosome> tournamentSelection(List<Chromosome> population) { public List<Chromosome> tournamentSelection(List<Chromosome> population) {
return tournamentSelection(population, param.getTournamentSize()); return tournamentSelection(population, param.getTournamentSize());
...@@ -259,8 +329,8 @@ public class GeneticOperations { ...@@ -259,8 +329,8 @@ public class GeneticOperations {
.findFirst().orElse(0); .findFirst().orElse(0);
List<Integer> MachineSelections= chromosome.getMachineSelection();
int machineSeq = chromosome.getMachineSelection().get(pos); int machineSeq = MachineSelections.get(pos);
// 选择当前所选设备外最短加工时间的机器 // 选择当前所选设备外最短加工时间的机器
...@@ -274,7 +344,8 @@ public class GeneticOperations { ...@@ -274,7 +344,8 @@ public class GeneticOperations {
.orElse(currentMachine); // 如果没有其他机器,保持当前 .orElse(currentMachine); // 如果没有其他机器,保持当前
machineSeq = optionalMachines.indexOf(minLoadMachine) + 1; machineSeq = optionalMachines.indexOf(minLoadMachine) + 1;
chromosome.getMachineSelection().set(pos, machineSeq); MachineSelections.set(pos, machineSeq);
chromosome.setMachineSelection(MachineSelections);
i++; i++;
} }
...@@ -298,6 +369,7 @@ public class GeneticOperations { ...@@ -298,6 +369,7 @@ public class GeneticOperations {
// 交换位置 // 交换位置
List<Integer> os = chromosome.getOperationSequencing(); List<Integer> os = chromosome.getOperationSequencing();
Collections.swap(os, idx1, idx2); Collections.swap(os, idx1, idx2);
chromosome.setOperationSequencing(os);
} else { } else {
// 反转:仅对高优先级工序集中的子序列反转 // 反转:仅对高优先级工序集中的子序列反转
OperationSequencingWeight osStart = selectHighPriorityIndex(chromosome.getOperationSequencing(), 0); OperationSequencingWeight osStart = selectHighPriorityIndex(chromosome.getOperationSequencing(), 0);
...@@ -318,6 +390,7 @@ public class GeneticOperations { ...@@ -318,6 +390,7 @@ public class GeneticOperations {
int pos2 = end - i; int pos2 = end - i;
Collections.swap(os, pos1, pos2); Collections.swap(os, pos1, pos2);
} }
chromosome.setOperationSequencing(os);
} }
} }
......
...@@ -668,7 +668,7 @@ public class IdGroupingWithDualSerial { ...@@ -668,7 +668,7 @@ public class IdGroupingWithDualSerial {
nodeInfo.getNewParentIds().isEmpty() ? "无" : nodeInfo.getNewParentIds(), nodeInfo.getNewParentIds().isEmpty() ? "无" : nodeInfo.getNewParentIds(),
nodeInfo.getNewChildIds()); nodeInfo.getNewChildIds());
} }
System.out.println("------------------------"); // System.out.println("------------------------");
} }
} }
} }
...@@ -65,7 +65,7 @@ int populationSize=param.getPopulationSize(); ...@@ -65,7 +65,7 @@ int populationSize=param.getPopulationSize();
.forEach(i -> { .forEach(i -> {
Chromosome chromo = new Chromosome(); // 初始化染色体 Chromosome chromo = new Chromosome(); // 初始化染色体
// chromo.setObjectiveWeights(_objectiveWeights); // chromo.setObjectiveWeights(_objectiveWeights);
chromo.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines)); // chromo.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines));
chromo.setOrders(orders); chromo.setOrders(orders);
// 全局选择(GS):按GlobalOpId顺序生成MachineSelection // 全局选择(GS):按GlobalOpId顺序生成MachineSelection
if (i < gsCount) { if (i < gsCount) {
......
...@@ -92,7 +92,7 @@ public class MachineCalculator { ...@@ -92,7 +92,7 @@ public class MachineCalculator {
time.setQuantity(quantity); time.setQuantity(quantity);
times.add(time); times.add(time);
if(islockMachineTime) { if(islockMachineTime) {
RemoveMachineAvailable(machine, time); RemoveMachineAvailable(machine, time,slot);
} }
return times; return times;
} }
...@@ -129,7 +129,7 @@ public class MachineCalculator { ...@@ -129,7 +129,7 @@ public class MachineCalculator {
st = shiftStart; st = shiftStart;
remainingTime = processingTime; remainingTime = processingTime;
prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0, 0); prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
oldTimes.addAll(ProductionDeepCopyUtil.deepCopyList(times)); oldTimes.addAll(ProductionDeepCopyUtil.deepCopyList(times,ScheduleResultDetail.class));
times.clear(); times.clear();
continue; continue;
} }
...@@ -159,7 +159,7 @@ public class MachineCalculator { ...@@ -159,7 +159,7 @@ public class MachineCalculator {
times.add(time); times.add(time);
if (islockMachineTime) { if (islockMachineTime) {
// 还原未使用的时间段 // 还原未使用的时间段
RemoveMachineAvailable(machine, time); RemoveMachineAvailable(machine, time,shift);
} }
} }
...@@ -182,47 +182,112 @@ public class MachineCalculator { ...@@ -182,47 +182,112 @@ public class MachineCalculator {
List<ScheduleResultDetail> times = new ArrayList<>(); List<ScheduleResultDetail> times = new ArrayList<>();
List<ScheduleResultDetail> oldTimes = new ArrayList<>(); List<ScheduleResultDetail> oldTimes = new ArrayList<>();
List<TimeSegment> timeSegments= findAvailableSegments(machine, currentTime, machineTasks, remainingTime, isInterrupt);
int estimateIndex= (int) Math.ceil(remainingTime / (double) ONE_DAY_MINUTES);
List<TimeSegment> timeSegments1=null;
if(estimateIndex>10)
{
timeSegments1= getEnoughSegmentsByEstimateIndex(timeSegments,currentTime,remainingTime);
}
if(timeSegments1==null) {
int i = 0;
while (remainingTime > 0) {
TimeSegment shift = timeSegments.get(i);
List<TimeSegment> timeSegments= findAvailableSegments(machine, currentTime, machineTasks, remainingTime, isInterrupt); Map<Integer, Object> outMap = CreateScheduleResultDetail(shift, st, remainingTime, oneTime);
remainingTime = (int) outMap.get(1);
ScheduleResultDetail time = (ScheduleResultDetail) outMap.get(2);
times.add(time);
// 还原未使用的时间段
RemoveMachineAvailable(machine, time,shift);
i++;
}
}else {
times= CaldScheduleResultDetail(timeSegments1,machine,st,remainingTime,oneTime);
}
return times;
}
private List<ScheduleResultDetail> CaldScheduleResultDetail(List<TimeSegment> timeSegments,Machine machine,LocalDateTime st,int remainingTime,double oneTime)
{
int i=0; int processable1 =(int)calculateTotalAvailableSecond(timeSegments, st);
while (remainingTime > 0) {
TimeSegment shift= timeSegments.get(i);
LocalDateTime shiftStart = shift.getStart();
LocalDateTime shiftEnd = shift.getEnd();
// 计算有效时间 List<ScheduleResultDetail> times = new ArrayList<>();
LocalDateTime effectiveStart = st.isAfter(shiftStart) ? st : shiftStart;
long availableSeconds = ChronoUnit.SECONDS.between(effectiveStart, shiftEnd);
long availableSeconds_e =Math.round(availableSeconds*shift.getEfficiency()) ;
// 处理当前班次 TimeSegment shiftfrist= timeSegments.get(0);
int processable = Math.min(remainingTime, (int) availableSeconds_e);
remainingTime -= processable;
currentTime = effectiveStart.plusSeconds(availableSeconds/availableSeconds_e*processable);
// 添加时间详情 Map<Integer, Object> outMap= CreateScheduleResultDetail(shiftfrist,st,remainingTime,oneTime);
ScheduleResultDetail time = new ScheduleResultDetail(); remainingTime=(int)outMap.get(1);
time.setKey(shift.getKey()); ScheduleResultDetail time1=(ScheduleResultDetail)outMap.get(2);
time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveStart)); times.add(time1);
time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, currentTime)); RemoveMachineAvailable(machine, time1,shiftfrist);
time.setQuantity((int)(processable/oneTime));
time.setOneTime(oneTime);
times.add(time);
// 还原未使用的时间段 // 计算有效时间
RemoveMachineAvailable(machine, time);
i++; List<TimeSegment> timeSegments2= timeSegments.subList(1,timeSegments.size()-1);
} LocalDateTime effectiveStart=timeSegments2.get(0).getStart();
LocalDateTime effectiveend=timeSegments2.get(timeSegments2.size()-1).getEnd();
int processable =(int)calculateTotalAvailableSecond(timeSegments2, st);
ScheduleResultDetail time = new ScheduleResultDetail();
time.setKey(UUID.randomUUID().toString());
time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveStart));
time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveend));
time.setQuantity((int)(processable/oneTime));
time.setOneTime(oneTime);
time.setUsedSegment(timeSegments2);
timeSegments2.forEach(t->t.setUsed(true));
remainingTime-=processable;
times.add(time);
TimeSegment shiftlast= timeSegments.get(timeSegments.size()-1);
Map<Integer, Object> outMaplast= CreateScheduleResultDetail(shiftlast,st,remainingTime,oneTime);
remainingTime=(int)outMaplast.get(1);
ScheduleResultDetail timelast=(ScheduleResultDetail)outMaplast.get(2);
times.add(timelast);
RemoveMachineAvailable(machine, timelast,shiftlast);
return times; return times;
} }
private Map<Integer, Object> CreateScheduleResultDetail(TimeSegment shift,LocalDateTime st,int remainingTime,double oneTime)
{
LocalDateTime shiftStart = shift.getStart();
LocalDateTime shiftEnd = shift.getEnd();
// 计算有效时间
LocalDateTime effectiveStart = st.isAfter(shiftStart) ? st : shiftStart;
long availableSeconds = ChronoUnit.SECONDS.between(effectiveStart, shiftEnd);
long availableSeconds_e =Math.round(availableSeconds*shift.getEfficiency()) ;
// 处理当前班次
int processable = Math.min(remainingTime, (int) availableSeconds_e);
remainingTime -= processable;
double e= (double)availableSeconds/availableSeconds_e*processable;
LocalDateTime currentTime = effectiveStart.plusSeconds((int)Math.ceil(e));
// 添加时间详情
ScheduleResultDetail time = new ScheduleResultDetail();
time.setKey(shift.getKey());
time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveStart));
time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, currentTime));
time.setQuantity((int)(processable/oneTime));
time.setOneTime(oneTime);
Map<Integer, Object> outMap=new HashMap<>();
outMap.put(1, remainingTime);
outMap.put(2, time);
return outMap;
}
/** /**
* 查找满足时长要求的无冲突可用时段 * 查找满足时长要求的无冲突可用时段
* @param machine 设备 * @param machine 设备
...@@ -323,6 +388,100 @@ i++; ...@@ -323,6 +388,100 @@ i++;
} }
} }
} }
private static final int ONE_DAY_MINUTES = 24 * 60*60; // 固定锚点:一天1440分钟,永不改变
/**
* 按预估索引快速获取满足时长的时段数组
* @param availableSegments 有序的可用时段列表(必须按Start升序,业务中天然满足)
* @param currentTime 排程开始时间
* @param requiredMinutes 需要的总分钟数(支持超大值:几万/几十万分钟)
* @return 刚好满足时长的片段数组
* @throws IllegalArgumentException 总时长不足时抛出
*/
public List<TimeSegment> getEnoughSegmentsByEstimateIndex(
List<TimeSegment> availableSegments,
LocalDateTime currentTime,
int requiredMinutes) {
// 基础校验
if (availableSegments == null || availableSegments.isEmpty()) {
throw new IllegalArgumentException("可用时段列表不能为空");
}
if (requiredMinutes <= 0) {
return null;
}
int totalSegmentCount = availableSegments.size();
// ========== 步骤1:核心!快速预估索引,一步到位,跳过几千个片段 ==========
// 预估逻辑:需求时长/每天分钟数 + 5(冗余值,防止预估不足,可根据业务调整,实际班次不是24小时),
int estimateIndex= (int) Math.ceil(requiredMinutes / (double) ONE_DAY_MINUTES);
estimateIndex =estimateIndex + 5;
// 边界保护:预估索引不能超过总片段数,也不能小于0
estimateIndex = Math.min(estimateIndex, totalSegmentCount - 1);
estimateIndex = Math.max(estimateIndex, 0);
// ========== 步骤2:双向逼近,小范围循环增减索引,循环次数≤20次 ==========
int targetIndex = estimateIndex;
while (true) {
// 计算当前索引的总有效时长
double currentTotal = calculateTotalMinutesByIndex(availableSegments, currentTime, targetIndex);
if (currentTotal >= requiredMinutes) {
// ✔️ 总时长满足,尝试往前减索引,找「最小满足索引」(减少后续裁剪的工作量)
if (targetIndex > 0) {
double prevTotal = calculateTotalMinutesByIndex(availableSegments, currentTime, targetIndex - 1);
if (prevTotal >= requiredMinutes) {
targetIndex--;
continue;
}
}
break; // 找到最小满足索引,退出循环
} else {
double syday= (int)Math.ceil((requiredMinutes-currentTotal)/(double) ONE_DAY_MINUTES);
// ❌ 总时长不足,往后加索引(每次加5,大步前进,加快逼近速度)
targetIndex +=Math.max(syday, 5);
if (targetIndex >= totalSegmentCount) {
// 所有片段总时长不足,抛出异常
double allTotal = calculateTotalMinutesByIndex(availableSegments, currentTime, totalSegmentCount - 1);
if(allTotal>requiredMinutes)
{
double prevTotal = calculateTotalMinutesByIndex(availableSegments, currentTime, targetIndex - 1);
if (prevTotal >= requiredMinutes) {
targetIndex--;
continue;
}
break;
}
else if(allTotal==requiredMinutes)
{
return availableSegments;
}else {
return null;
}
}
}
}
// ========== 步骤3:精准裁剪片段,返回最终结果 ==========
List<TimeSegment> resultList = availableSegments.subList(0,targetIndex);
return resultList;
}
/**
* 计算从0到指定索引的所有时段的总有效分钟数
*/
private double calculateTotalMinutesByIndex(List<TimeSegment> segments, LocalDateTime currentTime, int endIndex) {
return calculateTotalAvailableSecond(segments.subList(0,endIndex), currentTime);
}
/** /**
* 统一过滤有效可用片段 * 统一过滤有效可用片段
*/ */
...@@ -538,13 +697,17 @@ i++; ...@@ -538,13 +697,17 @@ i++;
if (newSegments == null || newSegments.isEmpty()) { if (newSegments == null || newSegments.isEmpty()) {
return; return;
} }
List<TimeSegment> availabilitySnapshot = new ArrayList<>(machine.getAvailability());
availabilitySnapshot.addAll(newSegments);
List<TimeSegment> mergedSegments = MergeSegments(availabilitySnapshot);
synchronized (machine.getAvailability()) {
// 合并片段(去重+排序),
machine.setAvailability(mergedSegments);
}
// 追加新片段,对应C#的 machine.Availability.AddRange(newSegments)
machine.getAvailability().addAll(newSegments);
// 合并片段(去重+排序),并重新赋值给设备的可用片段列表,对应C#的 machine.Availability = MergeSegments(...)
List<TimeSegment> mergedSegments = MergeSegments(machine.getAvailability());
machine.setAvailability(mergedSegments);
} }
private boolean CheckTask(Machine machine,List<GAScheduleResult> machineTasks,LocalDateTime prevEnd,LocalDateTime shiftStart) { private boolean CheckTask(Machine machine,List<GAScheduleResult> machineTasks,LocalDateTime prevEnd,LocalDateTime shiftStart) {
...@@ -572,10 +735,10 @@ i++; ...@@ -572,10 +735,10 @@ i++;
*/ */
private TimeSegment GetCurrentOrNextShift(Machine machine, LocalDateTime time, String prevtime, boolean checkprevtime) { private TimeSegment GetCurrentOrNextShift(Machine machine, LocalDateTime time, String prevtime, boolean checkprevtime) {
TimeSegment start = null; TimeSegment start = null;
List<TimeSegment> availabilitySnapshot = new ArrayList<>(machine.getAvailability());
if(machine.getAvailability()!=null) if (!availabilitySnapshot.isEmpty())
{ {
start = machine.getAvailability().stream() start = availabilitySnapshot.stream()
.filter(slot -> !slot.isUsed() && slot.getType() != SegmentType.MAINTENANCE) .filter(slot -> !slot.isUsed() && slot.getType() != SegmentType.MAINTENANCE)
.filter(slot -> slot.getStart().isAfter(time) || slot.getEnd().isAfter(time)) .filter(slot -> slot.getStart().isAfter(time) || slot.getEnd().isAfter(time))
.findFirst() .findFirst()
...@@ -590,8 +753,9 @@ i++; ...@@ -590,8 +753,9 @@ i++;
// 生成新时间段 // 生成新时间段
List<TimeSegment> timeSegments = machineScheduler.generateTimeSegment(machine, time.plusDays(1),0); List<TimeSegment> timeSegments = machineScheduler.generateTimeSegment(machine, time.plusDays(1),0);
machine.getAvailability().addAll(timeSegments); synchronized (machine.getAvailability()) {
machine.getAvailability().addAll(timeSegments);
}
// 更新设备时间线 // 更新设备时间线
Machine originalMachine = machines.stream() Machine originalMachine = machines.stream()
.filter(t -> t.getId() == machine.getId()) .filter(t -> t.getId() == machine.getId())
...@@ -812,17 +976,54 @@ i++; ...@@ -812,17 +976,54 @@ i++;
return times; return times;
} }
private void RemoveMachineAvailable(Machine machine, ScheduleResultDetail geneDetails) { private void RemoveMachineAvailable(Machine machine, ScheduleResultDetail geneDetails,TimeSegment targetSegment) {
// 关键修复2:加锁(若多线程访问),避免并发修改
synchronized (machine.getAvailability()) {
List<TimeSegment> availabilitySnapshot = new ArrayList<>(machine.getAvailability());
LocalDateTime geneEndTime = baseTime.plusSeconds(geneDetails.getEndTime());
if (targetSegment.getEnd().isAfter(geneEndTime)) {
TimeSegment usedSegment = new TimeSegment();
usedSegment.setStart(baseTime.plusSeconds(geneDetails.getStartTime()));
usedSegment.setEnd(geneEndTime);
usedSegment.setHoliday(false);
usedSegment.setKey(UUID.randomUUID().toString());
usedSegment.setType(SegmentType.REGULAR);
usedSegment.setUsed(true);
availabilitySnapshot.add(usedSegment);
geneDetails.setKey(usedSegment.getKey());
targetSegment.setStart(geneEndTime);
} else {
targetSegment.setUsed(true);
}
availabilitySnapshot.sort(Comparator.comparing(TimeSegment::getStart));
machine.setAvailability(availabilitySnapshot);
}
}
private void RemoveMachineAvailable1(Machine machine, ScheduleResultDetail geneDetails) {
List<TimeSegment> timeSegments = new ArrayList<>(); List<TimeSegment> timeSegments = new ArrayList<>();
int index = machine.getAvailability().stream() List<TimeSegment> availabilitySnapshot = new ArrayList<>(machine.getAvailability());
int index = availabilitySnapshot.stream()
.filter(t -> t.getKey().equals(geneDetails.getKey())) .filter(t -> t.getKey().equals(geneDetails.getKey()))
.findFirst() .findFirst()
.map(machine.getAvailability()::indexOf) .map(machine.getAvailability()::indexOf)
.orElse(-1); .orElse(-1);
if (index > -1) { if (index > -1) {
TimeSegment targetSegment = machine.getAvailability().get(index); TimeSegment targetSegment = availabilitySnapshot.get(index);
LocalDateTime geneEndTime = baseTime.plusSeconds(geneDetails.getEndTime()); LocalDateTime geneEndTime = baseTime.plusSeconds(geneDetails.getEndTime());
if (targetSegment.getEnd().isAfter(geneEndTime)) { if (targetSegment.getEnd().isAfter(geneEndTime)) {
...@@ -843,22 +1044,60 @@ i++; ...@@ -843,22 +1044,60 @@ i++;
} }
if (!timeSegments.isEmpty()) { if (!timeSegments.isEmpty()) {
machine.getAvailability().addAll(timeSegments); availabilitySnapshot.addAll(timeSegments);
}
availabilitySnapshot.sort(Comparator.comparing(TimeSegment::getStart));
// 关键修复2:加锁(若多线程访问),避免并发修改
synchronized (machine.getAvailability()) {
machine.setAvailability(availabilitySnapshot);
} }
machine.getAvailability().sort(Comparator.comparing(TimeSegment::getStart));
} }
public void AddMachineAvailable(Machine machine, List<ScheduleResultDetail> geneDetails) { public void AddMachineAvailable(Machine machine, List<ScheduleResultDetail> geneDetails) {
if (geneDetails == null || geneDetails.isEmpty()) return; if (geneDetails == null || geneDetails.isEmpty()) return;
synchronized (machine.getAvailability()) {
List<String> keys= geneDetails.stream().
filter(t->t.getUsedSegment()==null||t.getUsedSegment().size()==0)
.map(ScheduleResultDetail::getKey)
.collect(Collectors.toList());
List<String> keys1= geneDetails.stream().
filter(t->t.getUsedSegment()!=null)
.flatMap(detail -> detail.getUsedSegment().stream())
.map(TimeSegment::getKey).collect(Collectors.toList());
if(keys1!=null&&keys1.size()>0) {
keys.addAll(keys1);
}
machine.getAvailability().stream()
.filter(t ->keys.contains(t.getKey()))
.forEach(t->t.setUsed(false));
for (ScheduleResultDetail detail : geneDetails) {
machine.getAvailability().stream()
.filter(t -> t.getKey().equals(detail.getKey()))
.findFirst()
.ifPresent(t -> t.setUsed(false));
} }
}
machine.setAvailability(MergeSegments(machine.getAvailability())); public void AddMachineAvailable1(Machine machine, List<ScheduleResultDetail> geneDetails) {
if (geneDetails == null || geneDetails.isEmpty()) return;
List<TimeSegment> availabilitySnapshot = new ArrayList<>(machine.getAvailability());
for (ScheduleResultDetail detail : geneDetails) {
if(detail.getUsedSegment()!=null&&detail.getUsedSegment().size()>0)
{
List<TimeSegment> availabilitySnapshot1= detail.getUsedSegment();
availabilitySnapshot1.forEach(t->t.setUsed(false));
}else {
availabilitySnapshot.stream()
.filter(t -> t.getKey().equals(detail.getKey()))
.findFirst()
.ifPresent(t -> t.setUsed(false));
}
}
availabilitySnapshot= MergeSegments(availabilitySnapshot);
synchronized (machine.getAvailability()) {
machine.setAvailability(availabilitySnapshot);
}
} }
/** /**
* 分割设备可用时间段 * 分割设备可用时间段
......
...@@ -272,9 +272,8 @@ public class RoutingDataService { ...@@ -272,9 +272,8 @@ public class RoutingDataService {
entrys.add(entry); entrys.add(entry);
} }
// 输出每个节点的详细信息
System.out.println("------------------------");
} }
list.put(1,entrys); list.put(1,entrys);
list.put(2,results); list.put(2,results);
......
...@@ -928,13 +928,13 @@ Integer newMachineId1=newMachineId.intValue(); ...@@ -928,13 +928,13 @@ Integer newMachineId1=newMachineId.intValue();
GeneticDecoder decoder = new GeneticDecoder(globalParam,baseTime, chromosome.getMachines(), GeneticDecoder decoder = new GeneticDecoder(globalParam,baseTime, chromosome.getMachines(),
chromosome.getOrders(), null, machineScheduler,chromosome.getOrderMaterials()); chromosome.getOrders(), null, machineScheduler,chromosome.getOrderMaterials());
chromosome.setResultOld(ProductionDeepCopyUtil.deepCopyList(chromosome.getResult())); chromosome.setResultOld(ProductionDeepCopyUtil.deepCopyList(chromosome.getResult(),GAScheduleResult.class));
chromosome.getResult().clear(); chromosome.getResult().clear();
List<GAScheduleResult> Resultlock= chromosome.getResult().stream() List<GAScheduleResult> Resultlock= chromosome.getResult().stream()
.filter(o -> o.isIsLocked() == true) .filter(o -> o.isIsLocked() == true)
.collect(Collectors.toList()); .collect(Collectors.toList());
chromosome.setResult(ProductionDeepCopyUtil.deepCopyList(Resultlock)); chromosome.setResult(ProductionDeepCopyUtil.deepCopyList(Resultlock,GAScheduleResult.class));
decoder.decode(chromosome); decoder.decode(chromosome);
......
...@@ -98,7 +98,8 @@ public class PlanResultService { ...@@ -98,7 +98,8 @@ public class PlanResultService {
@Autowired @Autowired
private MaterialInfoMapper materialInfoMapper; private MaterialInfoMapper materialInfoMapper;
@Autowired
private MaterialPurchaseMapper materialPurchaseMapper;
@Autowired @Autowired
private StockMapper stockMapper; private StockMapper stockMapper;
...@@ -1139,14 +1140,19 @@ private GlobalParam InitGlobalParam() ...@@ -1139,14 +1140,19 @@ private GlobalParam InitGlobalParam()
public List<Material> getMaterials(){ public List<Material> getMaterials(){
List<Material> materials=new ArrayList<>(); List<Material> materials=new ArrayList<>();
System.out.println("开始初始化物料数据");
LambdaQueryWrapper<MaterialInfo> MaterialInfoWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<MaterialInfo> MaterialInfoWrapper = new LambdaQueryWrapper<>();
MaterialInfoWrapper.eq(MaterialInfo::getIsdeleted,0); MaterialInfoWrapper.eq(MaterialInfo::getIsdeleted,0);
List<MaterialInfo> materiallist=materialInfoMapper.selectList(MaterialInfoWrapper); List<MaterialInfo> materiallist=materialInfoMapper.selectList(MaterialInfoWrapper);
LambdaQueryWrapper<MaterialPurchase> materialPurchaseWrapper= new LambdaQueryWrapper<>();
materialPurchaseWrapper.eq(MaterialPurchase::getIsdeleted,0);
List<MaterialPurchase> MaterialPurchaselist=materialPurchaseMapper.selectList(materialPurchaseWrapper);
System.out.println("开始初始化物料数据");
LambdaQueryWrapper<Stock> StockWrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<Stock> StockWrapper = new LambdaQueryWrapper<>();
StockWrapper.eq(Stock::getIsdeleted,0); StockWrapper.eq(Stock::getIsdeleted,0);
......
...@@ -38,13 +38,13 @@ public class PlanResultServiceTest { ...@@ -38,13 +38,13 @@ public class PlanResultServiceTest {
// nsgaiiUtils.Test(); // nsgaiiUtils.Test();
//planResultService.execute2("C5FB5EF2A7334A0A92F826F4937E1008"); //planResultService.execute2("C5FB5EF2A7334A0A92F826F4937E1008");
// planResultService.execute2("726D4C1A712B4B1393175BD44B775B66"); planResultService.execute2("726D4C1A712B4B1393175BD44B775B66");
planResultService.execute2("BCA6FA43FFA444D3952CF8F6E1EA291B"); // planResultService.execute2("BCA6FA43FFA444D3952CF8F6E1EA291B");
// LocalDateTime t= LocalDateTime.of(2025, 11, 15, 6, 51, 11); // LocalDateTime t= LocalDateTime.of(2025, 11, 15, 6, 51, 11);
// List<Integer> opids=new ArrayList<>(); // List<Integer> opids=new ArrayList<>();
// opids.add(1); // opids.add(1);
// planResultService.Move("B571EF6682DB463AB2977B1055A74112",opids,t,3403L); // planResultService.Move("B571EF6682DB463AB2977B1055A74112",opids,t,3403L);
// planResultService.Redecode("12345679"); planResultService.Redecode("12345679");
// MaintenanceWindow maintenanceWindow=new MaintenanceWindow(); // MaintenanceWindow maintenanceWindow=new MaintenanceWindow();
// maintenanceWindow.setStartTime(LocalDateTime.of(2025, 10, 21, 0, 0, 0)); // maintenanceWindow.setStartTime(LocalDateTime.of(2025, 10, 21, 0, 0, 0));
// maintenanceWindow.setEndTime(LocalDateTime.of(2025, 10, 31, 0, 0, 0)); // maintenanceWindow.setEndTime(LocalDateTime.of(2025, 10, 31, 0, 0, 0));
......
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