Commit f7bdf363 authored by Tong Li's avatar Tong Li

遗传算法

parent eee3a165
...@@ -106,9 +106,9 @@ public class ResourceGanttController { ...@@ -106,9 +106,9 @@ public class ResourceGanttController {
@GetMapping("/getScene") @GetMapping("/getScene")
@Operation(summary = "获取所有场景ID", description = "获取所有场景ID") @Operation(summary = "获取所有场景ID", description = "获取所有场景ID")
public List<Chromosome> getScene() { public Chromosome getScene() {
// 调用 PlanResultService 获取 ScheduleChromosome 列表 // 调用 PlanResultService 获取 ScheduleChromosome 列表
List<Chromosome> scheduleChromosomes = planResultService.execute1(); Chromosome scheduleChromosomes = planResultService.execute1();
// 提取所有场景ID // 提取所有场景ID
return scheduleChromosomes; return scheduleChromosomes;
...@@ -116,9 +116,9 @@ public class ResourceGanttController { ...@@ -116,9 +116,9 @@ public class ResourceGanttController {
@GetMapping("/getScene2") @GetMapping("/getScene2")
@Operation(summary = "获取所有场景ID", description = "获取所有场景ID") @Operation(summary = "获取所有场景ID", description = "获取所有场景ID")
public List<Chromosome> getScene2() { public Chromosome getScene2() {
// 调用 PlanResultService 获取 ScheduleChromosome 列表 // 调用 PlanResultService 获取 ScheduleChromosome 列表
List<Chromosome> scheduleChromosomes = planResultService.execute2("EAA26D85B5824B40A17554297B4EA32B"); Chromosome scheduleChromosomes = planResultService.execute2("B571EF6682DB463AB2977B1055A74112");
// 提取所有场景ID // 提取所有场景ID
return scheduleChromosomes; return scheduleChromosomes;
......
...@@ -12,11 +12,18 @@ import java.util.List; ...@@ -12,11 +12,18 @@ import java.util.List;
@Data @Data
public class GAScheduleResult { public class GAScheduleResult {
private int GroupId; private int GroupId;
private int ProductId;
private int OperationId; private int OperationId;
/**
* 工单ID
*/
public String ExecId ;
public String OrderId ;
private String productId;
private long MachineId; private long MachineId;
private int StartTime; // 相对开始时间(分钟) private int StartTime; // 相对开始时间(秒)
private int EndTime; // 相对结束时间(分钟) private int EndTime; // 相对结束时间(秒)
private int teardownTime; //后处理
private double Quantity; // 批次大小(订单可拆分) private double Quantity; // 批次大小(订单可拆分)
private List<ScheduleResultDetail> GeneDetails; // 时间详情 private List<ScheduleResultDetail> GeneDetails; // 时间详情
private double OneTime; // 单件工时 private double OneTime; // 单件工时
......
package com.aps.entity.Algorithm.IDAndChildID;
import java.util.List;
import java.util.Map;
/**
* 作者:佟礼
* 时间:2025-11-29
*/
// 存储分组结果:节点信息列表、新父子映射
// 存储分组结果:节点信息列表、原始ID(String)→全局序号映射
// 存储分组结果:节点信息列表、原始ID→全局序号映射
public class GroupResult {
private List<NodeInfo> nodeInfoList;
private Map<String, Integer> originalToGlobalSerial;
public GroupResult(List<NodeInfo> nodeInfoList, Map<String, Integer> originalToGlobalSerial) {
this.nodeInfoList = nodeInfoList;
this.originalToGlobalSerial = originalToGlobalSerial;
}
// getter
public List<NodeInfo> getNodeInfoList() { return nodeInfoList; }
public Map<String, Integer> getOriginalToGlobalSerial() { return originalToGlobalSerial; }
}
package com.aps.entity.Algorithm.IDAndChildID;
import lombok.Data;
import java.util.List;
/**
* 作者:佟礼
* 时间:2025-11-29
*/
// 存储节点信息:原ID、新序号、新父ID、新子ID列表
@Data
// 存储节点信息:原ID(String)、全局新序号、分组内序号、新父ID列表、新子ID列表
public class NodeInfo {
private String originalId; // 原始ID
private Integer globalSerial; // 全局新序号
private Integer groupSerial; // 分组内序号
private List<Integer> newParentIds; // 新父ID列表(基于全局序号)
private List<Integer> newChildIds; // 新子ID列表(基于全局序号)
public NodeInfo(String originalId, Integer globalSerial, Integer groupSerial, List<Integer> newParentIds, List<Integer> newChildIds) {
this.originalId = originalId;
this.globalSerial = globalSerial;
this.groupSerial = groupSerial;
this.newParentIds = newParentIds;
this.newChildIds = newChildIds;
}
@Override
public String toString() {
return originalId + ":" + globalSerial;
}
}
...@@ -29,6 +29,7 @@ public class Entry { ...@@ -29,6 +29,7 @@ public class Entry {
*/ */
public String OrderId ; public String OrderId ;
private String productId;
/** /**
* 工单ID * 工单ID
*/ */
...@@ -36,7 +37,7 @@ public class Entry { ...@@ -36,7 +37,7 @@ public class Entry {
/** /**
* 离散参数 * 离散参数
*/ */
public String DiscreteParameter ; public List<String> DiscreteParameter ;
/** /**
* 基因编号 * 基因编号
*/ */
...@@ -58,6 +59,11 @@ public class Entry { ...@@ -58,6 +59,11 @@ public class Entry {
*/ */
public List<Integer> PrevEntryIds ;//前工序 public List<Integer> PrevEntryIds ;//前工序
/**
* 前工单ID
*/
public List<Integer> NextEntryIds ;//后工序
/** /**
* 是否可中断,间缝插针 * 是否可中断,间缝插针
*/ */
......
...@@ -11,15 +11,17 @@ public class GlobalParam { ...@@ -11,15 +11,17 @@ public class GlobalParam {
/// <summary> /// <summary>
/// 是否可以打破优先级 /// 是否可以打破优先级
/// </summary> /// </summary>
public static boolean IsBreakPriority = false; private boolean IsBreakPriority = false;
/// <summary> /// <summary>
/// 是否多台设备 /// 是否多台设备
/// </summary> /// </summary>
public static boolean IsMultipleMachine = false; private boolean IsMultipleMachine = false;
/// <summary> /// <summary>
/// 是否重叠 /// 是否重叠
/// </summary> /// </summary>
public static boolean IsOverlap = false; private boolean IsOverlap = false;
private boolean _smoothSetup = false; // 默认true,不占用设备时长
} }
...@@ -11,11 +11,14 @@ import java.time.OffsetDateTime; ...@@ -11,11 +11,14 @@ import java.time.OffsetDateTime;
@Data @Data
public class Order { public class Order {
private int id; private int id;
private String OrderId;
private int productId; private int productId;
private String materialId;
private double quantity = 100; // 100个 private double quantity = 100; // 100个
private double sYQuantity; private double sYQuantity;
private OffsetDateTime dueDate; private LocalDateTime dueDate;
private LocalDateTime orderCompletion; private LocalDateTime orderCompletion;
private double tardiness; private double tardiness;
private int priority; private int priority;
......
...@@ -96,38 +96,38 @@ public class ScheduleChromosome { ...@@ -96,38 +96,38 @@ public class ScheduleChromosome {
private List<Order> calTardiness() { private List<Order> calTardiness() {
tardiness = 0; tardiness = 0;
for (Order order : orders) { // for (Order order : orders) {
final int orderId = order.getId(); // final int orderId = order.getId();
List<Gene> orderGroups = genes.stream() // List<Gene> orderGroups = genes.stream()
.filter(g -> g.getOrderId() == orderId) // .filter(g -> g.getOrderId() == orderId)
.collect(Collectors.toList()); // .collect(Collectors.toList());
//
int orderCompletion = orderGroups.stream() // int orderCompletion = orderGroups.stream()
.mapToInt(Gene::getEndTime) // .mapToInt(Gene::getEndTime)
.max() // .max()
.orElse(0); // .orElse(0);
//
LocalDateTime orderCompletionTime = baseTime.plusMinutes(orderCompletion); // LocalDateTime orderCompletionTime = baseTime.plusMinutes(orderCompletion);
order.setOrderCompletion(orderCompletionTime); // order.setOrderCompletion(orderCompletionTime);
order.setTardiness(0); // order.setTardiness(0);
//
// 修复:统一时间类型 // // 修复:统一时间类型
LocalDateTime dueDateTime = order.getDueDate().toLocalDateTime(); // LocalDateTime dueDateTime = order.getDueDate();
//
if (orderCompletionTime.isAfter(dueDateTime)) { // if (orderCompletionTime.isAfter(dueDateTime)) {
// 方法1:使用分钟计算再转换为小时(推荐) // // 方法1:使用分钟计算再转换为小时(推荐)
long totalMinutes = java.time.temporal.ChronoUnit.MINUTES.between(dueDateTime, orderCompletionTime); // long totalMinutes = java.time.temporal.ChronoUnit.MINUTES.between(dueDateTime, orderCompletionTime);
double tardinessHours = totalMinutes / 60.0; // double tardinessHours = totalMinutes / 60.0;
//
// 方法2:或者保持原有逻辑但使用统一的时间类型 // // 方法2:或者保持原有逻辑但使用统一的时间类型
// long diffHours = java.time.temporal.ChronoUnit.HOURS.between(dueDateTime, orderCompletionTime); // // long diffHours = java.time.temporal.ChronoUnit.HOURS.between(dueDateTime, orderCompletionTime);
// long remainingMinutes = java.time.temporal.ChronoUnit.MINUTES.between(dueDateTime, orderCompletionTime) % 60; // // long remainingMinutes = java.time.temporal.ChronoUnit.MINUTES.between(dueDateTime, orderCompletionTime) % 60;
// double tardinessHours = diffHours + (double) remainingMinutes / 60; // // double tardinessHours = diffHours + (double) remainingMinutes / 60;
//
order.setTardiness(tardinessHours); // order.setTardiness(tardinessHours);
tardiness += tardinessHours; // tardiness += tardinessHours;
} // }
} // }
return orders; return null;
} }
} }
\ No newline at end of file
...@@ -6,10 +6,7 @@ import com.aps.entity.Algorithm.Chromosome; ...@@ -6,10 +6,7 @@ import com.aps.entity.Algorithm.Chromosome;
import com.aps.entity.Algorithm.GlobalOperationInfo; import com.aps.entity.Algorithm.GlobalOperationInfo;
import com.aps.entity.Algorithm.Pair; import com.aps.entity.Algorithm.Pair;
import com.aps.entity.Algorithm.ScheduleParams; import com.aps.entity.Algorithm.ScheduleParams;
import com.aps.entity.basic.Entry; import com.aps.entity.basic.*;
import com.aps.entity.basic.Machine;
import com.aps.entity.basic.Material;
import com.aps.entity.basic.Order;
import com.aps.service.plan.MachineSchedulerService; import com.aps.service.plan.MachineSchedulerService;
import java.util.*; import java.util.*;
...@@ -25,20 +22,22 @@ public class GeneticAlgorithm { ...@@ -25,20 +22,22 @@ public class GeneticAlgorithm {
private final MachineSchedulerService machineScheduler; private final MachineSchedulerService machineScheduler;
private final List<Order> orders; private final List<Order> orders;
private final List<Material> materials; private final List<Material> materials;
private static GlobalParam _GlobalParam;
public GeneticAlgorithm(List<Machine> machines, List<Order> orders, public GeneticAlgorithm(GlobalParam globalParam,List<Machine> machines, List<Order> orders,
List<Material> materials, MachineSchedulerService machineScheduler) { List<Material> materials, MachineSchedulerService machineScheduler) {
this.machines = machines; this.machines = machines;
this.orders = orders; this.orders = orders;
this.materials = materials; this.materials = materials;
this.machineScheduler = machineScheduler; this.machineScheduler = machineScheduler;
_GlobalParam=globalParam;
} }
public List<Chromosome> Run(ScheduleParams param, List<Entry> allOperations) { public Chromosome Run(ScheduleParams param, List<Entry> allOperations) {
System.out.println("开始"); System.out.println("开始");
Initialization initialization = new Initialization(allOperations); Initialization initialization = new Initialization(_GlobalParam,allOperations);
GeneticOperations geneticOps = new GeneticOperations(allOperations); GeneticOperations geneticOps = new GeneticOperations(_GlobalParam,allOperations);
// 预生成全局工序列表(所有初始化方法共享同一顺序) // 预生成全局工序列表(所有初始化方法共享同一顺序)
List<GlobalOperationInfo> globalOpList = initialization.generateGlobalOpList(); List<GlobalOperationInfo> globalOpList = initialization.generateGlobalOpList();
...@@ -124,36 +123,43 @@ public class GeneticAlgorithm { ...@@ -124,36 +123,43 @@ public class GeneticAlgorithm {
Iteration++; Iteration++;
} }
if(Iteration>20) if(Iteration>10)
{ {
break; break;
} }
} }
// 步骤3:返回最优解 // 步骤3:返回最优解
return population.stream() return best;
.sorted((c1, c2) -> Double.compare(c2.getFitness(), c1.getFitness()))
.limit(10)
.collect(Collectors.toList());
} }
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)
{ {
GeneticDecoder decoder = new GeneticDecoder(param.getBaseTime(), machines, orders, materials, machineScheduler); GeneticDecoder decoder = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler);
FitnessCalculator fitnessCalc = new FitnessCalculator(); FitnessCalculator fitnessCalc = new FitnessCalculator();
population.parallelStream().forEach(chromosome -> { // population.parallelStream().forEach(chromosome -> {
// chromosome.setResult(new ArrayList<>());
//
// // 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射
// chromosome.setMachines(ProductionDeepCopyUtil.deepCopyList(machines)); // 简单拷贝,实际可能需要深拷贝
//
// decoder.decodeChromosomeWithCache(chromosome, globalOpList, allOperations);
// chromosome.setFitness(fitnessCalc.calculateFitness(chromosome));
// });
population.forEach(chromosome -> {
chromosome.setResult(new ArrayList<>()); chromosome.setResult(new ArrayList<>());
// 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射 // 假设Machine类有拷贝方法,或使用MapStruct等工具进行映射
chromosome.setMachines(ProductionDeepCopyUtil.deepCopyList(machines)); // 简单拷贝,实际可能需要深拷贝 chromosome.setMachines(ProductionDeepCopyUtil.deepCopyList(machines)); // 简单拷贝,实际可能需要深拷贝
decoder.decodeChromosomeWithCache(chromosome, globalOpList, allOperations); Chromosome chromosomen= decoder.decodeChromosomeWithCache(chromosome, globalOpList, allOperations);
chromosome.setFitness(fitnessCalc.calculateFitness(chromosome)); if(chromosomen.getFitness()==0) {
chromosomen.setFitness(fitnessCalc.calculateFitness(chromosomen));
}
}); });
} }
} }
...@@ -2,6 +2,7 @@ package com.aps.service.Algorithm; ...@@ -2,6 +2,7 @@ package com.aps.service.Algorithm;
import com.aps.common.util.ProductionDeepCopyUtil; import com.aps.common.util.ProductionDeepCopyUtil;
import com.aps.entity.Algorithm.*; import com.aps.entity.Algorithm.*;
import com.aps.entity.ProdEquipment;
import com.aps.entity.basic.*; import com.aps.entity.basic.*;
import com.aps.service.plan.MachineSchedulerService; import com.aps.service.plan.MachineSchedulerService;
...@@ -28,7 +29,9 @@ public class GeneticDecoder { ...@@ -28,7 +29,9 @@ public class GeneticDecoder {
private final List<Order> orders; private final List<Order> orders;
private int orderMaxID; private int orderMaxID;
private final List<Material> materials; private final List<Material> materials;
public GeneticDecoder(LocalDateTime baseTime, List<Machine> machines, List<Order> orders, private List<Entry> _allOperations;
private GlobalParam _globalParam;
public GeneticDecoder(GlobalParam globalParam,LocalDateTime baseTime, List<Machine> machines, List<Order> orders,
List<Material> materials, MachineSchedulerService machineScheduler) { List<Material> materials, MachineSchedulerService machineScheduler) {
this.baseTime = baseTime; this.baseTime = baseTime;
this.machines = machines; this.machines = machines;
...@@ -36,11 +39,12 @@ public class GeneticDecoder { ...@@ -36,11 +39,12 @@ public class GeneticDecoder {
this.orders.forEach(t -> t.setSYQuantity(t.getQuantity())); this.orders.forEach(t -> t.setSYQuantity(t.getQuantity()));
this.materials = materials; this.materials = materials;
this.machineScheduler = machineScheduler; this.machineScheduler = machineScheduler;
this.orderMaxID = orders.stream().mapToInt(Order::getId).max().orElse(0); _globalParam=globalParam;
// this.orderMaxID = orders.stream().mapToInt(Order::getId).max().orElse(0);
} }
public void decodeChromosomeWithCache(Chromosome chromosome, List<GlobalOperationInfo> globalOpList, public Chromosome decodeChromosomeWithCache(Chromosome chromosome, List<GlobalOperationInfo> globalOpList,
List<Entry> allOperations) { List<Entry> allOperations) {
_allOperations=allOperations;
// 1. 创建缓存键 // 1. 创建缓存键
String cacheKey = createCacheKey(chromosome); String cacheKey = createCacheKey(chromosome);
...@@ -52,9 +56,9 @@ public class GeneticDecoder { ...@@ -52,9 +56,9 @@ public class GeneticDecoder {
Chromosome cachedResult = decodingCache.get(cacheKey); Chromosome cachedResult = decodingCache.get(cacheKey);
// 赋值给染色体 // 赋值给染色体
String ID=chromosome.getID(); String ID=chromosome.getID();
chromosome= ProductionDeepCopyUtil.deepCopy(cachedResult); Chromosome chromosomen= ProductionDeepCopyUtil.deepCopy(cachedResult);
chromosome.setID(ID); chromosomen.setID(ID);
return; return chromosomen;
} }
} finally { } finally {
cacheLock.unlock(); // 确保锁释放 cacheLock.unlock(); // 确保锁释放
...@@ -84,6 +88,7 @@ public class GeneticDecoder { ...@@ -84,6 +88,7 @@ public class GeneticDecoder {
} finally { } finally {
cacheLock.unlock(); cacheLock.unlock();
} }
return chromosome;
} }
/** /**
* 染色体解码为调度方案 * 染色体解码为调度方案
...@@ -163,12 +168,13 @@ public class GeneticDecoder { ...@@ -163,12 +168,13 @@ public class GeneticDecoder {
int opSequence = currentOp.getSequence(); int opSequence = currentOp.getSequence();
// 从映射表中获取机器和加工时间 // 从映射表中获取机器和加工时间
OpMachine machineInfo=opMachineMap.stream() OpMachine machineOption=opMachineMap.stream()
.filter(m -> m.getGroupId() == groupId&&m.getSequence()==opSequence) .filter(m -> m.getGroupId() == groupId&&m.getSequence()==opSequence)
.findFirst() .findFirst()
.orElse(null); .orElse(null);
Long machineId = machineInfo.getMachineId(); Long machineId = machineOption.getMachineId();
double processTime = machineInfo.getProcessingTime(); double processTime = machineOption.getProcessingTime();
Machine targetMachine = chromosome.getMachines().stream() Machine targetMachine = chromosome.getMachines().stream()
.filter(m -> m.getId() == machineId) .filter(m -> m.getId() == machineId)
.findFirst() .findFirst()
...@@ -184,13 +190,13 @@ public class GeneticDecoder { ...@@ -184,13 +190,13 @@ public class GeneticDecoder {
.collect(Collectors.toList()); .collect(Collectors.toList());
for (GAScheduleResult prevOp : prevOperations) { for (GAScheduleResult prevOp : prevOperations) {
prevtime = Math.max(prevtime, prevOp.getEndTime()); prevtime = Math.max(prevtime, prevOp.getEndTime()+prevOp.getTeardownTime());
} }
} }
} }
// 上个离散参数 // 上个离散参数
String lastDiscreteParameter = machineState.get(machineId); // String lastDiscreteParameter = machineState.get(machineId);
int bomtime = 0; int bomtime = 0;
prevtime = Math.max(prevtime, bomtime); prevtime = Math.max(prevtime, bomtime);
...@@ -200,14 +206,14 @@ public class GeneticDecoder { ...@@ -200,14 +206,14 @@ public class GeneticDecoder {
.findFirst() .findFirst()
.orElse(null); .orElse(null);
int changeoverTime =0; //(lastDiscreteParameter.isEmpty() || // int changeoverTime =0; //(lastDiscreteParameter.isEmpty() ||
// lastDiscreteParameter.equals(currentOp.getDiscreteParameter())) ? 0 : 0; // lastDiscreteParameter.equals(currentOp.getDiscreteParameter())) ? 0 : 0;
int actualEndTime = processWithSingleMachine(currentOp, machine, processTime, prevtime, chromosome); int actualEndTime = processWithSingleMachine(currentOp, machine, processTime, prevtime, chromosome);
orderProcessCounter.put(groupId, orderProcessCounter.get(groupId) + 1); orderProcessCounter.put(groupId, orderProcessCounter.get(groupId) + 1);
orderLastEndTime.put(groupId, actualEndTime); orderLastEndTime.put(groupId, actualEndTime);
machineState.put(machineId, currentOp.getDiscreteParameter()); // machineState.put(machineId, currentOp.getDiscreteParameter());
} }
// 步骤4:计算调度指标 // 步骤4:计算调度指标
...@@ -217,13 +223,74 @@ public class GeneticDecoder { ...@@ -217,13 +223,74 @@ public class GeneticDecoder {
private int processWithSingleMachine(Entry operation, Machine machine, double processingTime, private int processWithSingleMachine(Entry operation, Machine machine, double processingTime,
int prevtime, Chromosome chromosome) { int prevOperationEndTime, Chromosome chromosome) {
int processingTimeTotal =(int)(processingTime * operation.getQuantity()); int processingTimeTotal =(int)(processingTime * operation.getQuantity());
MachineOption machineOption= operation.getMachineOptions().stream()
.filter(t->t.getMachineId()==machine.getId())
.findFirst().orElse(null);
int teardownTime = machineOption.getTeardownTime();
int preTime = machineOption.getPreTime();
int setupTime = calculateSetupTime(chromosome.getResult(), operation, machine, machineOption);
System.out.println(" 处理时间: " + processingTime + ", 后处理: " + teardownTime +
", 前处理: " + preTime + ", 换型: " + setupTime);
// 确定任务的最早开始时间(基于前一道工序的完整结束时间,包含后处理)
int earliestStartTime = prevOperationEndTime;
// 检查设备上是否有前一个任务
GAScheduleResult lastGeneOnMachine = chromosome.getResult().stream()
.filter(g -> g.getMachineId() == machine.getId())
.max(Comparator.comparingInt(GAScheduleResult::getEndTime))
.orElse(null);
if (lastGeneOnMachine != null) {
// 设备上已有任务,当前任务必须在设备可用后开始
// 设备可用时间 = 前一个任务的主处理结束时间(后处理不占用设备)
int machineAvailableTime = lastGeneOnMachine.getEndTime();
if (setupTime > 0) {
if (_globalParam.is_smoothSetup()) {
machineAvailableTime += setupTime;
// 平滑模式:换型在非工作时间进行,不额外占用设备时间
System.out.println(" 平滑模式换型:在非工作时间进行,设备可用时间不变");
} else {
// 标准模式:换型需要额外占用设备时间
machineAvailableTime += setupTime;
System.out.println(" 标准模式换型:需要额外占用设备 " + setupTime + " 分钟");
}
}
earliestStartTime = Math.max(earliestStartTime, machineAvailableTime);
}
System.out.println(" 最终最早开始时间: " + earliestStartTime +
" (前序工序结束含后处理: " + prevOperationEndTime + ", 设备可用: " +
(lastGeneOnMachine != null ? lastGeneOnMachine.getEndTime() : 0) +
", 换型: " + setupTime + ")");
// 根据换型模式调整处理时间
// int processingTimeForScheduling;
if (_globalParam.is_smoothSetup()) {
// 平滑模式:只需要安排主处理时间
// processingTimeForScheduling = processingTimeTotal;
System.out.println(" 平滑模式:安排主处理时间 " + processingTime + " 分钟");
} else {
// 标准模式:需要安排主处理时间+换型时间
processingTimeTotal = processingTimeTotal + setupTime;
System.out.println(" 标准模式:安排主处理+" + setupTime + "分钟换型=" + processingTimeTotal + "分钟");
}
MachineCalculator machineCalculator=new MachineCalculator(baseTime,machines,machineScheduler); MachineCalculator machineCalculator=new MachineCalculator(baseTime,machines,machineScheduler);
List<ScheduleResultDetail> geneDetails = machineCalculator.getNextAvailableTime(machine, prevtime, -1, List<ScheduleResultDetail> geneDetails = machineCalculator.getNextAvailableTime(machine, earliestStartTime, -1,
processingTimeTotal, chromosome.getResult(), false, true, true); processingTimeTotal, chromosome.getResult(), false, true, true);
int startTime = geneDetails.stream() int startTime = geneDetails.stream()
.mapToInt(ScheduleResultDetail::getStartTime) .mapToInt(ScheduleResultDetail::getStartTime)
.min() .min()
...@@ -233,19 +300,110 @@ public class GeneticDecoder { ...@@ -233,19 +300,110 @@ public class GeneticDecoder {
.max() .max()
.orElse(0); .orElse(0);
// 冲突检测和解决
final int finalStartTime = startTime;
final int finalEndTime = endTime;
GAScheduleResult conflictingGene = chromosome.getResult().stream()
.filter(g -> g.getMachineId() == machine.getId())
.filter(g -> (finalStartTime < g.getEndTime() && finalEndTime > g.getStartTime()))
.findFirst()
.orElse(null);
if (conflictingGene != null) {
System.out.println(" ⚠️ 检测到时间冲突,重新调度");
int conflictSetupStartTime = conflictingGene.getEndTime();
int conflictSetupTime = calculateSetupTimeForConflict(chromosome.getResult(),operation , machine, machineOption, conflictingGene);
int conflictEarliestStartTime = conflictSetupStartTime + conflictSetupTime;
geneDetails = machineCalculator.getNextAvailableTime(machine, conflictEarliestStartTime, -1,
processingTimeTotal, chromosome.getResult(), false, true, true);
if (!geneDetails.isEmpty()) {
startTime = geneDetails.stream()
.mapToInt(ScheduleResultDetail::getStartTime)
.min()
.orElse(0);
endTime = geneDetails.stream()
.mapToInt(ScheduleResultDetail::getEndTime)
.max()
.orElse(0);
System.out.println(" 重新安排时间: " + ConvertTime(startTime) + " - " + ConvertTime(endTime));
}
}
GAScheduleResult result=new GAScheduleResult(); GAScheduleResult result=new GAScheduleResult();
result.setGroupId(operation.getGroupId()); result.setGroupId(operation.getGroupId());
result.setOperationId(operation.getId()); result.setOperationId(operation.getId());
result.setExecId(operation.getExecId());
result.setOrderId(operation.getOrderId());
result.setProductId(operation.getProductId());
result.setMachineId(machine.getId()); result.setMachineId(machine.getId());
result.setQuantity(operation.getQuantity()); result.setQuantity(operation.getQuantity());
result.setStartTime(startTime); result.setStartTime(startTime);
result.setEndTime(endTime); result.setEndTime(endTime);
result.setEndTime(teardownTime);
result.setOneTime(processingTime); result.setOneTime(processingTime);
result.setProcessingTime(processingTimeTotal); result.setProcessingTime(processingTimeTotal);
result.setGeneDetails(geneDetails); result.setGeneDetails(geneDetails);
chromosome.getResult().add(result); chromosome.getResult().add(result);
return endTime; return endTime;
} }
private String ConvertTime(int minute) {
return baseTime.plusSeconds(minute).format(java.time.format.DateTimeFormatter.ofPattern("MM-dd HH:mm"));
}
private int calculateSetupTime(List<GAScheduleResult> existingGenes, Entry operation, Machine machine, MachineOption machineOption) {
GAScheduleResult lastGeneOnMachine = existingGenes.stream()
.filter(g -> g.getMachineId() == machine.getId())
.max(Comparator.comparingInt(GAScheduleResult::getEndTime))
.orElse(null);
if (lastGeneOnMachine == null) {
System.out.println("设备 " + machine.getId() + " 上无历史任务,换型时间为0");
return 0;
}
Entry prev= _allOperations.stream().
filter(t->t.getExecId().equals(lastGeneOnMachine.getExecId()))
.findFirst().orElse(null);
int setupTime=0;
if(prev!=null)
{
//离散参数
// prev.getDiscreteParameter()
setupTime = (prev.getProductId() != operation.getProductId())
? machineOption.getSetupTime()
: 0;
if (setupTime > 0) {
System.out.println("设备 " + machine.getId() + " 需要换型,因为产品从 " + prev.getProductId() + " 变更为 " + operation.getProductId());
}
}
return setupTime;
}
private int calculateSetupTimeForConflict(List<GAScheduleResult> existingGenes, Entry operation, Machine machine,
MachineOption machineOption, GAScheduleResult conflictingGene) {
int setupTime = (conflictingGene.getProductId() != operation.getProductId())
? machineOption.getSetupTime()
: 0;
if (existingGenes.stream().filter(g -> g.getMachineId() == machine.getId()).count() <= 1) {
setupTime = 0;
}
if (setupTime > 0) {
System.out.println("设备 " + machine.getId() + " 需要换型,因为产品从 " + conflictingGene.getProductId() + " 变更为 " + operation.getProductId());
}
return setupTime;
}
private void calculateScheduleResult(Chromosome chromosome) { private void calculateScheduleResult(Chromosome chromosome) {
// 1. 最早完工时间(最小化) // 1. 最早完工时间(最小化)
...@@ -266,16 +424,22 @@ public class GeneticDecoder { ...@@ -266,16 +424,22 @@ public class GeneticDecoder {
.mapToInt(GAScheduleResult::getEndTime) .mapToInt(GAScheduleResult::getEndTime)
.max() .max()
.orElse(0); .orElse(0);
List<String> orderIds = group.getValue().stream()
.map(GAScheduleResult::getOrderId)
.distinct()
.sorted()
.collect(Collectors.toList());
Order order = orders.stream() Order order = orders.stream()
.filter(t -> t.getId() == groupId) .filter(t->orderIds.contains(t.getOrderId()))
.findFirst() .max(Comparator.comparing(Order::getDueDate))
.orElse(null); .orElse(null);
LocalDateTime dueDateTime=order.getDueDate();
LocalDateTime completionTime =baseTime.plusSeconds(orderCompletion);
LocalDateTime completionTime =baseTime.plusMinutes(orderCompletion);
// 修复:正确处理OffsetDateTime到LocalDateTime的转换
LocalDateTime dueDateTime = order.getDueDate().toLocalDateTime();
if (completionTime.isAfter(dueDateTime)) { if (completionTime.isAfter(dueDateTime)) {
// 计算延迟小时数(修复时间计算) // 计算延迟小时数(修复时间计算)
......
...@@ -18,9 +18,13 @@ import java.util.stream.Collectors; ...@@ -18,9 +18,13 @@ import java.util.stream.Collectors;
*/ */
public class GeneticOperations { public class GeneticOperations {
private final Random rnd = new Random(); private final Random rnd = new Random();
private static GlobalParam _GlobalParam;
private static List<Entry> allOperations; private static List<Entry> allOperations;
public GeneticOperations(List<Entry> allOperations) { public GeneticOperations(GlobalParam globalParam,List<Entry> allOperations) {
_GlobalParam=globalParam;
GeneticOperations.allOperations = allOperations; GeneticOperations.allOperations = allOperations;
} }
...@@ -225,7 +229,7 @@ public class GeneticOperations { ...@@ -225,7 +229,7 @@ public class GeneticOperations {
Random rnd = new Random(); Random rnd = new Random();
List<OperationSequencingWeight> indexWeights = CommonCalculator.getOsw(os, allOperations); List<OperationSequencingWeight> indexWeights = CommonCalculator.getOsw(os, allOperations);
if (!GlobalParam.IsBreakPriority) { if (!_GlobalParam.isIsBreakPriority()) {
if (weight == 0) { if (weight == 0) {
return indexWeights.get(rnd.nextInt(indexWeights.size())); return indexWeights.get(rnd.nextInt(indexWeights.size()));
} else { } else {
......
package com.aps.service.Algorithm;
import com.aps.entity.Algorithm.IDAndChildID.GroupResult;
import com.aps.entity.Algorithm.IDAndChildID.NodeInfo;
import lombok.Data;
import java.util.*;
import java.util.stream.Collectors;
/**
* 作者:佟礼
* 时间:2025-11-29
*/
public class IdGroupingWithDualSerial {
/**
* 递归获取ID的所有子孙节点(去重)
*/
/**
* 递归获取ID的所有子孙节点(去重)
*/
private static Set<String> getAllDescendants(String id, Map<String, Set<String>> parentToChildren, Set<String> visited) {
Set<String> descendants = new HashSet<>();
if (visited.contains(id) || !parentToChildren.containsKey(id)) {
return descendants;
}
visited.add(id);
Set<String> directChildren = parentToChildren.get(id);
for (String child : directChildren) {
descendants.add(child);
descendants.addAll(getAllDescendants(child, parentToChildren, visited));
}
return descendants;
}
/**
* 分组“无父级且子孙节点有交集”的ID(兼容空ChildID)
*/
private static List<List<String>> groupNoParentIds(List<String> idList, List<String> childIdList) {
// 构建父→子映射(过滤空ChildID,去重)
Map<String, Set<String>> parentToChildren = new HashMap<>();
for (int i = 0; i < idList.size(); i++) {
String parentId = idList.get(i);
String childId = childIdList.get(i);
// 跳过空ChildID
if (childId == null || childId.trim().isEmpty()) {
continue;
}
parentToChildren.computeIfAbsent(parentId, k -> new HashSet<>()).add(childId);
}
// 构建子→父映射(过滤空ChildID)
Map<String, Set<String>> childToParents = new HashMap<>();
for (int i = 0; i < idList.size(); i++) {
String parentId = idList.get(i);
String childId = childIdList.get(i);
if (childId == null || childId.trim().isEmpty()) {
continue;
}
childToParents.computeIfAbsent(childId, k -> new HashSet<>()).add(parentId);
}
Set<String> allChildIds = new HashSet<>();
for (String childId : childIdList) {
if (childId != null && !childId.trim().isEmpty()) {
allChildIds.add(childId);
}
}
List<String> noParentIds = parentToChildren.keySet().stream()
.filter(id -> !allChildIds.contains(id))
.collect(Collectors.toList());
// 处理无子女的孤立节点(如23)
Set<String> allParentIds = new HashSet<>(idList);
for (String id : allParentIds) {
if (!parentToChildren.containsKey(id) && !allChildIds.contains(id)) {
noParentIds.add(id); // 孤立节点作为根节点
}
}
List<List<String>> groups = new ArrayList<>();
Set<String> processed = new HashSet<>();
for (String root : noParentIds) {
if (processed.contains(root)) continue;
List<String> group = new ArrayList<>();
group.add(root);
processed.add(root);
Set<String> rootDescendants = getAllDescendants(root, parentToChildren, new HashSet<>());
for (String other : noParentIds) {
if (processed.contains(other)) continue;
Set<String> otherDescendants = getAllDescendants(other, parentToChildren, new HashSet<>());
Set<String> intersection = new HashSet<>(rootDescendants);
intersection.retainAll(otherDescendants);
if (!intersection.isEmpty()) {
group.add(other);
processed.add(other);
}
}
groups.add(group);
}
return groups;
}
/**
* 处理单个分组
*/
private static GroupResult processSingleGroup(List<String> groupRoots,
Map<String, Set<String>> parentToChildren,
Map<String, Set<String>> childToParents,
int[] globalCounter) {
// 收集分组内所有节点(包含孤立节点)
Set<String> groupNodes = new HashSet<>();
Queue<String> queue = new LinkedList<>(groupRoots);
while (!queue.isEmpty()) {
String node = queue.poll();
if (groupNodes.contains(node)) continue;
groupNodes.add(node);
if (parentToChildren.containsKey(node)) {
queue.addAll(parentToChildren.get(node));
}
}
// BFS遍历分配序号(包含孤立节点)
List<NodeInfo> nodeInfoList = new ArrayList<>();
Map<String, Integer> originalToGlobalSerial = new HashMap<>();
Queue<String> bfsQueue = new LinkedList<>(groupRoots);
Set<String> visited = new HashSet<>(groupRoots);
int groupCounter = 1;
// 处理根节点(包括孤立节点)
for (String root : groupRoots) {
originalToGlobalSerial.put(root, globalCounter[0]);
nodeInfoList.add(new NodeInfo(root, globalCounter[0]++, groupCounter++, new ArrayList<>(), new ArrayList<>()));
}
// 处理子节点
while (!bfsQueue.isEmpty()) {
String parent = bfsQueue.poll();
if (parentToChildren.containsKey(parent)) {
for (String child : parentToChildren.get(parent)) {
if (!groupNodes.contains(child) || visited.contains(child)) continue;
visited.add(child);
originalToGlobalSerial.put(child, globalCounter[0]);
List<Integer> parentSerials = childToParents.getOrDefault(child, new HashSet<>()).stream()
.filter(p -> originalToGlobalSerial.containsKey(p))
.map(originalToGlobalSerial::get)
.distinct()
.collect(Collectors.toList());
nodeInfoList.add(new NodeInfo(child, globalCounter[0]++, groupCounter++, parentSerials, new ArrayList<>()));
bfsQueue.add(child);
}
}
}
// 填充子ID列表(过滤空值)
for (NodeInfo nodeInfo : nodeInfoList) {
String originalId = nodeInfo.getOriginalId();
if (parentToChildren.containsKey(originalId)) {
List<Integer> childSerials = parentToChildren.get(originalId).stream()
.filter(c -> originalToGlobalSerial.containsKey(c))
.map(originalToGlobalSerial::get)
.distinct()
.collect(Collectors.toList());
nodeInfo.setNewChildIds(childSerials);
}
}
return new GroupResult(nodeInfoList, originalToGlobalSerial);
}
/**
* 主方法:处理包含空ChildID的数据
*/
public static List<GroupResult> groupAndOrderIds(List<String> idList, List<String> childIdList) {
List<List<String>> groups = groupNoParentIds(idList, childIdList);
Map<String, Set<String>> parentToChildren = new HashMap<>();
Map<String, Set<String>> childToParents = new HashMap<>();
for (int i = 0; i < idList.size(); i++) {
String parentId = idList.get(i);
String childId = childIdList.get(i);
if (childId == null || childId.trim().isEmpty()) {
continue;
}
parentToChildren.computeIfAbsent(parentId, k -> new HashSet<>()).add(childId);
childToParents.computeIfAbsent(childId, k -> new HashSet<>()).add(parentId);
}
int[] globalCounter = {1};
List<GroupResult> results = new ArrayList<>();
for (List<String> groupRoots : groups) {
GroupResult groupResult = processSingleGroup(groupRoots, parentToChildren, childToParents, globalCounter);
results.add(groupResult);
}
return results;
}
/**
* 简化添加新节点:直接指定新父ID、新子ID
* @param existingResults 已有结果
* @param targetGroupIndex 目标分组索引(如分组2为1)
* @param newId 新节点原始ID
* @param newParentIds 新节点的父ID列表(全局序号)
* @param newChildIds 新节点的子ID列表(全局序号)
* @return 更新后的结果
*/
/**
* 简化添加新节点:直接指定新父ID、新子ID(修复全局序号重复问题)
* @param existingResults 已有结果
* @param targetGroupIndex 目标分组索引(如分组2为1)
* @param newId 新节点原始ID
* @param newParentIds 新节点的父ID列表(全局序号)
* @param newChildIds 新节点的子ID列表(全局序号)
* @return 更新后的结果
*/
public static List<GroupResult> addNode(List<GroupResult> existingResults, int targetGroupIndex,
String newId, List<Integer> newParentIds, List<Integer> newChildIds) {
// 1. 空值安全检查
if (existingResults == null || existingResults.isEmpty() || targetGroupIndex < 0 || targetGroupIndex >= existingResults.size()) {
throw new IllegalArgumentException("无效的现有结果或目标分组索引");
}
if (newId == null || newId.trim().isEmpty()) {
throw new IllegalArgumentException("新节点ID不能为空");
}
newParentIds = newParentIds != null ? newParentIds : new ArrayList<>();
newChildIds = newChildIds != null ? newChildIds : new ArrayList<>();
// 2. 获取目标分组
GroupResult targetGroup = existingResults.get(targetGroupIndex);
List<NodeInfo> nodeList = new ArrayList<>(targetGroup.getNodeInfoList());
Map<String, Integer> serialMap = new HashMap<>(targetGroup.getOriginalToGlobalSerial());
// 3. 计算所有分组的最大全局序号(确保全局唯一)
int maxGlobalSerial = existingResults.stream()
.flatMap(g -> g.getNodeInfoList().stream())
.mapToInt(NodeInfo::getGlobalSerial)
.max()
.orElse(0);
int newGlobalSerial = maxGlobalSerial + 1;
// 4. 避免新序号与目标分组内现有序号冲突(双重保障)
while (serialMap.containsValue(newGlobalSerial)) {
newGlobalSerial++;
}
// 5. 找到新节点的插入位置(父节点之后)
int insertIndex = 0;
for (int i = 0; i < nodeList.size(); i++) {
NodeInfo node = nodeList.get(i);
if (newParentIds.contains(node.getGlobalSerial())) {
insertIndex = i + 1; // 插入到最后一个父节点之后
}
}
// 6. 创建新节点(分组内序号先设为0,后续重新计算)
NodeInfo newNode = new NodeInfo(newId, newGlobalSerial, 0, newParentIds, newChildIds);
nodeList.add(insertIndex, newNode);
serialMap.put(newId, newGlobalSerial);
// 7. 更新父节点的子ID列表(添加新节点的全局序号)
for (NodeInfo node : nodeList) {
if (newParentIds.contains(node.getGlobalSerial())) {
List<Integer> childIds = new ArrayList<>(node.getNewChildIds());
if (!childIds.contains(newGlobalSerial)) {
childIds.add(newGlobalSerial);
node.setNewChildIds(childIds);
}
}
}
// 8. 更新子节点的父ID列表(添加新节点的全局序号)
for (NodeInfo node : nodeList) {
if (newChildIds.contains(node.getGlobalSerial())) {
List<Integer> parentIds = new ArrayList<>(node.getNewParentIds());
if (!parentIds.contains(newGlobalSerial)) {
parentIds.add(newGlobalSerial);
node.setNewParentIds(parentIds);
}
}
}
// 9. 重新计算分组内序号(按列表顺序)
for (int i = 0; i < nodeList.size(); i++) {
nodeList.get(i).setGroupSerial(i + 1);
}
// 10. 替换目标分组并返回结果
List<GroupResult> newResults = new ArrayList<>(existingResults);
newResults.set(targetGroupIndex, new GroupResult(nodeList, serialMap));
return newResults;
}
/**
* 通过全局序号删除节点,并重新计算顺序和父子关系
* @param existingResults 已有分组结果
* @param deleteGlobalSerial 待删除节点的全局序号
* @return 删除后的分组结果
*/
public static List<GroupResult> deleteNodeByGlobalSerial(List<GroupResult> existingResults, int deleteGlobalSerial) {
// 1. 定位待删除节点及其所在分组
NodeInfo deleteNode = null;
int targetGroupIndex = -1;
GroupResult targetGroup = null;
for (int i = 0; i < existingResults.size(); i++) {
GroupResult group = existingResults.get(i);
Optional<NodeInfo> nodeOpt = group.getNodeInfoList().stream()
.filter(node -> deleteGlobalSerial == node.getGlobalSerial())
.findFirst();
if (nodeOpt.isPresent()) {
deleteNode = nodeOpt.get();
targetGroupIndex = i;
targetGroup = group;
break;
}
}
if (deleteNode == null) {
System.out.println("待删除节点不存在(全局序号:" + deleteGlobalSerial + ")");
return existingResults;
}
// 2. 获取待删除节点的关键信息
String deleteOriginalId = deleteNode.getOriginalId();
List<Integer> deleteParentIds = deleteNode.getNewParentIds();
List<Integer> deleteChildIds = deleteNode.getNewChildIds();
// 3. 从分组中移除节点,并清理序号映射
List<NodeInfo> newNodeList = targetGroup.getNodeInfoList().stream()
.filter(node -> deleteGlobalSerial != node.getGlobalSerial())
.collect(Collectors.toList());
Map<String, Integer> newSerialMap = new HashMap<>(targetGroup.getOriginalToGlobalSerial());
newSerialMap.remove(deleteOriginalId);
// 4. 更新父节点的子ID列表(移除待删除节点的全局序号)
for (NodeInfo node : newNodeList) {
if (deleteParentIds.contains(node.getGlobalSerial())) {
List<Integer> newChildIds = node.getNewChildIds().stream()
.filter(id -> id != deleteGlobalSerial)
.collect(Collectors.toList());
node.setNewChildIds(newChildIds);
}
}
// 5. 更新子节点的父ID列表(移除待删除节点的全局序号)
for (NodeInfo node : newNodeList) {
if (deleteChildIds.contains(node.getGlobalSerial())) {
List<Integer> newParentIds = node.getNewParentIds().stream()
.filter(id -> id != deleteGlobalSerial)
.collect(Collectors.toList());
node.setNewParentIds(newParentIds);
}
}
// 6. 重新计算分组内序号(顺序顺延)
for (int i = 0; i < newNodeList.size(); i++) {
newNodeList.get(i).setGroupSerial(i + 1);
}
// 7. (可选)重新计算全局序号(保持连续性,如需可开启)
// resetGlobalSerial(existingResults, targetGroupIndex, newNodeList);
// 8. 替换目标分组并返回结果
List<GroupResult> newResults = new ArrayList<>(existingResults);
newResults.set(targetGroupIndex, new GroupResult(newNodeList, newSerialMap));
return newResults;
}
/**
* 添加新数据(支持仅孤立节点的场景)
* @param existingResults 已有分组结果
* @param newIdList 新数据的ID列表
* @param newChildIdList 新数据的ChildID列表(允许空值)
* @return 包含新分组的结果列表
*/
public static List<GroupResult> addNewDataWithIsolatedGroup(List<GroupResult> existingResults, List<String> newIdList, List<String> newChildIdList) {
// 空值安全检查
if (newIdList == null || newIdList.isEmpty()) {
return existingResults;
}
if (newChildIdList == null) {
newChildIdList = new ArrayList<>();
}
// 1. 初始化数据结构
Set<String> allNewNodes = new HashSet<>(newIdList); // 所有新节点
Map<String, String> idToChild = new HashMap<>(); // 临时存储ID与ChildID的映射
// 构建ID→ChildID映射(处理空值)
for (int i = 0; i < newIdList.size(); i++) {
String id = newIdList.get(i);
String childId = i < newChildIdList.size() ? newChildIdList.get(i) : "";
if (id != null && !id.trim().isEmpty()) {
idToChild.put(id, (childId == null ? "" : childId.trim()));
allNewNodes.add(id); // 确保ID被加入
if (!childId.trim().isEmpty()) {
allNewNodes.add(childId.trim()); // 子节点也加入
}
}
}
// 2. 分离孤立节点和关联节点
List<String> isolatedNodes = new ArrayList<>();
List<String> relationNodes = new ArrayList<>();
for (String node : allNewNodes) {
String childId = idToChild.getOrDefault(node, "");
// 孤立节点:无ChildID,且不是任何节点的ChildID
boolean isIsolated = childId.isEmpty() && !idToChild.values().contains(node);
if (isIsolated) {
isolatedNodes.add(node);
} else {
relationNodes.add(node);
}
}
// 3. 获取现有结果的最大全局序号
int maxGlobalSerial = existingResults.stream()
.flatMap(g -> g.getNodeInfoList().stream())
.mapToInt(NodeInfo::getGlobalSerial)
.max()
.orElse(0);
int[] globalCounter = {maxGlobalSerial + 1};
// 4. 处理关联节点(如果有)
if (!relationNodes.isEmpty()) {
GroupResult relationGroup = createRelationGroup(idToChild, relationNodes, globalCounter);
existingResults.add(relationGroup);
}
// 5. 处理孤立节点(即使只有孤立节点也创建分组)
for (String isolatedNode : isolatedNodes) {
GroupResult isolatedGroup = createIsolatedGroup(isolatedNode, globalCounter);
existingResults.add(isolatedGroup);
}
return existingResults;
}
/**
* 创建关联节点的分组(20→21→22)
*/
private static GroupResult createRelationGroup(Map<String, String> idToChild, List<String> relationNodes, int[] globalCounter) {
// 构建父子映射
Map<String, Set<String>> parentToChildren = new HashMap<>();
Map<String, Set<String>> childToParents = new HashMap<>();
for (String parent : idToChild.keySet()) {
String child = idToChild.get(parent);
if (!child.isEmpty()) {
parentToChildren.computeIfAbsent(parent, k -> new HashSet<>()).add(child);
childToParents.computeIfAbsent(child, k -> new HashSet<>()).add(parent);
}
}
// 识别根节点(无父级的节点)
List<String> rootNodes = relationNodes.stream()
.filter(node -> !childToParents.containsKey(node))
.collect(Collectors.toList());
List<NodeInfo> nodeList = new ArrayList<>();
Map<String, Integer> serialMap = new HashMap<>();
Queue<String> queue = new LinkedList<>(rootNodes);
Set<String> visited = new HashSet<>(rootNodes);
int groupCounter = 1;
// 处理根节点
for (String root : rootNodes) {
serialMap.put(root, globalCounter[0]);
nodeList.add(new NodeInfo(root, globalCounter[0]++, groupCounter++, new ArrayList<>(), new ArrayList<>()));
}
// BFS处理子节点
while (!queue.isEmpty()) {
String parent = queue.poll();
if (parentToChildren.containsKey(parent)) {
for (String child : parentToChildren.get(parent)) {
if (visited.contains(child)) continue;
visited.add(child);
List<Integer> parentSerials = childToParents.get(child).stream()
.map(p -> serialMap.get(p))
.collect(Collectors.toList());
serialMap.put(child, globalCounter[0]);
nodeList.add(new NodeInfo(child, globalCounter[0]++, groupCounter++, parentSerials, new ArrayList<>()));
queue.add(child);
}
}
}
// 填充子ID列表
for (NodeInfo node : nodeList) {
String originalId = node.getOriginalId();
if (parentToChildren.containsKey(originalId)) {
List<Integer> childSerials = parentToChildren.get(originalId).stream()
.map(c -> serialMap.get(c))
.collect(Collectors.toList());
node.setNewChildIds(childSerials);
}
}
return new GroupResult(nodeList, serialMap);
}
/**
* 创建孤立节点的分组(如24)
*/
private static GroupResult createIsolatedGroup(String isolatedNode, int[] globalCounter) {
NodeInfo node = new NodeInfo(isolatedNode, globalCounter[0], 1, new ArrayList<>(), new ArrayList<>());
List<NodeInfo> nodeList = Collections.singletonList(node);
Map<String, Integer> serialMap = Collections.singletonMap(isolatedNode, globalCounter[0]++);
return new GroupResult(nodeList, serialMap);
}
// 测试(新数据)
public static void Test() {
// 新表格数据
List<String> idList = Arrays.asList("1", "2", "3", "3", "5", "10", "3", "6", "7", "9","23");
List<String> childIdList = Arrays.asList("2", "3", "4", "4", "10", "3", "11", "7", "8", "7","");
// 分组并生成结果
List<GroupResult> results = groupAndOrderIds(idList, childIdList);
// 新增节点信息
// 直接指定新节点信息:原始ID=12,新父ID=[8,9],新子ID=[11]
String newId = "13";
List<Integer> newParentIds = Arrays.asList(8, 9); // 6和9的全局序号
List<Integer> newChildIds = Arrays.asList(11); // 8的全局序号
int targetGroupIndex = 1; // 分组2的索引
// 添加新节点
results = addNode(results, targetGroupIndex, newId, newParentIds, newChildIds);
List<String> newIdList = Arrays.asList("20", "21", "24");
List<String> newChildIdList = Arrays.asList("21", "22", "");
// 添加新数据
results = addNewDataWithIsolatedGroup(results, newIdList, newChildIdList);
results = deleteNodeByGlobalSerial(results, 13);
// 输出结果
for (int i = 0; i < results.size(); i++) {
GroupResult groupResult = results.get(i);
List<NodeInfo> nodeInfoList = groupResult.getNodeInfoList();
System.out.println("分组" + (i + 1) + "顺序:" + nodeInfoList);
// 输出每个节点的详细信息
for (NodeInfo nodeInfo : nodeInfoList) {
System.out.printf("原始ID:%s → 全局序号:%d,分组内序号:%d,新父ID列表:%s,新子ID列表:%s%n",
nodeInfo.getOriginalId(),
nodeInfo.getGlobalSerial(),
nodeInfo.getGroupSerial(),
nodeInfo.getNewParentIds().isEmpty() ? "无" : nodeInfo.getNewParentIds(),
nodeInfo.getNewChildIds());
}
System.out.println("------------------------");
}
}
}
...@@ -17,9 +17,11 @@ import java.util.stream.IntStream; ...@@ -17,9 +17,11 @@ import java.util.stream.IntStream;
*/ */
public class Initialization { public class Initialization {
private static List<Entry> allOperations; private static List<Entry> allOperations;
private static GlobalParam _globalParam;
public Initialization(List<Entry> allOperations) { public Initialization(GlobalParam globalParam,List<Entry> allOperations) {
Initialization.allOperations = allOperations; Initialization.allOperations = allOperations;
_globalParam= globalParam;
} }
/** /**
* 预生成全局工序列表(按“订单0→订单1→…+订单内工序1→2→…”排序,分配GlobalOpId) * 预生成全局工序列表(按“订单0→订单1→…+订单内工序1→2→…”排序,分配GlobalOpId)
...@@ -257,7 +259,7 @@ int populationSize=param.getPopulationSize(); ...@@ -257,7 +259,7 @@ int populationSize=param.getPopulationSize();
*/ */
private List<Integer> shuffleWithPriority(List<Integer> os) { private List<Integer> shuffleWithPriority(List<Integer> os) {
if (!GlobalParam.IsBreakPriority) { if (!_globalParam.isIsBreakPriority()) {
return new ArrayList<>(os); return new ArrayList<>(os);
} }
......
...@@ -4,6 +4,7 @@ import com.aps.common.util.ProductionDeepCopyUtil; ...@@ -4,6 +4,7 @@ import com.aps.common.util.ProductionDeepCopyUtil;
import com.aps.entity.Algorithm.GAScheduleResult; import com.aps.entity.Algorithm.GAScheduleResult;
import com.aps.entity.Algorithm.ScheduleResultDetail; import com.aps.entity.Algorithm.ScheduleResultDetail;
import com.aps.entity.basic.*; import com.aps.entity.basic.*;
import com.aps.service.plan.AlgorithmScheduler8;
import com.aps.service.plan.MachineSchedulerService; import com.aps.service.plan.MachineSchedulerService;
import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils;
...@@ -37,15 +38,15 @@ public class MachineCalculator { ...@@ -37,15 +38,15 @@ public class MachineCalculator {
* 获取机器下一个可用时间窗口(考虑班次约束) * 获取机器下一个可用时间窗口(考虑班次约束)
*/ */
public List<ScheduleResultDetail> getNextAvailableTime(Machine machine, int proposedStartTime, public List<ScheduleResultDetail> getNextAvailableTime(Machine machine, int proposedStartTime,
int prevtime, double processingTime, int prevtime, int processingTime,
List<GAScheduleResult> existingTasks, List<GAScheduleResult> existingTasks,
boolean isInterrupt, boolean istask, boolean isInterrupt, boolean istask,
boolean islockMachineTime) { boolean islockMachineTime) {
LocalDateTime startTime = baseTime.plus(proposedStartTime, ChronoUnit.MINUTES); LocalDateTime startTime = baseTime.plus(proposedStartTime, ChronoUnit.SECONDS);
String prevtimestr = ""; String prevtimestr = "";
if (prevtime > -1) { if (prevtime > -1) {
prevtimestr = baseTime.plus(prevtime, ChronoUnit.MINUTES) prevtimestr = baseTime.plus(prevtime, ChronoUnit.SECONDS)
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
} }
...@@ -55,54 +56,49 @@ public class MachineCalculator { ...@@ -55,54 +56,49 @@ public class MachineCalculator {
} }
// 查找最早可用开始时间 // 查找最早可用开始时间
private List<ScheduleResultDetail> findEarliestStart(Machine machine, double processingTime,
LocalDateTime currentTime, String prevtime, private List<ScheduleResultDetail> findEarliestStart(
List<GAScheduleResult> existingTasks, Machine machine, int processingTime, LocalDateTime currentTime,
boolean checkprevtime, boolean islockMachineTime) { String prevtime, List<GAScheduleResult> existingTasks, boolean checkprevtime, boolean islockMachineTime
// 获取设备上已有任务 ) {
List<GAScheduleResult> machineTasks = existingTasks.stream() List<GAScheduleResult> machineTasks = existingTasks.stream()
.filter(t -> t.getMachineId() == machine.getId()) .filter(t -> t.getMachineId() == machine.getId())
.sorted(Comparator.comparingInt(GAScheduleResult::getStartTime)) .sorted(Comparator.comparingInt(GAScheduleResult::getStartTime))
.collect(Collectors.toList()); .collect(Collectors.toList());
List<ScheduleResultDetail> times = new ArrayList<>(); List<ScheduleResultDetail> times = new ArrayList<>();
TimeSegment slot =GetCurrentOrNextShift(machine, currentTime, prevtime, checkprevtime); TimeSegment slot = GetCurrentOrNextShift(machine, currentTime, prevtime, checkprevtime);
if (slot == null) return times;
LocalDateTime startCandidate = slot.getStart().isAfter(
(prevtime.isEmpty() ? currentTime : LocalDateTime.parse(prevtime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
) ? slot.getStart() : (prevtime.isEmpty() ? currentTime : LocalDateTime.parse(prevtime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
LocalDateTime endCandidate = startCandidate.plus((long)processingTime, ChronoUnit.MINUTES); LocalDateTime prevTimeDateTime = StringUtils.isEmpty(prevtime) ? null : LocalDateTime.parse(prevtime);
LocalDateTime startCandidate = slot.getStart().isAfter(prevTimeDateTime != null ? prevTimeDateTime : currentTime)
? slot.getStart()
: (prevTimeDateTime != null ? prevTimeDateTime : currentTime);
LocalDateTime endCandidate = startCandidate.plusSeconds(processingTime);
// 检查是否在可用时间段内
if (endCandidate.isAfter(slot.getEnd())) { if (endCandidate.isAfter(slot.getEnd())) {
// 放不下,继续寻找后续可用时间 return CaldEarliestStart(machine, processingTime, currentTime, prevtime, machineTasks, checkprevtime,islockMachineTime);
return CaldEarliestStart(machine, processingTime, currentTime, prevtime,
machineTasks, checkprevtime, islockMachineTime);
} else { } else {
ScheduleResultDetail time = new ScheduleResultDetail(); ScheduleResultDetail time = new ScheduleResultDetail();
time.setKey(slot.getKey()); time.setKey(slot.getKey());
time.setStartTime((int) ChronoUnit.MINUTES.between(baseTime, startCandidate)); time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, startCandidate));
time.setEndTime((int) ChronoUnit.MINUTES.between(baseTime, endCandidate)); time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, endCandidate));
times.add(time); times.add(time);
if(islockMachineTime) {
if (islockMachineTime) {
RemoveMachineAvailable(machine, time); RemoveMachineAvailable(machine, time);
} }
return times; return times;
} }
} }
private List<ScheduleResultDetail> CaldEarliestStart( private List<ScheduleResultDetail> CaldEarliestStart(
Machine machine, double processingTime, LocalDateTime currentTime, Machine machine, int processingTime, LocalDateTime currentTime,
String prevtime, List<GAScheduleResult> machineTasks, boolean checkprevtime, boolean islockMachineTime String prevtime, List<GAScheduleResult> machineTasks, boolean checkprevtime, boolean islockMachineTime
) { ) {
double remainingTime = processingTime; int remainingTime = processingTime;
LocalDateTime st = StringUtils.isEmpty(prevtime) ? currentTime : LocalDateTime.parse(prevtime); LocalDateTime st = StringUtils.isEmpty(prevtime) ? currentTime : LocalDateTime.parse(prevtime);
LocalDateTime prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0, 0); LocalDateTime prevEnd = LocalDateTime.of(2000, 1, 1, 0, 0, 0);
List<ScheduleResultDetail> times = new ArrayList<>(); List<ScheduleResultDetail> times = new ArrayList<>();
...@@ -122,7 +118,7 @@ public class MachineCalculator { ...@@ -122,7 +118,7 @@ public class MachineCalculator {
LocalDateTime finalPrevEnd = prevEnd; LocalDateTime finalPrevEnd = prevEnd;
boolean hasTask = machineTasks.stream() boolean hasTask = machineTasks.stream()
.anyMatch(t -> { .anyMatch(t -> {
LocalDateTime taskStart = baseTime.plusMinutes(t.getStartTime()); LocalDateTime taskStart = baseTime.plusSeconds(t.getStartTime());
return taskStart.isAfter(finalPrevEnd) && taskStart.isBefore(shiftStart); return taskStart.isAfter(finalPrevEnd) && taskStart.isBefore(shiftStart);
}); });
...@@ -158,29 +154,34 @@ public class MachineCalculator { ...@@ -158,29 +154,34 @@ public class MachineCalculator {
prevEnd = shiftEnd; prevEnd = shiftEnd;
// 计算有效时间 // 计算有效时间
LocalDateTime effectiveStart = st.isAfter(shiftStart) ? st : shiftStart; LocalDateTime effectiveStart = st.isAfter(shiftStart) ? st : shiftStart;
long availableMinutes = ChronoUnit.MINUTES.between(effectiveStart, shiftEnd); long availableSeconds = ChronoUnit.SECONDS.between(effectiveStart, shiftEnd);
// 处理当前班次 // 处理当前班次
double processable = Math.min(remainingTime, (int) availableMinutes); int processable = Math.min(remainingTime, (int) availableSeconds);
remainingTime -= processable; remainingTime -= processable;
currentTime = effectiveStart.plusMinutes((long)processable); currentTime = effectiveStart.plusSeconds(processable);
// 添加时间详情 // 添加时间详情
ScheduleResultDetail time = new ScheduleResultDetail(); ScheduleResultDetail time = new ScheduleResultDetail();
time.setKey(shift.getKey()); time.setKey(shift.getKey());
time.setStartTime((int) ChronoUnit.MINUTES.between(baseTime, effectiveStart)); time.setStartTime((int) ChronoUnit.SECONDS.between(baseTime, effectiveStart));
time.setEndTime((int) ChronoUnit.MINUTES.between(baseTime, currentTime)); time.setEndTime((int) ChronoUnit.SECONDS.between(baseTime, currentTime));
times.add(time); times.add(time);
if (islockMachineTime) { if (islockMachineTime) {
// 还原未使用的时间段
RemoveMachineAvailable(machine, time); RemoveMachineAvailable(machine, time);
} }
} }
// 还原未使用的时间段
if (islockMachineTime) { if (islockMachineTime) {
// 还原未使用的时间段 // 还原未使用的时间段
AddMachineAvailable(machine, oldTimes); AddMachineAvailable(machine, oldTimes);
} }
return times; return times;
} }
/** /**
* 获取设备当前或下一个有效班次 * 获取设备当前或下一个有效班次
*/ */
...@@ -196,7 +197,7 @@ public class MachineCalculator { ...@@ -196,7 +197,7 @@ public class MachineCalculator {
if (start == null) { if (start == null) {
// 生成新时间段 // 生成新时间段
List<TimeSegment> timeSegments = machineScheduler.generateTimeSegment(machine, time); List<TimeSegment> timeSegments = machineScheduler.generateTimeSegment(machine, time.plusDays(1));
machine.getAvailability().addAll(timeSegments); machine.getAvailability().addAll(timeSegments);
// 更新设备时间线 // 更新设备时间线
...@@ -215,6 +216,8 @@ public class MachineCalculator { ...@@ -215,6 +216,8 @@ public class MachineCalculator {
return start; return start;
} }
private void RemoveMachineAvailable(Machine machine, ScheduleResultDetail geneDetails) { private void RemoveMachineAvailable(Machine machine, ScheduleResultDetail geneDetails) {
List<TimeSegment> timeSegments = new ArrayList<>(); List<TimeSegment> timeSegments = new ArrayList<>();
...@@ -226,11 +229,11 @@ public class MachineCalculator { ...@@ -226,11 +229,11 @@ public class MachineCalculator {
if (index > -1) { if (index > -1) {
TimeSegment targetSegment = machine.getAvailability().get(index); TimeSegment targetSegment = machine.getAvailability().get(index);
LocalDateTime geneEndTime = baseTime.plusMinutes(geneDetails.getEndTime()); LocalDateTime geneEndTime = baseTime.plusSeconds(geneDetails.getEndTime());
if (targetSegment.getEnd().isAfter(geneEndTime)) { if (targetSegment.getEnd().isAfter(geneEndTime)) {
TimeSegment usedSegment = new TimeSegment(); TimeSegment usedSegment = new TimeSegment();
usedSegment.setStart(baseTime.plusMinutes(geneDetails.getStartTime())); usedSegment.setStart(baseTime.plusSeconds(geneDetails.getStartTime()));
usedSegment.setEnd(geneEndTime); usedSegment.setEnd(geneEndTime);
usedSegment.setHoliday(false); usedSegment.setHoliday(false);
usedSegment.setKey(UUID.randomUUID().toString()); usedSegment.setKey(UUID.randomUUID().toString());
......
...@@ -9,6 +9,7 @@ import org.springframework.util.CollectionUtils; ...@@ -9,6 +9,7 @@ import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.util.*; import java.util.*;
import java.util.function.Function; import java.util.function.Function;
...@@ -35,7 +36,7 @@ public class OrderSortService { ...@@ -35,7 +36,7 @@ public class OrderSortService {
registerFieldExtractor("dueDate", Order -> { registerFieldExtractor("dueDate", Order -> {
// 直接返回LocalDate,处理null情况 // 直接返回LocalDate,处理null情况
return Optional.ofNullable(Order.getDueDate()) return Optional.ofNullable(Order.getDueDate())
.map(OffsetDateTime::toLocalDate) .map(LocalDateTime::toLocalDate)
.orElse(null); .orElse(null);
}); });
registerFieldExtractor("priority", Order::getPriority); registerFieldExtractor("priority", Order::getPriority);
......
...@@ -324,7 +324,7 @@ public class AlgorithmScheduler6 { ...@@ -324,7 +324,7 @@ public class AlgorithmScheduler6 {
LocalDateTime completionTime = chromosome.getBaseTime().plusMinutes(orderCompletion); LocalDateTime completionTime = chromosome.getBaseTime().plusMinutes(orderCompletion);
// 修复:正确处理OffsetDateTime到LocalDateTime的转换 // 修复:正确处理OffsetDateTime到LocalDateTime的转换
LocalDateTime dueDateTime = order.getDueDate().toLocalDateTime(); LocalDateTime dueDateTime = order.getDueDate();
if (completionTime.isAfter(dueDateTime)) { if (completionTime.isAfter(dueDateTime)) {
// 计算延迟小时数(修复时间计算) // 计算延迟小时数(修复时间计算)
......
...@@ -473,7 +473,7 @@ public class AlgorithmScheduler7 { ...@@ -473,7 +473,7 @@ public class AlgorithmScheduler7 {
if (order != null) { if (order != null) {
LocalDateTime completionTime = chromosome.getBaseTime().plusMinutes(orderCompletion); LocalDateTime completionTime = chromosome.getBaseTime().plusMinutes(orderCompletion);
LocalDateTime dueDateTime = order.getDueDate().toLocalDateTime(); LocalDateTime dueDateTime = order.getDueDate();
if (completionTime.isAfter(dueDateTime)) { if (completionTime.isAfter(dueDateTime)) {
long totalMinutes = java.time.temporal.ChronoUnit.MINUTES.between(dueDateTime, completionTime); long totalMinutes = java.time.temporal.ChronoUnit.MINUTES.between(dueDateTime, completionTime);
......
...@@ -94,7 +94,7 @@ public class AlgorithmScheduler8 { ...@@ -94,7 +94,7 @@ public class AlgorithmScheduler8 {
// 为每个订单分配工序 // 为每个订单分配工序
for (Order order : _orders) { for (Order order : _orders) {
Product product = _products.stream() Product product = _products.stream()
.filter(p -> p.getId() == order.getProductId()) .filter(p -> p.getId()==order.getProductId())
.findFirst() .findFirst()
.orElseThrow(() -> new NoSuchElementException("Product not found: " + order.getProductId())); .orElseThrow(() -> new NoSuchElementException("Product not found: " + order.getProductId()));
...@@ -322,7 +322,7 @@ public class AlgorithmScheduler8 { ...@@ -322,7 +322,7 @@ public class AlgorithmScheduler8 {
// 创建基因 // 创建基因
Gene gene = new Gene(); Gene gene = new Gene();
gene.setOrderId(order.getId()); // gene.setOrderId(order.getId());
gene.setProductId(order.getProductId()); gene.setProductId(order.getProductId());
gene.setOperationId(operation.getId()); gene.setOperationId(operation.getId());
gene.setMachineId(machine.getId()); gene.setMachineId(machine.getId());
...@@ -415,21 +415,21 @@ public class AlgorithmScheduler8 { ...@@ -415,21 +415,21 @@ public class AlgorithmScheduler8 {
.mapToInt(Gene::getEndTime) .mapToInt(Gene::getEndTime)
.max() .max()
.orElse(0); .orElse(0);
Order order = _orders.stream() // Order order = _orders.stream()
.filter(o -> o.getId() == group.getKey()) // .filter(o -> o.getId() == group.getKey())
.findFirst() // .findFirst()
.orElse(null); // .orElse(null);
//
if (order != null) { // if (order != null) {
LocalDateTime completionTime = chromosome.getBaseTime().plusMinutes(orderCompletion); // LocalDateTime completionTime = chromosome.getBaseTime().plusMinutes(orderCompletion);
LocalDateTime dueDateTime = order.getDueDate().toLocalDateTime(); // LocalDateTime dueDateTime = order.getDueDate();
//
if (completionTime.isAfter(dueDateTime)) { // if (completionTime.isAfter(dueDateTime)) {
long hours = ChronoUnit.HOURS.between(dueDateTime, completionTime); // long hours = ChronoUnit.HOURS.between(dueDateTime, completionTime);
long minutes = ChronoUnit.MINUTES.between(dueDateTime, completionTime) % 60; // long minutes = ChronoUnit.MINUTES.between(dueDateTime, completionTime) % 60;
tardiness += hours + (double) minutes / 60; // tardiness += hours + (double) minutes / 60;
} // }
} // }
} }
// 3. 总换型时间 // 3. 总换型时间
......
...@@ -206,7 +206,12 @@ public class MachineSchedulerService { ...@@ -206,7 +206,12 @@ public class MachineSchedulerService {
&& s.getDays() != null && s.getDays() != null
&& containsDay(s.getDays(), date.getDayOfWeek())) && containsDay(s.getDays(), date.getDayOfWeek()))
.collect(Collectors.toList()); .collect(Collectors.toList());
if(shifts==null||shifts.size()==0) {
shifts = machine.getShifts().stream()
.filter(s -> s.getDays() != null
&& containsDay(s.getDays(), date.getDayOfWeek()))
.collect(Collectors.toList());
}
for (Shift shift : shifts) { for (Shift shift : shifts) {
LocalDateTime shiftStart = date.atTime(shift.getStartTime()); LocalDateTime shiftStart = date.atTime(shift.getStartTime());
LocalDateTime shiftEnd = shift.getEndTime().isBefore(shift.getStartTime()) ? LocalDateTime shiftEnd = shift.getEndTime().isBefore(shift.getStartTime()) ?
...@@ -247,6 +252,12 @@ public class MachineSchedulerService { ...@@ -247,6 +252,12 @@ public class MachineSchedulerService {
} }
private List<TimeSegment> mergeSegments(List<TimeSegment> segments) { private List<TimeSegment> mergeSegments(List<TimeSegment> segments) {
if(segments==null||segments.size()==0)
{
return null;
}
List<TimeSegment> maintenanceSegments = segments.stream() List<TimeSegment> maintenanceSegments = segments.stream()
.filter(t -> t.getType() == SegmentType.MAINTENANCE) .filter(t -> t.getType() == SegmentType.MAINTENANCE)
.collect(Collectors.toList()); .collect(Collectors.toList());
......
...@@ -7,6 +7,8 @@ import com.aps.controller.gantt.FileUploadController; ...@@ -7,6 +7,8 @@ import com.aps.controller.gantt.FileUploadController;
import com.aps.entity.*; import com.aps.entity.*;
import com.aps.entity.Algorithm.Chromosome; import com.aps.entity.Algorithm.Chromosome;
import com.aps.entity.Algorithm.GAScheduleResult; import com.aps.entity.Algorithm.GAScheduleResult;
import com.aps.entity.Algorithm.IDAndChildID.GroupResult;
import com.aps.entity.Algorithm.IDAndChildID.NodeInfo;
import com.aps.entity.Algorithm.ScheduleParams; import com.aps.entity.Algorithm.ScheduleParams;
import com.aps.entity.Algorithm.ScheduleResultDetail; import com.aps.entity.Algorithm.ScheduleResultDetail;
import com.aps.entity.basic.ScheduleChromosome; import com.aps.entity.basic.ScheduleChromosome;
...@@ -15,6 +17,7 @@ import com.aps.entity.Schedule.MachineVO; ...@@ -15,6 +17,7 @@ import com.aps.entity.Schedule.MachineVO;
import com.aps.entity.basic.*; import com.aps.entity.basic.*;
import com.aps.service.*; import com.aps.service.*;
import com.aps.service.Algorithm.GeneticAlgorithm; import com.aps.service.Algorithm.GeneticAlgorithm;
import com.aps.service.Algorithm.IdGroupingWithDualSerial;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -41,6 +44,10 @@ public class PlanResultService { ...@@ -41,6 +44,10 @@ public class PlanResultService {
@Autowired @Autowired
private MesShiftWorkSchedService _MesShiftWorkSchedService; private MesShiftWorkSchedService _MesShiftWorkSchedService;
@Autowired
private ProdLaunchOrderService _prodLaunchOrderService;
@Autowired @Autowired
private ProdProcessExecService _prodProcessExecService; private ProdProcessExecService _prodProcessExecService;
...@@ -119,7 +126,7 @@ public class PlanResultService { ...@@ -119,7 +126,7 @@ public class PlanResultService {
} }
} }
public List<Chromosome> execute1() { public Chromosome execute1() {
try { try {
...@@ -189,7 +196,7 @@ public class PlanResultService { ...@@ -189,7 +196,7 @@ public class PlanResultService {
for (Operation o : product.getOperations()) { // 假设Product类有getOperations()方法返回工序列表 for (Operation o : product.getOperations()) { // 假设Product类有getOperations()方法返回工序列表
Entry entry = new Entry(); Entry entry = new Entry();
entry.setId(id); entry.setId(id);
entry.setGroupId(order.getId()); // entry.setGroupId(order.getId());
entry.setSequence(sequence); entry.setSequence(sequence);
entry.setMachineOptions(o.getMachineOptions()); // 假设Operation类有获取机器选项的方法 entry.setMachineOptions(o.getMachineOptions()); // 假设Operation类有获取机器选项的方法
entry.setPriority(order.getPriority()); entry.setPriority(order.getPriority());
...@@ -206,12 +213,13 @@ public class PlanResultService { ...@@ -206,12 +213,13 @@ public class PlanResultService {
id++; id++;
} }
} }
GlobalParam globalParam=new GlobalParam();
// 5. 执行调度算法 // 5. 执行调度算法
GeneticAlgorithm scheduler =new GeneticAlgorithm(machines,orders,null,machineScheduler); //new GeneticAlgorithm(products, machines, orders, machineScheduler); GeneticAlgorithm scheduler =new GeneticAlgorithm(globalParam,machines,orders,null,machineScheduler); //new GeneticAlgorithm(products, machines, orders, machineScheduler);
List<Chromosome> Chromosomes =scheduler.Run(param,allOperations); Chromosome Chromosomes =scheduler.Run(param,allOperations);
Chromosomes.forEach(this::WriteScheduleSummary); //Chromosomes.forEach(this::WriteScheduleSummary);
return Chromosomes; return Chromosomes;
...@@ -220,13 +228,14 @@ public class PlanResultService { ...@@ -220,13 +228,14 @@ public class PlanResultService {
} }
} }
public List<Chromosome> execute2(String SceneId) { public Chromosome execute2(String SceneId) {
try { try {
ScheduleParams param = new ScheduleParams(); ScheduleParams param = new ScheduleParams();
param.setBaseTime(LocalDateTime.of(2025, 11, 1, 0, 0, 0)); param.setBaseTime(LocalDateTime.of(2025, 11, 1, 0, 0, 0));
param.setPopulationSize(50); param.setPopulationSize(50);
param.setMaxIterations(100); param.setMaxIterations(100);
// 1. 读取数据 // 1. 读取数据
// List<Machine> machines = loadData("machines.json", Machine.class); // List<Machine> machines = loadData("machines.json", Machine.class);
// List<Product> products = loadData("products.json", Product.class); // List<Product> products = loadData("products.json", Product.class);
...@@ -234,146 +243,40 @@ public class PlanResultService { ...@@ -234,146 +243,40 @@ public class PlanResultService {
List<ProdProcessExec> ProdProcessExecs= _prodProcessExecService.lambdaQuery()
.eq(ProdProcessExec::getSceneId,SceneId)
.list();
List<ProdEquipment> ProdEquipments= _prodEquipmentService.lambdaQuery() List<ProdEquipment> ProdEquipments= _prodEquipmentService.lambdaQuery()
.eq(ProdEquipment::getSceneId,SceneId) .eq(ProdEquipment::getSceneId,SceneId)
.list(); .list();
List<ProdLaunchOrder> ProdLaunchOrders= _prodLaunchOrderService.lambdaQuery()
.eq(ProdLaunchOrder::getSceneId,SceneId)
List<ProdOrderProcess> ProdOrderProcesss = _prodOrderProcessService.lambdaQuery()
.eq(ProdOrderProcess::getSceneId,SceneId)
.list(); .list();
Set<String> targetExecId = ProdOrderProcesss.stream()
.map(ProdOrderProcess::getTargetExecId) // 提取TARGET_ORDER_ID
.collect(Collectors.toSet()); // 转为Set去重
List<ProdProcessExec> ops= ProdProcessExecs.stream()
.filter(e -> !targetExecId.contains(e.getExecId())) // 过滤条件
.collect(Collectors.toList());
// 按设备分组
List<Long> MachineIds = ProdEquipments.stream()
.map(ProdEquipment::getEquipId)
.distinct()
.sorted()
.collect(Collectors.toList());
List<Machine> machines=new ArrayList<>();
for (Long id : MachineIds) {
Machine machine=new Machine();
machine.setId(id);
machines.add(machine);
}
//节假日
List<MesHoliday> holidays= _MesHolidayService.list();
LambdaQueryWrapper<ProdEquipSpecialCal> ProdEquipSpecialCalWrapper = new LambdaQueryWrapper<>();
ProdEquipSpecialCalWrapper.eq(ProdEquipSpecialCal::getSceneId, SceneId);
List<ProdEquipSpecialCal> ProdEquipSpecialCals= _prodEquipSpecialCalService.list(ProdEquipSpecialCalWrapper);
List<MesShiftWorkSched> MesShiftWorkScheds= _MesShiftWorkSchedService.list();
// 将节假日添加到所有设备中
InitCalendarToAllMachines(machines, ProdEquipSpecialCals,MesShiftWorkScheds);
// 3. 创建调度服务 // 3. 创建调度服务
MachineSchedulerService machineScheduler = new MachineSchedulerService( MachineSchedulerService machineScheduler = new MachineSchedulerService(
param.getBaseTime()); param.getBaseTime());
List<Machine> machines= InitCalendarToAllMachines(SceneId, ProdEquipments,machineScheduler);
// 4. 初始化机器时间线
for (Machine machine : machines) {
MachineTimeline timeline = machineScheduler.getOrCreateTimeline(machine);
machine.setAvailability(timeline.getSegments());
}
// 3. 构建订单-工序数据 // 3. 构建订单-工序数据
List<Entry> allOperations = new ArrayList<>();
Random rnd = new Random(); // 注意:此处变量声明但未使用,可根据实际需求保留或移除
int id = 0;
int groupid = 1;
List<Entry> entrys=new ArrayList<>();
for (ProdProcessExec op : ops) {
int sequence = 1;
Entry entry = new Entry(); List<Order> orders=new ArrayList<>();
id = id + 1; for (ProdLaunchOrder lo : ProdLaunchOrders) {
entry.setId(id); Order order=new Order();
entry.setGroupId(groupid); order.setOrderId(lo.getOrderId());
entry.setSequence(sequence); order.setMaterialId(lo.getMaterialId());
entry.setExecId(op.getExecId()); order.setDueDate(lo.getEndDate());
entry.setOrderId(op.getOrderId()); order.setQuantity(lo.getQuantity());
entry.setQuantity(op.getPlanQty()); orders.add(order);
List<ProdEquipment> Equipments= ProdEquipments.stream()
.filter(t->t.getExecId().equals(op.getExecId()))
.collect(Collectors.toList());
if(Equipments!=null&&Equipments.size()>0) {
List<MachineOption> mos=new ArrayList<>();
for (ProdEquipment e : Equipments) {
MachineOption mo=new MachineOption();
mo.setMachineId(e.getEquipId());
mo.setProcessingTime(e.getSpeed());
// mo.setTeardownTime(op.getPostprocessingTime());
mos.add(mo);
}
entry.setMachineOptions(mos);
}
// 假设Operation类有获取机器选项的方法
entry.setPriority(1);
entrys.add(entry);
List<ProdOrderProcess> nextop = ProdOrderProcesss.stream()
.filter(t -> t.getExecId().equals(op.getExecId()))
.collect(Collectors.toList());
if(nextop!=null&&nextop.size()>0) {
entrys.addAll(AddNextEntry(id, sequence, id, op.getExecId(), nextop, ProdOrderProcesss,ProdEquipments, ProdProcessExecs));
}
groupid++;
} }
List<Entry> entrys= InitEntrys(SceneId,ProdEquipments,ProdLaunchOrders);
// for (Order order : orders) {
// GlobalParam globalParam=new GlobalParam();
// int sequence = 1;
// for (Operation o : product.getOperations()) { // 假设Product类有getOperations()方法返回工序列表
// Entry entry = new Entry();
// entry.setId(id);
// entry.setGroupId(order.getId());
// entry.setSequence(sequence);
// entry.setMachineOptions(o.getMachineOptions()); // 假设Operation类有获取机器选项的方法
// entry.setPriority(order.getPriority());
// entry.setQuantity(order.getQuantity());
// // entry.setMaterialRequirements(o.getMaterialRequirements()); // 假设Operation类有获取物料需求的方法
//
// if (sequence != 1) {
// entry.getPrevEntryIds().add(id - 1); // 假设Entry类有getPrevEntryIds()返回List<Integer>
// }
//
// allOperations.add(entry);
//
// sequence++;
// id++;
// }
// }
// 5. 执行调度算法 // 5. 执行调度算法
GeneticAlgorithm scheduler =new GeneticAlgorithm(machines,null,null,machineScheduler); //new GeneticAlgorithm(products, machines, orders, machineScheduler); GeneticAlgorithm scheduler =new GeneticAlgorithm(globalParam,machines,orders,null,machineScheduler); //new GeneticAlgorithm(products, machines, orders, machineScheduler);
List<Chromosome> Chromosomes =scheduler.Run(param,allOperations); Chromosome Chromosomes =scheduler.Run(param,entrys);
Chromosomes.forEach(this::WriteScheduleSummary); // Chromosomes.forEach(this::WriteScheduleSummary);
return Chromosomes; return Chromosomes;
...@@ -382,61 +285,7 @@ public class PlanResultService { ...@@ -382,61 +285,7 @@ public class PlanResultService {
} }
} }
private List<Entry> AddNextEntry(int previd,int prevsequence,int pid,String execId ,List<ProdOrderProcess> nextop,List<ProdOrderProcess> ProdOrderProcesss,List<ProdEquipment> ProdEquipments,List<ProdProcessExec> ProdProcessExecs)
{
List<Entry> entrys=new ArrayList<>();
int id=previd;
int sequence=prevsequence;
for (ProdOrderProcess o : nextop) {
List<Integer> privids=new ArrayList<>();
privids.add(pid);
Entry entry = new Entry();
id=id+1;
entry.setId(id);
sequence=sequence+1;
entry.setSequence(sequence);
entry.setPrevEntryIds(privids);
entry.setExecId(o.getExecId());
ProdProcessExec op= ProdProcessExecs.stream().filter(t->t.getExecId()==o.getExecId()).findFirst().orElse(null);
entry.setOrderId(op.getOrderId());
entry.setQuantity(op.getPlanQty());
List<ProdEquipment> Equipments= ProdEquipments.stream()
.filter(t->t.getExecId().equals(op.getExecId()))
.collect(Collectors.toList());
if(Equipments!=null&&Equipments.size()>0) {
List<MachineOption> mos=new ArrayList<>();
for (ProdEquipment e : Equipments) {
MachineOption mo=new MachineOption();
mo.setMachineId(e.getEquipId());
mo.setProcessingTime(e.getSpeed());
// mo.setTeardownTime(op.getPostprocessingTime());
mos.add(mo);
}
entry.setMachineOptions(mos);
}
// 假设Operation类有获取机器选项的方法
entry.setPriority(1);
entrys.add(entry);
}
int id1=previd;
for (ProdOrderProcess o : nextop) {
List<ProdOrderProcess> nextop1 = ProdOrderProcesss.stream()
.filter(t -> t.getExecId() == o.getExecId())
.collect(Collectors.toList());
if(nextop1!=null&&nextop1.size()>0)
{
id1=id1+1;
entrys.addAll( AddNextEntry(id,sequence,id1,o.getExecId(),nextop1,ProdOrderProcesss,ProdEquipments,ProdProcessExecs));
}
}
return entrys;
}
...@@ -544,9 +393,36 @@ public class PlanResultService { ...@@ -544,9 +393,36 @@ public class PlanResultService {
} }
} }
private void InitCalendarToAllMachines(List<Machine> machines, List<ProdEquipSpecialCal> ProdEquipSpecialCals,List<MesShiftWorkSched> MesShiftWorkScheds) { private List<Machine> InitCalendarToAllMachines(String SceneId,List<ProdEquipment> ProdEquipments,MachineSchedulerService machineScheduler) {
// 按设备分组
List<Long> MachineIds = ProdEquipments.stream()
.map(ProdEquipment::getEquipId)
.distinct()
.sorted()
.collect(Collectors.toList());
List<Machine> machines=new ArrayList<>();
for (Long id : MachineIds) {
Machine machine=new Machine();
machine.setId(id);
machines.add(machine);
}
//节假日
List<MesHoliday> holidays= _MesHolidayService.list();
LambdaQueryWrapper<ProdEquipSpecialCal> ProdEquipSpecialCalWrapper = new LambdaQueryWrapper<>();
ProdEquipSpecialCalWrapper.eq(ProdEquipSpecialCal::getSceneId, SceneId);
List<ProdEquipSpecialCal> ProdEquipSpecialCals= _prodEquipSpecialCalService.list(ProdEquipSpecialCalWrapper);
List<MesShiftWorkSched> MesShiftWorkScheds= _MesShiftWorkSchedService.list();
if (machines == null) { if (machines == null) {
return; return null;
} }
for (Machine machine : machines) { for (Machine machine : machines) {
...@@ -578,6 +454,120 @@ public class PlanResultService { ...@@ -578,6 +454,120 @@ public class PlanResultService {
} }
// 4. 初始化机器时间线
for (Machine machine : machines) {
MachineTimeline timeline = machineScheduler.getOrCreateTimeline(machine);
machine.setAvailability(timeline.getSegments());
}
return machines;
}
private List<Entry> InitEntrys(String SceneId,List<ProdEquipment> ProdEquipments,List<ProdLaunchOrder> ProdLaunchOrders)
{
List<ProdProcessExec> ProdProcessExecs= _prodProcessExecService.lambdaQuery()
.eq(ProdProcessExec::getSceneId,SceneId)
.list();
List<ProdOrderProcess> ProdOrderProcesss = _prodOrderProcessService.lambdaQuery()
.eq(ProdOrderProcess::getSceneId,SceneId)
.list();
List<String> soutceExecId = ProdOrderProcesss.stream()
.map(ProdOrderProcess::getExecId)
.distinct() // 提取Exec_ID
.collect(Collectors.toList());
List<String> targetExecId = ProdOrderProcesss.stream()
.map(ProdOrderProcess::getTargetExecId)
.distinct() // 提取TARGET_Exec_ID
.collect(Collectors.toList());
List<String> ExecIdNoChild= ProdProcessExecs.stream()
.filter(e -> !soutceExecId.contains(e.getExecId())&&!targetExecId.contains(e.getExecId())) // 过滤条件
.map(ProdProcessExec::getExecId)
.distinct()
.collect(Collectors.toList());
if(ExecIdNoChild!=null&&ExecIdNoChild.size()>0)
{
for (String ExecId : ExecIdNoChild) {
soutceExecId.add(ExecId);
targetExecId.add("");
}
}
List<GroupResult> results= IdGroupingWithDualSerial.groupAndOrderIds(soutceExecId,targetExecId);
List<Entry> entrys=new ArrayList<>();
for (int i = 0; i < results.size(); i++) {
GroupResult groupResult = results.get(i);
List<NodeInfo> nodeInfoList = groupResult.getNodeInfoList();
System.out.println("分组" + (i + 1) + "顺序:" + nodeInfoList);
for (NodeInfo nodeInfo : nodeInfoList) {
System.out.printf("原始ID:%s → 全局序号:%d,分组内序号:%d,新父ID列表:%s,新子ID列表:%s%n",
nodeInfo.getOriginalId(),
nodeInfo.getGlobalSerial(),
nodeInfo.getGroupSerial(),
nodeInfo.getNewParentIds().isEmpty() ? "无" : nodeInfo.getNewParentIds(),
nodeInfo.getNewChildIds());
Entry entry = new Entry();
entry.setId(nodeInfo.getGlobalSerial());
entry.setGroupId(i + 1);
entry.setSequence(nodeInfo.getGroupSerial());
entry.setExecId(nodeInfo.getOriginalId());
entry.setPrevEntryIds(nodeInfo.getNewParentIds());
entry.setNextEntryIds(nodeInfo.getNewChildIds());
ProdProcessExec op= ProdProcessExecs.stream()
.filter(t->t.getExecId().equals(entry.getExecId()))
.findFirst().orElse(null);
if(op!=null)
{
entry.setOrderId(op.getOrderId());
entry.setQuantity(op.getPlanQty());
ProdLaunchOrder order = ProdLaunchOrders.stream()
.filter(t -> t.getOrderId().equals(op.getOrderId()))
.findFirst().orElse(null);
if (order != null) {
entry.setProductId(order.getMaterialId());
}
List<ProdEquipment> Equipments = ProdEquipments.stream()
.filter(t -> t.getExecId().equals(op.getExecId()))
.collect(Collectors.toList());
if (Equipments != null && Equipments.size() > 0) {
List<MachineOption> mos = new ArrayList<>();
for (ProdEquipment e : Equipments) {
MachineOption mo = new MachineOption();
mo.setMachineId(e.getEquipId());
mo.setProcessingTime(e.getSpeed());
// mo.setContantTime(op.getConstTime());
// mo.setTeardownTime(op.getPostprocessingTime());
mos.add(mo);
}
entry.setMachineOptions(mos);
}
}
entry.setPriority(1);
entrys.add(entry);
}
// 输出每个节点的详细信息
System.out.println("------------------------");
}
return entrys;
} }
/** /**
......
...@@ -69,7 +69,7 @@ class OrderSortServiceTest { ...@@ -69,7 +69,7 @@ class OrderSortServiceTest {
order.setProductId(100 + i); order.setProductId(100 + i);
order.setQuantity(50.0 * i); order.setQuantity(50.0 * i);
order.setPriority(15 - i); // 优先级:5,4,3,2,1(倒序) order.setPriority(15 - i); // 优先级:5,4,3,2,1(倒序)
order.setDueDate(OffsetDateTime.now().plusDays(i)); // 到期日递增 //order.setDueDate(OffsetDateTime.now().plusDays(i)); // 到期日递增
order.setTardiness(i * 0.5); order.setTardiness(i * 0.5);
order.setCanSplit(i % 2 == 0); order.setCanSplit(i % 2 == 0);
order.setCanInterrupt(i % 3 == 0); order.setCanInterrupt(i % 3 == 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