Commit 9a0c5df9 authored by Tong Li's avatar Tong Li

策略最小化换线

parent 994fc45b
...@@ -7,6 +7,7 @@ import java.util.List; ...@@ -7,6 +7,7 @@ import java.util.List;
public class OrderSortRule { public class OrderSortRule {
private boolean enabled; private boolean enabled;
private List<SortCondition> conditions; private List<SortCondition> conditions;
//private boolean minimizeChangeover=false;
@Data @Data
public static class SortCondition { public static class SortCondition {
......
...@@ -176,4 +176,11 @@ public class Order { ...@@ -176,4 +176,11 @@ public class Order {
* 物料需求 * 物料需求
*/ */
private List<OrderMaterialRequirement> materialRequirementList; private List<OrderMaterialRequirement> materialRequirementList;
/**
* 换线成本
*/
private double changeoverCost;
private int changeoverPriority;
} }
\ No newline at end of file
...@@ -489,19 +489,19 @@ if(finishedOrder==null||finishedOrder.size()==0) ...@@ -489,19 +489,19 @@ if(finishedOrder==null||finishedOrder.size()==0)
} }
int setupTime=0; int setupTime=0;
CopyOnWriteArrayList<GAScheduleResult> machineTasks=null;
CopyOnWriteArrayList<GAScheduleResult> machineTasks1 =chromosome.getResult().stream() CopyOnWriteArrayList<GAScheduleResult> machineTasks =chromosome.getResult().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.toCollection(CopyOnWriteArrayList::new)); .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
GAScheduleResult lastGeneOnMachine = null; GAScheduleResult lastGeneOnMachine = null;
if(machineTasks1!=null&&machineTasks1.size()>0) if(machineTasks!=null&&machineTasks.size()>0)
{ {
lastGeneOnMachine=machineTasks1.get(machineTasks1.size()-1); lastGeneOnMachine=machineTasks.get(machineTasks.size()-1);
} }
if(lastGeneOnMachine!=null) if(lastGeneOnMachine!=null&&_globalParam.is_smoothChangeOver())
{ {
earliestStartTime = Math.max(earliestStartTime,lastGeneOnMachine.getEndTime()); earliestStartTime = Math.max(earliestStartTime,lastGeneOnMachine.getEndTime());
} }
...@@ -543,16 +543,16 @@ if(finishedOrder==null||finishedOrder.size()==0) ...@@ -543,16 +543,16 @@ if(finishedOrder==null||finishedOrder.size()==0)
} }
machineTasks1 =chromosome.getResult().stream() machineTasks =chromosome.getResult().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.toCollection(CopyOnWriteArrayList::new)); .collect(Collectors.toCollection(CopyOnWriteArrayList::new));
if(machineTasks1!=null&&machineTasks1.size()>0) if(machineTasks!=null&&machineTasks.size()>0&&_globalParam.is_smoothChangeOver())
{ {
lastGeneOnMachine=machineTasks1.get(machineTasks1.size()-1); lastGeneOnMachine=machineTasks.get(machineTasks.size()-1);
} }
if (_globalParam.is_smoothChangeOver()) { if (_globalParam.is_smoothChangeOver()) {
......
...@@ -1617,6 +1617,9 @@ if(headers1==null) ...@@ -1617,6 +1617,9 @@ if(headers1==null)
redisUtils.del(sceneId+routingDiscreteParamCacheKey); redisUtils.del(sceneId+routingDiscreteParamCacheKey);
GlobalCacheUtil.remove(sceneId+routingDiscreteParamCacheKey); GlobalCacheUtil.remove(sceneId+routingDiscreteParamCacheKey);
redisUtils.del(sceneId+materialsCacheKey);
GlobalCacheUtil.remove(sceneId+materialsCacheKey);
} }
......
...@@ -90,6 +90,227 @@ public class OrderSortService { ...@@ -90,6 +90,227 @@ public class OrderSortService {
orders.addAll(sortedOrders); orders.addAll(sortedOrders);
} }
/**
* 计算两个订单之间的换线成本
*/
private double calculateChangeoverCost(Order order1, Order order2) {
if (order1 == null || order2 == null) {
return Double.MAX_VALUE;
}
double cost = 0.0;
// 1. 工艺路线不同,增加换线成本
if (!Objects.equals(order1.getRoutingId(), order2.getRoutingId())) {
cost += 100.0;
}
// 2. 物料系列不同,增加换线成本
if (!Objects.equals(order1.getSerie(), order2.getSerie())) {
cost += 50.0;
}
// 3. 物料代码不同,增加换线成本
if (!Objects.equals(order1.getMaterialCode(), order2.getMaterialCode())) {
cost += 25.0;
}
return cost;
}
/**
* 基于最小化换线成本的排序
*/
/**
* 基于最小化换线成本的排序,并返回带有优先级信息的订单列表
*/
private List<Order> sortByMinimizeChangeover(List<Order> orders) {
if (CollectionUtils.isEmpty(orders)) {
return new ArrayList<>();
}
List<Order> sortedOrders = new ArrayList<>();
List<Order> remainingOrders = new ArrayList<>(orders);
// 选择第一个订单作为起始点
Order currentOrder = remainingOrders.remove(0);
currentOrder.setChangeoverPriority(1);
sortedOrders.add(currentOrder);
int priority=2;
// 每次选择与当前最后一个订单换线成本最低的订单
while (!remainingOrders.isEmpty()) {
double minCost = Double.MAX_VALUE;
List<Order> bestOrders = new ArrayList<>();
// 找到换线成本最低的所有订单
for (Order order : remainingOrders) {
double cost = calculateChangeoverCost(currentOrder, order);
if (cost < minCost) {
minCost = cost;
order.setChangeoverCost(cost);
if(minCost==0){
order.setChangeoverPriority(currentOrder.getPriority());
}else {
order.setChangeoverPriority(priority);
}
bestOrders.clear();
bestOrders.add(order);
} else if (cost == minCost) {
order.setChangeoverCost(cost);
if(minCost==0){
order.setChangeoverPriority(currentOrder.getPriority());
}else {
order.setChangeoverPriority(priority);
}
bestOrders.add(order);
}
}
// 如果有多个成本相同的订单,将它们作为一组添加
if (!bestOrders.isEmpty()) {
sortedOrders.addAll(bestOrders);
remainingOrders.removeAll(bestOrders);
// 更新当前订单为最后添加的订单
currentOrder = bestOrders.get(bestOrders.size() - 1);
if(minCost!=0) {
priority++;
}
} else {
// 以防万一,添加剩余的第一个订单
Order nextOrder = remainingOrders.remove(0);
sortedOrders.add(nextOrder);
currentOrder = nextOrder;
if(minCost!=0) {
priority++;
}
}
}
return sortedOrders;
}
public void sortByMinimizeChangeover1(List<Order> orders,Map<Integer, List<Integer>> priorityPaths)
{
List<Order> optimizedOrders = sortByMinimizeChangeover(orders);
for (Order order : optimizedOrders) {
priorityPaths.get(order.getId()).add(order.getChangeoverPriority());
}
// convertPriorityPathsToNumeric(optimizedOrders, priorityPaths);
int i=0;
}
/**
* 处理排序条件,支持在任意位置应用最小化换线策略
*/
private void processConditionsWithMinimizeChangeover(List<Order> orders,
List<OrderSortRule.SortCondition> conditions,
int conditionIndex,
Map<Integer, List<Integer>> priorityPaths) {
// 递归终止:处理完所有条件后停止
if (conditionIndex >= conditions.size() || CollectionUtils.isEmpty(orders)) {
return;
}
OrderSortRule.SortCondition currentCondition = conditions.get(conditionIndex);
// 检查是否是最小化换线策略
if ("minimize_changeover".equals(currentCondition.getFieldName())) {
// 应用最小化换线策略
List<Order> optimizedOrders = sortByMinimizeChangeover(orders);
// 为最小化换线后的订单分配层级序号
// 相同成本的订单分配相同的序号
for (Order order : optimizedOrders) {
priorityPaths.get(order.getId()).add(order.getChangeoverPriority());
}
Map<Integer, List<Order>> priorityGroups = new HashMap<>();
for (Order order : optimizedOrders) {
int priority = order.getChangeoverPriority();
priorityGroups.computeIfAbsent(priority, k -> new ArrayList<>()).add(order);
}
// 按优先级分组顺序处理
List<Integer> sortedPriorities = priorityGroups.keySet().stream()
.sorted()
.collect(Collectors.toList());
for (Integer priority : sortedPriorities) {
List<Order> groupOrders = priorityGroups.get(priority);
// 递归处理下一个条件
processConditionsWithMinimizeChangeover(groupOrders, conditions, conditionIndex + 1, priorityPaths);
}
// 递归处理下一个条件
// processConditionsWithMinimizeChangeover(optimizedOrders, conditions, conditionIndex + 1, priorityPaths);
} else {
// 处理普通排序条件
String fieldName = currentCondition.getFieldName();
Function<Order, ?> keyExtractor = getFieldExtractor(fieldName);
if (keyExtractor == null) {
log.warn("跳过无效排序字段:{}", currentCondition.getFieldName());
processConditionsWithMinimizeChangeover(orders, conditions, conditionIndex + 1, priorityPaths);
return;
}
// 1. 按当前条件分组 处理null键
Map<Object, List<Order>> groups = new HashMap<>();
orders.forEach(order -> {
Object key = keyExtractor.apply(order);
groups.computeIfAbsent(key, k -> new ArrayList<>()).add(order);
});
// 2. 对分组键排序(关键:按条件配置的方向排序)
List<Object> sortedKeys = getSortedKeys(groups, currentCondition);
// 3. 为每个分组分配层级序号(从1开始)
for (int groupIndex = 0; groupIndex < sortedKeys.size(); groupIndex++) {
Object key = sortedKeys.get(groupIndex);
List<Order> groupOrders = groups.get(key);
// 分配当前层级序号(1、2、3...)
int levelNumber = groupIndex + 1;
groupOrders.forEach(order -> priorityPaths.get(order.getId()).add(levelNumber));
// 递归处理下一级条件
processConditionsWithMinimizeChangeover(groupOrders, conditions, conditionIndex + 1, priorityPaths);
}
}
}
private List<Order> sortWithConfiguredStrategy(List<Order> orders, OrderSortRule rule) {
// if (rule.getConditions().size()==1&&rule.getConditions().get(0).getFieldName().equals("minimize_changeover")) {
// return sortByMinimizeChangeover(orders);
// }
List<Order> currentOrders = new ArrayList<>(orders);
List<OrderSortRule.SortCondition> conditions = rule.getConditions().stream()
.sorted(Comparator.comparingInt(OrderSortRule.SortCondition::getSequence))
.collect(Collectors.toList());
// 为每个订单初始化优先级路径
Map<Integer, List<Integer>> priorityPaths = new HashMap<>();
currentOrders.forEach(order -> priorityPaths.put(order.getId(), new ArrayList<>()));
// 处理排序条件
processConditionsWithMinimizeChangeover(currentOrders, conditions, 0, priorityPaths);
// 将路径转换为最终格式
convertPriorityPathsToNumeric(currentOrders, priorityPaths);
// 按优先级升序排序(数值越小越优先)
return currentOrders.stream()
.sorted(Comparator.comparingDouble(Order::getActualPriority))
.collect(Collectors.toList());
}
/** /**
* 根据数据库配置的规则对订单排序 * 根据数据库配置的规则对订单排序
...@@ -136,14 +357,24 @@ public class OrderSortService { ...@@ -136,14 +357,24 @@ public class OrderSortService {
return new ArrayList<>(orders); return new ArrayList<>(orders);
} }
boolean hasMinimizeChangeover = rule.getConditions().stream()
.anyMatch(condition -> "minimize_changeover".equals(condition.getFieldName()));
if (hasMinimizeChangeover) {
// 仅使用最小化换线策略
return sortWithConfiguredStrategy(orders,rule);
} else {
// 按条件顺序排序(sequence越小越先执行) // 按条件顺序排序(sequence越小越先执行)
List<OrderSortRule.SortCondition> sortedConditions = rule.getConditions().stream() List<OrderSortRule.SortCondition> sortedConditions = rule.getConditions().stream()
.sorted(Comparator.comparingInt(OrderSortRule.SortCondition::getSequence)) .sorted(Comparator.comparingInt(OrderSortRule.SortCondition::getSequence))
.collect(Collectors.toList()); .collect(Collectors.toList());
// 为每个订单初始化优先级路径 // 为每个订单初始化优先级路径
Map<Order, List<Integer>> priorityPaths = new HashMap<>(); Map<Integer, List<Integer>> priorityPaths = new HashMap<>();
orders.forEach(order -> priorityPaths.put(order, new ArrayList<>())); orders.forEach(order -> priorityPaths.put(order.getId(), new ArrayList<>()));
// 递归分配层级化优先级(核心逻辑) // 递归分配层级化优先级(核心逻辑)
assignHierarchicalPriority(orders, sortedConditions, 0, priorityPaths); assignHierarchicalPriority(orders, sortedConditions, 0, priorityPaths);
...@@ -156,6 +387,7 @@ public class OrderSortService { ...@@ -156,6 +387,7 @@ public class OrderSortService {
.sorted(Comparator.comparingDouble(Order::getActualPriority)) .sorted(Comparator.comparingDouble(Order::getActualPriority))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
}
/** /**
* 递归分配层级化优先级路径 * 递归分配层级化优先级路径
...@@ -163,7 +395,7 @@ public class OrderSortService { ...@@ -163,7 +395,7 @@ public class OrderSortService {
private void assignHierarchicalPriority(List<Order> orders, private void assignHierarchicalPriority(List<Order> orders,
List<OrderSortRule.SortCondition> conditions, List<OrderSortRule.SortCondition> conditions,
int conditionIndex, int conditionIndex,
Map<Order, List<Integer>> priorityPaths) { Map<Integer, List<Integer>> priorityPaths) {
// 递归终止:处理完所有条件后停止,不再添加额外序号 // 递归终止:处理完所有条件后停止,不再添加额外序号
if (conditionIndex >= conditions.size() || CollectionUtils.isEmpty(orders)) { if (conditionIndex >= conditions.size() || CollectionUtils.isEmpty(orders)) {
return; return;
...@@ -196,7 +428,7 @@ public class OrderSortService { ...@@ -196,7 +428,7 @@ public class OrderSortService {
// 分配当前层级序号(1、2、3...) // 分配当前层级序号(1、2、3...)
int levelNumber = groupIndex + 1; int levelNumber = groupIndex + 1;
groupOrders.forEach(order -> priorityPaths.get(order).add(levelNumber)); groupOrders.forEach(order -> priorityPaths.get(order.getId()).add(levelNumber));
// 递归处理下一级条件 // 递归处理下一级条件
assignHierarchicalPriority(groupOrders, conditions, conditionIndex + 1, priorityPaths); assignHierarchicalPriority(groupOrders, conditions, conditionIndex + 1, priorityPaths);
...@@ -208,9 +440,9 @@ public class OrderSortService { ...@@ -208,9 +440,9 @@ public class OrderSortService {
* 3个条件 → [1,1,1] → 1.11 * 3个条件 → [1,1,1] → 1.11
* 4个条件 → [1,1,1,1] → 1.111 * 4个条件 → [1,1,1,1] → 1.111
*/ */
private void convertPriorityPathsToNumeric(List<Order> orders, Map<Order, List<Integer>> priorityPaths) { private void convertPriorityPathsToNumeric(List<Order> orders, Map<Integer, List<Integer>> priorityPaths) {
for (Order order : orders) { for (Order order : orders) {
List<Integer> path = priorityPaths.get(order); List<Integer> path = priorityPaths.get(order.getId());
if (CollectionUtils.isEmpty(path)) { if (CollectionUtils.isEmpty(path)) {
order.setActualPriority(0.0); order.setActualPriority(0.0);
continue; continue;
......
...@@ -1166,6 +1166,16 @@ private GlobalParam InitGlobalParam() ...@@ -1166,6 +1166,16 @@ private GlobalParam InitGlobalParam()
conditions.add(condition); conditions.add(condition);
files.add("orderCode"); files.add("orderCode");
i++; i++;
}else if (strategy.getName().equals("minimize_tool_changeovers")) {
// 最小化换线策略需要特殊处理,这里只做标记
// 实际排序逻辑将在orderSortService中处理
OrderSortRule.SortCondition condition = new OrderSortRule.SortCondition();
condition.setSequence(i);
condition.setFieldName("minimize_changeover");
condition.setReverse(false);
conditions.add(condition);
files.add("minimize_changeover");
i++;
} }
} }
......
...@@ -13,9 +13,7 @@ import java.time.LocalDate; ...@@ -13,9 +13,7 @@ import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.OffsetDateTime; import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.ArrayList; import java.util.*;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
...@@ -45,18 +43,70 @@ class OrderSortServiceTest { ...@@ -45,18 +43,70 @@ class OrderSortServiceTest {
// 创建多条件排序规则:先按dueDate,再按priority // 创建多条件排序规则:先按dueDate,再按priority
OrderSortRule rule = createMultiConditionRule(); OrderSortRule rule = createMultiConditionRule();
List<Order> orders=new ArrayList<>();
Order order=new Order();
order.setId(1);
order.setOrderId("001");
order.setRoutingId(1);
order.setMaterialCode("M001");
order.setSerie("S001");
orders.add(order);
Order order2=new Order();
order2.setId(2);
order2.setOrderId("002");
order2.setRoutingId(1);
order2.setMaterialCode("M002");
order2.setSerie("S001");
orders.add(order2);
Order order3=new Order();
order3.setId(3);
order3.setOrderId("003");
order3.setRoutingId(1);
order3.setMaterialCode("M002");
order3.setSerie("S001");
orders.add(order3);
Order order4=new Order();
order4.setId(4);
order4.setOrderId("004");
order4.setRoutingId(2);
order4.setMaterialCode("M001");
order4.setSerie("S002");
orders.add(order4);
Order order5=new Order();
order5.setId(5);
order5.setOrderId("005");
order5.setRoutingId(2);
order5.setMaterialCode("M002");
order5.setSerie("S003");
orders.add(order5);
Order order6=new Order();
order6.setId(6);
order6.setOrderId("005");
order6.setRoutingId(2);
order6.setMaterialCode("M002");
order6.setSerie("S003");
orders.add(order6);
// 执行测试 // 执行测试
orderSortService.assignPriority(testOrders, rule);
orderSortService.assignPriorityValues(orders, rule);
// 按照优先级排序 // 按照优先级排序
testOrders.sort( orders.sort(
Comparator.comparing(Order::getActualPriority).reversed() Comparator.comparing(Order::getActualPriority).reversed()
); );
// 验证多级优先级分配 // 验证多级优先级分配
printOrderPriorities(testOrders); // 调试输出 printOrderPriorities(orders); // 调试输出
} }
...@@ -102,17 +152,18 @@ class OrderSortServiceTest { ...@@ -102,17 +152,18 @@ class OrderSortServiceTest {
// 条件2:按到期日 // 条件2:按到期日
OrderSortRule.SortCondition condition2 = new OrderSortRule.SortCondition(); OrderSortRule.SortCondition condition2 = new OrderSortRule.SortCondition();
condition2.setSequence(2); condition2.setSequence(2);
condition2.setFieldName("dueDate"); condition2.setFieldName("minimize_changeover");
condition2.setReverse(false); // 早到期在前 condition2.setReverse(false); // 早到期在前
conditions.add(condition2); conditions.add(condition2);
// 条件3:按优先级 // 条件3:按优先级
OrderSortRule.SortCondition condition3 = new OrderSortRule.SortCondition(); OrderSortRule.SortCondition condition3 = new OrderSortRule.SortCondition();
condition3.setSequence(3); condition3.setSequence(3);
condition3.setFieldName("priority"); condition3.setFieldName("materialCode");
condition3.setReverse(true); // 高优先级在前 condition3.setReverse(true); // 高优先级在前
conditions.add(condition3); conditions.add(condition3);
rule.setConditions(conditions); rule.setConditions(conditions);
return rule; return rule;
} }
......
...@@ -42,7 +42,7 @@ public class PlanResultServiceTest { ...@@ -42,7 +42,7 @@ public class PlanResultServiceTest {
// planResultService.execute2("5475E00B844847ACB6DC20227967BA2F"); // planResultService.execute2("5475E00B844847ACB6DC20227967BA2F");
// planResultService.execute2("00E0C5D3E4AD4F36B56C39395906618D"); // planResultService.execute2("00E0C5D3E4AD4F36B56C39395906618D");
planResultService.execute2("31F0FF4DFAD844BD9C72EDEEF3430A1F"); planResultService.execute2("D6836ADCEF5F4537A4BDD896ECC2EC6A");
// planResultService.execute2("265F24B6DF3C40E4B17D193B0CC8AAF2"); // planResultService.execute2("265F24B6DF3C40E4B17D193B0CC8AAF2");
// LocalDateTime t= LocalDateTime.of(2026, 02, 14, 1, 25, 52); // LocalDateTime t= LocalDateTime.of(2026, 02, 14, 1, 25, 52);
// List<Integer> opids=new ArrayList<>();//BCA6FA43FFA444D3952CF8F6E1EA291B // List<Integer> opids=new ArrayList<>();//BCA6FA43FFA444D3952CF8F6E1EA291B
......
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