Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
H
HYH.APSJ
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
佟礼
HYH.APSJ
Commits
b9d3b3e5
Commit
b9d3b3e5
authored
Mar 09, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
策略最小化换线:小于10全部遍历,大于10用变邻域搜索方法
parent
9a0c5df9
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
250 additions
and
65 deletions
+250
-65
OrderSortService.java
...main/java/com/aps/service/Algorithm/OrderSortService.java
+248
-61
OrderSortServiceTest.java
src/test/java/com/aps/demo/OrderSortServiceTest.java
+2
-4
No files found.
src/main/java/com/aps/service/Algorithm/OrderSortService.java
View file @
b9d3b3e5
package
com
.
aps
.
service
.
Algorithm
;
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.common.util.ProductionDeepCopyUtil
;
import
com.aps.entity.Algorithm.OrderSortRule
;
import
com.aps.entity.Algorithm.OrderSortRule
;
import
com.aps.entity.basic.Order
;
import
com.aps.entity.basic.Order
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
...
@@ -14,6 +15,7 @@ import java.time.OffsetDateTime;
...
@@ -14,6 +15,7 @@ import java.time.OffsetDateTime;
import
java.util.*
;
import
java.util.*
;
import
java.util.function.Function
;
import
java.util.function.Function
;
import
java.util.stream.Collectors
;
import
java.util.stream.Collectors
;
import
java.util.stream.IntStream
;
/**
/**
* 增强版订单排序服务(最终版:严格匹配条件数格式)
* 增强版订单排序服务(最终版:严格匹配条件数格式)
...
@@ -120,90 +122,275 @@ public class OrderSortService {
...
@@ -120,90 +122,275 @@ public class OrderSortService {
/**
/**
* 基于最小化换线成本的排序
* 基于最小化换线成本的排序
*/
*/
private
List
<
Order
>
sortByMinimizeChangeover
(
List
<
Order
>
orders
)
{
if
(
CollectionUtils
.
isEmpty
(
orders
))
{
return
new
ArrayList
<>();
}
// 定义阈值:当订单数量小于等于这个值时,遍历所有起始点
int
threshold
=
5
;
if
(
orders
.
size
()
<=
threshold
)
{
// 订单数量较少,遍历所有起始点
return
sortByMinimizeChangeoverWithAllStarts
(
orders
);
}
else
{
// 订单数量较多,使用局部搜索
return
sortByMinimizeChangeoverWithLocalSearch
(
orders
);
}
}
/**
/**
* 基于
最小化换线成本的排序,并返回带有优先级信息的订单列表
* 基于
遍历所有起始点的最小化换线排序
*/
*/
private
List
<
Order
>
sortByMinimizeChangeover
(
List
<
Order
>
orders
)
{
private
List
<
Order
>
sortByMinimizeChangeover
WithAllStarts
(
List
<
Order
>
orders
)
{
if
(
CollectionUtils
.
isEmpty
(
orders
))
{
if
(
CollectionUtils
.
isEmpty
(
orders
))
{
return
new
ArrayList
<>();
return
new
ArrayList
<>();
}
}
List
<
Order
>
sortedOrders
=
new
ArrayList
<>();
List
<
Order
>
remainingOrders
=
new
ArrayList
<>(
orders
);
List
<
Map
.
Entry
<
List
<
Order
>,
Double
>>
results
=
IntStream
.
range
(
0
,
orders
.
size
())
// 选择第一个订单作为起始点
.
parallel
()
Order
currentOrder
=
remainingOrders
.
remove
(
0
);
.
mapToObj
(
i
->
{
currentOrder
.
setChangeoverPriority
(
1
);
List
<
Order
>
sortedOrders
=
generateInitialSolution
(
ProductionDeepCopyUtil
.
deepCopyList
(
orders
)
,
i
);
sortedOrders
.
add
(
currentOrder
);
// 计算总换线成本
int
priority
=
2
;
double
totalCost
=
calculateTotalChangeoverCost
(
sortedOrders
);
// 每次选择与当前最后一个订单换线成本最低的订单
return
new
AbstractMap
.
SimpleEntry
<>(
sortedOrders
,
totalCost
);
while
(!
remainingOrders
.
isEmpty
())
{
})
double
minCost
=
Double
.
MAX_VALUE
;
.
collect
(
Collectors
.
toList
());
List
<
Order
>
bestOrders
=
new
ArrayList
<>();
List
<
Order
>
bestSortedOrders
=
null
;
// 找到换线成本最低的所有订单
double
minTotalCost
=
Double
.
MAX_VALUE
;
for
(
Order
order
:
remainingOrders
)
{
double
cost
=
calculateChangeoverCost
(
currentOrder
,
order
);
for
(
Map
.
Entry
<
List
<
Order
>,
Double
>
entry
:
results
)
{
if
(
entry
.
getValue
()
<
minTotalCost
)
{
if
(
cost
<
minCost
)
{
minTotalCost
=
entry
.
getValue
();
minCost
=
cost
;
bestSortedOrders
=
entry
.
getKey
();
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
);
}
}
}
}
return
bestSortedOrders
;
}
// 如果有多个成本相同的订单,将它们作为一组添加
if
(!
bestOrders
.
isEmpty
())
{
sortedOrders
.
addAll
(
bestOrders
);
/**
remainingOrders
.
removeAll
(
bestOrders
);
* 基于局部搜索的最小化换线排序
// 更新当前订单为最后添加的订单
*/
currentOrder
=
bestOrders
.
get
(
bestOrders
.
size
()
-
1
);
private
List
<
Order
>
sortByMinimizeChangeoverWithLocalSearch
(
List
<
Order
>
orders
)
{
if
(
minCost
!=
0
)
{
if
(
CollectionUtils
.
isEmpty
(
orders
))
{
priority
++;
return
new
ArrayList
<>();
}
// 1. 生成多个初始解,选择最优的一个
List
<
Order
>
bestInitialSolution
=
null
;
double
bestInitialCost
=
Double
.
MAX_VALUE
;
// 尝试多个随机起始点
Set
<
Integer
>
selectedIndices
=
new
HashSet
<>();
Random
random
=
new
Random
();
int
maxAttempts
=
Math
.
min
(
5
,
orders
.
size
());
while
(
selectedIndices
.
size
()
<
maxAttempts
)
{
int
randomIndex
=
random
.
nextInt
(
orders
.
size
());
if
(
selectedIndices
.
add
(
randomIndex
))
{
List
<
Order
>
initialSolution
=
generateInitialSolution
(
ProductionDeepCopyUtil
.
deepCopyList
(
orders
)
,
randomIndex
);
double
initialCost
=
calculateTotalChangeoverCost
(
initialSolution
);
if
(
initialCost
<
bestInitialCost
)
{
bestInitialCost
=
initialCost
;
bestInitialSolution
=
initialSolution
;
}
}
}
}
List
<
Order
>
currentSolution
=
bestInitialSolution
!=
null
?
bestInitialSolution
:
generateInitialSolution
(
orders
,
0
);
double
currentCost
=
bestInitialCost
;
// 2. 局部搜索(允许所有相邻订单交换)
boolean
improved
;
int
maxIterations
=
50
;
int
iteration
=
0
;
do
{
improved
=
false
;
List
<
Order
>
bestNeighbor
=
new
ArrayList
<>(
currentSolution
);
double
bestNeighborCost
=
currentCost
;
// 遍历所有相邻订单对,尝试交换
for
(
int
i
=
0
;
i
<
currentSolution
.
size
()
-
1
;
i
++)
{
// 交换相邻订单
List
<
Order
>
neighbor
=
new
ArrayList
<>(
currentSolution
);
Collections
.
swap
(
neighbor
,
i
,
i
+
1
);
double
neighborCost
=
calculateTotalChangeoverCost2
(
neighbor
);
}
else
{
// 如果交换后成本更低,更新最佳邻居
// 以防万一,添加剩余的第一个订单
if
(
neighborCost
<
bestNeighborCost
)
{
Order
nextOrder
=
remainingOrders
.
remove
(
0
);
bestNeighbor
=
neighbor
;
sortedOrders
.
add
(
nextOrder
);
bestNeighborCost
=
neighborCost
;
currentOrder
=
nextOrder
;
improved
=
true
;
if
(
minCost
!=
0
)
{
priority
++;
}
}
}
}
// 如果找到更优解,更新当前解
if
(
improved
)
{
currentSolution
=
bestNeighbor
;
// assignChangeoverPriority(currentSolution);
currentCost
=
bestNeighborCost
;
}
iteration
++;
}
while
(
improved
&&
iteration
<
maxIterations
);
return
currentSolution
;
}
/**
* 计算订单序列的总换线成本
*/
/**
* 计算订单序列的总换线成本(考虑ChangeoverPriority分组)
*/
private
double
calculateTotalChangeoverCost2
(
List
<
Order
>
orders
)
{
if
(
CollectionUtils
.
isEmpty
(
orders
)
||
orders
.
size
()
<=
1
)
{
return
0.0
;
}
}
return
sortedOrders
;
double
totalCost
=
0.0
;
// 首先为订单分配ChangeoverPriority
assignChangeoverPriority
(
orders
);
totalCost
=
calculateTotalChangeoverCost
(
orders
);
return
totalCost
;
}
}
public
void
sortByMinimizeChangeover1
(
List
<
Order
>
orders
,
Map
<
Integer
,
List
<
Integer
>>
priorityPaths
)
/**
{
* 生成初始解(使用贪心算法)
List
<
Order
>
optimizedOrders
=
sortByMinimizeChangeover
(
orders
);
*/
private
List
<
Order
>
generateInitialSolution
(
List
<
Order
>
orders
,
int
i
)
{
if
(
CollectionUtils
.
isEmpty
(
orders
))
{
return
new
ArrayList
<>();
}
List
<
Order
>
sortedOrders
=
new
ArrayList
<>();
List
<
Order
>
remainingOrders
=
new
ArrayList
<>(
orders
);
// 选择第一个订单作为起始点
Order
currentOrder
=
remainingOrders
.
remove
(
i
);
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
.
getChangeoverPriority
());
}
else
{
order
.
setChangeoverPriority
(
priority
);
}
bestOrders
.
clear
();
bestOrders
.
add
(
order
);
}
else
if
(
cost
==
minCost
)
{
order
.
setChangeoverCost
(
cost
);
if
(
minCost
==
0
){
order
.
setChangeoverPriority
(
currentOrder
.
getChangeoverPriority
());
}
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
;
}
/**
* 为排序后的订单分配ChangeoverPriority
*/
private
void
assignChangeoverPriority
(
List
<
Order
>
orders
)
{
if
(
CollectionUtils
.
isEmpty
(
orders
))
{
return
;
}
int
priority
=
1
;
orders
.
get
(
0
).
setChangeoverPriority
(
priority
);
for
(
Order
order
:
optimizedOrders
)
{
for
(
int
i
=
1
;
i
<
orders
.
size
();
i
++)
{
double
cost
=
calculateChangeoverCost
(
orders
.
get
(
i
-
1
),
orders
.
get
(
i
));
priorityPaths
.
get
(
order
.
getId
()).
add
(
order
.
getChangeoverPriority
());
if
(
cost
>
0
)
{
//成本为0 ,则在同一级
priority
++;
orders
.
get
(
i
).
setChangeoverCost
(
cost
);
}
else
{
orders
.
get
(
i
).
setChangeoverCost
(
orders
.
get
(
i
-
1
).
getChangeoverCost
());
}
orders
.
get
(
i
).
setChangeoverPriority
(
priority
);
}
}
/**
* 计算订单序列的总换线成本
*/
private
double
calculateTotalChangeoverCost
(
List
<
Order
>
orders
)
{
if
(
CollectionUtils
.
isEmpty
(
orders
)
||
orders
.
size
()
<=
1
)
{
return
0.0
;
}
}
// convertPriorityPathsToNumeric(optimizedOrders, priorityPaths);
int
i
=
0
;
double
totalCost
=
0.0
;
// 001>002 2 cost 75
// 001>003 2 cost 75
//有一点问题,相同ChangeoverPriority 直接换型应该是0,002>003, 然而对象中存的是,
// 001>002,001>003 ,所以相同ChangeoverPriority 不加成本了
// 只计算不同优先级组之间的换线成本
for
(
int
i
=
0
;
i
<
orders
.
size
()
-
1
;
i
++)
{
Order
currentOrder
=
orders
.
get
(
i
);
Order
nextOrder
=
orders
.
get
(
i
+
1
);
// 只有当两个订单的ChangeoverPriority不同时,才计算换线成本
if
(
currentOrder
.
getChangeoverPriority
()
!=
nextOrder
.
getChangeoverPriority
())
{
totalCost
+=
orders
.
get
(
i
+
1
).
getChangeoverCost
();
}
}
return
totalCost
;
}
}
/**
/**
* 处理排序条件,支持在任意位置应用最小化换线策略
* 处理排序条件,支持在任意位置应用最小化换线策略
*/
*/
...
...
src/test/java/com/aps/demo/OrderSortServiceTest.java
View file @
b9d3b3e5
...
@@ -53,8 +53,6 @@ class OrderSortServiceTest {
...
@@ -53,8 +53,6 @@ class OrderSortServiceTest {
orders
.
add
(
order
);
orders
.
add
(
order
);
Order
order2
=
new
Order
();
Order
order2
=
new
Order
();
order2
.
setId
(
2
);
order2
.
setId
(
2
);
order2
.
setOrderId
(
"002"
);
order2
.
setOrderId
(
"002"
);
...
@@ -89,7 +87,7 @@ class OrderSortServiceTest {
...
@@ -89,7 +87,7 @@ class OrderSortServiceTest {
Order
order6
=
new
Order
();
Order
order6
=
new
Order
();
order6
.
setId
(
6
);
order6
.
setId
(
6
);
order6
.
setOrderId
(
"00
5
"
);
order6
.
setOrderId
(
"00
6
"
);
order6
.
setRoutingId
(
2
);
order6
.
setRoutingId
(
2
);
order6
.
setMaterialCode
(
"M002"
);
order6
.
setMaterialCode
(
"M002"
);
order6
.
setSerie
(
"S003"
);
order6
.
setSerie
(
"S003"
);
...
@@ -161,7 +159,7 @@ class OrderSortServiceTest {
...
@@ -161,7 +159,7 @@ class OrderSortServiceTest {
condition3
.
setSequence
(
3
);
condition3
.
setSequence
(
3
);
condition3
.
setFieldName
(
"materialCode"
);
condition3
.
setFieldName
(
"materialCode"
);
condition3
.
setReverse
(
true
);
// 高优先级在前
condition3
.
setReverse
(
true
);
// 高优先级在前
conditions
.
add
(
condition3
);
//
conditions.add(condition3);
rule
.
setConditions
(
conditions
);
rule
.
setConditions
(
conditions
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment