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
cb20ded9
Commit
cb20ded9
authored
Jun 18, 2026
by
Tong Li
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
优化
parent
a94f7c82
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
315 additions
and
114 deletions
+315
-114
GeneticDecoder.java
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
+11
-10
HybridAlgorithm.java
src/main/java/com/aps/service/Algorithm/HybridAlgorithm.java
+2
-1
VariableNeighborhoodSearch.java
...com/aps/service/Algorithm/VariableNeighborhoodSearch.java
+300
-101
PlanResultService.java
src/main/java/com/aps/service/plan/PlanResultService.java
+2
-2
No files found.
src/main/java/com/aps/service/Algorithm/GeneticDecoder.java
View file @
cb20ded9
...
...
@@ -788,7 +788,7 @@ public class GeneticDecoder {
Entry
currentOp
=
orderOps
.
get
(
scheduledCount
);
FileHelper
.
writeLogFile
(
"工序:"
+
currentOp
.
getId
());
int
opSequence
=
currentOp
.
getSequence
();
...
...
@@ -863,7 +863,8 @@ public class GeneticDecoder {
orderProcessCounter
.
put
(
groupId
,
orderProcessCounter
.
get
(
groupId
)
+
1
);
orderLastEndTime
.
put
(
groupId
,
actualEndTime
);
if
(
isJit
&&
orderProcessCounter
.
get
(
groupId
)
>=
entrysBygroupId
.
get
(
groupId
).
size
())
{
if
(
false
){
// if (isJit&& orderProcessCounter.get(groupId) >= entrysBygroupId.get(groupId).size()) {
List
<
Entry
>
orderOpsBySeq
=
entrysBygroupId
.
get
(
groupId
).
stream
()
.
sorted
(
Comparator
.
comparingInt
(
Entry:
:
getSequence
))
...
...
@@ -1503,10 +1504,10 @@ public class GeneticDecoder {
Entry
op
=
entryIndexById
.
get
(
result
.
getOperationId
());
Map
<
String
,
MaterialDeduction
>
deductions
=
readOperationStockDeductions
(
op
);
if
(
deductions
!=
null
&&
!
deductions
.
isEmpty
())
{
rollbackOperationStockDeduction
(
chromosome
,
deductions
);
}
//
Map<String, MaterialDeduction> deductions = readOperationStockDeductions(op);
//
if (deductions != null && !deductions.isEmpty()) {
//
rollbackOperationStockDeduction(chromosome, deductions);
//
}
}
machineTasksCache
.
clear
();
...
...
@@ -1540,10 +1541,10 @@ public class GeneticDecoder {
Entry
op
=
entryIndexById
.
get
(
result
.
getOperationId
());
Map
<
String
,
MaterialDeduction
>
deductions
=
readOperationStockDeductions
(
op
);
if
(
deductions
!=
null
&&
!
deductions
.
isEmpty
())
{
rollbackOperationStockDeduction
(
chromosome
,
deductions
);
}
//
Map<String, MaterialDeduction> deductions = readOperationStockDeductions(op);
//
if (deductions != null && !deductions.isEmpty()) {
//
rollbackOperationStockDeduction(chromosome, deductions);
//
}
Machine
machine
=
getMachineById
(
chromosome
,
result
.
getMachineId
());
if
(
machine
!=
null
)
{
AddMachineAvailable
(
machine
,
result
.
getGeneDetails
());
...
...
src/main/java/com/aps/service/Algorithm/HybridAlgorithm.java
View file @
cb20ded9
...
...
@@ -115,6 +115,7 @@ public class HybridAlgorithm {
List
<
GlobalOperationInfo
>
globalOpList
=
new
ArrayList
<>();
// initialization.generateGlobalOpList();
// 初始化变邻域搜索
_vns
=
new
VariableNeighborhoodSearch
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
_vns
.
initMachineSelectFrequency
();
_hillClimbing
=
new
HillClimbing
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
_simulatedAnnealing
=
new
SimulatedAnnealing
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
_tabuSearch
=
new
TabuSearch
(
allOperations
,
orders
,
materials
,
_entryRel
,
_fitnessCalculator
);
...
...
@@ -464,7 +465,7 @@ public class HybridAlgorithm {
FileHelper
.
writeLogFile
(
"解码---------------"
+
population
.
size
()
);
// GeneticDecoder decoder = new GeneticDecoder(_GlobalParam, param.getBaseTime(), machines, orders, materials, machineScheduler,materialRequirementService, sceneId);
boolean
ismore
=
tru
e
;
boolean
ismore
=
fals
e
;
if
(
ismore
)
{
CompletableFuture
.
allOf
(
population
.
stream
()
.
map
(
chromosome
->
CompletableFuture
.
runAsync
(()
->
decode
(
sharedDecoder
,
chromosome
,
param
,
allOperations
,
globalOpList
),
decodeExecutor
))
...
...
src/main/java/com/aps/service/Algorithm/VariableNeighborhoodSearch.java
View file @
cb20ded9
...
...
@@ -65,6 +65,11 @@ public class VariableNeighborhoodSearch {
private
static
final
double
SIGNIFICANT_IMPROVEMENT_THRESHOLD
=
0.01
;
// 显著改进阈值:提高到0.01以减少无效搜索
private
static
final
int
MAX_MINOR_IMPROVEMENTS
=
3
;
// 最大连续微小改进次数,超过后提前终止
// ==================== 设备选择多样性参数 ====================
private
static
final
double
LOAD_BALANCE_WEIGHT
=
0.5
;
// 负载均衡权重(越高越倾向低负载设备)
private
static
final
double
DIVERSITY_WEIGHT
=
0.4
;
// 设备选择多样性权重(越高越倾向选择次数少的设备)
private
static
final
double
RANDOM_NOISE_FOR_MACHINE
=
0.1
;
// 机器选择的随机扰动因子
// 日志级别
private
static
final
int
LOG_LEVEL_DEBUG
=
0
;
private
static
final
int
LOG_LEVEL_INFO
=
1
;
...
...
@@ -75,7 +80,7 @@ public class VariableNeighborhoodSearch {
private
static
final
int
MAX_LOCAL_SEARCH_NEIGHBORS
=
2
;
// 从5减少到2,大幅减少解码次数
private
void
log
(
String
message
)
{
log
(
message
,
LOG_LEVEL_INFO
,
fals
e
);
log
(
message
,
LOG_LEVEL_INFO
,
tru
e
);
}
private
void
log
(
String
message
,
boolean
enableLogging
)
{
...
...
@@ -107,6 +112,15 @@ public class VariableNeighborhoodSearch {
// 预检查:是否有工序有多个机器选项
private
boolean
hasMultipleMachineOptions
=
false
;
// 工序-设备选择频率:opKey(groupId_sequence) -> machineId -> 选择次数(用于鼓励设备选择多样性)
private
Map
<
String
,
Map
<
Long
,
Integer
>>
opMachineSelectFrequency
=
new
HashMap
<>();
// 瓶颈设备选择频率:machineId -> 被当作"瓶颈设备"的次数(用于鼓励探索不同的设备)
private
Map
<
Long
,
Integer
>
bottleneckMachineFrequency
=
new
HashMap
<>();
// 瓶颈工序选择频率:operationId -> 被当作"优化目标"的次数(用于鼓励探索不同的工序)
private
Map
<
Integer
,
Integer
>
bottleneckOpFrequency
=
new
HashMap
<>();
// 策略成功率统计
private
int
[]
strategySuccessCount
=
new
int
[
4
];
private
int
[]
strategyTotalCount
=
new
int
[
4
];
...
...
@@ -315,6 +329,10 @@ public class VariableNeighborhoodSearch {
public
Chromosome
search
(
Chromosome
chromosome
,
GeneticDecoder
decoder
,
List
<
Machine
>
machines
)
{
log
(
"变邻域搜索 - 开始执行"
,
true
);
// 注意:设备选择频率不在这里重置
// 频率在整个优化流程起点(HybridAlgorithm初始化时)调用 initMachineSelectFrequency() 初始化一次
// 这样频率可以跨模拟退火、变邻域搜索、禁忌搜索等所有算法累积,真正鼓励设备选择多样性
// 深拷贝当前染色体
Chromosome
current
=
ProductionDeepCopyUtil
.
deepCopy
(
chromosome
,
Chromosome
.
class
);
// geneticOperations.DelOrder(current);
...
...
@@ -643,11 +661,71 @@ public class VariableNeighborhoodSearch {
return
result
;
}
// 找出利用率最高的设备
Long
bottleneckMachineId
=
utilization
.
entrySet
().
stream
()
.
max
(
Map
.
Entry
.
comparingByValue
())
.
map
(
Map
.
Entry
::
getKey
)
.
orElse
(
null
);
// === 频率驱动的瓶颈设备选择 ===
// 不再总是选利用率最高的,而是给利用率高+历史被选次数少的设备更高评分
List
<
Map
.
Entry
<
Long
,
Double
>>
machineEntries
=
new
ArrayList
<>(
utilization
.
entrySet
());
machineEntries
.
sort
((
a
,
b
)
->
Double
.
compare
(
b
.
getValue
(),
a
.
getValue
()));
// 取利用率前30%的设备作为候选(确保都是高利用率的,不选冷门低负载设备)
int
topCount
=
Math
.
max
(
3
,
Math
.
min
(
machineEntries
.
size
(),
(
int
)
Math
.
ceil
(
machineEntries
.
size
()
*
0.3
)));
List
<
Map
.
Entry
<
Long
,
Double
>>
topMachines
=
machineEntries
.
subList
(
0
,
topCount
);
// 给每个候选设备计算综合评分(利用率 + 频率多样性)
double
maxUtil
=
topMachines
.
get
(
0
).
getValue
();
double
minUtil
=
topMachines
.
get
(
topMachines
.
size
()
-
1
).
getValue
();
double
utilRange
=
Math
.
max
(
0.01
,
maxUtil
-
minUtil
);
List
<
Object
[]>
scoredMachines
=
new
ArrayList
<>();
int
maxFreq
=
1
;
for
(
Map
.
Entry
<
Long
,
Double
>
entry
:
topMachines
)
{
int
freq
=
bottleneckMachineFrequency
.
getOrDefault
(
entry
.
getKey
(),
0
);
maxFreq
=
Math
.
max
(
maxFreq
,
freq
);
}
for
(
Map
.
Entry
<
Long
,
Double
>
entry
:
topMachines
)
{
Long
machineId
=
entry
.
getKey
();
double
util
=
entry
.
getValue
();
int
freq
=
bottleneckMachineFrequency
.
getOrDefault
(
machineId
,
0
);
// 归一化评分
double
normalizedUtil
=
(
util
-
minUtil
)
/
utilRange
;
// 0~1
double
diversityScore
=
1.0
/
(
1.0
+
freq
);
// 0次→1.0, 次数越多越低
// 综合评分:60% 利用率 + 40% 频率多样性 + 小随机扰动
double
score
=
0.6
*
normalizedUtil
+
0.4
*
diversityScore
+
0.1
*
rnd
.
nextDouble
();
scoredMachines
.
add
(
new
Object
[]{
machineId
,
score
,
util
,
freq
});
}
// 按综合评分降序排序
scoredMachines
.
sort
((
a
,
b
)
->
Double
.
compare
((
Double
)
b
[
1
],
(
Double
)
a
[
1
]));
// 70%选评分最高的,30%按加权随机
Long
selectedMachineId
;
if
(
rnd
.
nextDouble
()
<
0.7
||
scoredMachines
.
size
()
<=
1
)
{
selectedMachineId
=
(
Long
)
scoredMachines
.
get
(
0
)[
0
];
}
else
{
// 加权轮盘赌
double
totalScore
=
0
;
for
(
Object
[]
m
:
scoredMachines
)
{
totalScore
+=
(
Double
)
m
[
1
];
}
double
r
=
rnd
.
nextDouble
()
*
totalScore
;
double
cumSum
=
0
;
selectedMachineId
=
(
Long
)
scoredMachines
.
get
(
scoredMachines
.
size
()
-
1
)[
0
];
for
(
Object
[]
m
:
scoredMachines
)
{
cumSum
+=
(
Double
)
m
[
1
];
if
(
r
<=
cumSum
)
{
selectedMachineId
=
(
Long
)
m
[
0
];
break
;
}
}
}
// 更新该设备被选为瓶颈设备的频率
bottleneckMachineFrequency
.
merge
(
selectedMachineId
,
1
,
Integer:
:
sum
);
Long
bottleneckMachineId
=
selectedMachineId
;
result
.
put
(
"bottleneckMachineId"
,
bottleneckMachineId
);
result
.
put
(
"utilization"
,
utilization
);
...
...
@@ -1205,54 +1283,65 @@ public class VariableNeighborhoodSearch {
return
null
;
}
//
优先选择订单数多的优先级的工序
//
构建优先级->订单数的映射
//
=== 频率驱动的瓶颈工序选择 ===
//
不再只按优先级排序,综合考虑优先级+历史被选次数,鼓励探索不同工序
Map
<
Double
,
Set
<
Integer
>>
priorityToGroupIds
=
new
HashMap
<>();
int
maxGroupCount
=
1
;
for
(
GAScheduleResult
op
:
candidates
)
{
Entry
entry
=
entrybyids
.
get
(
op
.
getOperationId
());
if
(
entry
!=
null
)
{
double
priority
=
entry
.
getPriority
();
priorityToGroupIds
.
computeIfAbsent
(
priority
,
k
->
new
HashSet
<>()).
add
(
op
.
getGroupId
());
int
groupCount
=
priorityToGroupIds
.
computeIfAbsent
(
priority
,
k
->
new
HashSet
<>()).
size
()
+
1
;
priorityToGroupIds
.
get
(
priority
).
add
(
op
.
getGroupId
());
maxGroupCount
=
Math
.
max
(
maxGroupCount
,
priorityToGroupIds
.
get
(
priority
).
size
());
}
}
// 按订单数从多到少排序候选工序
List
<
GAScheduleResult
>
sortedCandidates
=
new
ArrayList
<>(
candidates
);
sortedCandidates
.
sort
((
a
,
b
)
->
{
Entry
entryA
=
entrybyids
.
get
(
a
.
getOperationId
());
Entry
entryB
=
entrybyids
.
get
(
b
.
getOperationId
());
// 给每个候选工序计算综合评分
List
<
Object
[]>
scoredOps
=
new
ArrayList
<>();
int
maxOpFreq
=
1
;
for
(
GAScheduleResult
op
:
candidates
)
{
int
freq
=
bottleneckOpFrequency
.
getOrDefault
(
op
.
getOperationId
(),
0
);
maxOpFreq
=
Math
.
max
(
maxOpFreq
,
freq
);
}
// 统一处理null值:null值排后面
if
(
entryA
==
null
&&
entryB
==
null
)
return
0
;
if
(
entryA
==
null
)
return
1
;
if
(
entryB
==
null
)
return
-
1
;
for
(
GAScheduleResult
op
:
candidates
)
{
Entry
entry
=
entrybyids
.
get
(
op
.
getOperationId
());
if
(
entry
==
null
)
continue
;
int
sizeA
=
priorityToGroupIds
.
getOrDefault
(
entryA
.
getPriority
(),
new
HashSet
<>()).
size
();
int
sizeB
=
priorityToGroupIds
.
getOrDefault
(
entryB
.
getPriority
(),
new
HashSet
<>()).
size
();
// 优先级评分:订单数多的优先级组排前面(0~1归一化)
int
groupCount
=
priorityToGroupIds
.
getOrDefault
(
entry
.
getPriority
(),
new
HashSet
<>()).
size
();
double
priorityScore
=
(
double
)
groupCount
/
maxGroupCount
;
// 订单数多的优先级排前面
int
sizeCompare
=
Integer
.
compare
(
sizeB
,
sizeA
);
if
(
sizeCompare
!=
0
)
{
return
sizeCompare
;
// 频率多样性评分(0次→1.0, 次数越多越低)
int
freq
=
bottleneckOpFrequency
.
getOrDefault
(
op
.
getOperationId
(),
0
);
double
diversityScore
=
1.0
/
(
1.0
+
freq
);
// 综合评分:50% 优先级 + 40% 频率多样性 + 10% 随机
double
score
=
0.5
*
priorityScore
+
0.4
*
diversityScore
+
0.1
*
rnd
.
nextDouble
();
scoredOps
.
add
(
new
Object
[]{
op
,
score
,
groupCount
,
freq
});
}
// 订单数相同时,按优先级排序
return
Double
.
compare
(
entryA
.
getPriority
(),
entryB
.
getPriority
());
});
// 按综合评分降序排序
scoredOps
.
sort
((
a
,
b
)
->
Double
.
compare
((
Double
)
b
[
1
],
(
Double
)
a
[
1
]));
// 70%概率选择前3个候选,30%概率
随机选择
// 70%概率选择前3个候选,30%概率
在更后面选
GAScheduleResult
selectedOp
;
if
(
s
ortedCandidate
s
.
size
()
<=
3
)
{
selectedOp
=
sortedCandidates
.
get
(
rnd
.
nextInt
(
sortedCandidates
.
size
()))
;
if
(
s
coredOp
s
.
size
()
<=
3
)
{
selectedOp
=
(
GAScheduleResult
)
scoredOps
.
get
(
rnd
.
nextInt
(
scoredOps
.
size
()))[
0
]
;
}
else
{
if
(
rnd
.
nextDouble
()
<
0.7
)
{
selectedOp
=
sortedCandidates
.
get
(
rnd
.
nextInt
(
Math
.
min
(
3
,
sortedCandidates
.
size
())))
;
selectedOp
=
(
GAScheduleResult
)
scoredOps
.
get
(
rnd
.
nextInt
(
Math
.
min
(
3
,
scoredOps
.
size
())))[
0
]
;
}
else
{
int
otherCount
=
s
ortedCandidate
s
.
size
()
-
3
;
selectedOp
=
sortedCandidates
.
get
(
3
+
rnd
.
nextInt
(
otherCount
))
;
int
otherCount
=
s
coredOp
s
.
size
()
-
3
;
selectedOp
=
(
GAScheduleResult
)
scoredOps
.
get
(
3
+
rnd
.
nextInt
(
otherCount
))[
0
]
;
}
}
// 更新该工序被选为优化目标的频率
bottleneckOpFrequency
.
merge
(
selectedOp
.
getOperationId
(),
1
,
Integer:
:
sum
);
int
maPos
=
-
1
;
Entry
entry
=
entrybyids
.
get
(
selectedOp
.
getOperationId
());
...
...
@@ -1300,15 +1389,22 @@ public class VariableNeighborhoodSearch {
}
/**
* 给指定位置的工序换设备 -
考虑设备负载均衡优化
* 优先选择负载低的设备
* 给指定位置的工序换设备 -
综合考虑设备负载均衡和选择多样性
* 优先选择负载低
且选择次数少
的设备
*/
private
Chromosome
generateMachineChangeForSpecificOp
(
Chromosome
chromosome
,
List
<
MachineOption
>
machineOptions
,
int
idx
)
{
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
// ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
CopyOnWriteArrayList
<
Integer
>
ms
=
neighbor
.
getMachineSelection
();
if
(!
ms
.
isEmpty
()
&&
idx
>=
0
&&
idx
<
ms
.
size
())
{
if
(
machineOptions
.
size
()
>
1
)
{
// 获取工序信息,用于频率跟踪
String
opKey
=
null
;
if
(
idx
<
chromosome
.
getGlobalOpList
().
size
())
{
Entry
op
=
chromosome
.
getGlobalOpList
().
get
(
idx
).
getOp
();
opKey
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
();
}
int
currentMachineSeq
=
ms
.
get
(
idx
);
List
<
Integer
>
availableMachines
=
new
ArrayList
<>();
for
(
int
i
=
1
;
i
<=
machineOptions
.
size
();
i
++)
{
...
...
@@ -1318,10 +1414,14 @@ public class VariableNeighborhoodSearch {
}
if
(!
availableMachines
.
isEmpty
())
{
// 选择
负载较低的设备(设备负载均衡优化)
int
newMachineSeq
=
selectMachineByLoad
(
availableMachines
,
machineOptions
,
chromosome
);
// 选择
综合考虑负载均衡和选择多样性的设备
int
newMachineSeq
=
selectMachineByLoad
(
availableMachines
,
machineOptions
,
chromosome
,
opKey
);
ms
.
set
(
idx
,
newMachineSeq
);
neighbor
.
setMachineSelection
(
ms
);
// 更新该设备被选择的频率记录
Long
selectedMachineId
=
machineOptions
.
get
(
newMachineSeq
-
1
).
getMachineId
();
updateMachineSelectFrequency
(
opKey
,
selectedMachineId
);
}
}
}
...
...
@@ -1402,52 +1502,66 @@ public class VariableNeighborhoodSearch {
.
collect
(
Collectors
.
toList
());
Map
<
Integer
,
Integer
>
orderCompletionTimes
=
calculateOrderCompletionTimes
(
allResults
);
//
先构建优先级->订单数的映射
//
=== 频率驱动的瓶颈工序选择(与tryChangeMachineForBottleneckOp相同策略) ===
Map
<
Double
,
Set
<
Integer
>>
priorityToGroupIds
=
new
HashMap
<>();
int
maxGroupCount
=
1
;
for
(
GAScheduleResult
op
:
bottleneckOps
)
{
Entry
entry
=
entrybyids
.
get
(
op
.
getOperationId
());
if
(
entry
!=
null
)
{
double
priority
=
entry
.
getPriority
();
priorityToGroupIds
.
computeIfAbsent
(
priority
,
k
->
new
HashSet
<>()).
add
(
op
.
getGroupId
());
int
groupCount
=
priorityToGroupIds
.
computeIfAbsent
(
priority
,
k
->
new
HashSet
<>()).
size
()
+
1
;
priorityToGroupIds
.
get
(
priority
).
add
(
op
.
getGroupId
());
maxGroupCount
=
Math
.
max
(
maxGroupCount
,
priorityToGroupIds
.
get
(
priority
).
size
());
}
}
List
<
GAScheduleResult
>
sortedBottleneckOps
=
new
ArrayList
<>(
bottleneckOps
);
sortedBottleneckOps
.
sort
((
a
,
b
)
->
{
Entry
entryA
=
entrybyids
.
get
(
a
.
getOperationId
());
Entry
entryB
=
entrybyids
.
get
(
b
.
getOperationId
());
// 给每个候选工序计算综合评分
List
<
Object
[]>
scoredOps
=
new
ArrayList
<>();
for
(
GAScheduleResult
op
:
bottleneckOps
)
{
Entry
entry
=
entrybyids
.
get
(
op
.
getOperationId
());
if
(
entry
==
null
)
continue
;
// 统一处理null值:null值排后面
if
(
entryA
==
null
&&
entryB
==
null
)
return
0
;
if
(
entryA
==
null
)
return
1
;
if
(
entryB
==
null
)
return
-
1
;
// 优先级评分(0~1归一化)
int
groupCount
=
priorityToGroupIds
.
getOrDefault
(
entry
.
getPriority
(),
new
HashSet
<>()).
size
();
double
priorityScore
=
(
double
)
groupCount
/
maxGroupCount
;
// 优先按订单数从多到少排序
int
sizeA
=
priorityToGroupIds
.
getOrDefault
(
entryA
.
getPriority
(),
new
HashSet
<>()).
size
();
int
sizeB
=
priorityToGroupIds
.
getOrDefault
(
entryB
.
getPriority
(),
new
HashSet
<>()).
size
();
int
sizeCompare
=
Integer
.
compare
(
sizeB
,
sizeA
);
if
(
sizeCompare
!=
0
)
{
return
sizeCompare
;
// 订单完成时间评分:完成时间越晚,越需要优化(0~1归一化)
int
endTime
=
orderCompletionTimes
.
getOrDefault
(
op
.
getGroupId
(),
0
);
int
maxEndTime
=
0
;
for
(
int
t
:
orderCompletionTimes
.
values
())
{
maxEndTime
=
Math
.
max
(
maxEndTime
,
t
);
}
double
timeScore
=
maxEndTime
>
0
?
(
double
)
endTime
/
maxEndTime
:
0.5
;
// 订单数相同时,按优先级排序
int
priorityCompare
=
Double
.
compare
(
entryA
.
getPriority
(),
entryB
.
getPriority
());
if
(
priorityCompare
!=
0
)
{
return
priorityCompare
;
// 频率多样性评分(0次→1.0, 次数越多越低)
int
freq
=
bottleneckOpFrequency
.
getOrDefault
(
op
.
getOperationId
(),
0
);
double
diversityScore
=
1.0
/
(
1.0
+
freq
);
// 综合评分:35% 优先级 + 25% 时间 + 40% 频率多样性 + 小随机
double
score
=
0.35
*
priorityScore
+
0.25
*
timeScore
+
0.4
*
diversityScore
+
0.1
*
rnd
.
nextDouble
();
scoredOps
.
add
(
new
Object
[]{
op
,
score
,
freq
});
}
// 优先级相同时,按完成时间排序
int
endTimeA
=
orderCompletionTimes
.
getOrDefault
(
a
.
getGroupId
(),
0
);
int
endTimeB
=
orderCompletionTimes
.
getOrDefault
(
b
.
getGroupId
(),
0
);
return
Integer
.
compare
(
endTimeB
,
endTimeA
);
});
// 按综合评分降序排序
scoredOps
.
sort
((
a
,
b
)
->
Double
.
compare
((
Double
)
b
[
1
],
(
Double
)
a
[
1
]));
if
(
s
ortedBottleneck
Ops
.
isEmpty
())
{
if
(
s
cored
Ops
.
isEmpty
())
{
log
(
"tryMoveBottleneckOpForward: 排序后为空"
);
return
null
;
}
GAScheduleResult
selectedOp
=
sortedBottleneckOps
.
get
(
rnd
.
nextInt
(
Math
.
min
(
5
,
sortedBottleneckOps
.
size
())));
// 70%选前5个中的随机,30%选更后面的
GAScheduleResult
selectedOp
;
int
topN
=
Math
.
min
(
5
,
scoredOps
.
size
());
if
(
rnd
.
nextDouble
()
<
0.7
||
scoredOps
.
size
()
<=
5
)
{
selectedOp
=
(
GAScheduleResult
)
scoredOps
.
get
(
rnd
.
nextInt
(
topN
))[
0
];
}
else
{
selectedOp
=
(
GAScheduleResult
)
scoredOps
.
get
(
topN
+
rnd
.
nextInt
(
scoredOps
.
size
()
-
topN
))[
0
];
}
// 更新该工序被选为优化目标的频率
bottleneckOpFrequency
.
merge
(
selectedOp
.
getOperationId
(),
1
,
Integer:
:
sum
);
Entry
entry
=
entrybyids
.
get
(
selectedOp
.
getOperationId
());
if
(
entry
==
null
)
{
...
...
@@ -1922,7 +2036,7 @@ public class VariableNeighborhoodSearch {
*/
private
Chromosome
generateMachineChangeNeighbor
(
Chromosome
chromosome
)
{
log
(
"generateMachineChangeNeighbor"
);
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
// ProductionDeepCopyUtil.deepCopy(chromosome, Chromosome.class);
Chromosome
neighbor
=
copyChromosome
(
chromosome
);
CopyOnWriteArrayList
<
Integer
>
ms
=
neighbor
.
getMachineSelection
();
if
(!
ms
.
isEmpty
())
{
int
idx
=
rnd
.
nextInt
(
ms
.
size
());
...
...
@@ -1930,6 +2044,9 @@ public class VariableNeighborhoodSearch {
Entry
op
=
globalOp
.
getOp
();
if
(
op
.
getMachineOptions
().
size
()
>
1
)
{
// 构建工序唯一键,用于频率跟踪
String
opKey
=
op
.
getGroupId
()
+
"_"
+
op
.
getSequence
();
int
currentMachineSeq
=
ms
.
get
(
idx
);
List
<
Integer
>
availableMachines
=
new
ArrayList
<>();
List
<
MachineOption
>
machineOptions
=
new
ArrayList
<>();
...
...
@@ -1941,10 +2058,14 @@ public class VariableNeighborhoodSearch {
}
if
(!
availableMachines
.
isEmpty
())
{
//
选择负载较低的设备(设备负载均衡优化)
int
newMachineSeq
=
selectMachineByLoad
(
availableMachines
,
machineOptions
,
chromosome
);
//
综合考虑负载均衡和选择多样性
int
newMachineSeq
=
selectMachineByLoad
(
availableMachines
,
machineOptions
,
chromosome
,
opKey
);
ms
.
set
(
idx
,
newMachineSeq
);
neighbor
.
setMachineSelection
(
ms
);
// 更新频率记录
Long
selectedMachineId
=
op
.
getMachineOptions
().
get
(
newMachineSeq
-
1
).
getMachineId
();
updateMachineSelectFrequency
(
opKey
,
selectedMachineId
);
}
}
}
...
...
@@ -2343,52 +2464,130 @@ public class VariableNeighborhoodSearch {
/**
* 机器选项和负载信息的辅助类
*/
private
static
class
MachineOptionWith
Utilization
{
private
static
class
MachineOptionWith
Score
{
int
seq
;
MachineOption
option
;
double
utilization
;
double
score
;
// 综合评分(越高越优)
double
utilization
;
// 设备利用率
int
frequency
;
// 该设备被该工序选择的次数
double
diversityScore
;
// 多样性评分
MachineOptionWith
Utilization
(
int
seq
,
MachineOption
option
,
double
utilization
)
{
MachineOptionWith
Score
(
int
seq
,
MachineOption
option
,
double
utilization
,
int
frequency
,
double
diversityScore
)
{
this
.
seq
=
seq
;
this
.
option
=
option
;
this
.
utilization
=
utilization
;
this
.
frequency
=
frequency
;
this
.
diversityScore
=
diversityScore
;
this
.
score
=
0.0
;
}
}
/**
* 选择负载较低的设备 - 设备负载均衡优化
* 优先选择负载低的设备
* 选择设备 - 综合考虑负载均衡和设备选择多样性
* 综合评分:score = 负载均衡分 * 权重 + 多样性分 * 权重 + 随机扰动
* - 负载均衡分 = 1 - utilization(利用率越低越好)
* - 多样性分 = 1 / (1 + frequency)(选择次数越少越好)
* - 然后使用加权轮盘赌选择,得分最高的设备
*/
private
int
selectMachineByLoad
(
List
<
Integer
>
availableMachineSeqs
,
List
<
MachineOption
>
machineOptions
,
Chromosome
chromosome
)
{
private
int
selectMachineByLoad
(
List
<
Integer
>
availableMachineSeqs
,
List
<
MachineOption
>
machineOptions
,
Chromosome
chromosome
,
String
opKey
)
{
// 计算当前各设备的负载(利用率)
Map
<
Long
,
Double
>
machineUtilization
=
calculateMachineUtilization
(
chromosome
,
true
);
Map
<
Long
,
Double
>
machineUtilization
=
calculateMachineUtilization
(
chromosome
,
true
);
// 构建可用机器列表,计算综合评分
List
<
MachineOptionWithScore
>
availableMachines
=
new
ArrayList
<>();
// 构建可用机器列表,按负载从低到高排序
List
<
MachineOptionWithUtilization
>
availableMachines
=
new
ArrayList
<>();
for
(
int
seq
:
availableMachineSeqs
)
{
if
(
seq
-
1
>=
machineOptions
.
size
())
{
if
(
seq
-
1
>=
machineOptions
.
size
())
{
break
;
}
MachineOption
option
=
machineOptions
.
get
(
seq
-
1
);
Long
machineId
=
option
.
getMachineId
();
double
utilization
=
machineUtilization
.
getOrDefault
(
machineId
,
0.0
);
availableMachines
.
add
(
new
MachineOptionWithUtilization
(
seq
,
option
,
utilization
));
// 获取该工序对该设备的选择次数
int
frequency
=
0
;
if
(
opKey
!=
null
&&
opMachineSelectFrequency
.
containsKey
(
opKey
))
{
frequency
=
opMachineSelectFrequency
.
get
(
opKey
).
getOrDefault
(
machineId
,
0
);
}
// 按利用率从低到高排序
availableMachines
.
sort
(
Comparator
.
comparingDouble
(
m
->
m
.
utilization
));
// 归一化多样性分:选择次数越少,分越高(0~1范围
double
diversity
=
1.0
/
(
1.0
+
frequency
);
// 0次→1, 1次→0.5, 2次→0.33...
if
(
availableMachines
.
size
()==
0
)
{
// 综合评分
double
loadBalanceScore
=
(
1.0
-
utilization
);
double
noise
=
rnd
.
nextDouble
()
*
RANDOM_NOISE_FOR_MACHINE
;
double
score
=
LOAD_BALANCE_WEIGHT
*
loadBalanceScore
+
DIVERSITY_WEIGHT
*
diversity
+
noise
;
MachineOptionWithScore
machineWithScore
=
new
MachineOptionWithScore
(
seq
,
option
,
utilization
,
frequency
,
diversity
);
machineWithScore
.
score
=
score
;
availableMachines
.
add
(
machineWithScore
);
}
if
(
availableMachines
.
size
()
==
0
)
{
return
1
;
}
// 70%概率选择负载最低的设备,30%概率随机选择
// 按综合评分降序排序
availableMachines
.
sort
((
m1
,
m2
)
->
Double
.
compare
(
m2
.
score
,
m1
.
score
));
// 使用加权轮盘赌选择(70%概率选择得分最高的,30%按评分加权随机
if
(
rnd
.
nextDouble
()
<
0.7
)
{
return
availableMachines
.
get
(
0
).
seq
;
}
else
{
return
availableMachines
.
get
(
rnd
.
nextInt
(
availableMachines
.
size
())).
seq
;
// 按评分加权随机选择
double
totalScore
=
0
;
for
(
MachineOptionWithScore
m
:
availableMachines
)
{
totalScore
+=
Math
.
max
(
m
.
score
,
0.001
);
}
double
r
=
rnd
.
nextDouble
()
*
totalScore
;
double
cumSum
=
0
;
for
(
MachineOptionWithScore
m
:
availableMachines
)
{
cumSum
+=
Math
.
max
(
m
.
score
,
0.001
);
if
(
r
<=
cumSum
)
{
return
m
.
seq
;
}
}
return
availableMachines
.
get
(
availableMachines
.
size
()
-
1
).
seq
;
}
}
/**
* 更新工序-设备选择频率记录
*/
private
void
updateMachineSelectFrequency
(
String
opKey
,
Long
machineId
)
{
if
(
opKey
==
null
||
opKey
.
isEmpty
()
||
machineId
==
null
||
machineId
<=
0
)
return
;
opMachineSelectFrequency
.
computeIfAbsent
(
opKey
,
k
->
new
HashMap
<>()).
merge
(
machineId
,
1
,
Integer:
:
sum
);
}
/**
* 初始化所有频率表(在整个优化流程开始时调用一次)
* 频率在模拟退火、变邻域搜索、禁忌搜索等所有算法中共享,不会随单个算法search调用而重置
* 这样才能真正鼓励探索多样性:
* 1) 同一工序尝试不同的设备
* 2) 尝试不同的瓶颈设备
* 3) 尝试不同的瓶颈工序作为优化目标
*/
public
void
initMachineSelectFrequency
()
{
opMachineSelectFrequency
.
clear
();
bottleneckMachineFrequency
.
clear
();
bottleneckOpFrequency
.
clear
();
}
/**
* 获取频率表(用于调试日志)
*/
public
Map
<
String
,
Map
<
Long
,
Integer
>>
getMachineSelectFrequency
()
{
return
opMachineSelectFrequency
;
}
public
Map
<
Long
,
Integer
>
getBottleneckMachineFrequency
()
{
return
bottleneckMachineFrequency
;
}
public
Map
<
Integer
,
Integer
>
getBottleneckOpFrequency
()
{
return
bottleneckOpFrequency
;
}
/**
...
...
src/main/java/com/aps/service/plan/PlanResultService.java
View file @
cb20ded9
...
...
@@ -177,8 +177,8 @@ public class PlanResultService {
* 后续会按场景创建人自动回退到可用的策略配置。
*/
public
Chromosome
execute2
(
String
SceneId
)
{
return
execute2
(
SceneId
,
2361
l
,
241
l
,
null
);
//
return execute2(SceneId, 2321l, 207l, null);
//
return execute2(SceneId, 2361l, 241l, null);
return
execute2
(
SceneId
,
2321
l
,
207
l
,
null
);
}
...
...
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