Commit c6275d54 authored by Tong Li's avatar Tong Li

拆分工序

parent ee19eb74
......@@ -85,7 +85,9 @@ public class HybridAlgorithm {
{
throw new RuntimeException("没有待排产工单");
}
if (_GlobalParam.isIsMultipleMachine()) {
allOperations = OperationSplitService.splitMultiMachineOperations(allOperations, _GlobalParam, machines, _entryRel);
}
// if(materials!=null&&materials.size()>0) {
//
// materialRequirementService.init(materials, orders, allOperations, _entryRel, machineScheduler, machines,_GlobalParam);
......@@ -433,6 +435,7 @@ public class HybridAlgorithm {
chromosome.setMaterials(ProductionDeepCopyUtil.deepCopyTreeMap(materials, String.class, Material.class)); // 简单拷贝,实际可能需要深拷贝
chromosome.setAllOperations(ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(allOperations), Entry.class) ); // 简单拷贝,实际可能需要深拷贝
chromosome.setGlobalOpList(ProductionDeepCopyUtil.deepCopyList(globalOpList, GlobalOperationInfo.class) ); // 简单拷贝,实际可能需要深拷贝
//chromosome.setObjectiveWeights(_objectiveWeights);
chromosome.setBaseTime(param.getBaseTime());
......@@ -489,8 +492,9 @@ public class HybridAlgorithm {
chromosome.setOperatRel(ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(_entryRel), GroupResult.class) ); // 简单拷贝,实际可能需要深拷贝
chromosome.setMaterials(ProductionDeepCopyUtil.deepCopyTreeMap(materials, String.class, Material.class)); // 简单拷贝,实际可能需要深拷贝
chromosome.setAllOperations(ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(allOperations), Entry.class) ); // 简单拷贝,实际可能需要深拷贝
// chromosome.setGlobalOpList(ProductionDeepCopyUtil.deepCopyList(globalOpList, GlobalOperationInfo.class) ); // 简单拷贝,实际可能需要深拷贝
if (chromosome.getAllOperations() == null || chromosome.getAllOperations().isEmpty()) {
chromosome.setAllOperations(ProductionDeepCopyUtil.deepCopyList(new CopyOnWriteArrayList<>(allOperations), Entry.class) );
} // chromosome.setGlobalOpList(ProductionDeepCopyUtil.deepCopyList(globalOpList, GlobalOperationInfo.class) ); // 简单拷贝,实际可能需要深拷贝
//chromosome.setObjectiveWeights(_objectiveWeights);
chromosome.setBaseTime(param.getBaseTime());
// chromosome.setInitMachines(ProductionDeepCopyUtil.deepCopyList(machines,Machine.class)); // 简单拷贝,实际可能需要深拷贝
......
......@@ -476,7 +476,10 @@ public class Initialization {
.thenComparing(randomIds::get));
}
}
if (_globalParam.isIsMultipleMachine()) {
sortedOps = OperationSplitService.splitOpsForHeuristic(sortedOps, rnd);
chromosome.setAllOperations(new CopyOnWriteArrayList<>(sortedOps));
}
int globalOpId = 0;
// 为每个工序选择机器
......@@ -581,7 +584,10 @@ public class Initialization {
.thenComparing(randomIds::get));
}
if (_globalParam.isIsMultipleMachine()) {
sortedOps = OperationSplitService.splitOpsForHeuristic(sortedOps, rnd);
chromosome.setAllOperations(new CopyOnWriteArrayList<>(sortedOps));
}
int globalOpId = 0;
// 为每个工序选择机器
for (Entry op : sortedOps) {
......@@ -670,6 +676,10 @@ public class Initialization {
.thenComparing(op -> op.getMachineOptions().get(0).getProcessingTime() * op.getQuantity())
.thenComparing(randomIds::get));
if (_globalParam.isIsMultipleMachine()) {
sortedOps = OperationSplitService.splitOpsForHeuristic(sortedOps, rnd);
chromosome.setAllOperations(new CopyOnWriteArrayList<>(sortedOps));
}
int globalOpId = 0;
for (Entry op : sortedOps) {
......@@ -815,7 +825,10 @@ public class Initialization {
})
.thenComparing(randomIds::get));
}
if (_globalParam.isIsMultipleMachine()) {
sortedOps = OperationSplitService.splitOpsForHeuristic(sortedOps, rnd);
chromosome.setAllOperations(new CopyOnWriteArrayList<>(sortedOps));
}
int globalOpId = 0;
for (Entry op : sortedOps) {
int groupId = op.getGroupId();
......@@ -905,7 +918,10 @@ public class Initialization {
})
.thenComparing(op -> op.getProductId() != null ? op.getProductId() : "")
.thenComparing(randomIds::get));
if (_globalParam.isIsMultipleMachine()) {
sortedOps = OperationSplitService.splitOpsForHeuristic(sortedOps, rnd);
chromosome.setAllOperations(new CopyOnWriteArrayList<>(sortedOps));
}
int globalOpId = 0;
for (Entry op : sortedOps) {
int groupId = op.getGroupId();
......@@ -969,7 +985,10 @@ public class Initialization {
.thenComparing(op -> op.getProductId() != null ? op.getProductId() : "") // 相同物料排在一起,减少换型
.thenComparing(randomIds::get));
if (_globalParam.isIsMultipleMachine()) {
sortedOps = OperationSplitService.splitOpsForHeuristic(sortedOps, rnd);
chromosome.setAllOperations(new CopyOnWriteArrayList<>(sortedOps));
}
int globalOpId = 0;
......
......@@ -2,6 +2,8 @@ package com.aps.service.Algorithm;
import com.aps.common.util.FileHelper;
import com.aps.common.util.ProductionDeepCopyUtil;
import com.aps.entity.Algorithm.IDAndChildID.GroupResult;
import com.aps.entity.Algorithm.IDAndChildID.NodeInfo;
import com.aps.entity.Algorithm.OperationDependency;
import com.aps.entity.basic.Entry;
import com.aps.entity.basic.GlobalParam;
......@@ -30,14 +32,20 @@ public class OperationSplitService {
/**
* 对工序列表进行多设备拆分(预处理入口,结合设备负载)
*
* 对齐 SpiltOperation 的处理顺序:
* 1. 先通过 IdGroupingWithDualSerial.addNode 更新 OperatRel,生成新的 GlobalSerial、GroupSerial、NewParentIds、NewChildIds
* 2. 再从 OperatRel 的 NodeInfo 生成 Entry,设置 NextOperationId 和 PrevOperationId
*
* @param allOperations 原始工序列表
* @param globalParam 全局参数
* @param machines 设备列表(用于计算各设备总预期负载)
* @param operatRel 工序关系列表(可变参数,拆分后会被原地更新)
* @return 拆分后的工序列表
*/
public static List<Entry> splitMultiMachineOperations(List<Entry> allOperations,
GlobalParam globalParam,
List<Machine> machines) {
List<Machine> machines,
List<GroupResult> operatRel) {
if (allOperations == null || allOperations.isEmpty()) {
return allOperations;
}
......@@ -55,50 +63,140 @@ public class OperationSplitService {
FileHelper.writeLogFile("[工序拆分] 开始多设备工序拆分(负载感知),原始工序数=" + allOperations.size());
// 旧 Entry 索引(id → Entry)
Map<Integer, Entry> oldEntryMap = new LinkedHashMap<>();
for (Entry op : allOperations) {
oldEntryMap.put(op.getId(), op);
}
Map<Long, Double> machineTotalLoad = calcMachineTotalLoad(allOperations);
int maxId = allOperations.stream().mapToInt(Entry::getId).max().orElse(0);
int nextId = maxId + 1;
// ===== Phase 1: 先更新 OperatRel(结构权威)=====
List<GroupResult> currentRel = (operatRel != null && !operatRel.isEmpty())
? new ArrayList<>(operatRel) : rebuildOperatRel(allOperations);
Map<String, SplitOpMeta> splitMetas = new LinkedHashMap<>();
Map<Integer, List<Integer>> splitMapping = new LinkedHashMap<>();
List<Entry> result = new ArrayList<>();
int totalSplitOps = 0;
int totalSplitCount = 0;
Map<Integer, List<Entry>> groupMap = new LinkedHashMap<>();
Set<Entry> splitOriginals = new LinkedHashSet<>();
for (Entry op : allOperations) {
groupMap.computeIfAbsent(op.getGroupId(), k -> new ArrayList<>()).add(op);
List<MachineOption> options = op.getMachineOptions();
if (options == null || options.size() <= 1) {
continue;
}
splitOriginals.add(op);
}
int totalSplitCount = 0;
int totalSplitOps = 0;
for (Entry op : splitOriginals) {
List<MachineOption> options = op.getMachineOptions();
int groupIdx = op.getGroupId() - 1;
GroupResult gr = currentRel.get(groupIdx);
for (Map.Entry<Integer, List<Entry>> groupEntry : groupMap.entrySet()) {
List<Entry> groupOps = groupEntry.getValue();
groupOps.sort(Comparator.comparingInt(Entry::getSequence));
List<Entry> newGroupOps = new ArrayList<>();
for (Entry op : groupOps) {
List<MachineOption> options = op.getMachineOptions();
if (options != null && options.size() > 1) {
List<Entry> subOps = splitEntryByLoad(op, options, nextId, machineTotalLoad);
nextId += subOps.size();
newGroupOps.addAll(subOps);
splitMapping.put(op.getId(),
subOps.stream().map(Entry::getId).collect(Collectors.toList()));
totalSplitOps++;
totalSplitCount += subOps.size();
} else {
newGroupOps.add(op);
}
NodeInfo origNode = gr.getNodeInfoList().stream()
.filter(n -> n.getOriginalId().equals(op.getExecId()))
.findFirst().orElse(null);
if (origNode == null) {
continue;
}
for (int i = 0; i < newGroupOps.size(); i++) {
newGroupOps.get(i).setSequence(i + 1);
List<Integer> parentIds = origNode.getNewParentIds() != null
? new ArrayList<>(origNode.getNewParentIds()) : new ArrayList<>();
List<Integer> childIds = origNode.getNewChildIds() != null
? new ArrayList<>(origNode.getNewChildIds()) : new ArrayList<>();
String mainId = UUID.randomUUID().toString().replace("-", "");
double[] qtys = calcQuantityDistribution(op, options, machineTotalLoad);
SplitOpMeta meta = new SplitOpMeta(mainId, op);
meta.subExecIds.add(op.getExecId());
meta.subQtys.add(qtys[0]);
meta.subMachineOptions.add(options.get(0));
for (int i = 1; i < options.size(); i++) {
String newExecId = UUID.randomUUID().toString().replace("-", "");
currentRel = IdGroupingWithDualSerial.addNode(
currentRel, groupIdx, newExecId, parentIds, childIds, op.getExecId());
meta.subExecIds.add(newExecId);
meta.subQtys.add(qtys[i]);
meta.subMachineOptions.add(options.get(i));
}
result.addAll(newGroupOps);
splitMetas.put(op.getExecId(), meta);
totalSplitOps++;
totalSplitCount += options.size();
}
updateAllDependencies(result, splitMapping);
// 写回 operatRel
if (operatRel != null) {
operatRel.clear();
operatRel.addAll(currentRel);
}
FileHelper.writeLogFile(String.format(
"[工序拆分] OperatRel已更新,添加了%d个新节点,共%d个分组",
totalSplitCount - splitOriginals.size(), currentRel.size()));
// ===== Phase 2: 从更新后的 OperatRel 生成 Entry =====
List<Entry> result = new ArrayList<>();
for (int gi = 0; gi < currentRel.size(); gi++) {
GroupResult gr = currentRel.get(gi);
int groupId = gi + 1;
for (NodeInfo node : gr.getNodeInfoList()) {
int globalSerial = node.getGlobalSerial();
String execId = node.getOriginalId();
Entry entry = oldEntryMap.get(globalSerial);
if (entry != null) {
entry.setId(globalSerial);
entry.setSequence(node.getGroupSerial());
entry.setGroupId(groupId);
setEntryDepsFromNodeInfo(entry, node);
SplitOpMeta meta = splitMetas.get(execId);
if (meta != null) {
entry.setMainId(meta.mainId);
entry.setSplitSourceId(meta.originalEntry.getId());
entry.setState(1);
entry.setNewCreate(false);
entry.setQuantity(meta.subQtys.get(0));
MachineOption mo = meta.subMachineOptions.get(0);
entry.setSelectMachineID(mo.getMachineId());
entry.setMachineOptions(Collections.singletonList(mo));
}
} else {
SplitOpMeta meta = findMetaForExecId(splitMetas, execId);
if (meta != null) {
int idx = meta.subExecIds.indexOf(execId);
if (idx > 0) {
Entry sub = ProductionDeepCopyUtil.deepCopy(meta.originalEntry, Entry.class);
sub.setId(globalSerial);
sub.setExecId(execId);
sub.setSequence(node.getGroupSerial());
sub.setGroupId(groupId);
setEntryDepsFromNodeInfo(sub, node);
sub.setMainId(meta.mainId);
sub.setSplitSourceId(meta.originalEntry.getId());
sub.setState(2);
sub.setNewCreate(true);
sub.setSelectMachineID(meta.subMachineOptions.get(idx).getMachineId());
sub.setMachineOptions(
Collections.singletonList(meta.subMachineOptions.get(idx)));
sub.setQuantity(meta.subQtys.get(idx));
entry = sub;
oldEntryMap.put(globalSerial, entry);
}
}
}
if (entry != null) {
result.add(entry);
}
}
}
FileHelper.writeLogFile(String.format(
"[工序拆分] 拆分了%d道多设备工序 → 产生%d道子工序,最终总工序数=%d",
......@@ -228,6 +326,7 @@ public class OperationSplitService {
int maxId = ops.stream().mapToInt(Entry::getId).max().orElse(0);
int nextId = maxId + 1;
Map<Integer, List<Integer>> splitMapping = new LinkedHashMap<>();
List<Entry> result = new ArrayList<>();
for (Map.Entry<Integer, List<Entry>> groupEntry : groupMap.entrySet()) {
List<Entry> expanded = new ArrayList<>();
......@@ -236,6 +335,8 @@ public class OperationSplitService {
if (op.getSplitSourceId() == null && options != null && options.size() > 1) {
List<Entry> subOps = splitEntryRandomPartial(op, options, nextId, rnd);
nextId += subOps.size();
splitMapping.put(op.getId(),
subOps.stream().map(Entry::getId).collect(Collectors.toList()));
expanded.addAll(subOps);
} else {
expanded.add(op);
......@@ -246,6 +347,8 @@ public class OperationSplitService {
}
result.addAll(expanded);
}
updateAllDependencies(result, splitMapping);
return result;
}
......@@ -263,6 +366,90 @@ public class OperationSplitService {
return load;
}
private static void setEntryDepsFromNodeInfo(Entry entry, NodeInfo node) {
if (node.getNewParentIds() != null && !node.getNewParentIds().isEmpty()) {
List<OperationDependency> prevDeps = new ArrayList<>();
for (int parentId : node.getNewParentIds()) {
if (parentId > 0) {
OperationDependency dep = new OperationDependency();
dep.setPrevOperationId(parentId);
dep.setNextOperationId(entry.getId());
prevDeps.add(dep);
}
}
entry.setPrevEntryIds(prevDeps);
}
if (node.getNewChildIds() != null && !node.getNewChildIds().isEmpty()) {
List<OperationDependency> nextDeps = new ArrayList<>();
for (int childId : node.getNewChildIds()) {
if (childId > 0) {
OperationDependency dep = new OperationDependency();
dep.setPrevOperationId(entry.getId());
dep.setNextOperationId(childId);
nextDeps.add(dep);
}
}
entry.setNextEntryIds(nextDeps);
}
}
private static double[] calcQuantityDistribution(Entry original, List<MachineOption> options,
Map<Long, Double> loadMap) {
int n = options.size();
double[] weights = new double[n];
double totalWeight = 0;
for (int i = 0; i < n; i++) {
MachineOption mo = options.get(i);
if (loadMap != null) {
double load = loadMap.getOrDefault(mo.getMachineId(), 0.0);
weights[i] = 1.0 / Math.max(load + mo.getProcessingTime(), 0.001);
} else {
weights[i] = 1.0 / Math.max(mo.getProcessingTime(), 0.001);
}
totalWeight += weights[i];
}
double[] quantities = new double[n];
double remaining = original.getQuantity();
for (int i = 0; i < n; i++) {
double proportion = (i == n - 1) ? 1.0 : weights[i] / totalWeight;
double qty = Math.max(1, Math.round(original.getQuantity() * proportion * 100.0) / 100.0);
if (i == n - 1) {
qty = remaining;
}
qty = Math.min(qty, remaining);
remaining -= qty;
quantities[i] = qty;
}
return quantities;
}
private static SplitOpMeta findMetaForExecId(Map<String, SplitOpMeta> metas, String execId) {
for (SplitOpMeta meta : metas.values()) {
if (meta.subExecIds.contains(execId)) {
return meta;
}
}
return null;
}
private static class SplitOpMeta {
final String mainId;
final Entry originalEntry;
final List<String> subExecIds = new ArrayList<>();
final List<Double> subQtys = new ArrayList<>();
final List<MachineOption> subMachineOptions = new ArrayList<>();
SplitOpMeta(String mainId, Entry originalEntry) {
this.mainId = mainId;
this.originalEntry = originalEntry;
}
}
private static void fixDependencyReferences(List<OperationDependency> deps,
int originalId, int newId, boolean isPrev) {
if (deps == null) return;
......@@ -326,4 +513,58 @@ public class OperationSplitService {
FileHelper.writeLogFile(String.format(
"[工序拆分] 更新了%d个拆分的依赖引用", splitMapping.size()));
}
/**
* 从拆分后的 Entry 列表重建 OperatRel (GroupResult 列表)
* 对齐 IdGroupingWithDualSerial 的输出格式:
* originalId = execId, globalSerial = id, groupSerial = sequence
* newParentIds = 从 prevEntryIds 提取的 prevOperationId
* newChildIds = 从 nextEntryIds 提取的 nextOperationId
*/
public static List<GroupResult> rebuildOperatRel(List<Entry> allOperations) {
Map<Integer, List<Entry>> groupMap = new LinkedHashMap<>();
for (Entry op : allOperations) {
groupMap.computeIfAbsent(op.getGroupId(), k -> new ArrayList<>()).add(op);
}
List<GroupResult> results = new ArrayList<>();
for (Map.Entry<Integer, List<Entry>> groupEntry : groupMap.entrySet()) {
List<Entry> groupOps = groupEntry.getValue();
groupOps.sort(Comparator.comparingInt(Entry::getSequence));
List<NodeInfo> nodeInfoList = new ArrayList<>();
Map<String, Integer> originalToGlobalSerial = new HashMap<>();
for (Entry op : groupOps) {
List<Integer> parentIds = new ArrayList<>();
if (op.getPrevEntryIds() != null) {
for (OperationDependency dep : op.getPrevEntryIds()) {
if (dep.getPrevOperationId() > 0) {
parentIds.add(dep.getPrevOperationId());
}
}
}
List<Integer> childIds = new ArrayList<>();
if (op.getNextEntryIds() != null) {
for (OperationDependency dep : op.getNextEntryIds()) {
if (dep.getNextOperationId() > 0) {
childIds.add(dep.getNextOperationId());
}
}
}
String execId = op.getExecId() != null ? op.getExecId() : "";
int globalSerial = op.getId();
int groupSerial = op.getSequence();
originalToGlobalSerial.put(execId, globalSerial);
nodeInfoList.add(new NodeInfo(execId, globalSerial, groupSerial, parentIds, childIds));
}
results.add(new GroupResult(nodeInfoList, originalToGlobalSerial));
}
return results;
}
}
\ No newline at end of file
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