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
6da2535b
Commit
6da2535b
authored
Jun 11, 2026
by
DESKTOP-VKRD9QF\Administration
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
http://39.100.78.207:1213/tongli/hyh.apsj
parents
90219e38
f322e462
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
570 additions
and
14 deletions
+570
-14
Order.java
src/main/java/com/aps/entity/basic/Order.java
+11
-0
CpSatInitializer.java
...main/java/com/aps/service/Algorithm/CpSatInitializer.java
+6
-2
CpSatOrderMergeService.java
...ava/com/aps/service/Algorithm/CpSatOrderMergeService.java
+342
-0
GeneticDecoder.java
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
+1
-1
HybridAlgorithm.java
src/main/java/com/aps/service/Algorithm/HybridAlgorithm.java
+3
-1
RoutingDataService.java
...in/java/com/aps/service/Algorithm/RoutingDataService.java
+21
-4
PlanResultService.java
src/main/java/com/aps/service/plan/PlanResultService.java
+184
-4
PlanResultServiceTest.java
src/test/java/com/aps/demo/PlanResultServiceTest.java
+2
-2
No files found.
src/main/java/com/aps/entity/basic/Order.java
View file @
6da2535b
...
...
@@ -193,4 +193,15 @@ public class Order {
* 多级排序路径(用于精确字典序排序,避免浮点精度问题)
*/
private
List
<
Integer
>
sortKey
;
/**
* 合并来源订单ID列表(合并订单时记录原始订单ID,用于结果追溯)
*/
private
List
<
String
>
mergedChildOrderIds
;
/**
* 是否为合并订单
*/
private
boolean
merged
=
false
;
}
\ No newline at end of file
src/main/java/com/aps/service/Algorithm/CpSatInitializer.java
View file @
6da2535b
...
...
@@ -74,8 +74,12 @@ public class CpSatInitializer {
}
else
if
(
opCount
<=
LARGE_SCALE_THRESHOLD
)
{
return
largeScaleDecomposed
(
globalOpList
,
targetCount
,
timeBudgetSec
);
}
else
{
FileHelper
.
writeLogFile
(
"[CP-SAT] 工序数超过阈值,跳过CP-SAT,回退启发式"
);
return
Collections
.
emptyList
();
return
largeScaleDecomposed
(
globalOpList
,
targetCount
,
timeBudgetSec
);
// FileHelper.writeLogFile("[CP-SAT] 工序数超过阈值,跳过CP-SAT,回退启发式");
// return Collections.emptyList();
}
}
catch
(
Exception
e
)
{
FileHelper
.
writeLogFile
(
"[CP-SAT] 求解异常,回退启发式: "
+
e
.
getMessage
());
...
...
src/main/java/com/aps/service/Algorithm/CpSatOrderMergeService.java
0 → 100644
View file @
6da2535b
package
com
.
aps
.
service
.
Algorithm
;
import
com.aps.entity.basic.Material
;
import
com.aps.entity.basic.Order
;
import
com.google.ortools.Loader
;
import
com.google.ortools.sat.CpModel
;
import
com.google.ortools.sat.CpSolver
;
import
com.google.ortools.sat.CpSolverStatus
;
import
com.google.ortools.sat.IntVar
;
import
com.google.ortools.sat.LinearExpr
;
import
com.google.ortools.sat.LinearExprBuilder
;
import
com.google.ortools.sat.Literal
;
import
java.math.BigDecimal
;
import
java.time.LocalDateTime
;
import
java.time.temporal.ChronoUnit
;
import
java.util.*
;
import
java.util.stream.Collectors
;
/**
* 基于 OR-Tools CP-SAT 的订单合并求解器
* 将兼容订单建模为 Bin Packing 问题:
* 每个物料组内,最小化合并组数,同时满足 maxProduction 约束
*
* 作者:佟礼
* 时间:2026-05-27
*/
public
class
CpSatOrderMergeService
{
private
static
boolean
nativeLibAvailable
=
false
;
static
{
try
{
Loader
.
loadNativeLibraries
();
nativeLibAvailable
=
true
;
}
catch
(
Exception
ignored
)
{
System
.
err
.
println
(
"[CP-SAT OrderMerge] 原生库加载失败: "
+
ignored
.
getMessage
());
}
}
public
static
boolean
isAvailable
()
{
return
nativeLibAvailable
;
}
private
static
final
int
DEFAULT_DUE_DATE_RANGE_DAYS
=
7
;
private
static
final
int
MAX_SOLVE_TIME_SECONDS
=
10
;
/**
* 使用 CP-SAT 求解最优订单合并方案
*
* @param orders 原始订单列表
* @param materials 物料列表(用于 maxProduction)
* @param dueDateRangeDays 允许合并的交付日期最大相差天数
* @return entry: key=合并后的订单列表, value=originalOrderId→mergedOrder 映射表
*/
public
AbstractMap
.
SimpleEntry
<
List
<
Order
>,
Map
<
String
,
Order
>>
mergeOrders
(
List
<
Order
>
orders
,
List
<
Material
>
materials
,
int
dueDateRangeDays
)
{
if
(!
nativeLibAvailable
)
{
System
.
err
.
println
(
"[CP-SAT OrderMerge] 原生库不可用,回退到贪心合并"
);
return
mergeOrdersGreedy
(
orders
,
materials
,
dueDateRangeDays
);
}
if
(
orders
==
null
||
orders
.
size
()
<=
1
)
{
return
new
AbstractMap
.
SimpleEntry
<>(
orders
,
new
HashMap
<>());
}
Map
<
String
,
Material
>
materialMap
=
buildMaterialMap
(
materials
);
Map
<
String
,
Order
>
mergeMap
=
new
HashMap
<>();
List
<
Order
>
mergedOrders
=
new
ArrayList
<>();
List
<
Order
>
remaining
=
new
ArrayList
<>(
orders
);
while
(!
remaining
.
isEmpty
())
{
Order
base
=
remaining
.
remove
(
0
);
List
<
Order
>
cluster
=
new
ArrayList
<>();
cluster
.
add
(
base
);
Material
material
=
materialMap
.
get
(
base
.
getMaterialId
());
BigDecimal
maxProduction
=
(
material
!=
null
&&
material
.
getMaxProduction
()
!=
null
&&
material
.
getMaxProduction
().
compareTo
(
BigDecimal
.
ZERO
)
>
0
)
?
material
.
getMaxProduction
()
:
null
;
Iterator
<
Order
>
it
=
remaining
.
iterator
();
while
(
it
.
hasNext
())
{
Order
candidate
=
it
.
next
();
if
(
canMergeHard
(
base
,
candidate
,
dueDateRangeDays
))
{
cluster
.
add
(
candidate
);
it
.
remove
();
}
}
if
(
cluster
.
size
()
==
1
)
{
mergedOrders
.
add
(
base
);
}
else
{
List
<
List
<
Order
>>
groups
;
if
(
maxProduction
!=
null
)
{
groups
=
solveBinPacking
(
cluster
,
maxProduction
);
}
else
{
groups
=
new
ArrayList
<>();
groups
.
add
(
cluster
);
}
for
(
List
<
Order
>
group
:
groups
)
{
if
(
group
.
size
()
==
1
)
{
mergedOrders
.
add
(
group
.
get
(
0
));
}
else
{
Order
merged
=
createMergedOrder
(
group
);
mergedOrders
.
add
(
merged
);
for
(
Order
child
:
group
)
{
mergeMap
.
put
(
child
.
getOrderId
(),
merged
);
}
}
}
}
}
return
new
AbstractMap
.
SimpleEntry
<>(
mergedOrders
,
mergeMap
);
}
/**
* 硬约束兼容性检查:materialCode + routingId + serie + 时间重叠 + 交付日期范围
*/
static
boolean
canMergeHard
(
Order
a
,
Order
b
,
int
dueDateRangeDays
)
{
if
(
a
==
null
||
b
==
null
)
return
false
;
if
(
a
.
getRoutingId
()
==
null
||
b
.
getRoutingId
()
==
null
)
return
false
;
if
(!
a
.
getRoutingId
().
equals
(
b
.
getRoutingId
()))
return
false
;
if
(
a
.
getMaterialCode
()
==
null
||
b
.
getMaterialCode
()
==
null
)
return
false
;
if
(!
a
.
getMaterialCode
().
equals
(
b
.
getMaterialCode
()))
return
false
;
if
(
a
.
getSerie
()
==
null
||
b
.
getSerie
()
==
null
)
return
false
;
if
(!
a
.
getSerie
().
equals
(
b
.
getSerie
()))
return
false
;
if
(
a
.
isMerged
()
||
b
.
isMerged
())
return
false
;
if
(
a
.
getStartDate
()
==
null
||
a
.
getDueDate
()
==
null
||
b
.
getStartDate
()
==
null
||
b
.
getDueDate
()
==
null
)
return
false
;
boolean
overlap
=
!
a
.
getDueDate
().
isBefore
(
b
.
getStartDate
())
&&
!
b
.
getDueDate
().
isBefore
(
a
.
getStartDate
());
if
(!
overlap
)
return
false
;
long
daysDiff
=
Math
.
abs
(
ChronoUnit
.
DAYS
.
between
(
a
.
getDueDate
().
toLocalDate
(),
b
.
getDueDate
().
toLocalDate
()));
return
daysDiff
<=
dueDateRangeDays
;
}
/**
* CP-SAT Bin Packing:将 cluster 中的订单分配到最少的分组,每个分组总数量 ≤ maxProduction
*/
private
List
<
List
<
Order
>>
solveBinPacking
(
List
<
Order
>
cluster
,
BigDecimal
maxProduction
)
{
int
n
=
cluster
.
size
();
long
maxProdLong
=
maxProduction
.
longValue
();
CpModel
model
=
new
CpModel
();
IntVar
[][]
x
=
new
IntVar
[
n
][
n
];
IntVar
[]
y
=
new
IntVar
[
n
];
for
(
int
g
=
0
;
g
<
n
;
g
++)
{
y
[
g
]
=
model
.
newBoolVar
(
"y_"
+
g
);
}
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
for
(
int
g
=
0
;
g
<
n
;
g
++)
{
x
[
i
][
g
]
=
model
.
newBoolVar
(
"x_"
+
i
+
"_"
+
g
);
}
}
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
LinearExprBuilder
sumRow
=
LinearExpr
.
newBuilder
();
for
(
int
g
=
0
;
g
<
n
;
g
++)
{
sumRow
.
add
(
x
[
i
][
g
]);
}
model
.
addEquality
(
sumRow
,
1
);
}
long
[]
quantities
=
new
long
[
n
];
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
quantities
[
i
]
=
(
long
)
cluster
.
get
(
i
).
getQuantity
();
}
for
(
int
g
=
0
;
g
<
n
;
g
++)
{
LinearExprBuilder
groupSum
=
LinearExpr
.
newBuilder
();
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
groupSum
.
addTerm
(
x
[
i
][
g
],
quantities
[
i
]);
}
model
.
addLessOrEqual
(
groupSum
,
maxProdLong
);
}
for
(
int
g
=
0
;
g
<
n
;
g
++)
{
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
model
.
addLessOrEqual
(
x
[
i
][
g
],
y
[
g
]);
}
}
for
(
int
g
=
1
;
g
<
n
;
g
++)
{
model
.
addLessOrEqual
(
y
[
g
],
y
[
g
-
1
]);
}
LinearExprBuilder
objExpr
=
LinearExpr
.
newBuilder
();
for
(
int
g
=
0
;
g
<
n
;
g
++)
{
objExpr
.
add
(
y
[
g
]);
}
model
.
minimize
(
objExpr
);
CpSolver
solver
=
new
CpSolver
();
solver
.
getParameters
().
setMaxTimeInSeconds
(
MAX_SOLVE_TIME_SECONDS
);
solver
.
getParameters
().
setLogSearchProgress
(
false
);
CpSolverStatus
status
=
solver
.
solve
(
model
);
List
<
List
<
Order
>>
groups
=
new
ArrayList
<>();
if
(
status
==
CpSolverStatus
.
OPTIMAL
||
status
==
CpSolverStatus
.
FEASIBLE
)
{
for
(
int
g
=
0
;
g
<
n
;
g
++)
{
if
(
solver
.
value
(
y
[
g
])>
0
)
{
List
<
Order
>
group
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
n
;
i
++)
{
if
(
solver
.
value
(
x
[
i
][
g
])>
0
)
{
group
.
add
(
cluster
.
get
(
i
));
}
}
if
(!
group
.
isEmpty
())
{
groups
.
add
(
group
);
}
}
}
}
else
{
groups
.
add
(
cluster
);
}
return
groups
;
}
private
Map
<
String
,
Material
>
buildMaterialMap
(
List
<
Material
>
materials
)
{
if
(
materials
==
null
||
materials
.
isEmpty
())
{
return
Collections
.
emptyMap
();
}
return
materials
.
stream
()
.
filter
(
m
->
m
.
getId
()
!=
null
)
.
collect
(
Collectors
.
toMap
(
Material:
:
getId
,
m
->
m
,
(
e
,
r
)
->
e
));
}
private
Order
createMergedOrder
(
List
<
Order
>
group
)
{
Order
merged
=
new
Order
();
Order
first
=
group
.
get
(
0
);
merged
.
setOrderId
(
first
.
getOrderId
());
merged
.
setOrderCode
(
first
.
getOrderCode
()
+
"-MG"
);
merged
.
setMaterialCode
(
first
.
getMaterialCode
());
merged
.
setMaterialName
(
first
.
getMaterialName
());
merged
.
setMaterialId
(
first
.
getMaterialId
());
merged
.
setSerie
(
first
.
getSerie
());
merged
.
setRoutingId
(
first
.
getRoutingId
());
merged
.
setRoutingCode
(
first
.
getRoutingCode
());
merged
.
setProductId
(
first
.
getProductId
());
merged
.
setMerged
(
true
);
double
totalQty
=
group
.
stream
().
mapToDouble
(
Order:
:
getQuantity
).
sum
();
merged
.
setQuantity
(
totalQty
);
merged
.
setSYQuantity
(
totalQty
);
LocalDateTime
maxStartDate
=
group
.
stream
()
.
map
(
Order:
:
getStartDate
)
.
filter
(
Objects:
:
nonNull
)
.
max
(
LocalDateTime:
:
compareTo
)
.
orElse
(
null
);
merged
.
setStartDate
(
maxStartDate
);
LocalDateTime
minDueDate
=
group
.
stream
()
.
map
(
Order:
:
getDueDate
)
.
filter
(
Objects:
:
nonNull
)
.
min
(
LocalDateTime:
:
compareTo
)
.
orElse
(
null
);
merged
.
setDueDate
(
minDueDate
);
int
minPriority
=
group
.
stream
()
.
mapToInt
(
Order:
:
getPriority
)
.
min
()
.
orElse
(
first
.
getPriority
());
merged
.
setPriority
(
minPriority
);
merged
.
setActualPriority
(
minPriority
);
List
<
String
>
childIds
=
group
.
stream
()
.
map
(
Order:
:
getOrderId
)
.
collect
(
Collectors
.
toList
());
merged
.
setMergedChildOrderIds
(
childIds
);
return
merged
;
}
/**
* 贪心合并回退方案(当 OR-Tools 原生库不可用时使用)
*/
private
AbstractMap
.
SimpleEntry
<
List
<
Order
>,
Map
<
String
,
Order
>>
mergeOrdersGreedy
(
List
<
Order
>
orders
,
List
<
Material
>
materials
,
int
dueDateRangeDays
)
{
if
(
orders
==
null
||
orders
.
size
()
<=
1
)
{
return
new
AbstractMap
.
SimpleEntry
<>(
orders
,
new
HashMap
<>());
}
Map
<
String
,
Material
>
materialMap
=
buildMaterialMap
(
materials
);
Map
<
String
,
Order
>
mergeMap
=
new
HashMap
<>();
List
<
Order
>
mergedOrders
=
new
ArrayList
<>();
List
<
Order
>
remaining
=
new
ArrayList
<>(
orders
);
while
(!
remaining
.
isEmpty
())
{
Order
base
=
remaining
.
remove
(
0
);
List
<
Order
>
mergeGroup
=
new
ArrayList
<>();
mergeGroup
.
add
(
base
);
double
groupQty
=
base
.
getQuantity
();
Material
material
=
materialMap
.
get
(
base
.
getMaterialId
());
BigDecimal
maxProduction
=
(
material
!=
null
&&
material
.
getMaxProduction
()
!=
null
&&
material
.
getMaxProduction
().
compareTo
(
BigDecimal
.
ZERO
)
>
0
)
?
material
.
getMaxProduction
()
:
null
;
Iterator
<
Order
>
it
=
remaining
.
iterator
();
while
(
it
.
hasNext
())
{
Order
candidate
=
it
.
next
();
if
(!
canMergeHard
(
base
,
candidate
,
dueDateRangeDays
))
{
continue
;
}
double
newQty
=
groupQty
+
candidate
.
getQuantity
();
if
(
maxProduction
!=
null
&&
BigDecimal
.
valueOf
(
newQty
).
compareTo
(
maxProduction
)
>
0
)
{
continue
;
}
mergeGroup
.
add
(
candidate
);
groupQty
=
newQty
;
it
.
remove
();
}
if
(
mergeGroup
.
size
()
==
1
)
{
mergedOrders
.
add
(
base
);
}
else
{
Order
merged
=
createMergedOrder
(
mergeGroup
);
mergedOrders
.
add
(
merged
);
for
(
Order
child
:
mergeGroup
)
{
mergeMap
.
put
(
child
.
getOrderId
(),
merged
);
}
}
}
return
new
AbstractMap
.
SimpleEntry
<>(
mergedOrders
,
mergeMap
);
}
}
\ No newline at end of file
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
View file @
6da2535b
...
...
@@ -1633,7 +1633,7 @@ if(groupId==7)
bomtime
=
getOperationBOMTime
(
operation
,
chromosome
,
earliestStartTime
,
2
);
earliestStartTime
=
Math
.
max
(
earliestStartTime
,
bomtime
);
//倒排需要工序排完再验证原材料,保证bom供应商就行
FileHelper
.
writeLogFile
(
"工序:"
+
operation
.
getId
()+
"BOMTIME:"
+
bomtime
);
//
FileHelper.writeLogFile("工序:"+operation.getId()+ "BOMTIME:"+bomtime);
}
}
...
...
src/main/java/com/aps/service/Algorithm/HybridAlgorithm.java
View file @
6da2535b
...
...
@@ -98,8 +98,10 @@ public class HybridAlgorithm {
// .filter(t->existIds.add(t.getId()))//HashSet.add() 方法:添加成功返回 true,重复返回 false;
// .collect(Collectors.toList());
// }
LocalDateTime
starttime
=
LocalDateTime
.
now
();
FileHelper
.
writeLogFile
(
"排产-----------开始-----------"
+
allOperations
.
get
(
0
).
getSceneId
());
FileHelper
.
writeLogFile
(
"排产-----------开始-----
"
+
(
_GlobalParam
.
isJit
()?
"倒排"
:
"正排"
)+
"
------"
+
allOperations
.
get
(
0
).
getSceneId
());
// 在整个流程开始时创建一个全局 shared decoder,所有阶段共享解码缓存
GeneticDecoder
sharedDecoder
=
new
GeneticDecoder
(
_GlobalParam
,
param
.
getBaseTime
(),
machines
,
orders
,
materials
,
machineScheduler
,
materialRequirementService
,
sceneId
);
...
...
src/main/java/com/aps/service/Algorithm/RoutingDataService.java
View file @
6da2535b
...
...
@@ -63,6 +63,11 @@ public class RoutingDataService {
private
EquipinfoService
_equipinfoService
;
public
Map
<
Integer
,
Object
>
InitEntrys
(
String
SceneId
,
List
<
ProdEquipment
>
ProdEquipments
,
List
<
Order
>
ProdLaunchOrders
)
{
return
InitEntrys
(
SceneId
,
ProdEquipments
,
ProdLaunchOrders
,
null
);
}
public
Map
<
Integer
,
Object
>
InitEntrys
(
String
SceneId
,
List
<
ProdEquipment
>
ProdEquipments
,
List
<
Order
>
ProdLaunchOrders
,
Map
<
String
,
Order
>
mergeMap
)
{
Map
<
Integer
,
Object
>
list
=
new
HashMap
<>();
List
<
ProdProcessExec
>
ProdProcessExecs
=
_prodProcessExecService
.
lambdaQuery
()
...
...
@@ -111,6 +116,11 @@ public class RoutingDataService {
}
public
Map
<
Integer
,
Object
>
CreateEntry
(
String
SceneId
,
List
<
ProdEquipment
>
ProdEquipments
,
List
<
Order
>
ProdLaunchOrders
,
List
<
RoutingDiscreteParam
>
routingDiscreteParams
,
List
<
ProdOrderProcess
>
ProdOrderProcesss
,
List
<
ProdProcessExec
>
ProdProcessExecs
,
List
<
GroupResult
>
existingResults
,
int
FinishOpertionID
)
{
return
CreateEntry
(
SceneId
,
ProdEquipments
,
ProdLaunchOrders
,
routingDiscreteParams
,
ProdOrderProcesss
,
ProdProcessExecs
,
existingResults
,
FinishOpertionID
,
null
);
}
public
Map
<
Integer
,
Object
>
CreateEntry
(
String
SceneId
,
List
<
ProdEquipment
>
ProdEquipments
,
List
<
Order
>
ProdLaunchOrders
,
List
<
RoutingDiscreteParam
>
routingDiscreteParams
,
List
<
ProdOrderProcess
>
ProdOrderProcesss
,
List
<
ProdProcessExec
>
ProdProcessExecs
,
List
<
GroupResult
>
existingResults
,
int
FinishOpertionID
,
Map
<
String
,
Order
>
mergeMap
)
{
Map
<
Integer
,
Object
>
list
=
new
HashMap
<>();
List
<
String
>
soutceExecId
=
ProdOrderProcesss
.
stream
()
...
...
@@ -240,9 +250,9 @@ public class RoutingDataService {
entry
.
setDepartmentId
(
op
.
getDepartmentId
());
}
entry
.
setIsInterrupt
(
op
.
getCanInterrupt
());
Order
order
=
ProdLaunchOrders
.
stream
()
.
filter
(
t
->
t
.
getOrderId
().
equals
(
op
.
getOrderId
()))
.
findFirst
().
orElse
(
null
);
Order
order
=
findOrderByOrderId
(
ProdLaunchOrders
,
mergeMap
,
op
.
getOrderId
());
if
(
order
!=
null
)
{
entry
.
setOrderCode
(
order
.
getOrderCode
());
entry
.
setProductId
(
order
.
getMaterialId
());
...
...
@@ -315,7 +325,14 @@ if(entry.getMachineOptions()!=null)
return
list
;
}
private
Order
findOrderByOrderId
(
List
<
Order
>
orderList
,
Map
<
String
,
Order
>
mergeMap
,
String
orderId
)
{
if
(
mergeMap
!=
null
&&
mergeMap
.
containsKey
(
orderId
))
{
return
mergeMap
.
get
(
orderId
);
}
return
orderList
.
stream
()
.
filter
(
t
->
t
.
getOrderId
().
equals
(
orderId
))
.
findFirst
().
orElse
(
null
);
}
public
List
<
Machine
>
InitCalendarToAllMachines
(
String
SceneId
,
List
<
ProdEquipment
>
ProdEquipments
,
MachineSchedulerService
machineScheduler
,
boolean
IsUseCalendar
)
{
// 按设备分组
...
...
src/main/java/com/aps/service/plan/PlanResultService.java
View file @
6da2535b
...
...
@@ -177,7 +177,9 @@ public class PlanResultService {
* 后续会按场景创建人自动回退到可用的策略配置。
*/
public
Chromosome
execute2
(
String
SceneId
)
{
return
execute2
(
SceneId
,
2361
l
,
241
l
,
null
);
// return execute2(SceneId, 2361l, 241l, null);
return
execute2
(
SceneId
,
2321
l
,
207
l
,
null
);
}
/**
...
...
@@ -275,9 +277,9 @@ public class PlanResultService {
// 5. 执行调度算法
HybridAlgorithm
scheduler
=
new
HybridAlgorithm
(
globalParam
,
machines
,
orders
,
materialmap
,
materialIds
,
machineScheduler
,
entryRel
,
materialRequirementService
,
_sceneService
,
SceneId
);
//new GeneticAlgorithm(products, machines, orders, machineScheduler);
param
.
initAdaptiveParams
(
entrys
.
size
());
double
[]
customWeights
=
new
double
[]
{
0.4
,
0.1
,
0.1
,
0.1
,
0.3
};
// 延迟时间权重提升到0.5
//
double[] customWeights = new double[] { 0.4, 0.1, 0.1, 0.1, 0.3 }; // 延迟时间权重提升到0.5
//完工时间、总流程时间、总换型时间、机器负载标准差、延迟时间
scheduler
.
Init
();
//
scheduler.Init();
Chromosome
chromosome
=
scheduler
.
Run
(
param
,
entrys
);
KpiCalculator
kpiCalculator
=
new
KpiCalculator
(
chromosome
);
...
...
@@ -2476,6 +2478,184 @@ if(job.getGeneDetails()!=null)
return
orders
;
}
/**
* 排产前合并兼容订单:相同物料+相同工艺路线+相同系列+时间窗口重叠且交付日期相近的订单合并为一个
* @param orders 原始订单列表
* @param materials 物料列表(用于 maxProduction 上限校验)
* @return entry: key=合并后的订单列表, value=originalOrderId→mergedOrder 映射表
*/
public
AbstractMap
.
SimpleEntry
<
List
<
Order
>,
Map
<
String
,
Order
>>
mergeOrders
(
List
<
Order
>
orders
,
List
<
Material
>
materials
)
{
return
mergeOrders
(
orders
,
materials
,
DEFAULT_MERGE_DUE_DATE_RANGE_DAYS
);
}
/**
* 使用 OR-Tools CP-SAT 求解最优合并方案(替代贪心算法)
* 将兼容订单建模为 Bin Packing,最小化合并组数
*
* @param orders 原始订单列表
* @param materials 物料列表
* @param dueDateRangeDays 交付日期相差上限(天)
* @return entry: key=合并后的订单列表, value=originalOrderId→mergedOrder 映射表
*/
public
AbstractMap
.
SimpleEntry
<
List
<
Order
>,
Map
<
String
,
Order
>>
mergeOrdersWithCpSat
(
List
<
Order
>
orders
,
List
<
Material
>
materials
,
int
dueDateRangeDays
)
{
CpSatOrderMergeService
solver
=
new
CpSatOrderMergeService
();
return
solver
.
mergeOrders
(
orders
,
materials
,
dueDateRangeDays
);
}
/**
* @param dueDateRangeDays 允许合并的交付日期最大相差天数
*/
public
AbstractMap
.
SimpleEntry
<
List
<
Order
>,
Map
<
String
,
Order
>>
mergeOrders
(
List
<
Order
>
orders
,
List
<
Material
>
materials
,
int
dueDateRangeDays
)
{
if
(
orders
==
null
||
orders
.
size
()
<=
1
)
{
return
new
AbstractMap
.
SimpleEntry
<>(
orders
,
new
HashMap
<>());
}
Map
<
String
,
Material
>
materialMap
=
buildMaterialMap
(
materials
);
Map
<
String
,
Order
>
mergeMap
=
new
HashMap
<>();
List
<
Order
>
mergedOrders
=
new
ArrayList
<>();
List
<
Order
>
remaining
=
new
ArrayList
<>(
orders
);
while
(!
remaining
.
isEmpty
())
{
Order
base
=
remaining
.
remove
(
0
);
List
<
Order
>
mergeGroup
=
new
ArrayList
<>();
mergeGroup
.
add
(
base
);
double
groupQty
=
base
.
getQuantity
();
Material
material
=
materialMap
.
get
(
base
.
getMaterialId
());
BigDecimal
maxProduction
=
(
material
!=
null
&&
material
.
getMaxProduction
()
!=
null
&&
material
.
getMaxProduction
().
compareTo
(
BigDecimal
.
ZERO
)
>
0
)
?
material
.
getMaxProduction
()
:
null
;
Iterator
<
Order
>
it
=
remaining
.
iterator
();
while
(
it
.
hasNext
())
{
Order
candidate
=
it
.
next
();
if
(!
canMerge
(
base
,
candidate
,
dueDateRangeDays
))
{
continue
;
}
double
newQty
=
groupQty
+
candidate
.
getQuantity
();
if
(
maxProduction
!=
null
&&
BigDecimal
.
valueOf
(
newQty
).
compareTo
(
maxProduction
)
>
0
)
{
continue
;
}
mergeGroup
.
add
(
candidate
);
groupQty
=
newQty
;
it
.
remove
();
}
if
(
mergeGroup
.
size
()
==
1
)
{
mergedOrders
.
add
(
base
);
}
else
{
Order
merged
=
createMergedOrder
(
mergeGroup
);
mergedOrders
.
add
(
merged
);
for
(
Order
child
:
mergeGroup
)
{
mergeMap
.
put
(
child
.
getOrderId
(),
merged
);
}
}
}
FileHelper
.
writeLogFile
(
String
.
format
(
"订单合并完成:原始%d个 → 合并后%d个,合并组%d组"
,
orders
.
size
(),
mergedOrders
.
size
(),
(
int
)
mergeMap
.
values
().
stream
().
distinct
().
count
()));
return
new
AbstractMap
.
SimpleEntry
<>(
mergedOrders
,
mergeMap
);
}
private
static
final
int
DEFAULT_MERGE_DUE_DATE_RANGE_DAYS
=
7
;
private
Map
<
String
,
Material
>
buildMaterialMap
(
List
<
Material
>
materials
)
{
if
(
materials
==
null
||
materials
.
isEmpty
())
{
return
Collections
.
emptyMap
();
}
return
materials
.
stream
()
.
filter
(
m
->
m
.
getId
()
!=
null
)
.
collect
(
Collectors
.
toMap
(
Material:
:
getId
,
m
->
m
,
(
existing
,
replacement
)
->
existing
));
}
private
boolean
canMerge
(
Order
a
,
Order
b
,
int
dueDateRangeDays
)
{
if
(
a
==
null
||
b
==
null
)
{
return
false
;
}
if
(
a
.
getRoutingId
()
==
null
||
b
.
getRoutingId
()
==
null
)
{
return
false
;
}
if
(!
a
.
getRoutingId
().
equals
(
b
.
getRoutingId
()))
{
return
false
;
}
if
(
a
.
getMaterialCode
()
==
null
||
b
.
getMaterialCode
()
==
null
)
{
return
false
;
}
if
(!
a
.
getMaterialCode
().
equals
(
b
.
getMaterialCode
()))
{
return
false
;
}
if
(
a
.
getSerie
()
==
null
||
b
.
getSerie
()
==
null
)
{
return
false
;
}
if
(!
a
.
getSerie
().
equals
(
b
.
getSerie
()))
{
return
false
;
}
if
(
a
.
isMerged
()
||
b
.
isMerged
())
{
return
false
;
}
if
(
a
.
getStartDate
()
==
null
||
a
.
getDueDate
()
==
null
||
b
.
getStartDate
()
==
null
||
b
.
getDueDate
()
==
null
)
{
return
false
;
}
boolean
overlap
=
!
a
.
getDueDate
().
isBefore
(
b
.
getStartDate
())
&&
!
b
.
getDueDate
().
isBefore
(
a
.
getStartDate
());
if
(!
overlap
)
{
return
false
;
}
long
daysDiff
=
Math
.
abs
(
ChronoUnit
.
DAYS
.
between
(
a
.
getDueDate
().
toLocalDate
(),
b
.
getDueDate
().
toLocalDate
()));
return
daysDiff
<=
dueDateRangeDays
;
}
private
Order
createMergedOrder
(
List
<
Order
>
group
)
{
Order
merged
=
new
Order
();
Order
first
=
group
.
get
(
0
);
merged
.
setOrderId
(
first
.
getOrderId
());
merged
.
setOrderCode
(
first
.
getOrderCode
()
+
"-MG"
);
merged
.
setMaterialCode
(
first
.
getMaterialCode
());
merged
.
setMaterialName
(
first
.
getMaterialName
());
merged
.
setMaterialId
(
first
.
getMaterialId
());
merged
.
setSerie
(
first
.
getSerie
());
merged
.
setRoutingId
(
first
.
getRoutingId
());
merged
.
setRoutingCode
(
first
.
getRoutingCode
());
merged
.
setProductId
(
first
.
getProductId
());
merged
.
setMerged
(
true
);
double
totalQty
=
group
.
stream
().
mapToDouble
(
Order:
:
getQuantity
).
sum
();
merged
.
setQuantity
(
totalQty
);
merged
.
setSYQuantity
(
totalQty
);
LocalDateTime
maxStartDate
=
group
.
stream
()
.
map
(
Order:
:
getStartDate
)
.
filter
(
Objects:
:
nonNull
)
.
max
(
LocalDateTime:
:
compareTo
)
.
orElse
(
null
);
merged
.
setStartDate
(
maxStartDate
);
LocalDateTime
minDueDate
=
group
.
stream
()
.
map
(
Order:
:
getDueDate
)
.
filter
(
Objects:
:
nonNull
)
.
min
(
LocalDateTime:
:
compareTo
)
.
orElse
(
null
);
merged
.
setDueDate
(
minDueDate
);
int
minPriority
=
group
.
stream
()
.
mapToInt
(
Order:
:
getPriority
)
.
min
()
.
orElse
(
first
.
getPriority
());
merged
.
setPriority
(
minPriority
);
merged
.
setActualPriority
(
minPriority
);
List
<
String
>
childIds
=
group
.
stream
()
.
map
(
Order:
:
getOrderId
)
.
collect
(
Collectors
.
toList
());
merged
.
setMergedChildOrderIds
(
childIds
);
return
merged
;
}
public
List
<
Material
>
InitMaterial
()
{
List
<
Material
>
materials
=
new
ArrayList
<>();
FileHelper
.
writeLogFile
(
"初始化物料-----------开始-------"
);
...
...
src/test/java/com/aps/demo/PlanResultServiceTest.java
View file @
6da2535b
...
...
@@ -42,8 +42,8 @@ public class PlanResultServiceTest {
// nsgaiiUtils.Test();
// planResultService.execute2("64E64F6B68094AF38CEDC418630C3CC2");//2000
planResultService
.
execute2
(
"E1448B3C9C8743DEAB39708F2CFE348A"
);
//2000
// planResultService.execute2("E1448B3C9C8743DEAB39708F2CFE348A");//倒排bomces
planResultService
.
execute2
(
"197083D0D26A449EB179AC103C753FD3"
);
// planResultService.execute2("15210B13B88A453F8B84AAC7F16C7541");//2000
// planResultService.execute2("E29F2B3ADA8149F6B916B5119296A92B");//2000
...
...
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