Commit 34bcb88f authored by Tong Li's avatar Tong Li

Merge remote-tracking branch 'origin/tl'

parents f96d4ca7 4562cda0
......@@ -28,36 +28,49 @@ public class Chromosome {
/// <summary>
/// 机器选择部分(可选机器集中的顺序号)
/// </summary>
private List<Integer> MachineSelection;
private List<Integer> machineSelection;
/// <summary>
/// 工序排序部分(工件/订单ID)
/// </summary>
private String MachineStr;
private String machineStr;
public String getMachineStr() {
if(MachineSelection==null) return "";
return MachineSelection.stream()
/// <summary>
/// 机器选择部分 + 工序排序部分
/// </summary>
private String geneStr;
public void setMachineSelection(List<Integer> val) {
machineSelection = val;
machineStr = machineSelection.stream()
.map(String::valueOf) // 将每个 Integer 转换为 String
.collect(Collectors.joining(","));
};
geneStr=machineStr+ "_" +operationStr;
}
/// <summary>
/// 工序排序部分(工件/订单ID)
/// </summary>
private List<Integer> OperationSequencing;
private List<Integer> operationSequencing;
public void setOperationSequencing(List<Integer> val) {
operationSequencing = val;
operationStr = operationSequencing.stream()
.map(String::valueOf) // 将每个 Integer 转换为 String
.collect(Collectors.joining(","));
geneStr=machineStr+ "_" +operationStr;
}
/// <summary>
/// 工序排序部分(工件/订单ID)
/// </summary>
private String OperationStr;
private String operationStr;
public String getOperationStr() {
if(OperationSequencing==null) return "";
return OperationSequencing.stream()
.map(String::valueOf) // 将每个 Integer 转换为 String
.collect(Collectors.joining("|"));
};
private List<GlobalOperationInfo> globalOpList;
private List<Entry> allOperations;
......@@ -68,9 +81,19 @@ public class Chromosome {
private List<GroupResult> OperatRel;
private ObjectiveWeights objectiveWeights;
/*
* 最早完工时间(最小化) 最小化总加工时间 最小总换型时间
*/
private double[] Objectives ; // 多目标值:[Makespan, TotalFlowTime, TotalChangeover, LoadStd, Delay]
private double[] MaxObjectives ; //
private double[] MinObjectives ; //
private int Rank; // 非支配排序等级(1最优)
private double CrowdingDistance =0; // 拥挤距离
private double CrowdingDistance =0; // 拥挤距离 越小越优
/*
*(Objectives - min) / (max - min);
*/
private double[] WeightedObjectives;//越靠近1越优
private double WeightedObjective =0; // 加权目标值(用于自定义权重)
/// <summary>
/// 适应度值
......
......@@ -41,7 +41,7 @@ public class ObjectiveWeights {
* @param minValues 各维度目标值的最小值
* @param maxValues 各维度目标值的最大值
* @param isMinimize 各维度是否为最小化目标(true:值越小越优;false:值越大越优)
* @return 归一化后目标值(范围:[0,1],无0值兜底)
* @return 归一化后目标值(范围:[0,1],无0值兜底) 越靠近1越优
*/
public double[] normalizeObjectives(double[] objectives, double[] minValues, double[] maxValues, boolean[] isMinimize) {
if (objectives == null || objectives.length == 0) {
......@@ -89,7 +89,7 @@ public class ObjectiveWeights {
}
}
// 兜底:限制范围[1e-6,1],彻底避免0值
normalized[i] = Math.max(Math.min(normalized[i], 1.0), 1e-6);
normalized[i] = Math.max(Math.min(normalized[i], 1.0), 0.0001);
}
}
return normalized;
......
......@@ -20,8 +20,8 @@ public class ScheduleParams {
private static final int MAX_MAX_ITERATIONS = 200;
private static final float MIN_CROSSOVER_PROB = 0.6f;
private static final float MAX_CROSSOVER_PROB = 0.9f;
private static final float MIN_MUTATION_PROB = 0.05f;
private static final float MAX_MUTATION_PROB = 0.2f;
private static final float MIN_MUTATION_PROB = 0.3f;
private static final float MAX_MUTATION_PROB = 0.7f;
private static final int MIN_TOURNAMENT_SIZE = 3;
private static final int MAX_TOURNAMENT_SIZE = 7;
......
......@@ -23,7 +23,7 @@ private LocalDateTime effectiveStartTime;
private LocalDateTime effectiveEndTime;
private Long referenceId;
private Integer referenceType;
private BigDecimal efficiencyCoeff;
private Double efficiencyCoeff;
private Integer minUtilization;
private Integer maxUtilization;
private String referenceName;
......
......@@ -15,7 +15,7 @@ private LocalDateTime endDate;
private String shiftWorkSchedCode;
private String periodDesc;
private Integer equipId;
private Long efficiencyCoeff;
private double efficiencyCoeff;
private Long referenceId;
private String referenceName;
private Long creatorUserId;
......
......@@ -19,7 +19,7 @@ public class Shift {
private int priority;
private boolean isSpecial;
private Integer status;//0:正常班次 1:临时班次 2:维修
private double efficiency=1;
// 添加设备ID和名称字段
private Long machineId;
private String machineName;
......
......@@ -18,10 +18,17 @@ public class TimeSegment {
private SegmentType type; // 时间段类型(关联SegmentType枚举)
private boolean isHoliday; // 是否节假日(true=节假日)
private boolean isUsed; // 是否已被占用(true=已分配任务)
private double efficiency=1;//效率
// 无参构造(Lombok默认生成)
public TimeSegment() {}
public TimeSegment(LocalDateTime start, LocalDateTime end) {
this.start = start;
this.end = end;
}
......
package com.aps.service.Algorithm;
import com.aps.entity.Algorithm.Chromosome;
import com.aps.entity.Algorithm.ObjectiveWeights;
import java.util.List;
......@@ -12,23 +13,26 @@ public class FitnessCalculator {
/**
* 多目标适应度计算(加权求和)
*/
public double calculateFitness(Chromosome chromosome) {
// 权重可根据实际需求调整
double w1 = 0.3; // 最早完工时间(越小越好,归一化后取反)
double w2 = 0.2; // 总流程时间(越小越好)
double w3 = 0.15; // 总换型时间(越小越好)
double w4 = 0.2; // 机器负载均衡(标准差越小越好)
double w5 = 0.15; // 交付期延迟(越小越好)
public double calculateFitness(Chromosome chromosome,ObjectiveWeights objectiveWeights) {
// 归一化(假设最大可能值,实际应根据问题规模调整)
double normMakespan =1/ (1 +(double) chromosome.getMakespan());
double normFlowTime = 1/ (1 + (double) chromosome.getTotalFlowTime() );
double normChangeover = 1/ (1 + (double) chromosome.getTotalChangeoverTime());
double normLoadStd = chromosome.getMachineLoadStd();
double normDelay = 1/ (1 + (double) chromosome.getDelayTime() );
double fitness=0;
for(int i=0;i<chromosome.getObjectives().length;i++)
{
// 归一化(假设最大可能值,实际应根据问题规模调整)
double val=1/ (1 +chromosome.getObjectives()[i]);
if(!objectiveWeights.isPureNSGAIIMode())
{
val=val*objectiveWeights.getWeights()[i];
}
fitness+=val;
// 1/1+1 0.5
// 1/1+2 0.3
// 1/1+3 0.25
// 值越大 归一化 后越小
}
// 适应度值(越大越好)
return w1 * normMakespan + w2 * normFlowTime + w3 * normChangeover + w4 * normLoadStd + w5 * normDelay;
return fitness;
}
/**
* 计算种群适应度标准差(用于参数微调)
......
......@@ -62,6 +62,12 @@ public class GeneticAlgorithm {
}
public Chromosome Run(ScheduleParams param, List<Entry> allOperations) {
if(allOperations==null||allOperations.size()==0)
{
throw new RuntimeException("没有待排产工单");
}
if(materials!=null&&materials.size()>0) {
materialRequirementService.init(materials, orders, allOperations, _entryRel, machineScheduler, machines,_GlobalParam);
......@@ -70,17 +76,22 @@ public class GeneticAlgorithm {
LocalDateTime starttime=LocalDateTime.now();
FileHelper.writeLogFile("排产-----------开始-----------"+allOperations.get(0).getSceneId());
Initialization initialization = new Initialization(_GlobalParam,allOperations,orders,machines);
Initialization initialization = new Initialization(_GlobalParam,allOperations,orders,machines,_objectiveWeights);
GeneticOperations geneticOps = new GeneticOperations(_GlobalParam,allOperations,param);
// 预生成全局工序列表(所有初始化方法共享同一顺序)
List<GlobalOperationInfo> globalOpList = initialization.generateGlobalOpList();
FileHelper.writeLogFile("初始化种群-----------开始-------");
Machine ms= machines.stream().filter(t->t.getName().equals("铲车-2")).findFirst().orElse(null);
// 步骤1:初始化种群
List<Chromosome> population = initialization.generateInitialPopulation(param, globalOpList);
population= chromosomeDistinct(population);
FileHelper.writeLogFile("初始化种群-----------结束-------");
FileHelper.writeLogFile("初始化批量解码-----------开始-------");
Chromosomedecode(param,allOperations,globalOpList,population);
......@@ -90,18 +101,13 @@ public class GeneticAlgorithm {
.mapToInt(GlobalOperationInfo::getGroupId)
.max()
.orElse(0);
Chromosome best=new Chromosome();
Chromosome best=GetBest(fronts,"初始");
// best=fronts.get(0).stream()
// .max(Comparator.comparingDouble(Chromosome::getFitness))
// .orElse(null);
WriteKpis(fronts,"初始");
best = fronts.get(0).stream()
.sorted((c1, c2) -> Double.compare(c2.getWeightedObjective(), c1.getWeightedObjective()))
.findFirst()
.orElse(null);
WriteKpi(best,"最大");
double bestFitness=best.getWeightedObjective();
double bestFitness=best.getFitness();
int Iteration=0;
// 步骤2:迭代进化
FileHelper.writeLogFile("迭代进化-----------开始-------"+param.getMaxIterations());
......@@ -149,13 +155,20 @@ public class GeneticAlgorithm {
FileHelper.writeLogFile("交叉操作-----------结束-------");
FileHelper.writeLogFile("变异操作-----------开始-------");
// 变异操作
List<Chromosome> nextPopulation1 = new ArrayList<>();
for (Chromosome chromosome : nextPopulation) {
if (rnd.nextDouble() < param.getMutationProb()) {
geneticOps.mutate(chromosome, globalOpList);
Chromosome chromosome1= ProductionDeepCopyUtil.deepCopy(chromosome,Chromosome.class);
geneticOps.mutate(chromosome1, globalOpList);
nextPopulation1.add(chromosome1);
}
}
nextPopulation.addAll(nextPopulation1);
FileHelper.writeLogFile("变异操作-----------结束-------");
FileHelper.writeLogFile("变异批量解码-----------开始-------");
nextPopulation= chromosomeDistinct(nextPopulation);
Chromosomedecode(param,allOperations,globalOpList,nextPopulation);
FileHelper.writeLogFile("变异批量解码-----------开始-------");
// // 精英保留
......@@ -169,6 +182,7 @@ public class GeneticAlgorithm {
List<Chromosome> newPopulation = new ArrayList<>();
newPopulation.addAll(population);
newPopulation.addAll(nextPopulation);
newPopulation= chromosomeDistinct(newPopulation);
FileHelper.writeLogFile("非支配排序-----------开始-------");
// 2.7 非支配排序
List<List<Chromosome>> combinedFronts = _nsgaIIUtils.parallelFastNonDominatedSort(newPopulation);
......@@ -181,17 +195,11 @@ public class GeneticAlgorithm {
// .collect(Collectors.toList());
fronts = _nsgaIIUtils.parallelFastNonDominatedSort(population);
WriteKpis(fronts,String.valueOf(iter));
best = fronts.get(0).stream()
.sorted((c1, c2) -> Double.compare(c2.getWeightedObjective(), c1.getWeightedObjective()))
.findFirst()
.orElse(null);
WriteKpi(best,"最大");
if(bestFitness<best.getWeightedObjective())
best= GetBest(combinedFronts,String.valueOf(iter));
if(bestFitness<best.getFitness())
{
bestFitness=best.getWeightedObjective();
bestFitness=best.getFitness();
Iteration=1;
......@@ -222,6 +230,36 @@ public class GeneticAlgorithm {
}
private Chromosome GetBest(List<List<Chromosome>> fronts,String msg)
{
WriteKpis(fronts,msg);
List<Chromosome> fChromosomes= fronts.get(0);
fChromosomes.sort((c1, c2) -> {
int rankCompare = Double.compare(c1.getCrowdingDistance(), c2.getCrowdingDistance());
return rankCompare != 0 ? rankCompare : Double.compare(c1.getFitness(), c2.getFitness());
});
Chromosome best=fChromosomes.get(0);
WriteKpi(best,"最大");
return best;
}
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 void WriteKpis(List<List<Chromosome>> fronts,String index) {
for (int i=0;i<fronts.size();i++)
{
......@@ -253,10 +291,10 @@ public class GeneticAlgorithm {
chromosome.setMachines(ProductionDeepCopyUtil.deepCopyList(machines)); // 简单拷贝,实际可能需要深拷贝
chromosome.setAllOperations(allOperations); // 简单拷贝,实际可能需要深拷贝
chromosome.setGlobalOpList(globalOpList); // 简单拷贝,实际可能需要深拷贝
//chromosome.setObjectiveWeights(_objectiveWeights);
decoder.decodeChromosomeWithCache(chromosome);
if (chromosome.getFitness() == 0) {
chromosome.setFitness(_fitnessCalculator.calculateFitness(chromosome));
chromosome.setFitness(_fitnessCalculator.calculateFitness(chromosome,_objectiveWeights));
}
});
......
......@@ -92,6 +92,7 @@ public class GeneticDecoder {
chromosome.setDelayTime(cachedResult.getDelayTime());
chromosome.setResult(ProductionDeepCopyUtil.deepCopyList(cachedResult.getResult(),GAScheduleResult.class));
// Chromosome chromosomen= ProductionDeepCopyUtil.deepCopy(cachedResult);
FileHelper.writeLogFile("解码-----------结束-------"+chromosome.getID());
return chromosome;
}
......@@ -373,7 +374,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
int setupTime = calculateSetupTime(chromosome.getResult(), operation, machine, machineOption);
FileHelper.writeLogFile(" "+operation.getGroupId()+" : "+operation.getId()+",处理时间: " + processingTime + ", 后处理: " + teardownTime +
", 前处理: " + preTime + ", 换型: " + setupTime+ ", 数量: " + operation.getQuantity()+ ", 设备: "+machine.getId());
", 前处理: " + preTime + ", 换型: " + setupTime+ ", 数量: " + operation.getQuantity()+ ", 设备: "+machine.getId()+ ", 是否可中断: "+operation.getIsInterrupt());
// 确定任务的最早开始时间(基于前一道工序的完整结束时间,包含后处理)
......@@ -429,7 +430,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
List<ScheduleResultDetail> geneDetails = machineCalculator.getNextAvailableTime(machine, earliestStartTime, -1,
processingTimeTotal, chromosome.getResult(), false, true,processingTime, operation.getQuantity(), true);
processingTimeTotal, chromosome.getResult(), operation.IsInterrupt!=1, true,processingTime, operation.getQuantity(), true);
......@@ -929,7 +930,7 @@ if(finishedOrder==null||finishedOrder.size()==0)
// 3. 最小总换型时间
double totalSetupTime = calculateTotalSetupTime(chromosome);
// 4. 最小化总流程时间
// 4. 最小化总流程时间 所有工序加工时间的总和
double totalFlowTime = calculateTotalFlowTime(chromosome);
// 5. 机器负载均衡
......@@ -969,36 +970,34 @@ if(finishedOrder==null||finishedOrder.size()==0)
// 计算机器负载均衡指标
private double calculateMachineLoadBalance(Chromosome chromosome) {
Map<Long, Double> machineUtilization = new HashMap<>();
int maxEndTime = chromosome.getResult().stream()
.mapToInt(GAScheduleResult::getEndTime)
.max()
.orElse(0);
int sumWork = chromosome.getResult().stream()
.mapToInt(GAScheduleResult::getFlowTime)
.sum();//总的加工时间
if (maxEndTime == 0) return 0;
if (sumWork == 0) return 0;
for (Machine machine : chromosome.getMachines()) {
List<GAScheduleResult> machineGenes = chromosome.getResult().stream()
double busyTime = chromosome.getResult().stream()
.filter(g -> g.getMachineId() == machine.getId())
.collect(Collectors.toList());
double busyTime = machineGenes.stream()
.mapToInt(g -> g.getEndTime() - g.getStartTime())
.mapToInt(g -> g.getFlowTime())
.sum();
machineUtilization.put(machine.getId(), busyTime / maxEndTime);
machineUtilization.put(machine.getId(), busyTime / sumWork);
}
double avgUtilization = machineUtilization.values().stream()
.mapToDouble(Double::doubleValue)
.average()
.orElse(0);
.sum()/ chromosome.getMachines().size();
double variance = machineUtilization.values().stream()
.mapToDouble(u -> Math.pow(u - avgUtilization, 2))
.sum() / chromosome.getMachines().size();
// 方差越小,负载越均衡
return 1.0 / (1 + variance);
// 标准差与平均值的比值衡量负载离散程度,值越小说明均衡度越高
return Math.sqrt(variance)/avgUtilization ;
}
/**
* 补全:创建缓存键(核心逻辑,需与原 C# CreateCacheKey 一致)
......@@ -1006,13 +1005,15 @@ if(finishedOrder==null||finishedOrder.size()==0)
*/
private String createCacheKey(Chromosome chromosome) {
return chromosome.getGeneStr();
// 拼接机器选择:用 "," 分隔(例:1,3,2,4)
String machineStr = chromosome.getMachineStr();
// String machineStr = chromosome.getMachineStr();
// 拼接工序排序:用 "|" 分隔(例:2|1|3|4)
String operationStr = chromosome.getOperationStr();
// String operationStr = chromosome.getOperationStr();
// 组合最终键(用 "_" 分隔两部分,避免冲突)
return machineStr + "_" + operationStr;
// return machineStr + "_" + operationStr;
}
}
......@@ -34,39 +34,23 @@ public class GeneticOperations {
*/
public List<Chromosome> tournamentSelection(List<Chromosome> population, int tournamentSize) {
int populationSize = population.size();
List<Chromosome> selected = new ArrayList<>(populationSize); // 预初始化容量
List<Chromosome> selected = new ArrayList<>(); // 预初始化容量
// 边界值处理:锦标赛规模不能超过种群规模,且至少为1
int effectiveTournamentSize = Math.max(1, Math.min(tournamentSize, populationSize));
while (selected.size() < populationSize) {
while (selected.size() < populationSize-tournamentSize) {
// 优化1:不复制整个种群,直接随机抽取有效锦标赛规模的个体,避免大量内存拷贝和shuffle开销
Chromosome bestCandidate = null;
int bestRank = Integer.MAX_VALUE;
double bestCrowdingDistance = -Double.MAX_VALUE;
// 优化2:单次循环随机抽取+实时比较,无需创建候选列表、无需排序,O(k)时间复杂度(k为锦标赛规模)
for (int i = 0; i < effectiveTournamentSize; i++) {
// 随机获取一个种群个体(直接通过索引访问,无需打乱整个列表)
int randomIndex = rnd.nextInt(populationSize);
Chromosome current = population.get(randomIndex);
// 优化3:手动实现排序逻辑的比较,避免Stream API的额外开销
if (bestCandidate == null) {
bestCandidate = current;
bestRank = current.getRank();
bestCrowdingDistance = current.getCrowdingDistance();
} else {
// 先比较Rank(升序:Rank越小越优)
if (current.getRank() < bestRank) {
updateBestCandidate(current, bestCandidate, bestRank, bestCrowdingDistance);
} else if (current.getRank() == bestRank) {
// Rank相同时,比较拥挤距离(降序:值越大越优)
if (current.getCrowdingDistance() > bestCrowdingDistance) {
updateBestCandidate(current, bestCandidate, bestRank, bestCrowdingDistance);
}
}
}
}
Collections.shuffle(population, new Random());//随机排序
int endIndex = Math.min(effectiveTournamentSize, population.size());
List<Chromosome> chromosomes=population.subList(0, endIndex);
chromosomes.sort((c1, c2) -> {
int rankCompare = Integer.compare(c1.getRank(), c2.getRank());
return rankCompare != 0 ? rankCompare : Double.compare(c1.getCrowdingDistance(), c2.getCrowdingDistance());
});
Chromosome bestCandidate = chromosomes.get(0);
// 深拷贝最优个体并加入选中列表(确保线程安全和种群独立性)
if (bestCandidate != null) {
......@@ -75,12 +59,7 @@ public class GeneticOperations {
}
return selected;
}
private void updateBestCandidate(Chromosome current, Chromosome bestCandidate,
int bestRank, double bestCrowdingDistance) {
bestRank = current.getRank();
bestCrowdingDistance = current.getCrowdingDistance();
bestCandidate = current;
}
// 重载,使用默认锦标赛大小3
public List<Chromosome> tournamentSelection(List<Chromosome> population) {
return tournamentSelection(population, param.getTournamentSize());
......@@ -239,25 +218,33 @@ public class GeneticOperations {
* 变异操作
*/
public void mutate(Chromosome chromosome, List<GlobalOperationInfo> globalOpList, double baseMutationProb) {
int i= rnd.nextInt(2);
if(i==0) {
// 1. 机器选择部分变异
mutateMachineSelection(chromosome, globalOpList, baseMutationProb);
boolean state= mutateMachineSelection(chromosome, globalOpList, baseMutationProb);
if(!state)
{
i=1;
}
}
if(i==1) {
// 2. 工序排序部分变异
mutateOperationSequencing(chromosome);
}
}
// 重载,使用默认变异概率
public void mutate(Chromosome chromosome, List<GlobalOperationInfo> globalOpList) {
mutate(chromosome, globalOpList, 0.1);
}
private void mutateMachineSelection(Chromosome chromosome, List<GlobalOperationInfo> globalOpList, double baseMutationProb) {
private boolean mutateMachineSelection(Chromosome chromosome, List<GlobalOperationInfo> globalOpList, double baseMutationProb) {
// 计算变异位置数量
List<Entry> entrys= allOperations.stream().filter(t->t.getMachineOptions().size()>1).collect(Collectors.toList());
if(entrys==null||entrys.size()==0)
{
return;
return false;
}
Integer count=entrys.size();
int r = Math.max(1, (int) (count * baseMutationProb));
......@@ -291,6 +278,7 @@ public class GeneticOperations {
i++;
}
return true;
}
/**
......
......@@ -3,6 +3,7 @@ package com.aps.service.Algorithm;
import com.aps.common.util.ProductionDeepCopyUtil;
import com.aps.entity.Algorithm.Chromosome;
import com.aps.entity.Algorithm.GlobalOperationInfo;
import com.aps.entity.Algorithm.ObjectiveWeights;
import com.aps.entity.Algorithm.ScheduleParams;
import com.aps.entity.basic.*;
......@@ -22,11 +23,14 @@ public class Initialization {
private static List<Machine> machines;
public Initialization(GlobalParam globalParam,List<Entry> allOperations,List<Order> _orders,List<Machine> _machines) {
private ObjectiveWeights _objectiveWeights = new ObjectiveWeights();
public Initialization(GlobalParam globalParam,List<Entry> allOperations,List<Order> _orders,List<Machine> _machines,ObjectiveWeights objectiveWeights) {
Initialization.allOperations = allOperations;
_globalParam= globalParam;
orders=_orders;
machines=_machines;
_objectiveWeights= objectiveWeights;
}
/**
* 预生成全局工序列表(按“订单0→订单1→…+订单内工序1→2→…”排序,分配GlobalOpId)
......@@ -60,6 +64,7 @@ int populationSize=param.getPopulationSize();
.parallel() // 开启并行
.forEach(i -> {
Chromosome chromo = new Chromosome(); // 初始化染色体
// chromo.setObjectiveWeights(_objectiveWeights);
chromo.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines));
chromo.setOrders(orders);
// 全局选择(GS):按GlobalOpId顺序生成MachineSelection
......
......@@ -54,7 +54,7 @@ public class MachineCalculator {
// 查找合适的班次窗口
return findEarliestStart(machine, processingTime, startTime, prevtimestr,
existingTasks, oneTime, quantity, istask, islockMachineTime);
existingTasks, oneTime, quantity, istask, islockMachineTime,isInterrupt);
}
......@@ -63,7 +63,7 @@ public class MachineCalculator {
private List<ScheduleResultDetail> findEarliestStart(
Machine machine, int processingTime, LocalDateTime currentTime,
String prevtime, List<GAScheduleResult> existingTasks,double oneTime,double quantity, boolean checkprevtime, boolean islockMachineTime
) {
,boolean isInterrupt) {
List<GAScheduleResult> machineTasks = existingTasks.stream()
.filter(t -> t.getMachineId() == machine.getId())
.sorted(Comparator.comparingInt(GAScheduleResult::getStartTime))
......@@ -81,7 +81,7 @@ public class MachineCalculator {
LocalDateTime endCandidate = startCandidate.plusSeconds(processingTime);
if (endCandidate.isAfter(slot.getEnd())) {
return CaldEarliestStart(machine, processingTime, currentTime, prevtime, machineTasks,oneTime,quantity, checkprevtime,islockMachineTime);
return CaldEarliestStart(machine, processingTime, currentTime, prevtime, machineTasks,oneTime,quantity, checkprevtime,islockMachineTime,isInterrupt);
} else {
ScheduleResultDetail time = new ScheduleResultDetail();
time.setKey(slot.getKey());
......@@ -98,7 +98,7 @@ public class MachineCalculator {
}
private List<ScheduleResultDetail> CaldEarliestStart(
private List<ScheduleResultDetail> CaldEarliestStart1(
Machine machine, int processingTime, LocalDateTime currentTime,
String prevtime, List<GAScheduleResult> machineTasks,double oneTime,double quantity, boolean checkprevtime, boolean islockMachineTime
) {
......@@ -171,6 +171,372 @@ public class MachineCalculator {
return times;
}
private List<ScheduleResultDetail> CaldEarliestStart(
Machine machine, int processingTime, LocalDateTime currentTime,
String prevtime, List<GAScheduleResult> machineTasks,double oneTime,double quantity, boolean checkprevtime, boolean islockMachineTime
,boolean isInterrupt) {
int remainingTime = processingTime;
LocalDateTime st = StringUtils.isEmpty(prevtime) ? currentTime : LocalDateTime.parse(prevtime);
LocalDateTime prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
List<ScheduleResultDetail> times = new ArrayList<>();
List<ScheduleResultDetail> oldTimes = new ArrayList<>();
List<TimeSegment> timeSegments= findAvailableSegments(machine, currentTime, machineTasks, remainingTime, isInterrupt);
int i=0;
while (remainingTime > 0) {
TimeSegment shift= timeSegments.get(i);
if (shift == null) break;
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;
currentTime = effectiveStart.plusSeconds(availableSeconds/availableSeconds_e*processable);
// 添加时间详情
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);
times.add(time);
// 还原未使用的时间段
RemoveMachineAvailable(machine, time);
i++;
}
return times;
}
/**
* 查找满足时长要求的无冲突可用时段(对应原C#方法)
* @param machine 设备
* @param start 起始时间
* @param machineTasks 设备已有任务
* @param requiredMinutes 工单所需总时长(分钟)
* @param requireContinuous 是否不可中断(true=不可中断)
* @return 满足条件的可用片段列表
*/
private List<TimeSegment> findAvailableSegments(
Machine machine,
LocalDateTime start,
List<GAScheduleResult> machineTasks,
double requiredMinutes,
boolean requireContinuous) {
List<TimeSegment> availableSegments = new ArrayList<>();
LocalDateTime current = start;
// 预先排序设备可用片段,避免后续遍历混乱
List<TimeSegment> allUseTimeSegment = machine.getAvailability().stream()
.filter(slot -> !slot.isUsed() && slot.getType() != SegmentType.MAINTENANCE)
.sorted(Comparator.comparing(TimeSegment::getStart, (a, b) -> a.compareTo(b)))
.collect(Collectors.toList());
// 替换while(true),增加明确退出条件(原逻辑保留,可根据业务补充退出判断)
while (true) {
// 统一过滤逻辑:消除重复的FindAll代码
List<TimeSegment> useSegments = filterValidUseSegments(machine.getAvailability(), current, requireContinuous, requiredMinutes);
if (useSegments != null && !useSegments.isEmpty()) {
// 计算可用时间总和(保留原有逻辑)
double totalUseTime = calculateTotalAvailableSecond(useSegments, current);
// 不足所需时长时,自动生成未来片段并补充
while (totalUseTime < requiredMinutes) {
// 生成未来1天的片段(基于当前可用片段的最大结束时间)
LocalDateTime lastSegmentEnd = machine.getAvailability().stream()
.max(Comparator.comparing(TimeSegment::getEnd, (a, b) -> a.compareTo(b)))
.map(TimeSegment::getEnd)
.orElse(current);
List<TimeSegment> newSegments = machineScheduler.generateTimeSegment(machine, lastSegmentEnd.plusDays(1));
addSegmentsWithDeduplication(machine, newSegments);
// 重新过滤可用片段
useSegments = filterValidUseSegments(machine.getAvailability(), current, requireContinuous, requiredMinutes);
// 重新计算总可用时间
totalUseTime = calculateTotalAvailableSecond(useSegments, current);
}
// 若总可用时间满足要求,处理冲突
if (totalUseTime >= requiredMinutes) {
// 获取当前可用片段范围内的冲突
LocalDateTime firstSegmentStart = useSegments.get(0).getStart();
LocalDateTime lastSegmentEnd = useSegments.get(useSegments.size() - 1).getEnd();
List<TimeSegment> conflictSegments = getConflictIntervals(machine, machineTasks, firstSegmentStart, lastSegmentEnd);
if (conflictSegments == null || conflictSegments.isEmpty()) {
// 无冲突:直接返回可用片段(保留原有逻辑)
if (useSegments.get(0).getStart().compareTo(current) < 0) {
spiltMachineAvailable(machine, useSegments.get(0), current);
useSegments.get(0).setStart(current);
}
return useSegments;
} else {
// 有冲突:可选返回冲突前足够片段或跳过冲突
List<TimeSegment> resultSegments = handleConflictsWithSumLogic(useSegments, conflictSegments, current, requiredMinutes);
if (resultSegments != null && !resultSegments.isEmpty()) {
if (resultSegments.get(0).getStart().compareTo(current) < 0) {
spiltMachineAvailable(machine, resultSegments.get(0), current);
resultSegments.get(0).setStart(current);
}
return resultSegments;
} else {
// 冲突前片段不足,重置current为最后一个冲突的结束时间,重新查找
LocalDateTime lastConflictEnd = conflictSegments.stream()
.max(Comparator.comparing(TimeSegment::getEnd, (a, b) -> a.compareTo(b)))
.map(TimeSegment::getEnd)
.orElse(current);
current = lastConflictEnd;
}
}
}
} else {
// 无可用片段时,生成未来1天的片段
LocalDateTime lastSegmentEnd = machine.getAvailability().stream()
.max(Comparator.comparing(TimeSegment::getEnd, (a, b) -> a.compareTo(b)))
.map(TimeSegment::getEnd)
.orElse(current);
List<TimeSegment> newSegments = machineScheduler.generateTimeSegment(machine, lastSegmentEnd.plusDays(1));
addSegmentsWithDeduplication(machine, newSegments);
}
}
}
/**
* 统一过滤有效可用片段
*/
private List<TimeSegment> filterValidUseSegments(List<TimeSegment> allSegments,
LocalDateTime currentTime,
boolean requireContinuous,
double requiredMinutes) {
// 空判断:对应C#的 allSegments == null || allSegments.Count == 0
if (allSegments == null || allSegments.isEmpty()) {
return new ArrayList<>();
}
// 统一过滤条件
List<TimeSegment> baseValidSegments = allSegments.stream()
.filter(slot -> !slot.isUsed() // 对应 !slot.IsUsed
&& slot.getType() != SegmentType.MAINTENANCE // 对应 slot.Type != SegmentType.Maintenance
&& slot.getEnd().compareTo(currentTime) > 0) // 对应 slot.End > currentTime
.collect(Collectors.toList());
// 无需不可中断或所需时长无效时,直接返回基础有效片段
if (!requireContinuous || requiredMinutes <= 0) {
return baseValidSegments;
}
// 要求不可中断时,过滤符合连续时长要求的片段
return filterContinuousCompliantSegments(baseValidSegments, currentTime, requiredMinutes);
}
/**
* 计算可用片段的总有效时长
* @param useSegments 可用片段列表
* @param currentTime 当前时间
* @return 总可用时长(分钟)
*/
private double calculateTotalAvailableSecond(List<TimeSegment> useSegments, LocalDateTime currentTime) {
// 空判断:
if (useSegments == null || useSegments.size()==0) {
return 0.0;
}
return useSegments.stream()
.mapToDouble(segment -> {
// 取片段起始时间和当前时间的最大值,对应C#的 t.Start < currentTime ? currentTime : t.Start
LocalDateTime effectiveStart = segment.getStart().compareTo(currentTime) < 0 ? currentTime : segment.getStart();
// 计算单个片段的有效时长(分钟),并乘以效率值,对应C#的 (t.End - effectiveStart).TotalMinutes * t.Efficiency
double segmentSeconds =ChronoUnit.SECONDS.between(effectiveStart, segment.getEnd());
return segmentSeconds * segment.getEfficiency();
})
.sum(); // 累加所有片段的有效时长
}
/**
* 辅助方法:过滤出满足连续时长要求的片段(仅不可中断配置生效时调用)
* 前置剔除零散无效片段,减少后续逻辑处理量
*/
private List<TimeSegment> filterContinuousCompliantSegments(
List<TimeSegment> baseValidSegments,
LocalDateTime currentTime,
double requiredContinuous) {
// 空判断:对应C#的 baseValidSegments.Count == 0
if (baseValidSegments == null || baseValidSegments.isEmpty()) {
return new ArrayList<>();
}
List<TimeSegment> continuousCompliantSegments = new ArrayList<>();
List<TimeSegment> tempContinuousGroup = new ArrayList<>();
double tempContinuous = 0.0;
LocalDateTime lastSegmentEnd = currentTime;
// 遍历基础有效片段,筛选出可拼接成连续时长的片段组(对应C#的foreach)
for (TimeSegment segment : baseValidSegments) {
// 确定有效起始时间:对应C#的三元表达式 segment.Start > currentTime ? segment.Start : currentTime
LocalDateTime effectiveStart = segment.getStart().compareTo(currentTime) > 0 ? segment.getStart() : currentTime;
if (effectiveStart.compareTo(segment.getEnd()) >= 0) {
// 该片段无有效时长,跳过
continue;
}
// 判断是否与临时连续组无缝衔接
if (!tempContinuousGroup.isEmpty() && effectiveStart.compareTo(lastSegmentEnd) != 0) {
// 不衔接:先判断临时组是否满足连续时长,满足则加入结果
if (tempContinuous >= requiredContinuous) {
continuousCompliantSegments.addAll(tempContinuousGroup); // 对应C#的AddRange
}
// 重置临时组
tempContinuousGroup.clear();
tempContinuous = 0.0;
}
// 加入临时连续组,累加时长
tempContinuousGroup.add(segment);
// 计算当前片段有效时长(分钟)并累加
double segmentEffective = ChronoUnit.SECONDS.between(effectiveStart, segment.getEnd()) * segment.getEfficiency();
tempContinuous += segmentEffective;
// 更新最后一个片段结束时间(加1秒)
lastSegmentEnd = segment.getEnd().plusSeconds(1);
// 临时组满足连续时长,直接加入结果(提前终止当前组遍历)
if (tempContinuous >= requiredContinuous) {
continuousCompliantSegments.addAll(tempContinuousGroup);
// 可选择是否继续遍历(此处继续,获取所有符合条件的片段;也可break直接返回第一个组)
tempContinuousGroup.clear();
tempContinuous = 0.0;
}
}
// 遍历结束后,检查最后一个临时组是否满足连续时长
if (tempContinuous >= requiredContinuous) {
continuousCompliantSegments.addAll(tempContinuousGroup);
}
// 去重并排序(避免重复片段),对应C#的MergeSegments方法
return MergeSegments(continuousCompliantSegments);
}
/**
* 批量获取冲突区间(优化边界判断,更严谨)
* 依赖:Machine、ScheduleResult、TimeSegment、DateTime 类(已在前序代码中定义,需补充部分属性)
*/
private List<TimeSegment> getConflictIntervals(
Machine machine,
List<GAScheduleResult> machineTasks,
LocalDateTime start,
LocalDateTime end) {
List<TimeSegment> conflictIntervals = new ArrayList<>();
// 1. 维护窗口冲突(优化重叠判断,更严谨)
if (machine.getMaintenanceWindows() != null && !machine.getMaintenanceWindows().isEmpty()) {
// 过滤重叠的维护窗口并转换为TimeSegment
List<TimeSegment> maintenanceConflicts = machine.getMaintenanceWindows().stream()
// 正确的重叠判断:w.StartTime < end && w.EndTime > start
.filter(w -> w.getStartTime().compareTo(end) < 0 && w.getEndTime().compareTo(start) > 0)
// 转换为TimeSegment对象
.map(w -> new TimeSegment(w.getStartTime(), w.getEndTime()))
.collect(Collectors.toList());
// 批量添加冲突片段
conflictIntervals.addAll(maintenanceConflicts);
}
// 2. 已有任务冲突
if (machineTasks != null && machineTasks.size()>0) {
// 第一步:转换任务为TimeSegment并过滤重叠冲突
List<TimeSegment> taskConflicts = machineTasks.stream()
.map(w -> {
// 计算任务起始和结束时间:baseTime.AddMinutes(w.StartTime)/w.EndTime
LocalDateTime taskStart = baseTime.plusSeconds(w.getStartTime());
LocalDateTime taskEnd = baseTime.plusSeconds(w.getEndTime());
return new TimeSegment(taskStart, taskEnd);
})
// 正确的重叠判断:t.Start < end && t.End > start
.filter(t -> t.getStart().compareTo(end) < 0 && t.getEnd().compareTo(start) > 0)
.collect(Collectors.toList());
// 批量添加任务冲突片段
conflictIntervals.addAll(taskConflicts);
}
// 按开始时间排序
return conflictIntervals.stream()
.sorted(Comparator.comparing(TimeSegment::getStart, Comparator.nullsLast(LocalDateTime::compareTo)))
.collect(Collectors.toList());
}
/**
* 按总和逻辑处理冲突(保留原有冲突处理逻辑,优化严谨性)
* @param useSegments 可用片段列表
* @param conflictSegments 冲突片段列表
* @param currentTime 当前时间
* @param requiredMinutes 所需总时长(分钟)
* @return 满足条件的片段列表,无满足条件时返回null
*/
private List<TimeSegment> handleConflictsWithSumLogic(
List<TimeSegment> useSegments,
List<TimeSegment> conflictSegments,
LocalDateTime currentTime,
double requiredMinutes) {
// 遍历所有冲突片段,对应C#的foreach循环
for (TimeSegment conflict : conflictSegments) {
LocalDateTime currentTime1=currentTime;
// 过滤冲突前的可用片段(
List<TimeSegment> preConflictSegments = useSegments.stream()
.filter(slot ->
(slot.getStart().compareTo(currentTime1) >= 0 || slot.getEnd().compareTo(currentTime1) > 0)
&& slot.getEnd().compareTo(conflict.getStart()) <= 0
)
.collect(Collectors.toList());
// 计算冲突前片段的总可用时长
double preConflictTotalTime = calculateTotalAvailableSecond(preConflictSegments, currentTime);
// 冲突前时长超过所需时长则返回(保留原有判断逻辑),否则更新当前时间跳过冲突
if (preConflictTotalTime > requiredMinutes) {
return preConflictSegments;
} else {
//更新当前时间为冲突结束时间+1秒
currentTime = conflict.getEnd().plusSeconds(1);
}
}
// 所有冲突前片段均不足所需时长,返回null(与原C#逻辑一致)
return null;
}
/**
* 追加片段并去重、排序(避免冗余片段和遍历混乱)
*/
private void addSegmentsWithDeduplication(Machine machine, List<TimeSegment> newSegments) {
// 空判断:新片段为null或空集合时直接返回,对应C#的 newSegments == null || newSegments.Count == 0
if (newSegments == null || newSegments.isEmpty()) {
return;
}
// 追加新片段,对应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) {
LocalDateTime finalPrevEnd = prevEnd;
boolean hasTask = machineTasks.stream()
......@@ -484,6 +850,46 @@ public class MachineCalculator {
machine.setAvailability(MergeSegments(machine.getAvailability()));
}
/**
* 分割设备可用时间段
* @param machine 设备实例
* @param timeSegment 待分割的时间片段
* @param start 分割起始时间
*/
private void spiltMachineAvailable(Machine machine, TimeSegment timeSegment, LocalDateTime start) {
List<TimeSegment> timeSegments = new ArrayList<>();
// 查找待分割片段在设备可用列表中的索引,对应C#的 FindIndex
int inx = machine.getAvailability().stream()
.filter(t -> t.getKey().equals(timeSegment.getKey()))
.findFirst()
.map(machine.getAvailability()::indexOf)
.orElse(-1);
if (inx > -1) {
// 创建分割后的前半段时间片段,对应原C#逻辑
TimeSegment time = new TimeSegment();
time.setStart(timeSegment.getStart());
// 对应C#的 start.AddSeconds(-1)
time.setEnd(start.plusSeconds(-1));
time.setHoliday(false); // 对应C#的 IsHoliday = false
// 对应C#的 Guid.NewGuid().ToString(),生成唯一标识
time.setKey(UUID.randomUUID().toString());
time.setType(SegmentType.REGULAR);
time.setUsed(false); // 对应C#的 IsUsed = false
timeSegments.add(time);
// 更新原片段的起始时间为分割时间,对应C#的 machine.Availability[inx].Start = start
machine.getAvailability().get(inx).setStart(start);
}
// 批量添加分割后的片段(空判断优化,符合Java规范)
if (timeSegments != null && !timeSegments.isEmpty()) {
machine.getAvailability().addAll(timeSegments);
}
// 按起始时间排序,对应C#的 Sort((a, b) => a.Start.CompareTo(b.Start))
machine.getAvailability().sort((a, b) -> a.getStart().compareTo(b.getStart()));
}
private List<TimeSegment> MergeSegments(List<TimeSegment> segments) {
List<TimeSegment> maintenanceSegments = segments.stream()
......
package com.aps.service.Algorithm;
import com.aps.common.util.GlobalCacheUtil;
import com.aps.common.util.SnowFlackIdWorker;
import com.aps.common.util.redis.RedisUtils;
import com.aps.entity.*;
import com.aps.entity.Algorithm.BOMBuildResult;
import com.aps.entity.Algorithm.IDAndChildID.GroupResult;
......@@ -54,6 +56,8 @@ public class MaterialRequirementService {
@Autowired
RoutingDetailConnectService routingDetailConnectService;
@Autowired
private RedisUtils redisUtils;
private List<Order> orders;
......@@ -153,7 +157,7 @@ if(routingIds.size()==0)
allRequirements.addAll(result.getMaterialRequirements());
childorders.addAll(result.getChildOrders());
_newEntrys.addAll(result.getNewEntrys());
// _newMachines.addAll(result.getNewMachines());
_newMachines.addAll(result.getNewMachines());
}
......@@ -163,10 +167,10 @@ if(routingIds.size()==0)
orders.addAll(childorders);
// _allOperations.addAll(_newEntrys);
Set<Long> existIds = new HashSet<>();
// _Machines.addAll(_newMachines.stream()
// .filter(t->existIds.add(t.getId()))//HashSet.add() 方法:添加成功返回 true,重复返回 false;
// .collect(Collectors.toList()));
_Machines.addAll(_newMachines);
_Machines=_Machines.stream()
.filter(t->existIds.add(t.getId()))//HashSet.add() 方法:添加成功返回 true,重复返回 false;
.collect(Collectors.toList());
}
return allRequirements;
......@@ -227,7 +231,7 @@ if(routingIds.size()==0)
materialRequirements.addAll(operationResult.getMaterialRequirements());
childorders2.addAll(operationResult.getChildOrders());
_newEntrys.addAll(operationResult.getNewEntrys());
// _newMachines.addAll(operationResult.getNewMachines());
_newMachines.addAll(operationResult.getNewMachines());
}
}
}
......@@ -369,9 +373,25 @@ if(routingIds.size()==0)
ProdLaunchOrders.add(order);
Map<Integer, Object> list=_routingDataService.CreateEntry( sceneId, ProdEquipmentList, ProdLaunchOrders, routingDiscreteParams, ProdOrderProcesslist, processExecList,_entryRel,finishOpertionID );
List<Machine> machines=new ArrayList<>();
List<Machine> allmachines = (List<Machine>) GlobalCacheUtil.get("machines");
if (allmachines == null || allmachines.size() == 0) {
allmachines = (List<Machine>) redisUtils.get("machines");
if (allmachines == null || allmachines.size() == 0) {
List<Long> equipIds = ProdEquipmentList.stream()
.map(ProdEquipment::getEquipId)
.distinct() // 提取Exec_ID
.collect(Collectors.toList());
machines=allmachines.stream().filter(t->equipIds.contains(t.getId())).collect(Collectors.toList());
}
// List<Machine> machines= _routingDataService.InitCalendarToAllMachines(sceneId,ProdEquipmentList,machineScheduler, globalParam.isIsUseCalendar());
}
if (machines == null || machines.size() == 0) {
machines= _routingDataService.InitCalendarToAllMachines(sceneId,ProdEquipmentList,machineScheduler, globalParam.isIsUseCalendar());
}
if(list.get(1)!=null)
{
......@@ -380,7 +400,7 @@ if(routingIds.size()==0)
}
Map<Integer, Object> rest=new HashMap<>();
rest.put(1,list.get(1));
// rest.put(2,machines);
rest.put(2,machines);
return rest;
}
......@@ -606,7 +626,7 @@ if(routingIds.size()==0)
_childorders.add(childorder);
List<Entry> newentrys=(List<Entry>)list.get(1);
_newEntrys.addAll(newentrys);
// _newMachines.addAll((List<Machine>)list.get(2));
_newMachines.addAll((List<Machine>)list.get(2));
orderMaterial.getProductOrderID().add(childorder.getId());
operation.getDependentOnOrderIds().add(childorder.getId());
// 递归构建BOM
......@@ -617,7 +637,7 @@ if(routingIds.size()==0)
materialRequirements.addAll(childResult.getMaterialRequirements());
_childorders.addAll(childResult.getChildOrders());
_newEntrys.addAll(childResult.getNewEntrys());
// _newMachines.addAll(childResult.getNewMachines());
_newMachines.addAll(childResult.getNewMachines());
}
}
}
......
......@@ -19,6 +19,15 @@ public class NSGAIIUtils {
private ObjectiveWeights objectiveWeights;
private int taskCount; // 并行任务数(默认=CPU核心数)
// true 越小越好
private boolean[] isMinimize = {true, true, true, true, true};
public void init(ObjectiveWeights weights, int taskCount,boolean[] isMinimize) {
this.objectiveWeights = (weights != null) ? weights : new ObjectiveWeights();
this.taskCount = (taskCount > 0) ? taskCount : Runtime.getRuntime().availableProcessors();
this.isMinimize=isMinimize;
}
/**
* 初始化(设置权重和并行任务数)
*/
......@@ -40,16 +49,14 @@ public class NSGAIIUtils {
*/
public List<List<Chromosome>> parallelFastNonDominatedSort(List<Chromosome> population) {
int popSize = population.size();
List<List<Chromosome>> fronts = new ArrayList<>();
if (popSize <= taskCount * 10) { // 小规模种群直接串行
// 步骤1:预处理 - 计算归一化目标值和加权目标值
preprocessObjectives(population);
return fastNonDominatedSort(population);
}
if (popSize <= taskCount * 10) { // 小规模种群直接串行
fronts = fastNonDominatedSort(population);
} else {
// 步骤1:预处理 - 计算归一化目标值和加权目标值
preprocessObjectives(population);
// 步骤2:拆分种群为多个块,并行计算支配关系
List<List<Chromosome>> chunks = splitPopulation(population, taskCount);
......@@ -78,12 +85,12 @@ public class NSGAIIUtils {
});
// 步骤3:生成前沿
List<List<Chromosome>> fronts = new ArrayList<>();
List<Chromosome> front1 = new ArrayList<>();
for (Chromosome p : population) {
if (dominatedCount.get(p).get() == 0) {
p.setRank(1);
front1.add(p);
}
}
......@@ -97,7 +104,7 @@ public class NSGAIIUtils {
for (Chromosome q : dominanceMatrix.get(p)) {
AtomicInteger count = dominatedCount.get(q);
if (count.decrementAndGet() == 0) {
q.setRank(i + 2);
nextFront.add(q);
}
}
......@@ -107,10 +114,36 @@ public class NSGAIIUtils {
fronts.add(nextFront);
}
}
}
assignRankToSolutions(fronts);
return fronts;
}
/**
* 用Stream API为分层后的解批量赋值Rank
*/
public void assignRankToSolutions(List<List<Chromosome>> result) {
if (result == null || result.isEmpty()) {
return;
}
// 遍历外层List,同时获取索引和对应的解列表
IntStream.range(0, result.size()).forEach(i -> {
int rank = i + 1;
List<Chromosome> solutionsInRank = result.get(i);
if(solutionsInRank!=null&&solutionsInRank.size()>0)
{
solutionsInRank.stream()
.filter(Objects::nonNull) // 过滤null的Solution
.forEach(solution -> solution.setRank(rank));
if(solutionsInRank.size()>1) {
parallelCalculateCrowdingDistance(solutionsInRank);
}
}
});
}
/**
......@@ -118,36 +151,42 @@ public class NSGAIIUtils {
*/
public List<List<Chromosome>> fastNonDominatedSort(List<Chromosome> population) {
// 1. 初始化数据结构:S(被支配集合)、n(支配数)
//当前解能支配的其他解的集合。
Map<Chromosome, List<Chromosome>> S = new HashMap<>();
//能支配当前解的其他解的数量;
Map<Chromosome, Integer> n = new HashMap<>();
List<List<Chromosome>> fronts = new ArrayList<>();
// 为每个个体预先初始化 S 和 n
for (Chromosome p : population) {
S.put(p, new ArrayList<>()); // 初始化空集合,避免null
n.put(p, 0); // 支配数初始化为0
S.put(p, new ArrayList<>()); // 初始化空集合,避免null 当前解能支配的其他解的集合
n.put(p, 0); // 支配数初始化为0 。能支配当前解的其他解的数量
}
//S 当前解能支配的其他解的集合。
//n 能支配当前解的其他解的数量;
// 2. 计算每个个体的支配关系
for (Chromosome p : population) {
for (Chromosome q : population) {
if (p == q) continue;
for (Chromosome s1 : population) {
for (Chromosome s2 : population) {
if (s1 == s2) continue;
// p.getWeightedObjective() < q.getWeightedObjective();
if (dominates(p, q)) {
// p支配q,将q加入p的被支配集合S
S.get(p).add(q);
} else if (dominates(q, p)) {
// q支配p,增加p的支配数n
n.put(p, n.get(p) + 1);
//【0,1】 越靠近1 越好
if (dominates(s1, s2)) {
//s1支配s2 → 更新s1的被支配集合,s2的支配数+1
S.get(s1).add(s2);
} else if (dominates(s2, s1)) {
// s2支配s1 → s1的被支配数+1(避免重复计算)
n.put(s1, n.get(s1) + 1);
}
}
// 3. 初始化第一前沿(支配数为0的个体)
if (n.get(p) == 0) {
if (n.get(s1) == 0) {
if (fronts.isEmpty()) {
fronts.add(new ArrayList<>());
}
fronts.get(0).add(p);
// s1.setRank(1);
fronts.get(0).add(s1);
}
}
......@@ -160,6 +199,7 @@ public class NSGAIIUtils {
for (Chromosome q : S.get(p)) {
n.put(q, n.get(q) - 1);
if (n.get(q) == 0) {
nextFront.add(q);
}
}
......@@ -170,27 +210,32 @@ public class NSGAIIUtils {
return fronts;
}
/**
* 预处理目标值(归一化+加权)
*/
private void preprocessObjectives(List<Chromosome> population) {
int kpisize = population.get(0).getObjectives().length;
// 计算每个目标的最大/最小值
double[] minValues = new double[5];
double[] maxValues = new double[5];
for (int i = 0; i < 5; i++) {
double[] minValues = new double[kpisize];
double[] maxValues = new double[kpisize];
for (int i = 0; i < kpisize; i++) {
final int idx = i;
minValues[i] = population.stream().mapToDouble(c -> c.getObjectives()[idx]).min().orElse(0);
maxValues[i] = population.stream().mapToDouble(c -> c.getObjectives()[idx]).max().orElse(0);
}
boolean[] isMinimize = {true, true, true, false, true};
// 并行计算归一化和加权目标值
population.parallelStream().forEach(chromo -> {
double[] normalized = objectiveWeights.normalizeObjectives(chromo.getObjectives(), minValues, maxValues,isMinimize);
double[] normalized = objectiveWeights.normalizeObjectives(chromo.getObjectives(), minValues, maxValues,this.isMinimize);
chromo.setMaxObjectives(maxValues);
chromo.setMinObjectives(minValues);
chromo.setWeightedObjectives(normalized);
if (objectiveWeights.isPureNSGAIIMode()) {
chromo.setWeightedObjective(objectiveWeights.calculateObjective(normalized));
}else {
} else {
chromo.setWeightedObjective(objectiveWeights.calculateWeightedObjective(normalized));
}
});
......@@ -212,42 +257,55 @@ public class NSGAIIUtils {
}
/**
* 判断p是否支配q(支持自定义权重)
*/
public boolean dominates(Chromosome p, Chromosome q) {
// 纯NSGA-II模式:标准帕累托支配
double[] pObjectives = p.getWeightedObjectives();
double[] qObjectives = q.getWeightedObjectives();
if (objectiveWeights.isPureNSGAIIMode()) {
boolean allBetterOrEqual = true;
boolean oneBetter = false;
boolean hasBetter = false; // 是否至少有一个目标更优
boolean hasWorse = false; // 是否有任何一个目标更差
double[] pObjectives = p.getObjectives();
double[] qObjectives = q.getObjectives();
for (int i = 0; i < pObjectives.length; i++) {
if (pObjectives[i] > qObjectives[i]) {
allBetterOrEqual = false;
break;
} else if (pObjectives[i] < qObjectives[i]) {
oneBetter = true;
double thisObj = pObjectives[i];
double otherObj = qObjectives[i];
// 目标越大越好:当前解 > 另一个解 → 更优
if (thisObj > otherObj) {
hasBetter = true;
}
// 当前解 < 另一个解 → 更差
else if (thisObj < otherObj) {
hasWorse = true;
}
}
return allBetterOrEqual && oneBetter;
return hasBetter && !hasWorse;
}
// 加权NSGA-II模式:融合权重的支配关系
else {
// 方式1:加权目标值更小则支配(简单高效)
return p.getWeightedObjective() < q.getWeightedObjective();
// 方式2(可选):加权后的帕累托支配
// double pWeightedSum = 0, qWeightedSum = 0;
// for (int i = 0; i < p.getObjectives().length; i++) {
// pWeightedSum += p.getObjectives()[i] * objectiveWeights.getWeights()[i];
// qWeightedSum += q.getObjectives()[i] * objectiveWeights.getWeights()[i];
// }
// return pWeightedSum < qWeightedSum;
// 方式1:加权目标值更大则支配(简单高效)
//WeightedObjective 已计算,归一法【0,1】,越靠近1 越好
double thisScore = p.getWeightedObjective();
double otherScore = q.getWeightedObjective();
// - 加权得分严格更优;
// - 至少一个权重>0的目标上不劣于对方(避免极端情况)
boolean hasBetterScore = thisScore > otherScore;
boolean hasAtLeastOneNotWorse = false;
for (int i = 0; i < p.getObjectives().length; i++) {
if (objectiveWeights.getWeights()[i] <= 0) continue; // 跳过权重为0的目标
double thisObj = pObjectives[i];
double otherObj = qObjectives[i];
if (thisObj >= otherObj) {
hasAtLeastOneNotWorse = true;
break;
}
}
return hasBetterScore && hasAtLeastOneNotWorse;
}
}
......@@ -257,39 +315,67 @@ public class NSGAIIUtils {
public void parallelCalculateCrowdingDistance(List<Chromosome> front) {
if (front.isEmpty()) return;
int objCount = front.get(0).getObjectives().length;
int kpisize = front.get(0).getObjectives().length;
int popSize = front.size();
// 初始化距离为0
front.parallelStream().forEach(chromo -> chromo.setCrowdingDistance(0.0));
// front.parallelStream().forEach(chromo -> chromo.setCrowdingDistance(0.0));
// 计算每个目标的最大/最小值
double[] idealPoint = new double[kpisize];
for (int i = 0; i < kpisize; i++) {
final int idx = i;
if(isMinimize[i])
{
idealPoint[i] = front.stream().mapToDouble(c -> c.getObjectives()[idx]).min().orElse(0);
}else {
idealPoint[i] = front.stream().mapToDouble(c -> c.getObjectives()[idx]).max().orElse(0);
}
}
if(popSize>taskCount*10)
{
// 对每个目标维度并行计算距离
IntStream.range(0, objCount).parallel().forEach(m -> {
IntStream.range(0, popSize).parallel().forEach(m -> {
// 按当前目标排序
List<Chromosome> sorted = front.stream()
.sorted(Comparator.comparingDouble(c -> c.getObjectives()[m]))
.collect(Collectors.toList());
Chromosome chromo=front.get(m);
double[] idealPoint1 = idealPoint;
double[] objectives = chromo.getObjectives();
double distance = calculateEuclideanDistance(objectives, idealPoint1);
// 边界个体距离设为无穷大
sorted.get(0).setCrowdingDistance(Double.POSITIVE_INFINITY);
sorted.get(popSize - 1).setCrowdingDistance(Double.POSITIVE_INFINITY);
double maxObj = sorted.get(popSize - 1).getObjectives()[m];
double minObj = sorted.get(0).getObjectives()[m];
chromo.setCrowdingDistance(distance);
});
}else {
front.forEach(chromo -> {
if (maxObj - minObj == 0) return;
double[] idealPoint1 = idealPoint;
double[] objectives = chromo.getObjectives();
double distance = calculateEuclideanDistance(objectives, idealPoint1);
// 计算中间个体的拥挤距离
for (int i = 1; i < popSize - 1; i++) {
Chromosome chromo = sorted.get(i);
synchronized (chromo) { // 线程安全
double distance = chromo.getCrowdingDistance() +
(sorted.get(i + 1).getObjectives()[m] - sorted.get(i - 1).getObjectives()[m])
/ (maxObj - minObj);
chromo.setCrowdingDistance(distance);
});
}
}
});
/**
* 计算目标值列表与理想点的欧氏距离
* @param objectives 解的目标值列表
* @param idealPoint 理想点
* @return 欧氏距离(值越小越优)
*/
private double calculateEuclideanDistance(double[] objectives, double[] idealPoint) {
double sum = 0.0;
for (int i = 0; i < objectives.length; i++) {
double diff = objectives[i] - idealPoint[i]; //与理想值的差
sum += diff * diff; // 平方和
}
return Math.sqrt(sum); // 开平方得到欧氏距离
}
/**
......@@ -304,8 +390,7 @@ public class NSGAIIUtils {
nextPopulation.addAll(front);
currentSize += front.size();
} else {
// 并行计算拥挤距离
parallelCalculateCrowdingDistance(front);
// 按拥挤距离排序,取前N个
List<Chromosome> sortedByDistance = front.stream()
.sorted((c1, c2) -> Double.compare(c2.getCrowdingDistance(), c1.getCrowdingDistance()))
......@@ -319,7 +404,53 @@ public class NSGAIIUtils {
return nextPopulation;
}
public void Test() {
ObjectiveWeights weights = new ObjectiveWeights();
double[] weightvs = new double[] { 0.5, 0.5 };
weights.setWeights(weightvs);
weights.setPureNSGAIIMode(false);
init(weights);
List<Chromosome> chromosomeList = new ArrayList<>();
Chromosome chromosome1 = new Chromosome();
chromosome1.setID("A");
chromosome1.setObjectives(new double[]{1, 3});
chromosomeList.add(chromosome1);
Chromosome chromosome4 = new Chromosome();
chromosome4.setID("B");
chromosome4.setObjectives(new double[]{2, 2});
chromosomeList.add(chromosome4);
Chromosome chromosome5 = new Chromosome();
chromosome5.setID("C");
chromosome5.setObjectives(new double[]{3, 1});
chromosomeList.add(chromosome5);
Chromosome chromosome2 = new Chromosome();
chromosome2.setID("D");
chromosome2.setObjectives(new double[]{2, 3});
chromosomeList.add(chromosome2);
Chromosome chromosome3 = new Chromosome();
chromosome3.setID("E");
chromosome3.setObjectives(new double[]{4, 4});
chromosomeList.add(chromosome3);
parallelFastNonDominatedSort(chromosomeList);
// 解 A(1,3):
// 支配的解:D(2,3)、E(4,4)→ S (A) = {D,E}
// 被支配的解:无 → n (A) = 0
// 解 B(2,2):
// 支配的解:D(2,3)、E(4,4)→ S (B) = {D,E}
// 被支配的解:无 → n (B) = 0
// 解 C(3,1):
// 支配的解:E(4,4)→ S (C) = {E}
// 被支配的解:无 → n (C) = 0
// 解 D(2,3):
// 支配的解:E(4,4)→ S (D) = {E}
// 被支配的解:A、B → n (D) = 2
// 解 E(4,4):
// 支配的解:无 → S (E) = ∅
// 被支配的解:A、B、C、D → n (E) = 4
}
}
......@@ -136,7 +136,7 @@ public class RoutingDataService {
}
List<Entry> entrys=new ArrayList<>();
Set<Long> machineIds=new HashSet<>();
for (int i = index; i < results.size(); i++) {
GroupResult groupResult = results.get(i);
List<NodeInfo> nodeInfoList = groupResult.getNodeInfoList();
......@@ -234,6 +234,7 @@ public class RoutingDataService {
if (Equipments != null && Equipments.size() > 0) {
List<MachineOption> mos = new ArrayList<>();
for (ProdEquipment e : Equipments) {
machineIds.add(e.getEquipId());
MachineOption mo = new MachineOption();
mo.setMachineId(e.getEquipId());
mo.setRuntime(e.getRuntime());
......@@ -261,7 +262,7 @@ public class RoutingDataService {
}
list.put(1,entrys);
list.put(2,results);
list.put(3,machineIds);
return list;
}
......@@ -465,7 +466,11 @@ public class RoutingDataService {
shift.setMachineId(machine.getId());
shift.setStartDate(machineProdEquipSpecialCal.getEffectiveStartTime());
shift.setEndDate(machineProdEquipSpecialCal.getEffectiveEndTime());
if(machineProdEquipSpecialCal.getEfficiencyCoeff()!=null) {
shift.setEfficiency(machineProdEquipSpecialCal.getEfficiencyCoeff());
}
shifts1.add(shift);
}
}
......@@ -621,6 +626,7 @@ public class RoutingDataService {
days.add(6);
days.add(0);
shift.setDays(days);
shift.setStartDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
shift.setEndDate(LocalDateTime.of(2000, 1, 1, 0, 0, 0));
shifts1.add(shift);
......
......@@ -79,7 +79,9 @@ public class ProdEquipSpecialCalServiceImpl extends ServiceImpl<ProdEquipSpecial
specialCal.setPlanResourceId(capacityDef.getPlanResourceId());
// 处理数值类型转换的空值
if (capacityDef.getEfficiencyCoeff() != null) {
specialCal.setEfficiencyCoeff(capacityDef.getEfficiencyCoeff().longValue());
specialCal.setEfficiencyCoeff(capacityDef.getEfficiencyCoeff().doubleValue());
}else {
specialCal.setEfficiencyCoeff(1);
}
specialCal.setReferenceId(capacityDef.getReferenceId());
......
......@@ -10,14 +10,17 @@ import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
public class MachineSchedulerService {
// 全局缓存(线程安全)
private static final ConcurrentHashMap<Long, MachineTimeline> timelineCache = new ConcurrentHashMap<>();
private final ReentrantLock cacheLock = new ReentrantLock();
private LocalDateTime currentTime;
private List<Holiday> holidays;
......@@ -34,19 +37,19 @@ public class MachineSchedulerService {
long machineId = machine.getId();
// 尝试从缓存获取
// MachineTimeline timeline = timelineCache.get(machineId);
// if (timeline != null) {
// // 检查有效期(4小时刷新)
// if (Duration.between(timeline.getLastUpdated(), LocalDateTime.now()).toHours() < 4) {
// return timeline;
// }
// }
MachineTimeline timeline = timelineCache.get(machineId);
if (timeline != null) {
// 检查有效期(4小时刷新)
if (Duration.between(timeline.getLastUpdated(), LocalDateTime.now()).toMinutes() < 10) {
return timeline;
}
}
// 创建新时间线(60天范围)
MachineTimeline newTimeline = generateTimeline(machine);
newTimeline.setSegments(mergeSegments(newTimeline.getSegments()));
// timelineCache.put(machineId, newTimeline);
timelineCache.put(machineId, newTimeline);
return newTimeline;
}
......@@ -54,11 +57,11 @@ public class MachineSchedulerService {
MachineTimeline timeline = new MachineTimeline();
timeline.setMachineId(machine.getId());
timeline.setValidFrom(currentTime);
timeline.setValidTo(currentTime.plusDays(60));
timeline.setValidTo(currentTime.plusDays(200));
timeline.setLastUpdated(LocalDateTime.now());
LocalDate currentDate = currentTime.toLocalDate();
LocalDate endDate = currentTime.plusDays(60).toLocalDate();
LocalDate endDate = currentTime.plusDays(200).toLocalDate();
List<TimeSegment> allSegments = new ArrayList<>();
......@@ -110,23 +113,37 @@ public class MachineSchedulerService {
}
public List<TimeSegment> generateTimeSegment(Machine machine, LocalDateTime currentTime) {
cacheLock.lock();
Long machineId = machine.getId();
MachineTimeline timeline = timelineCache.get(machineId);
try {
if (timeline == null) {
timeline = new MachineTimeline();
timeline.setMachineId(machine.getId());
timeline.setValidFrom(currentTime);
timeline.setValidTo(currentTime.plusDays(60));
timeline.setValidTo(currentTime.plusDays(200));
timeline.setLastUpdated(LocalDateTime.now());
timeline.setSegments(new ArrayList<>());
} else {
timeline.setValidTo(currentTime.plusDays(60));
if (timeline.getValidTo().compareTo(currentTime) > 0) {
LocalDateTime currentTime1=currentTime;
List<TimeSegment> timeSegments= timeline.getSegments().stream()
.filter(t->t.getStart().isAfter(currentTime1)||t.getStart().isBefore(currentTime1))
.collect(Collectors.toList());
return ProductionDeepCopyUtil.deepCopyList(timeSegments,TimeSegment.class);
} else {
timeline.setValidTo(currentTime.plusDays(200));
timeline.setLastUpdated(LocalDateTime.now());
}
}
}finally {
cacheLock.unlock();
}
LocalDate currentDate = currentTime.toLocalDate();
LocalDate endDate = currentTime.plusDays(60).toLocalDate();
LocalDate endDate = currentTime.plusDays(200).toLocalDate();
List<TimeSegment> segments = new ArrayList<>();
......@@ -173,6 +190,14 @@ public class MachineSchedulerService {
timeline.setSegments(mergeSegments(timeline.getSegments()));
segments = mergeSegments(segments);
cacheLock.lock();
try {
timelineCache.put(machineId, timeline);
}finally {
cacheLock.unlock();
}
return segments;
}
......@@ -213,13 +238,14 @@ public class MachineSchedulerService {
LocalDateTime shiftEnd = shift.getEndTime().isBefore(shift.getStartTime()) ?
date.plusDays(1).atTime(shift.getEndTime()) :
date.atTime(shift.getEndTime());
segments.add(new TimeSegment(
TimeSegment timeSegment= new TimeSegment(
shiftStart,
shiftEnd,
shift.isTemporaryShift() ? SegmentType.TEMP : SegmentType.REGULAR,
false
));
);
timeSegment.setEfficiency(shift.getEfficiency());
segments.add(timeSegment);
}
} else {
// 非假期:处理常规班次
......@@ -231,24 +257,42 @@ public class MachineSchedulerService {
&& containsDay(s.getDays(), date.getDayOfWeek()))
.collect(Collectors.toList());
if(shifts==null||shifts.size()==0) {
LocalDate sd= LocalDate.of(2000, 1, 1);
long days=Math.abs(ChronoUnit.DAYS.between(LocalDate.now(),date));
if(days>600)
{
segments.add(new TimeSegment
(
date.atTime(0,0,0),
date.atTime(23,59,59),
SegmentType.REGULAR,
false
));
return segments;
}else {
LocalDate sd = LocalDate.of(2000, 1, 1);
shifts = machine.getShifts().stream()
.filter(s ->sd.compareTo(s.getStartDate().toLocalDate())==0&& s.getDays() != null
.filter(s -> sd.compareTo(s.getStartDate().toLocalDate()) == 0 && s.getDays() != null
&& containsDay(s.getDays(), date.getDayOfWeek()))
.collect(Collectors.toList());
}
}
for (Shift shift : shifts) {
LocalDateTime shiftStart = date.atTime(shift.getStartTime());
LocalDateTime shiftEnd = shift.getEndTime().isBefore(shift.getStartTime()) ?
date.plusDays(1).atTime(shift.getEndTime()) :
date.atTime(shift.getEndTime());
segments.add(new TimeSegment(
TimeSegment timeSegment= new TimeSegment(
shiftStart,
shiftEnd,
shift.isTemporaryShift() ? SegmentType.TEMP : SegmentType.REGULAR,
false
));
);
timeSegment.setEfficiency(shift.getEfficiency());
segments.add(timeSegment);
}
}
......
......@@ -339,13 +339,17 @@ order.setDueDate(LocalDateTime.of(2025, 12, 1,0,0,0));
List<GroupResult> entryRel=(List<GroupResult>)list.get(2);
Set<Long> machineIds=(Set<Long>)list.get(3);
machines= machines.stream().filter(t->machineIds.contains(t.getId())).collect(Collectors.toList());
// 5. 执行调度算法
GeneticAlgorithm scheduler =new GeneticAlgorithm(globalParam,machines,orders,Materials,machineScheduler,entryRel,materialRequirementService); //new GeneticAlgorithm(products, machines, orders, machineScheduler);
param.initAdaptiveParams(entrys.size());
double[] customWeights = new double[] { 0.2, 0.1, 0.1, 0.1, 0.5 }; // 延迟时间权重提升到0.5
scheduler.Init(null,false);
double[] customWeights = new double[] { 0.4, 0.1, 0.1, 0.1, 0.3 }; // 延迟时间权重提升到0.5
//完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
scheduler.Init(customWeights,false);
Chromosome chromosome =scheduler.Run(param,entrys);
KpiCalculator kpiCalculator=new KpiCalculator(chromosome);
......@@ -648,14 +652,16 @@ order.setDueDate(LocalDateTime.of(2025, 12, 1,0,0,0));
List<Entry> entrys=(List<Entry>)list.get(1);
List<GroupResult> entryRel=(List<GroupResult>)list.get(2);
Set<Long> machineIds=(Set<Long>)list.get(3);
machines= machines.stream().filter(t->machineIds.contains(t.getId())).collect(Collectors.toList());
// 5. 执行调度算法
GeneticAlgorithm scheduler =new GeneticAlgorithm(globalParam,machines,orders,Materials,machineScheduler,entryRel,materialRequirementService); //new GeneticAlgorithm(products, machines, orders, machineScheduler);
param.initAdaptiveParams(entrys.size());
// double[] customWeights = new double[] { 0.2, 0.1, 0.1, 0.1, 0.5 }; // 延迟时间权重提升到0.5
scheduler.Init(null,true);
double[] customWeights = new double[] { 0.4, 0.1, 0.1, 0.1, 0.3 }; // 延迟时间权重提升到0.5
//完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
scheduler.Init(customWeights,false);
Chromosome chromosomes =scheduler.Run(param,entrys);
KpiCalculator kpiCalculator=new KpiCalculator(chromosomes);
kpiCalculator.calculatekpi();
......@@ -783,14 +789,15 @@ order.setDueDate(LocalDateTime.of(2025, 12, 1,0,0,0));
private List<Machine> InitCalendarToAllMachines(String SceneId,List<ProdEquipment> ProdEquipments,MachineSchedulerService machineScheduler,boolean IsUseCalendar) {
// 按设备分组
FileHelper.writeLogFile("初始化设备日历-----------开始-------");
if(!IsUseCalendar) {
ScheduleParams param = InitScheduleParams();
List<Machine> machines=new ArrayList<>();
if(!IsUseCalendar) {
return _routingDataService.InitNoCalendarToAllMachines(machineScheduler,param.getBaseTime());
machines = _routingDataService.InitNoCalendarToAllMachines(machineScheduler,param.getBaseTime());
}else {
ScheduleParams param = InitScheduleParams();
return _routingDataService.InitCalendarToAllMachines( machineScheduler,param.getBaseTime());
machines = _routingDataService.InitCalendarToAllMachines( machineScheduler,param.getBaseTime());
// List<Machine> machines = _routingDataService.InitCalendarToAllMachines(SceneId, ProdEquipments, machineScheduler, IsUseCalendar);
// List<Machine> machines = (List<Machine>) GlobalCacheUtil.get("machines");
......@@ -805,12 +812,13 @@ order.setDueDate(LocalDateTime.of(2025, 12, 1,0,0,0));
// }
// }
//
// FileHelper.writeLogFile("初始化设备日历-----------结束-------");
// GlobalCacheUtil.put("machines", machines, 10, TimeUnit.MINUTES);
// return machines;
}
}
FileHelper.writeLogFile("初始化设备日历-----------结束-------");
redisUtils.set("machines",machines);
GlobalCacheUtil.put("machines", machines, 10, TimeUnit.MINUTES);
return machines;
}
public List<Machine> InitCalendarToAllMachines ()
{
......
......@@ -3,8 +3,10 @@ package com.aps.demo;
import com.aps.ApsApplication;
import com.aps.common.util.RangeSubtractUtil;
import com.aps.entity.Algorithm.Chromosome;
import com.aps.entity.Algorithm.ObjectiveWeights;
import com.aps.entity.Gantt.ProductGanttVO;
import com.aps.entity.basic.Machine;
import com.aps.service.Algorithm.NSGAIIUtils;
import com.aps.service.plan.PlanResultService;
import com.aps.service.plan.SceneService;
import org.junit.jupiter.api.Test;
......@@ -30,9 +32,11 @@ public class PlanResultServiceTest {
// RangeSubtractUtil.test();
// planResultService.testSceneChromsome("qwerty");
// Chromosome chromosome= planResultService.moveChromosome("qwerty",3);
planResultService.execute2("B7881EF032044B9BA4F6007875510B70");
// planResultService.execute2("BE037838EF074B07B87D7DE763107398");
// planResultService.execute2("31EC5BAF7F6B41DFB79AB031D81C53C0");
// planResultService.execute2("B7881EF032044B9BA4F6007875510B70");
// NSGAIIUtils nsgaiiUtils=new NSGAIIUtils();
// nsgaiiUtils.Test();
planResultService.execute2("31EC5BAF7F6B41DFB79AB031D81C53C0");
// LocalDateTime t= LocalDateTime.of(2025, 11, 15, 6, 51, 11);
// List<Integer> opids=new ArrayList<>();
// opids.add(1);
......
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